From 218934fa2ed1c702a6d3923d2aa2cc6b43c48684 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:43:23 -0500 Subject: initial commit --- files/zh-tw/_redirects.txt | 732 ++ files/zh-tw/_wikihistory.json | 9180 ++++++++++++++++++++ .../archive/add-ons/developing_add-ons/index.html | 50 + files/zh-tw/archive/add-ons/index.html | 8 + .../index.html | 51 + .../working_with_multiprocess_firefox/index.html | 235 + .../zh-tw/archive/apps/advanced_topics/index.html | 76 + files/zh-tw/archive/apps/index.html | 8 + .../contacts/index.html | 71 + .../device_storage/index.html | 111 + .../geolocation/index.html | 20 + .../3rd_party_app_developer_guide/index.html | 90 + .../web_activity/index.html | 116 + .../index.html" | 70 + .../index.html" | 78 + files/zh-tw/archive/b2g_os/add-ons/index.html | 282 + files/zh-tw/archive/b2g_os/api/fmradio/index.html | 110 + files/zh-tw/archive/b2g_os/api/index.html | 156 + files/zh-tw/archive/b2g_os/apps/index.html | 45 + .../apps/writing_a_web_app_for_b2g/index.html | 25 + files/zh-tw/archive/b2g_os/architecture/index.html | 717 ++ .../gaia_ui_tests_run_tests/index.html | 111 + .../automated_testing/gaia-ui-tests/index.html | 69 + .../archive/b2g_os/automated_testing/index.html | 77 + files/zh-tw/archive/b2g_os/building/index.html | 124 + .../firefox_os_build_process_summary/index.html | 108 + .../building_and_installing_firefox_os/index.html | 65 + .../choosing_how_to_run_gaia_or_b2g/index.html | 59 + files/zh-tw/archive/b2g_os/debugging/index.html | 21 + .../firefox_os_build_prerequisites/index.html | 606 ++ files/zh-tw/archive/b2g_os/index.html | 222 + .../index.html | 53 + files/zh-tw/archive/b2g_os/introduction/index.html | 86 + .../archive/b2g_os/phone_guide/flame/index.html | 50 + files/zh-tw/archive/b2g_os/phone_guide/index.html | 6 + .../archive/b2g_os/phone_guide/zte_open/index.html | 287 + .../b2g_os/platform/apps_architecture/index.html | 24 + .../b2g_os/platform/gaia/gaia_apps/index.html | 78 + .../zh-tw/archive/b2g_os/platform/gaia/index.html | 68 + .../platform/gaia/introduction_to_gaia/index.html | 13 + .../zh-tw/archive/b2g_os/platform/gonk/index.html | 22 + files/zh-tw/archive/b2g_os/platform/index.html | 75 + .../index.html | 53 + .../preparing_for_your_first_b2g_build/index.html | 138 + .../archive/b2g_os/quickstart/app_tools/index.html | 28 + files/zh-tw/archive/b2g_os/quickstart/index.html | 51 + .../b2g_os/quickstart/your_first_app/index.html | 265 + files/zh-tw/archive/b2g_os/releases/1.2/index.html | 465 + files/zh-tw/archive/b2g_os/releases/index.html | 24 + .../index.html | 43 + .../index.html | 208 + .../security/application_security/index.html | 124 + files/zh-tw/archive/b2g_os/security/index.html | 70 + .../b2g_os/security/security_model/index.html | 299 + .../b2g_os/security/system_security/index.html | 376 + files/zh-tw/archive/b2g_os/simulator/index.html | 90 + .../simulator/simulator_walkthrough/index.html | 268 + .../b2g_os/using_the_app_manager/index.html | 259 + .../b2g_os/using_the_b2g_desktop_client/index.html | 180 + .../b2g_os/using_the_b2g_emulators/index.html | 69 + .../archive/b2g_os/web_telephony_api/index.html | 25 + .../writing_apps_for_boot_to_gecko/index.html | 12 + files/zh-tw/archive/css3/index.html | 584 ++ files/zh-tw/archive/index.html | 21 + files/zh-tw/archive/mdn/index.html | 18 + .../zh-tw/archive/mdn/persona_sign-ins/index.html | 28 + .../archive/meta_docs/custom_classes/index.html | 189 + files/zh-tw/archive/meta_docs/index.html | 12 + .../creating_a_web_based_tone_generator/index.html | 91 + files/zh-tw/archive/misc_top_level/index.html | 8 + .../index.html | 18 + .../mozilla/creating_a_microsummary/index.html | 214 + .../zh-tw/archive/mozilla/drag_and_drop/index.html | 142 + files/zh-tw/archive/mozilla/firefox/index.html | 8 + .../mozilla/firefox/using_microformats/index.html | 78 + files/zh-tw/archive/mozilla/index.html | 10 + .../archive/mozilla/marketplace/apis/index.html | 36 + .../archive/mozilla/marketplace/faq/index.html | 154 + files/zh-tw/archive/mozilla/marketplace/index.html | 159 + .../marketplace/marketplace_apis/index.html | 69 + .../monetization/app_payments_guide/index.html | 48 + .../monetization/app_pricing/index.html | 3698 ++++++++ .../monetization/in-app_payments/index.html | 332 + .../mozilla/marketplace/monetization/index.html | 80 + .../introduction_monetization/index.html | 77 + .../monetization/payments_status/index.html | 30 + .../profiting_from_your_app/index.html | 95 + .../monetization/validating_a_receipt/index.html | 132 + .../marketplace/options/hosted_apps/index.html | 69 + .../publishing/adding_a_subdomain/index.html | 40 + .../publishing/creating_a_store/index.html | 22 + .../mozilla/marketplace/publishing/index.html | 9 + .../marketplace/publishing/introduction/index.html | 87 + .../managing_your_apps/app_statistics/index.html | 66 + .../marketplace_screenshot_criteria/index.html | 80 + .../publishing/packaged_apps/index.html | 75 + .../publishing/policies_and_guidelines/index.html | 10 + .../introduction/index.html | 39 + .../publishing/pricing/introduction/index.html | 57 + .../publishing/pricing/payment_accounts/index.html | 61 + .../promote_as_upgrade_to_free_version/index.html | 26 + .../publishing/privacy_policies/index.html | 28 + .../publishing/publish_options/index.html | 145 + .../publishing/submission_checklist/index.html | 72 + .../submit/enter_your_apps_details/index.html | 129 + .../marketplace/publishing/submit/index.html | 10 + .../publishing/submit/load_your_app/index.html | 134 + .../publishing/submit/next_steps/index.html | 16 + .../publishing/submit/overview/index.html | 128 + .../sign-in_to_your_developer_account/index.html | 52 + .../publishing/updating_apps/index.html | 27 + .../mozilla/marketplace/submission/index.html | 9 + .../marketplace_review_criteria/index.html | 80 + .../submission/pre-submission_checklist/index.html | 36 + .../submission/rating_your_content/index.html | 117 + .../index.html | 1070 +++ .../archive/mozilla/persona/branding/index.html | 42 + files/zh-tw/archive/mozilla/persona/index.html | 125 + .../persona/internationalization/index.html | 51 + .../archive/mozilla/persona/quick_setup/index.html | 137 + .../persona/remote_verification_api/index.html | 171 + .../archive/mozilla/persona/why_persona/index.html | 30 + files/zh-tw/archive/mozilla/xpinstall/index.html | 65 + .../xpinstall/scripting_by_example/index.html | 244 + files/zh-tw/archive/mozilla/xul/index.html | 99 + .../archive/mozilla/xul/template_guide/index.html | 5 + .../archive/mozilla/xul/the_joy_of_xul/index.html | 49 + .../archive/mozilla/xul/xul_reference/index.html | 344 + files/zh-tw/archive/mozilla/xulrunner/index.html | 88 + .../mozilla/xulrunner/xulrunner_tips/index.html | 213 + files/zh-tw/archive/themes/index.html | 11 + files/zh-tw/archive/web/e4x/index.html | 6 + .../web/e4x/processing_xml_with_e4x/index.html | 229 + files/zh-tw/archive/web/index.html | 12 + files/zh-tw/archive/web_standards/index.html | 76 + .../rdf_in_fifty_words_or_less/index.html | 85 + files/zh-tw/code_snippets/index.html | 190 + .../zh-tw/code_snippets/tabbed_browser/index.html | 398 + .../index.html" | 9 + files/zh-tw/cross-site_xmlhttprequest/index.html | 108 + .../index.html" | 5 + files/zh-tw/dragdrop/index.html | 5 + files/zh-tw/extensions/index.html | 9 + .../index.html | 49 + .../index.html" | 884 ++ .../index.html" | 240 + .../firefox_3_animated_png_support/index.html | 39 + .../firefox_3_drag_and_drop_events/index.html | 33 + .../index.html" | 48 + files/zh-tw/games/index.html | 85 + files/zh-tw/games/introduction/index.html | 122 + files/zh-tw/games/techniques/index.html | 32 + .../bounce_off_the_walls/index.html | 98 + .../create_the_canvas_and_draw_on_it/index.html | 118 + .../2d_breakout_game_pure_javascript/index.html | 57 + .../move_the_ball/index.html | 136 + files/zh-tw/games/tutorials/index.html | 25 + .../tcpsocket/index.html" | 140 + files/zh-tw/glossary/404/index.html | 16 + files/zh-tw/glossary/502/index.html | 20 + files/zh-tw/glossary/abstraction/index.html | 14 + files/zh-tw/glossary/accessibility/index.html | 31 + files/zh-tw/glossary/adobe_flash/index.html | 28 + files/zh-tw/glossary/ajax/index.html | 25 + files/zh-tw/glossary/algorithm/index.html | 6 + files/zh-tw/glossary/api/index.html | 34 + files/zh-tw/glossary/apple_safari/index.html | 27 + files/zh-tw/glossary/argument/index.html | 24 + files/zh-tw/glossary/aria/index.html | 17 + files/zh-tw/glossary/arpa/index.html | 18 + files/zh-tw/glossary/arpanet/index.html | 17 + files/zh-tw/glossary/array/index.html | 31 + files/zh-tw/glossary/ascii/index.html | 16 + files/zh-tw/glossary/asynchronous/index.html | 19 + files/zh-tw/glossary/atag/index.html | 24 + files/zh-tw/glossary/attribute/index.html | 18 + files/zh-tw/glossary/bandwidth/index.html | 16 + files/zh-tw/glossary/blink/index.html | 20 + files/zh-tw/glossary/block/css/index.html | 22 + files/zh-tw/glossary/block/index.html | 13 + files/zh-tw/glossary/boolean/index.html | 52 + files/zh-tw/glossary/bootstrap/index.html | 16 + files/zh-tw/glossary/browser/index.html | 24 + files/zh-tw/glossary/browsing_context/index.html | 22 + files/zh-tw/glossary/buffer/index.html | 17 + files/zh-tw/glossary/cache/index.html | 14 + files/zh-tw/glossary/cacheable/index.html | 59 + files/zh-tw/glossary/callback_function/index.html | 36 + files/zh-tw/glossary/canvas/index.html | 34 + files/zh-tw/glossary/character/index.html | 22 + files/zh-tw/glossary/character_encoding/index.html | 25 + files/zh-tw/glossary/character_set/index.html | 30 + files/zh-tw/glossary/chrome/index.html | 8 + files/zh-tw/glossary/cipher_suite/index.html | 25 + files/zh-tw/glossary/ciphertext/index.html | 18 + files/zh-tw/glossary/class/index.html | 22 + files/zh-tw/glossary/closure/index.html | 23 + files/zh-tw/glossary/cms/index.html | 14 + files/zh-tw/glossary/compile/index.html | 23 + files/zh-tw/glossary/compile_time/index.html | 19 + .../zh-tw/glossary/computer_programming/index.html | 20 + files/zh-tw/glossary/constructor/index.html | 41 + files/zh-tw/glossary/continuous_media/index.html | 11 + files/zh-tw/glossary/cookie/index.html | 21 + files/zh-tw/glossary/cors/index.html | 49 + files/zh-tw/glossary/crawler/index.html | 12 + files/zh-tw/glossary/crud/index.html | 14 + files/zh-tw/glossary/cryptography/index.html | 20 + files/zh-tw/glossary/csp/index.html | 25 + files/zh-tw/glossary/csrf/index.html | 23 + files/zh-tw/glossary/css/index.html | 49 + files/zh-tw/glossary/css_pixel/index.html | 24 + files/zh-tw/glossary/css_preprocessor/index.html | 26 + files/zh-tw/glossary/css_selector/index.html | 60 + files/zh-tw/glossary/cssom/index.html | 18 + files/zh-tw/glossary/data_structure/index.html | 14 + files/zh-tw/glossary/developer_tools/index.html | 29 + files/zh-tw/glossary/dhtml/index.html | 7 + files/zh-tw/glossary/dns/index.html | 18 + files/zh-tw/glossary/doctype/index.html | 22 + files/zh-tw/glossary/document_directive/index.html | 35 + files/zh-tw/glossary/dom/index.html | 29 + files/zh-tw/glossary/domain/index.html | 16 + files/zh-tw/glossary/domain_name/index.html | 18 + files/zh-tw/glossary/dos_attack/index.html | 34 + files/zh-tw/glossary/ecma/index.html | 20 + files/zh-tw/glossary/ecmascript/index.html | 22 + files/zh-tw/glossary/element/index.html | 20 + files/zh-tw/glossary/empty_element/index.html | 33 + files/zh-tw/glossary/engine/index.html | 17 + files/zh-tw/glossary/event/index.html | 24 + files/zh-tw/glossary/firefox_os/index.html | 23 + files/zh-tw/glossary/firewall/index.html | 20 + .../zh-tw/glossary/first-class_function/index.html | 98 + .../glossary/first_contentful_paint/index.html | 15 + files/zh-tw/glossary/first_cpu_idle/index.html | 6 + files/zh-tw/glossary/first_input_delay/index.html | 15 + files/zh-tw/glossary/ftp/index.html | 20 + files/zh-tw/glossary/git/index.html | 15 + files/zh-tw/glossary/grid/index.html | 71 + files/zh-tw/glossary/hash/index.html | 17 + files/zh-tw/glossary/head/index.html | 19 + files/zh-tw/glossary/hoisting/index.html | 72 + files/zh-tw/glossary/host/index.html | 20 + files/zh-tw/glossary/html/index.html | 51 + files/zh-tw/glossary/html5/index.html | 16 + files/zh-tw/glossary/http/index.html | 13 + files/zh-tw/glossary/identifier/index.html | 19 + files/zh-tw/glossary/iife/index.html | 69 + files/zh-tw/glossary/immutable/index.html | 22 + files/zh-tw/glossary/index.html | 25 + files/zh-tw/glossary/indexeddb/index.html | 20 + files/zh-tw/glossary/ip_address/index.html | 21 + files/zh-tw/glossary/jank/index.html | 6 + files/zh-tw/glossary/java/index.html | 23 + files/zh-tw/glossary/javascript/index.html | 41 + files/zh-tw/glossary/jpeg/index.html | 14 + files/zh-tw/glossary/jquery/index.html | 42 + files/zh-tw/glossary/json/index.html | 29 + files/zh-tw/glossary/key/index.html | 20 + files/zh-tw/glossary/keyword/index.html | 19 + files/zh-tw/glossary/ligature/index.html | 16 + files/zh-tw/glossary/localization/index.html | 63 + files/zh-tw/glossary/mathml/index.html | 23 + files/zh-tw/glossary/mime_type/index.html | 32 + files/zh-tw/glossary/mvc/index.html | 28 + files/zh-tw/glossary/node.js/index.html | 22 + files/zh-tw/glossary/null/index.html | 26 + files/zh-tw/glossary/number/index.html | 27 + files/zh-tw/glossary/object/index.html | 18 + files/zh-tw/glossary/oop/index.html | 15 + files/zh-tw/glossary/opera_browser/index.html | 21 + files/zh-tw/glossary/parameter/index.html | 38 + files/zh-tw/glossary/php/index.html | 55 + files/zh-tw/glossary/png/index.html | 17 + files/zh-tw/glossary/pop/index.html | 22 + files/zh-tw/glossary/port/index.html | 23 + files/zh-tw/glossary/presto/index.html | 18 + .../glossary/progressive_enhancement/index.html | 14 + files/zh-tw/glossary/property/index.html | 13 + .../zh-tw/glossary/property/javascript/index.html | 22 + files/zh-tw/glossary/protocol/index.html | 21 + files/zh-tw/glossary/prototype/index.html | 16 + files/zh-tw/glossary/pseudo-element/index.html | 16 + files/zh-tw/glossary/python/index.html | 33 + files/zh-tw/glossary/recursion/index.html | 15 + files/zh-tw/glossary/reflow/index.html | 12 + files/zh-tw/glossary/regular_expression/index.html | 29 + .../glossary/responsive_web_design/index.html | 16 + files/zh-tw/glossary/rest/index.html | 26 + files/zh-tw/glossary/routers/index.html | 29 + files/zh-tw/glossary/ruby/index.html | 31 + files/zh-tw/glossary/seo/index.html | 40 + files/zh-tw/glossary/server/index.html | 19 + files/zh-tw/glossary/sgml/index.html | 21 + files/zh-tw/glossary/spa/index.html | 38 + files/zh-tw/glossary/sql/index.html | 21 + files/zh-tw/glossary/sql_injection/index.html | 63 + files/zh-tw/glossary/svg/index.html | 33 + files/zh-tw/glossary/svn/index.html | 24 + files/zh-tw/glossary/synchronous/index.html | 19 + files/zh-tw/glossary/type/index.html | 17 + files/zh-tw/glossary/uri/index.html | 15 + files/zh-tw/glossary/url/index.html | 35 + files/zh-tw/glossary/viewport/index.html | 25 + files/zh-tw/glossary/w3c/index.html | 19 + files/zh-tw/glossary/webextensions/index.html | 19 + files/zh-tw/glossary/websockets/index.html | 29 + .../zh-tw/html5_cross_browser_polyfills/index.html | 34 + .../introducing_the_audio_api_extension/index.html | 181 + files/zh-tw/learn/accessibility/index.html | 75 + files/zh-tw/learn/accessibility/mobile/index.html | 302 + .../learn/accessibility/wai-aria_basics/index.html | 421 + .../accessibility/what_is_accessibility/index.html | 201 + files/zh-tw/learn/common_questions/index.html | 135 + .../what_is_a_web_server/index.html | 116 + files/zh-tw/learn/css/css_layout/index.html | 71 + .../css/first_steps/getting_started/index.html | 265 + .../learn/css/first_steps/how_css_works/index.html | 156 + files/zh-tw/learn/css/first_steps/index.html | 59 + .../learn/css/first_steps/what_is_css/index.html | 131 + files/zh-tw/learn/css/index.html | 72 + files/zh-tw/learn/css/styling_text/index.html | 40 + .../css_basics/index.html | 273 + .../dealing_with_files/index.html | 117 + .../how_the_web_works/index.html | 101 + .../html_basics/index.html | 232 + .../learn/getting_started_with_the_web/index.html | 59 + .../installing_basic_software/index.html | 73 + .../javascript_basics/index.html | 440 + .../publishing_your_website/index.html | 116 + .../what_will_your_website_look_like/index.html | 108 + files/zh-tw/learn/how_to_contribute/index.html | 81 + .../forms/how_to_structure_an_html_form/index.html | 315 + files/zh-tw/learn/html/forms/index.html | 359 + files/zh-tw/learn/html/howto/index.html | 150 + files/zh-tw/learn/html/index.html | 61 + .../advanced_text_formatting/index.html | 456 + .../creating_hyperlinks/index.html | 326 + .../document_and_website_structure/index.html | 283 + .../getting_started/index.html | 626 ++ .../html_text_fundamentals/index.html | 953 ++ .../learn/html/introduction_to_html/index.html | 61 + .../the_head_metadata_in_html/index.html | 261 + .../index.html" | 502 ++ .../learn/html/multimedia_and_embedding/index.html | 53 + .../video_and_audio_content/index.html | 339 + .../index.html | 104 + .../index.html" | 386 + files/zh-tw/learn/html/tables/index.html | 34 + .../tables/\345\237\272\347\244\216/index.html" | 568 ++ files/zh-tw/learn/index.html | 238 + .../build_your_own_function/index.html | 246 + .../building_blocks/conditionals/index.html | 789 ++ .../building_blocks/functions/index.html | 396 + .../building_blocks/image_gallery/index.html | 135 + .../learn/javascript/building_blocks/index.html | 52 + .../building_blocks/looping_code/index.html | 928 ++ .../building_blocks/return_values/index.html | 172 + .../javascript/client-side_web_apis/index.html | 39 + .../manipulating_documents/index.html | 314 + .../first_steps/a_first_splash/index.html | 706 ++ .../learn/javascript/first_steps/arrays/index.html | 571 ++ .../zh-tw/learn/javascript/first_steps/index.html | 71 + .../learn/javascript/first_steps/math/index.html | 426 + .../first_steps/silly_story_generator/index.html | 149 + .../javascript/first_steps/strings/index.html | 352 + .../first_steps/useful_string_methods/index.html | 714 ++ .../javascript/first_steps/variables/index.html | 344 + .../first_steps/what_is_javascript/index.html | 425 + .../first_steps/what_went_wrong/index.html | 253 + files/zh-tw/learn/javascript/howto/index.html | 294 + files/zh-tw/learn/javascript/index.html | 71 + .../adding_bouncing_balls_features/index.html | 184 + .../learn/javascript/objects/basics/index.html | 243 + files/zh-tw/learn/javascript/objects/index.html | 42 + .../javascript/objects/inheritance/index.html | 210 + .../zh-tw/learn/javascript/objects/json/index.html | 325 + .../objects/object-oriented_js/index.html | 277 + .../objects/object_building_practice/index.html | 283 + .../objects/object_prototypes/index.html | 236 + files/zh-tw/learn/performance/index.html | 124 + .../index.html" | 130 + .../learn/server-side/django/admin_site/index.html | 354 + .../server-side/django/authentication/index.html | 698 ++ .../learn/server-side/django/deployment/index.html | 675 ++ .../django/development_environment/index.html | 429 + .../django/django_assessment_blog/index.html | 316 + .../learn/server-side/django/forms/index.html | 661 ++ .../server-side/django/generic_views/index.html | 612 ++ .../learn/server-side/django/home_page/index.html | 383 + files/zh-tw/learn/server-side/django/index.html | 115 + .../server-side/django/introduction/index.html | 306 + .../learn/server-side/django/models/index.html | 475 + .../learn/server-side/django/sessions/index.html | 185 + .../server-side/django/skeleton_website/index.html | 388 + .../learn/server-side/django/testing/index.html | 907 ++ .../tutorial_local_library_website/index.html | 92 + .../django/web_application_security/index.html | 180 + .../express_nodejs/deployment/index.html | 521 ++ .../development_environment/index.html | 385 + .../displaying_data/author_detail_page/index.html | 89 + .../displaying_data/author_list_page/index.html | 85 + .../displaying_data/book_detail_page/index.html | 112 + .../displaying_data/book_list_page/index.html | 72 + .../index.html | 91 + .../bookinstance_list_page/index.html | 71 + .../date_formatting_using_moment/index.html | 60 + .../flow_control_using_async/index.html | 137 + .../displaying_data/genre_detail_page/index.html | 123 + .../displaying_data/home_page/index.html | 133 + .../express_nodejs/displaying_data/index.html | 87 + .../locallibrary_base_template/index.html | 71 + .../displaying_data/template_primer/index.html | 149 + .../forms/create_author_form/index.html | 155 + .../forms/create_book_form/index.html | 214 + .../forms/create_bookinstance_form/index.html | 150 + .../forms/create_genre_form/index.html | 294 + .../forms/delete_author_form/index.html | 167 + .../server-side/express_nodejs/forms/index.html | 274 + .../learn/server-side/express_nodejs/index.html | 73 + .../express_nodejs/introduction/index.html | 522 ++ .../server-side/express_nodejs/mongoose/index.html | 792 ++ .../server-side/express_nodejs/routes/index.html | 646 ++ .../express_nodejs/skeleton_website/index.html | 506 ++ .../tutorial_local_library_website/index.html | 91 + .../zh-tw/learn/server-side/first_steps/index.html | 41 + .../\344\273\213\347\264\271/index.html" | 225 + files/zh-tw/learn/server-side/index.html | 59 + .../client-side_javascript_frameworks/index.html | 130 + .../introduction/index.html | 387 + .../react_todo_list_beginning/index.html | 614 ++ .../automated_testing/index.html | 372 + .../cross_browser_testing/index.html | 33 + files/zh-tw/learn/tools_and_testing/index.html | 31 + .../localization_quick_start_guide/index.html | 32 + .../initial_setup/index.html | 95 + files/zh-tw/mdn/about/index.html | 104 + files/zh-tw/mdn/community/index.html | 52 + .../community/\350\253\226\345\243\207/index.html" | 53 + .../mdn/contribute/getting_started/index.html | 105 + .../howto/create_an_mdn_account/index.html | 34 + .../howto/create_and_edit_pages/index.html | 144 + .../howto/do_a_technical_review/index.html | 50 + .../howto/do_an_editorial_review/index.html | 55 + files/zh-tw/mdn/contribute/howto/index.html | 14 + .../howto/set_the_summary_for_a_page/index.html | 50 + files/zh-tw/mdn/contribute/howto/tag/index.html | 374 + files/zh-tw/mdn/contribute/index.html | 20 + files/zh-tw/mdn/contribute/localize/index.html | 33 + .../localize/localization_projects/index.html | 1085 +++ .../localize/translating_pages/index.html | 52 + files/zh-tw/mdn/editor/basics/index.html | 55 + files/zh-tw/mdn/editor/edit_box/index.html | 134 + files/zh-tw/mdn/editor/index.html | 23 + files/zh-tw/mdn/guidelines/index.html | 13 + .../mdn/guidelines/writing_style_guide/index.html | 567 ++ files/zh-tw/mdn/index.html | 32 + files/zh-tw/mdn/kuma/index.html | 26 + files/zh-tw/mdn/tools/index.html | 15 + files/zh-tw/mdn/tools/kumascript/index.html | 490 ++ .../tools/kumascript/troubleshooting/index.html | 63 + files/zh-tw/mdn_at_ten/index.html | 37 + files/zh-tw/mercurial/index.html | 22 + .../mozilla/add-ons/add-on_debugger/index.html | 78 + .../mozilla/add-ons/add-on_guidelines/index.html | 117 + files/zh-tw/mozilla/add-ons/amo/index.html | 9 + files/zh-tw/mozilla/add-ons/amo/policy/index.html | 21 + .../index.html" | 24 + .../add-ons/firefox_for_android/api/index.html | 30 + .../mozilla/add-ons/firefox_for_android/index.html | 70 + files/zh-tw/mozilla/add-ons/index.html | 89 + files/zh-tw/mozilla/add-ons/sdk/builder/index.html | 13 + files/zh-tw/mozilla/add-ons/sdk/guides/index.html | 115 + .../sdk/high-level_apis/context-menu/index.html | 588 ++ .../mozilla/add-ons/sdk/high-level_apis/index.html | 10 + files/zh-tw/mozilla/add-ons/sdk/index.html | 82 + .../mozilla/add-ons/sdk/low-level_apis/index.html | 20 + .../mozilla/add-ons/themes/obsolete/index.html | 10 + .../anatomy_of_a_webextension/index.html | 139 + .../api/cookies/cookiestore/index.html | 80 + .../add-ons/webextensions/api/cookies/index.html | 163 + .../webextensions/api/cookies/onchanged/index.html | 118 + .../api/cookies/onchangedcause/index.html | 82 + .../mozilla/add-ons/webextensions/api/index.html | 53 + .../add-ons/webextensions/api/storage/index.html | 103 + .../webextensions/api/storage/local/index.html | 84 + .../api/storage/storagearea/get/index.html | 122 + .../api/storage/storagearea/index.html | 85 + .../webextensions/content_scripts/index.html | 444 + .../zh-tw/mozilla/add-ons/webextensions/index.html | 115 + .../webextensions/internationalization/index.html | 400 + .../webextensions/manifest.json/author/index.html | 44 + .../manifest.json/background/index.html | 93 + .../browser_specific_settings/index.html | 88 + .../manifest.json/homepage_url/index.html | 46 + .../add-ons/webextensions/manifest.json/index.html | 113 + .../manifest.json/options_ui/index.html | 110 + .../user_interface/browser_action/index.html | 50 + .../user_interface/context_menu_items/index.html | 54 + .../user_interface/devtools_panels/index.html | 66 + .../webextensions/user_interface/index.html | 94 + .../user_interface/sidebars/index.html | 55 + .../what_are_webextensions/index.html | 26 + .../your_first_webextension/index.html | 150 + .../your_second_webextension/index.html | 368 + .../index.html | 66 + files/zh-tw/mozilla/chrome_registration/index.html | 348 + files/zh-tw/mozilla/connect/index.html | 126 + .../mozilla/creating_mozsearch_plugins/index.html | 56 + files/zh-tw/mozilla/developer_guide/index.html | 92 + .../developer_guide/source_code/cvs/index.html | 182 + .../mozilla/developer_guide/source_code/index.html | 44 + .../mozilla/firefox/developer_edition/index.html | 56 + .../firefox/developer_edition/reverting/index.html | 25 + files/zh-tw/mozilla/firefox/index.html | 62 + .../firefox/multiprocess_firefox/index.html | 80 + files/zh-tw/mozilla/firefox/privacy/index.html | 9 + .../firefox/privacy/tracking_protection/index.html | 74 + .../zh-tw/mozilla/firefox/releases/1.5/index.html | 103 + files/zh-tw/mozilla/firefox/releases/10/index.html | 209 + files/zh-tw/mozilla/firefox/releases/11/index.html | 111 + .../2/adding_feed_readers_to_firefox/index.html | 36 + files/zh-tw/mozilla/firefox/releases/2/index.html | 89 + .../firefox/releases/2/security_changes/index.html | 29 + .../zh-tw/mozilla/firefox/releases/3.6/index.html | 301 + .../firefox/releases/3/dom_improvements/index.html | 26 + .../3/firefox_3_css_improvement/index.html | 30 + files/zh-tw/mozilla/firefox/releases/3/index.html | 93 + files/zh-tw/mozilla/firefox/releases/35/index.html | 130 + .../index.html" | 228 + files/zh-tw/mozilla/firefox/releases/4/index.html | 231 + files/zh-tw/mozilla/firefox/releases/5/index.html | 165 + files/zh-tw/mozilla/firefox/releases/6/index.html | 291 + files/zh-tw/mozilla/firefox/releases/61/index.html | 139 + files/zh-tw/mozilla/firefox/releases/68/index.html | 240 + files/zh-tw/mozilla/firefox/releases/7/index.html | 189 + files/zh-tw/mozilla/firefox/releases/8/index.html | 259 + files/zh-tw/mozilla/firefox/releases/9/index.html | 231 + files/zh-tw/mozilla/firefox/releases/index.html | 12 + .../gecko/chrome/api/browser_api/index.html | 158 + files/zh-tw/mozilla/gecko/chrome/api/index.html | 14 + files/zh-tw/mozilla/gecko/chrome/index.html | 15 + files/zh-tw/mozilla/gecko/index.html | 65 + files/zh-tw/mozilla/index.html | 11 + .../infallible_memory_allocation/index.html | 84 + .../introduction_to_layout_in_mozilla/index.html | 358 + .../mozilla/javascript_code_modules/index.html | 102 + .../javascript_code_modules/promise.jsm/index.html | 144 + .../promise.jsm/promise/index.html | 215 + files/zh-tw/mozilla/js-ctypes/index.html | 97 + files/zh-tw/mozilla/localization/index.html | 25 + .../localizing_with_pontoon/index.html | 135 + files/zh-tw/mozilla/mathml_project/index.html | 60 + .../mozilla/mathml_project/screenshots/index.html | 14 + .../\351\226\213\351\240\255/index.html" | 91 + .../performance/about_colon_memory/index.html | 188 + files/zh-tw/mozilla/performance/index.html | 130 + files/zh-tw/mozilla/preferences/index.html | 48 + .../preferences/preferences_system/index.html | 40 + .../preferences_system/new_attributes/index.html | 55 + files/zh-tw/mozilla/projects/index.html | 14 + .../nss/getting_started_with_nss/index.html | 58 + files/zh-tw/mozilla/projects/nss/index.html | 180 + files/zh-tw/mozilla/projects/rhino/index.html | 27 + .../mozilla/projects/rhino/license/index.html | 47 + .../mozilla/qa/bug_writing_guidelines/index.html | 246 + files/zh-tw/mozilla/qa/index.html | 251 + files/zh-tw/mozilla/rust/index.html | 40 + files/zh-tw/mozilla/tech/index.html | 14 + .../zh-tw/mozilla/tech/xpcom/reference/index.html | 27 + .../tech/xpcom/reference/interface/index.html | 19 + .../interface/nsicontentpolicy/index.html | 491 ++ .../autoconfiguration/fileformat/howto/index.html | 199 + .../autoconfiguration/fileformat/index.html | 10 + .../thunderbird/autoconfiguration/index.html | 113 + .../index.html | 26 + .../index.html | 260 + files/zh-tw/mozilla/thunderbird/index.html | 79 + .../thunderbird/thunderbird_extensions/index.html | 135 + .../theme_packaging/index.html | 105 + files/zh-tw/prism/index.html | 89 + .../index.html" | 21 + .../index.html" | 11 + files/zh-tw/profile_manager/index.html | 110 + files/zh-tw/python/index.html | 65 + files/zh-tw/sandbox/index.html | 180 + files/zh-tw/svg/tutorial/basic_shapes/index.html | 150 + files/zh-tw/tools/3d_view/index.html | 102 + files/zh-tw/tools/browser_toolbox/index.html | 41 + files/zh-tw/tools/debugger/how_to/index.html | 11 + .../debugger/how_to/open_the_debugger/index.html | 24 + .../debugger/how_to/set_a_breakpoint/index.html | 25 + files/zh-tw/tools/debugger/index.html | 58 + .../tools/firefox_os_1.1_simulator/index.html | 240 + files/zh-tw/tools/index.html | 192 + files/zh-tw/tools/network_monitor/index.html | 584 ++ .../how_to/examine_grid_layouts/index.html | 30 + files/zh-tw/tools/page_inspector/how_to/index.html | 11 + files/zh-tw/tools/page_inspector/index.html | 50 + .../zh-tw/tools/performance/allocations/index.html | 86 + .../zh-tw/tools/performance/frame_rate/index.html | 58 + files/zh-tw/tools/performance/index.html | 82 + .../firefox_for_android/index.html | 77 + files/zh-tw/tools/remote_debugging/index.html | 22 + .../zh-tw/tools/responsive_design_mode/index.html | 184 + files/zh-tw/tools/scratchpad/index.html | 109 + files/zh-tw/tools/settings/index.html | 185 + files/zh-tw/tools/style_editor/index.html | 103 + files/zh-tw/tools/web_audio_editor/index.html | 36 + .../tools/web_console/console_messages/index.html | 389 + files/zh-tw/tools/web_console/index.html | 37 + .../web_console/keyboard_shortcuts/index.html | 10 + .../web_console/opening_the_web_console/index.html | 23 + .../zh-tw/tools/web_console/rich_output/index.html | 75 + .../tools/web_console/split_console/index.html | 14 + .../the_command_line_interpreter/index.html | 121 + files/zh-tw/tools/webide/index.html | 290 + .../zh-tw/tools/webide/troubleshooting/index.html | 46 + .../accessibility/aria/aria_techniques/index.html | 164 + .../aria/forms/basic_form_hints/index.html | 119 + .../zh-tw/web/accessibility/aria/forms/index.html | 19 + files/zh-tw/web/accessibility/aria/index.html | 142 + files/zh-tw/web/accessibility/index.html | 61 + .../mobile_accessibility_checklist/index.html | 94 + files/zh-tw/web/api/abortcontroller/index.html | 97 + .../zh-tw/web/api/ambient_light_events/index.html | 96 + .../analysernode/getbytefrequencydata/index.html | 149 + files/zh-tw/web/api/analysernode/index.html | 226 + files/zh-tw/web/api/animationevent/index.html | 182 + .../animationevent/initanimationevent/index.html | 129 + files/zh-tw/web/api/battery_status_api/index.html | 38 + files/zh-tw/web/api/blob/blob/index.html | 125 + files/zh-tw/web/api/blob/index.html | 116 + files/zh-tw/web/api/blob/size/index.html | 114 + files/zh-tw/web/api/blob/type/index.html | 114 + files/zh-tw/web/api/body/index.html | 99 + files/zh-tw/web/api/body/json/index.html | 73 + .../drawing_graphics_with_canvas/index.html | 161 + files/zh-tw/web/api/canvas_api/index.html | 158 + .../tutorial/advanced_animations/index.html | 376 + .../tutorial/applying_styles_and_colors/index.html | 669 ++ .../tutorial/basic_animations/index.html | 347 + .../api/canvas_api/tutorial/basic_usage/index.html | 158 + .../api/canvas_api/tutorial/compositing/index.html | 207 + .../canvas_api/tutorial/drawing_shapes/index.html | 551 ++ .../canvas_api/tutorial/drawing_text/index.html | 397 + files/zh-tw/web/api/canvas_api/tutorial/index.html | 69 + .../tutorial/optimizing_canvas/index.html | 26 + .../pixel_manipulation_with_canvas/index.html | 265 + .../canvas_api/tutorial/transformations/index.html | 336 + .../canvas_api/tutorial/using_images/index.html | 342 + .../canvasrenderingcontext2d/clearrect/index.html | 189 + .../web/api/canvasrenderingcontext2d/index.html | 459 + .../zh-tw/web/api/channel_messaging_api/index.html | 158 + files/zh-tw/web/api/characterdata/index.html | 156 + files/zh-tw/web/api/childnode/index.html | 182 + files/zh-tw/web/api/clients/index.html | 113 + files/zh-tw/web/api/clipboardevent/index.html | 119 + files/zh-tw/web/api/console/assert/index.html | 118 + files/zh-tw/web/api/console/index.html | 289 + .../index.html | 33 + files/zh-tw/web/api/css_object_model/index.html | 131 + .../managing_screen_orientation/index.html | 172 + .../using_dynamic_styling_information/index.html | 132 + files/zh-tw/web/api/cssstyledeclaration/index.html | 90 + files/zh-tw/web/api/cssstylesheet/index.html | 187 + .../web/api/cssstylesheet/insertrule/index.html | 219 + .../web/api/customevent/customevent/index.html | 90 + files/zh-tw/web/api/customevent/index.html | 88 + files/zh-tw/web/api/datatransfer/index.html | 204 + .../api/detecting_device_orientation/index.html | 278 + files/zh-tw/web/api/devicemotionevent/index.html | 116 + .../web/api/deviceorientationevent/index.html | 122 + .../web/api/document.createtreewalker/index.html | 224 + files/zh-tw/web/api/document/body/index.html | 128 + .../api/document/createdocumentfragment/index.html | 136 + .../web/api/document/createelement/index.html | 179 + .../zh-tw/web/api/document/createrange/index.html | 33 + .../web/api/document/createtextnode/index.html | 120 + .../zh-tw/web/api/document/defaultview/index.html | 94 + files/zh-tw/web/api/document/designmode/index.html | 114 + .../web/api/document/documentelement/index.html | 60 + .../zh-tw/web/api/document/execcommand/index.html | 172 + files/zh-tw/web/api/document/forms/index.html | 75 + .../api/document/getelementsbyclassname/index.html | 127 + files/zh-tw/web/api/document/head/index.html | 114 + files/zh-tw/web/api/document/index.html | 446 + .../zh-tw/web/api/document/keyup_event/index.html | 149 + .../web/api/document/queryselector/index.html | 102 + files/zh-tw/web/api/document/readystate/index.html | 108 + .../web/api/document/registerelement/index.html | 113 + .../zh-tw/web/api/document/scroll_event/index.html | 103 + files/zh-tw/web/api/document/width/index.html | 45 + .../api/document_object_model/examples/index.html | 373 + .../how_to_create_a_dom_tree/index.html | 145 + .../zh-tw/web/api/document_object_model/index.html | 384 + .../document_object_model/whitespace/index.html | 183 + .../\344\272\213\344\273\266/index.html" | 69 + files/zh-tw/web/api/documentfragment/index.html | 248 + files/zh-tw/web/api/documenttype/index.html | 200 + files/zh-tw/web/api/domparser/index.html | 200 + files/zh-tw/web/api/domstring/index.html | 50 + files/zh-tw/web/api/domtokenlist/index.html | 117 + .../web/api/dragevent/datatransfer/index.html | 118 + files/zh-tw/web/api/dragevent/index.html | 160 + files/zh-tw/web/api/element/attributes/index.html | 121 + files/zh-tw/web/api/element/classlist/index.html | 403 + files/zh-tw/web/api/element/click_event/index.html | 205 + .../zh-tw/web/api/element/clientheight/index.html | 62 + .../zh-tw/web/api/element/getattribute/index.html | 71 + files/zh-tw/web/api/element/index.html | 674 ++ files/zh-tw/web/api/element/innerhtml/index.html | 215 + .../web/api/element/insertadjacenthtml/index.html | 135 + .../web/api/element/queryselectorall/index.html | 140 + .../zh-tw/web/api/element/scrollheight/index.html | 170 + files/zh-tw/web/api/element/scrolltop/index.html | 73 + .../web/api/element/touchcancel_event/index.html | 169 + files/zh-tw/web/api/errorevent/index.html | 148 + files/zh-tw/web/api/event/bubbles/index.html | 63 + .../event/comparison_of_event_targets/index.html | 164 + files/zh-tw/web/api/event/createevent/index.html | 29 + files/zh-tw/web/api/event/currenttarget/index.html | 70 + .../web/api/event/defaultprevented/index.html | 100 + files/zh-tw/web/api/event/event/index.html | 87 + files/zh-tw/web/api/event/eventphase/index.html | 179 + files/zh-tw/web/api/event/index.html | 210 + files/zh-tw/web/api/event/istrusted/index.html | 107 + .../zh-tw/web/api/event/preventdefault/index.html | 129 + .../api/event/stopimmediatepropagation/index.html | 94 + .../zh-tw/web/api/event/stoppropagation/index.html | 63 + files/zh-tw/web/api/event/target/index.html | 134 + files/zh-tw/web/api/event/timestamp/index.html | 54 + files/zh-tw/web/api/event/type/index.html | 97 + files/zh-tw/web/api/eventlistener/index.html | 93 + .../web/api/eventtarget/dispatchevent/index.html | 134 + files/zh-tw/web/api/eventtarget/index.html | 177 + .../api/eventtarget/removeeventlistener/index.html | 274 + files/zh-tw/web/api/fetch_api/index.html | 84 + .../zh-tw/web/api/fetch_api/using_fetch/index.html | 379 + files/zh-tw/web/api/file/file/index.html | 112 + files/zh-tw/web/api/file/filename/index.html | 32 + files/zh-tw/web/api/file/index.html | 121 + .../using_files_from_web_applications/index.html | 411 + files/zh-tw/web/api/file_handle_api/index.html | 233 + files/zh-tw/web/api/filelist/index.html | 149 + files/zh-tw/web/api/filereader/error/index.html | 102 + files/zh-tw/web/api/filereader/index.html | 213 + .../zh-tw/web/api/filereader/readystate/index.html | 98 + files/zh-tw/web/api/filesystem/index.html | 118 + files/zh-tw/web/api/formdata/get/index.html | 145 + files/zh-tw/web/api/formdata/index.html | 218 + .../api/formdata/using_formdata_objects/index.html | 137 + files/zh-tw/web/api/fullscreen_api/index.html | 240 + files/zh-tw/web/api/gainnode/gain/index.html | 113 + files/zh-tw/web/api/gainnode/index.html | 168 + .../web/api/geolocation/clearwatch/index.html | 132 + .../api/geolocation/getcurrentposition/index.html | 127 + files/zh-tw/web/api/geolocation/index.html | 118 + .../api/geolocation/using_geolocation/index.html | 251 + .../web/api/geolocation/watchposition/index.html | 143 + .../api/geolocationcoordinates/accuracy/index.html | 93 + .../api/geolocationcoordinates/altitude/index.html | 93 + .../altitudeaccuracy/index.html | 93 + .../api/geolocationcoordinates/heading/index.html | 93 + .../web/api/geolocationcoordinates/index.html | 113 + .../api/geolocationcoordinates/latitude/index.html | 93 + .../geolocationcoordinates/longitude/index.html | 93 + .../api/geolocationcoordinates/speed/index.html | 93 + .../web/api/geolocationposition/coords/index.html | 93 + files/zh-tw/web/api/geolocationposition/index.html | 103 + .../api/geolocationposition/timestamp/index.html | 93 + .../api/geolocationpositionerror/code/index.html | 120 + .../web/api/geolocationpositionerror/index.html | 128 + .../geolocationpositionerror/message/index.html | 93 + files/zh-tw/web/api/globaleventhandlers/index.html | 682 ++ .../web/api/globaleventhandlers/onclick/index.html | 144 + .../web/api/globaleventhandlers/onclose/index.html | 102 + files/zh-tw/web/api/history/index.html | 183 + files/zh-tw/web/api/history_api/index.html | 255 + .../drag_operations/index.html | 336 + .../web/api/html_drag_and_drop_api/index.html | 249 + files/zh-tw/web/api/htmlcanvaselement/index.html | 262 + .../web/api/htmlcanvaselement/todataurl/index.html | 201 + files/zh-tw/web/api/htmlcollection/index.html | 95 + files/zh-tw/web/api/htmldataelement/index.html | 59 + files/zh-tw/web/api/htmldocument/index.html | 16 + files/zh-tw/web/api/htmlelement/click/index.html | 115 + files/zh-tw/web/api/htmlelement/dataset/index.html | 167 + files/zh-tw/web/api/htmlelement/index.html | 447 + files/zh-tw/web/api/htmlelement/lang/index.html | 59 + files/zh-tw/web/api/htmlelement/style/index.html | 79 + files/zh-tw/web/api/htmlformelement/index.html | 245 + .../api/htmlformelement/submit_event/index.html | 60 + files/zh-tw/web/api/htmlimageelement/index.html | 408 + files/zh-tw/web/api/htmlinputelement/index.html | 592 ++ files/zh-tw/web/api/htmlmediaelement/index.html | 243 + .../htmlmediaelement/ratechange_event/index.html | 82 + .../web/api/htmlmediaelement/readystate/index.html | 110 + .../api/htmlselectelement/checkvalidity/index.html | 98 + files/zh-tw/web/api/htmlselectelement/index.html | 283 + .../htmlselectelement/setcustomvalidity/index.html | 50 + files/zh-tw/web/api/idbdatabase/index.html | 219 + files/zh-tw/web/api/index.html | 15 + .../basic_concepts_behind_indexeddb/index.html | 209 + files/zh-tw/web/api/indexeddb_api/index.html | 148 + .../api/indexeddb_api/using_indexeddb/index.html | 1085 +++ files/zh-tw/web/api/keyboardevent/index.html | 449 + .../web/api/keyboardevent/keyboardevent/index.html | 202 + files/zh-tw/web/api/media_streams_api/index.html | 87 + files/zh-tw/web/api/mediaquerylist/index.html | 144 + .../api/mediasource/activesourcebuffers/index.html | 126 + .../zh-tw/web/api/mediasource/duration/index.html | 149 + files/zh-tw/web/api/mediasource/index.html | 144 + .../web/api/mediasource/mediasource/index.html | 122 + .../web/api/mediasource/readystate/index.html | 136 + files/zh-tw/web/api/mouseevent/index.html | 317 + files/zh-tw/web/api/mutationobserver/index.html | 276 + files/zh-tw/web/api/namednodemap/index.html | 156 + .../zh-tw/web/api/navigator/geolocation/index.html | 96 + files/zh-tw/web/api/navigator/index.html | 154 + .../navigator/registerprotocolhandler/index.html | 170 + .../web-based_protocol_handlers/index.html | 28 + files/zh-tw/web/api/navigatoronline/index.html | 129 + .../online_and_offline_events/index.html | 101 + .../web/api/network_information_api/index.html | 46 + files/zh-tw/web/api/node/childnodes/index.html | 66 + files/zh-tw/web/api/node/clonenode/index.html | 160 + files/zh-tw/web/api/node/index.html | 529 ++ files/zh-tw/web/api/node/innertext/index.html | 86 + files/zh-tw/web/api/node/insertbefore/index.html | 167 + files/zh-tw/web/api/node/nodename/index.html | 102 + files/zh-tw/web/api/node/nodetype/index.html | 171 + files/zh-tw/web/api/node/ownerdocument/index.html | 111 + files/zh-tw/web/api/node/removechild/index.html | 133 + files/zh-tw/web/api/node/textcontent/index.html | 158 + files/zh-tw/web/api/nodelist/index.html | 219 + .../web/api/nondocumenttypechildnode/index.html | 125 + files/zh-tw/web/api/notification/index.html | 355 + files/zh-tw/web/api/notifications_api/index.html | 198 + .../using_the_notifications_api/index.html | 236 + files/zh-tw/web/api/parentnode/children/index.html | 152 + .../api/parentnode/firstelementchild/index.html | 95 + files/zh-tw/web/api/parentnode/index.html | 166 + files/zh-tw/web/api/payment_request_api/index.html | 117 + files/zh-tw/web/api/paymentrequest/index.html | 80 + files/zh-tw/web/api/performance.timing/index.html | 56 + files/zh-tw/web/api/performance/index.html | 140 + files/zh-tw/web/api/pointer_lock_api/index.html | 285 + .../positionoptions/enablehighaccuracy/index.html | 93 + files/zh-tw/web/api/positionoptions/index.html | 105 + .../web/api/positionoptions/maximumage/index.html | 93 + .../web/api/positionoptions/timeout/index.html | 93 + files/zh-tw/web/api/progressevent/index.html | 161 + files/zh-tw/web/api/proximity_events/index.html | 118 + files/zh-tw/web/api/range/index.html | 249 + files/zh-tw/web/api/response/index.html | 120 + files/zh-tw/web/api/screen/index.html | 89 + files/zh-tw/web/api/screen/orientation/index.html | 114 + files/zh-tw/web/api/server-sent_events/index.html | 115 + .../using_server-sent_events/index.html | 202 + files/zh-tw/web/api/storage/index.html | 106 + files/zh-tw/web/api/touch/index.html | 207 + files/zh-tw/web/api/touch_events/index.html | 387 + files/zh-tw/web/api/touchevent/index.html | 201 + files/zh-tw/web/api/touchlist/index.html | 120 + files/zh-tw/web/api/uievent/index.html | 188 + files/zh-tw/web/api/uievent/uievent/index.html | 134 + files/zh-tw/web/api/url/createobjecturl/index.html | 137 + files/zh-tw/web/api/url/index.html | 212 + files/zh-tw/web/api/validitystate/index.html | 145 + files/zh-tw/web/api/vibration_api/index.html | 113 + files/zh-tw/web/api/web_audio_api/index.html | 119 + .../api/web_video_text_tracks_format/index.html | 691 ++ files/zh-tw/web/api/web_workers_api/index.html | 215 + .../web_workers_api/using_web_workers/index.html | 791 ++ files/zh-tw/web/api/webgl_api/index.html | 255 + .../index.html | 280 + .../animating_objects_with_webgl/index.html | 55 + .../tutorial/getting_started_with_webgl/index.html | 73 + files/zh-tw/web/api/webgl_api/tutorial/index.html | 41 + .../index.html | 123 + files/zh-tw/web/api/webrtc_api/index.html | 193 + files/zh-tw/web/api/webvr_api/index.html | 246 + files/zh-tw/web/api/wheelevent/index.html | 196 + files/zh-tw/web/api/window.history/index.html | 51 + files/zh-tw/web/api/window.onpopstate/index.html | 57 + .../api/window.requestanimationframe/index.html | 94 + .../web/api/window/getcomputedstyle/index.html | 200 + files/zh-tw/web/api/window/index.html | 468 + files/zh-tw/web/api/window/localstorage/index.html | 82 + files/zh-tw/web/api/window/location/index.html | 373 + files/zh-tw/web/api/window/navigator/index.html | 58 + files/zh-tw/web/api/window/opener/index.html | 30 + .../api/window/orientationchange_event/index.html | 69 + files/zh-tw/web/api/window/print/index.html | 46 + .../web/api/window/requestidlecallback/index.html | 119 + .../zh-tw/web/api/window/sessionstorage/index.html | 94 + .../index.html | 35 + files/zh-tw/web/api/window/sidebar/index.html | 56 + files/zh-tw/web/api/windowbase64/index.html | 113 + files/zh-tw/web/api/windoweventhandlers/index.html | 182 + .../windoweventhandlers/onbeforeunload/index.html | 153 + .../api/windoworworkerglobalscope/btoa/index.html | 136 + .../web/api/windoworworkerglobalscope/index.html | 98 + .../setinterval/index.html | 627 ++ files/zh-tw/web/api/windowtimers/index.html | 114 + files/zh-tw/web/api/xmlhttprequest/index.html | 177 + .../xmlhttprequest/onreadystatechange/index.html | 113 + .../web/api/xmlhttprequest/readystate/index.html | 148 + .../api/xmlhttprequest/setrequestheader/index.html | 66 + .../zh-tw/web/api/xmlhttprequest/status/index.html | 115 + .../index.html | 260 + .../xmlhttprequest/using_xmlhttprequest/index.html | 766 ++ .../api/xmlhttprequest/withcredentials/index.html | 48 + .../api/xmlhttprequest/xmlhttprequest/index.html | 50 + .../web/api/xmlhttprequesteventtarget/index.html | 111 + files/zh-tw/web/css/@font-face/index.html | 247 + files/zh-tw/web/css/@media/height/index.html | 77 + files/zh-tw/web/css/@media/index.html | 377 + files/zh-tw/web/css/@viewport/height/index.html | 120 + files/zh-tw/web/css/@viewport/index.html | 159 + files/zh-tw/web/css/_colon_first-child/index.html | 154 + .../zh-tw/web/css/_colon_first-of-type/index.html | 162 + files/zh-tw/web/css/_colon_lang/index.html | 98 + files/zh-tw/web/css/_colon_target/index.html | 275 + .../web/css/_doublecolon_first-letter/index.html | 206 + files/zh-tw/web/css/animation-fill-mode/index.html | 158 + files/zh-tw/web/css/attr()/index.html | 200 + .../zh-tw/web/css/background-attachment/index.html | 151 + files/zh-tw/web/css/background-color/index.html | 115 + .../web/css/border-image/border-image/index.html | 111 + files/zh-tw/web/css/border-image/index.html | 9 + files/zh-tw/web/css/border/index.html | 134 + files/zh-tw/web/css/box-shadow/index.html | 228 + files/zh-tw/web/css/box-sizing/index.html | 94 + files/zh-tw/web/css/clip/index.html | 174 + .../zh-tw/web/css/common_css_questions/index.html | 165 + files/zh-tw/web/css/css_animations/index.html | 136 + .../css_animations/using_css_animations/index.html | 334 + .../web/css/css_background_and_borders/index.html | 152 + .../using_css_multiple_backgrounds/index.html | 84 + files/zh-tw/web/css/css_box_model/index.html | 167 + .../mastering_margin_collapsing/index.html | 107 + .../css/css_colors/color_picker_tool/index.html | 3221 +++++++ files/zh-tw/web/css/css_colors/index.html | 119 + .../web/css/css_flexible_box_layout/index.html | 118 + .../using_css_flexible_boxes/index.html | 382 + .../basic_concepts_of_grid_layout/index.html | 715 ++ files/zh-tw/web/css/css_grid_layout/index.html | 252 + .../consistent_list_indentation/index.html | 67 + .../web/css/css_lists_and_counters/index.html | 127 + files/zh-tw/web/css/css_positioning/index.html | 108 + .../understanding_z_index/index.html | 40 + .../stacking_context_example_1/index.html | 139 + .../web/css/css_properties_reference/index.html | 317 + files/zh-tw/web/css/css_selectors/index.html | 123 + .../index.html | 62 + files/zh-tw/web/css/css_transitions/index.html | 110 + .../using_css_transitions/index.html | 384 + files/zh-tw/web/css/cursor/index.html | 306 + .../zh-tw/web/css/descendant_combinator/index.html | 121 + files/zh-tw/web/css/grid-row/index.html | 194 + .../zh-tw/web/css/grid-template-columns/index.html | 196 + files/zh-tw/web/css/grid-template/index.html | 197 + files/zh-tw/web/css/height/index.html | 234 + files/zh-tw/web/css/ime-mode/index.html | 56 + files/zh-tw/web/css/index.html | 100 + files/zh-tw/web/css/inheritance/index.html | 48 + files/zh-tw/web/css/line-break/index.html | 71 + files/zh-tw/web/css/media_queries/index.html | 112 + .../media_queries/testing_media_queries/index.html | 118 + files/zh-tw/web/css/object-fit/index.html | 217 + files/zh-tw/web/css/pseudo-classes/index.html | 129 + files/zh-tw/web/css/radial-gradient()/index.html | 183 + files/zh-tw/web/css/reference/index.html | 211 + files/zh-tw/web/css/replaced_element/index.html | 20 + files/zh-tw/web/css/ruby-position/index.html | 112 + .../zh-tw/web/css/shorthand_properties/index.html | 138 + files/zh-tw/web/css/syntax/index.html | 74 + files/zh-tw/web/css/transform-function/index.html | 894 ++ .../transform-function/translate3d()/index.html | 116 + files/zh-tw/web/css/transform-origin/index.html | 455 + files/zh-tw/web/css/transform/index.html | 159 + files/zh-tw/web/css/transition-duration/index.html | 342 + .../web/css/transition-timing-function/index.html | 605 ++ files/zh-tw/web/css/transition/index.html | 106 + files/zh-tw/web/css/type_selectors/index.html | 79 + files/zh-tw/web/css/white-space/index.html | 425 + files/zh-tw/web/css/width/index.html | 294 + .../web/demos_of_open_web_technologies/index.html | 144 + files/zh-tw/web/events/abort/index.html | 67 + files/zh-tw/web/events/domcontentloaded/index.html | 133 + files/zh-tw/web/events/index.html | 1928 ++++ files/zh-tw/web/events/load/index.html | 88 + .../web/guide/ajax/getting_started/index.html | 287 + files/zh-tw/web/guide/ajax/index.html | 119 + files/zh-tw/web/guide/api/index.html | 25 + files/zh-tw/web/guide/dom/index.html | 21 + .../creating_and_triggering_events/index.html | 144 + .../web/guide/events/event_handlers/index.html | 178 + files/zh-tw/web/guide/events/index.html | 52 + files/zh-tw/web/guide/graphics/index.html | 49 + .../web/guide/html/content_categories/index.html | 150 + .../web/guide/html/event_attributes/index.html | 84 + files/zh-tw/web/guide/html/html5/index.html | 112 + .../html/html5/introduction_to_html5/index.html | 40 + files/zh-tw/web/guide/index.html | 29 + .../introduction_to_web_development/index.html | 13 + files/zh-tw/web/guide/performance/index.html | 14 + files/zh-tw/web/guide/woff/index.html | 100 + .../writing_forward-compatible_websites/index.html | 70 + files/zh-tw/web/html/applying_color/index.html | 502 ++ files/zh-tw/web/html/attributes/index.html | 643 ++ .../zh-tw/web/html/block-level_elements/index.html | 130 + files/zh-tw/web/html/element/a/index.html | 313 + files/zh-tw/web/html/element/blink/index.html | 75 + files/zh-tw/web/html/element/blockquote/index.html | 149 + files/zh-tw/web/html/element/br/index.html | 130 + files/zh-tw/web/html/element/button/index.html | 355 + files/zh-tw/web/html/element/canvas/index.html | 193 + files/zh-tw/web/html/element/code/index.html | 138 + files/zh-tw/web/html/element/div/index.html | 95 + files/zh-tw/web/html/element/font/index.html | 45 + files/zh-tw/web/html/element/form/index.html | 191 + files/zh-tw/web/html/element/frameset/index.html | 39 + files/zh-tw/web/html/element/hr/index.html | 168 + files/zh-tw/web/html/element/index.html | 106 + files/zh-tw/web/html/element/input/index.html | 750 ++ .../zh-tw/web/html/element/input/submit/index.html | 211 + files/zh-tw/web/html/element/marquee/index.html | 112 + files/zh-tw/web/html/element/meter/index.html | 143 + files/zh-tw/web/html/element/nav/index.html | 107 + files/zh-tw/web/html/element/optgroup/index.html | 161 + files/zh-tw/web/html/element/picture/index.html | 156 + files/zh-tw/web/html/element/q/index.html | 103 + files/zh-tw/web/html/element/ruby/index.html | 93 + files/zh-tw/web/html/element/script/index.html | 202 + files/zh-tw/web/html/element/summary/index.html | 135 + files/zh-tw/web/html/element/table/index.html | 362 + files/zh-tw/web/html/element/template/index.html | 145 + files/zh-tw/web/html/element/time/index.html | 162 + files/zh-tw/web/html/forms_in_html/index.html | 83 + .../html/global_attributes/data-_star_/index.html | 114 + files/zh-tw/web/html/global_attributes/index.html | 474 + .../html/global_attributes/spellcheck/index.html | 39 + files/zh-tw/web/html/index.html | 105 + .../html/quirks_mode_and_standards_mode/index.html | 46 + files/zh-tw/web/html/reference/index.html | 22 + .../web/html/supported_media_formats/index.html | 466 + .../html/using_the_application_cache/index.html | 391 + files/zh-tw/web/http/authentication/index.html | 123 + files/zh-tw/web/http/basics_of_http/index.html | 51 + .../web/http/basics_of_http/mime_types/index.html | 324 + .../index.html | 372 + files/zh-tw/web/http/caching/index.html | 154 + files/zh-tw/web/http/cookies/index.html | 194 + .../http/cors/errors/corsdidnotsucceed/index.html | 22 + .../cors/errors/corsmissingalloworigin/index.html | 48 + .../errors/corsnotsupportingcredentials/index.html | 32 + files/zh-tw/web/http/cors/errors/index.html | 76 + files/zh-tw/web/http/cors/index.html | 549 ++ files/zh-tw/web/http/data_uris/index.html | 128 + files/zh-tw/web/http/headers/accept/index.html | 92 + files/zh-tw/web/http/headers/dnt/index.html | 83 + files/zh-tw/web/http/headers/index.html | 360 + files/zh-tw/web/http/headers/server/index.html | 73 + .../headers/strict-transport-security/index.html | 110 + files/zh-tw/web/http/headers/user-agent/index.html | 146 + .../web/http/headers/x-forwarded-for/index.html | 74 + .../web/http/headers/x-frame-options/index.html | 146 + files/zh-tw/web/http/index.html | 83 + .../zh-tw/web/http/link_prefetching_faq/index.html | 121 + files/zh-tw/web/http/methods/connect/index.html | 82 + files/zh-tw/web/http/methods/get/index.html | 69 + files/zh-tw/web/http/methods/index.html | 63 + files/zh-tw/web/http/methods/post/index.html | 124 + .../web/http/protocol_upgrade_mechanism/index.html | 152 + .../web/http/server-side_access_control/index.html | 212 + files/zh-tw/web/http/status/100/index.html | 42 + files/zh-tw/web/http/status/101/index.html | 46 + files/zh-tw/web/http/status/200/index.html | 50 + files/zh-tw/web/http/status/201/index.html | 43 + files/zh-tw/web/http/status/202/index.html | 33 + files/zh-tw/web/http/status/203/index.html | 37 + files/zh-tw/web/http/status/204/index.html | 49 + files/zh-tw/web/http/status/205/index.html | 39 + files/zh-tw/web/http/status/206/index.html | 79 + files/zh-tw/web/http/status/300/index.html | 38 + files/zh-tw/web/http/status/301/index.html | 54 + files/zh-tw/web/http/status/403/index.html | 49 + files/zh-tw/web/http/status/404/index.html | 59 + files/zh-tw/web/http/status/409/index.html | 35 + files/zh-tw/web/http/status/411/index.html | 38 + files/zh-tw/web/http/status/415/index.html | 39 + .../web/http/status/418_i_m_a_teapot/index.html | 45 + files/zh-tw/web/http/status/451/index.html | 65 + files/zh-tw/web/http/status/500/index.html | 43 + files/zh-tw/web/http/status/502/index.html | 57 + files/zh-tw/web/http/status/503/index.html | 67 + files/zh-tw/web/http/status/504/index.html | 46 + files/zh-tw/web/http/status/index.html | 191 + files/zh-tw/web/index.html | 101 + .../a_re-introduction_to_javascript/index.html | 910 ++ .../web/javascript/about_javascript/index.html | 69 + files/zh-tw/web/javascript/closures/index.html | 396 + .../web/javascript/data_structures/index.html | 294 + .../index.html | 259 + .../equality_comparisons_and_sameness/index.html | 431 + files/zh-tw/web/javascript/eventloop/index.html | 109 + .../control_flow_and_error_handling/index.html | 429 + .../guide/details_of_the_object_model/index.html | 720 ++ .../guide/expressions_and_operators/index.html | 934 ++ .../web/javascript/guide/functions/index.html | 442 + .../javascript/guide/grammar_and_types/index.html | 697 ++ files/zh-tw/web/javascript/guide/index.html | 116 + .../guide/indexed_collections/index.html | 450 + .../web/javascript/guide/introduction/index.html | 180 + .../guide/iterators_and_generators/index.html | 193 + .../javascript/guide/keyed_collections/index.html | 156 + .../guide/loops_and_iteration/index.html | 337 + .../javascript/guide/numbers_and_dates/index.html | 383 + .../guide/regular_expressions/index.html | 700 ++ .../web/javascript/guide/using_promises/index.html | 256 + .../guide/working_with_objects/index.html | 499 ++ files/zh-tw/web/javascript/index.html | 133 + .../inheritance_and_the_prototype_chain/index.html | 310 + .../index.html | 393 + .../javascript_technologies_overview/index.html | 80 + .../web/javascript/language_resources/index.html | 77 + .../web/javascript/memory_management/index.html | 204 + .../javascript/new_in_javascript/1.1/index.html | 71 + .../javascript/new_in_javascript/1.2/index.html | 89 + .../javascript/new_in_javascript/1.3/index.html | 138 + .../javascript/new_in_javascript/1.4/index.html | 25 + .../javascript/new_in_javascript/1.5/index.html | 37 + .../javascript/new_in_javascript/1.6/index.html | 87 + .../javascript/new_in_javascript/1.7/index.html | 600 ++ .../javascript/new_in_javascript/1.8.1/index.html | 41 + .../javascript/new_in_javascript/1.8.5/index.html | 132 + .../javascript/new_in_javascript/1.8/index.html | 125 + .../web/javascript/new_in_javascript/index.html | 71 + .../index.html" | 43 + .../index.html" | 11 + .../index.html" | 25 + .../index.html" | 105 + .../index.html" | 87 + .../index.html" | 13 + .../index.html" | 15 + .../index.html" | 18 + .../index.html" | 50 + .../obsolete_pages/unicode/index.html | 32 + .../index.html" | 27 + .../index.html" | 39 + .../throw_\350\252\236\346\263\225/index.html" | 34 + .../index.html" | 162 + .../obsolete_pages/\345\200\274/index.html" | 29 + .../index.html" | 13 + .../index.html" | 44 + .../index.html" | 55 + .../index.html" | 56 + .../index.html" | 40 + .../index.html" | 33 + .../index.html" | 42 + .../index.html" | 33 + .../index.html" | 117 + .../\345\270\270\346\225\270/index.html" | 27 + .../index.html" | 9 + .../break_\350\252\236\346\263\225/index.html" | 27 + .../continue_\350\252\236\346\263\225/index.html" | 49 + .../index.html" | 22 + .../for_\350\252\236\346\263\225/index.html" | 53 + .../index.html" | 15 + .../label_\350\252\236\346\263\225/index.html" | 22 + .../while_\350\252\236\346\263\225/index.html" | 38 + .../index.html" | 110 + .../index.html" | 18 + .../index.html" | 27 + .../index.html" | 21 + .../index.html" | 58 + .../index.html" | 40 + .../index.html" | 23 + .../index.html" | 10 + .../index.html" | 12 + .../index.html" | 103 + .../index.html" | 184 + .../index.html" | 34 + .../index.html" | 58 + .../index.html" | 35 + .../index.html" | 42 + .../index.html" | 114 + .../index.html" | 42 + .../index.html" | 53 + .../\347\271\274\346\211\277/index.html" | 146 + .../index.html" | 31 + .../index.html" | 143 + .../index.html" | 14 + .../index.html" | 19 + .../index.html" | 24 + .../index.html" | 135 + .../index.html" | 15 + .../\350\250\273\350\247\243/index.html" | 20 + .../\350\256\212\346\225\270/index.html" | 56 + .../index.html" | 293 + .../index.html" | 29 + .../index.html" | 64 + .../index.html" | 30 + .../index.html" | 11 + .../index.html" | 14 + .../index.html" | 185 + .../index.html" | 19 + .../index.html" | 42 + .../index.html" | 227 + .../\351\227\234\346\226\274/index.html" | 47 + .../index.html" | 451 + .../index.html" | 19 + .../eval_\345\207\275\346\225\270/index.html" | 16 + .../index.html" | 14 + .../isfinite_\345\207\275\346\225\270/index.html" | 23 + .../isnan_\345\207\275\346\225\270/index.html" | 25 + .../index.html" | 34 + .../index.html" | 21 + .../array_\347\211\251\344\273\266/index.html" | 151 + .../boolean_\347\211\251\344\273\266/index.html" | 12 + .../date_\347\211\251\344\273\266/index.html" | 82 + .../function_\347\211\251\344\273\266/index.html" | 45 + .../index.html" | 12 + .../math_\347\211\251\344\273\266/index.html" | 69 + .../number_\347\211\251\344\273\266/index.html" | 80 + .../regexp_\347\211\251\344\273\266/index.html" | 9 + .../string_\347\211\251\344\273\266/index.html" | 88 + .../reference/classes/constructor/index.html | 157 + .../reference/classes/extends/index.html | 108 + .../web/javascript/reference/classes/index.html | 362 + .../javascript/reference/classes/static/index.html | 123 + .../errors/bad_return_or_yield/index.html | 51 + .../web/javascript/reference/errors/index.html | 22 + .../errors/invalid_array_length/index.html | 74 + .../missing_curly_after_property_list/index.html | 47 + .../reference/errors/no_properties/index.html | 36 + .../reference/errors/not_a_function/index.html | 80 + .../reference/errors/not_defined/index.html | 67 + .../errors/redeclared_parameter/index.html | 57 + .../reference/errors/too_much_recursion/index.html | 50 + .../reference/errors/unexpected_type/index.html | 49 + .../functions/arguments/callee/index.html | 197 + .../reference/functions/arguments/index.html | 235 + .../reference/functions/arrow_functions/index.html | 340 + .../functions/default_parameters/index.html | 292 + .../javascript/reference/functions/get/index.html | 170 + .../web/javascript/reference/functions/index.html | 617 ++ .../functions/method_definitions/index.html | 213 + .../reference/functions/rest_parameters/index.html | 155 + .../javascript/reference/functions/set/index.html | 138 + .../global_objects/array/@@iterator/index.html | 89 + .../global_objects/array/concat/index.html | 157 + .../global_objects/array/copywithin/index.html | 156 + .../global_objects/array/entries/index.html | 86 + .../global_objects/array/every/index.html | 191 + .../reference/global_objects/array/fill/index.html | 156 + .../global_objects/array/filter/index.html | 238 + .../reference/global_objects/array/find/index.html | 204 + .../global_objects/array/findindex/index.html | 181 + .../reference/global_objects/array/flat/index.html | 148 + .../global_objects/array/foreach/index.html | 297 + .../reference/global_objects/array/from/index.html | 215 + .../global_objects/array/includes/index.html | 175 + .../reference/global_objects/array/index.html | 457 + .../global_objects/array/indexof/index.html | 260 + .../global_objects/array/isarray/index.html | 134 + .../reference/global_objects/array/join/index.html | 109 + .../reference/global_objects/array/keys/index.html | 76 + .../global_objects/array/lastindexof/index.html | 168 + .../global_objects/array/length/index.html | 131 + .../reference/global_objects/array/map/index.html | 320 + .../reference/global_objects/array/of/index.html | 98 + .../reference/global_objects/array/pop/index.html | 98 + .../reference/global_objects/array/push/index.html | 143 + .../global_objects/array/reduce/index.html | 472 + .../global_objects/array/reverse/index.html | 90 + .../global_objects/array/shift/index.html | 114 + .../global_objects/array/slice/index.html | 242 + .../reference/global_objects/array/some/index.html | 217 + .../reference/global_objects/array/sort/index.html | 248 + .../global_objects/array/splice/index.html | 150 + .../global_objects/array/unshift/index.html | 101 + .../global_objects/array/values/index.html | 77 + .../global_objects/arraybuffer/index.html | 225 + .../arraybuffer/prototype/index.html | 110 + .../global_objects/asyncfunction/index.html | 118 + .../reference/global_objects/bigint/index.html | 279 + .../reference/global_objects/boolean/index.html | 199 + .../reference/global_objects/dataview/index.html | 173 + .../global_objects/date/getday/index.html | 72 + .../reference/global_objects/date/index.html | 263 + .../reference/global_objects/date/now/index.html | 123 + .../global_objects/date/prototype/index.html | 245 + .../reference/global_objects/date/utc/index.html | 157 + .../global_objects/error/columnnumber/index.html | 81 + .../reference/global_objects/error/index.html | 233 + .../global_objects/function/apply/index.html | 260 + .../global_objects/function/bind/index.html | 321 + .../global_objects/function/call/index.html | 105 + .../reference/global_objects/function/index.html | 191 + .../global_objects/function/length/index.html | 144 + .../global_objects/function/prototype/index.html | 138 + .../javascript/reference/global_objects/index.html | 201 + .../reference/global_objects/infinity/index.html | 76 + .../reference/global_objects/isnan/index.html | 183 + .../reference/global_objects/json/index.html | 206 + .../reference/global_objects/json/parse/index.html | 170 + .../global_objects/json/stringify/index.html | 280 + .../reference/global_objects/map/index.html | 265 + .../reference/global_objects/math/abs/index.html | 104 + .../reference/global_objects/math/ceil/index.html | 170 + .../reference/global_objects/math/floor/index.html | 169 + .../reference/global_objects/math/index.html | 196 + .../reference/global_objects/math/max/index.html | 117 + .../reference/global_objects/math/pow/index.html | 107 + .../global_objects/math/random/index.html | 95 + .../reference/global_objects/math/round/index.html | 212 + .../reference/global_objects/nan/index.html | 85 + .../reference/global_objects/null/index.html | 124 + .../reference/global_objects/number/index.html | 219 + .../global_objects/number/isfinite/index.html | 93 + .../global_objects/number/isnan/index.html | 99 + .../global_objects/number/prototype/index.html | 84 + .../global_objects/number/toexponential/index.html | 164 + .../global_objects/number/tofixed/index.html | 108 + .../global_objects/object/assign/index.html | 249 + .../global_objects/object/create/index.html | 258 + .../object/defineproperties/index.html | 224 + .../object/defineproperty/index.html | 380 + .../global_objects/object/freeze/index.html | 198 + .../object/getprototypeof/index.html | 128 + .../object/hasownproperty/index.html | 184 + .../reference/global_objects/object/index.html | 222 + .../global_objects/object/keys/index.html | 208 + .../object/preventextensions/index.html | 179 + .../global_objects/object/proto/index.html | 137 + .../global_objects/object/prototype/index.html | 218 + .../global_objects/object/watch/index.html | 191 + .../reference/global_objects/parseint/index.html | 193 + .../global_objects/promise/all/index.html | 207 + .../global_objects/promise/catch/index.html | 189 + .../global_objects/promise/finally/index.html | 102 + .../reference/global_objects/promise/index.html | 256 + .../global_objects/promise/prototype/index.html | 64 + .../global_objects/promise/race/index.html | 171 + .../global_objects/promise/reject/index.html | 72 + .../global_objects/promise/resolve/index.html | 142 + .../global_objects/promise/then/index.html | 271 + .../reference/global_objects/proxy/index.html | 400 + .../reference/global_objects/rangeerror/index.html | 152 + .../reference/global_objects/reflect/index.html | 130 + .../reference/global_objects/regexp/index.html | 269 + .../reference/global_objects/set/add/index.html | 83 + .../reference/global_objects/set/clear/index.html | 79 + .../reference/global_objects/set/delete/index.html | 98 + .../global_objects/set/entries/index.html | 78 + .../reference/global_objects/set/has/index.html | 92 + .../reference/global_objects/set/index.html | 243 + .../reference/global_objects/set/values/index.html | 79 + .../reference/global_objects/string/index.html | 328 + .../global_objects/string/match/index.html | 151 + .../global_objects/string/padstart/index.html | 96 + .../global_objects/string/prototype/index.html | 176 + .../global_objects/string/replace/index.html | 286 + .../global_objects/string/tolowercase/index.html | 77 + .../reference/global_objects/typedarray/index.html | 268 + .../reference/global_objects/undefined/index.html | 136 + .../reference/global_objects/urierror/index.html | 131 + files/zh-tw/web/javascript/reference/index.html | 300 + .../reference/iteration_protocols/index.html | 351 + .../reference/lexical_grammar/index.html | 548 ++ .../operators/arithmetic_operators/index.html | 308 + .../reference/operators/async_function/index.html | 111 + .../reference/operators/await/index.html | 152 + .../operators/bitwise_operators/index.html | 554 ++ .../reference/operators/comma_operator/index.html | 145 + .../operators/comparison_operators/index.html | 283 + .../operators/conditional_operator/index.html | 101 + .../operators/destructuring_assignment/index.html | 423 + .../web/javascript/reference/operators/index.html | 301 + .../operators/logical_operators/index.html | 243 + .../operators/object_initializer/index.html | 431 + .../operators/operator_precedence/index.html | 316 + .../operators/optional_chaining/index.html | 195 + .../reference/operators/spread_syntax/index.html | 248 + .../reference/operators/super/index.html | 179 + .../javascript/reference/operators/this/index.html | 385 + .../reference/operators/typeof/index.html | 177 + .../reference/statements/async_function/index.html | 163 + .../reference/statements/block/index.html | 86 + .../reference/statements/break/index.html | 120 + .../reference/statements/const/index.html | 129 + .../reference/statements/debugger/index.html | 75 + .../reference/statements/export/index.html | 165 + .../reference/statements/for...in/index.html | 116 + .../reference/statements/function_star_/index.html | 207 + .../reference/statements/if...else/index.html | 169 + .../reference/statements/import/index.html | 203 + .../web/javascript/reference/statements/index.html | 147 + .../reference/statements/label/index.html | 203 + .../javascript/reference/statements/let/index.html | 246 + .../reference/statements/return/index.html | 156 + .../reference/statements/switch/index.html | 309 + .../reference/statements/throw/index.html | 234 + .../javascript/reference/statements/var/index.html | 248 + .../javascript/reference/strict_mode/index.html | 369 + .../reference/template_literals/index.html | 252 + files/zh-tw/web/javascript/shells/index.html | 42 + files/zh-tw/web/javascript/typed_arrays/index.html | 227 + files/zh-tw/web/manifest/index.html | 327 + files/zh-tw/web/mathml/authoring/index.html | 285 + files/zh-tw/web/mathml/index.html | 107 + .../zh-tw/web/media/formats/containers/index.html | 1325 +++ files/zh-tw/web/media/formats/index.html | 88 + files/zh-tw/web/media/index.html | 64 + files/zh-tw/web/opensearch/index.html | 179 + files/zh-tw/web/progressive_web_apps/index.html | 77 + files/zh-tw/web/reference/api/index.html | 59 + files/zh-tw/web/reference/index.html | 29 + files/zh-tw/web/security/index.html | 16 + .../web/security/insecure_passwords/index.html | 76 + .../index.html | 29 + files/zh-tw/web/security/mixed_content/index.html | 80 + .../web/security/same-origin_policy/index.html | 117 + .../security/weak_signature_algorithm/index.html | 16 + files/zh-tw/web/svg/attribute/fill-rule/index.html | 46 + files/zh-tw/web/svg/attribute/index.html | 386 + .../web/svg/attribute/stroke-dashoffset/index.html | 75 + files/zh-tw/web/svg/index.html | 22 + .../web/svg/tutorial/fills_and_strokes/index.html | 184 + .../web/svg/tutorial/getting_started/index.html | 91 + files/zh-tw/web/svg/tutorial/gradients/index.html | 148 + files/zh-tw/web/svg/tutorial/index.html | 51 + .../zh-tw/web/svg/tutorial/introduction/index.html | 26 + files/zh-tw/web/svg/tutorial/patterns/index.html | 54 + files/zh-tw/web/svg/tutorial/positions/index.html | 51 + .../tutorial/\350\267\257\345\276\204/index.html" | 239 + .../web/svg/\346\225\231\345\255\270/index.html" | 13 + files/zh-tw/web/tutorials/index.html | 247 + .../zh-tw/web/\346\200\247\350\203\275/index.html" | 481 + files/zh-tw/web_development/index.html | 5 + .../historical_artifacts_to_avoid/index.html" | 89 + .../zh-tw/web_\351\226\213\347\231\274/index.html" | 15 + files/zh-tw/webapi/alarm/index.html | 196 + files/zh-tw/webapi/camera/index.html | 20 + files/zh-tw/webapi/contacts/index.html | 197 + files/zh-tw/webapi/device_storage/index.html | 228 + files/zh-tw/webapi/idle/index.html | 61 + files/zh-tw/webapi/index.html | 126 + files/zh-tw/webapi/network_stats/index.html | 86 + files/zh-tw/webapi/permissions/index.html | 85 + files/zh-tw/webapi/power_management/index.html | 102 + files/zh-tw/webapi/settings/index.html | 69 + files/zh-tw/webapi/simple_push/index.html | 115 + files/zh-tw/webapi/tcp_socket/index.html | 69 + files/zh-tw/webapi/time_and_clock/index.html | 30 + files/zh-tw/webapi/web_activities/index.html | 415 + files/zh-tw/webapi/webfm_api/index.html | 130 + files/zh-tw/webapi/websms/index.html | 130 + files/zh-tw/webassembly/index.html | 118 + files/zh-tw/websockets/index.html | 155 + .../websockets_reference/closeevent/index.html | 145 + .../websockets/websockets_reference/index.html | 25 + .../websockets_reference/messageevent/index.html | 80 + .../websockets_reference/websocket/index.html | 276 + .../index.html | 179 + files/zh-tw/xhtml/index.html | 29 + files/zh-tw/xpcnativewrapper/index.html | 237 + files/zh-tw/xpcom/index.html | 47 + .../zh-tw/xul_\346\225\231\345\255\270/index.html" | 136 + files/zh-tw/zh-tw/index.html | 5 + files/zh-tw/zones/index.html | 53 + .../index.html" | 32 + .../background/index.html" | 102 + .../index.html" | 97 + .../index.html" | 10 + .../index.html" | 6 + .../index.html" | 23 + .../contents.rdf/index.html" | 48 + .../index.html" | 38 + .../install.rdf/index.html" | 47 + .../uuid/index.html" | 16 + .../index.html" | 117 + 1487 files changed, 235448 insertions(+) create mode 100644 files/zh-tw/_redirects.txt create mode 100644 files/zh-tw/_wikihistory.json create mode 100644 files/zh-tw/archive/add-ons/developing_add-ons/index.html create mode 100644 files/zh-tw/archive/add-ons/index.html create mode 100644 files/zh-tw/archive/add-ons/supporting_search_suggestions_in_search_plugins/index.html create mode 100644 files/zh-tw/archive/add-ons/working_with_multiprocess_firefox/index.html create mode 100644 files/zh-tw/archive/apps/advanced_topics/index.html create mode 100644 files/zh-tw/archive/apps/index.html create mode 100644 files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/contacts/index.html create mode 100644 files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/device_storage/index.html create mode 100644 files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/geolocation/index.html create mode 100644 files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/index.html create mode 100644 files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/web_activity/index.html create mode 100644 "files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/\345\260\201\345\214\205\345\274\217_(packaged)_app/index.html" create mode 100644 "files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/\346\211\230\347\256\241\346\233\264\346\226\260\344\275\234\346\245\255_(hosting_updates)_/index.html" create mode 100644 files/zh-tw/archive/b2g_os/add-ons/index.html create mode 100644 files/zh-tw/archive/b2g_os/api/fmradio/index.html create mode 100644 files/zh-tw/archive/b2g_os/api/index.html create mode 100644 files/zh-tw/archive/b2g_os/apps/index.html create mode 100644 files/zh-tw/archive/b2g_os/apps/writing_a_web_app_for_b2g/index.html create mode 100644 files/zh-tw/archive/b2g_os/architecture/index.html create mode 100644 files/zh-tw/archive/b2g_os/automated_testing/gaia-ui-tests/gaia_ui_tests_run_tests/index.html create mode 100644 files/zh-tw/archive/b2g_os/automated_testing/gaia-ui-tests/index.html create mode 100644 files/zh-tw/archive/b2g_os/automated_testing/index.html create mode 100644 files/zh-tw/archive/b2g_os/building/index.html create mode 100644 files/zh-tw/archive/b2g_os/building_and_installing_firefox_os/firefox_os_build_process_summary/index.html create mode 100644 files/zh-tw/archive/b2g_os/building_and_installing_firefox_os/index.html create mode 100644 files/zh-tw/archive/b2g_os/choosing_how_to_run_gaia_or_b2g/index.html create mode 100644 files/zh-tw/archive/b2g_os/debugging/index.html create mode 100644 files/zh-tw/archive/b2g_os/firefox_os_build_prerequisites/index.html create mode 100644 files/zh-tw/archive/b2g_os/index.html create mode 100644 files/zh-tw/archive/b2g_os/installing_boot_to_gecko_on_a_mobile_device/index.html create mode 100644 files/zh-tw/archive/b2g_os/introduction/index.html create mode 100644 files/zh-tw/archive/b2g_os/phone_guide/flame/index.html create mode 100644 files/zh-tw/archive/b2g_os/phone_guide/index.html create mode 100644 files/zh-tw/archive/b2g_os/phone_guide/zte_open/index.html create mode 100644 files/zh-tw/archive/b2g_os/platform/apps_architecture/index.html create mode 100644 files/zh-tw/archive/b2g_os/platform/gaia/gaia_apps/index.html create mode 100644 files/zh-tw/archive/b2g_os/platform/gaia/index.html create mode 100644 files/zh-tw/archive/b2g_os/platform/gaia/introduction_to_gaia/index.html create mode 100644 files/zh-tw/archive/b2g_os/platform/gonk/index.html create mode 100644 files/zh-tw/archive/b2g_os/platform/index.html create mode 100644 files/zh-tw/archive/b2g_os/platform/out_of_memory_management_on_firefox_os/index.html create mode 100644 files/zh-tw/archive/b2g_os/preparing_for_your_first_b2g_build/index.html create mode 100644 files/zh-tw/archive/b2g_os/quickstart/app_tools/index.html create mode 100644 files/zh-tw/archive/b2g_os/quickstart/index.html create mode 100644 files/zh-tw/archive/b2g_os/quickstart/your_first_app/index.html create mode 100644 files/zh-tw/archive/b2g_os/releases/1.2/index.html create mode 100644 files/zh-tw/archive/b2g_os/releases/index.html create mode 100644 files/zh-tw/archive/b2g_os/running_custom_builds_in_the_app_manager/index.html create mode 100644 files/zh-tw/archive/b2g_os/screencast_series_colon__app_basics_for_firefox_os/index.html create mode 100644 files/zh-tw/archive/b2g_os/security/application_security/index.html create mode 100644 files/zh-tw/archive/b2g_os/security/index.html create mode 100644 files/zh-tw/archive/b2g_os/security/security_model/index.html create mode 100644 files/zh-tw/archive/b2g_os/security/system_security/index.html create mode 100644 files/zh-tw/archive/b2g_os/simulator/index.html create mode 100644 files/zh-tw/archive/b2g_os/simulator/simulator_walkthrough/index.html create mode 100644 files/zh-tw/archive/b2g_os/using_the_app_manager/index.html create mode 100644 files/zh-tw/archive/b2g_os/using_the_b2g_desktop_client/index.html create mode 100644 files/zh-tw/archive/b2g_os/using_the_b2g_emulators/index.html create mode 100644 files/zh-tw/archive/b2g_os/web_telephony_api/index.html create mode 100644 files/zh-tw/archive/b2g_os/writing_apps_for_boot_to_gecko/index.html create mode 100644 files/zh-tw/archive/css3/index.html create mode 100644 files/zh-tw/archive/index.html create mode 100644 files/zh-tw/archive/mdn/index.html create mode 100644 files/zh-tw/archive/mdn/persona_sign-ins/index.html create mode 100644 files/zh-tw/archive/meta_docs/custom_classes/index.html create mode 100644 files/zh-tw/archive/meta_docs/index.html create mode 100644 files/zh-tw/archive/misc_top_level/creating_a_web_based_tone_generator/index.html create mode 100644 files/zh-tw/archive/misc_top_level/index.html create mode 100644 files/zh-tw/archive/misc_top_level/same-origin_policy_for_file_colon__uris/index.html create mode 100644 files/zh-tw/archive/mozilla/creating_a_microsummary/index.html create mode 100644 files/zh-tw/archive/mozilla/drag_and_drop/index.html create mode 100644 files/zh-tw/archive/mozilla/firefox/index.html create mode 100644 files/zh-tw/archive/mozilla/firefox/using_microformats/index.html create mode 100644 files/zh-tw/archive/mozilla/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/apis/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/faq/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/marketplace_apis/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/monetization/app_payments_guide/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/monetization/app_pricing/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/monetization/in-app_payments/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/monetization/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/monetization/introduction_monetization/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/monetization/payments_status/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/monetization/profiting_from_your_app/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/monetization/validating_a_receipt/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/options/hosted_apps/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/adding_a_subdomain/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/creating_a_store/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/introduction/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/managing_your_apps/app_statistics/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/marketplace_screenshot_criteria/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/packaged_apps/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/policies_and_guidelines/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/policies_and_guidelines/introduction/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/pricing/introduction/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/pricing/payment_accounts/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/pricing/promote_as_upgrade_to_free_version/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/privacy_policies/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/publish_options/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/submission_checklist/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/submit/enter_your_apps_details/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/submit/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/submit/load_your_app/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/submit/next_steps/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/submit/overview/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/submit/sign-in_to_your_developer_account/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/publishing/updating_apps/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/submission/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/submission/marketplace_review_criteria/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/submission/pre-submission_checklist/index.html create mode 100644 files/zh-tw/archive/mozilla/marketplace/submission/rating_your_content/index.html create mode 100644 files/zh-tw/archive/mozilla/migrate_apps_from_internet_explorer_to_mozilla/index.html create mode 100644 files/zh-tw/archive/mozilla/persona/branding/index.html create mode 100644 files/zh-tw/archive/mozilla/persona/index.html create mode 100644 files/zh-tw/archive/mozilla/persona/internationalization/index.html create mode 100644 files/zh-tw/archive/mozilla/persona/quick_setup/index.html create mode 100644 files/zh-tw/archive/mozilla/persona/remote_verification_api/index.html create mode 100644 files/zh-tw/archive/mozilla/persona/why_persona/index.html create mode 100644 files/zh-tw/archive/mozilla/xpinstall/index.html create mode 100644 files/zh-tw/archive/mozilla/xpinstall/scripting_by_example/index.html create mode 100644 files/zh-tw/archive/mozilla/xul/index.html create mode 100644 files/zh-tw/archive/mozilla/xul/template_guide/index.html create mode 100644 files/zh-tw/archive/mozilla/xul/the_joy_of_xul/index.html create mode 100644 files/zh-tw/archive/mozilla/xul/xul_reference/index.html create mode 100644 files/zh-tw/archive/mozilla/xulrunner/index.html create mode 100644 files/zh-tw/archive/mozilla/xulrunner/xulrunner_tips/index.html create mode 100644 files/zh-tw/archive/themes/index.html create mode 100644 files/zh-tw/archive/web/e4x/index.html create mode 100644 files/zh-tw/archive/web/e4x/processing_xml_with_e4x/index.html create mode 100644 files/zh-tw/archive/web/index.html create mode 100644 files/zh-tw/archive/web_standards/index.html create mode 100644 files/zh-tw/archive/web_standards/rdf_in_fifty_words_or_less/index.html create mode 100644 files/zh-tw/code_snippets/index.html create mode 100644 files/zh-tw/code_snippets/tabbed_browser/index.html create mode 100644 "files/zh-tw/core_javascript_1.5_\346\255\243\350\246\217\350\241\250\351\201\224\345\274\217\347\232\204\345\273\272\347\253\213/index.html" create mode 100644 files/zh-tw/cross-site_xmlhttprequest/index.html create mode 100644 "files/zh-tw/dom_\350\247\200\345\257\237\345\231\250/index.html" create mode 100644 files/zh-tw/dragdrop/index.html create mode 100644 files/zh-tw/extensions/index.html create mode 100644 files/zh-tw/extensions/using_the_dom_file_api_in_chrome_code/index.html create mode 100644 "files/zh-tw/firefox_2_\344\275\210\346\231\257\344\270\273\351\241\214\344\271\213\346\233\264\345\213\225/index.html" create mode 100644 "files/zh-tw/firefox_3.5_\346\212\200\350\241\223\346\226\207\344\273\266/index.html" create mode 100644 files/zh-tw/firefox_3_animated_png_support/index.html create mode 100644 files/zh-tw/firefox_3_drag_and_drop_events/index.html create mode 100644 "files/zh-tw/firefox_\344\270\255\347\232\204\351\233\242\347\267\232\350\263\207\346\272\220/index.html" create mode 100644 files/zh-tw/games/index.html create mode 100644 files/zh-tw/games/introduction/index.html create mode 100644 files/zh-tw/games/techniques/index.html create mode 100644 files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.html create mode 100644 files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.html create mode 100644 files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/index.html create mode 100644 files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.html create mode 100644 files/zh-tw/games/tutorials/index.html create mode 100644 "files/zh-tw/gecko_dom_\345\217\203\350\200\203/tcpsocket/index.html" create mode 100644 files/zh-tw/glossary/404/index.html create mode 100644 files/zh-tw/glossary/502/index.html create mode 100644 files/zh-tw/glossary/abstraction/index.html create mode 100644 files/zh-tw/glossary/accessibility/index.html create mode 100644 files/zh-tw/glossary/adobe_flash/index.html create mode 100644 files/zh-tw/glossary/ajax/index.html create mode 100644 files/zh-tw/glossary/algorithm/index.html create mode 100644 files/zh-tw/glossary/api/index.html create mode 100644 files/zh-tw/glossary/apple_safari/index.html create mode 100644 files/zh-tw/glossary/argument/index.html create mode 100644 files/zh-tw/glossary/aria/index.html create mode 100644 files/zh-tw/glossary/arpa/index.html create mode 100644 files/zh-tw/glossary/arpanet/index.html create mode 100644 files/zh-tw/glossary/array/index.html create mode 100644 files/zh-tw/glossary/ascii/index.html create mode 100644 files/zh-tw/glossary/asynchronous/index.html create mode 100644 files/zh-tw/glossary/atag/index.html create mode 100644 files/zh-tw/glossary/attribute/index.html create mode 100644 files/zh-tw/glossary/bandwidth/index.html create mode 100644 files/zh-tw/glossary/blink/index.html create mode 100644 files/zh-tw/glossary/block/css/index.html create mode 100644 files/zh-tw/glossary/block/index.html create mode 100644 files/zh-tw/glossary/boolean/index.html create mode 100644 files/zh-tw/glossary/bootstrap/index.html create mode 100644 files/zh-tw/glossary/browser/index.html create mode 100644 files/zh-tw/glossary/browsing_context/index.html create mode 100644 files/zh-tw/glossary/buffer/index.html create mode 100644 files/zh-tw/glossary/cache/index.html create mode 100644 files/zh-tw/glossary/cacheable/index.html create mode 100644 files/zh-tw/glossary/callback_function/index.html create mode 100644 files/zh-tw/glossary/canvas/index.html create mode 100644 files/zh-tw/glossary/character/index.html create mode 100644 files/zh-tw/glossary/character_encoding/index.html create mode 100644 files/zh-tw/glossary/character_set/index.html create mode 100644 files/zh-tw/glossary/chrome/index.html create mode 100644 files/zh-tw/glossary/cipher_suite/index.html create mode 100644 files/zh-tw/glossary/ciphertext/index.html create mode 100644 files/zh-tw/glossary/class/index.html create mode 100644 files/zh-tw/glossary/closure/index.html create mode 100644 files/zh-tw/glossary/cms/index.html create mode 100644 files/zh-tw/glossary/compile/index.html create mode 100644 files/zh-tw/glossary/compile_time/index.html create mode 100644 files/zh-tw/glossary/computer_programming/index.html create mode 100644 files/zh-tw/glossary/constructor/index.html create mode 100644 files/zh-tw/glossary/continuous_media/index.html create mode 100644 files/zh-tw/glossary/cookie/index.html create mode 100644 files/zh-tw/glossary/cors/index.html create mode 100644 files/zh-tw/glossary/crawler/index.html create mode 100644 files/zh-tw/glossary/crud/index.html create mode 100644 files/zh-tw/glossary/cryptography/index.html create mode 100644 files/zh-tw/glossary/csp/index.html create mode 100644 files/zh-tw/glossary/csrf/index.html create mode 100644 files/zh-tw/glossary/css/index.html create mode 100644 files/zh-tw/glossary/css_pixel/index.html create mode 100644 files/zh-tw/glossary/css_preprocessor/index.html create mode 100644 files/zh-tw/glossary/css_selector/index.html create mode 100644 files/zh-tw/glossary/cssom/index.html create mode 100644 files/zh-tw/glossary/data_structure/index.html create mode 100644 files/zh-tw/glossary/developer_tools/index.html create mode 100644 files/zh-tw/glossary/dhtml/index.html create mode 100644 files/zh-tw/glossary/dns/index.html create mode 100644 files/zh-tw/glossary/doctype/index.html create mode 100644 files/zh-tw/glossary/document_directive/index.html create mode 100644 files/zh-tw/glossary/dom/index.html create mode 100644 files/zh-tw/glossary/domain/index.html create mode 100644 files/zh-tw/glossary/domain_name/index.html create mode 100644 files/zh-tw/glossary/dos_attack/index.html create mode 100644 files/zh-tw/glossary/ecma/index.html create mode 100644 files/zh-tw/glossary/ecmascript/index.html create mode 100644 files/zh-tw/glossary/element/index.html create mode 100644 files/zh-tw/glossary/empty_element/index.html create mode 100644 files/zh-tw/glossary/engine/index.html create mode 100644 files/zh-tw/glossary/event/index.html create mode 100644 files/zh-tw/glossary/firefox_os/index.html create mode 100644 files/zh-tw/glossary/firewall/index.html create mode 100644 files/zh-tw/glossary/first-class_function/index.html create mode 100644 files/zh-tw/glossary/first_contentful_paint/index.html create mode 100644 files/zh-tw/glossary/first_cpu_idle/index.html create mode 100644 files/zh-tw/glossary/first_input_delay/index.html create mode 100644 files/zh-tw/glossary/ftp/index.html create mode 100644 files/zh-tw/glossary/git/index.html create mode 100644 files/zh-tw/glossary/grid/index.html create mode 100644 files/zh-tw/glossary/hash/index.html create mode 100644 files/zh-tw/glossary/head/index.html create mode 100644 files/zh-tw/glossary/hoisting/index.html create mode 100644 files/zh-tw/glossary/host/index.html create mode 100644 files/zh-tw/glossary/html/index.html create mode 100644 files/zh-tw/glossary/html5/index.html create mode 100644 files/zh-tw/glossary/http/index.html create mode 100644 files/zh-tw/glossary/identifier/index.html create mode 100644 files/zh-tw/glossary/iife/index.html create mode 100644 files/zh-tw/glossary/immutable/index.html create mode 100644 files/zh-tw/glossary/index.html create mode 100644 files/zh-tw/glossary/indexeddb/index.html create mode 100644 files/zh-tw/glossary/ip_address/index.html create mode 100644 files/zh-tw/glossary/jank/index.html create mode 100644 files/zh-tw/glossary/java/index.html create mode 100644 files/zh-tw/glossary/javascript/index.html create mode 100644 files/zh-tw/glossary/jpeg/index.html create mode 100644 files/zh-tw/glossary/jquery/index.html create mode 100644 files/zh-tw/glossary/json/index.html create mode 100644 files/zh-tw/glossary/key/index.html create mode 100644 files/zh-tw/glossary/keyword/index.html create mode 100644 files/zh-tw/glossary/ligature/index.html create mode 100644 files/zh-tw/glossary/localization/index.html create mode 100644 files/zh-tw/glossary/mathml/index.html create mode 100644 files/zh-tw/glossary/mime_type/index.html create mode 100644 files/zh-tw/glossary/mvc/index.html create mode 100644 files/zh-tw/glossary/node.js/index.html create mode 100644 files/zh-tw/glossary/null/index.html create mode 100644 files/zh-tw/glossary/number/index.html create mode 100644 files/zh-tw/glossary/object/index.html create mode 100644 files/zh-tw/glossary/oop/index.html create mode 100644 files/zh-tw/glossary/opera_browser/index.html create mode 100644 files/zh-tw/glossary/parameter/index.html create mode 100644 files/zh-tw/glossary/php/index.html create mode 100644 files/zh-tw/glossary/png/index.html create mode 100644 files/zh-tw/glossary/pop/index.html create mode 100644 files/zh-tw/glossary/port/index.html create mode 100644 files/zh-tw/glossary/presto/index.html create mode 100644 files/zh-tw/glossary/progressive_enhancement/index.html create mode 100644 files/zh-tw/glossary/property/index.html create mode 100644 files/zh-tw/glossary/property/javascript/index.html create mode 100644 files/zh-tw/glossary/protocol/index.html create mode 100644 files/zh-tw/glossary/prototype/index.html create mode 100644 files/zh-tw/glossary/pseudo-element/index.html create mode 100644 files/zh-tw/glossary/python/index.html create mode 100644 files/zh-tw/glossary/recursion/index.html create mode 100644 files/zh-tw/glossary/reflow/index.html create mode 100644 files/zh-tw/glossary/regular_expression/index.html create mode 100644 files/zh-tw/glossary/responsive_web_design/index.html create mode 100644 files/zh-tw/glossary/rest/index.html create mode 100644 files/zh-tw/glossary/routers/index.html create mode 100644 files/zh-tw/glossary/ruby/index.html create mode 100644 files/zh-tw/glossary/seo/index.html create mode 100644 files/zh-tw/glossary/server/index.html create mode 100644 files/zh-tw/glossary/sgml/index.html create mode 100644 files/zh-tw/glossary/spa/index.html create mode 100644 files/zh-tw/glossary/sql/index.html create mode 100644 files/zh-tw/glossary/sql_injection/index.html create mode 100644 files/zh-tw/glossary/svg/index.html create mode 100644 files/zh-tw/glossary/svn/index.html create mode 100644 files/zh-tw/glossary/synchronous/index.html create mode 100644 files/zh-tw/glossary/type/index.html create mode 100644 files/zh-tw/glossary/uri/index.html create mode 100644 files/zh-tw/glossary/url/index.html create mode 100644 files/zh-tw/glossary/viewport/index.html create mode 100644 files/zh-tw/glossary/w3c/index.html create mode 100644 files/zh-tw/glossary/webextensions/index.html create mode 100644 files/zh-tw/glossary/websockets/index.html create mode 100644 files/zh-tw/html5_cross_browser_polyfills/index.html create mode 100644 files/zh-tw/introducing_the_audio_api_extension/index.html create mode 100644 files/zh-tw/learn/accessibility/index.html create mode 100644 files/zh-tw/learn/accessibility/mobile/index.html create mode 100644 files/zh-tw/learn/accessibility/wai-aria_basics/index.html create mode 100644 files/zh-tw/learn/accessibility/what_is_accessibility/index.html create mode 100644 files/zh-tw/learn/common_questions/index.html create mode 100644 files/zh-tw/learn/common_questions/what_is_a_web_server/index.html create mode 100644 files/zh-tw/learn/css/css_layout/index.html create mode 100644 files/zh-tw/learn/css/first_steps/getting_started/index.html create mode 100644 files/zh-tw/learn/css/first_steps/how_css_works/index.html create mode 100644 files/zh-tw/learn/css/first_steps/index.html create mode 100644 files/zh-tw/learn/css/first_steps/what_is_css/index.html create mode 100644 files/zh-tw/learn/css/index.html create mode 100644 files/zh-tw/learn/css/styling_text/index.html create mode 100644 files/zh-tw/learn/getting_started_with_the_web/css_basics/index.html create mode 100644 files/zh-tw/learn/getting_started_with_the_web/dealing_with_files/index.html create mode 100644 files/zh-tw/learn/getting_started_with_the_web/how_the_web_works/index.html create mode 100644 files/zh-tw/learn/getting_started_with_the_web/html_basics/index.html create mode 100644 files/zh-tw/learn/getting_started_with_the_web/index.html create mode 100644 files/zh-tw/learn/getting_started_with_the_web/installing_basic_software/index.html create mode 100644 files/zh-tw/learn/getting_started_with_the_web/javascript_basics/index.html create mode 100644 files/zh-tw/learn/getting_started_with_the_web/publishing_your_website/index.html create mode 100644 files/zh-tw/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html create mode 100644 files/zh-tw/learn/how_to_contribute/index.html create mode 100644 files/zh-tw/learn/html/forms/how_to_structure_an_html_form/index.html create mode 100644 files/zh-tw/learn/html/forms/index.html create mode 100644 files/zh-tw/learn/html/howto/index.html create mode 100644 files/zh-tw/learn/html/index.html create mode 100644 files/zh-tw/learn/html/introduction_to_html/advanced_text_formatting/index.html create mode 100644 files/zh-tw/learn/html/introduction_to_html/creating_hyperlinks/index.html create mode 100644 files/zh-tw/learn/html/introduction_to_html/document_and_website_structure/index.html create mode 100644 files/zh-tw/learn/html/introduction_to_html/getting_started/index.html create mode 100644 files/zh-tw/learn/html/introduction_to_html/html_text_fundamentals/index.html create mode 100644 files/zh-tw/learn/html/introduction_to_html/index.html create mode 100644 files/zh-tw/learn/html/introduction_to_html/the_head_metadata_in_html/index.html create mode 100644 "files/zh-tw/learn/html/multimedia_and_embedding/html\344\270\255\347\232\204\345\234\226\347\211\207/index.html" create mode 100644 files/zh-tw/learn/html/multimedia_and_embedding/index.html create mode 100644 files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/index.html create mode 100644 files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/test_your_skills_colon__multimedia_and_embedding/index.html create mode 100644 "files/zh-tw/learn/html/multimedia_and_embedding/\345\205\266\344\273\226_\345\265\214\345\205\245_\346\212\200\350\241\223/index.html" create mode 100644 files/zh-tw/learn/html/tables/index.html create mode 100644 "files/zh-tw/learn/html/tables/\345\237\272\347\244\216/index.html" create mode 100644 files/zh-tw/learn/index.html create mode 100644 files/zh-tw/learn/javascript/building_blocks/build_your_own_function/index.html create mode 100644 files/zh-tw/learn/javascript/building_blocks/conditionals/index.html create mode 100644 files/zh-tw/learn/javascript/building_blocks/functions/index.html create mode 100644 files/zh-tw/learn/javascript/building_blocks/image_gallery/index.html create mode 100644 files/zh-tw/learn/javascript/building_blocks/index.html create mode 100644 files/zh-tw/learn/javascript/building_blocks/looping_code/index.html create mode 100644 files/zh-tw/learn/javascript/building_blocks/return_values/index.html create mode 100644 files/zh-tw/learn/javascript/client-side_web_apis/index.html create mode 100644 files/zh-tw/learn/javascript/client-side_web_apis/manipulating_documents/index.html create mode 100644 files/zh-tw/learn/javascript/first_steps/a_first_splash/index.html create mode 100644 files/zh-tw/learn/javascript/first_steps/arrays/index.html create mode 100644 files/zh-tw/learn/javascript/first_steps/index.html create mode 100644 files/zh-tw/learn/javascript/first_steps/math/index.html create mode 100644 files/zh-tw/learn/javascript/first_steps/silly_story_generator/index.html create mode 100644 files/zh-tw/learn/javascript/first_steps/strings/index.html create mode 100644 files/zh-tw/learn/javascript/first_steps/useful_string_methods/index.html create mode 100644 files/zh-tw/learn/javascript/first_steps/variables/index.html create mode 100644 files/zh-tw/learn/javascript/first_steps/what_is_javascript/index.html create mode 100644 files/zh-tw/learn/javascript/first_steps/what_went_wrong/index.html create mode 100644 files/zh-tw/learn/javascript/howto/index.html create mode 100644 files/zh-tw/learn/javascript/index.html create mode 100644 files/zh-tw/learn/javascript/objects/adding_bouncing_balls_features/index.html create mode 100644 files/zh-tw/learn/javascript/objects/basics/index.html create mode 100644 files/zh-tw/learn/javascript/objects/index.html create mode 100644 files/zh-tw/learn/javascript/objects/inheritance/index.html create mode 100644 files/zh-tw/learn/javascript/objects/json/index.html create mode 100644 files/zh-tw/learn/javascript/objects/object-oriented_js/index.html create mode 100644 files/zh-tw/learn/javascript/objects/object_building_practice/index.html create mode 100644 files/zh-tw/learn/javascript/objects/object_prototypes/index.html create mode 100644 files/zh-tw/learn/performance/index.html create mode 100644 "files/zh-tw/learn/performance/\345\244\232\345\252\222\351\253\224/index.html" create mode 100644 files/zh-tw/learn/server-side/django/admin_site/index.html create mode 100644 files/zh-tw/learn/server-side/django/authentication/index.html create mode 100644 files/zh-tw/learn/server-side/django/deployment/index.html create mode 100644 files/zh-tw/learn/server-side/django/development_environment/index.html create mode 100644 files/zh-tw/learn/server-side/django/django_assessment_blog/index.html create mode 100644 files/zh-tw/learn/server-side/django/forms/index.html create mode 100644 files/zh-tw/learn/server-side/django/generic_views/index.html create mode 100644 files/zh-tw/learn/server-side/django/home_page/index.html create mode 100644 files/zh-tw/learn/server-side/django/index.html create mode 100644 files/zh-tw/learn/server-side/django/introduction/index.html create mode 100644 files/zh-tw/learn/server-side/django/models/index.html create mode 100644 files/zh-tw/learn/server-side/django/sessions/index.html create mode 100644 files/zh-tw/learn/server-side/django/skeleton_website/index.html create mode 100644 files/zh-tw/learn/server-side/django/testing/index.html create mode 100644 files/zh-tw/learn/server-side/django/tutorial_local_library_website/index.html create mode 100644 files/zh-tw/learn/server-side/django/web_application_security/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/deployment/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/development_environment/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_detail_page/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_detail_page/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_detail_page_and_challenge/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/home_page/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/displaying_data/template_primer/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/forms/create_author_form/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/forms/create_book_form/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/forms/create_genre_form/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/forms/delete_author_form/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/forms/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/introduction/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/mongoose/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/routes/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/skeleton_website/index.html create mode 100644 files/zh-tw/learn/server-side/express_nodejs/tutorial_local_library_website/index.html create mode 100644 files/zh-tw/learn/server-side/first_steps/index.html create mode 100644 "files/zh-tw/learn/server-side/first_steps/\344\273\213\347\264\271/index.html" create mode 100644 files/zh-tw/learn/server-side/index.html create mode 100644 files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/index.html create mode 100644 files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/introduction/index.html create mode 100644 files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/react_todo_list_beginning/index.html create mode 100644 files/zh-tw/learn/tools_and_testing/cross_browser_testing/automated_testing/index.html create mode 100644 files/zh-tw/learn/tools_and_testing/cross_browser_testing/index.html create mode 100644 files/zh-tw/learn/tools_and_testing/index.html create mode 100644 files/zh-tw/localization_quick_start_guide/index.html create mode 100644 files/zh-tw/localization_quick_start_guide/initial_setup/index.html create mode 100644 files/zh-tw/mdn/about/index.html create mode 100644 files/zh-tw/mdn/community/index.html create mode 100644 "files/zh-tw/mdn/community/\350\253\226\345\243\207/index.html" create mode 100644 files/zh-tw/mdn/contribute/getting_started/index.html create mode 100644 files/zh-tw/mdn/contribute/howto/create_an_mdn_account/index.html create mode 100644 files/zh-tw/mdn/contribute/howto/create_and_edit_pages/index.html create mode 100644 files/zh-tw/mdn/contribute/howto/do_a_technical_review/index.html create mode 100644 files/zh-tw/mdn/contribute/howto/do_an_editorial_review/index.html create mode 100644 files/zh-tw/mdn/contribute/howto/index.html create mode 100644 files/zh-tw/mdn/contribute/howto/set_the_summary_for_a_page/index.html create mode 100644 files/zh-tw/mdn/contribute/howto/tag/index.html create mode 100644 files/zh-tw/mdn/contribute/index.html create mode 100644 files/zh-tw/mdn/contribute/localize/index.html create mode 100644 files/zh-tw/mdn/contribute/localize/localization_projects/index.html create mode 100644 files/zh-tw/mdn/contribute/localize/translating_pages/index.html create mode 100644 files/zh-tw/mdn/editor/basics/index.html create mode 100644 files/zh-tw/mdn/editor/edit_box/index.html create mode 100644 files/zh-tw/mdn/editor/index.html create mode 100644 files/zh-tw/mdn/guidelines/index.html create mode 100644 files/zh-tw/mdn/guidelines/writing_style_guide/index.html create mode 100644 files/zh-tw/mdn/index.html create mode 100644 files/zh-tw/mdn/kuma/index.html create mode 100644 files/zh-tw/mdn/tools/index.html create mode 100644 files/zh-tw/mdn/tools/kumascript/index.html create mode 100644 files/zh-tw/mdn/tools/kumascript/troubleshooting/index.html create mode 100644 files/zh-tw/mdn_at_ten/index.html create mode 100644 files/zh-tw/mercurial/index.html create mode 100644 files/zh-tw/mozilla/add-ons/add-on_debugger/index.html create mode 100644 files/zh-tw/mozilla/add-ons/add-on_guidelines/index.html create mode 100644 files/zh-tw/mozilla/add-ons/amo/index.html create mode 100644 files/zh-tw/mozilla/add-ons/amo/policy/index.html create mode 100644 "files/zh-tw/mozilla/add-ons/amo/policy/\350\201\257\347\265\241\350\263\207\350\250\212/index.html" create mode 100644 files/zh-tw/mozilla/add-ons/firefox_for_android/api/index.html create mode 100644 files/zh-tw/mozilla/add-ons/firefox_for_android/index.html create mode 100644 files/zh-tw/mozilla/add-ons/index.html create mode 100644 files/zh-tw/mozilla/add-ons/sdk/builder/index.html create mode 100644 files/zh-tw/mozilla/add-ons/sdk/guides/index.html create mode 100644 files/zh-tw/mozilla/add-ons/sdk/high-level_apis/context-menu/index.html create mode 100644 files/zh-tw/mozilla/add-ons/sdk/high-level_apis/index.html create mode 100644 files/zh-tw/mozilla/add-ons/sdk/index.html create mode 100644 files/zh-tw/mozilla/add-ons/sdk/low-level_apis/index.html create mode 100644 files/zh-tw/mozilla/add-ons/themes/obsolete/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/anatomy_of_a_webextension/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/api/cookies/cookiestore/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/api/cookies/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/api/cookies/onchanged/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/api/cookies/onchangedcause/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/api/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/api/storage/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/api/storage/local/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/api/storage/storagearea/get/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/api/storage/storagearea/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/content_scripts/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/internationalization/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/manifest.json/author/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/manifest.json/background/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/manifest.json/browser_specific_settings/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/manifest.json/homepage_url/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/manifest.json/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/manifest.json/options_ui/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/user_interface/browser_action/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/user_interface/context_menu_items/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/user_interface/devtools_panels/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/user_interface/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/user_interface/sidebars/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/what_are_webextensions/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/your_first_webextension/index.html create mode 100644 files/zh-tw/mozilla/add-ons/webextensions/your_second_webextension/index.html create mode 100644 files/zh-tw/mozilla/adding_phishing_protection_data_providers/index.html create mode 100644 files/zh-tw/mozilla/chrome_registration/index.html create mode 100644 files/zh-tw/mozilla/connect/index.html create mode 100644 files/zh-tw/mozilla/creating_mozsearch_plugins/index.html create mode 100644 files/zh-tw/mozilla/developer_guide/index.html create mode 100644 files/zh-tw/mozilla/developer_guide/source_code/cvs/index.html create mode 100644 files/zh-tw/mozilla/developer_guide/source_code/index.html create mode 100644 files/zh-tw/mozilla/firefox/developer_edition/index.html create mode 100644 files/zh-tw/mozilla/firefox/developer_edition/reverting/index.html create mode 100644 files/zh-tw/mozilla/firefox/index.html create mode 100644 files/zh-tw/mozilla/firefox/multiprocess_firefox/index.html create mode 100644 files/zh-tw/mozilla/firefox/privacy/index.html create mode 100644 files/zh-tw/mozilla/firefox/privacy/tracking_protection/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/1.5/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/10/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/11/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/2/adding_feed_readers_to_firefox/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/2/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/2/security_changes/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/3.6/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/3/dom_improvements/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/3/firefox_3_css_improvement/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/3/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/35/index.html create mode 100644 "files/zh-tw/mozilla/firefox/releases/4/firefox_4_\351\226\213\347\231\274\350\200\205\346\226\260\345\212\237\350\203\275\346\246\202\350\246\275/index.html" create mode 100644 files/zh-tw/mozilla/firefox/releases/4/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/5/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/6/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/61/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/68/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/7/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/8/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/9/index.html create mode 100644 files/zh-tw/mozilla/firefox/releases/index.html create mode 100644 files/zh-tw/mozilla/gecko/chrome/api/browser_api/index.html create mode 100644 files/zh-tw/mozilla/gecko/chrome/api/index.html create mode 100644 files/zh-tw/mozilla/gecko/chrome/index.html create mode 100644 files/zh-tw/mozilla/gecko/index.html create mode 100644 files/zh-tw/mozilla/index.html create mode 100644 files/zh-tw/mozilla/infallible_memory_allocation/index.html create mode 100644 files/zh-tw/mozilla/introduction_to_layout_in_mozilla/index.html create mode 100644 files/zh-tw/mozilla/javascript_code_modules/index.html create mode 100644 files/zh-tw/mozilla/javascript_code_modules/promise.jsm/index.html create mode 100644 files/zh-tw/mozilla/javascript_code_modules/promise.jsm/promise/index.html create mode 100644 files/zh-tw/mozilla/js-ctypes/index.html create mode 100644 files/zh-tw/mozilla/localization/index.html create mode 100644 files/zh-tw/mozilla/localization/localizing_with_pontoon/index.html create mode 100644 files/zh-tw/mozilla/mathml_project/index.html create mode 100644 files/zh-tw/mozilla/mathml_project/screenshots/index.html create mode 100644 "files/zh-tw/mozilla/mathml_project/\351\226\213\351\240\255/index.html" create mode 100644 files/zh-tw/mozilla/performance/about_colon_memory/index.html create mode 100644 files/zh-tw/mozilla/performance/index.html create mode 100644 files/zh-tw/mozilla/preferences/index.html create mode 100644 files/zh-tw/mozilla/preferences/preferences_system/index.html create mode 100644 files/zh-tw/mozilla/preferences/preferences_system/new_attributes/index.html create mode 100644 files/zh-tw/mozilla/projects/index.html create mode 100644 files/zh-tw/mozilla/projects/nss/getting_started_with_nss/index.html create mode 100644 files/zh-tw/mozilla/projects/nss/index.html create mode 100644 files/zh-tw/mozilla/projects/rhino/index.html create mode 100644 files/zh-tw/mozilla/projects/rhino/license/index.html create mode 100644 files/zh-tw/mozilla/qa/bug_writing_guidelines/index.html create mode 100644 files/zh-tw/mozilla/qa/index.html create mode 100644 files/zh-tw/mozilla/rust/index.html create mode 100644 files/zh-tw/mozilla/tech/index.html create mode 100644 files/zh-tw/mozilla/tech/xpcom/reference/index.html create mode 100644 files/zh-tw/mozilla/tech/xpcom/reference/interface/index.html create mode 100644 files/zh-tw/mozilla/tech/xpcom/reference/interface/nsicontentpolicy/index.html create mode 100644 files/zh-tw/mozilla/thunderbird/autoconfiguration/fileformat/howto/index.html create mode 100644 files/zh-tw/mozilla/thunderbird/autoconfiguration/fileformat/index.html create mode 100644 files/zh-tw/mozilla/thunderbird/autoconfiguration/index.html create mode 100644 files/zh-tw/mozilla/thunderbird/deploying_thunderbird_in_the_enterprise/index.html create mode 100644 files/zh-tw/mozilla/thunderbird/deploying_thunderbird_in_the_enterprise/upgrading_thunderbird_in_the_enterprise/index.html create mode 100644 files/zh-tw/mozilla/thunderbird/index.html create mode 100644 files/zh-tw/mozilla/thunderbird/thunderbird_extensions/index.html create mode 100644 files/zh-tw/mozilla/thunderbird/thunderbird_extensions/theme_packaging/index.html create mode 100644 files/zh-tw/prism/index.html create mode 100644 "files/zh-tw/prism/\344\270\273\350\246\226\347\252\227/index.html" create mode 100644 "files/zh-tw/prism/\345\256\211\350\243\235\347\250\213\345\274\217/index.html" create mode 100644 files/zh-tw/profile_manager/index.html create mode 100644 files/zh-tw/python/index.html create mode 100644 files/zh-tw/sandbox/index.html create mode 100644 files/zh-tw/svg/tutorial/basic_shapes/index.html create mode 100644 files/zh-tw/tools/3d_view/index.html create mode 100644 files/zh-tw/tools/browser_toolbox/index.html create mode 100644 files/zh-tw/tools/debugger/how_to/index.html create mode 100644 files/zh-tw/tools/debugger/how_to/open_the_debugger/index.html create mode 100644 files/zh-tw/tools/debugger/how_to/set_a_breakpoint/index.html create mode 100644 files/zh-tw/tools/debugger/index.html create mode 100644 files/zh-tw/tools/firefox_os_1.1_simulator/index.html create mode 100644 files/zh-tw/tools/index.html create mode 100644 files/zh-tw/tools/network_monitor/index.html create mode 100644 files/zh-tw/tools/page_inspector/how_to/examine_grid_layouts/index.html create mode 100644 files/zh-tw/tools/page_inspector/how_to/index.html create mode 100644 files/zh-tw/tools/page_inspector/index.html create mode 100644 files/zh-tw/tools/performance/allocations/index.html create mode 100644 files/zh-tw/tools/performance/frame_rate/index.html create mode 100644 files/zh-tw/tools/performance/index.html create mode 100644 files/zh-tw/tools/remote_debugging/firefox_for_android/index.html create mode 100644 files/zh-tw/tools/remote_debugging/index.html create mode 100644 files/zh-tw/tools/responsive_design_mode/index.html create mode 100644 files/zh-tw/tools/scratchpad/index.html create mode 100644 files/zh-tw/tools/settings/index.html create mode 100644 files/zh-tw/tools/style_editor/index.html create mode 100644 files/zh-tw/tools/web_audio_editor/index.html create mode 100644 files/zh-tw/tools/web_console/console_messages/index.html create mode 100644 files/zh-tw/tools/web_console/index.html create mode 100644 files/zh-tw/tools/web_console/keyboard_shortcuts/index.html create mode 100644 files/zh-tw/tools/web_console/opening_the_web_console/index.html create mode 100644 files/zh-tw/tools/web_console/rich_output/index.html create mode 100644 files/zh-tw/tools/web_console/split_console/index.html create mode 100644 files/zh-tw/tools/web_console/the_command_line_interpreter/index.html create mode 100644 files/zh-tw/tools/webide/index.html create mode 100644 files/zh-tw/tools/webide/troubleshooting/index.html create mode 100644 files/zh-tw/web/accessibility/aria/aria_techniques/index.html create mode 100644 files/zh-tw/web/accessibility/aria/forms/basic_form_hints/index.html create mode 100644 files/zh-tw/web/accessibility/aria/forms/index.html create mode 100644 files/zh-tw/web/accessibility/aria/index.html create mode 100644 files/zh-tw/web/accessibility/index.html create mode 100644 files/zh-tw/web/accessibility/mobile_accessibility_checklist/index.html create mode 100644 files/zh-tw/web/api/abortcontroller/index.html create mode 100644 files/zh-tw/web/api/ambient_light_events/index.html create mode 100644 files/zh-tw/web/api/analysernode/getbytefrequencydata/index.html create mode 100644 files/zh-tw/web/api/analysernode/index.html create mode 100644 files/zh-tw/web/api/animationevent/index.html create mode 100644 files/zh-tw/web/api/animationevent/initanimationevent/index.html create mode 100644 files/zh-tw/web/api/battery_status_api/index.html create mode 100644 files/zh-tw/web/api/blob/blob/index.html create mode 100644 files/zh-tw/web/api/blob/index.html create mode 100644 files/zh-tw/web/api/blob/size/index.html create mode 100644 files/zh-tw/web/api/blob/type/index.html create mode 100644 files/zh-tw/web/api/body/index.html create mode 100644 files/zh-tw/web/api/body/json/index.html create mode 100644 files/zh-tw/web/api/canvas_api/drawing_graphics_with_canvas/index.html create mode 100644 files/zh-tw/web/api/canvas_api/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/advanced_animations/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/applying_styles_and_colors/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/basic_animations/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/basic_usage/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/compositing/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/drawing_shapes/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/drawing_text/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/optimizing_canvas/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/transformations/index.html create mode 100644 files/zh-tw/web/api/canvas_api/tutorial/using_images/index.html create mode 100644 files/zh-tw/web/api/canvasrenderingcontext2d/clearrect/index.html create mode 100644 files/zh-tw/web/api/canvasrenderingcontext2d/index.html create mode 100644 files/zh-tw/web/api/channel_messaging_api/index.html create mode 100644 files/zh-tw/web/api/characterdata/index.html create mode 100644 files/zh-tw/web/api/childnode/index.html create mode 100644 files/zh-tw/web/api/clients/index.html create mode 100644 files/zh-tw/web/api/clipboardevent/index.html create mode 100644 files/zh-tw/web/api/console/assert/index.html create mode 100644 files/zh-tw/web/api/console/index.html create mode 100644 files/zh-tw/web/api/css_object_model/determining_the_dimensions_of_elements/index.html create mode 100644 files/zh-tw/web/api/css_object_model/index.html create mode 100644 files/zh-tw/web/api/css_object_model/managing_screen_orientation/index.html create mode 100644 files/zh-tw/web/api/css_object_model/using_dynamic_styling_information/index.html create mode 100644 files/zh-tw/web/api/cssstyledeclaration/index.html create mode 100644 files/zh-tw/web/api/cssstylesheet/index.html create mode 100644 files/zh-tw/web/api/cssstylesheet/insertrule/index.html create mode 100644 files/zh-tw/web/api/customevent/customevent/index.html create mode 100644 files/zh-tw/web/api/customevent/index.html create mode 100644 files/zh-tw/web/api/datatransfer/index.html create mode 100644 files/zh-tw/web/api/detecting_device_orientation/index.html create mode 100644 files/zh-tw/web/api/devicemotionevent/index.html create mode 100644 files/zh-tw/web/api/deviceorientationevent/index.html create mode 100644 files/zh-tw/web/api/document.createtreewalker/index.html create mode 100644 files/zh-tw/web/api/document/body/index.html create mode 100644 files/zh-tw/web/api/document/createdocumentfragment/index.html create mode 100644 files/zh-tw/web/api/document/createelement/index.html create mode 100644 files/zh-tw/web/api/document/createrange/index.html create mode 100644 files/zh-tw/web/api/document/createtextnode/index.html create mode 100644 files/zh-tw/web/api/document/defaultview/index.html create mode 100644 files/zh-tw/web/api/document/designmode/index.html create mode 100644 files/zh-tw/web/api/document/documentelement/index.html create mode 100644 files/zh-tw/web/api/document/execcommand/index.html create mode 100644 files/zh-tw/web/api/document/forms/index.html create mode 100644 files/zh-tw/web/api/document/getelementsbyclassname/index.html create mode 100644 files/zh-tw/web/api/document/head/index.html create mode 100644 files/zh-tw/web/api/document/index.html create mode 100644 files/zh-tw/web/api/document/keyup_event/index.html create mode 100644 files/zh-tw/web/api/document/queryselector/index.html create mode 100644 files/zh-tw/web/api/document/readystate/index.html create mode 100644 files/zh-tw/web/api/document/registerelement/index.html create mode 100644 files/zh-tw/web/api/document/scroll_event/index.html create mode 100644 files/zh-tw/web/api/document/width/index.html create mode 100644 files/zh-tw/web/api/document_object_model/examples/index.html create mode 100644 files/zh-tw/web/api/document_object_model/how_to_create_a_dom_tree/index.html create mode 100644 files/zh-tw/web/api/document_object_model/index.html create mode 100644 files/zh-tw/web/api/document_object_model/whitespace/index.html create mode 100644 "files/zh-tw/web/api/document_object_model/\344\272\213\344\273\266/index.html" create mode 100644 files/zh-tw/web/api/documentfragment/index.html create mode 100644 files/zh-tw/web/api/documenttype/index.html create mode 100644 files/zh-tw/web/api/domparser/index.html create mode 100644 files/zh-tw/web/api/domstring/index.html create mode 100644 files/zh-tw/web/api/domtokenlist/index.html create mode 100644 files/zh-tw/web/api/dragevent/datatransfer/index.html create mode 100644 files/zh-tw/web/api/dragevent/index.html create mode 100644 files/zh-tw/web/api/element/attributes/index.html create mode 100644 files/zh-tw/web/api/element/classlist/index.html create mode 100644 files/zh-tw/web/api/element/click_event/index.html create mode 100644 files/zh-tw/web/api/element/clientheight/index.html create mode 100644 files/zh-tw/web/api/element/getattribute/index.html create mode 100644 files/zh-tw/web/api/element/index.html create mode 100644 files/zh-tw/web/api/element/innerhtml/index.html create mode 100644 files/zh-tw/web/api/element/insertadjacenthtml/index.html create mode 100644 files/zh-tw/web/api/element/queryselectorall/index.html create mode 100644 files/zh-tw/web/api/element/scrollheight/index.html create mode 100644 files/zh-tw/web/api/element/scrolltop/index.html create mode 100644 files/zh-tw/web/api/element/touchcancel_event/index.html create mode 100644 files/zh-tw/web/api/errorevent/index.html create mode 100644 files/zh-tw/web/api/event/bubbles/index.html create mode 100644 files/zh-tw/web/api/event/comparison_of_event_targets/index.html create mode 100644 files/zh-tw/web/api/event/createevent/index.html create mode 100644 files/zh-tw/web/api/event/currenttarget/index.html create mode 100644 files/zh-tw/web/api/event/defaultprevented/index.html create mode 100644 files/zh-tw/web/api/event/event/index.html create mode 100644 files/zh-tw/web/api/event/eventphase/index.html create mode 100644 files/zh-tw/web/api/event/index.html create mode 100644 files/zh-tw/web/api/event/istrusted/index.html create mode 100644 files/zh-tw/web/api/event/preventdefault/index.html create mode 100644 files/zh-tw/web/api/event/stopimmediatepropagation/index.html create mode 100644 files/zh-tw/web/api/event/stoppropagation/index.html create mode 100644 files/zh-tw/web/api/event/target/index.html create mode 100644 files/zh-tw/web/api/event/timestamp/index.html create mode 100644 files/zh-tw/web/api/event/type/index.html create mode 100644 files/zh-tw/web/api/eventlistener/index.html create mode 100644 files/zh-tw/web/api/eventtarget/dispatchevent/index.html create mode 100644 files/zh-tw/web/api/eventtarget/index.html create mode 100644 files/zh-tw/web/api/eventtarget/removeeventlistener/index.html create mode 100644 files/zh-tw/web/api/fetch_api/index.html create mode 100644 files/zh-tw/web/api/fetch_api/using_fetch/index.html create mode 100644 files/zh-tw/web/api/file/file/index.html create mode 100644 files/zh-tw/web/api/file/filename/index.html create mode 100644 files/zh-tw/web/api/file/index.html create mode 100644 files/zh-tw/web/api/file/using_files_from_web_applications/index.html create mode 100644 files/zh-tw/web/api/file_handle_api/index.html create mode 100644 files/zh-tw/web/api/filelist/index.html create mode 100644 files/zh-tw/web/api/filereader/error/index.html create mode 100644 files/zh-tw/web/api/filereader/index.html create mode 100644 files/zh-tw/web/api/filereader/readystate/index.html create mode 100644 files/zh-tw/web/api/filesystem/index.html create mode 100644 files/zh-tw/web/api/formdata/get/index.html create mode 100644 files/zh-tw/web/api/formdata/index.html create mode 100644 files/zh-tw/web/api/formdata/using_formdata_objects/index.html create mode 100644 files/zh-tw/web/api/fullscreen_api/index.html create mode 100644 files/zh-tw/web/api/gainnode/gain/index.html create mode 100644 files/zh-tw/web/api/gainnode/index.html create mode 100644 files/zh-tw/web/api/geolocation/clearwatch/index.html create mode 100644 files/zh-tw/web/api/geolocation/getcurrentposition/index.html create mode 100644 files/zh-tw/web/api/geolocation/index.html create mode 100644 files/zh-tw/web/api/geolocation/using_geolocation/index.html create mode 100644 files/zh-tw/web/api/geolocation/watchposition/index.html create mode 100644 files/zh-tw/web/api/geolocationcoordinates/accuracy/index.html create mode 100644 files/zh-tw/web/api/geolocationcoordinates/altitude/index.html create mode 100644 files/zh-tw/web/api/geolocationcoordinates/altitudeaccuracy/index.html create mode 100644 files/zh-tw/web/api/geolocationcoordinates/heading/index.html create mode 100644 files/zh-tw/web/api/geolocationcoordinates/index.html create mode 100644 files/zh-tw/web/api/geolocationcoordinates/latitude/index.html create mode 100644 files/zh-tw/web/api/geolocationcoordinates/longitude/index.html create mode 100644 files/zh-tw/web/api/geolocationcoordinates/speed/index.html create mode 100644 files/zh-tw/web/api/geolocationposition/coords/index.html create mode 100644 files/zh-tw/web/api/geolocationposition/index.html create mode 100644 files/zh-tw/web/api/geolocationposition/timestamp/index.html create mode 100644 files/zh-tw/web/api/geolocationpositionerror/code/index.html create mode 100644 files/zh-tw/web/api/geolocationpositionerror/index.html create mode 100644 files/zh-tw/web/api/geolocationpositionerror/message/index.html create mode 100644 files/zh-tw/web/api/globaleventhandlers/index.html create mode 100644 files/zh-tw/web/api/globaleventhandlers/onclick/index.html create mode 100644 files/zh-tw/web/api/globaleventhandlers/onclose/index.html create mode 100644 files/zh-tw/web/api/history/index.html create mode 100644 files/zh-tw/web/api/history_api/index.html create mode 100644 files/zh-tw/web/api/html_drag_and_drop_api/drag_operations/index.html create mode 100644 files/zh-tw/web/api/html_drag_and_drop_api/index.html create mode 100644 files/zh-tw/web/api/htmlcanvaselement/index.html create mode 100644 files/zh-tw/web/api/htmlcanvaselement/todataurl/index.html create mode 100644 files/zh-tw/web/api/htmlcollection/index.html create mode 100644 files/zh-tw/web/api/htmldataelement/index.html create mode 100644 files/zh-tw/web/api/htmldocument/index.html create mode 100644 files/zh-tw/web/api/htmlelement/click/index.html create mode 100644 files/zh-tw/web/api/htmlelement/dataset/index.html create mode 100644 files/zh-tw/web/api/htmlelement/index.html create mode 100644 files/zh-tw/web/api/htmlelement/lang/index.html create mode 100644 files/zh-tw/web/api/htmlelement/style/index.html create mode 100644 files/zh-tw/web/api/htmlformelement/index.html create mode 100644 files/zh-tw/web/api/htmlformelement/submit_event/index.html create mode 100644 files/zh-tw/web/api/htmlimageelement/index.html create mode 100644 files/zh-tw/web/api/htmlinputelement/index.html create mode 100644 files/zh-tw/web/api/htmlmediaelement/index.html create mode 100644 files/zh-tw/web/api/htmlmediaelement/ratechange_event/index.html create mode 100644 files/zh-tw/web/api/htmlmediaelement/readystate/index.html create mode 100644 files/zh-tw/web/api/htmlselectelement/checkvalidity/index.html create mode 100644 files/zh-tw/web/api/htmlselectelement/index.html create mode 100644 files/zh-tw/web/api/htmlselectelement/setcustomvalidity/index.html create mode 100644 files/zh-tw/web/api/idbdatabase/index.html create mode 100644 files/zh-tw/web/api/index.html create mode 100644 files/zh-tw/web/api/indexeddb_api/basic_concepts_behind_indexeddb/index.html create mode 100644 files/zh-tw/web/api/indexeddb_api/index.html create mode 100644 files/zh-tw/web/api/indexeddb_api/using_indexeddb/index.html create mode 100644 files/zh-tw/web/api/keyboardevent/index.html create mode 100644 files/zh-tw/web/api/keyboardevent/keyboardevent/index.html create mode 100644 files/zh-tw/web/api/media_streams_api/index.html create mode 100644 files/zh-tw/web/api/mediaquerylist/index.html create mode 100644 files/zh-tw/web/api/mediasource/activesourcebuffers/index.html create mode 100644 files/zh-tw/web/api/mediasource/duration/index.html create mode 100644 files/zh-tw/web/api/mediasource/index.html create mode 100644 files/zh-tw/web/api/mediasource/mediasource/index.html create mode 100644 files/zh-tw/web/api/mediasource/readystate/index.html create mode 100644 files/zh-tw/web/api/mouseevent/index.html create mode 100644 files/zh-tw/web/api/mutationobserver/index.html create mode 100644 files/zh-tw/web/api/namednodemap/index.html create mode 100644 files/zh-tw/web/api/navigator/geolocation/index.html create mode 100644 files/zh-tw/web/api/navigator/index.html create mode 100644 files/zh-tw/web/api/navigator/registerprotocolhandler/index.html create mode 100644 files/zh-tw/web/api/navigator/registerprotocolhandler/web-based_protocol_handlers/index.html create mode 100644 files/zh-tw/web/api/navigatoronline/index.html create mode 100644 files/zh-tw/web/api/navigatoronline/online_and_offline_events/index.html create mode 100644 files/zh-tw/web/api/network_information_api/index.html create mode 100644 files/zh-tw/web/api/node/childnodes/index.html create mode 100644 files/zh-tw/web/api/node/clonenode/index.html create mode 100644 files/zh-tw/web/api/node/index.html create mode 100644 files/zh-tw/web/api/node/innertext/index.html create mode 100644 files/zh-tw/web/api/node/insertbefore/index.html create mode 100644 files/zh-tw/web/api/node/nodename/index.html create mode 100644 files/zh-tw/web/api/node/nodetype/index.html create mode 100644 files/zh-tw/web/api/node/ownerdocument/index.html create mode 100644 files/zh-tw/web/api/node/removechild/index.html create mode 100644 files/zh-tw/web/api/node/textcontent/index.html create mode 100644 files/zh-tw/web/api/nodelist/index.html create mode 100644 files/zh-tw/web/api/nondocumenttypechildnode/index.html create mode 100644 files/zh-tw/web/api/notification/index.html create mode 100644 files/zh-tw/web/api/notifications_api/index.html create mode 100644 files/zh-tw/web/api/notifications_api/using_the_notifications_api/index.html create mode 100644 files/zh-tw/web/api/parentnode/children/index.html create mode 100644 files/zh-tw/web/api/parentnode/firstelementchild/index.html create mode 100644 files/zh-tw/web/api/parentnode/index.html create mode 100644 files/zh-tw/web/api/payment_request_api/index.html create mode 100644 files/zh-tw/web/api/paymentrequest/index.html create mode 100644 files/zh-tw/web/api/performance.timing/index.html create mode 100644 files/zh-tw/web/api/performance/index.html create mode 100644 files/zh-tw/web/api/pointer_lock_api/index.html create mode 100644 files/zh-tw/web/api/positionoptions/enablehighaccuracy/index.html create mode 100644 files/zh-tw/web/api/positionoptions/index.html create mode 100644 files/zh-tw/web/api/positionoptions/maximumage/index.html create mode 100644 files/zh-tw/web/api/positionoptions/timeout/index.html create mode 100644 files/zh-tw/web/api/progressevent/index.html create mode 100644 files/zh-tw/web/api/proximity_events/index.html create mode 100644 files/zh-tw/web/api/range/index.html create mode 100644 files/zh-tw/web/api/response/index.html create mode 100644 files/zh-tw/web/api/screen/index.html create mode 100644 files/zh-tw/web/api/screen/orientation/index.html create mode 100644 files/zh-tw/web/api/server-sent_events/index.html create mode 100644 files/zh-tw/web/api/server-sent_events/using_server-sent_events/index.html create mode 100644 files/zh-tw/web/api/storage/index.html create mode 100644 files/zh-tw/web/api/touch/index.html create mode 100644 files/zh-tw/web/api/touch_events/index.html create mode 100644 files/zh-tw/web/api/touchevent/index.html create mode 100644 files/zh-tw/web/api/touchlist/index.html create mode 100644 files/zh-tw/web/api/uievent/index.html create mode 100644 files/zh-tw/web/api/uievent/uievent/index.html create mode 100644 files/zh-tw/web/api/url/createobjecturl/index.html create mode 100644 files/zh-tw/web/api/url/index.html create mode 100644 files/zh-tw/web/api/validitystate/index.html create mode 100644 files/zh-tw/web/api/vibration_api/index.html create mode 100644 files/zh-tw/web/api/web_audio_api/index.html create mode 100644 files/zh-tw/web/api/web_video_text_tracks_format/index.html create mode 100644 files/zh-tw/web/api/web_workers_api/index.html create mode 100644 files/zh-tw/web/api/web_workers_api/using_web_workers/index.html create mode 100644 files/zh-tw/web/api/webgl_api/index.html create mode 100644 files/zh-tw/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html create mode 100644 files/zh-tw/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html create mode 100644 files/zh-tw/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html create mode 100644 files/zh-tw/web/api/webgl_api/tutorial/index.html create mode 100644 files/zh-tw/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html create mode 100644 files/zh-tw/web/api/webrtc_api/index.html create mode 100644 files/zh-tw/web/api/webvr_api/index.html create mode 100644 files/zh-tw/web/api/wheelevent/index.html create mode 100644 files/zh-tw/web/api/window.history/index.html create mode 100644 files/zh-tw/web/api/window.onpopstate/index.html create mode 100644 files/zh-tw/web/api/window.requestanimationframe/index.html create mode 100644 files/zh-tw/web/api/window/getcomputedstyle/index.html create mode 100644 files/zh-tw/web/api/window/index.html create mode 100644 files/zh-tw/web/api/window/localstorage/index.html create mode 100644 files/zh-tw/web/api/window/location/index.html create mode 100644 files/zh-tw/web/api/window/navigator/index.html create mode 100644 files/zh-tw/web/api/window/opener/index.html create mode 100644 files/zh-tw/web/api/window/orientationchange_event/index.html create mode 100644 files/zh-tw/web/api/window/print/index.html create mode 100644 files/zh-tw/web/api/window/requestidlecallback/index.html create mode 100644 files/zh-tw/web/api/window/sessionstorage/index.html create mode 100644 files/zh-tw/web/api/window/sidebar/adding_search_engines_from_web_pages/index.html create mode 100644 files/zh-tw/web/api/window/sidebar/index.html create mode 100644 files/zh-tw/web/api/windowbase64/index.html create mode 100644 files/zh-tw/web/api/windoweventhandlers/index.html create mode 100644 files/zh-tw/web/api/windoweventhandlers/onbeforeunload/index.html create mode 100644 files/zh-tw/web/api/windoworworkerglobalscope/btoa/index.html create mode 100644 files/zh-tw/web/api/windoworworkerglobalscope/index.html create mode 100644 files/zh-tw/web/api/windoworworkerglobalscope/setinterval/index.html create mode 100644 files/zh-tw/web/api/windowtimers/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/onreadystatechange/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/readystate/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/setrequestheader/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/status/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/synchronous_and_asynchronous_requests/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/using_xmlhttprequest/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/withcredentials/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/xmlhttprequest/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequesteventtarget/index.html create mode 100644 files/zh-tw/web/css/@font-face/index.html create mode 100644 files/zh-tw/web/css/@media/height/index.html create mode 100644 files/zh-tw/web/css/@media/index.html create mode 100644 files/zh-tw/web/css/@viewport/height/index.html create mode 100644 files/zh-tw/web/css/@viewport/index.html create mode 100644 files/zh-tw/web/css/_colon_first-child/index.html create mode 100644 files/zh-tw/web/css/_colon_first-of-type/index.html create mode 100644 files/zh-tw/web/css/_colon_lang/index.html create mode 100644 files/zh-tw/web/css/_colon_target/index.html create mode 100644 files/zh-tw/web/css/_doublecolon_first-letter/index.html create mode 100644 files/zh-tw/web/css/animation-fill-mode/index.html create mode 100644 files/zh-tw/web/css/attr()/index.html create mode 100644 files/zh-tw/web/css/background-attachment/index.html create mode 100644 files/zh-tw/web/css/background-color/index.html create mode 100644 files/zh-tw/web/css/border-image/border-image/index.html create mode 100644 files/zh-tw/web/css/border-image/index.html create mode 100644 files/zh-tw/web/css/border/index.html create mode 100644 files/zh-tw/web/css/box-shadow/index.html create mode 100644 files/zh-tw/web/css/box-sizing/index.html create mode 100644 files/zh-tw/web/css/clip/index.html create mode 100644 files/zh-tw/web/css/common_css_questions/index.html create mode 100644 files/zh-tw/web/css/css_animations/index.html create mode 100644 files/zh-tw/web/css/css_animations/using_css_animations/index.html create mode 100644 files/zh-tw/web/css/css_background_and_borders/index.html create mode 100644 files/zh-tw/web/css/css_background_and_borders/using_css_multiple_backgrounds/index.html create mode 100644 files/zh-tw/web/css/css_box_model/index.html create mode 100644 files/zh-tw/web/css/css_box_model/mastering_margin_collapsing/index.html create mode 100644 files/zh-tw/web/css/css_colors/color_picker_tool/index.html create mode 100644 files/zh-tw/web/css/css_colors/index.html create mode 100644 files/zh-tw/web/css/css_flexible_box_layout/index.html create mode 100644 files/zh-tw/web/css/css_flexible_box_layout/using_css_flexible_boxes/index.html create mode 100644 files/zh-tw/web/css/css_grid_layout/basic_concepts_of_grid_layout/index.html create mode 100644 files/zh-tw/web/css/css_grid_layout/index.html create mode 100644 files/zh-tw/web/css/css_lists_and_counters/consistent_list_indentation/index.html create mode 100644 files/zh-tw/web/css/css_lists_and_counters/index.html create mode 100644 files/zh-tw/web/css/css_positioning/index.html create mode 100644 files/zh-tw/web/css/css_positioning/understanding_z_index/index.html create mode 100644 files/zh-tw/web/css/css_positioning/understanding_z_index/stacking_context_example_1/index.html create mode 100644 files/zh-tw/web/css/css_properties_reference/index.html create mode 100644 files/zh-tw/web/css/css_selectors/index.html create mode 100644 files/zh-tw/web/css/css_selectors/using_the__colon_target_pseudo-class_in_selectors/index.html create mode 100644 files/zh-tw/web/css/css_transitions/index.html create mode 100644 files/zh-tw/web/css/css_transitions/using_css_transitions/index.html create mode 100644 files/zh-tw/web/css/cursor/index.html create mode 100644 files/zh-tw/web/css/descendant_combinator/index.html create mode 100644 files/zh-tw/web/css/grid-row/index.html create mode 100644 files/zh-tw/web/css/grid-template-columns/index.html create mode 100644 files/zh-tw/web/css/grid-template/index.html create mode 100644 files/zh-tw/web/css/height/index.html create mode 100644 files/zh-tw/web/css/ime-mode/index.html create mode 100644 files/zh-tw/web/css/index.html create mode 100644 files/zh-tw/web/css/inheritance/index.html create mode 100644 files/zh-tw/web/css/line-break/index.html create mode 100644 files/zh-tw/web/css/media_queries/index.html create mode 100644 files/zh-tw/web/css/media_queries/testing_media_queries/index.html create mode 100644 files/zh-tw/web/css/object-fit/index.html create mode 100644 files/zh-tw/web/css/pseudo-classes/index.html create mode 100644 files/zh-tw/web/css/radial-gradient()/index.html create mode 100644 files/zh-tw/web/css/reference/index.html create mode 100644 files/zh-tw/web/css/replaced_element/index.html create mode 100644 files/zh-tw/web/css/ruby-position/index.html create mode 100644 files/zh-tw/web/css/shorthand_properties/index.html create mode 100644 files/zh-tw/web/css/syntax/index.html create mode 100644 files/zh-tw/web/css/transform-function/index.html create mode 100644 files/zh-tw/web/css/transform-function/translate3d()/index.html create mode 100644 files/zh-tw/web/css/transform-origin/index.html create mode 100644 files/zh-tw/web/css/transform/index.html create mode 100644 files/zh-tw/web/css/transition-duration/index.html create mode 100644 files/zh-tw/web/css/transition-timing-function/index.html create mode 100644 files/zh-tw/web/css/transition/index.html create mode 100644 files/zh-tw/web/css/type_selectors/index.html create mode 100644 files/zh-tw/web/css/white-space/index.html create mode 100644 files/zh-tw/web/css/width/index.html create mode 100644 files/zh-tw/web/demos_of_open_web_technologies/index.html create mode 100644 files/zh-tw/web/events/abort/index.html create mode 100644 files/zh-tw/web/events/domcontentloaded/index.html create mode 100644 files/zh-tw/web/events/index.html create mode 100644 files/zh-tw/web/events/load/index.html create mode 100644 files/zh-tw/web/guide/ajax/getting_started/index.html create mode 100644 files/zh-tw/web/guide/ajax/index.html create mode 100644 files/zh-tw/web/guide/api/index.html create mode 100644 files/zh-tw/web/guide/dom/index.html create mode 100644 files/zh-tw/web/guide/events/creating_and_triggering_events/index.html create mode 100644 files/zh-tw/web/guide/events/event_handlers/index.html create mode 100644 files/zh-tw/web/guide/events/index.html create mode 100644 files/zh-tw/web/guide/graphics/index.html create mode 100644 files/zh-tw/web/guide/html/content_categories/index.html create mode 100644 files/zh-tw/web/guide/html/event_attributes/index.html create mode 100644 files/zh-tw/web/guide/html/html5/index.html create mode 100644 files/zh-tw/web/guide/html/html5/introduction_to_html5/index.html create mode 100644 files/zh-tw/web/guide/index.html create mode 100644 files/zh-tw/web/guide/introduction_to_web_development/index.html create mode 100644 files/zh-tw/web/guide/performance/index.html create mode 100644 files/zh-tw/web/guide/woff/index.html create mode 100644 files/zh-tw/web/guide/writing_forward-compatible_websites/index.html create mode 100644 files/zh-tw/web/html/applying_color/index.html create mode 100644 files/zh-tw/web/html/attributes/index.html create mode 100644 files/zh-tw/web/html/block-level_elements/index.html create mode 100644 files/zh-tw/web/html/element/a/index.html create mode 100644 files/zh-tw/web/html/element/blink/index.html create mode 100644 files/zh-tw/web/html/element/blockquote/index.html create mode 100644 files/zh-tw/web/html/element/br/index.html create mode 100644 files/zh-tw/web/html/element/button/index.html create mode 100644 files/zh-tw/web/html/element/canvas/index.html create mode 100644 files/zh-tw/web/html/element/code/index.html create mode 100644 files/zh-tw/web/html/element/div/index.html create mode 100644 files/zh-tw/web/html/element/font/index.html create mode 100644 files/zh-tw/web/html/element/form/index.html create mode 100644 files/zh-tw/web/html/element/frameset/index.html create mode 100644 files/zh-tw/web/html/element/hr/index.html create mode 100644 files/zh-tw/web/html/element/index.html create mode 100644 files/zh-tw/web/html/element/input/index.html create mode 100644 files/zh-tw/web/html/element/input/submit/index.html create mode 100644 files/zh-tw/web/html/element/marquee/index.html create mode 100644 files/zh-tw/web/html/element/meter/index.html create mode 100644 files/zh-tw/web/html/element/nav/index.html create mode 100644 files/zh-tw/web/html/element/optgroup/index.html create mode 100644 files/zh-tw/web/html/element/picture/index.html create mode 100644 files/zh-tw/web/html/element/q/index.html create mode 100644 files/zh-tw/web/html/element/ruby/index.html create mode 100644 files/zh-tw/web/html/element/script/index.html create mode 100644 files/zh-tw/web/html/element/summary/index.html create mode 100644 files/zh-tw/web/html/element/table/index.html create mode 100644 files/zh-tw/web/html/element/template/index.html create mode 100644 files/zh-tw/web/html/element/time/index.html create mode 100644 files/zh-tw/web/html/forms_in_html/index.html create mode 100644 files/zh-tw/web/html/global_attributes/data-_star_/index.html create mode 100644 files/zh-tw/web/html/global_attributes/index.html create mode 100644 files/zh-tw/web/html/global_attributes/spellcheck/index.html create mode 100644 files/zh-tw/web/html/index.html create mode 100644 files/zh-tw/web/html/quirks_mode_and_standards_mode/index.html create mode 100644 files/zh-tw/web/html/reference/index.html create mode 100644 files/zh-tw/web/html/supported_media_formats/index.html create mode 100644 files/zh-tw/web/html/using_the_application_cache/index.html create mode 100644 files/zh-tw/web/http/authentication/index.html create mode 100644 files/zh-tw/web/http/basics_of_http/index.html create mode 100644 files/zh-tw/web/http/basics_of_http/mime_types/index.html create mode 100644 files/zh-tw/web/http/browser_detection_using_the_user_agent/index.html create mode 100644 files/zh-tw/web/http/caching/index.html create mode 100644 files/zh-tw/web/http/cookies/index.html create mode 100644 files/zh-tw/web/http/cors/errors/corsdidnotsucceed/index.html create mode 100644 files/zh-tw/web/http/cors/errors/corsmissingalloworigin/index.html create mode 100644 files/zh-tw/web/http/cors/errors/corsnotsupportingcredentials/index.html create mode 100644 files/zh-tw/web/http/cors/errors/index.html create mode 100644 files/zh-tw/web/http/cors/index.html create mode 100644 files/zh-tw/web/http/data_uris/index.html create mode 100644 files/zh-tw/web/http/headers/accept/index.html create mode 100644 files/zh-tw/web/http/headers/dnt/index.html create mode 100644 files/zh-tw/web/http/headers/index.html create mode 100644 files/zh-tw/web/http/headers/server/index.html create mode 100644 files/zh-tw/web/http/headers/strict-transport-security/index.html create mode 100644 files/zh-tw/web/http/headers/user-agent/index.html create mode 100644 files/zh-tw/web/http/headers/x-forwarded-for/index.html create mode 100644 files/zh-tw/web/http/headers/x-frame-options/index.html create mode 100644 files/zh-tw/web/http/index.html create mode 100644 files/zh-tw/web/http/link_prefetching_faq/index.html create mode 100644 files/zh-tw/web/http/methods/connect/index.html create mode 100644 files/zh-tw/web/http/methods/get/index.html create mode 100644 files/zh-tw/web/http/methods/index.html create mode 100644 files/zh-tw/web/http/methods/post/index.html create mode 100644 files/zh-tw/web/http/protocol_upgrade_mechanism/index.html create mode 100644 files/zh-tw/web/http/server-side_access_control/index.html create mode 100644 files/zh-tw/web/http/status/100/index.html create mode 100644 files/zh-tw/web/http/status/101/index.html create mode 100644 files/zh-tw/web/http/status/200/index.html create mode 100644 files/zh-tw/web/http/status/201/index.html create mode 100644 files/zh-tw/web/http/status/202/index.html create mode 100644 files/zh-tw/web/http/status/203/index.html create mode 100644 files/zh-tw/web/http/status/204/index.html create mode 100644 files/zh-tw/web/http/status/205/index.html create mode 100644 files/zh-tw/web/http/status/206/index.html create mode 100644 files/zh-tw/web/http/status/300/index.html create mode 100644 files/zh-tw/web/http/status/301/index.html create mode 100644 files/zh-tw/web/http/status/403/index.html create mode 100644 files/zh-tw/web/http/status/404/index.html create mode 100644 files/zh-tw/web/http/status/409/index.html create mode 100644 files/zh-tw/web/http/status/411/index.html create mode 100644 files/zh-tw/web/http/status/415/index.html create mode 100644 files/zh-tw/web/http/status/418_i_m_a_teapot/index.html create mode 100644 files/zh-tw/web/http/status/451/index.html create mode 100644 files/zh-tw/web/http/status/500/index.html create mode 100644 files/zh-tw/web/http/status/502/index.html create mode 100644 files/zh-tw/web/http/status/503/index.html create mode 100644 files/zh-tw/web/http/status/504/index.html create mode 100644 files/zh-tw/web/http/status/index.html create mode 100644 files/zh-tw/web/index.html create mode 100644 files/zh-tw/web/javascript/a_re-introduction_to_javascript/index.html create mode 100644 files/zh-tw/web/javascript/about_javascript/index.html create mode 100644 files/zh-tw/web/javascript/closures/index.html create mode 100644 files/zh-tw/web/javascript/data_structures/index.html create mode 100644 files/zh-tw/web/javascript/enumerability_and_ownership_of_properties/index.html create mode 100644 files/zh-tw/web/javascript/equality_comparisons_and_sameness/index.html create mode 100644 files/zh-tw/web/javascript/eventloop/index.html create mode 100644 files/zh-tw/web/javascript/guide/control_flow_and_error_handling/index.html create mode 100644 files/zh-tw/web/javascript/guide/details_of_the_object_model/index.html create mode 100644 files/zh-tw/web/javascript/guide/expressions_and_operators/index.html create mode 100644 files/zh-tw/web/javascript/guide/functions/index.html create mode 100644 files/zh-tw/web/javascript/guide/grammar_and_types/index.html create mode 100644 files/zh-tw/web/javascript/guide/index.html create mode 100644 files/zh-tw/web/javascript/guide/indexed_collections/index.html create mode 100644 files/zh-tw/web/javascript/guide/introduction/index.html create mode 100644 files/zh-tw/web/javascript/guide/iterators_and_generators/index.html create mode 100644 files/zh-tw/web/javascript/guide/keyed_collections/index.html create mode 100644 files/zh-tw/web/javascript/guide/loops_and_iteration/index.html create mode 100644 files/zh-tw/web/javascript/guide/numbers_and_dates/index.html create mode 100644 files/zh-tw/web/javascript/guide/regular_expressions/index.html create mode 100644 files/zh-tw/web/javascript/guide/using_promises/index.html create mode 100644 files/zh-tw/web/javascript/guide/working_with_objects/index.html create mode 100644 files/zh-tw/web/javascript/index.html create mode 100644 files/zh-tw/web/javascript/inheritance_and_the_prototype_chain/index.html create mode 100644 files/zh-tw/web/javascript/introduction_to_object-oriented_javascript/index.html create mode 100644 files/zh-tw/web/javascript/javascript_technologies_overview/index.html create mode 100644 files/zh-tw/web/javascript/language_resources/index.html create mode 100644 files/zh-tw/web/javascript/memory_management/index.html create mode 100644 files/zh-tw/web/javascript/new_in_javascript/1.1/index.html create mode 100644 files/zh-tw/web/javascript/new_in_javascript/1.2/index.html create mode 100644 files/zh-tw/web/javascript/new_in_javascript/1.3/index.html create mode 100644 files/zh-tw/web/javascript/new_in_javascript/1.4/index.html create mode 100644 files/zh-tw/web/javascript/new_in_javascript/1.5/index.html create mode 100644 files/zh-tw/web/javascript/new_in_javascript/1.6/index.html create mode 100644 files/zh-tw/web/javascript/new_in_javascript/1.7/index.html create mode 100644 files/zh-tw/web/javascript/new_in_javascript/1.8.1/index.html create mode 100644 files/zh-tw/web/javascript/new_in_javascript/1.8.5/index.html create mode 100644 files/zh-tw/web/javascript/new_in_javascript/1.8/index.html create mode 100644 files/zh-tw/web/javascript/new_in_javascript/index.html create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/javascript_\346\246\202\350\246\201/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/liveconnect_\346\246\202\350\246\201/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/liveconnect_\346\246\202\350\246\201/java_\345\220\221_javascript_\347\232\204\351\200\232\350\250\212/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/liveconnect_\346\246\202\350\246\201/java_\345\220\221_javascript_\347\232\204\351\200\232\350\250\212/liveconnect_\351\241\236\345\210\245\347\232\204\344\275\277\347\224\250/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/liveconnect_\346\246\202\350\246\201/javascript_\345\220\221_java_\347\232\204\351\200\232\350\250\212/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/liveconnect_\346\246\202\350\246\201/\345\214\205\350\243\235\345\231\250\347\232\204\351\201\213\347\224\250/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/liveconnect_\346\246\202\350\246\201/\350\263\207\346\226\231\351\241\236\345\236\213\347\232\204\350\275\211\346\217\233/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/liveconnect_\346\246\202\350\246\201/\350\263\207\346\226\231\351\241\236\345\236\213\347\232\204\350\275\211\346\217\233/\345\276\236_java_\345\210\260_javascript_\347\232\204\350\275\211\346\217\233/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/liveconnect_\346\246\202\350\246\201/\350\263\207\346\226\231\351\241\236\345\236\213\347\232\204\350\275\211\346\217\233/\345\276\236_javascript_\345\210\260_java_\347\232\204\350\275\211\346\217\233/index.html" create mode 100644 files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/unicode/index.html create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\344\273\245\351\241\236\345\210\245\347\202\272\345\237\272\347\244\216\347\232\204\350\252\236\350\250\200_vs._\344\273\245\345\216\237\345\236\213\347\202\272\345\237\272\347\244\216\347\232\204\350\252\236\350\250\200/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\344\276\213\345\244\226\350\231\225\347\220\206\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\344\276\213\345\244\226\350\231\225\347\220\206\350\252\236\346\263\225/throw_\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\344\276\213\345\244\226\350\231\225\347\220\206\350\252\236\346\263\225/try...catch_\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\200\274/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\206\215\350\253\207\345\261\254\346\200\247\347\232\204\347\271\274\346\211\277/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\206\215\350\253\207\345\261\254\346\200\247\347\232\204\347\271\274\346\211\277/\345\257\246\351\253\224\351\227\234\344\277\202\347\232\204\347\242\272\345\256\232/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\206\215\350\253\207\345\261\254\346\200\247\347\232\204\347\271\274\346\211\277/\345\261\200\345\237\237\345\200\274\345\222\214\347\271\274\346\211\277\345\200\274/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\206\215\350\253\207\345\261\254\346\200\247\347\232\204\347\271\274\346\211\277/\345\273\272\346\247\213\345\255\220\344\270\255\347\232\204\345\205\250\345\237\237\350\263\207\350\250\212/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\206\215\350\253\207\345\261\254\346\200\247\347\232\204\347\271\274\346\211\277/\346\262\222\346\234\211\345\244\232\351\207\215\347\271\274\346\211\277/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\207\275\346\225\270\347\232\204\345\221\274\345\217\253/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\207\275\346\225\270\347\232\204\345\256\232\347\276\251/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\215\200\345\241\212\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\255\227\351\235\242\350\241\250\351\201\224/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\270\270\346\225\270/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\273\272\347\253\213\346\226\260\347\232\204\347\211\251\344\273\266/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\276\252\347\222\260\350\252\236\346\263\225/break_\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\276\252\347\222\260\350\252\236\346\263\225/continue_\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\276\252\347\222\260\350\252\236\346\263\225/do...while_\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\276\252\347\222\260\350\252\236\346\263\225/for_\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\276\252\347\222\260\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\276\252\347\222\260\350\252\236\346\263\225/label_\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\345\276\252\347\222\260\350\252\236\346\263\225/while_\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\226\260\347\211\251\344\273\266\347\232\204\345\273\272\347\253\213/getter_\345\222\214_setter_\347\232\204\345\256\232\347\276\251/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\226\260\347\211\251\344\273\266\347\232\204\345\273\272\347\253\213/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\226\260\347\211\251\344\273\266\347\232\204\345\273\272\347\253\213/\344\275\277\347\224\250_this_\345\217\226\345\276\227\347\211\251\344\273\266\347\232\204\345\217\203\350\200\203/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\226\260\347\211\251\344\273\266\347\232\204\345\273\272\347\253\213/\345\261\254\346\200\247\347\232\204\345\210\252\351\231\244/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\226\260\347\211\251\344\273\266\347\232\204\345\273\272\347\253\213/\345\273\272\346\247\213\345\255\220\345\207\275\346\225\270\347\232\204\344\275\277\347\224\250/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\226\260\347\211\251\344\273\266\347\232\204\345\273\272\347\253\213/\346\226\271\346\263\225\347\232\204\345\256\232\347\276\251/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\226\260\347\211\251\344\273\266\347\232\204\345\273\272\347\253\213/\347\211\251\344\273\266\345\210\235\345\247\213\345\214\226\345\255\220\347\232\204\344\275\277\347\224\250/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\226\260\347\211\251\344\273\266\347\232\204\345\273\272\347\253\213/\347\211\251\344\273\266\345\261\254\346\200\247\347\232\204\347\264\242\345\274\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\226\260\347\211\251\344\273\266\347\232\204\345\273\272\347\253\213/\351\207\235\345\260\215\347\211\251\344\273\266\347\232\204\351\241\236\345\236\213\345\256\232\347\276\251\345\261\254\346\200\247/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\242\235\344\273\266\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\255\243\350\246\217\350\241\250\351\201\224\345\274\217\346\250\241\345\274\217\347\232\204\347\267\250\345\257\253/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\255\243\350\246\217\350\241\250\351\201\224\345\274\217\347\232\204\345\273\272\347\253\213/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\255\243\350\246\217\350\241\250\351\201\224\345\274\217\347\232\204\351\201\213\347\224\250/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\255\243\350\246\217\350\241\250\351\201\224\345\274\217\347\232\204\351\201\213\347\224\250/\344\275\277\347\224\250\346\250\231\350\252\214\347\232\204\351\200\262\351\232\216\346\220\234\345\260\213/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\255\243\350\246\217\350\241\250\351\201\224\345\274\217\347\232\204\351\201\213\347\224\250/\346\213\254\345\274\247\345\255\220\345\255\227\344\270\262\347\232\204\346\257\224\345\260\215\347\265\220\346\236\234\347\232\204\351\201\213\347\224\250/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\346\255\243\350\246\217\350\241\250\351\201\224\345\274\217\347\232\204\351\201\213\347\224\250/\346\255\243\350\246\217\350\241\250\351\201\224\345\274\217\347\232\204\347\257\204\344\276\213/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\347\211\251\344\273\266\345\222\214\345\261\254\346\200\247/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\347\211\251\344\273\266\347\232\204\346\223\215\344\275\234\350\252\236\346\263\225/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\347\271\274\346\211\277/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\350\201\267\345\223\241\347\232\204\344\276\213\345\255\220/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\350\201\267\345\223\241\347\232\204\344\276\213\345\255\220/\346\233\264\351\235\210\346\264\273\347\232\204\345\273\272\346\247\213\345\255\220/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\350\201\267\345\223\241\347\232\204\344\276\213\345\255\220/\347\211\251\344\273\266\347\232\204\345\261\254\346\200\247/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\350\201\267\345\223\241\347\232\204\344\276\213\345\255\220/\347\211\251\344\273\266\347\232\204\345\261\254\346\200\247/\345\261\254\346\200\247\347\232\204\345\212\240\345\205\245/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\350\201\267\345\223\241\347\232\204\344\276\213\345\255\220/\347\211\251\344\273\266\347\232\204\345\261\254\346\200\247/\345\261\254\346\200\247\347\232\204\347\271\274\346\211\277/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\350\201\267\345\223\241\347\232\204\344\276\213\345\255\220/\351\232\216\345\261\244\347\232\204\345\273\272\347\253\213/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\350\241\250\351\201\224\345\274\217/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\350\250\273\350\247\243/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\350\256\212\346\225\270/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\350\277\255\344\273\243\345\231\250\345\222\214\347\224\242\347\224\237\345\231\250/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\201\213\347\256\227\345\255\220/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\201\213\347\256\227\345\255\220/\344\273\243\345\205\245\351\201\213\347\256\227\345\255\220/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\201\213\347\256\227\345\255\220/\344\275\215\345\205\203\351\201\213\347\256\227\345\255\220/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\201\213\347\256\227\345\255\220/\345\255\227\344\270\262\351\201\213\347\256\227\345\255\220/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\201\213\347\256\227\345\255\220/\346\257\224\350\274\203\351\201\213\347\256\227\345\255\220/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\201\213\347\256\227\345\255\220/\347\211\271\346\256\212\351\201\213\347\256\227\345\255\220/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\201\213\347\256\227\345\255\220/\347\256\227\350\241\223\351\201\213\347\256\227\345\255\220/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\201\213\347\256\227\345\255\220/\351\202\217\350\274\257\351\201\213\347\256\227\345\255\220/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\226\211\345\214\205\347\232\204\351\201\213\347\224\250/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\227\234\346\226\274/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\231\243\345\210\227\347\232\204\351\201\213\347\224\250/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\345\207\275\346\225\270/escape_\345\222\214_unescape_\345\207\275\346\225\270/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\345\207\275\346\225\270/eval_\345\207\275\346\225\270/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\345\207\275\346\225\270/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\345\207\275\346\225\270/isfinite_\345\207\275\346\225\270/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\345\207\275\346\225\270/isnan_\345\207\275\346\225\270/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\345\207\275\346\225\270/number_\345\222\214_string_\345\207\275\346\225\270/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\345\207\275\346\225\270/parseint_\345\222\214_parsefloat_\345\207\275\346\225\270/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\346\240\270\345\277\203\347\211\251\344\273\266/array_\347\211\251\344\273\266/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\346\240\270\345\277\203\347\211\251\344\273\266/boolean_\347\211\251\344\273\266/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\346\240\270\345\277\203\347\211\251\344\273\266/date_\347\211\251\344\273\266/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\346\240\270\345\277\203\347\211\251\344\273\266/function_\347\211\251\344\273\266/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\346\240\270\345\277\203\347\211\251\344\273\266/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\346\240\270\345\277\203\347\211\251\344\273\266/math_\347\211\251\344\273\266/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\346\240\270\345\277\203\347\211\251\344\273\266/number_\347\211\251\344\273\266/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\346\240\270\345\277\203\347\211\251\344\273\266/regexp_\347\211\251\344\273\266/index.html" create mode 100644 "files/zh-tw/web/javascript/obsolete_pages/obsolete_pages/obsolete_pages/\351\240\220\345\205\210\345\256\232\347\276\251\347\232\204\346\240\270\345\277\203\347\211\251\344\273\266/string_\347\211\251\344\273\266/index.html" create mode 100644 files/zh-tw/web/javascript/reference/classes/constructor/index.html create mode 100644 files/zh-tw/web/javascript/reference/classes/extends/index.html create mode 100644 files/zh-tw/web/javascript/reference/classes/index.html create mode 100644 files/zh-tw/web/javascript/reference/classes/static/index.html create mode 100644 files/zh-tw/web/javascript/reference/errors/bad_return_or_yield/index.html create mode 100644 files/zh-tw/web/javascript/reference/errors/index.html create mode 100644 files/zh-tw/web/javascript/reference/errors/invalid_array_length/index.html create mode 100644 files/zh-tw/web/javascript/reference/errors/missing_curly_after_property_list/index.html create mode 100644 files/zh-tw/web/javascript/reference/errors/no_properties/index.html create mode 100644 files/zh-tw/web/javascript/reference/errors/not_a_function/index.html create mode 100644 files/zh-tw/web/javascript/reference/errors/not_defined/index.html create mode 100644 files/zh-tw/web/javascript/reference/errors/redeclared_parameter/index.html create mode 100644 files/zh-tw/web/javascript/reference/errors/too_much_recursion/index.html create mode 100644 files/zh-tw/web/javascript/reference/errors/unexpected_type/index.html create mode 100644 files/zh-tw/web/javascript/reference/functions/arguments/callee/index.html create mode 100644 files/zh-tw/web/javascript/reference/functions/arguments/index.html create mode 100644 files/zh-tw/web/javascript/reference/functions/arrow_functions/index.html create mode 100644 files/zh-tw/web/javascript/reference/functions/default_parameters/index.html create mode 100644 files/zh-tw/web/javascript/reference/functions/get/index.html create mode 100644 files/zh-tw/web/javascript/reference/functions/index.html create mode 100644 files/zh-tw/web/javascript/reference/functions/method_definitions/index.html create mode 100644 files/zh-tw/web/javascript/reference/functions/rest_parameters/index.html create mode 100644 files/zh-tw/web/javascript/reference/functions/set/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/@@iterator/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/concat/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/copywithin/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/entries/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/every/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/fill/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/filter/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/find/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/findindex/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/flat/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/foreach/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/from/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/includes/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/indexof/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/isarray/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/join/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/keys/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/lastindexof/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/length/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/map/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/of/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/pop/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/push/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/reduce/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/reverse/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/shift/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/slice/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/some/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/sort/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/splice/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/unshift/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/array/values/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/arraybuffer/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/arraybuffer/prototype/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/asyncfunction/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/bigint/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/boolean/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/dataview/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/date/getday/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/date/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/date/now/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/date/prototype/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/date/utc/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/error/columnnumber/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/error/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/function/apply/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/function/bind/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/function/call/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/function/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/function/length/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/function/prototype/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/infinity/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/isnan/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/json/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/json/parse/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/json/stringify/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/map/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/math/abs/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/math/ceil/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/math/floor/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/math/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/math/max/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/math/pow/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/math/random/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/math/round/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/nan/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/null/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/number/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/number/isfinite/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/number/isnan/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/number/prototype/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/number/toexponential/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/number/tofixed/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/assign/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/create/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/defineproperties/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/defineproperty/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/freeze/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/getprototypeof/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/hasownproperty/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/keys/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/preventextensions/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/proto/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/prototype/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/object/watch/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/parseint/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/promise/all/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/promise/catch/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/promise/finally/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/promise/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/promise/prototype/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/promise/race/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/promise/reject/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/promise/resolve/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/promise/then/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/proxy/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/rangeerror/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/reflect/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/regexp/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/set/add/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/set/clear/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/set/delete/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/set/entries/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/set/has/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/set/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/set/values/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/string/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/string/match/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/string/padstart/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/string/prototype/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/string/replace/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/string/tolowercase/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/typedarray/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/undefined/index.html create mode 100644 files/zh-tw/web/javascript/reference/global_objects/urierror/index.html create mode 100644 files/zh-tw/web/javascript/reference/index.html create mode 100644 files/zh-tw/web/javascript/reference/iteration_protocols/index.html create mode 100644 files/zh-tw/web/javascript/reference/lexical_grammar/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/arithmetic_operators/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/async_function/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/await/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/bitwise_operators/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/comma_operator/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/comparison_operators/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/conditional_operator/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/destructuring_assignment/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/logical_operators/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/object_initializer/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/operator_precedence/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/optional_chaining/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/spread_syntax/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/super/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/this/index.html create mode 100644 files/zh-tw/web/javascript/reference/operators/typeof/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/async_function/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/block/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/break/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/const/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/debugger/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/export/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/for...in/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/function_star_/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/if...else/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/import/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/label/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/let/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/return/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/switch/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/throw/index.html create mode 100644 files/zh-tw/web/javascript/reference/statements/var/index.html create mode 100644 files/zh-tw/web/javascript/reference/strict_mode/index.html create mode 100644 files/zh-tw/web/javascript/reference/template_literals/index.html create mode 100644 files/zh-tw/web/javascript/shells/index.html create mode 100644 files/zh-tw/web/javascript/typed_arrays/index.html create mode 100644 files/zh-tw/web/manifest/index.html create mode 100644 files/zh-tw/web/mathml/authoring/index.html create mode 100644 files/zh-tw/web/mathml/index.html create mode 100644 files/zh-tw/web/media/formats/containers/index.html create mode 100644 files/zh-tw/web/media/formats/index.html create mode 100644 files/zh-tw/web/media/index.html create mode 100644 files/zh-tw/web/opensearch/index.html create mode 100644 files/zh-tw/web/progressive_web_apps/index.html create mode 100644 files/zh-tw/web/reference/api/index.html create mode 100644 files/zh-tw/web/reference/index.html create mode 100644 files/zh-tw/web/security/index.html create mode 100644 files/zh-tw/web/security/insecure_passwords/index.html create mode 100644 files/zh-tw/web/security/mixed_content/how_to_fix_website_with_mixed_content/index.html create mode 100644 files/zh-tw/web/security/mixed_content/index.html create mode 100644 files/zh-tw/web/security/same-origin_policy/index.html create mode 100644 files/zh-tw/web/security/weak_signature_algorithm/index.html create mode 100644 files/zh-tw/web/svg/attribute/fill-rule/index.html create mode 100644 files/zh-tw/web/svg/attribute/index.html create mode 100644 files/zh-tw/web/svg/attribute/stroke-dashoffset/index.html create mode 100644 files/zh-tw/web/svg/index.html create mode 100644 files/zh-tw/web/svg/tutorial/fills_and_strokes/index.html create mode 100644 files/zh-tw/web/svg/tutorial/getting_started/index.html create mode 100644 files/zh-tw/web/svg/tutorial/gradients/index.html create mode 100644 files/zh-tw/web/svg/tutorial/index.html create mode 100644 files/zh-tw/web/svg/tutorial/introduction/index.html create mode 100644 files/zh-tw/web/svg/tutorial/patterns/index.html create mode 100644 files/zh-tw/web/svg/tutorial/positions/index.html create mode 100644 "files/zh-tw/web/svg/tutorial/\350\267\257\345\276\204/index.html" create mode 100644 "files/zh-tw/web/svg/\346\225\231\345\255\270/index.html" create mode 100644 files/zh-tw/web/tutorials/index.html create mode 100644 "files/zh-tw/web/\346\200\247\350\203\275/index.html" create mode 100644 files/zh-tw/web_development/index.html create mode 100644 "files/zh-tw/web_\351\226\213\347\231\274/historical_artifacts_to_avoid/index.html" create mode 100644 "files/zh-tw/web_\351\226\213\347\231\274/index.html" create mode 100644 files/zh-tw/webapi/alarm/index.html create mode 100644 files/zh-tw/webapi/camera/index.html create mode 100644 files/zh-tw/webapi/contacts/index.html create mode 100644 files/zh-tw/webapi/device_storage/index.html create mode 100644 files/zh-tw/webapi/idle/index.html create mode 100644 files/zh-tw/webapi/index.html create mode 100644 files/zh-tw/webapi/network_stats/index.html create mode 100644 files/zh-tw/webapi/permissions/index.html create mode 100644 files/zh-tw/webapi/power_management/index.html create mode 100644 files/zh-tw/webapi/settings/index.html create mode 100644 files/zh-tw/webapi/simple_push/index.html create mode 100644 files/zh-tw/webapi/tcp_socket/index.html create mode 100644 files/zh-tw/webapi/time_and_clock/index.html create mode 100644 files/zh-tw/webapi/web_activities/index.html create mode 100644 files/zh-tw/webapi/webfm_api/index.html create mode 100644 files/zh-tw/webapi/websms/index.html create mode 100644 files/zh-tw/webassembly/index.html create mode 100644 files/zh-tw/websockets/index.html create mode 100644 files/zh-tw/websockets/websockets_reference/closeevent/index.html create mode 100644 files/zh-tw/websockets/websockets_reference/index.html create mode 100644 files/zh-tw/websockets/websockets_reference/messageevent/index.html create mode 100644 files/zh-tw/websockets/websockets_reference/websocket/index.html create mode 100644 files/zh-tw/websockets/writing_websocket_client_applications/index.html create mode 100644 files/zh-tw/xhtml/index.html create mode 100644 files/zh-tw/xpcnativewrapper/index.html create mode 100644 files/zh-tw/xpcom/index.html create mode 100644 "files/zh-tw/xul_\346\225\231\345\255\270/index.html" create mode 100644 files/zh-tw/zh-tw/index.html create mode 100644 files/zh-tw/zones/index.html create mode 100644 "files/zh-tw/\344\273\245_windows_\347\231\273\351\214\204\347\242\274\345\256\211\350\243\235\346\223\264\345\205\205\345\245\227\344\273\266/index.html" create mode 100644 "files/zh-tw/\344\275\210\346\231\257\344\270\273\351\241\214/background/index.html" create mode 100644 "files/zh-tw/\344\275\210\346\231\257\344\270\273\351\241\214/index.html" create mode 100644 "files/zh-tw/\345\217\203\350\210\207_mozilla_\345\260\210\346\241\210/index.html" create mode 100644 "files/zh-tw/\345\273\272\347\253\213\346\223\264\345\205\205\345\245\227\344\273\266/index.html" create mode 100644 "files/zh-tw/\346\223\264\345\205\205\345\245\227\344\273\266/index.html" create mode 100644 "files/zh-tw/\350\243\275\344\275\234_firefox_\344\275\210\346\231\257\344\270\273\351\241\214/contents.rdf/index.html" create mode 100644 "files/zh-tw/\350\243\275\344\275\234_firefox_\344\275\210\346\231\257\344\270\273\351\241\214/index.html" create mode 100644 "files/zh-tw/\350\243\275\344\275\234_firefox_\344\275\210\346\231\257\344\270\273\351\241\214/install.rdf/index.html" create mode 100644 "files/zh-tw/\350\243\275\344\275\234_firefox_\344\275\210\346\231\257\344\270\273\351\241\214/uuid/index.html" create mode 100644 "files/zh-tw/\350\243\275\344\275\234_firefox_\344\275\210\346\231\257\344\270\273\351\241\214/\344\270\212\346\211\213\347\257\207/index.html" (limited to 'files/zh-tw') diff --git a/files/zh-tw/_redirects.txt b/files/zh-tw/_redirects.txt new file mode 100644 index 0000000000..ae909ee393 --- /dev/null +++ b/files/zh-tw/_redirects.txt @@ -0,0 +1,732 @@ +# FROM-URL TO-URL +/zh-TW/docs/%E4%BB%8B%E7%B4%B9 /zh-TW/docs/Mozilla/Developer_guide/Introduction +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup /zh-TW/docs/Web/Apps +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Basics /zh-TW/docs/Web/Apps/Basics +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Design /zh-TW/docs/Web/Apps/Design +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Developing /zh-TW/docs/Web/Apps/Developing +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/FAQs /zh-TW/docs/Web/Apps/FAQs +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/For_Web_developers /zh-TW/docs/Web/Apps/For_Web_developers +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/For_mobile_developers /zh-TW/docs/Web/Apps/For_mobile_developers +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Getting_Started /zh-TW/docs/Web/Apps/Getting_Started +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Publishing /zh-TW/docs/Web/Apps/Publishing +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Quickstart /zh-TW/docs/Web/Apps/Quickstart +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Quickstart/Design /zh-TW/docs/Web/Apps/Quickstart/Design +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Quickstart/Design/Concept_A_great_app /zh-TW/docs/Web/Apps/Quickstart/Design/Concept_A_great_app +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Tutorials /zh-TW/docs/Web/Apps/Tutorials +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Tutorials/Audio_and_video /zh-TW/docs/Web/Apps/Tutorials/Audio_and_video +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Tutorials/Debugging_the_app /zh-TW/docs/Web/Apps/Tutorials/Debugging_the_app +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Tutorials/Games /zh-TW/docs/Web/Apps/Tutorials/Games +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Tutorials/General /zh-TW/docs/Web/Apps/Tutorials/General +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F-840092-dup/Tutorials/General/Maintaining_the_app /zh-TW/docs/Web/Apps/Tutorials/General/Maintaining_the_app +/zh-TW/docs/%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F/Manifest-840092-dup /zh-TW/docs/Web/Apps/Developing/Manifest/Manifest-840092-dup +/zh-TW/docs/%E6%8E%A7%E5%88%B6_HTML_%E8%A1%A8%E5%96%AE%E4%B8%AD%E7%9A%84%E6%8B%BC%E5%AD%97%E6%AA%A2%E6%9F%A5%E5%8A%9F%E8%83%BD /zh-TW/docs/Web/HTML/Global_attributes/spellcheck +/zh-TW/docs/%E6%96%B0%E5%A2%9E%E6%B6%88%E6%81%AF%E4%BE%86%E6%BA%90%E9%96%B1%E8%AE%80%E5%B7%A5%E5%85%B7 /zh-TW/docs/Mozilla/Firefox/Releases/2/Adding_feed_readers_to_Firefox +/zh-TW/docs/%E6%9C%AC%E5%9C%B0%E5%8C%96 /zh-TW/docs/Glossary/Localization +/zh-TW/docs/%E8%87%AA%E7%B6%B2%E9%A0%81%E6%B7%BB%E5%8A%A0%E6%90%9C%E5%B0%8B%E5%BC%95%E6%93%8E /zh-TW/docs/Web/API/Window/sidebar/Adding_search_engines_from_Web_pages +/zh-TW/docs/%E8%A3%BD%E4%BD%9C_Firefox_%E4%BD%88%E6%99%AF%E4%B8%BB%E9%A1%8C:%E4%B8%8A%E6%89%8B%E7%AF%87 /zh-TW/docs/%E8%A3%BD%E4%BD%9C_Firefox_%E4%BD%88%E6%99%AF%E4%B8%BB%E9%A1%8C/%E4%B8%8A%E6%89%8B%E7%AF%87 +/zh-TW/docs/%E8%A3%BD%E4%BD%9C_Firefox_%E4%BD%88%E6%99%AF%E4%B8%BB%E9%A1%8C:UUID /zh-TW/docs/%E8%A3%BD%E4%BD%9C_Firefox_%E4%BD%88%E6%99%AF%E4%B8%BB%E9%A1%8C/UUID +/zh-TW/docs/%E8%A3%BD%E4%BD%9C_Firefox_%E4%BD%88%E6%99%AF%E4%B8%BB%E9%A1%8C:contents.rdf /zh-TW/docs/%E8%A3%BD%E4%BD%9C_Firefox_%E4%BD%88%E6%99%AF%E4%B8%BB%E9%A1%8C/contents.rdf +/zh-TW/docs/%E8%A3%BD%E4%BD%9C_Firefox_%E4%BD%88%E6%99%AF%E4%B8%BB%E9%A1%8C:install.rdf /zh-TW/docs/%E8%A3%BD%E4%BD%9C_Firefox_%E4%BD%88%E6%99%AF%E4%B8%BB%E9%A1%8C/install.rdf +/zh-TW/docs/%E8%A3%BD%E4%BD%9C_OpenSearch_%E6%90%9C%E5%B0%8B%E6%A8%A1%E7%B5%84 /zh-TW/docs/Web/OpenSearch +/zh-TW/docs/%E8%AA%BF%E6%95%B4%E5%88%97%E8%A1%A8%E7%B8%AE%E6%8E%92 /zh-TW/docs/Web/CSS/CSS_Lists_and_Counters/Consistent_list_indentation +/zh-TW/docs/%E9%87%8D%E6%96%B0%E4%BB%8B%E7%B4%B9_JavaScript /zh-TW/docs/Web/JavaScript/A_re-introduction_to_JavaScript +/zh-TW/docs/%E9%A6%96%E9%A0%81 /zh-TW/docs/Web +/zh-TW/docs/AJAX /zh-TW/docs/Web/Guide/AJAX +/zh-TW/docs/AJAX/%E4%B8%8A%E6%89%8B%E7%AF%87 /zh-TW/docs/Web/Guide/AJAX/Getting_Started +/zh-TW/docs/AJAX/Getting_Started /zh-TW/docs/Web/Guide/AJAX/Getting_Started +/zh-TW/docs/AJAX:%E4%B8%8A%E6%89%8B%E7%AF%87 /zh-TW/docs/Web/Guide/AJAX/Getting_Started +/zh-TW/docs/CSS /zh-TW/docs/Web/CSS +/zh-TW/docs/CSS/-moz-border-image /zh-TW/docs/Web/CSS/border-image/border-image +/zh-TW/docs/CSS/@font-face /zh-TW/docs/Web/CSS/@font-face +/zh-TW/docs/CSS/border-image /zh-TW/docs/Web/CSS/border-image +/zh-TW/docs/CSS/border-image/border-image /zh-TW/docs/Web/CSS/border-image/border-image +/zh-TW/docs/CSS/ime-mode /zh-TW/docs/Web/CSS/ime-mode +/zh-TW/docs/CSS:ime-mode /zh-TW/docs/Web/CSS/ime-mode +/zh-TW/docs/CSS_%E4%B8%80%E8%88%AC%E5%95%8F%E9%A1%8C /zh-TW/docs/Web/CSS/Common_CSS_Questions +/zh-TW/docs/CSS_%E5%8B%95%E7%95%AB /zh-TW/docs/Web/CSS/CSS_Animations/Using_CSS_animations +/zh-TW/docs/CSS_%E8%BD%89%E5%A0%B4 /zh-TW/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions +/zh-TW/docs/CSS_%E9%81%8E%E6%B8%A1 /zh-TW/docs/CSS_轉場 +/zh-TW/docs/Canvas_%E6%95%99%E5%AD%B8/%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95 /zh-TW/docs/Canvas_tutorial/Basic_usage +/zh-TW/docs/Canvas_%E6%95%99%E5%AD%B8/%E7%B9%AA%E8%A3%BD%E5%9C%96%E5%BD%A2 /zh-TW/docs/Canvas_tutorial/Drawing_shapes +/zh-TW/docs/Canvas_tutorial /en-US/docs/Web/API/Canvas_API/Tutorial +/zh-TW/docs/Consistent_List_Indentation /zh-TW/docs/Web/CSS/CSS_Lists_and_Counters/Consistent_list_indentation +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8 /zh-TW/docs/Web/JavaScript/Guide +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E4%BB%A5%E9%A1%9E%E5%88%A5%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80_vs._%E4%BB%A5%E5%8E%9F%E5%9E%8B%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BB%A5%E9%A1%9E%E5%88%A5%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80_vs._%E4%BB%A5%E5%8E%9F%E5%9E%8B%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/throw_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/throw_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/try...catch_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/try...catch_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%80%BC /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%80%BC +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%AF%A6%E9%AB%94%E9%97%9C%E4%BF%82%E7%9A%84%E7%A2%BA%E5%AE%9A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%AF%A6%E9%AB%94%E9%97%9C%E4%BF%82%E7%9A%84%E7%A2%BA%E5%AE%9A +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%B1%80%E5%9F%9F%E5%80%BC%E5%92%8C%E7%B9%BC%E6%89%BF%E5%80%BC /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%B1%80%E5%9F%9F%E5%80%BC%E5%92%8C%E7%B9%BC%E6%89%BF%E5%80%BC +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%BB%BA%E6%A7%8B%E5%AD%90%E4%B8%AD%E7%9A%84%E5%85%A8%E5%9F%9F%E8%B3%87%E8%A8%8A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%BB%BA%E6%A7%8B%E5%AD%90%E4%B8%AD%E7%9A%84%E5%85%A8%E5%9F%9F%E8%B3%87%E8%A8%8A +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E6%B2%92%E6%9C%89%E5%A4%9A%E9%87%8D%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E6%B2%92%E6%9C%89%E5%A4%9A%E9%87%8D%E7%B9%BC%E6%89%BF +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%87%BD%E6%95%B8%E7%9A%84%E5%91%BC%E5%8F%AB /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%87%BD%E6%95%B8%E7%9A%84%E5%91%BC%E5%8F%AB +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%87%BD%E6%95%B8%E7%9A%84%E5%AE%9A%E7%BE%A9 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%87%BD%E6%95%B8%E7%9A%84%E5%AE%9A%E7%BE%A9 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%8D%80%E5%A1%8A%E6%96%87%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%8D%80%E5%A1%8A%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%AD%97%E9%9D%A2%E8%A1%A8%E9%81%94 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%AD%97%E9%9D%A2%E8%A1%A8%E9%81%94 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%B8%B8%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%B8%B8%E6%95%B8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%BB%BA%E7%AB%8B%E6%96%B0%E7%9A%84%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BB%BA%E7%AB%8B%E6%96%B0%E7%9A%84%E7%89%A9%E4%BB%B6 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%BB%BA%E7%AB%8B%E6%96%B0%E7%9A%84%E7%89%A9%E4%BB%B6/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/break_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/break_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/continue_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/continue_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/do...while_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/do...while_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/for_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/for_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/label_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/label_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/while_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/while_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%96%87%E6%B3%95 /zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E4%BD%BF%E7%94%A8_this_%E5%8F%96%E5%BE%97%E7%89%A9%E4%BB%B6%E7%9A%84%E5%8F%83%E8%80%83 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E4%BD%BF%E7%94%A8_this_%E5%8F%96%E5%BE%97%E7%89%A9%E4%BB%B6%E7%9A%84%E5%8F%83%E8%80%83 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%88%AA%E9%99%A4 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%88%AA%E9%99%A4 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%BB%BA%E6%A7%8B%E5%AD%90%E5%87%BD%E6%95%B8%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%BB%BA%E6%A7%8B%E5%AD%90%E5%87%BD%E6%95%B8%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E6%96%B9%E6%B3%95%E7%9A%84%E5%AE%9A%E7%BE%A9 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E6%96%B9%E6%B3%95%E7%9A%84%E5%AE%9A%E7%BE%A9 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B4%A2%E5%BC%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B4%A2%E5%BC%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E9%87%9D%E5%B0%8D%E7%89%A9%E4%BB%B6%E7%9A%84%E9%A1%9E%E5%9E%8B%E5%AE%9A%E7%BE%A9%E5%B1%AC%E6%80%A7 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E9%87%9D%E5%B0%8D%E7%89%A9%E4%BB%B6%E7%9A%84%E9%A1%9E%E5%9E%8B%E5%AE%9A%E7%BE%A9%E5%B1%AC%E6%80%A7 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/Getter_%E5%92%8C_Setter_%E7%9A%84%E5%AE%9A%E7%BE%A9 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/Getter_%E5%92%8C_Setter_%E7%9A%84%E5%AE%9A%E7%BE%A9 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%A2%9D%E4%BB%B6%E6%96%87%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%A2%9D%E4%BB%B6%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F /zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E7%89%A9%E4%BB%B6%E5%92%8C%E5%B1%AC%E6%80%A7 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%89%A9%E4%BB%B6%E5%92%8C%E5%B1%AC%E6%80%A7 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E7%89%A9%E4%BB%B6%E7%9A%84%E6%93%8D%E4%BD%9C%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%89%A9%E4%BB%B6%E7%9A%84%E6%93%8D%E4%BD%9C%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%B9%BC%E6%89%BF +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E6%9B%B4%E9%9D%88%E6%B4%BB%E7%9A%84%E5%BB%BA%E6%A7%8B%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E6%9B%B4%E9%9D%88%E6%B4%BB%E7%9A%84%E5%BB%BA%E6%A7%8B%E5%AD%90 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%8A%A0%E5%85%A5 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%8A%A0%E5%85%A5 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E9%9A%8E%E5%B1%A4%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E9%9A%8E%E5%B1%A4%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%A1%A8%E9%81%94%E5%BC%8F /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%A1%A8%E9%81%94%E5%BC%8F +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%A8%BB%E8%A7%A3 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%A8%BB%E8%A7%A3 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%AE%8A%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%AE%8A%E6%95%B8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%92%8C%E7%94%A2%E7%94%9F%E5%99%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%92%8C%E7%94%A2%E7%94%9F%E5%99%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BB%A3%E5%85%A5%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BB%A3%E5%85%A5%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BD%8D%E5%85%83%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BD%8D%E5%85%83%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%81%8B%E7%AE%97%E5%AD%90/%E5%AD%97%E4%B8%B2%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E5%AD%97%E4%B8%B2%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%81%8B%E7%AE%97%E5%AD%90/%E6%AF%94%E8%BC%83%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E6%AF%94%E8%BC%83%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%89%B9%E6%AE%8A%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%89%B9%E6%AE%8A%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%AE%97%E8%A1%93%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%AE%97%E8%A1%93%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%81%8B%E7%AE%97%E5%AD%90/%E9%82%8F%E8%BC%AF%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E9%82%8F%E8%BC%AF%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%96%89%E5%8C%85%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%96%89%E5%8C%85%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%97%9C%E6%96%BC /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%97%9C%E6%96%BC +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%99%A3%E5%88%97%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%99%A3%E5%88%97%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/Number_%E5%92%8C_String_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/Number_%E5%92%8C_String_%E5%87%BD%E6%95%B8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/escape_%E5%92%8C_unescape_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/escape_%E5%92%8C_unescape_%E5%87%BD%E6%95%B8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/eval_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/eval_%E5%87%BD%E6%95%B8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isFinite_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isFinite_%E5%87%BD%E6%95%B8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isNaN_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isNaN_%E5%87%BD%E6%95%B8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/parseInt_%E5%92%8C_parseFloat_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/parseInt_%E5%92%8C_parseFloat_%E5%87%BD%E6%95%B8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Array_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Array_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Boolean_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Boolean_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Date_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Date_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Function_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Function_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Math_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Math_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Number_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Number_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/RegExp_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/RegExp_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/String_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/String_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/JavaScript_%E6%A6%82%E8%A6%81 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/JavaScript_%E6%A6%82%E8%A6%81 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/LiveConnect_%E6%A6%82%E8%A6%81 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/LiveConnect_%E6%A6%82%E8%A6%81/%E5%8C%85%E8%A3%9D%E5%99%A8%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E5%8C%85%E8%A3%9D%E5%99%A8%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_JavaScript_%E5%88%B0_Java_%E7%9A%84%E8%BD%89%E6%8F%9B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_JavaScript_%E5%88%B0_Java_%E7%9A%84%E8%BD%89%E6%8F%9B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_Java_%E5%88%B0_JavaScript_%E7%9A%84%E8%BD%89%E6%8F%9B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_Java_%E5%88%B0_JavaScript_%E7%9A%84%E8%BD%89%E6%8F%9B +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/LiveConnect_%E6%A6%82%E8%A6%81/JavaScript_%E5%90%91_Java_%E7%9A%84%E9%80%9A%E8%A8%8A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/JavaScript_%E5%90%91_Java_%E7%9A%84%E9%80%9A%E8%A8%8A +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A/LiveConnect_%E9%A1%9E%E5%88%A5%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A/LiveConnect_%E9%A1%9E%E5%88%A5%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/Unicode /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/Unicode +/zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/arguments_%E7%89%A9%E4%BB%B6%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Reference/Functions/arguments +/zh-TW/docs/Core_JavaScript_1.5_%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/DOM /en-US/docs/Web/API/Document_Object_Model +/zh-TW/docs/DOM/XMLHttpRequest /zh-TW/docs/Web/API/XMLHttpRequest +/zh-TW/docs/DOM/XMLHttpRequest/FormData /zh-TW/docs/Web/API/FormData +/zh-TW/docs/DOM/XMLHttpRequest/Synchronous_and_Asynchronous_Requests /zh-TW/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests +/zh-TW/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest /zh-TW/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest +/zh-TW/docs/DOM/window.location /zh-TW/docs/Web/API/Window/location +/zh-TW/docs/DOM_%E4%B8%AD%E7%9A%84%E7%A9%BA%E7%99%BD%E5%AD%97%E5%85%83 /zh-TW/docs/Web/API/Document_Object_Model/Whitespace +/zh-TW/docs/Developer_Guide /zh-TW/docs/Mozilla/Developer_guide +/zh-TW/docs/Developer_Guide/%E5%8E%9F%E5%A7%8B%E7%A2%BC /zh-TW/docs/Mozilla/Developer_guide/Source_Code +/zh-TW/docs/Developer_guide_temp /zh-TW/docs/Mozilla/Developer_guide +/zh-TW/docs/Developer_guide_temp/%E4%BB%8B%E7%B4%B9 /zh-TW/docs/Mozilla/Developer_guide/Introduction +/zh-TW/docs/Developer_guide_temp/%E5%8E%9F%E5%A7%8B%E7%A2%BC /zh-TW/docs/Mozilla/Developer_guide/Source_Code +/zh-TW/docs/Developer_guide_temp/Build_Instructions /zh-TW/docs/Mozilla/Developer_guide/Build_Instructions +/zh-TW/docs/Developer_guide_temp/Build_Instructions/Windows_Prerequisites /zh-TW/docs/Mozilla/Developer_guide/Build_Instructions/Windows_Prerequisites +/zh-TW/docs/DragDrop/Drag_and_Drop /zh-TW/docs/Web/API/HTML_Drag_and_Drop_API +/zh-TW/docs/Drawing_text_using_a_canvas /zh-TW/docs/Web/API/Canvas_API/Tutorial/Drawing_text +/zh-TW/docs/Firefox_2 /zh-TW/docs/Mozilla/Firefox/Releases/2 +/zh-TW/docs/Firefox_2_%E6%8A%80%E8%A1%93%E6%96%87%E4%BB%B6 /zh-TW/docs/Mozilla/Firefox/Releases/2 +/zh-TW/docs/Firefox_2_%E7%9A%84%E5%AE%89%E5%85%A8%E5%8A%9F%E8%83%BD /zh-TW/docs/Mozilla/Firefox/Releases/2/Security_changes +/zh-TW/docs/Firefox_3.1_%E6%8A%80%E8%A1%93%E6%96%87%E4%BB%B6 /zh-TW/docs/Firefox_3.5_%E6%8A%80%E8%A1%93%E6%96%87%E4%BB%B6 +/zh-TW/docs/Firefox_3_%E6%8A%80%E8%A1%93%E6%96%87%E4%BB%B6 /zh-TW/docs/Mozilla/Firefox/Releases/3 +/zh-TW/docs/Firefox_3_CSS_Improvement /zh-TW/docs/Mozilla/Firefox/Releases/3/Firefox_3_CSS_Improvement +/zh-TW/docs/Firefox_3_Dom_Improvements /zh-TW/docs/Mozilla/Firefox/Releases/3/DOM_improvements +/zh-TW/docs/Firefox_3_Online_and_Offline_Events /zh-TW/docs/Web/API/NavigatorOnLine/Online_and_offline_events +/zh-TW/docs/Firefox_3_Web-based_protocol_handler /zh-TW/docs/Web/API/Navigator/registerProtocolHandler/Web-based_protocol_handlers +/zh-TW/docs/Firefox_3_for_developers /zh-TW/docs/Mozilla/Firefox/Releases/3 +/zh-TW/docs/Firefox_3_supports_Cross-site_XMLHttpRequest /zh-TW/docs/Cross-site_XMLHttpRequest +/zh-TW/docs/Firefox_4_%E9%96%8B%E7%99%BC%E8%80%85%E6%96%B0%E5%8A%9F%E8%83%BD%E6%A6%82%E8%A6%BD /zh-TW/docs/Mozilla/Firefox/Releases/4/Firefox_4_%E9%96%8B%E7%99%BC%E8%80%85%E6%96%B0%E5%8A%9F%E8%83%BD%E6%A6%82%E8%A6%BD +/zh-TW/docs/Firefox_4_for_developers /zh-TW/docs/Mozilla/Firefox/Releases/4 +/zh-TW/docs/Firefox_4_for_developers/Firefox_4_%E9%96%8B%E7%99%BC%E8%80%85%E6%96%B0%E5%8A%9F%E8%83%BD%E6%A6%82%E8%A6%BD /zh-TW/docs/Mozilla/Firefox/Releases/4/Firefox_4_%E9%96%8B%E7%99%BC%E8%80%85%E6%96%B0%E5%8A%9F%E8%83%BD%E6%A6%82%E8%A6%BD +/zh-TW/docs/Firefox_7_for_developers /zh-TW/docs/Mozilla/Firefox/Releases/7 +/zh-TW/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/%E7%90%83%E6%8B%8D%E5%92%8C%E9%8D%B5%E7%9B%A4%E6%8E%A7%E5%88%B6 /zh-TW/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls +/zh-TW/docs/Games/Workflows /zh-TW/docs/Games/Tutorials +/zh-TW/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript /zh-TW/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript +/zh-TW/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/%E7%90%83%E6%8B%8D%E5%92%8C%E9%8D%B5%E7%9B%A4%E6%8E%A7%E5%88%B6 /zh-TW/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls +/zh-TW/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls /zh-TW/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls +/zh-TW/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it /zh-TW/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it +/zh-TW/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball /zh-TW/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball +/zh-TW/docs/Glossary/%E5%81%BD%E5%85%83%E7%B4%A0 /zh-TW/docs/Glossary/Pseudo-element +/zh-TW/docs/Glossary/%E5%AD%97%E5%85%83 /zh-TW/docs/Glossary/Character +/zh-TW/docs/Glossary/%E5%AD%97%E5%85%83%E7%B7%A8%E7%A2%BC /zh-TW/docs/Glossary/character_encoding +/zh-TW/docs/Glossary/%E5%B8%83%E6%9E%97 /zh-TW/docs/Glossary/Boolean +/zh-TW/docs/Glossary/%E6%8A%BD%E8%B1%A1%E5%8C%96 /zh-TW/docs/Glossary/Abstraction +/zh-TW/docs/Glossary/%E7%80%8F%E8%A6%BD%E5%99%A8 /zh-TW/docs/Glossary/Browser +/zh-TW/docs/Glossary/%E7%89%A9%E4%BB%B6%E5%B0%8E%E5%90%91%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88(OOP) /zh-TW/docs/Glossary/OOP +/zh-TW/docs/Glossary/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B /zh-TW/docs/Glossary/Data_structure +/zh-TW/docs/Glossary/%E9%99%A3%E5%88%97 /zh-TW/docs/Glossary/array +/zh-TW/docs/HTML /zh-TW/docs/Web/HTML +/zh-TW/docs/HTML/Canvas /zh-TW/docs/Web/API/Canvas_API +/zh-TW/docs/HTML/Element /zh-TW/docs/Web/HTML/Element +/zh-TW/docs/HTML/Element/HTML_%E5%85%83%E7%B4%A0 /zh-TW/docs/Web/HTML/Element +/zh-TW/docs/HTML/Element/a /zh-TW/docs/Web/HTML/Element/a +/zh-TW/docs/HTML/HTML5 /zh-TW/docs/Web/Guide/HTML/HTML5 +/zh-TW/docs/HTML/HTML5_%E8%A1%A8%E5%96%AE /zh-TW/docs/Learn/HTML/Forms +/zh-TW/docs/HTML/HTML_%E5%85%83%E7%B4%A0 /zh-TW/docs/Web/HTML/HTML_%E5%85%83%E7%B4%A0 +/zh-TW/docs/HTML/Introduction /zh-CN/docs/learn/HTML/Introduction_to_HTML +/zh-TW/docs/HTTP /zh-TW/docs/Web/HTTP +/zh-TW/docs/HTTP/Access_control_CORS /zh-TW/docs/Web/HTTP/CORS +/zh-TW/docs/HTTP/Browser_detection_using_the_user_agent /zh-TW/docs/Web/HTTP/Browser_detection_using_the_user_agent +/zh-TW/docs/HTTP/Link_prefetching_FAQ /zh-TW/docs/Web/HTTP/Link_prefetching_FAQ +/zh-TW/docs/HTTP/Response_codes /zh-TW/docs/Web/HTTP/Status +/zh-TW/docs/HTTP/X-Frame-Options /zh-TW/docs/Web/HTTP/Headers/X-Frame-Options +/zh-TW/docs/HTTP/data_URIs /zh-TW/docs/Web/HTTP/data_URIs +/zh-TW/docs/IndexedDB /zh-TW/docs/Web/API/IndexedDB_API +/zh-TW/docs/IndexedDB/Basic_Concepts_Behind_IndexedDB /zh-TW/docs/Web/API/IndexedDB_API/Basic_Concepts_Behind_IndexedDB +/zh-TW/docs/IndexedDB/Using_IndexedDB /zh-TW/docs/Web/API/IndexedDB_API/Using_IndexedDB +/zh-TW/docs/JavaScript /zh-TW/docs/Web/JavaScript +/zh-TW/docs/JavaScript/About_JavaScript /zh-TW/docs/Web/JavaScript/About_JavaScript +/zh-TW/docs/JavaScript/Guide /zh-TW/docs/Web/JavaScript/Guide +/zh-TW/docs/JavaScript/Guide/Details_of_the_Object_Model /zh-TW/docs/Web/JavaScript/Guide/Details_of_the_Object_Model +/zh-TW/docs/JavaScript/Guide/Functions /zh-TW/docs/Web/JavaScript/Guide/Functions +/zh-TW/docs/JavaScript/Guide/JavaScript_%E6%A6%82%E8%A7%80 /zh-TW/docs/Web/JavaScript/Guide/Introduction +/zh-TW/docs/JavaScript/Guide/JavaScript_%E6%A6%82%E8%A7%80%EF%BC%88JavaScript_Overview%EF%BC%89 /zh-TW/docs/Web/JavaScript/Guide/Introduction +/zh-TW/docs/JavaScript/Guide/JavaScript_Overview /zh-TW/docs/Web/JavaScript/Guide/Introduction +/zh-TW/docs/JavaScript/Guide/JavaScript_Overview-redirect-1 /zh-TW/docs/Web/JavaScript/Guide/Introduction +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages /zh-TW/docs/Web/JavaScript/Guide +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E4%BB%A5%E9%A1%9E%E5%88%A5%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80_vs._%E4%BB%A5%E5%8E%9F%E5%9E%8B%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BB%A5%E9%A1%9E%E5%88%A5%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80_vs._%E4%BB%A5%E5%8E%9F%E5%9E%8B%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/throw_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/throw_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/try...catch_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/try...catch_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%80%BC /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%80%BC +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%AF%A6%E9%AB%94%E9%97%9C%E4%BF%82%E7%9A%84%E7%A2%BA%E5%AE%9A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%AF%A6%E9%AB%94%E9%97%9C%E4%BF%82%E7%9A%84%E7%A2%BA%E5%AE%9A +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%B1%80%E5%9F%9F%E5%80%BC%E5%92%8C%E7%B9%BC%E6%89%BF%E5%80%BC /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%B1%80%E5%9F%9F%E5%80%BC%E5%92%8C%E7%B9%BC%E6%89%BF%E5%80%BC +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%BB%BA%E6%A7%8B%E5%AD%90%E4%B8%AD%E7%9A%84%E5%85%A8%E5%9F%9F%E8%B3%87%E8%A8%8A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%BB%BA%E6%A7%8B%E5%AD%90%E4%B8%AD%E7%9A%84%E5%85%A8%E5%9F%9F%E8%B3%87%E8%A8%8A +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E6%B2%92%E6%9C%89%E5%A4%9A%E9%87%8D%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E6%B2%92%E6%9C%89%E5%A4%9A%E9%87%8D%E7%B9%BC%E6%89%BF +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%87%BD%E6%95%B8%E7%9A%84%E5%91%BC%E5%8F%AB /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%87%BD%E6%95%B8%E7%9A%84%E5%91%BC%E5%8F%AB +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%87%BD%E6%95%B8%E7%9A%84%E5%AE%9A%E7%BE%A9 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%87%BD%E6%95%B8%E7%9A%84%E5%AE%9A%E7%BE%A9 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E6%96%87%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%AD%97%E9%9D%A2%E8%A1%A8%E9%81%94 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%AD%97%E9%9D%A2%E8%A1%A8%E9%81%94 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%B8%B8%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%B8%B8%E6%95%B8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%BB%BA%E7%AB%8B%E6%96%B0%E7%9A%84%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BB%BA%E7%AB%8B%E6%96%B0%E7%9A%84%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%BB%BA%E7%AB%8B%E6%96%B0%E7%9A%84%E7%89%A9%E4%BB%B6/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/break_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/break_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/continue_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/continue_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/do...while_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/do...while_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/for_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/for_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/label_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/label_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/while_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/while_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%96%87%E6%B3%95 /zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E4%BD%BF%E7%94%A8_this_%E5%8F%96%E5%BE%97%E7%89%A9%E4%BB%B6%E7%9A%84%E5%8F%83%E8%80%83 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E4%BD%BF%E7%94%A8_this_%E5%8F%96%E5%BE%97%E7%89%A9%E4%BB%B6%E7%9A%84%E5%8F%83%E8%80%83 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%88%AA%E9%99%A4 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%88%AA%E9%99%A4 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%BB%BA%E6%A7%8B%E5%AD%90%E5%87%BD%E6%95%B8%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%BB%BA%E6%A7%8B%E5%AD%90%E5%87%BD%E6%95%B8%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E6%96%B9%E6%B3%95%E7%9A%84%E5%AE%9A%E7%BE%A9 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E6%96%B9%E6%B3%95%E7%9A%84%E5%AE%9A%E7%BE%A9 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B4%A2%E5%BC%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B4%A2%E5%BC%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E9%87%9D%E5%B0%8D%E7%89%A9%E4%BB%B6%E7%9A%84%E9%A1%9E%E5%9E%8B%E5%AE%9A%E7%BE%A9%E5%B1%AC%E6%80%A7 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E9%87%9D%E5%B0%8D%E7%89%A9%E4%BB%B6%E7%9A%84%E9%A1%9E%E5%9E%8B%E5%AE%9A%E7%BE%A9%E5%B1%AC%E6%80%A7 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/Getter_%E5%92%8C_Setter_%E7%9A%84%E5%AE%9A%E7%BE%A9 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/Getter_%E5%92%8C_Setter_%E7%9A%84%E5%AE%9A%E7%BE%A9 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E6%96%87%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F /zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E7%89%A9%E4%BB%B6%E5%92%8C%E5%B1%AC%E6%80%A7 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%89%A9%E4%BB%B6%E5%92%8C%E5%B1%AC%E6%80%A7 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E7%89%A9%E4%BB%B6%E7%9A%84%E6%93%8D%E4%BD%9C%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%89%A9%E4%BB%B6%E7%9A%84%E6%93%8D%E4%BD%9C%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%B9%BC%E6%89%BF +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E6%9B%B4%E9%9D%88%E6%B4%BB%E7%9A%84%E5%BB%BA%E6%A7%8B%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E6%9B%B4%E9%9D%88%E6%B4%BB%E7%9A%84%E5%BB%BA%E6%A7%8B%E5%AD%90 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%8A%A0%E5%85%A5 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%8A%A0%E5%85%A5 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E9%9A%8E%E5%B1%A4%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E9%9A%8E%E5%B1%A4%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E8%A1%A8%E9%81%94%E5%BC%8F /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%A1%A8%E9%81%94%E5%BC%8F +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E8%A8%BB%E8%A7%A3 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%A8%BB%E8%A7%A3 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E8%AE%8A%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%AE%8A%E6%95%B8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%92%8C%E7%94%A2%E7%94%9F%E5%99%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%92%8C%E7%94%A2%E7%94%9F%E5%99%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BB%A3%E5%85%A5%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BB%A3%E5%85%A5%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BD%8D%E5%85%83%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BD%8D%E5%85%83%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E5%AD%97%E4%B8%B2%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E5%AD%97%E4%B8%B2%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E6%AF%94%E8%BC%83%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E6%AF%94%E8%BC%83%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%89%B9%E6%AE%8A%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%89%B9%E6%AE%8A%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%AE%97%E8%A1%93%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%AE%97%E8%A1%93%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E9%82%8F%E8%BC%AF%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E9%82%8F%E8%BC%AF%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%96%89%E5%8C%85%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%96%89%E5%8C%85%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%97%9C%E6%96%BC /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%97%9C%E6%96%BC +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%99%A3%E5%88%97%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%99%A3%E5%88%97%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/Number_%E5%92%8C_String_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/Number_%E5%92%8C_String_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/escape_%E5%92%8C_unescape_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/escape_%E5%92%8C_unescape_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/eval_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/eval_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isFinite_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isFinite_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isNaN_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isNaN_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/parseInt_%E5%92%8C_parseFloat_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/parseInt_%E5%92%8C_parseFloat_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Array_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Array_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Boolean_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Boolean_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Date_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Date_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Function_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Function_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Math_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Math_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Number_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Number_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/RegExp_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/RegExp_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/String_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/String_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/JavaScript_%E6%A6%82%E8%A6%81 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/JavaScript_%E6%A6%82%E8%A6%81 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E5%8C%85%E8%A3%9D%E5%99%A8%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E5%8C%85%E8%A3%9D%E5%99%A8%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_JavaScript_%E5%88%B0_Java_%E7%9A%84%E8%BD%89%E6%8F%9B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_JavaScript_%E5%88%B0_Java_%E7%9A%84%E8%BD%89%E6%8F%9B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_Java_%E5%88%B0_JavaScript_%E7%9A%84%E8%BD%89%E6%8F%9B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_Java_%E5%88%B0_JavaScript_%E7%9A%84%E8%BD%89%E6%8F%9B +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/JavaScript_%E5%90%91_Java_%E7%9A%84%E9%80%9A%E8%A8%8A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/JavaScript_%E5%90%91_Java_%E7%9A%84%E9%80%9A%E8%A8%8A +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A/LiveConnect_%E9%A1%9E%E5%88%A5%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A/LiveConnect_%E9%A1%9E%E5%88%A5%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/Unicode /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/Unicode +/zh-TW/docs/JavaScript/Guide/Obsolete_Pages/arguments_%E7%89%A9%E4%BB%B6%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Reference/Functions/arguments +/zh-TW/docs/JavaScript/Guide/Regular_Expressions /zh-TW/docs/Web/JavaScript/Guide/Regular_Expressions +/zh-TW/docs/JavaScript/Guide/Values,_variables,_and_literals /zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types +/zh-TW/docs/JavaScript/Guide/Working_with_Objects /zh-TW/docs/Web/JavaScript/Guide/Working_with_Objects +/zh-TW/docs/JavaScript/New_in_JavaScript /zh-TW/docs/Web/JavaScript/New_in_JavaScript +/zh-TW/docs/JavaScript/New_in_JavaScript/JavaScript_1.6_%E6%96%B0%E9%AE%AE%E4%BA%8B /zh-TW/docs/Web/JavaScript/New_in_JavaScript/1.6 +/zh-TW/docs/JavaScript/New_in_JavaScript/JavaScript_1.7_%E6%96%B0%E9%AE%AE%E4%BA%8B /zh-TW/docs/Web/JavaScript/New_in_JavaScript/1.7 +/zh-TW/docs/JavaScript/Obsolete_Pages /zh-TW/docs/Web/JavaScript/Obsolete_Pages +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages /zh-TW/docs/Web/JavaScript/Guide +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages /zh-TW/docs/Web/JavaScript/Guide +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BB%A5%E9%A1%9E%E5%88%A5%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80_vs._%E4%BB%A5%E5%8E%9F%E5%9E%8B%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BB%A5%E9%A1%9E%E5%88%A5%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80_vs._%E4%BB%A5%E5%8E%9F%E5%9E%8B%E7%82%BA%E5%9F%BA%E7%A4%8E%E7%9A%84%E8%AA%9E%E8%A8%80 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/throw_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/throw_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/try...catch_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%E8%AA%9E%E6%B3%95/try...catch_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%80%BC /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%80%BC +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%AF%A6%E9%AB%94%E9%97%9C%E4%BF%82%E7%9A%84%E7%A2%BA%E5%AE%9A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%AF%A6%E9%AB%94%E9%97%9C%E4%BF%82%E7%9A%84%E7%A2%BA%E5%AE%9A +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%B1%80%E5%9F%9F%E5%80%BC%E5%92%8C%E7%B9%BC%E6%89%BF%E5%80%BC /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%B1%80%E5%9F%9F%E5%80%BC%E5%92%8C%E7%B9%BC%E6%89%BF%E5%80%BC +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%BB%BA%E6%A7%8B%E5%AD%90%E4%B8%AD%E7%9A%84%E5%85%A8%E5%9F%9F%E8%B3%87%E8%A8%8A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E5%BB%BA%E6%A7%8B%E5%AD%90%E4%B8%AD%E7%9A%84%E5%85%A8%E5%9F%9F%E8%B3%87%E8%A8%8A +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E6%B2%92%E6%9C%89%E5%A4%9A%E9%87%8D%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%86%8D%E8%AB%87%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF/%E6%B2%92%E6%9C%89%E5%A4%9A%E9%87%8D%E7%B9%BC%E6%89%BF +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%87%BD%E6%95%B8%E7%9A%84%E5%91%BC%E5%8F%AB /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%87%BD%E6%95%B8%E7%9A%84%E5%91%BC%E5%8F%AB +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%87%BD%E6%95%B8%E7%9A%84%E5%AE%9A%E7%BE%A9 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%87%BD%E6%95%B8%E7%9A%84%E5%AE%9A%E7%BE%A9 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E6%96%87%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%AD%97%E9%9D%A2%E8%A1%A8%E9%81%94 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%AD%97%E9%9D%A2%E8%A1%A8%E9%81%94 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%B8%B8%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%B8%B8%E6%95%B8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BB%BA%E7%AB%8B%E6%96%B0%E7%9A%84%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BB%BA%E7%AB%8B%E6%96%B0%E7%9A%84%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BB%BA%E7%AB%8B%E6%96%B0%E7%9A%84%E7%89%A9%E4%BB%B6/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/break_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/break_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/continue_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/continue_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/do...while_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/do...while_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/for_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/for_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/label_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/label_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/while_%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BE%AA%E7%92%B0%E8%AA%9E%E6%B3%95/while_%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%87%E6%B3%95 /zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E4%BD%BF%E7%94%A8_this_%E5%8F%96%E5%BE%97%E7%89%A9%E4%BB%B6%E7%9A%84%E5%8F%83%E8%80%83 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E4%BD%BF%E7%94%A8_this_%E5%8F%96%E5%BE%97%E7%89%A9%E4%BB%B6%E7%9A%84%E5%8F%83%E8%80%83 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%88%AA%E9%99%A4 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%88%AA%E9%99%A4 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%BB%BA%E6%A7%8B%E5%AD%90%E5%87%BD%E6%95%B8%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E5%BB%BA%E6%A7%8B%E5%AD%90%E5%87%BD%E6%95%B8%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E6%96%B9%E6%B3%95%E7%9A%84%E5%AE%9A%E7%BE%A9 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E6%96%B9%E6%B3%95%E7%9A%84%E5%AE%9A%E7%BE%A9 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B4%A2%E5%BC%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B4%A2%E5%BC%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E9%87%9D%E5%B0%8D%E7%89%A9%E4%BB%B6%E7%9A%84%E9%A1%9E%E5%9E%8B%E5%AE%9A%E7%BE%A9%E5%B1%AC%E6%80%A7 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E9%87%9D%E5%B0%8D%E7%89%A9%E4%BB%B6%E7%9A%84%E9%A1%9E%E5%9E%8B%E5%AE%9A%E7%BE%A9%E5%B1%AC%E6%80%A7 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/Getter_%E5%92%8C_Setter_%E7%9A%84%E5%AE%9A%E7%BE%A9 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/Getter_%E5%92%8C_Setter_%E7%9A%84%E5%AE%9A%E7%BE%A9 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E6%96%87%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F /zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%89%A9%E4%BB%B6%E5%92%8C%E5%B1%AC%E6%80%A7 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%89%A9%E4%BB%B6%E5%92%8C%E5%B1%AC%E6%80%A7 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%89%A9%E4%BB%B6%E7%9A%84%E6%93%8D%E4%BD%9C%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%89%A9%E4%BB%B6%E7%9A%84%E6%93%8D%E4%BD%9C%E8%AA%9E%E6%B3%95 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E7%B9%BC%E6%89%BF +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E6%9B%B4%E9%9D%88%E6%B4%BB%E7%9A%84%E5%BB%BA%E6%A7%8B%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E6%9B%B4%E9%9D%88%E6%B4%BB%E7%9A%84%E5%BB%BA%E6%A7%8B%E5%AD%90 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%8A%A0%E5%85%A5 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E5%8A%A0%E5%85%A5 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E7%89%A9%E4%BB%B6%E7%9A%84%E5%B1%AC%E6%80%A7/%E5%B1%AC%E6%80%A7%E7%9A%84%E7%B9%BC%E6%89%BF +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E9%9A%8E%E5%B1%A4%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%81%B7%E5%93%A1%E7%9A%84%E4%BE%8B%E5%AD%90/%E9%9A%8E%E5%B1%A4%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%A1%A8%E9%81%94%E5%BC%8F /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%A1%A8%E9%81%94%E5%BC%8F +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%A8%BB%E8%A7%A3 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%A8%BB%E8%A7%A3 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%AE%8A%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%AE%8A%E6%95%B8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%92%8C%E7%94%A2%E7%94%9F%E5%99%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%92%8C%E7%94%A2%E7%94%9F%E5%99%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BB%A3%E5%85%A5%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BB%A3%E5%85%A5%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BD%8D%E5%85%83%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E4%BD%8D%E5%85%83%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E5%AD%97%E4%B8%B2%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E5%AD%97%E4%B8%B2%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E6%AF%94%E8%BC%83%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E6%AF%94%E8%BC%83%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%89%B9%E6%AE%8A%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%89%B9%E6%AE%8A%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%AE%97%E8%A1%93%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E7%AE%97%E8%A1%93%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E9%82%8F%E8%BC%AF%E9%81%8B%E7%AE%97%E5%AD%90 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%81%8B%E7%AE%97%E5%AD%90/%E9%82%8F%E8%BC%AF%E9%81%8B%E7%AE%97%E5%AD%90 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%96%89%E5%8C%85%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%96%89%E5%8C%85%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%97%9C%E6%96%BC /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%97%9C%E6%96%BC +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%99%A3%E5%88%97%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%99%A3%E5%88%97%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/Number_%E5%92%8C_String_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/Number_%E5%92%8C_String_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/escape_%E5%92%8C_unescape_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/escape_%E5%92%8C_unescape_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/eval_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/eval_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isFinite_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isFinite_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isNaN_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/isNaN_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/parseInt_%E5%92%8C_parseFloat_%E5%87%BD%E6%95%B8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E5%87%BD%E6%95%B8/parseInt_%E5%92%8C_parseFloat_%E5%87%BD%E6%95%B8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Array_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Array_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Boolean_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Boolean_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Date_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Date_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Function_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Function_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Math_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Math_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Number_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/Number_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/RegExp_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/RegExp_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/String_%E7%89%A9%E4%BB%B6 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E9%A0%90%E5%85%88%E5%AE%9A%E7%BE%A9%E7%9A%84%E6%A0%B8%E5%BF%83%E7%89%A9%E4%BB%B6/String_%E7%89%A9%E4%BB%B6 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/JavaScript_%E6%A6%82%E8%A6%81 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/JavaScript_%E6%A6%82%E8%A6%81 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E5%8C%85%E8%A3%9D%E5%99%A8%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E5%8C%85%E8%A3%9D%E5%99%A8%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_JavaScript_%E5%88%B0_Java_%E7%9A%84%E8%BD%89%E6%8F%9B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_JavaScript_%E5%88%B0_Java_%E7%9A%84%E8%BD%89%E6%8F%9B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_Java_%E5%88%B0_JavaScript_%E7%9A%84%E8%BD%89%E6%8F%9B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B%E7%9A%84%E8%BD%89%E6%8F%9B/%E5%BE%9E_Java_%E5%88%B0_JavaScript_%E7%9A%84%E8%BD%89%E6%8F%9B +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/JavaScript_%E5%90%91_Java_%E7%9A%84%E9%80%9A%E8%A8%8A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/JavaScript_%E5%90%91_Java_%E7%9A%84%E9%80%9A%E8%A8%8A +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A/LiveConnect_%E9%A1%9E%E5%88%A5%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_%E6%A6%82%E8%A6%81/Java_%E5%90%91_JavaScript_%E7%9A%84%E9%80%9A%E8%A8%8A/LiveConnect_%E9%A1%9E%E5%88%A5%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/Unicode /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/Unicode +/zh-TW/docs/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/arguments_%E7%89%A9%E4%BB%B6%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Reference/Functions/arguments +/zh-TW/docs/JavaScript/Reference /zh-TW/docs/Web/JavaScript/Reference +/zh-TW/docs/JavaScript/Reference/Global_Objects /zh-TW/docs/Web/JavaScript/Reference/Global_Objects +/zh-TW/docs/JavaScript/Reference/Global_Objects/Function /zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function +/zh-TW/docs/JavaScript/Reference/Global_Objects/Function/call /zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/call +/zh-TW/docs/JavaScript/Reference/Global_Objects/String /zh-TW/docs/Web/JavaScript/Reference/Global_Objects/String +/zh-TW/docs/JavaScript/Reference/Global_Objects/String/replace /zh-TW/docs/Web/JavaScript/Reference/Global_Objects/String/replace +/zh-TW/docs/JavaScript/Reference/Operators /zh-TW/docs/Web/JavaScript/Reference/Operators +/zh-TW/docs/JavaScript/Reference/Operators/typeof /zh-TW/docs/Web/JavaScript/Reference/Operators/typeof +/zh-TW/docs/JavaScript/Reference/Statements /zh-TW/docs/Web/JavaScript/Reference/Statements +/zh-TW/docs/JavaScript/Reference/Statements/block /zh-TW/docs/Web/JavaScript/Reference/Statements/block +/zh-TW/docs/JavaScript/Reference/Statements/break /zh-TW/docs/Web/JavaScript/Reference/Statements/break +/zh-TW/docs/JavaScript/Reference/Statements/for...in /zh-TW/docs/Web/JavaScript/Reference/Statements/for...in +/zh-TW/docs/JavaScript/Reference/Statements/var /zh-TW/docs/Web/JavaScript/Reference/Statements/var +/zh-TW/docs/JavaScript/Same_origin_policy_for_JavaScript /zh-TW/docs/Web/Security/Same-origin_policy +/zh-TW/docs/JavaScript_%E6%8A%80%E8%A1%93%E7%B0%A1%E4%BB%8B /zh-TW/docs/Web/JavaScript/JavaScript_technologies_overview +/zh-TW/docs/JavaScript_%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F /zh-TW/docs/Web/JavaScript/Guide/Regular_Expressions +/zh-TW/docs/JavaScript_%E7%89%A9%E4%BB%B6%E5%B0%8E%E5%90%91%E4%BB%8B%E7%B4%B9 /zh-TW/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript +/zh-TW/docs/JavaScript_%E8%AA%9E%E8%A8%80%E7%9A%84%E8%B3%87%E6%BA%90 /zh-TW/docs/Web/JavaScript/Language_Resources +/zh-TW/docs/JavaScript_1.6_%E6%96%B0%E9%AE%AE%E4%BA%8B /zh-TW/docs/Web/JavaScript/New_in_JavaScript/1.6 +/zh-TW/docs/JavaScript_1.7_%E6%96%B0%E9%AE%AE%E4%BA%8B /zh-TW/docs/Web/JavaScript/New_in_JavaScript/1.7 +/zh-TW/docs/JavaScript_1.8.1_%E6%96%B0%E9%AE%AE%E4%BA%8B /zh-TW/docs/Web/JavaScript/New_in_JavaScript/1.8.1 +/zh-TW/docs/JavaScript_1.8_%E6%96%B0%E9%AE%AE%E4%BA%8B /zh-TW/docs/Web/JavaScript/New_in_JavaScript/1.8 +/zh-TW/docs/JavaScript_technologies_overview /zh-TW/docs/Web/JavaScript/JavaScript_technologies_overview +/zh-TW/docs/JavaScript_technologies_overview-redirect-1 /zh-TW/docs/Web/JavaScript/JavaScript_technologies_overview +/zh-TW/docs/JavaScript_typed_arrays /zh-TW/docs/Web/JavaScript/Typed_arrays +/zh-TW/docs/JavaScript_typed_arrays/ArrayBuffer /zh-TW/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer +/zh-TW/docs/Learn/CSS/%E6%96%87%E5%AD%97%E6%A8%A3%E5%BC%8F /zh-TW/docs/Learn/CSS/Styling_text +/zh-TW/docs/Learn/CSS/%E6%A8%A3%E5%BC%8F%E5%8C%96%E5%AE%B9%E5%99%A8 /en-US/docs/Learn/CSS/Building_blocks +/zh-TW/docs/Learn/CSS/CSS_%E8%BD%89%E5%A0%B4 /zh-TW/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions +/zh-TW/docs/Learn/CSS/Consistent_List_Indentation /zh-TW/docs/Web/CSS/CSS_Lists_and_Counters/Consistent_list_indentation +/zh-TW/docs/Learn/CSS/Getting_started /en-US/docs/Learn/CSS/First_steps +/zh-TW/docs/Learn/CSS/Getting_started/Layout /zh-TW/docs/Learn/CSS/CSS_layout +/zh-TW/docs/Learn/CSS/Getting_started/What_is_CSS /en-US/docs/Learn/CSS/First_steps/How_CSS_works +/zh-TW/docs/Learn/CSS/Getting_started/Why_use_CSS /en-US/docs/Learn/CSS/First_steps/How_CSS_works +/zh-TW/docs/Learn/CSS/Introduction_to_CSS /en-US/docs/Learn/CSS/First_steps +/zh-TW/docs/Learn/CSS/Introduction_to_CSS/How_CSS_works /en-US/docs/Learn/CSS/First_steps/How_CSS_works +/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Layout /zh-TW/docs/Learn/CSS/CSS_layout +/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Selectors /en-US/docs/Learn/CSS/Building_blocks/Selectors +/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Syntax /en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured +/zh-TW/docs/Learn/CSS/Introduction_to_CSS/What_is_CSS /en-US/docs/Learn/CSS/First_steps/How_CSS_works +/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Why_use_CSS /en-US/docs/Learn/CSS/First_steps/How_CSS_works +/zh-TW/docs/Learn/CSS/Styling_boxes /en-US/docs/Learn/CSS/Building_blocks +/zh-TW/docs/Learn/CSS/Testing_media_queries /zh-TW/docs/Web/CSS/Media_Queries/Testing_media_queries +/zh-TW/docs/Learn/CSS/Understanding_z_index /zh-TW/docs/Web/CSS/CSS_Positioning/Understanding_z_index +/zh-TW/docs/Learn/CSS/Understanding_z_index/Stacking_context_example_1 /zh-TW/docs/Web/CSS/CSS_Positioning/Understanding_z_index/Stacking_context_example_1 +/zh-TW/docs/Learn/CSS/Using_the_:target_selector /zh-TW/docs/Web/CSS/CSS_Selectors/Using_the_:target_pseudo-class_in_selectors +/zh-TW/docs/Learn/HTML/HTML%E4%BB%8B%E7%B4%B9 /zh-TW/docs/Learn/HTML/Introduction_to_HTML +/zh-TW/docs/Learn/JavaScript/%E5%A6%82%E4%BD%95%E9%81%8B%E7%94%A8 /zh-TW/docs/Learn/JavaScript/Howto +/zh-TW/docs/Learn/JavaScript/%E7%AC%AC%E4%B8%80%E6%AD%A5 /zh-TW/docs/Learn/JavaScript/First_steps +/zh-TW/docs/Learn/JavaScript/Building_blocks/%E5%87%BD%E6%95%B8 /zh-TW/docs/Learn/JavaScript/Building_blocks/Functions +/zh-TW/docs/Learn/JavaScript/Building_blocks/%E5%9B%9E%E5%82%B3%E5%80%BC /zh-TW/docs/Learn/JavaScript/Building_blocks/Return_values +/zh-TW/docs/Learn/JavaScript/Building_blocks/%E5%BB%BA%E7%AB%8B%E8%87%AA%E5%B7%B1%E7%9A%84%E5%8A%9F%E8%83%BD%E5%87%BD%E6%95%B8 /zh-TW/docs/Learn/JavaScript/Building_blocks/Build_your_own_function +/zh-TW/docs/Learn/JavaScript/Building_blocks/%E5%BE%AA%E7%92%B0%E4%BB%A3%E7%A2%BC /zh-TW/docs/Learn/JavaScript/Building_blocks/Looping_code +/zh-TW/docs/Learn/JavaScript/Building_blocks/%E6%A2%9D%E4%BB%B6 /zh-TW/docs/Learn/JavaScript/Building_blocks/conditionals +/zh-TW/docs/Learn/JavaScript/First_steps/%E5%82%BB%E6%95%85%E4%BA%8B%E7%94%A2%E7%94%9F%E5%99%A8 /zh-TW/docs/Learn/JavaScript/First_steps/Silly_story_generator +/zh-TW/docs/Learn/JavaScript/First_steps/%E5%88%9D%E6%AC%A1%E6%8E%A5%E8%A7%B8 /zh-TW/docs/Learn/JavaScript/First_steps/A_first_splash +/zh-TW/docs/Learn/JavaScript/First_steps/%E5%AD%97%E7%AC%A6%E4%B8%B2 /zh-TW/docs/Learn/JavaScript/First_steps/Strings +/zh-TW/docs/Learn/JavaScript/First_steps/%E6%95%B8%E5%AD%B8 /zh-TW/docs/Learn/JavaScript/First_steps/Math +/zh-TW/docs/Learn/JavaScript/First_steps/%E6%9C%89%E7%94%A8%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%96%B9%E6%B3%95 /zh-TW/docs/Learn/JavaScript/First_steps/Useful_string_methods +/zh-TW/docs/Learn/JavaScript/First_steps/%E8%AE%8A%E6%95%B8 /zh-TW/docs/Learn/JavaScript/First_steps/Variables +/zh-TW/docs/Learn/JavaScript/First_steps/%E9%99%A3%E5%88%97 /zh-TW/docs/Learn/JavaScript/First_steps/Arrays +/zh-TW/docs/MDN/Contribute/Content /zh-TW/docs/MDN/Guidelines +/zh-TW/docs/MDN/Contribute/Content/Style_guide /zh-TW/docs/MDN/Guidelines/Writing_style_guide +/zh-TW/docs/MDN/Contribute/Creating_and_editing_pages /zh-TW/docs/MDN/Contribute/Howto/Create_and_edit_pages +/zh-TW/docs/MDN/Contribute/Editor /zh-TW/docs/MDN/Editor +/zh-TW/docs/MDN/Contribute/Editor/Basics /zh-TW/docs/MDN/Editor/Basics +/zh-TW/docs/MDN/Contribute/Editor/Edit_box /zh-TW/docs/MDN/Editor/Edit_box +/zh-TW/docs/MDN/Contribute/Guidelines /zh-TW/docs/MDN/Guidelines +/zh-TW/docs/MDN/Contribute/Guidelines/Style_guide /zh-TW/docs/MDN/Guidelines/Writing_style_guide +/zh-TW/docs/MDN/Contribute/Guidelines/Writing_style_guide /zh-TW/docs/MDN/Guidelines/Writing_style_guide +/zh-TW/docs/MDN/Contribute/Howto/%E7%B7%A8%E8%BC%AF%E5%AF%A9%E6%9F%A5 /zh-TW/docs/MDN/Contribute/Howto/Do_an_editorial_review +/zh-TW/docs/MDN/Contribute/Tools /zh-TW/docs/MDN/Tools +/zh-TW/docs/MDN/Contribute/Tools/KumaScript /zh-TW/docs/MDN/Tools/KumaScript +/zh-TW/docs/MDN/Contribute/Tools/KumaScript/Troubleshooting /zh-TW/docs/MDN/Tools/KumaScript/Troubleshooting +/zh-TW/docs/MDN/Getting_started /zh-TW/docs/MDN/Contribute/Getting_started +/zh-TW/docs/MDN/Kuma/Troubleshooting_KumaScript_errors /zh-TW/docs/MDN/Tools/KumaScript/Troubleshooting +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/%E7%94%A8%E6%88%B6%E4%BB%8B%E9%9D%A2 /zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/%E7%94%A8%E6%88%B6%E4%BB%8B%E9%9D%A2/%E5%81%B4%E9%82%8A%E6%AC%84 /zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/Sidebars +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/%E7%94%A8%E6%88%B6%E4%BB%8B%E9%9D%A2/%E5%B7%A5%E5%85%B7%E5%88%97%E6%8C%89%E9%88%95 /zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/Browser_action +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/%E7%94%A8%E6%88%B6%E4%BB%8B%E9%9D%A2/%E5%BF%AB%E6%8D%B7%E9%81%B8%E5%96%AE%E9%A0%85 /zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/Context_menu_items +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/%E7%94%A8%E6%88%B6%E4%BB%8B%E9%9D%A2/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7%E9%9D%A2%E6%9D%BF /zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/devtools_panels +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/%E7%94%A8%E6%88%B6%E9%AB%94%E9%A9%97%E6%9C%80%E4%BD%B3%E5%AF%A6%E8%B8%90 https://extensionworkshop.com/documentation/develop/user-experience-best-practices/ +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/Porting_from_Google_Chrome https://extensionworkshop.com/documentation/develop/porting-a-google-chrome-extension/ +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/manifest.json/%E4%BD%9C%E8%80%85 /zh-TW/docs/Mozilla/Add-ons/WebExtensions/manifest.json/author +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/manifest.json/applications /zh-TW/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/%E5%81%B4%E9%82%8A%E6%AC%84 /zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/Sidebars +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/%E5%B7%A5%E5%85%B7%E5%88%97%E6%8C%89%E9%88%95 /zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/Browser_action +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/%E5%BF%AB%E6%8D%B7%E9%81%B8%E5%96%AE%E9%A0%85 /zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/Context_menu_items +/zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7%E9%9D%A2%E6%9D%BF /zh-TW/docs/Mozilla/Add-ons/WebExtensions/user_interface/devtools_panels +/zh-TW/docs/Mozilla/Developer_guide/%E4%BB%8B%E7%B4%B9 /zh-TW/docs/Mozilla/Developer_guide/Introduction +/zh-TW/docs/Mozilla/Developer_guide/%E5%8E%9F%E5%A7%8B%E7%A2%BC /zh-TW/docs/Mozilla/Developer_guide/Source_Code +/zh-TW/docs/Mozilla/Firefox/Releases/2/%E6%96%B0%E5%A2%9E%E6%B6%88%E6%81%AF%E4%BE%86%E6%BA%90%E9%96%B1%E8%AE%80%E5%B7%A5%E5%85%B7 /zh-TW/docs/Mozilla/Firefox/Releases/2/Adding_feed_readers_to_Firefox +/zh-TW/docs/Mozilla/Firefox/Releases/2/Firefox_2_%E7%9A%84%E5%AE%89%E5%85%A8%E5%8A%9F%E8%83%BD /zh-TW/docs/Mozilla/Firefox/Releases/2/Security_changes +/zh-TW/docs/Mozilla/Firefox/Releases/3/Firefox_3_Dom_Improvements /zh-TW/docs/Mozilla/Firefox/Releases/3/DOM_improvements +/zh-TW/docs/Mozilla_event_reference /zh-TW/docs/Web/Events +/zh-TW/docs/Mozilla_event_reference/DOMContentLoaded_(event) /zh-TW/docs/Web/Events/DOMContentLoaded +/zh-TW/docs/Offline_resources_on_Firefox /zh-TW/docs/Web/HTML/Using_the_application_cache +/zh-TW/docs/Prism:%E4%B8%BB%E8%A6%96%E7%AA%97 /zh-TW/docs/Prism/%E4%B8%BB%E8%A6%96%E7%AA%97 +/zh-TW/docs/Prism:%E5%AE%89%E8%A3%9D%E7%A8%8B%E5%BC%8F /zh-TW/docs/Prism/%E5%AE%89%E8%A3%9D%E7%A8%8B%E5%BC%8F +/zh-TW/docs/Quirks_Mode_and_Standards_Mode /zh-TW/docs/Web/HTML/Quirks_Mode_and_Standards_Mode +/zh-TW/docs/SVG /zh-TW/docs/Web/SVG +/zh-TW/docs/SVG/%E6%95%99%E5%AD%B8 /zh-TW/docs/Web/SVG/%E6%95%99%E5%AD%B8 +/zh-TW/docs/SVG/Tutorial /zh-TW/docs/Web/SVG/Tutorial +/zh-TW/docs/SVG/Tutorial/%E5%85%A5%E9%97%A8 /zh-TW/docs/Web/SVG/Tutorial/Getting_Started +/zh-TW/docs/SVG/Tutorial/%E5%9B%BE%E6%A1%88 /zh-TW/docs/Web/SVG/Tutorial/Patterns +/zh-TW/docs/SVG/Tutorial/%E5%9F%BA%E6%9C%AC%E5%BD%A2%E7%8A%B6 /zh-TW/docs/SVG/Tutorial/Basic_Shapes +/zh-TW/docs/SVG/Tutorial/%E5%A1%AB%E5%85%85%E4%B8%8E%E8%BE%B9%E6%A1%86 /zh-TW/docs/Web/SVG/Tutorial/Fills_and_Strokes +/zh-TW/docs/SVG/Tutorial/%E6%B8%90%E5%8F%98 /zh-TW/docs/Web/SVG/Tutorial/Gradients +/zh-TW/docs/SVG/Tutorial/%E8%B7%AF%E5%BE%84 /zh-TW/docs/Web/SVG/Tutorial/%E8%B7%AF%E5%BE%84 +/zh-TW/docs/SVG/Tutorial/Introduction /zh-TW/docs/Web/SVG/Tutorial/Introduction +/zh-TW/docs/SVG/Tutorial/Positions /zh-TW/docs/Web/SVG/Tutorial/Positions +/zh-TW/docs/Security/%E5%BC%B1%E7%B0%BD%E7%AB%A0%E6%BC%94%E7%AE%97%E6%B3%95 /zh-TW/docs/Web/Security/Weak_Signature_Algorithm +/zh-TW/docs/Security/%E7%BC%BA%E5%B0%91%E5%AE%89%E5%85%A8%E6%80%A7%E7%9A%84%E5%AF%86%E7%A2%BC /zh-TW/docs/Web/Security/Insecure_passwords +/zh-TW/docs/Security/MixedContent /zh-TW/docs/Web/Security/Mixed_content +/zh-TW/docs/Security/MixedContent/How_to_fix_website_with_mixed_content /zh-TW/docs/Web/Security/Mixed_content/How_to_fix_website_with_mixed_content +/zh-TW/docs/Using_files_from_web_applications /zh-TW/docs/Web/API/File/Using_files_from_web_applications +/zh-TW/docs/Using_geolocation /zh-TW/docs/Web/API/Geolocation/Using_geolocation +/zh-TW/docs/Web/API/Canvas_API/Tutorial/%E5%9F%BA%E7%A4%8E%E5%8B%95%E7%95%AB /zh-TW/docs/Web/API/Canvas_API/Tutorial/Basic_animations +/zh-TW/docs/Web/API/Canvas_API/Tutorial/%E6%9C%80%E4%BD%B3%E5%8C%96_canvas /zh-TW/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas +/zh-TW/docs/Web/API/Coordinates /zh-TW/docs/Web/API/GeolocationCoordinates +/zh-TW/docs/Web/API/Coordinates/accuracy /zh-TW/docs/Web/API/GeolocationCoordinates/accuracy +/zh-TW/docs/Web/API/Coordinates/altitude /zh-TW/docs/Web/API/GeolocationCoordinates/altitude +/zh-TW/docs/Web/API/Coordinates/altitudeAccuracy /zh-TW/docs/Web/API/GeolocationCoordinates/altitudeAccuracy +/zh-TW/docs/Web/API/Coordinates/heading /zh-TW/docs/Web/API/GeolocationCoordinates/heading +/zh-TW/docs/Web/API/Coordinates/latitude /zh-TW/docs/Web/API/GeolocationCoordinates/latitude +/zh-TW/docs/Web/API/Coordinates/longitude /zh-TW/docs/Web/API/GeolocationCoordinates/longitude +/zh-TW/docs/Web/API/Coordinates/speed /zh-TW/docs/Web/API/GeolocationCoordinates/speed +/zh-TW/docs/Web/API/DocumentTemp /zh-TW/docs/Web/API/Document +/zh-TW/docs/Web/API/DocumentTemp/createElement /zh-TW/docs/Web/API/Document/createElement +/zh-TW/docs/Web/API/DocumentTemp/createRange /zh-TW/docs/Web/API/Document/createRange +/zh-TW/docs/Web/API/DocumentTemp/createTextNode /zh-TW/docs/Web/API/Document/createTextNode +/zh-TW/docs/Web/API/DocumentTemp/defaultView /zh-TW/docs/Web/API/Document/defaultView +/zh-TW/docs/Web/API/DocumentTemp/forms /zh-TW/docs/Web/API/Document/forms +/zh-TW/docs/Web/API/DocumentTemp/getElementsByClassName /zh-TW/docs/Web/API/Document/getElementsByClassName +/zh-TW/docs/Web/API/DocumentTemp/head /zh-TW/docs/Web/API/Document/head +/zh-TW/docs/Web/API/DocumentTemp/querySelector /zh-TW/docs/Web/API/Document/querySelector +/zh-TW/docs/Web/API/DocumentTemp/readyState /zh-TW/docs/Web/API/Document/readyState +/zh-TW/docs/Web/API/DocumentTemp/width /zh-TW/docs/Web/API/Document/width +/zh-TW/docs/Web/API/Document_Object_Model/Whitespace_in_the_DOM /zh-TW/docs/Web/API/Document_Object_Model/Whitespace +/zh-TW/docs/Web/API/Position /zh-TW/docs/Web/API/GeolocationPosition +/zh-TW/docs/Web/API/Position/coords /zh-TW/docs/Web/API/GeolocationPosition/coords +/zh-TW/docs/Web/API/Position/timestamp /zh-TW/docs/Web/API/GeolocationPosition/timestamp +/zh-TW/docs/Web/API/PositionError /zh-TW/docs/Web/API/GeolocationPositionError +/zh-TW/docs/Web/API/PositionError/code /zh-TW/docs/Web/API/GeolocationPositionError/code +/zh-TW/docs/Web/API/PositionError/message /zh-TW/docs/Web/API/GeolocationPositionError/message +/zh-TW/docs/Web/API/WebGL_API/Tutorial/WebGL%E5%85%A5%E9%96%80 /zh-TW/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL +/zh-TW/docs/Web/API/XMLHttpRequest/FormData /zh-TW/docs/Web/API/FormData +/zh-TW/docs/Web/API/document.querySelector /zh-TW/docs/Web/API/Document/querySelector +/zh-TW/docs/Web/Apps/Progressive /zh-TW/docs/Web/Progressive_web_apps +/zh-TW/docs/Web/Apps/Progressive/Responsive /zh-TW/docs/Web/Progressive_web_apps/Responsive +/zh-TW/docs/Web/CSS/%E5%8F%83%E8%80%83 /zh-TW/docs/Web/CSS/Reference +/zh-TW/docs/Web/CSS/%E5%BD%88%E9%A0%AD /zh-TW/docs/Web/CSS/box-sizing +/zh-TW/docs/Web/CSS/%E7%B9%BC%E6%89%BF /zh-TW/docs/Web/CSS/inheritance +/zh-TW/docs/Web/CSS/%E8%AA%9E%E6%B3%95 /zh-TW/docs/Web/CSS/Syntax +/zh-TW/docs/Web/CSS/-moz-border-image /zh-TW/docs/Web/CSS/border-image/border-image +/zh-TW/docs/Web/CSS/CSS_%E4%B8%80%E8%88%AC%E5%95%8F%E9%A1%8C /zh-TW/docs/Web/CSS/Common_CSS_Questions +/zh-TW/docs/Web/CSS/CSS_%E7%B6%B2%E6%A0%BC_%E5%B8%83%E5%B1%80 /zh-TW/docs/Web/CSS/CSS_Grid_Layout +/zh-TW/docs/Web/CSS/CSS_Box_Model/%E7%90%86%E8%A7%A3%E9%82%8A%E7%95%8C%E9%87%8D%E7%96%8A%E7%9A%84%E5%8E%9F%E5%9B%A0 /zh-TW/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing +/zh-TW/docs/Web/CSS/Descendant_selectors /zh-TW/docs/Web/CSS/Descendant_combinator +/zh-TW/docs/Web/CSS/attr /zh-TW/docs/Web/CSS/attr() +/zh-TW/docs/Web/CSS/radial-gradient /zh-TW/docs/Web/CSS/radial-gradient() +/zh-TW/docs/Web/CSS/transform-function/translate3d /zh-TW/docs/Web/CSS/transform-function/translate3d() +/zh-TW/docs/Web/Events/click /zh-TW/docs/Web/API/Element/click_event +/zh-TW/docs/Web/Events/keyup /zh-TW/docs/Web/API/Document/keyup_event +/zh-TW/docs/Web/Events/orientationchange /zh-TW/docs/Web/API/Window/orientationchange_event +/zh-TW/docs/Web/Events/ratechange /zh-TW/docs/Web/API/HTMLMediaElement/ratechange_event +/zh-TW/docs/Web/Events/scroll /zh-TW/docs/Web/API/Document/scroll_event +/zh-TW/docs/Web/Events/submit /zh-TW/docs/Web/API/HTMLFormElement/submit_event +/zh-TW/docs/Web/Events/touchcancel /zh-TW/docs/Web/API/Element/touchcancel_event +/zh-TW/docs/Web/Guide/%E5%9C%96%E5%83%8F /zh-TW/docs/Web/Guide/Graphics +/zh-TW/docs/Web/Guide/API/DOM/Manipulating_the_browser_history/Manipulating_the_browser_history /zh-TW/docs/Web/API/History_API +/zh-TW/docs/Web/Guide/API/WebRTC /zh-TW/docs/Web/API/WebRTC_API +/zh-TW/docs/Web/Guide/CSS /zh-TW/docs/Learn/CSS +/zh-TW/docs/Web/Guide/CSS/%E4%BD%BF%E7%94%A8_%E5%A4%9A%E9%87%8D_%E8%83%8C%E6%99%AF /zh-TW/docs/Web/CSS/CSS_Background_and_Borders/Using_CSS_multiple_backgrounds +/zh-TW/docs/Web/Guide/CSS/CSS_%E8%BD%89%E5%A0%B4 /zh-TW/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions +/zh-TW/docs/Web/Guide/CSS/Consistent_List_Indentation /zh-TW/docs/Web/CSS/CSS_Lists_and_Counters/Consistent_list_indentation +/zh-TW/docs/Web/Guide/CSS/Getting_started /en-US/docs/Learn/CSS/First_steps +/zh-TW/docs/Web/Guide/CSS/Getting_started/%E7%82%BA%E4%BB%80%E9%BA%BC%E8%A6%81%E7%94%A8CSS /en-US/docs/Learn/CSS/First_steps/How_CSS_works +/zh-TW/docs/Web/Guide/CSS/Getting_started/Layout /zh-TW/docs/Learn/CSS/CSS_layout +/zh-TW/docs/Web/Guide/CSS/Getting_started/What_is_CSS /en-US/docs/Learn/CSS/First_steps/How_CSS_works +/zh-TW/docs/Web/Guide/CSS/Getting_started/Why_use_CSS /en-US/docs/Learn/CSS/First_steps/How_CSS_works +/zh-TW/docs/Web/Guide/CSS/Testing_media_queries /zh-TW/docs/Web/CSS/Media_Queries/Testing_media_queries +/zh-TW/docs/Web/Guide/CSS/Understanding_z_index /zh-TW/docs/Web/CSS/CSS_Positioning/Understanding_z_index +/zh-TW/docs/Web/Guide/CSS/Understanding_z_index/Stacking_context_example_1 /zh-TW/docs/Web/CSS/CSS_Positioning/Understanding_z_index/Stacking_context_example_1 +/zh-TW/docs/Web/Guide/CSS/Using_the_:target_selector /zh-TW/docs/Web/CSS/CSS_Selectors/Using_the_:target_pseudo-class_in_selectors +/zh-TW/docs/Web/Guide/DOM/Manipulating_the_browser_history /zh-TW/docs/Web/API/History_API +/zh-TW/docs/Web/Guide/DOM/Using_full_screen_mode /zh-TW/docs/Web/API/Fullscreen_API +/zh-TW/docs/Web/Guide/HTML /zh-TW/docs/Learn/HTML +/zh-TW/docs/Web/Guide/HTML/Canvas_tutorial /zh-TW/docs/Web/API/Canvas_API/Tutorial +/zh-TW/docs/Web/Guide/HTML/Canvas_tutorial/%E5%9F%BA%E7%A4%8E%E5%8B%95%E7%95%AB /zh-TW/docs/Web/API/Canvas_API/Tutorial/Basic_animations +/zh-TW/docs/Web/Guide/HTML/Canvas_tutorial/%E6%9C%80%E4%BD%B3%E5%8C%96_canvas /zh-TW/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas +/zh-TW/docs/Web/Guide/HTML/Canvas_tutorial/Applying_styles_and_colors /zh-TW/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors +/zh-TW/docs/Web/Guide/HTML/Canvas_tutorial/Basic_usage /zh-TW/docs/Web/API/Canvas_API/Tutorial/Basic_usage +/zh-TW/docs/Web/Guide/HTML/Canvas_tutorial/Compositing /zh-TW/docs/Web/API/Canvas_API/Tutorial/Compositing +/zh-TW/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes /zh-TW/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes +/zh-TW/docs/Web/Guide/HTML/Canvas_tutorial/Transformations /zh-TW/docs/Web/API/Canvas_API/Tutorial/Transformations +/zh-TW/docs/Web/Guide/HTML/Canvas_tutorial/Using_images /zh-TW/docs/Web/API/Canvas_API/Tutorial/Using_images +/zh-TW/docs/Web/Guide/HTML/Drag_and_drop /zh-TW/docs/Web/API/HTML_Drag_and_Drop_API +/zh-TW/docs/Web/Guide/HTML/Drag_operations /zh-TW/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations +/zh-TW/docs/Web/Guide/HTML/Forms /zh-TW/docs/Learn/HTML/Forms +/zh-TW/docs/Web/Guide/HTML/Forms/How_to_structure_an_HTML_form /zh-TW/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form +/zh-TW/docs/Web/Guide/Performance/Using_web_workers /zh-TW/docs/Web/API/Web_Workers_API/Using_web_workers +/zh-TW/docs/Web/HTML/%E5%8D%80%E5%A1%8A%E7%B4%9A%E5%85%83%E7%B4%A0 /zh-TW/docs/Web/HTML/Block-level_elements +/zh-TW/docs/Web/HTML/Canvas /zh-TW/docs/Web/API/Canvas_API +/zh-TW/docs/Web/HTML/Canvas/Drawing_graphics_with_canvas /zh-TW/docs/Web/API/Canvas_API/Drawing_graphics_with_canvas +/zh-TW/docs/Web/HTML/Element/%E5%B0%8E%E8%88%AA%E6%AC%84 /zh-TW/docs/Web/HTML/Element/nav +/zh-TW/docs/Web/HTML/Element/HTML_%E5%85%83%E7%B4%A0 /zh-TW/docs/Web/HTML/Element +/zh-TW/docs/Web/HTML/Element_old /zh-TW/docs/Web/HTML/HTML_%E5%85%83%E7%B4%A0 +/zh-TW/docs/Web/HTML/HTML5 /zh-TW/docs/Web/Guide/HTML/HTML5 +/zh-TW/docs/Web/HTML/HTML5/Introduction_to_HTML5 /zh-TW/docs/Web/Guide/HTML/HTML5/Introduction_to_HTML5 +/zh-TW/docs/Web/HTML/HTML5_%E8%A1%A8%E5%96%AE /zh-TW/docs/Learn/HTML/Forms +/zh-TW/docs/Web/HTML/Introduction /zh-CN/docs/learn/HTML/Introduction_to_HTML +/zh-TW/docs/Web/HTML/Offline_resources_on_Firefox /zh-TW/docs/Web/HTML/Using_the_application_cache +/zh-TW/docs/Web/HTTP/Access_control_CORS /zh-TW/docs/Web/HTTP/CORS +/zh-TW/docs/Web/HTTP/Response_codes /zh-TW/docs/Web/HTTP/Status +/zh-TW/docs/Web/HTTP/X-Frame-Options /zh-TW/docs/Web/HTTP/Headers/X-Frame-Options +/zh-TW/docs/Web/JavaScript/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B /zh-TW/docs/Web/JavaScript/Data_structures +/zh-TW/docs/Web/JavaScript/%E9%87%8D%E6%96%B0%E4%BB%8B%E7%B4%B9_JavaScript /zh-TW/docs/Web/JavaScript/A_re-introduction_to_JavaScript +/zh-TW/docs/Web/JavaScript/Guide/JavaScript_%E6%A6%82%E8%A7%80 /zh-TW/docs/Web/JavaScript/Guide/Introduction +/zh-TW/docs/Web/JavaScript/Guide/JavaScript_%E6%A6%82%E8%A7%80%EF%BC%88JavaScript_Overview%EF%BC%89 /zh-TW/docs/Web/JavaScript/Guide/Introduction +/zh-TW/docs/Web/JavaScript/Guide/JavaScript_Overview /zh-TW/docs/Web/JavaScript/Guide/Introduction +/zh-TW/docs/Web/JavaScript/Guide/Obsolete_Pages /zh-TW/docs/Web/JavaScript/Guide +/zh-TW/docs/Web/JavaScript/Guide/Values,_variables,_and_literals /zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types +/zh-TW/docs/Web/JavaScript/Guide_old /zh-TW/docs/Web/JavaScript/Guide +/zh-TW/docs/Web/JavaScript/Guide_old/Details_of_the_Object_Model /zh-TW/docs/Web/JavaScript/Guide/Details_of_the_Object_Model +/zh-TW/docs/Web/JavaScript/Guide_old/Functions /zh-TW/docs/Web/JavaScript/Guide/Functions +/zh-TW/docs/Web/JavaScript/Guide_old/Grammar_and_types /zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types +/zh-TW/docs/Web/JavaScript/Guide_old/Introduction /zh-TW/docs/Web/JavaScript/Guide/Introduction +/zh-TW/docs/Web/JavaScript/Guide_old/JavaScript_%E6%A6%82%E8%A7%80 /zh-TW/docs/Web/JavaScript/Guide/Introduction +/zh-TW/docs/Web/JavaScript/Guide_old/JavaScript_%E6%A6%82%E8%A7%80%EF%BC%88JavaScript_Overview%EF%BC%89 /zh-TW/docs/Web/JavaScript/Guide/Introduction +/zh-TW/docs/Web/JavaScript/Guide_old/Keyed_collections /zh-TW/docs/Web/JavaScript/Guide/Keyed_collections +/zh-TW/docs/Web/JavaScript/Guide_old/Regular_Expressions /zh-TW/docs/Web/JavaScript/Guide/Regular_Expressions +/zh-TW/docs/Web/JavaScript/Guide_old/Working_with_Objects /zh-TW/docs/Web/JavaScript/Guide/Working_with_Objects +/zh-TW/docs/Web/JavaScript/JavaScript_typed_arrays /zh-TW/docs/Web/JavaScript/Typed_arrays +/zh-TW/docs/Web/JavaScript/JavaScript_typed_arrays/ArrayBuffer /zh-TW/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer +/zh-TW/docs/Web/JavaScript/JavaScript_typed_arrays/ArrayBuffer/prototype /zh-TW/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/prototype +/zh-TW/docs/Web/JavaScript/New_in_JavaScript/JavaScript_1.6_%E6%96%B0%E9%AE%AE%E4%BA%8B /zh-TW/docs/Web/JavaScript/New_in_JavaScript/1.6 +/zh-TW/docs/Web/JavaScript/New_in_JavaScript/JavaScript_1.7_%E6%96%B0%E9%AE%AE%E4%BA%8B /zh-TW/docs/Web/JavaScript/New_in_JavaScript/1.7 +/zh-TW/docs/Web/JavaScript/Obsolete_Pages undefined +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Control_flow_and_error_handling /zh-TW/docs/Web/JavaScript/Guide/Control_flow_and_error_handling +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Expressions_and_Operators /zh-TW/docs/Web/JavaScript/Guide/Expressions_and_Operators +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Keyed_collections /zh-TW/docs/Web/JavaScript/Guide/Keyed_collections +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Loops_and_iteration /zh-TW/docs/Web/JavaScript/Guide/Loops_and_iteration +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages /zh-TW/docs/Web/JavaScript/Guide +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages /zh-TW/docs/Web/JavaScript/Guide +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E6%96%87%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%8D%80%E5%A1%8A%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E5%BB%BA%E7%AB%8B%E6%96%B0%E7%9A%84%E7%89%A9%E4%BB%B6/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%B0%E7%89%A9%E4%BB%B6%E7%9A%84%E5%BB%BA%E7%AB%8B/%E7%89%A9%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%9A%84%E4%BD%BF%E7%94%A8 +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%96%87%E6%B3%95 /zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E6%96%87%E6%B3%95 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%A2%9D%E4%BB%B6%E8%AA%9E%E6%B3%95 +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F /zh-TW/docs/Core_JavaScript_1.5_%E6%95%99%E5%AD%B8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%B7%A8%E5%AF%AB +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E5%BB%BA%E7%AB%8B +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E4%BD%BF%E7%94%A8%E6%A8%99%E8%AA%8C%E7%9A%84%E9%80%B2%E9%9A%8E%E6%90%9C%E5%B0%8B +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%8B%AC%E5%BC%A7%E5%AD%90%E5%AD%97%E4%B8%B2%E7%9A%84%E6%AF%94%E5%B0%8D%E7%B5%90%E6%9E%9C%E7%9A%84%E9%81%8B%E7%94%A8 +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E5%89%87%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B /zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E9%81%8B%E7%94%A8/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E5%BC%8F%E7%9A%84%E7%AF%84%E4%BE%8B +/zh-TW/docs/Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/arguments_%E7%89%A9%E4%BB%B6%E7%9A%84%E4%BD%BF%E7%94%A8 /zh-TW/docs/Web/JavaScript/Reference/Functions/arguments +/zh-TW/docs/Web/JavaScript/Same_origin_policy_for_JavaScript /zh-TW/docs/Web/Security/Same-origin_policy +/zh-TW/docs/Web/JavaScript/Typed_arrays/ArrayBuffer /zh-TW/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer +/zh-TW/docs/Web/JavaScript/Typed_arrays/ArrayBuffer/prototype /zh-TW/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/prototype +/zh-TW/docs/Web/Reference/Events /zh-TW/docs/Web/Events +/zh-TW/docs/Web/Reference/Events/DOMContentLoaded /zh-TW/docs/Web/Events/DOMContentLoaded +/zh-TW/docs/Web/Reference/Events/DOMContentLoaded_(event) /zh-TW/docs/Web/Events/DOMContentLoaded +/zh-TW/docs/Web/Reference/Events/click /zh-TW/docs/Web/API/Element/click_event +/zh-TW/docs/Web/Reference/Events/submit /zh-TW/docs/Web/API/HTMLFormElement/submit_event +/zh-TW/docs/Web/Reference/Events/touchcancel /zh-TW/docs/Web/API/Element/touchcancel_event +/zh-TW/docs/Web/SVG/Tutorial/%E5%85%A5%E9%97%A8 /zh-TW/docs/Web/SVG/Tutorial/Getting_Started +/zh-TW/docs/Web/SVG/Tutorial/%E5%9B%BE%E6%A1%88 /zh-TW/docs/Web/SVG/Tutorial/Patterns +/zh-TW/docs/Web/SVG/Tutorial/%E5%9F%BA%E6%9C%AC%E5%BD%A2%E7%8A%B6 /zh-TW/docs/SVG/Tutorial/Basic_Shapes +/zh-TW/docs/Web/SVG/Tutorial/%E5%A1%AB%E5%85%85%E4%B8%8E%E8%BE%B9%E6%A1%86 /zh-TW/docs/Web/SVG/Tutorial/Fills_and_Strokes +/zh-TW/docs/Web/SVG/Tutorial/%E6%B8%90%E5%8F%98 /zh-TW/docs/Web/SVG/Tutorial/Gradients +/zh-TW/docs/Web/WebGL /zh-TW/docs/Web/API/WebGL_API +/zh-TW/docs/WebAPI/Battery_Status /zh-TW/docs/Web/API/Battery_Status_API +/zh-TW/docs/WebAPI/Detecting_device_orientation /zh-TW/docs/Web/API/Detecting_device_orientation +/zh-TW/docs/WebAPI/FileHandle /zh-TW/docs/Web/API/File_Handle_API +/zh-TW/docs/WebAPI/Managing_screen_orientation /zh-TW/docs/Web/API/CSS_Object_Model/Managing_screen_orientation +/zh-TW/docs/WebAPI/Network_Information /zh-TW/docs/Web/API/Network_Information_API +/zh-TW/docs/WebAPI/Pointer_Lock /zh-TW/docs/Web/API/Pointer_Lock_API +/zh-TW/docs/WebAPI/Proximity /zh-TW/docs/Web/API/Proximity_Events +/zh-TW/docs/WebAPI/Using_Light_Events /zh-TW/docs/Web/API/Ambient_Light_Events +/zh-TW/docs/WebAPI/Using_Web_Notifications /zh-TW/docs/Web/API/Notifications_API/Using_the_Notifications_API +/zh-TW/docs/WebAPI/Vibration /zh-TW/docs/Web/API/Vibration_API +/zh-TW/docs/Web_%E9%96%8B%E7%99%BC/Web%E9%96%8B%E7%99%BC%E5%85%A5%E9%96%80 /zh-TW/docs/Web/Guide/Introduction_to_Web_development +/zh-TW/docs/Web_Audio_API /zh-TW/docs/Web/API/Web_Audio_API +/zh-TW/docs/Web_development/Writing_forward-compatible_websites /zh-TW/docs/Web/Guide/Writing_forward-compatible_websites +/zh-TW/docs/en /en-US/ diff --git a/files/zh-tw/_wikihistory.json b/files/zh-tw/_wikihistory.json new file mode 100644 index 0000000000..4febc0f7d2 --- /dev/null +++ b/files/zh-tw/_wikihistory.json @@ -0,0 +1,9180 @@ +{ + "Core_JavaScript_1.5_正規表達式的建立": { + "modified": "2019-03-24T00:00:58.216Z", + "contributors": [ + "wbamberg", + "happysadman" + ] + }, + "Cross-site_XMLHttpRequest": { + "modified": "2019-01-16T15:28:10.716Z", + "contributors": [ + "Mgjbot", + "BobChao", + "Coolcd" + ] + }, + "DOM_觀察器": { + "modified": "2019-01-16T13:41:41.852Z", + "contributors": [ + "273K" + ] + }, + "DragDrop": { + "modified": "2019-01-16T13:26:51.358Z", + "contributors": [ + "sailplaneTW" + ] + }, + "Firefox_3.5_技術文件": { + "modified": "2019-03-23T23:59:44.778Z", + "contributors": [ + "irvinfly", + "RJ_Hsiao", + "teoli", + "Littlebtc", + "BobChao" + ] + }, + "Firefox_中的離線資源": { + "modified": "2019-03-24T00:13:31.494Z", + "contributors": [ + "sailplaneTW" + ] + }, + "Games": { + "modified": "2019-09-09T15:35:53.246Z", + "contributors": [ + "SphinxKnight", + "wbamberg", + "iigmir", + "fscholz", + "MashKao" + ] + }, + "Games/Introduction": { + "modified": "2019-01-16T19:41:58.412Z", + "contributors": [ + "wbamberg", + "jackblackevo", + "RishYang", + "MashKao" + ] + }, + "Games/Techniques": { + "modified": "2019-01-17T01:09:15.300Z", + "contributors": [ + "wbamberg", + "chrisdavidmills" + ] + }, + "Games/Tutorials": { + "modified": "2019-03-23T22:47:44.453Z", + "contributors": [ + "wbamberg", + "jackblackevo", + "chrisdavidmills" + ] + }, + "Games/Tutorials/2D_Breakout_game_pure_JavaScript": { + "modified": "2019-03-23T22:47:44.181Z", + "contributors": [ + "wbamberg", + "jackblackevo", + "MashKao", + "weihanglo", + "benjaminchen", + "RishYang" + ] + }, + "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls": { + "modified": "2019-03-23T22:42:23.279Z", + "contributors": [ + "wbamberg", + "RishYang", + "jackblackevo", + "tomchang1", + "feiye1", + "Jamin", + "EasonWang01" + ] + }, + "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it": { + "modified": "2019-07-06T06:25:00.544Z", + "contributors": [ + "SLMT", + "wbamberg", + "jackblackevo", + "RishYang" + ] + }, + "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball": { + "modified": "2019-03-23T22:45:54.347Z", + "contributors": [ + "wbamberg", + "jackblackevo", + "Randy_Chen", + "weihanglo", + "Jamin", + "RishYang" + ] + }, + "Glossary": { + "modified": "2020-10-07T11:15:41.747Z", + "contributors": [ + "peterbe", + "SphinxKnight", + "wbamberg", + "Chou-Chun-Yu", + "iigmir", + "marktwtn", + "jackblackevo", + "Jeremie" + ] + }, + "Glossary/404": { + "modified": "2019-03-23T22:23:29.116Z", + "contributors": [ + "iigmir", + "marktwtn" + ] + }, + "Glossary/502": { + "modified": "2019-03-18T21:44:50.733Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/AJAX": { + "modified": "2019-03-23T22:28:09.468Z", + "contributors": [ + "Rocker", + "iigmir" + ] + }, + "Glossary/API": { + "modified": "2019-03-18T21:45:17.379Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/ARIA": { + "modified": "2019-03-18T21:44:55.861Z", + "contributors": [ + "iigmir", + "Rocker" + ] + }, + "Glossary/ARPA": { + "modified": "2019-03-18T21:42:24.969Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/ASCII": { + "modified": "2019-03-18T21:42:57.788Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/ATAG": { + "modified": "2019-03-18T21:44:30.079Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Abstraction": { + "modified": "2019-03-23T22:04:33.213Z", + "contributors": [ + "serinahsu", + "jackblackevo" + ] + }, + "Glossary/Accessibility": { + "modified": "2019-08-12T14:53:15.273Z", + "contributors": [ + "ayugioh2003", + "LNDDYL", + "willynpi", + "Rocker" + ] + }, + "Glossary/Adobe_Flash": { + "modified": "2020-05-23T16:50:31.350Z", + "contributors": [ + "iigmir", + "Rocker" + ] + }, + "Glossary/Algorithm": { + "modified": "2019-01-17T00:19:24.512Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Apple_Safari": { + "modified": "2019-03-18T21:44:37.542Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Argument": { + "modified": "2019-04-23T04:30:03.619Z", + "contributors": [ + "jackblackevo", + "iigmir", + "Rocker" + ] + }, + "Glossary/Arpanet": { + "modified": "2019-03-18T21:41:50.711Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Asynchronous": { + "modified": "2019-08-12T14:24:28.607Z", + "contributors": [ + "ayugioh2003", + "petercpg", + "iigmir" + ] + }, + "Glossary/Attribute": { + "modified": "2019-03-23T22:31:19.472Z", + "contributors": [ + "Rocker", + "iigmir", + "jackblackevo" + ] + }, + "Glossary/Bandwidth": { + "modified": "2019-03-18T21:44:58.394Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Blink": { + "modified": "2019-03-23T22:26:07.848Z", + "contributors": [ + "petercpg" + ] + }, + "Glossary/Block": { + "modified": "2019-03-18T21:44:30.568Z", + "contributors": [ + "Sheppy" + ] + }, + "Glossary/Block/CSS": { + "modified": "2019-03-18T21:44:30.419Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Boolean": { + "modified": "2019-03-23T22:11:57.041Z", + "contributors": [ + "jackblackevo", + "vintif" + ] + }, + "Glossary/Bootstrap": { + "modified": "2020-05-23T17:07:57.268Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Browser": { + "modified": "2019-03-23T22:54:30.687Z", + "contributors": [ + "iigmir", + "irvinfly" + ] + }, + "Glossary/Browsing_context": { + "modified": "2019-03-18T21:45:10.444Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/CMS": { + "modified": "2020-01-08T23:11:50.383Z", + "contributors": [ + "jjyaung", + "iigmir" + ] + }, + "Glossary/CORS": { + "modified": "2019-03-23T22:20:31.350Z", + "contributors": [ + "Rocker", + "jackblackevo", + "iigmir", + "afutseng" + ] + }, + "Glossary/CRUD": { + "modified": "2019-12-13T00:20:11.698Z", + "contributors": [ + "AlanSyue" + ] + }, + "Glossary/CSP": { + "modified": "2019-03-18T21:42:06.219Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/CSRF": { + "modified": "2020-06-01T13:34:09.077Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/CSS": { + "modified": "2020-01-29T11:39:11.856Z", + "contributors": [ + "jjyaung", + "Chou-Chun-Yu", + "iigmir" + ] + }, + "Glossary/CSSOM": { + "modified": "2019-12-09T06:15:08.221Z", + "contributors": [ + "afutseng" + ] + }, + "Glossary/CSS_Selector": { + "modified": "2020-01-08T23:14:25.094Z", + "contributors": [ + "jjyaung", + "iigmir" + ] + }, + "Glossary/CSS_pixel": { + "modified": "2019-12-10T23:33:41.801Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/CSS_preprocessor": { + "modified": "2020-05-23T15:15:52.045Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Cache": { + "modified": "2020-01-07T20:19:13.685Z", + "contributors": [ + "jjyaung", + "iigmir" + ] + }, + "Glossary/Callback_function": { + "modified": "2019-03-18T21:45:30.183Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Canvas": { + "modified": "2019-03-23T22:12:33.666Z", + "contributors": [ + "vintif" + ] + }, + "Glossary/Character": { + "modified": "2019-03-23T22:15:30.036Z", + "contributors": [ + "jackblackevo", + "AfricanxAdmiral" + ] + }, + "Glossary/Chrome": { + "modified": "2019-03-23T22:49:53.479Z", + "contributors": [ + "leVirve" + ] + }, + "Glossary/Cipher_suite": { + "modified": "2019-03-18T21:44:16.996Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Ciphertext": { + "modified": "2019-03-18T21:44:24.122Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Class": { + "modified": "2019-08-12T15:30:11.761Z", + "contributors": [ + "ayugioh2003", + "Rocker" + ] + }, + "Glossary/Closure": { + "modified": "2019-03-18T21:44:42.611Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Compile": { + "modified": "2019-03-18T21:44:17.421Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Compile_time": { + "modified": "2019-03-18T21:43:32.243Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Computer_Programming": { + "modified": "2020-06-01T13:22:38.424Z", + "contributors": [ + "iigmir", + "Rocker" + ] + }, + "Glossary/Constructor": { + "modified": "2019-03-23T22:16:57.732Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Continuous_Media": { + "modified": "2020-02-25T03:18:35.922Z", + "contributors": [ + "JamesGoler" + ] + }, + "Glossary/Cookie": { + "modified": "2019-03-18T21:44:06.722Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Crawler": { + "modified": "2019-03-23T22:07:26.742Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Cryptography": { + "modified": "2019-03-18T21:44:26.909Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/DHTML": { + "modified": "2019-03-23T23:05:14.683Z", + "contributors": [ + "wildsky" + ] + }, + "Glossary/DNS": { + "modified": "2019-03-18T21:42:20.975Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/DOM": { + "modified": "2019-03-18T21:44:43.965Z", + "contributors": [ + "abler0122" + ] + }, + "Glossary/DOS_attack": { + "modified": "2019-03-18T21:43:00.216Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Data_structure": { + "modified": "2019-03-23T22:12:01.136Z", + "contributors": [ + "jackblackevo", + "vintif" + ] + }, + "Glossary/Developer_Tools": { + "modified": "2019-03-18T21:42:38.696Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Doctype": { + "modified": "2019-03-23T22:37:58.936Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Document_directive": { + "modified": "2019-03-18T21:41:10.612Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Domain": { + "modified": "2019-03-18T21:44:05.100Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Domain_name": { + "modified": "2019-04-11T07:41:10.867Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/ECMA": { + "modified": "2019-03-23T22:26:14.045Z", + "contributors": [ + "petercpg" + ] + }, + "Glossary/ECMAScript": { + "modified": "2019-08-12T15:22:21.776Z", + "contributors": [ + "ayugioh2003" + ] + }, + "Glossary/Element": { + "modified": "2019-08-12T15:14:24.188Z", + "contributors": [ + "ayugioh2003" + ] + }, + "Glossary/Empty_element": { + "modified": "2019-03-18T21:41:26.001Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Engine": { + "modified": "2019-03-18T21:41:31.602Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/FTP": { + "modified": "2019-03-18T21:42:31.337Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Firefox_OS": { + "modified": "2019-03-18T21:44:10.196Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/First-class_Function": { + "modified": "2020-04-26T05:17:55.398Z", + "contributors": [ + "nighet", + "Arisu" + ] + }, + "Glossary/First_CPU_idle": { + "modified": "2019-12-09T05:44:22.503Z", + "contributors": [ + "afutseng" + ] + }, + "Glossary/First_contentful_paint": { + "modified": "2019-12-09T05:35:40.356Z", + "contributors": [ + "afutseng" + ] + }, + "Glossary/First_input_delay": { + "modified": "2019-12-09T05:57:35.745Z", + "contributors": [ + "afutseng" + ] + }, + "Glossary/Git": { + "modified": "2019-03-23T22:20:30.755Z", + "contributors": [ + "iigmir", + "afutseng" + ] + }, + "Glossary/Grid": { + "modified": "2019-03-18T21:15:33.503Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/HTML": { + "modified": "2019-12-23T12:34:17.059Z", + "contributors": [ + "Uemmra3", + "iigmir" + ] + }, + "Glossary/HTML5": { + "modified": "2019-03-18T21:43:07.468Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/HTTP": { + "modified": "2019-03-23T22:22:08.807Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Head": { + "modified": "2019-03-18T21:42:17.897Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Hoisting": { + "modified": "2019-03-23T22:15:30.480Z", + "contributors": [ + "iigmir", + "Julia-H", + "jsgao0", + "Daisord" + ] + }, + "Glossary/Host": { + "modified": "2020-04-07T10:31:06.895Z", + "contributors": [ + "iigmir", + "slivenred", + "Rocker" + ] + }, + "Glossary/IIFE": { + "modified": "2019-03-18T21:40:45.117Z", + "contributors": [ + "PeterTing", + "othree" + ] + }, + "Glossary/IP_Address": { + "modified": "2019-03-23T22:26:11.146Z", + "contributors": [ + "LNDDYL", + "petercpg" + ] + }, + "Glossary/Identifier": { + "modified": "2019-03-18T21:42:10.774Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Immutable": { + "modified": "2019-03-23T22:14:17.839Z", + "contributors": [ + "jsgao0" + ] + }, + "Glossary/IndexedDB": { + "modified": "2019-03-23T22:27:22.105Z", + "contributors": [ + "petercpg", + "ddtet" + ] + }, + "Glossary/JSON": { + "modified": "2019-03-23T22:07:09.680Z", + "contributors": [ + "jmlntw" + ] + }, + "Glossary/Jank": { + "modified": "2019-01-17T02:24:07.422Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Java": { + "modified": "2020-05-23T17:24:41.278Z", + "contributors": [ + "iigmir", + "Rocker" + ] + }, + "Glossary/JavaScript": { + "modified": "2019-03-23T22:21:44.170Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Key": { + "modified": "2019-03-18T21:41:03.451Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Keyword": { + "modified": "2019-03-18T21:43:25.817Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Ligature": { + "modified": "2019-03-18T21:42:40.057Z", + "contributors": [ + "MashKao" + ] + }, + "Glossary/Localization": { + "modified": "2019-03-23T23:41:05.296Z", + "contributors": [ + "LNDDYL", + "jackblackevo", + "teoli", + "Mgjbot", + "Josesun" + ] + }, + "Glossary/MIME_type": { + "modified": "2020-02-27T00:22:42.482Z", + "contributors": [ + "iigmir", + "Rocker" + ] + }, + "Glossary/MVC": { + "modified": "2019-03-23T22:06:52.468Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/MathML": { + "modified": "2019-03-18T21:43:04.439Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Node.js": { + "modified": "2019-03-23T22:31:42.758Z", + "contributors": [ + "MashKao", + "iigmir" + ] + }, + "Glossary/Null": { + "modified": "2019-03-18T21:41:44.373Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Number": { + "modified": "2019-03-18T21:43:06.067Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/OOP": { + "modified": "2019-03-23T22:25:27.137Z", + "contributors": [ + "jackblackevo", + "iigmir", + "mhlin" + ] + }, + "Glossary/Object": { + "modified": "2019-03-23T22:20:26.457Z", + "contributors": [ + "iigmir", + "stdio2017" + ] + }, + "Glossary/Opera_Browser": { + "modified": "2019-03-23T22:26:09.236Z", + "contributors": [ + "petercpg" + ] + }, + "Glossary/PHP": { + "modified": "2019-12-10T23:51:32.813Z", + "contributors": [ + "iigmir", + "wildsky" + ] + }, + "Glossary/PNG": { + "modified": "2019-03-18T21:43:45.458Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/POP": { + "modified": "2019-04-11T07:11:52.215Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Parameter": { + "modified": "2020-11-15T10:35:16.374Z", + "contributors": [ + "realspirit2017" + ] + }, + "Glossary/Port": { + "modified": "2019-03-23T22:26:13.956Z", + "contributors": [ + "petercpg" + ] + }, + "Glossary/Presto": { + "modified": "2019-03-23T22:26:12.268Z", + "contributors": [ + "petercpg" + ] + }, + "Glossary/Progressive_Enhancement": { + "modified": "2019-03-23T22:22:17.291Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Protocol": { + "modified": "2019-03-23T22:26:12.061Z", + "contributors": [ + "petercpg" + ] + }, + "Glossary/Prototype": { + "modified": "2019-03-18T21:44:16.275Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Pseudo-element": { + "modified": "2019-03-23T22:04:36.224Z", + "contributors": [ + "serinahsu", + "jackblackevo" + ] + }, + "Glossary/Python": { + "modified": "2020-02-27T00:05:00.804Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/REST": { + "modified": "2019-03-18T21:43:34.013Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Recursion": { + "modified": "2019-03-23T22:24:39.190Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Reflow": { + "modified": "2019-03-23T22:14:40.596Z", + "contributors": [ + "jackblackevo" + ] + }, + "Glossary/Regular_expression": { + "modified": "2019-03-23T22:31:40.731Z", + "contributors": [ + "petercpg", + "iigmir" + ] + }, + "Glossary/Responsive_web_design": { + "modified": "2020-02-27T00:27:23.047Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Ruby": { + "modified": "2020-02-27T00:09:53.452Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/SEO": { + "modified": "2019-10-17T06:29:26.247Z", + "contributors": [ + "iigmir", + "slivenred" + ] + }, + "Glossary/SGML": { + "modified": "2019-03-23T22:26:12.834Z", + "contributors": [ + "petercpg" + ] + }, + "Glossary/SPA": { + "modified": "2020-06-01T13:03:21.776Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/SQL": { + "modified": "2019-03-23T22:28:09.553Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/SQL_Injection": { + "modified": "2019-03-23T22:31:49.084Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/SVG": { + "modified": "2019-03-23T22:08:49.246Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/SVN": { + "modified": "2019-03-18T21:40:39.931Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/Server": { + "modified": "2019-03-23T22:11:10.326Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Synchronous": { + "modified": "2019-03-18T21:45:24.621Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/Type": { + "modified": "2019-03-23T22:18:38.339Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/URI": { + "modified": "2020-11-15T10:56:07.712Z", + "contributors": [ + "realspirit2017" + ] + }, + "Glossary/URL": { + "modified": "2019-12-23T12:39:40.086Z", + "contributors": [ + "Uemmra3", + "Rocker" + ] + }, + "Glossary/Viewport": { + "modified": "2019-10-05T05:58:15.650Z", + "contributors": [ + "ayugioh2003" + ] + }, + "Glossary/W3C": { + "modified": "2019-03-23T22:28:08.358Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/WebExtensions": { + "modified": "2019-03-23T22:07:09.589Z", + "contributors": [ + "jmlntw" + ] + }, + "Glossary/WebSockets": { + "modified": "2019-03-18T21:31:09.770Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/array": { + "modified": "2019-03-23T22:15:27.805Z", + "contributors": [ + "iigmir", + "jackblackevo", + "vintif" + ] + }, + "Glossary/buffer": { + "modified": "2019-03-18T21:44:30.702Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/cacheable": { + "modified": "2019-03-18T21:43:19.964Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/character_encoding": { + "modified": "2019-03-23T22:15:28.906Z", + "contributors": [ + "jackblackevo", + "AfricanxAdmiral" + ] + }, + "Glossary/character_set": { + "modified": "2019-04-04T12:54:28.232Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/event": { + "modified": "2019-03-18T21:43:22.669Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/firewall": { + "modified": "2019-03-18T21:43:50.549Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/hash": { + "modified": "2019-03-18T21:42:32.887Z", + "contributors": [ + "Rocker" + ] + }, + "Glossary/jQuery": { + "modified": "2020-05-23T15:08:04.982Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/jpeg": { + "modified": "2019-03-18T21:44:36.385Z", + "contributors": [ + "iigmir" + ] + }, + "Glossary/property": { + "modified": "2019-03-23T22:31:19.880Z", + "contributors": [ + "iigmir", + "MashKao", + "Jeremie" + ] + }, + "Glossary/property/JavaScript": { + "modified": "2019-03-23T22:31:19.578Z", + "contributors": [ + "iigmir", + "marktwtn", + "jackblackevo" + ] + }, + "Glossary/routers": { + "modified": "2020-02-27T00:38:00.019Z", + "contributors": [ + "iigmir" + ] + }, + "HTML5_Cross_Browser_Polyfills": { + "modified": "2019-01-16T13:58:45.342Z", + "contributors": [ + "Kennyluck" + ] + }, + "Learn": { + "modified": "2020-08-04T10:38:00.665Z", + "contributors": [ + "did1335", + "SphinxKnight", + "ayugioh2003", + "svarlamov", + "xerviam", + "iigmir", + "SecondSpirit", + "afutseng", + "MashKao", + "jackblackevo", + "kscarfone" + ] + }, + "Learn/Accessibility": { + "modified": "2020-07-16T22:40:01.949Z", + "contributors": [ + "iigmir", + "hadleyel" + ] + }, + "Learn/Accessibility/Mobile": { + "modified": "2020-07-16T22:40:33.645Z", + "contributors": [ + "sophie.wulala" + ] + }, + "Learn/Accessibility/WAI-ARIA_basics": { + "modified": "2020-07-16T22:40:24.926Z", + "contributors": [ + "iigmir", + "li-liam" + ] + }, + "Learn/Accessibility/What_is_accessibility": { + "modified": "2020-07-16T22:40:07.534Z", + "contributors": [ + "ballfish", + "iigmir" + ] + }, + "Learn/CSS": { + "modified": "2020-09-05T00:19:05.982Z", + "contributors": [ + "ddtet", + "anniesnoopymd", + "PtCt", + "jackblackevo" + ] + }, + "Learn/CSS/CSS_layout": { + "modified": "2020-07-16T22:26:35.040Z", + "contributors": [ + "xuan0123", + "xerviam", + "Rocker", + "jackblackevo", + "georgelin422" + ] + }, + "Learn/CSS/First_steps": { + "modified": "2020-10-04T12:16:14.514Z", + "contributors": [ + "ddtet", + "yungfen8911", + "chrisdavidmills" + ] + }, + "Learn/CSS/First_steps/Getting_started": { + "modified": "2020-11-15T11:55:24.776Z", + "contributors": [ + "ssuhung", + "ddtet" + ] + }, + "Learn/CSS/First_steps/How_CSS_works": { + "modified": "2020-07-16T22:28:02.731Z", + "contributors": [ + "JamesGoler" + ] + }, + "Learn/CSS/First_steps/What_is_CSS": { + "modified": "2020-10-15T22:34:12.625Z", + "contributors": [ + "ddtet" + ] + }, + "Learn/CSS/Styling_text": { + "modified": "2020-07-16T22:26:01.676Z", + "contributors": [ + "jackblackevo", + "xuan0123" + ] + }, + "Learn/Common_questions": { + "modified": "2020-07-16T22:35:28.440Z", + "contributors": [ + "stephaniehobson" + ] + }, + "Learn/Common_questions/What_is_a_web_server": { + "modified": "2020-07-16T22:35:32.438Z", + "contributors": [ + "LanKuDot", + "iigmir" + ] + }, + "Learn/Getting_started_with_the_web": { + "modified": "2020-07-16T22:33:57.918Z", + "contributors": [ + "egg734631", + "jackblackevo", + "chrisdavidmills", + "2238", + "SecondSpirit", + "MashKao", + "afutseng", + "lynn456", + "arbatskiy" + ] + }, + "Learn/Getting_started_with_the_web/CSS_basics": { + "modified": "2020-08-01T04:32:20.530Z", + "contributors": [ + "wslisam", + "jpliu24", + "seanhung-isu", + "nighet", + "Paul0302", + "jjyaung", + "thegaze77", + "eric211924", + "e7822501", + "yuwei2s", + "Ruiyuan34", + "iigmir", + "Chintears", + "montagne3653", + "freddy50806", + "YuCheng", + "ffturtle" + ] + }, + "Learn/Getting_started_with_the_web/Dealing_with_files": { + "modified": "2020-07-16T22:34:39.964Z", + "contributors": [ + "jackblackevo", + "SecondSpirit" + ] + }, + "Learn/Getting_started_with_the_web/HTML_basics": { + "modified": "2020-07-16T22:34:54.083Z", + "contributors": [ + "nighet", + "jackblackevo", + "YuCheng", + "iigmir", + "weichi", + "shinglyu" + ] + }, + "Learn/Getting_started_with_the_web/How_the_Web_works": { + "modified": "2020-10-14T07:48:44.116Z", + "contributors": [ + "RocketSH", + "no249a002", + "iigmir" + ] + }, + "Learn/Getting_started_with_the_web/Installing_basic_software": { + "modified": "2020-07-16T22:34:12.856Z", + "contributors": [ + "iigmir", + "jackblackevo", + "SecondSpirit", + "MashKao" + ] + }, + "Learn/Getting_started_with_the_web/JavaScript_basics": { + "modified": "2020-07-16T22:35:18.923Z", + "contributors": [ + "rayainman", + "jyzeng17", + "Ice1187", + "Jyo238", + "Fangfeidenimen", + "jackblackevo", + "Chiahong", + "YuCheng", + "victor0801x", + "VioletVivirand" + ] + }, + "Learn/Getting_started_with_the_web/Publishing_your_website": { + "modified": "2020-07-16T22:34:30.592Z", + "contributors": [ + "jyzeng17", + "iigmir", + "MLJ" + ] + }, + "Learn/Getting_started_with_the_web/What_will_your_website_look_like": { + "modified": "2020-07-16T22:34:21.648Z", + "contributors": [ + "jackblackevo", + "iosos", + "SecondSpirit", + "MashKao" + ] + }, + "Learn/HTML": { + "modified": "2020-11-08T04:39:50.729Z", + "contributors": [ + "ssuhung", + "NekoChan-2851", + "nighet", + "jjyaung", + "ShengHaoLo", + "sbeing", + "BbsonLin", + "jian5753", + "chrisdavidmills" + ] + }, + "Learn/HTML/Forms": { + "modified": "2020-07-16T22:21:03.096Z", + "contributors": [ + "nighet", + "chrisdavidmills", + "iigmir", + "Shiyou", + "saka6333", + "jcchang", + "sjmiles" + ] + }, + "Learn/HTML/Forms/How_to_structure_an_HTML_form": { + "modified": "2020-07-16T22:21:16.863Z", + "contributors": [ + "iigmir", + "anniesnoopymd", + "chrisdavidmills", + "Sheppy", + "kitty-5420" + ] + }, + "Learn/HTML/Howto": { + "modified": "2020-07-16T22:22:31.553Z", + "contributors": [ + "fish0819", + "iigmir", + "abler0122" + ] + }, + "Learn/HTML/Introduction_to_HTML": { + "modified": "2020-10-24T16:53:35.988Z", + "contributors": [ + "NekoChan-2851", + "JamesGoler", + "pccisme", + "jian5753", + "JunliXiao", + "yvonne6344", + "jackblackevo", + "akccakcctw", + "SecondSpirit" + ] + }, + "Learn/HTML/Introduction_to_HTML/Advanced_text_formatting": { + "modified": "2020-07-16T22:24:00.731Z", + "contributors": [ + "RichKe" + ] + }, + "Learn/HTML/Introduction_to_HTML/Creating_hyperlinks": { + "modified": "2020-07-16T22:23:49.670Z", + "contributors": [ + "JamesGoler" + ] + }, + "Learn/HTML/Introduction_to_HTML/Document_and_website_structure": { + "modified": "2020-09-26T12:33:20.817Z", + "contributors": [ + "CoderAmutu", + "did1335" + ] + }, + "Learn/HTML/Introduction_to_HTML/Getting_started": { + "modified": "2020-07-16T22:23:10.341Z", + "contributors": [ + "JamesGoler", + "Jkywang", + "egg734631", + "freddy50806", + "MLJ", + "jwhitlock" + ] + }, + "Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals": { + "modified": "2020-07-16T22:23:41.134Z", + "contributors": [ + "ReneeZhou", + "iigmir", + "alkalineW" + ] + }, + "Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML": { + "modified": "2020-07-16T22:23:27.064Z", + "contributors": [ + "kutshaitsi", + "JamesGoler", + "andreswang26", + "eric211924", + "MLJ" + ] + }, + "Learn/HTML/Multimedia_and_embedding": { + "modified": "2020-07-16T22:24:31.157Z", + "contributors": [ + "zackjtl", + "clamser0402", + "CATITANK" + ] + }, + "Learn/HTML/Multimedia_and_embedding/HTML中的圖片": { + "modified": "2020-07-20T05:13:25.235Z", + "contributors": [ + "zackjtl", + "LeonchanTW" + ] + }, + "Learn/HTML/Multimedia_and_embedding/Video_and_audio_content": { + "modified": "2020-09-27T07:40:33.292Z", + "contributors": [ + "mohammad92asghari" + ] + }, + "Learn/HTML/Multimedia_and_embedding/Video_and_audio_content/Test_your_skills:_Multimedia_and_embedding": { + "modified": "2020-09-27T08:06:04.019Z", + "contributors": [ + "CoderAmutu" + ] + }, + "Learn/HTML/Multimedia_and_embedding/其他_嵌入_技術": { + "modified": "2020-09-27T08:20:57.717Z", + "contributors": [ + "CoderAmutu" + ] + }, + "Learn/HTML/Tables": { + "modified": "2020-07-16T22:25:16.897Z", + "contributors": [ + "iigmir" + ] + }, + "Learn/HTML/Tables/基礎": { + "modified": "2020-11-25T04:21:37.312Z", + "contributors": [ + "123milkcat", + "allchangechallenge" + ] + }, + "Learn/How_to_contribute": { + "modified": "2020-07-16T22:33:48.192Z", + "contributors": [ + "SphinxKnight", + "willynpi", + "iigmir" + ] + }, + "Learn/JavaScript": { + "modified": "2020-07-30T05:29:53.810Z", + "contributors": [ + "klareh", + "nighet", + "ddtet", + "xerviam", + "MashKao", + "flyinglimao", + "fredliu16", + "chrisdavidmills" + ] + }, + "Learn/JavaScript/Building_blocks": { + "modified": "2020-07-16T22:31:11.353Z", + "contributors": [ + "AlbertTien", + "mdasinc", + "mubiesam", + "metismini", + "ArchieAtOrigins" + ] + }, + "Learn/JavaScript/Building_blocks/Build_your_own_function": { + "modified": "2020-07-16T22:31:32.052Z", + "contributors": [ + "jackblackevo", + "mubiesam" + ] + }, + "Learn/JavaScript/Building_blocks/Functions": { + "modified": "2020-07-16T22:31:27.864Z", + "contributors": [ + "jackblackevo", + "mubiesam" + ] + }, + "Learn/JavaScript/Building_blocks/Image_gallery": { + "modified": "2020-07-16T22:31:45.353Z", + "contributors": [ + "richblack" + ] + }, + "Learn/JavaScript/Building_blocks/Looping_code": { + "modified": "2020-11-25T23:18:26.484Z", + "contributors": [ + "aeolusg38", + "jackblackevo", + "mubiesam" + ] + }, + "Learn/JavaScript/Building_blocks/Return_values": { + "modified": "2020-07-16T22:31:35.396Z", + "contributors": [ + "jackblackevo", + "mubiesam" + ] + }, + "Learn/JavaScript/Building_blocks/conditionals": { + "modified": "2020-07-16T22:31:17.163Z", + "contributors": [ + "alexmav04", + "Sumendik", + "jackblackevo", + "mubiesam" + ] + }, + "Learn/JavaScript/Client-side_web_APIs": { + "modified": "2020-07-16T22:32:43.326Z", + "contributors": [ + "tangerine1202", + "nykevinwong", + "mubiesam" + ] + }, + "Learn/JavaScript/Client-side_web_APIs/Manipulating_documents": { + "modified": "2020-07-16T22:32:50.717Z", + "contributors": [ + "BbsonLin" + ] + }, + "Learn/JavaScript/First_steps": { + "modified": "2020-10-14T02:07:07.650Z", + "contributors": [ + "RocketSH", + "nighet", + "ddtet", + "BbsonLin", + "Rocker", + "lightyen", + "michaellee8", + "lele99123", + "jackblackevo", + "SoniaBeesee" + ] + }, + "Learn/JavaScript/First_steps/A_first_splash": { + "modified": "2020-10-13T14:09:02.521Z", + "contributors": [ + "RocketSH", + "hmysjiang", + "Hungyun", + "SphinxKnight", + "dorakao0408", + "mhuang211", + "lebniz", + "RishYang", + "egg734631", + "mubiesam", + "iron0336", + "jackblackevo", + "yuwei2s" + ] + }, + "Learn/JavaScript/First_steps/Arrays": { + "modified": "2020-10-29T03:57:18.783Z", + "contributors": [ + "Winston_Sung", + "lebniz", + "jackblackevo", + "iigmir", + "mubiesam" + ] + }, + "Learn/JavaScript/First_steps/Math": { + "modified": "2020-11-25T05:35:33.086Z", + "contributors": [ + "123milkcat", + "RocketSH", + "hanson931101", + "jackblackevo", + "mubiesam" + ] + }, + "Learn/JavaScript/First_steps/Silly_story_generator": { + "modified": "2020-10-12T07:22:32.955Z", + "contributors": [ + "RocketSH", + "jackblackevo", + "tonyyoung3", + "mubiesam" + ] + }, + "Learn/JavaScript/First_steps/Strings": { + "modified": "2020-11-23T07:01:24.301Z", + "contributors": [ + "123milkcat", + "Winston_Sung", + "RocketSH", + "alexmav04", + "lebniz", + "jackblackevo", + "mubiesam" + ] + }, + "Learn/JavaScript/First_steps/Useful_string_methods": { + "modified": "2020-10-14T02:47:53.938Z", + "contributors": [ + "RocketSH", + "alexmav04", + "tangerine1202", + "jackblackevo", + "JohnKeng", + "mubiesam" + ] + }, + "Learn/JavaScript/First_steps/Variables": { + "modified": "2020-10-14T02:32:59.320Z", + "contributors": [ + "RocketSH", + "docrob0t", + "SiderealArt", + "Playpaper", + "jackblackevo", + "cyanchu", + "mubiesam" + ] + }, + "Learn/JavaScript/First_steps/What_is_JavaScript": { + "modified": "2020-11-24T13:14:38.112Z", + "contributors": [ + "docrob0t", + "RocketSH", + "ddtet", + "hmysjiang", + "nighet", + "bl1zz4rd", + "jrvstw", + "RishYang", + "mhlemonh", + "laichenghuan", + "Rocker", + "MLJ" + ] + }, + "Learn/JavaScript/First_steps/What_went_wrong": { + "modified": "2020-10-16T09:05:43.185Z", + "contributors": [ + "RocketSH", + "hmysjiang", + "lebniz", + "tonyyoung3", + "benjaminchen" + ] + }, + "Learn/JavaScript/Howto": { + "modified": "2020-07-16T22:33:12.146Z", + "contributors": [ + "jackblackevo", + "DoJQuadArts" + ] + }, + "Learn/JavaScript/Objects": { + "modified": "2020-07-16T22:31:54.909Z", + "contributors": [ + "iigmir", + "MashKao" + ] + }, + "Learn/JavaScript/Objects/Adding_bouncing_balls_features": { + "modified": "2020-07-16T22:32:36.968Z", + "contributors": [ + "BobChao", + "MashKao" + ] + }, + "Learn/JavaScript/Objects/Basics": { + "modified": "2020-07-16T22:32:03.311Z", + "contributors": [ + "hunterflag", + "tangerine1202", + "sss63232", + "richblack", + "iigmir", + "MashKao" + ] + }, + "Learn/JavaScript/Objects/Inheritance": { + "modified": "2020-07-16T22:32:17.083Z", + "contributors": [ + "tangerine1202", + "Yang09701194", + "roycrxtw", + "MashKao" + ] + }, + "Learn/JavaScript/Objects/JSON": { + "modified": "2020-07-16T22:32:30.018Z", + "contributors": [ + "roycrxtw", + "MashKao" + ] + }, + "Learn/JavaScript/Objects/Object-oriented_JS": { + "modified": "2020-07-16T22:32:09.821Z", + "contributors": [ + "DahisC", + "tangerine1202", + "iigmir", + "cjchng", + "roycrxtw", + "MashKao" + ] + }, + "Learn/JavaScript/Objects/Object_building_practice": { + "modified": "2020-07-16T22:32:33.523Z", + "contributors": [ + "comicat", + "roycrxtw", + "MashKao" + ] + }, + "Learn/JavaScript/Objects/Object_prototypes": { + "modified": "2020-07-16T22:32:23.310Z", + "contributors": [ + "tangerine1202", + "roycrxtw", + "MashKao" + ] + }, + "Learn/Performance": { + "modified": "2020-07-16T22:40:40.169Z", + "contributors": [ + "estelle" + ] + }, + "Learn/Performance/多媒體": { + "modified": "2020-07-16T22:40:44.626Z", + "contributors": [ + "b84330808" + ] + }, + "Learn/Server-side": { + "modified": "2020-07-16T22:36:04.016Z", + "contributors": [ + "iigmir", + "rsidorov" + ] + }, + "Learn/Server-side/Django": { + "modified": "2020-07-16T22:36:37.414Z", + "contributors": [ + "iigmir", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/Admin_site": { + "modified": "2020-07-16T22:37:06.543Z", + "contributors": [ + "condal36", + "Bong99", + "Yuehua-Liu", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/Authentication": { + "modified": "2020-07-22T04:08:45.043Z", + "contributors": [ + "zcecil", + "condal36", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/Deployment": { + "modified": "2020-07-16T22:37:43.781Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Django/Forms": { + "modified": "2020-11-13T23:21:29.124Z", + "contributors": [ + "joshra", + "condal36", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/Generic_views": { + "modified": "2020-11-13T03:46:00.269Z", + "contributors": [ + "joshra", + "hsiaocy", + "a27936343", + "AlonChen", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/Home_page": { + "modified": "2020-07-16T22:37:12.554Z", + "contributors": [ + "condal36", + "zenuie", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/Introduction": { + "modified": "2020-07-16T22:36:42.822Z", + "contributors": [ + "SphinxKnight", + "tan800630", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/Models": { + "modified": "2020-10-03T02:04:47.327Z", + "contributors": [ + "hsiaocy", + "Yuehua-Liu", + "Ajameomeo", + "willynpi", + "LeonH", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/Sessions": { + "modified": "2020-10-19T12:00:28.346Z", + "contributors": [ + "hsiaocy", + "condal36", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/Testing": { + "modified": "2020-07-16T22:37:39.988Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Django/Tutorial_local_library_website": { + "modified": "2020-07-16T22:36:50.916Z", + "contributors": [ + "willynpi", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/development_environment": { + "modified": "2020-07-16T22:36:47.959Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Django/django_assessment_blog": { + "modified": "2020-07-16T22:37:50.139Z", + "contributors": [ + "willynpi", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/skeleton_website": { + "modified": "2020-07-16T22:36:55.864Z", + "contributors": [ + "Yuehua-Liu", + "Ericchen159", + "LeonH", + "edgar-chen" + ] + }, + "Learn/Server-side/Django/web_application_security": { + "modified": "2020-07-16T22:37:47.653Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs": { + "modified": "2020-07-16T22:37:56.965Z", + "contributors": [ + "iigmir", + "tonyyoung3", + "xxi511", + "lol-russo" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data": { + "modified": "2020-07-16T22:38:32.471Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page": { + "modified": "2020-07-16T22:38:39.533Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page": { + "modified": "2020-07-16T22:38:38.387Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_detail_page_and_challenge": { + "modified": "2020-07-16T22:38:39.883Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page": { + "modified": "2020-07-16T22:38:37.189Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page": { + "modified": "2020-07-16T22:38:39.240Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page": { + "modified": "2020-07-16T22:38:36.489Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment": { + "modified": "2020-07-16T22:38:37.729Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page": { + "modified": "2020-07-16T22:38:38.850Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/Home_page": { + "modified": "2020-07-16T22:38:35.865Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template": { + "modified": "2020-07-16T22:38:35.227Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer": { + "modified": "2020-07-16T22:38:34.841Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async": { + "modified": "2020-07-16T22:38:33.995Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/Introduction": { + "modified": "2020-09-27T06:14:07.664Z", + "contributors": [ + "edward_hu", + "edgar-chen", + "xxi511" + ] + }, + "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website": { + "modified": "2020-07-16T22:38:17.846Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/deployment": { + "modified": "2020-07-16T22:38:51.489Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/development_environment": { + "modified": "2020-09-27T05:38:44.626Z", + "contributors": [ + "chengzee", + "edgar-chen", + "xxi511" + ] + }, + "Learn/Server-side/Express_Nodejs/forms": { + "modified": "2020-07-16T22:38:42.914Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/forms/Create_BookInstance_form": { + "modified": "2020-07-16T22:38:46.419Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/forms/Create_author_form": { + "modified": "2020-07-16T22:38:44.881Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/forms/Create_book_form": { + "modified": "2020-07-16T22:38:45.325Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/forms/Create_genre_form": { + "modified": "2020-07-16T22:38:44.086Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/forms/Delete_author_form": { + "modified": "2020-07-16T22:38:46.873Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/mongoose": { + "modified": "2020-09-28T05:01:32.342Z", + "contributors": [ + "chengzee", + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/routes": { + "modified": "2020-07-16T22:38:29.382Z", + "contributors": [ + "edgar-chen" + ] + }, + "Learn/Server-side/Express_Nodejs/skeleton_website": { + "modified": "2020-09-28T00:50:58.875Z", + "contributors": [ + "chengzee", + "edgar-chen" + ] + }, + "Learn/Server-side/First_steps": { + "modified": "2020-07-16T22:36:11.738Z", + "contributors": [ + "iigmir" + ] + }, + "Learn/Server-side/First_steps/介紹": { + "modified": "2020-10-29T10:39:42.677Z", + "contributors": [ + "JamesGoler", + "Kun-Neng", + "vivihenry", + "frank030310" + ] + }, + "Learn/Tools_and_testing": { + "modified": "2020-07-16T22:38:58.702Z", + "contributors": [ + "iigmir" + ] + }, + "Learn/Tools_and_testing/Client-side_JavaScript_frameworks": { + "modified": "2020-07-16T22:39:34.178Z", + "contributors": [ + "iigmir" + ] + }, + "Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction": { + "modified": "2020-11-18T23:19:28.135Z", + "contributors": [ + "MerlinCute", + "iigmir" + ] + }, + "Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning": { + "modified": "2020-11-10T07:16:31.083Z", + "contributors": [ + "RocketSH" + ] + }, + "Learn/Tools_and_testing/Cross_browser_testing": { + "modified": "2020-07-16T22:39:02.574Z", + "contributors": [ + "wbamberg", + "iigmir" + ] + }, + "Learn/Tools_and_testing/Cross_browser_testing/Automated_testing": { + "modified": "2020-07-16T22:39:19.937Z", + "contributors": [ + "wbamberg", + "iigmir", + "roycrxtw" + ] + }, + "MDN": { + "modified": "2019-09-10T15:45:39.460Z", + "contributors": [ + "SphinxKnight", + "wbamberg", + "jmlntw", + "Jeremie", + "SecondSpirit", + "irvinfly", + "Sheppy" + ] + }, + "MDN/About": { + "modified": "2019-09-10T08:57:06.612Z", + "contributors": [ + "SphinxKnight", + "wbamberg", + "jackblackevo", + "Rocker", + "jmlntw", + "jswisher", + "iigmir", + "teoli", + "young3578671", + "irvinfly", + "abs0986211642" + ] + }, + "MDN/Community": { + "modified": "2020-05-24T00:35:19.952Z", + "contributors": [ + "nighet", + "wbamberg", + "SecondSpirit", + "ALiangLiang", + "a0983891582", + "king_5266" + ] + }, + "MDN/Community/論壇": { + "modified": "2020-05-24T00:50:25.189Z", + "contributors": [ + "nighet" + ] + }, + "MDN/Contribute": { + "modified": "2019-01-16T19:25:51.462Z", + "contributors": [ + "wbamberg", + "iigmir", + "irvinfly", + "PHIDIAS", + "emmanuelodenyire" + ] + }, + "MDN/Contribute/Getting_started": { + "modified": "2020-09-30T17:17:21.724Z", + "contributors": [ + "chrisdavidmills", + "did1335", + "ayugioh2003", + "wbamberg", + "Rocker", + "iigmir", + "jmlntw", + "RichKe", + "SecondSpirit", + "ALiangLiang", + "Seinlin", + "BobChao", + "anna.hp.huang", + "zzzzpaul", + "wildsky" + ] + }, + "MDN/Contribute/Howto": { + "modified": "2019-01-16T20:46:52.062Z", + "contributors": [ + "wbamberg", + "ArvinH", + "klez" + ] + }, + "MDN/Contribute/Howto/Create_an_MDN_account": { + "modified": "2019-01-16T21:17:57.540Z", + "contributors": [ + "wbamberg", + "iigmir", + "f19857466" + ] + }, + "MDN/Contribute/Howto/Create_and_edit_pages": { + "modified": "2019-04-23T05:30:19.186Z", + "contributors": [ + "jackblackevo", + "wbamberg", + "Shiyou", + "Supaplex", + "darksnidget", + "SecondSpirit", + "coby777" + ] + }, + "MDN/Contribute/Howto/Do_a_technical_review": { + "modified": "2019-03-23T22:32:06.855Z", + "contributors": [ + "wbamberg", + "iigmir", + "mgrn" + ] + }, + "MDN/Contribute/Howto/Do_an_editorial_review": { + "modified": "2019-08-12T14:08:44.950Z", + "contributors": [ + "ayugioh2003", + "wbamberg", + "jwhitlock", + "flyinglimao" + ] + }, + "MDN/Contribute/Howto/Set_the_summary_for_a_page": { + "modified": "2019-03-23T22:02:13.738Z", + "contributors": [ + "wbamberg", + "Astrid-GitHub", + "RSyehann" + ] + }, + "MDN/Contribute/Howto/Tag": { + "modified": "2019-03-23T22:54:12.092Z", + "contributors": [ + "wbamberg", + "yami" + ] + }, + "MDN/Contribute/Localize": { + "modified": "2019-01-16T19:52:54.512Z", + "contributors": [ + "wbamberg", + "ballfish", + "Sheppy" + ] + }, + "MDN/Contribute/Localize/Localization_projects": { + "modified": "2019-03-18T21:23:31.576Z", + "contributors": [ + "eyeccc" + ] + }, + "MDN/Contribute/Localize/Translating_pages": { + "modified": "2019-09-03T06:12:45.102Z", + "contributors": [ + "Lazine", + "wbamberg", + "iigmir", + "irvinfly", + "tai58585888@gmail.com", + "bryanyou" + ] + }, + "MDN/Editor": { + "modified": "2020-09-30T15:44:37.576Z", + "contributors": [ + "chrisdavidmills", + "wbamberg", + "EatPizza311", + "tpst1114", + "jswisher" + ] + }, + "MDN/Editor/Basics": { + "modified": "2020-09-30T15:44:37.917Z", + "contributors": [ + "chrisdavidmills", + "wbamberg", + "tpst1114" + ] + }, + "MDN/Editor/Edit_box": { + "modified": "2020-09-30T15:44:37.748Z", + "contributors": [ + "chrisdavidmills", + "wbamberg", + "jackblackevo", + "JoanneWu" + ] + }, + "MDN/Guidelines": { + "modified": "2020-09-30T15:33:00.096Z", + "contributors": [ + "chrisdavidmills", + "wbamberg", + "fscholz", + "irvinfly", + "Sheppy" + ] + }, + "MDN/Guidelines/Writing_style_guide": { + "modified": "2020-09-30T15:33:00.614Z", + "contributors": [ + "chrisdavidmills", + "jswisher", + "wbamberg", + "flyinglimao", + "iigmir", + "fscholz", + "BrianHuang", + "irvinfly", + "kiss007sky", + "wildsky" + ] + }, + "MDN/Kuma": { + "modified": "2019-09-06T03:30:44.825Z", + "contributors": [ + "SphinxKnight", + "wbamberg", + "iigmir", + "SecondSpirit", + "a8040282", + "Sheppy" + ] + }, + "MDN/Tools": { + "modified": "2020-09-30T16:55:39.074Z", + "contributors": [ + "chrisdavidmills", + "wbamberg", + "jackblackevo" + ] + }, + "MDN/Tools/KumaScript": { + "modified": "2020-09-30T16:55:39.461Z", + "contributors": [ + "chrisdavidmills", + "wbamberg", + "jackblackevo" + ] + }, + "MDN/Tools/KumaScript/Troubleshooting": { + "modified": "2020-09-30T16:55:39.606Z", + "contributors": [ + "chrisdavidmills", + "wbamberg", + "jackblackevo", + "iigmir", + "alk03073135" + ] + }, + "MDN_at_ten": { + "modified": "2019-03-23T22:49:37.556Z", + "contributors": [ + "alk03073135" + ] + }, + "Mozilla": { + "modified": "2019-03-23T23:33:56.932Z", + "contributors": [ + "iigmir", + "ethertank" + ] + }, + "Mozilla/Add-ons": { + "modified": "2019-03-18T21:08:19.815Z", + "contributors": [ + "iigmir", + "refrain4121", + "a780201", + "A520", + "irvinfly", + "softcup", + "teoli", + "petercpg", + "wildsky", + "Anomitro_Munshi" + ] + }, + "Mozilla/Add-ons/WebExtensions": { + "modified": "2019-03-18T21:07:16.806Z", + "contributors": [ + "jmlntw", + "flyinglimao", + "iigmir", + "ALiangLiang", + "wbamberg" + ] + }, + "Mozilla/Add-ons/WebExtensions/API": { + "modified": "2019-11-26T22:20:23.005Z", + "contributors": [ + "wbamberg", + "Makyen" + ] + }, + "Mozilla/Add-ons/WebExtensions/API/cookies": { + "modified": "2020-10-15T21:56:17.735Z", + "contributors": [ + "wbamberg", + "BobChao" + ] + }, + "Mozilla/Add-ons/WebExtensions/API/cookies/CookieStore": { + "modified": "2020-10-15T21:56:17.810Z", + "contributors": [ + "wbamberg", + "iigmir" + ] + }, + "Mozilla/Add-ons/WebExtensions/API/cookies/OnChangedCause": { + "modified": "2020-10-15T21:56:19.833Z", + "contributors": [ + "wbamberg", + "iigmir" + ] + }, + "Mozilla/Add-ons/WebExtensions/API/cookies/onChanged": { + "modified": "2020-10-15T21:56:17.446Z", + "contributors": [ + "wbamberg", + "iigmir" + ] + }, + "Mozilla/Add-ons/WebExtensions/API/storage": { + "modified": "2020-10-15T21:57:11.902Z", + "contributors": [ + "wbamberg", + "0711kps", + "Makyen" + ] + }, + "Mozilla/Add-ons/WebExtensions/API/storage/StorageArea": { + "modified": "2020-10-15T22:02:56.746Z", + "contributors": [ + "wbamberg", + "chrisdavidmills" + ] + }, + "Mozilla/Add-ons/WebExtensions/API/storage/StorageArea/get": { + "modified": "2020-10-15T22:02:56.819Z", + "contributors": [ + "wbamberg", + "iigmir" + ] + }, + "Mozilla/Add-ons/WebExtensions/API/storage/local": { + "modified": "2020-10-15T21:57:10.754Z", + "contributors": [ + "wbamberg", + "iigmir" + ] + }, + "Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension": { + "modified": "2020-04-20T22:14:29.842Z", + "contributors": [ + "eugene87222", + "JamesGoler", + "Dream_Rhythm", + "a39705397", + "start1119", + "Kahiro" + ] + }, + "Mozilla/Add-ons/WebExtensions/Content_scripts": { + "modified": "2019-03-18T21:02:28.504Z", + "contributors": [ + "0711kps" + ] + }, + "Mozilla/Add-ons/WebExtensions/Internationalization": { + "modified": "2019-03-18T21:04:29.607Z", + "contributors": [ + "iigmir" + ] + }, + "Mozilla/Add-ons/WebExtensions/What_are_WebExtensions": { + "modified": "2019-03-18T21:06:44.158Z", + "contributors": [ + "honeymagico", + "iigmir" + ] + }, + "Mozilla/Add-ons/WebExtensions/Your_first_WebExtension": { + "modified": "2019-03-18T21:06:51.398Z", + "contributors": [ + "BobChao", + "iigmir", + "ALiangLiang" + ] + }, + "Mozilla/Add-ons/WebExtensions/Your_second_WebExtension": { + "modified": "2020-06-30T05:06:14.538Z", + "contributors": [ + "LeonH", + "eugene87222", + "RishYang", + "timmyshih", + "Tamako" + ] + }, + "Mozilla/Add-ons/WebExtensions/manifest.json": { + "modified": "2020-10-15T22:06:23.531Z", + "contributors": [ + "landylan", + "wbamberg", + "ExE-Boss" + ] + }, + "Mozilla/Add-ons/WebExtensions/manifest.json/author": { + "modified": "2020-10-15T22:06:20.756Z", + "contributors": [ + "jackblackevo", + "wbamberg", + "0711kps" + ] + }, + "Mozilla/Add-ons/WebExtensions/manifest.json/background": { + "modified": "2020-10-15T22:06:22.887Z", + "contributors": [ + "0711kps" + ] + }, + "Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings": { + "modified": "2020-10-15T22:06:22.269Z", + "contributors": [ + "wbamberg", + "ExE-Boss", + "0711kps" + ] + }, + "Mozilla/Add-ons/WebExtensions/manifest.json/homepage_url": { + "modified": "2020-10-15T22:06:22.588Z", + "contributors": [ + "wbamberg", + "0711kps" + ] + }, + "Mozilla/Add-ons/WebExtensions/manifest.json/options_ui": { + "modified": "2020-10-15T22:06:23.412Z", + "contributors": [ + "wbamberg", + "0711kps" + ] + }, + "Mozilla/Add-ons/WebExtensions/user_interface": { + "modified": "2019-04-23T05:01:36.148Z", + "contributors": [ + "jackblackevo", + "0711kps" + ] + }, + "Mozilla/Add-ons/WebExtensions/user_interface/Browser_action": { + "modified": "2019-04-23T05:01:57.057Z", + "contributors": [ + "jackblackevo", + "0711kps" + ] + }, + "Mozilla/Add-ons/WebExtensions/user_interface/Context_menu_items": { + "modified": "2019-04-23T05:04:17.208Z", + "contributors": [ + "jackblackevo", + "0711kps" + ] + }, + "Mozilla/Add-ons/WebExtensions/user_interface/Sidebars": { + "modified": "2019-04-23T05:02:36.826Z", + "contributors": [ + "jackblackevo", + "0711kps" + ] + }, + "Mozilla/Add-ons/WebExtensions/user_interface/devtools_panels": { + "modified": "2019-04-23T05:05:05.338Z", + "contributors": [ + "jackblackevo", + "0711kps" + ] + }, + "Mozilla/Developer_guide": { + "modified": "2019-03-23T23:37:29.771Z", + "contributors": [ + "jackblackevo", + "pytseng", + "tessarakt3" + ] + }, + "Mozilla/Developer_guide/Source_Code": { + "modified": "2019-03-23T23:37:28.223Z", + "contributors": [ + "jackblackevo", + "iigmir", + "yehchge" + ] + }, + "Mozilla/Developer_guide/Source_Code/CVS": { + "modified": "2019-04-21T11:31:24.705Z", + "contributors": [ + "wangshi3" + ] + }, + "Mozilla/Firefox": { + "modified": "2020-01-18T14:58:24.025Z", + "contributors": [ + "leela52452", + "SphinxKnight", + "wbamberg", + "wildsky", + "RJ_Hsiao", + "Flymok", + "Prashanth" + ] + }, + "Mozilla/Firefox/Releases": { + "modified": "2019-01-16T17:46:20.383Z", + "contributors": [ + "wbamberg", + "RJ_Hsiao", + "ziyunfei" + ] + }, + "Mozilla/Firefox/Releases/1.5": { + "modified": "2019-03-23T23:06:56.466Z", + "contributors": [ + "wbamberg", + "RJ_Hsiao" + ] + }, + "Mozilla/Firefox/Releases/10": { + "modified": "2019-03-18T21:09:01.391Z", + "contributors": [ + "fscholz", + "wbamberg", + "RJ_Hsiao" + ] + }, + "Mozilla/Firefox/Releases/11": { + "modified": "2019-03-23T23:07:01.282Z", + "contributors": [ + "wbamberg", + "RJ_Hsiao" + ] + }, + "Mozilla/Firefox/Releases/2": { + "modified": "2019-04-23T05:37:52.313Z", + "contributors": [ + "jackblackevo", + "wbamberg", + "Josesun", + "BobChao" + ] + }, + "Mozilla/Firefox/Releases/2/Adding_feed_readers_to_Firefox": { + "modified": "2019-04-23T05:38:36.737Z", + "contributors": [ + "jackblackevo", + "wbamberg", + "BobChao" + ] + }, + "Mozilla/Firefox/Releases/2/Security_changes": { + "modified": "2019-04-23T05:38:12.921Z", + "contributors": [ + "jackblackevo", + "wbamberg", + "SphinxKnight", + "Sheppy", + "Tobbytw", + "BobChao" + ] + }, + "Mozilla/Firefox/Releases/3": { + "modified": "2019-04-23T05:36:15.221Z", + "contributors": [ + "jackblackevo", + "wbamberg", + "RJ_Hsiao", + "teoli", + "Mgjbot", + "BobChao", + "Coolcd" + ] + }, + "Mozilla/Firefox/Releases/3.6": { + "modified": "2019-12-13T20:33:24.338Z", + "contributors": [ + "wbamberg", + "SphinxKnight", + "RJ_Hsiao" + ] + }, + "Mozilla/Firefox/Releases/3/DOM_improvements": { + "modified": "2019-04-23T05:36:36.182Z", + "contributors": [ + "jackblackevo", + "wbamberg", + "teoli", + "Coolcd" + ] + }, + "Mozilla/Firefox/Releases/35": { + "modified": "2019-12-13T20:33:34.355Z", + "contributors": [ + "wbamberg", + "RJ_Hsiao" + ] + }, + "Mozilla/Firefox/Releases/4": { + "modified": "2019-04-23T03:28:51.373Z", + "contributors": [ + "jackblackevo", + "wbamberg", + "SphinxKnight", + "Kennyluck", + "BobChao" + ] + }, + "Mozilla/Firefox/Releases/4/Firefox_4_開發者新功能概覽": { + "modified": "2019-04-23T03:28:52.095Z", + "contributors": [ + "jackblackevo", + "wbamberg", + "SphinxKnight", + "irvinfly", + "teoli", + "BobChao" + ] + }, + "Mozilla/Firefox/Releases/5": { + "modified": "2019-03-23T23:06:59.171Z", + "contributors": [ + "fscholz", + "wbamberg", + "iigmir", + "RJ_Hsiao" + ] + }, + "Mozilla/Firefox/Releases/6": { + "modified": "2019-11-21T00:43:15.848Z", + "contributors": [ + "wbamberg", + "RJ_Hsiao" + ] + }, + "Mozilla/Firefox/Releases/61": { + "modified": "2019-01-17T03:05:55.327Z", + "contributors": [ + "wbamberg", + "BobChao" + ] + }, + "Mozilla/Firefox/Releases/68": { + "modified": "2020-05-02T05:45:42.258Z", + "contributors": [ + "abc52090241" + ] + }, + "Mozilla/Firefox/Releases/7": { + "modified": "2019-04-23T05:35:00.727Z", + "contributors": [ + "jackblackevo", + "wbamberg", + "RJ_Hsiao", + "ethertank", + "Sheppy" + ] + }, + "Mozilla/Firefox/Releases/8": { + "modified": "2019-11-21T00:43:09.976Z", + "contributors": [ + "wbamberg", + "Sebastianz", + "RJ_Hsiao" + ] + }, + "Mozilla/Firefox/Releases/9": { + "modified": "2019-12-13T20:33:11.984Z", + "contributors": [ + "wbamberg", + "fscholz", + "RJ_Hsiao" + ] + }, + "Python": { + "modified": "2019-03-23T23:33:19.493Z", + "contributors": [ + "garylai1990" + ] + }, + "SVG/Tutorial/Basic_Shapes": { + "modified": "2019-04-23T03:35:52.184Z", + "contributors": [ + "jackblackevo", + "ethertank", + "Dx.Yang" + ] + }, + "Tools": { + "modified": "2020-07-16T22:44:20.103Z", + "contributors": [ + "SphinxKnight", + "wbamberg", + "iigmir", + "irvinfly", + "Weicheng", + "a0983891582", + "kingt_tsai", + "RJ_Hsiao", + "iinnttoo", + "yangshiqiangzy", + "Somnlent", + "benson.peng", + "dinoop.p1" + ] + }, + "Tools/3D_View": { + "modified": "2020-07-16T22:34:25.840Z", + "contributors": [ + "Sean64", + "Seafox" + ] + }, + "Tools/Browser_Toolbox": { + "modified": "2020-07-16T22:35:56.020Z", + "contributors": [ + "grapherd", + "a0983891582", + "jan730921" + ] + }, + "Tools/Debugger": { + "modified": "2020-07-16T22:35:06.897Z", + "contributors": [ + "iigmir", + "wbamberg", + "stephaniehobson", + "yurenju", + "MashKao" + ] + }, + "Tools/Debugger/How_to": { + "modified": "2020-07-16T22:35:08.733Z", + "contributors": [ + "wbamberg" + ] + }, + "Tools/Debugger/How_to/Open_the_debugger": { + "modified": "2020-07-16T22:35:09.582Z", + "contributors": [ + "marcus7777777" + ] + }, + "Tools/Debugger/How_to/Set_a_breakpoint": { + "modified": "2020-07-16T22:35:10.325Z", + "contributors": [ + "Kevinwuu" + ] + }, + "Tools/Firefox_OS_1.1_Simulator": { + "modified": "2020-07-16T22:35:58.639Z", + "contributors": [ + "MashKao" + ] + }, + "Tools/Network_Monitor": { + "modified": "2020-07-16T22:35:32.529Z", + "contributors": [ + "Fashaun" + ] + }, + "Tools/Page_Inspector": { + "modified": "2020-07-16T22:34:30.099Z", + "contributors": [ + "Fashaun", + "iigmir", + "jsx", + "zmh_w", + "RJ_Hsiao" + ] + }, + "Tools/Page_Inspector/How_to": { + "modified": "2020-07-16T22:34:32.460Z", + "contributors": [ + "iigmir", + "sidgan" + ] + }, + "Tools/Page_Inspector/How_to/Examine_grid_layouts": { + "modified": "2020-07-16T22:34:47.546Z", + "contributors": [ + "iigmir" + ] + }, + "Tools/Performance": { + "modified": "2020-07-16T22:36:14.144Z", + "contributors": [ + "irvinfly" + ] + }, + "Tools/Performance/Allocations": { + "modified": "2020-07-16T22:36:22.457Z", + "contributors": [ + "johnny801018" + ] + }, + "Tools/Performance/Frame_rate": { + "modified": "2020-07-16T22:36:19.429Z", + "contributors": [ + "black80887" + ] + }, + "Tools/Remote_Debugging": { + "modified": "2020-07-16T22:35:38.579Z", + "contributors": [ + "Keung162", + "yhn5525" + ] + }, + "Tools/Remote_Debugging/Firefox_for_Android": { + "modified": "2020-07-16T22:35:39.658Z", + "contributors": [ + "king620707" + ] + }, + "Tools/Responsive_Design_Mode": { + "modified": "2020-07-16T22:35:22.603Z", + "contributors": [ + "iigmir" + ] + }, + "Tools/Settings": { + "modified": "2020-07-16T22:36:35.954Z", + "contributors": [ + "abc52090241" + ] + }, + "Tools/Style_Editor": { + "modified": "2020-07-16T22:35:02.268Z", + "contributors": [ + "Kashashi", + "bassam", + "RJ_Hsiao" + ] + }, + "Tools/Web_Audio_Editor": { + "modified": "2020-07-16T22:36:09.045Z", + "contributors": [ + "Seafox" + ] + }, + "Tools/Web_Console": { + "modified": "2020-07-16T22:34:10.824Z", + "contributors": [ + "iigmir", + "maybe", + "bassam", + "king_5266" + ] + }, + "Tools/Web_Console/Console_messages": { + "modified": "2020-07-16T22:34:16.848Z", + "contributors": [ + "iigmir" + ] + }, + "Tools/Web_Console/Keyboard_shortcuts": { + "modified": "2020-07-16T22:34:24.444Z", + "contributors": [ + "iigmir" + ] + }, + "Tools/Web_Console/Opening_the_Web_Console": { + "modified": "2020-07-16T22:34:17.831Z", + "contributors": [ + "iigmir" + ] + }, + "Tools/Web_Console/Rich_output": { + "modified": "2020-07-16T22:34:20.675Z", + "contributors": [ + "iigmir" + ] + }, + "Tools/Web_Console/Split_console": { + "modified": "2020-07-16T22:34:21.659Z", + "contributors": [ + "iigmir" + ] + }, + "Tools/Web_Console/The_command_line_interpreter": { + "modified": "2020-07-16T22:34:19.994Z", + "contributors": [ + "iigmir" + ] + }, + "Web": { + "modified": "2020-04-05T02:12:59.455Z", + "contributors": [ + "nighet", + "santoschenwbu", + "ppdada", + "Honesty1997", + "xerviam", + "willynpi", + "sos418", + "Luke.Liu", + "tigercosmos", + "iigmir", + "irvinfly", + "togorepqddj", + "sailplaneTW", + "Sheppy" + ] + }, + "Web/API": { + "modified": "2019-03-23T23:28:12.241Z", + "contributors": [ + "xerviam", + "Demi_Yu", + "jackblackevo", + "iigmir", + "teoli", + "zhangmingyu", + "Shiyou", + "saka6333", + "ethertank" + ] + }, + "Web/API/AbortController": { + "modified": "2020-10-15T22:21:29.412Z", + "contributors": [ + "Zhusee", + "lixingnan200" + ] + }, + "Web/API/Ambient_Light_Events": { + "modified": "2019-03-23T23:27:04.119Z", + "contributors": [ + "jackblackevo", + "teoli", + "MashKao" + ] + }, + "Web/API/AnalyserNode": { + "modified": "2019-03-23T22:40:29.435Z", + "contributors": [ + "Sebastianz" + ] + }, + "Web/API/AnalyserNode/getByteFrequencyData": { + "modified": "2019-03-23T22:40:34.425Z", + "contributors": [ + "ALiangLiang", + "wildsky" + ] + }, + "Web/API/AnimationEvent": { + "modified": "2019-03-23T22:58:51.711Z", + "contributors": [ + "iigmir", + "saka6333", + "fscholz" + ] + }, + "Web/API/AnimationEvent/initAnimationEvent": { + "modified": "2019-03-23T22:58:50.823Z", + "contributors": [ + "teoli", + "cs047899" + ] + }, + "Web/API/Battery_Status_API": { + "modified": "2019-03-23T23:27:02.640Z", + "contributors": [ + "jackblackevo", + "MashKao" + ] + }, + "Web/API/Blob": { + "modified": "2020-10-15T21:38:13.856Z", + "contributors": [ + "jackblackevo", + "flyinglimao", + "changbenny", + "alk03073135" + ] + }, + "Web/API/Blob/Blob": { + "modified": "2019-03-23T22:31:20.533Z", + "contributors": [ + "flyinglimao", + "jackblackevo" + ] + }, + "Web/API/Blob/size": { + "modified": "2019-03-23T22:05:46.891Z", + "contributors": [ + "flyinglimao" + ] + }, + "Web/API/Blob/type": { + "modified": "2019-03-23T22:05:38.897Z", + "contributors": [ + "flyinglimao" + ] + }, + "Web/API/Body": { + "modified": "2020-10-15T22:10:19.507Z", + "contributors": [ + "RickBrown" + ] + }, + "Web/API/Body/json": { + "modified": "2020-10-15T22:10:18.425Z", + "contributors": [ + "xstar", + "eyeccc" + ] + }, + "Web/API/CSSStyleDeclaration": { + "modified": "2019-03-23T22:30:39.103Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/CSSStyleSheet": { + "modified": "2019-03-23T22:04:52.980Z", + "contributors": [ + "jpmedley" + ] + }, + "Web/API/CSSStyleSheet/insertRule": { + "modified": "2019-03-23T22:04:53.326Z", + "contributors": [ + "oooooo" + ] + }, + "Web/API/CSS_Object_Model": { + "modified": "2019-03-23T22:48:37.625Z", + "contributors": [ + "jackblackevo", + "fscholz" + ] + }, + "Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements": { + "modified": "2019-03-18T20:58:55.989Z", + "contributors": [ + "SphinxKnight", + "iigmir", + "alk03073135" + ] + }, + "Web/API/CSS_Object_Model/Managing_screen_orientation": { + "modified": "2019-03-23T23:25:59.570Z", + "contributors": [ + "jackblackevo", + "MashKao" + ] + }, + "Web/API/CSS_Object_Model/Using_dynamic_styling_information": { + "modified": "2019-03-23T22:20:10.346Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/CanvasRenderingContext2D": { + "modified": "2019-03-23T22:19:40.312Z", + "contributors": [ + "jsgao0", + "jackblackevo" + ] + }, + "Web/API/CanvasRenderingContext2D/clearRect": { + "modified": "2019-03-23T22:19:19.507Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Canvas_API": { + "modified": "2019-03-24T00:16:12.599Z", + "contributors": [ + "pig3629", + "jackblackevo", + "fscholz", + "teoli", + "elin", + "ethertank", + "dextra", + "Kennyluck", + "happysadman" + ] + }, + "Web/API/Canvas_API/Drawing_graphics_with_canvas": { + "modified": "2019-03-23T23:13:40.314Z", + "contributors": [ + "fscholz", + "sailplaneTW" + ] + }, + "Web/API/Canvas_API/Tutorial": { + "modified": "2019-03-18T20:36:19.502Z", + "contributors": [ + "sheng-tai", + "jackblackevo", + "fscholz", + "elin", + "foxbrush" + ] + }, + "Web/API/Canvas_API/Tutorial/Advanced_animations": { + "modified": "2019-03-23T22:03:12.070Z", + "contributors": [ + "pig3629" + ] + }, + "Web/API/Canvas_API/Tutorial/Applying_styles_and_colors": { + "modified": "2019-10-10T16:48:11.045Z", + "contributors": [ + "jackblackevo", + "fscholz", + "Sebastianz", + "foxbrush" + ] + }, + "Web/API/Canvas_API/Tutorial/Basic_animations": { + "modified": "2019-03-23T23:26:07.752Z", + "contributors": [ + "jackblackevo", + "Lambert", + "fscholz", + "foxbrush" + ] + }, + "Web/API/Canvas_API/Tutorial/Basic_usage": { + "modified": "2019-06-14T06:57:52.611Z", + "contributors": [ + "jackblackevo", + "fscholz", + "foxbrush" + ] + }, + "Web/API/Canvas_API/Tutorial/Compositing": { + "modified": "2019-03-23T23:14:05.379Z", + "contributors": [ + "jackblackevo", + "fscholz", + "elin", + "foxbrush" + ] + }, + "Web/API/Canvas_API/Tutorial/Drawing_shapes": { + "modified": "2019-03-23T23:27:29.654Z", + "contributors": [ + "Snailpool", + "jackblackevo", + "fscholz", + "foxbrush", + "elin" + ] + }, + "Web/API/Canvas_API/Tutorial/Drawing_text": { + "modified": "2019-03-23T23:38:19.546Z", + "contributors": [ + "jackblackevo", + "sssdx" + ] + }, + "Web/API/Canvas_API/Tutorial/Optimizing_canvas": { + "modified": "2019-03-23T23:26:06.214Z", + "contributors": [ + "jackblackevo", + "fscholz", + "foxbrush" + ] + }, + "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas": { + "modified": "2019-09-28T03:43:09.354Z", + "contributors": [ + "pig3629" + ] + }, + "Web/API/Canvas_API/Tutorial/Transformations": { + "modified": "2019-10-10T16:48:13.377Z", + "contributors": [ + "Chi-Hsin", + "jackblackevo", + "fscholz", + "foxbrush" + ] + }, + "Web/API/Canvas_API/Tutorial/Using_images": { + "modified": "2019-03-23T23:12:00.146Z", + "contributors": [ + "aver803bath5", + "jackblackevo", + "fscholz", + "foxbrush" + ] + }, + "Web/API/Channel_Messaging_API": { + "modified": "2019-03-23T22:49:07.205Z", + "contributors": [ + "foxbrush" + ] + }, + "Web/API/CharacterData": { + "modified": "2019-03-23T22:30:36.282Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/ChildNode": { + "modified": "2019-03-23T22:30:29.724Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Clients": { + "modified": "2019-03-23T22:41:01.027Z", + "contributors": [ + "xiantank" + ] + }, + "Web/API/ClipboardEvent": { + "modified": "2019-03-23T22:31:08.942Z", + "contributors": [ + "fscholz", + "jackblackevo" + ] + }, + "Web/API/Console": { + "modified": "2020-10-15T22:03:31.329Z", + "contributors": [ + "Syihoy", + "porfirion" + ] + }, + "Web/API/CustomEvent": { + "modified": "2020-10-15T21:38:37.754Z", + "contributors": [ + "fscholz", + "jackblackevo", + "Shiyou" + ] + }, + "Web/API/CustomEvent/CustomEvent": { + "modified": "2020-10-15T21:38:44.505Z", + "contributors": [ + "fscholz", + "Shiyou" + ] + }, + "Web/API/DOMParser": { + "modified": "2019-03-23T22:32:53.615Z", + "contributors": [ + "kenttsai" + ] + }, + "Web/API/DOMString": { + "modified": "2019-03-23T22:48:01.923Z", + "contributors": [ + "Shiyou" + ] + }, + "Web/API/DOMTokenList": { + "modified": "2019-03-23T22:30:39.565Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/DataTransfer": { + "modified": "2019-03-23T22:31:19.371Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Detecting_device_orientation": { + "modified": "2019-03-23T23:27:03.486Z", + "contributors": [ + "jackblackevo", + "MashKao" + ] + }, + "Web/API/DeviceMotionEvent": { + "modified": "2019-03-23T22:19:09.256Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/DeviceOrientationEvent": { + "modified": "2019-03-23T22:19:19.032Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Document": { + "modified": "2019-12-24T11:58:47.714Z", + "contributors": [ + "ianchen0119", + "jackblackevo", + "Sheppy" + ] + }, + "Web/API/Document/body": { + "modified": "2019-03-23T22:12:47.911Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Document/createDocumentFragment": { + "modified": "2019-03-23T22:05:41.694Z", + "contributors": [ + "tigercosmos" + ] + }, + "Web/API/Document/createElement": { + "modified": "2019-06-17T10:27:41.514Z", + "contributors": [ + "lebniz", + "jackblackevo" + ] + }, + "Web/API/Document/createRange": { + "modified": "2019-03-23T22:26:49.785Z", + "contributors": [ + "jackblackevo", + "bblurock" + ] + }, + "Web/API/Document/createTextNode": { + "modified": "2019-03-23T22:30:00.695Z", + "contributors": [ + "jackblackevo", + "rikrik527" + ] + }, + "Web/API/Document/defaultView": { + "modified": "2019-03-23T22:30:50.854Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Document/designMode": { + "modified": "2019-03-23T22:04:59.325Z", + "contributors": [ + "jmlntw" + ] + }, + "Web/API/Document/documentElement": { + "modified": "2019-03-23T22:12:40.763Z", + "contributors": [ + "Snailpool", + "jackblackevo" + ] + }, + "Web/API/Document/execCommand": { + "modified": "2020-10-15T21:57:17.621Z", + "contributors": [ + "t7yang", + "grain0217", + "Mrscrystal", + "tpst1114" + ] + }, + "Web/API/Document/forms": { + "modified": "2019-03-23T22:31:24.583Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Document/getElementsByClassName": { + "modified": "2019-03-23T22:49:19.402Z", + "contributors": [ + "jackblackevo", + "iigmir", + "Shiyou", + "alk03073135" + ] + }, + "Web/API/Document/head": { + "modified": "2019-03-23T22:48:02.502Z", + "contributors": [ + "jackblackevo", + "Shiyou" + ] + }, + "Web/API/Document/keyup_event": { + "modified": "2019-04-18T03:52:12.531Z", + "contributors": [ + "irenesmith", + "fscholz", + "JoanneWu" + ] + }, + "Web/API/Document/querySelector": { + "modified": "2019-03-23T23:28:13.625Z", + "contributors": [ + "jackblackevo", + "jsx", + "AshfaqHossain", + "carl_tw" + ] + }, + "Web/API/Document/readyState": { + "modified": "2019-06-11T20:31:50.296Z", + "contributors": [ + "StanleyDing", + "jackblackevo", + "Shiyou", + "alk03073135" + ] + }, + "Web/API/Document/registerElement": { + "modified": "2019-03-18T21:37:29.505Z", + "contributors": [ + "Chang-jui-hsuan" + ] + }, + "Web/API/Document/scroll_event": { + "modified": "2019-04-08T09:05:58.589Z", + "contributors": [ + "irenesmith", + "fscholz", + "dwatow" + ] + }, + "Web/API/Document/width": { + "modified": "2019-03-23T22:21:01.741Z", + "contributors": [ + "jackblackevo", + "ginszme" + ] + }, + "Web/API/DocumentFragment": { + "modified": "2019-03-23T22:30:16.185Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/DocumentType": { + "modified": "2019-03-23T22:31:03.437Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Document_Object_Model": { + "modified": "2019-03-24T00:03:11.264Z", + "contributors": [ + "jackblackevo", + "fscholz", + "irvinfly", + "shyangs" + ] + }, + "Web/API/Document_Object_Model/Examples": { + "modified": "2019-04-22T07:31:11.966Z", + "contributors": [ + "jackblackevo", + "PJCHENder" + ] + }, + "Web/API/Document_Object_Model/How_to_create_a_DOM_tree": { + "modified": "2019-03-23T22:13:19.887Z", + "contributors": [ + "seantw" + ] + }, + "Web/API/Document_Object_Model/Whitespace": { + "modified": "2020-01-30T13:21:14.453Z", + "contributors": [ + "chrisdavidmills", + "jackblackevo", + "ethertank", + "Mgjbot", + "BobChao" + ] + }, + "Web/API/Document_Object_Model/事件": { + "modified": "2019-03-23T22:27:33.501Z", + "contributors": [ + "H-W-Chang" + ] + }, + "Web/API/DragEvent": { + "modified": "2020-02-27T01:36:51.610Z", + "contributors": [ + "moojitsai", + "hunterflag", + "jackblackevo" + ] + }, + "Web/API/DragEvent/dataTransfer": { + "modified": "2019-03-23T22:31:17.568Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Element": { + "modified": "2019-03-18T21:08:56.279Z", + "contributors": [ + "fscholz", + "jackblackevo", + "arhoads" + ] + }, + "Web/API/Element/attributes": { + "modified": "2020-10-15T22:14:29.910Z", + "contributors": [ + "WangHsuan" + ] + }, + "Web/API/Element/classList": { + "modified": "2019-03-23T22:30:27.664Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Element/click_event": { + "modified": "2019-03-18T20:47:28.188Z", + "contributors": [ + "irenesmith", + "fscholz", + "Shiyou" + ] + }, + "Web/API/Element/clientHeight": { + "modified": "2019-03-18T20:58:47.478Z", + "contributors": [ + "SphinxKnight", + "iigmir", + "alk03073135" + ] + }, + "Web/API/Element/getAttribute": { + "modified": "2019-03-23T22:25:57.546Z", + "contributors": [ + "pdexx" + ] + }, + "Web/API/Element/innerHTML": { + "modified": "2020-10-15T22:21:46.093Z", + "contributors": [ + "itsems", + "dayknchung" + ] + }, + "Web/API/Element/insertAdjacentHTML": { + "modified": "2019-03-18T21:29:09.618Z", + "contributors": [ + "akccakcctw", + "NoobTW" + ] + }, + "Web/API/Element/querySelectorAll": { + "modified": "2020-10-15T21:51:24.241Z", + "contributors": [ + "wbamberg", + "Shiyou", + "alk03073135" + ] + }, + "Web/API/Element/scrollHeight": { + "modified": "2019-03-18T20:59:06.982Z", + "contributors": [ + "SphinxKnight", + "iigmir", + "alk03073135" + ] + }, + "Web/API/Element/scrollTop": { + "modified": "2019-03-23T22:48:35.906Z", + "contributors": [ + "iigmir", + "alk03073135" + ] + }, + "Web/API/Element/touchcancel_event": { + "modified": "2019-04-30T14:15:58.983Z", + "contributors": [ + "wbamberg", + "irenesmith", + "fscholz", + "jackblackevo", + "james_yang" + ] + }, + "Web/API/ErrorEvent": { + "modified": "2019-03-23T22:48:04.106Z", + "contributors": [ + "Shiyou" + ] + }, + "Web/API/Event": { + "modified": "2020-10-15T21:38:26.088Z", + "contributors": [ + "jackblackevo", + "Shiyou", + "Sheppy" + ] + }, + "Web/API/Event/Comparison_of_Event_Targets": { + "modified": "2019-03-23T22:31:03.921Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Event/Event": { + "modified": "2020-10-15T21:38:36.713Z", + "contributors": [ + "fscholz", + "jackblackevo", + "Shiyou" + ] + }, + "Web/API/Event/bubbles": { + "modified": "2019-03-23T22:31:08.554Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Event/createEvent": { + "modified": "2019-03-23T22:46:58.596Z", + "contributors": [ + "Shiyou" + ] + }, + "Web/API/Event/currentTarget": { + "modified": "2020-10-15T21:47:11.367Z", + "contributors": [ + "iigmir", + "jackblackevo" + ] + }, + "Web/API/Event/defaultPrevented": { + "modified": "2019-03-23T22:31:01.738Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Event/eventPhase": { + "modified": "2019-03-23T22:31:04.871Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Event/isTrusted": { + "modified": "2019-03-23T22:31:07.261Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Event/preventDefault": { + "modified": "2019-03-23T22:31:19.138Z", + "contributors": [ + "SphinxKnight", + "peter611122", + "jackblackevo" + ] + }, + "Web/API/Event/stopImmediatePropagation": { + "modified": "2019-03-23T22:48:43.662Z", + "contributors": [ + "jackblackevo", + "alk03073135" + ] + }, + "Web/API/Event/stopPropagation": { + "modified": "2020-10-15T21:47:06.947Z", + "contributors": [ + "jackblackevo", + "iigmir" + ] + }, + "Web/API/Event/target": { + "modified": "2019-03-23T22:30:57.189Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Event/timeStamp": { + "modified": "2019-03-23T22:47:41.207Z", + "contributors": [ + "Shiyou" + ] + }, + "Web/API/Event/type": { + "modified": "2019-03-23T22:31:05.836Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/EventListener": { + "modified": "2020-10-15T21:47:11.807Z", + "contributors": [ + "t7yang", + "tigercosmos", + "jackblackevo" + ] + }, + "Web/API/EventTarget": { + "modified": "2019-03-23T22:55:39.329Z", + "contributors": [ + "jackblackevo", + "Shiyou", + "alk03073135", + "teoli" + ] + }, + "Web/API/EventTarget/dispatchEvent": { + "modified": "2019-03-23T22:48:01.449Z", + "contributors": [ + "jackblackevo", + "Shiyou" + ] + }, + "Web/API/EventTarget/removeEventListener": { + "modified": "2019-03-23T22:31:15.037Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Fetch_API": { + "modified": "2020-10-15T21:51:00.689Z", + "contributors": [ + "Zhusee", + "iigmir", + "guAnsunyata", + "jackblackevo" + ] + }, + "Web/API/Fetch_API/Using_Fetch": { + "modified": "2020-10-15T22:05:15.481Z", + "contributors": [ + "MollyHuang", + "JamesGoler", + "LeonClancy", + "cakeant", + "hms5232", + "Tamako", + "MOSapeizer" + ] + }, + "Web/API/File": { + "modified": "2020-10-15T21:47:08.052Z", + "contributors": [ + "pan93412", + "jackblackevo" + ] + }, + "Web/API/File/File": { + "modified": "2019-03-23T22:06:05.257Z", + "contributors": [ + "Freeeeze", + "lynn456" + ] + }, + "Web/API/File/Using_files_from_web_applications": { + "modified": "2019-03-24T00:11:30.210Z", + "contributors": [ + "chrisdavidmills", + "PtCt", + "y7t2ffff", + "Shiyou", + "alk03073135", + "irvinfly", + "Vdragon", + "orinx" + ] + }, + "Web/API/File/fileName": { + "modified": "2019-03-23T22:06:22.686Z", + "contributors": [ + "lynn456" + ] + }, + "Web/API/FileList": { + "modified": "2019-03-23T22:31:11.090Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/FileReader": { + "modified": "2019-03-23T22:31:25.177Z", + "contributors": [ + "jackblackevo", + "iigmir" + ] + }, + "Web/API/FileReader/error": { + "modified": "2019-03-23T22:06:18.177Z", + "contributors": [ + "lynn456" + ] + }, + "Web/API/FileReader/readyState": { + "modified": "2019-03-23T22:06:21.825Z", + "contributors": [ + "lynn456" + ] + }, + "Web/API/FileSystem": { + "modified": "2019-03-23T22:12:37.390Z", + "contributors": [ + "abc225666" + ] + }, + "Web/API/File_Handle_API": { + "modified": "2019-03-23T23:28:50.291Z", + "contributors": [ + "jackblackevo", + "MashKao" + ] + }, + "Web/API/FormData": { + "modified": "2019-03-23T23:35:14.599Z", + "contributors": [ + "lowtan", + "jackblackevo", + "teoli", + "Shiyou", + "ziyunfei" + ] + }, + "Web/API/FormData/Using_FormData_Objects": { + "modified": "2019-03-23T22:18:54.087Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/FormData/get": { + "modified": "2019-03-23T22:25:04.671Z", + "contributors": [ + "Snailpool" + ] + }, + "Web/API/Fullscreen_API": { + "modified": "2019-03-23T22:49:47.826Z", + "contributors": [ + "wbamberg", + "jackblackevo", + "lee011", + "alk03073135" + ] + }, + "Web/API/GainNode": { + "modified": "2019-03-23T22:20:28.411Z", + "contributors": [ + "stdio2017" + ] + }, + "Web/API/GainNode/gain": { + "modified": "2019-03-23T22:20:30.391Z", + "contributors": [ + "stdio2017" + ] + }, + "Web/API/Geolocation": { + "modified": "2019-03-23T22:36:12.802Z", + "contributors": [ + "yachiehwu", + "fscholz" + ] + }, + "Web/API/Geolocation/Using_geolocation": { + "modified": "2019-12-15T11:33:42.173Z", + "contributors": [ + "ayugioh2003", + "jackblackevo", + "MashKao" + ] + }, + "Web/API/Geolocation/clearWatch": { + "modified": "2019-03-23T22:36:15.036Z", + "contributors": [ + "yachiehwu" + ] + }, + "Web/API/Geolocation/getCurrentPosition": { + "modified": "2019-03-23T22:36:11.405Z", + "contributors": [ + "alphan_chen", + "yachiehwu" + ] + }, + "Web/API/Geolocation/watchPosition": { + "modified": "2019-03-23T22:36:17.405Z", + "contributors": [ + "yachiehwu" + ] + }, + "Web/API/GeolocationCoordinates": { + "modified": "2019-12-10T09:36:01.136Z", + "contributors": [ + "chrisdavidmills", + "yachiehwu", + "alphan_chen" + ] + }, + "Web/API/GeolocationCoordinates/accuracy": { + "modified": "2019-12-10T09:36:00.979Z", + "contributors": [ + "chrisdavidmills", + "yachiehwu" + ] + }, + "Web/API/GeolocationCoordinates/altitude": { + "modified": "2019-12-10T09:36:00.968Z", + "contributors": [ + "chrisdavidmills", + "yachiehwu" + ] + }, + "Web/API/GeolocationCoordinates/altitudeAccuracy": { + "modified": "2019-12-10T09:36:01.111Z", + "contributors": [ + "chrisdavidmills", + "yachiehwu" + ] + }, + "Web/API/GeolocationCoordinates/heading": { + "modified": "2019-12-10T09:36:01.669Z", + "contributors": [ + "chrisdavidmills", + "yachiehwu" + ] + }, + "Web/API/GeolocationCoordinates/latitude": { + "modified": "2019-12-10T09:36:01.243Z", + "contributors": [ + "chrisdavidmills", + "yachiehwu" + ] + }, + "Web/API/GeolocationCoordinates/longitude": { + "modified": "2019-12-10T09:36:01.384Z", + "contributors": [ + "chrisdavidmills", + "yachiehwu" + ] + }, + "Web/API/GeolocationCoordinates/speed": { + "modified": "2019-12-10T09:36:01.521Z", + "contributors": [ + "chrisdavidmills", + "yachiehwu" + ] + }, + "Web/API/GeolocationPosition": { + "modified": "2019-12-10T11:05:17.271Z", + "contributors": [ + "chrisdavidmills", + "alphan_chen", + "yachiehwu" + ] + }, + "Web/API/GeolocationPosition/coords": { + "modified": "2019-12-10T11:05:17.441Z", + "contributors": [ + "chrisdavidmills", + "alphan_chen", + "yachiehwu" + ] + }, + "Web/API/GeolocationPosition/timestamp": { + "modified": "2019-12-10T11:05:17.586Z", + "contributors": [ + "chrisdavidmills", + "alphan_chen", + "yachiehwu" + ] + }, + "Web/API/GeolocationPositionError": { + "modified": "2019-12-10T10:46:55.263Z", + "contributors": [ + "chrisdavidmills", + "alphan_chen", + "yachiehwu" + ] + }, + "Web/API/GeolocationPositionError/code": { + "modified": "2019-12-10T10:46:55.437Z", + "contributors": [ + "chrisdavidmills", + "alphan_chen", + "yachiehwu" + ] + }, + "Web/API/GeolocationPositionError/message": { + "modified": "2019-12-10T10:46:55.457Z", + "contributors": [ + "chrisdavidmills", + "alphan_chen", + "yachiehwu" + ] + }, + "Web/API/GlobalEventHandlers": { + "modified": "2019-03-23T22:31:11.882Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/GlobalEventHandlers/onclick": { + "modified": "2019-08-27T10:57:49.300Z", + "contributors": [ + "StanleyDing" + ] + }, + "Web/API/GlobalEventHandlers/onclose": { + "modified": "2019-03-23T22:13:45.424Z", + "contributors": [ + "StanleyDing" + ] + }, + "Web/API/HTMLCanvasElement": { + "modified": "2019-03-23T22:48:19.691Z", + "contributors": [ + "jackblackevo", + "alk03073135", + "teoli" + ] + }, + "Web/API/HTMLCanvasElement/toDataURL": { + "modified": "2019-03-23T22:48:22.609Z", + "contributors": [ + "Ethan", + "alk03073135" + ] + }, + "Web/API/HTMLCollection": { + "modified": "2019-03-23T22:30:38.649Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/HTMLDataElement": { + "modified": "2020-10-15T22:09:39.473Z", + "contributors": [ + "qwer5656" + ] + }, + "Web/API/HTMLDocument": { + "modified": "2019-03-23T22:30:43.077Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/HTMLElement": { + "modified": "2019-03-23T22:30:28.594Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/HTMLElement/click": { + "modified": "2019-03-23T22:19:07.322Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/HTMLElement/dataset": { + "modified": "2019-03-18T21:38:45.005Z", + "contributors": [ + "willynpi" + ] + }, + "Web/API/HTMLElement/lang": { + "modified": "2019-03-23T22:12:53.096Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/HTMLElement/style": { + "modified": "2019-03-23T22:20:07.015Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/HTMLFormElement": { + "modified": "2019-03-23T22:18:52.812Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/HTMLFormElement/submit_event": { + "modified": "2019-04-12T00:17:26.826Z", + "contributors": [ + "estelle", + "fscholz", + "Shiyou" + ] + }, + "Web/API/HTMLImageElement": { + "modified": "2019-03-23T22:18:52.559Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/HTMLInputElement": { + "modified": "2019-03-23T22:30:03.357Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/HTMLMediaElement": { + "modified": "2020-10-15T22:01:39.859Z", + "contributors": [ + "fscholz", + "jsgao0" + ] + }, + "Web/API/HTMLMediaElement/ratechange_event": { + "modified": "2019-03-18T20:49:27.842Z", + "contributors": [ + "estelle", + "EvenC" + ] + }, + "Web/API/HTMLMediaElement/readyState": { + "modified": "2020-10-15T22:07:42.605Z", + "contributors": [ + "NoobTW" + ] + }, + "Web/API/HTMLSelectElement": { + "modified": "2019-03-23T22:18:47.753Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/HTMLSelectElement/checkValidity": { + "modified": "2019-03-23T22:10:09.837Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/HTMLSelectElement/setCustomValidity": { + "modified": "2020-10-15T21:54:50.657Z", + "contributors": [ + "iigmir", + "jackblackevo" + ] + }, + "Web/API/HTML_Drag_and_Drop_API": { + "modified": "2019-03-23T23:10:47.648Z", + "contributors": [ + "ayhaadam", + "iigmir", + "jackblackevo", + "teoli", + "foxbrush" + ] + }, + "Web/API/HTML_Drag_and_Drop_API/Drag_operations": { + "modified": "2019-03-23T23:10:36.835Z", + "contributors": [ + "oooooo", + "jackblackevo", + "foxbrush" + ] + }, + "Web/API/History": { + "modified": "2019-03-23T22:06:32.333Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/History_API": { + "modified": "2019-05-23T03:21:29.855Z", + "contributors": [ + "SphinxKnight", + "KatsuragiCSL", + "jackblackevo", + "changbenny", + "rexct", + "irvinfly", + "Klern", + "Sheppy", + "ChiLiJung" + ] + }, + "Web/API/IDBDatabase": { + "modified": "2019-03-23T22:39:46.666Z", + "contributors": [ + "ALiangLiang" + ] + }, + "Web/API/IndexedDB_API": { + "modified": "2019-03-23T23:34:48.559Z", + "contributors": [ + "wbamberg", + "jackblackevo", + "foxbrush", + "MashKao", + "ethertank", + "princetoad@gmail.com" + ] + }, + "Web/API/IndexedDB_API/Basic_Concepts_Behind_IndexedDB": { + "modified": "2019-03-18T20:39:41.131Z", + "contributors": [ + "choznerol", + "jackblackevo", + "birdca", + "foxbrush", + "thomaschen" + ] + }, + "Web/API/IndexedDB_API/Using_IndexedDB": { + "modified": "2019-06-26T04:56:24.502Z", + "contributors": [ + "jackblackevo", + "foxbrush" + ] + }, + "Web/API/KeyboardEvent": { + "modified": "2019-03-18T21:09:08.334Z", + "contributors": [ + "fscholz", + "wbamberg", + "Shiyou" + ] + }, + "Web/API/KeyboardEvent/KeyboardEvent": { + "modified": "2019-03-23T22:47:21.168Z", + "contributors": [ + "Shiyou" + ] + }, + "Web/API/MediaQueryList": { + "modified": "2019-03-23T22:56:00.808Z", + "contributors": [ + "foxbrush" + ] + }, + "Web/API/MediaSource": { + "modified": "2020-10-15T21:52:20.197Z", + "contributors": [ + "aChinKaiWu" + ] + }, + "Web/API/MediaSource/MediaSource": { + "modified": "2019-03-23T22:17:49.071Z", + "contributors": [ + "aChinKaiWu" + ] + }, + "Web/API/MediaSource/activeSourceBuffers": { + "modified": "2019-03-23T22:17:50.588Z", + "contributors": [ + "aChinKaiWu" + ] + }, + "Web/API/MediaSource/duration": { + "modified": "2019-03-23T22:17:52.088Z", + "contributors": [ + "aChinKaiWu" + ] + }, + "Web/API/MediaSource/readyState": { + "modified": "2019-03-23T22:17:05.691Z", + "contributors": [ + "aChinKaiWu" + ] + }, + "Web/API/Media_Streams_API": { + "modified": "2020-11-05T04:25:49.611Z", + "contributors": [ + "SphinxKnight", + "yckevin1130" + ] + }, + "Web/API/MouseEvent": { + "modified": "2019-03-23T22:19:36.683Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/MutationObserver": { + "modified": "2019-03-23T22:39:23.098Z", + "contributors": [ + "Petingo", + "ALiangLiang" + ] + }, + "Web/API/NamedNodeMap": { + "modified": "2019-03-23T22:30:37.384Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Navigator": { + "modified": "2019-03-23T22:36:11.927Z", + "contributors": [ + "iigmir", + "jackblackevo", + "teoli" + ] + }, + "Web/API/Navigator/geolocation": { + "modified": "2019-03-23T22:36:10.122Z", + "contributors": [ + "yachiehwu", + "alphan_chen" + ] + }, + "Web/API/Navigator/registerProtocolHandler": { + "modified": "2019-03-23T22:01:47.891Z", + "contributors": [ + "chrisdavidmills" + ] + }, + "Web/API/Navigator/registerProtocolHandler/Web-based_protocol_handlers": { + "modified": "2019-03-23T23:51:06.175Z", + "contributors": [ + "chrisdavidmills", + "teoli", + "Coolcd" + ] + }, + "Web/API/NavigatorOnLine": { + "modified": "2019-03-23T22:02:07.853Z", + "contributors": [ + "chrisdavidmills" + ] + }, + "Web/API/NavigatorOnLine/Online_and_offline_events": { + "modified": "2019-03-23T23:51:04.713Z", + "contributors": [ + "chrisdavidmills", + "teoli", + "Coolcd" + ] + }, + "Web/API/Network_Information_API": { + "modified": "2019-03-23T23:26:00.923Z", + "contributors": [ + "jackblackevo", + "MashKao" + ] + }, + "Web/API/Node": { + "modified": "2019-03-23T22:31:01.035Z", + "contributors": [ + "jackblackevo", + "Sebastianz" + ] + }, + "Web/API/Node/childNodes": { + "modified": "2019-03-23T22:12:04.783Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Node/cloneNode": { + "modified": "2019-03-23T22:18:53.920Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Node/innerText": { + "modified": "2019-03-23T22:12:44.697Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Node/insertBefore": { + "modified": "2020-10-15T22:10:04.295Z", + "contributors": [ + "willynpi" + ] + }, + "Web/API/Node/nodeName": { + "modified": "2019-03-23T22:12:43.285Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Node/nodeType": { + "modified": "2019-03-23T22:30:58.367Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Node/ownerDocument": { + "modified": "2019-03-23T22:30:38.954Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Node/removeChild": { + "modified": "2020-10-15T22:20:11.215Z", + "contributors": [ + "ginszme", + "lebniz" + ] + }, + "Web/API/Node/textContent": { + "modified": "2019-03-23T22:30:14.613Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/NodeList": { + "modified": "2019-03-23T22:30:29.129Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/NonDocumentTypeChildNode": { + "modified": "2019-03-23T22:30:38.352Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Notifications_API": { + "modified": "2020-04-21T06:01:14.944Z", + "contributors": [ + "kinlish", + "jackblackevo" + ] + }, + "Web/API/Notifications_API/Using_the_Notifications_API": { + "modified": "2019-03-23T23:25:54.456Z", + "contributors": [ + "SiderealArt", + "jackblackevo", + "MashKao" + ] + }, + "Web/API/ParentNode": { + "modified": "2019-12-24T08:07:24.128Z", + "contributors": [ + "ianchen0119", + "jackblackevo" + ] + }, + "Web/API/ParentNode/children": { + "modified": "2019-03-23T22:12:04.488Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/ParentNode/firstElementChild": { + "modified": "2020-10-15T22:25:38.862Z", + "contributors": [ + "ianchen0119" + ] + }, + "Web/API/PaymentRequest": { + "modified": "2020-10-15T22:13:15.817Z", + "contributors": [ + "iigmir" + ] + }, + "Web/API/Payment_Request_API": { + "modified": "2020-10-15T22:17:10.641Z", + "contributors": [ + "iigmir" + ] + }, + "Web/API/Performance": { + "modified": "2020-10-15T22:10:19.285Z", + "contributors": [ + "fscholz", + "jasonslyvia" + ] + }, + "Web/API/Performance.timing": { + "modified": "2020-10-15T21:29:18.100Z", + "contributors": [ + "fscholz", + "BobChao" + ] + }, + "Web/API/Pointer_Lock_API": { + "modified": "2019-03-23T23:21:42.932Z", + "contributors": [ + "fscholz", + "jackblackevo", + "MashKao" + ] + }, + "Web/API/PositionOptions": { + "modified": "2019-03-23T22:36:10.505Z", + "contributors": [ + "alphan_chen", + "yachiehwu" + ] + }, + "Web/API/PositionOptions/enableHighAccuracy": { + "modified": "2019-03-23T22:36:14.585Z", + "contributors": [ + "alphan_chen", + "yachiehwu" + ] + }, + "Web/API/PositionOptions/maximumAge": { + "modified": "2019-03-23T22:36:18.389Z", + "contributors": [ + "alphan_chen", + "yachiehwu" + ] + }, + "Web/API/PositionOptions/timeout": { + "modified": "2019-03-23T22:36:20.985Z", + "contributors": [ + "alphan_chen", + "yachiehwu" + ] + }, + "Web/API/ProgressEvent": { + "modified": "2019-03-23T22:23:49.095Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Proximity_Events": { + "modified": "2019-03-23T23:26:18.756Z", + "contributors": [ + "jackblackevo", + "teoli", + "MashKao" + ] + }, + "Web/API/Range": { + "modified": "2019-03-23T22:11:39.715Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Response": { + "modified": "2020-10-15T22:20:33.291Z", + "contributors": [ + "Snailpool" + ] + }, + "Web/API/Screen": { + "modified": "2019-03-23T22:19:37.677Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Screen/orientation": { + "modified": "2019-03-23T22:19:12.880Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Server-sent_events": { + "modified": "2019-03-23T22:48:59.519Z", + "contributors": [ + "alk03073135" + ] + }, + "Web/API/Server-sent_events/Using_server-sent_events": { + "modified": "2020-10-15T21:38:16.488Z", + "contributors": [ + "t7yang", + "Shiyou", + "alk03073135" + ] + }, + "Web/API/Storage": { + "modified": "2020-10-15T22:18:31.680Z", + "contributors": [ + "Snailpool" + ] + }, + "Web/API/Touch": { + "modified": "2019-03-23T22:19:42.184Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/TouchEvent": { + "modified": "2019-03-23T22:19:43.288Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/TouchList": { + "modified": "2019-03-23T22:19:16.026Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Touch_events": { + "modified": "2019-03-23T22:19:45.724Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/UIEvent": { + "modified": "2019-03-23T22:47:07.957Z", + "contributors": [ + "jackblackevo", + "Shiyou" + ] + }, + "Web/API/UIEvent/UIEvent": { + "modified": "2019-03-23T22:47:00.620Z", + "contributors": [ + "Shiyou" + ] + }, + "Web/API/URL": { + "modified": "2019-03-23T22:45:27.784Z", + "contributors": [ + "jackblackevo", + "Sebastianz" + ] + }, + "Web/API/URL/createObjectURL": { + "modified": "2019-03-23T22:45:24.757Z", + "contributors": [ + "mike-su" + ] + }, + "Web/API/ValidityState": { + "modified": "2019-03-23T22:10:00.790Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Vibration_API": { + "modified": "2019-03-23T23:26:11.215Z", + "contributors": [ + "jackblackevo", + "MashKao" + ] + }, + "Web/API/WebGL_API": { + "modified": "2019-03-23T23:05:10.310Z", + "contributors": [ + "oberonfrog", + "JamsYC.Huang", + "fscholz", + "bassam", + "wildsky" + ] + }, + "Web/API/WebGL_API/Tutorial": { + "modified": "2019-03-23T22:28:04.854Z", + "contributors": [ + "oberonfrog", + "leannechen", + "fscholz" + ] + }, + "Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context": { + "modified": "2019-03-23T22:05:33.181Z", + "contributors": [ + "oberonfrog" + ] + }, + "Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL": { + "modified": "2019-03-23T22:05:08.179Z", + "contributors": [ + "oberonfrog" + ] + }, + "Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL": { + "modified": "2019-03-23T22:28:11.788Z", + "contributors": [ + "Milkker", + "jackblackevo", + "mmis1000", + "oberonfrog", + "iamlockon" + ] + }, + "Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL": { + "modified": "2019-03-23T22:05:32.507Z", + "contributors": [ + "oberonfrog" + ] + }, + "Web/API/WebRTC_API": { + "modified": "2020-03-24T21:28:22.800Z", + "contributors": [ + "LeonH", + "VirtualDruid", + "jackblackevo" + ] + }, + "Web/API/WebVR_API": { + "modified": "2019-03-23T22:05:10.343Z", + "contributors": [ + "oberonfrog" + ] + }, + "Web/API/Web_Audio_API": { + "modified": "2019-04-23T04:18:05.778Z", + "contributors": [ + "jackblackevo", + "MashKao" + ] + }, + "Web/API/Web_Video_Text_Tracks_Format": { + "modified": "2019-03-23T23:11:00.411Z", + "contributors": [ + "wbamberg", + "BobChao" + ] + }, + "Web/API/Web_Workers_API": { + "modified": "2019-03-23T22:31:22.820Z", + "contributors": [ + "teoli" + ] + }, + "Web/API/Web_Workers_API/Using_web_workers": { + "modified": "2019-03-23T23:27:47.429Z", + "contributors": [ + "t7yang", + "teoli", + "jackblackevo", + "foxbrush", + "walkingice" + ] + }, + "Web/API/WheelEvent": { + "modified": "2019-03-18T21:36:10.655Z", + "contributors": [ + "Zhang-Junzhi" + ] + }, + "Web/API/Window": { + "modified": "2019-03-23T22:30:42.242Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Window.history": { + "modified": "2019-03-23T23:27:30.087Z", + "contributors": [ + "jackblackevo", + "jsx", + "ChiLiJung" + ] + }, + "Web/API/Window.onpopstate": { + "modified": "2019-03-23T23:27:28.070Z", + "contributors": [ + "irvinfly", + "khalid32", + "ChiLiJung" + ] + }, + "Web/API/Window.requestAnimationFrame": { + "modified": "2020-10-15T21:24:54.235Z", + "contributors": [ + "t7yang", + "Ekanan", + "North", + "foxbrush" + ] + }, + "Web/API/Window/getComputedStyle": { + "modified": "2019-03-23T22:10:08.484Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Window/localStorage": { + "modified": "2020-10-15T22:24:50.356Z", + "contributors": [ + "chrischi0922s", + "alkalineW" + ] + }, + "Web/API/Window/location": { + "modified": "2019-04-23T03:35:06.433Z", + "contributors": [ + "jackblackevo", + "khalid32", + "appleboy" + ] + }, + "Web/API/Window/navigator": { + "modified": "2019-07-25T17:42:57.501Z", + "contributors": [ + "lixingnan200", + "jackblackevo" + ] + }, + "Web/API/Window/opener": { + "modified": "2019-03-23T22:06:26.845Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/Window/orientationchange_event": { + "modified": "2020-10-15T22:05:03.774Z", + "contributors": [ + "jackblackevo", + "fscholz", + "BwayCer" + ] + }, + "Web/API/Window/print": { + "modified": "2019-03-18T21:45:25.421Z", + "contributors": [ + "laneser" + ] + }, + "Web/API/Window/requestIdleCallback": { + "modified": "2019-03-23T22:08:40.506Z", + "contributors": [ + "zonr" + ] + }, + "Web/API/Window/sessionStorage": { + "modified": "2020-10-15T21:58:23.409Z", + "contributors": [ + "iigmir", + "EyiLee", + "EricPing" + ] + }, + "Web/API/Window/sidebar": { + "modified": "2019-03-23T22:03:03.633Z", + "contributors": [ + "IsaacSchemm" + ] + }, + "Web/API/Window/sidebar/Adding_search_engines_from_Web_pages": { + "modified": "2019-01-16T15:28:04.055Z", + "contributors": [ + "jackblackevo", + "Mgjbot", + "BobChao" + ] + }, + "Web/API/WindowBase64": { + "modified": "2019-03-23T22:30:45.308Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/WindowEventHandlers": { + "modified": "2019-03-23T22:30:52.273Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/WindowEventHandlers/onbeforeunload": { + "modified": "2019-03-23T22:27:46.116Z", + "contributors": [ + "hstarorg" + ] + }, + "Web/API/WindowOrWorkerGlobalScope": { + "modified": "2020-10-15T22:29:08.795Z", + "contributors": [ + "mfuji09" + ] + }, + "Web/API/WindowOrWorkerGlobalScope/btoa": { + "modified": "2020-10-15T22:35:15.820Z", + "contributors": [ + "evo938evo938" + ] + }, + "Web/API/WindowOrWorkerGlobalScope/setInterval": { + "modified": "2020-10-15T22:29:07.467Z", + "contributors": [ + "chrischi0922s" + ] + }, + "Web/API/WindowTimers": { + "modified": "2019-03-18T21:16:54.761Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/XMLHttpRequest": { + "modified": "2020-10-15T21:21:13.079Z", + "contributors": [ + "ginszme", + "fscholz", + "willynpi", + "jackblackevo", + "teoli", + "foxbrush", + "natevw" + ] + }, + "Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests": { + "modified": "2019-03-23T22:55:39.839Z", + "contributors": [ + "blackbingo", + "teoli", + "alk03073135" + ] + }, + "Web/API/XMLHttpRequest/Using_XMLHttpRequest": { + "modified": "2019-03-23T23:25:28.545Z", + "contributors": [ + "jackblackevo", + "teoli", + "foxbrush" + ] + }, + "Web/API/XMLHttpRequest/XMLHttpRequest": { + "modified": "2020-04-01T05:25:46.906Z", + "contributors": [ + "ginszme" + ] + }, + "Web/API/XMLHttpRequest/onreadystatechange": { + "modified": "2019-03-23T22:16:06.897Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/XMLHttpRequest/readyState": { + "modified": "2019-03-23T22:16:03.865Z", + "contributors": [ + "jWorker", + "jackblackevo", + "ginszme" + ] + }, + "Web/API/XMLHttpRequest/setRequestHeader": { + "modified": "2020-10-15T22:28:44.084Z", + "contributors": [ + "ginszme" + ] + }, + "Web/API/XMLHttpRequest/status": { + "modified": "2019-03-23T22:12:50.172Z", + "contributors": [ + "ginszme" + ] + }, + "Web/API/XMLHttpRequest/withCredentials": { + "modified": "2020-10-15T22:17:19.013Z", + "contributors": [ + "willh" + ] + }, + "Web/API/XMLHttpRequestEventTarget": { + "modified": "2019-03-23T22:12:26.382Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/API/console/assert": { + "modified": "2020-10-15T22:03:27.482Z", + "contributors": [ + "lin826", + "iigmir" + ] + }, + "Web/API/document.createTreeWalker": { + "modified": "2019-03-23T23:14:12.386Z", + "contributors": [ + "jsx", + "shyangs" + ] + }, + "Web/API/notification": { + "modified": "2020-04-21T05:58:29.795Z", + "contributors": [ + "kinlish", + "bros0215", + "SphinxKnight", + "Shiyou" + ] + }, + "Web/Accessibility": { + "modified": "2019-09-11T08:39:45.699Z", + "contributors": [ + "SphinxKnight", + "iigmir", + "boa0332" + ] + }, + "Web/Accessibility/ARIA": { + "modified": "2019-03-23T22:50:56.989Z", + "contributors": [ + "teoli" + ] + }, + "Web/Accessibility/ARIA/ARIA_Techniques": { + "modified": "2019-03-18T21:39:54.388Z", + "contributors": [ + "oooooo" + ] + }, + "Web/Accessibility/ARIA/forms": { + "modified": "2019-06-27T12:10:30.271Z", + "contributors": [ + "FredericChang", + "Sheppy" + ] + }, + "Web/Accessibility/ARIA/forms/Basic_form_hints": { + "modified": "2019-03-23T22:50:58.911Z", + "contributors": [ + "PatrickTaiwan", + "Shiyou", + "alk03073135" + ] + }, + "Web/Accessibility/Mobile_accessibility_checklist": { + "modified": "2019-03-18T21:32:14.782Z", + "contributors": [ + "li-liam" + ] + }, + "Web/CSS": { + "modified": "2019-09-11T03:42:04.510Z", + "contributors": [ + "SphinxKnight", + "jjyaung", + "xuan0123", + "jackblackevo", + "iigmir", + "flyinglimao", + "thomasaria", + "irvinfly", + "teoli", + "ethertank", + "sailplaneTW", + "Mgjbot", + "BobChao" + ] + }, + "Web/CSS/::first-letter": { + "modified": "2019-03-23T22:31:14.643Z", + "contributors": [ + "iigmir" + ] + }, + "Web/CSS/:first-child": { + "modified": "2019-03-23T22:28:52.270Z", + "contributors": [ + "mgrn" + ] + }, + "Web/CSS/:first-of-type": { + "modified": "2019-03-23T22:10:08.926Z", + "contributors": [ + "nyngwang" + ] + }, + "Web/CSS/:lang": { + "modified": "2020-10-15T22:13:50.122Z", + "contributors": [ + "oooooo" + ] + }, + "Web/CSS/:target": { + "modified": "2019-03-23T22:49:40.294Z", + "contributors": [ + "alk03073135" + ] + }, + "Web/CSS/@font-face": { + "modified": "2019-03-23T23:28:16.382Z", + "contributors": [ + "fscholz", + "teoli", + "carl_tw" + ] + }, + "Web/CSS/@media": { + "modified": "2019-03-23T22:21:19.252Z", + "contributors": [ + "iigmir", + "xim" + ] + }, + "Web/CSS/@media/height": { + "modified": "2019-03-23T22:21:21.278Z", + "contributors": [ + "MashKao", + "yvonne6344" + ] + }, + "Web/CSS/@viewport": { + "modified": "2019-03-18T21:16:53.558Z", + "contributors": [ + "cvrebert" + ] + }, + "Web/CSS/@viewport/height": { + "modified": "2019-10-22T02:02:49.952Z", + "contributors": [ + "Zhang-Junzhi", + "yvonne6344" + ] + }, + "Web/CSS/CSS_Animations": { + "modified": "2019-03-23T22:43:48.571Z", + "contributors": [ + "teoli" + ] + }, + "Web/CSS/CSS_Animations/Using_CSS_animations": { + "modified": "2019-03-24T00:13:58.706Z", + "contributors": [ + "SphinxKnight", + "teoli", + "ethertank", + "sailplaneTW" + ] + }, + "Web/CSS/CSS_Background_and_Borders": { + "modified": "2019-03-23T22:44:17.591Z", + "contributors": [ + "teoli" + ] + }, + "Web/CSS/CSS_Background_and_Borders/Using_CSS_multiple_backgrounds": { + "modified": "2019-03-23T22:48:53.708Z", + "contributors": [ + "sss63232", + "Shiyou", + "teoli", + "alk03073135" + ] + }, + "Web/CSS/CSS_Box_Model": { + "modified": "2019-03-23T22:24:07.076Z", + "contributors": [ + "Sebastianz" + ] + }, + "Web/CSS/CSS_Box_Model/Mastering_margin_collapsing": { + "modified": "2020-08-17T06:43:18.638Z", + "contributors": [ + "osk2", + "lilychen1388", + "jackblackevo", + "MOSapeizer" + ] + }, + "Web/CSS/CSS_Colors": { + "modified": "2019-03-23T22:44:44.114Z", + "contributors": [ + "Sebastianz", + "teoli" + ] + }, + "Web/CSS/CSS_Colors/Color_picker_tool": { + "modified": "2019-03-23T22:44:42.147Z", + "contributors": [ + "Shiyou", + "alk03073135" + ] + }, + "Web/CSS/CSS_Flexible_Box_Layout": { + "modified": "2020-07-30T05:18:51.473Z", + "contributors": [ + "klareh", + "iigmir", + "1986slayer", + "WynnChen" + ] + }, + "Web/CSS/CSS_Flexible_Box_Layout/Using_CSS_flexible_boxes": { + "modified": "2020-05-11T23:59:37.780Z", + "contributors": [ + "wildsky", + "iigmir", + "1986slayer" + ] + }, + "Web/CSS/CSS_Grid_Layout": { + "modified": "2020-02-01T05:41:13.615Z", + "contributors": [ + "SvampK", + "iigmir", + "1986slayer", + "jackblackevo" + ] + }, + "Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout": { + "modified": "2019-10-24T13:10:33.813Z", + "contributors": [ + "akccakcctw", + "iigmir", + "1986slayer" + ] + }, + "Web/CSS/CSS_Lists_and_Counters": { + "modified": "2019-03-23T22:18:52.970Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/CSS/CSS_Lists_and_Counters/Consistent_list_indentation": { + "modified": "2019-03-24T00:14:02.326Z", + "contributors": [ + "jackblackevo", + "ethertank", + "sailplaneTW" + ] + }, + "Web/CSS/CSS_Positioning": { + "modified": "2019-03-23T22:18:48.097Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/CSS/CSS_Positioning/Understanding_z_index": { + "modified": "2019-03-23T22:55:06.815Z", + "contributors": [ + "jackblackevo", + "Jeremie" + ] + }, + "Web/CSS/CSS_Positioning/Understanding_z_index/Stacking_context_example_1": { + "modified": "2019-03-23T22:55:03.379Z", + "contributors": [ + "jackblackevo", + "h140100" + ] + }, + "Web/CSS/CSS_Properties_Reference": { + "modified": "2020-10-21T10:34:59.711Z", + "contributors": [ + "SvampK", + "jackblackevo" + ] + }, + "Web/CSS/CSS_Selectors": { + "modified": "2020-10-24T16:00:38.628Z", + "contributors": [ + "NekoChan-2851", + "weichengcing", + "BobChao", + "noih", + "jsgao0", + "jackblackevo" + ] + }, + "Web/CSS/CSS_Selectors/Using_the_:target_pseudo-class_in_selectors": { + "modified": "2019-03-23T22:49:42.209Z", + "contributors": [ + "jackblackevo", + "alk03073135" + ] + }, + "Web/CSS/CSS_Transitions": { + "modified": "2019-03-23T22:18:48.267Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/CSS/CSS_Transitions/Using_CSS_transitions": { + "modified": "2019-03-24T00:14:17.322Z", + "contributors": [ + "jackblackevo", + "elin", + "ethertank", + "sailplaneTW" + ] + }, + "Web/CSS/Common_CSS_Questions": { + "modified": "2020-07-16T22:25:46.290Z", + "contributors": [ + "fscholz", + "teoli", + "Mgjbot", + "BobChao" + ] + }, + "Web/CSS/Descendant_combinator": { + "modified": "2019-03-23T22:47:36.182Z", + "contributors": [ + "ExE-Boss", + "changbenny" + ] + }, + "Web/CSS/Media_Queries": { + "modified": "2019-03-23T22:18:53.365Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/CSS/Media_Queries/Testing_media_queries": { + "modified": "2019-03-23T22:55:57.771Z", + "contributors": [ + "jackblackevo", + "foxbrush" + ] + }, + "Web/CSS/Pseudo-classes": { + "modified": "2019-03-23T22:25:22.712Z", + "contributors": [ + "iigmir" + ] + }, + "Web/CSS/Reference": { + "modified": "2019-03-23T22:00:54.291Z", + "contributors": [ + "jackblackevo", + "pigmu" + ] + }, + "Web/CSS/Replaced_element": { + "modified": "2019-03-23T22:59:51.482Z", + "contributors": [ + "MashKao" + ] + }, + "Web/CSS/Shorthand_properties": { + "modified": "2019-03-23T23:05:17.353Z", + "contributors": [ + "fscholz", + "irvinfly", + "wildsky" + ] + }, + "Web/CSS/Syntax": { + "modified": "2020-06-01T00:28:11.978Z", + "contributors": [ + "bensontobeicsc", + "jackblackevo", + "xuan0123" + ] + }, + "Web/CSS/Type_selectors": { + "modified": "2020-10-15T22:16:41.850Z", + "contributors": [ + "a1178961372", + "YvonneYu" + ] + }, + "Web/CSS/animation-fill-mode": { + "modified": "2019-03-18T21:42:33.553Z", + "contributors": [ + "yoonasy" + ] + }, + "Web/CSS/attr()": { + "modified": "2020-11-04T08:52:16.034Z", + "contributors": [ + "chrisdavidmills", + "DevinKWu", + "SphinxKnight", + "iigmir", + "mrstork", + "prayash", + "andyyou" + ] + }, + "Web/CSS/background-attachment": { + "modified": "2020-10-15T22:23:27.829Z", + "contributors": [ + "ayugioh2003" + ] + }, + "Web/CSS/background-color": { + "modified": "2020-10-15T21:39:17.646Z", + "contributors": [ + "SphinxKnight", + "s10750257", + "Sebastianz", + "Shiyou" + ] + }, + "Web/CSS/border": { + "modified": "2020-10-15T22:17:53.607Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/CSS/border-image": { + "modified": "2019-03-24T00:08:26.325Z", + "contributors": [ + "wbamberg", + "teoli", + "Kennyluck" + ] + }, + "Web/CSS/border-image/border-image": { + "modified": "2019-03-24T00:08:11.061Z", + "contributors": [ + "mrstork", + "teoli", + "Kennyluck" + ] + }, + "Web/CSS/box-shadow": { + "modified": "2020-09-11T09:09:21.899Z", + "contributors": [ + "slivenred", + "jackblackevo", + "DoJQuadArts", + "Sebastianz", + "alk03073135" + ] + }, + "Web/CSS/box-sizing": { + "modified": "2020-10-15T21:47:19.062Z", + "contributors": [ + "chih-hsi-chen", + "yungshenglu", + "SJW", + "PJCHENder", + "iigmir", + "fscholz", + "jwhitlock", + "YuCheng" + ] + }, + "Web/CSS/clip": { + "modified": "2019-03-23T22:33:08.119Z", + "contributors": [ + "Jerry-Hong" + ] + }, + "Web/CSS/cursor": { + "modified": "2020-10-15T22:07:15.106Z", + "contributors": [ + "it4u" + ] + }, + "Web/CSS/grid-row": { + "modified": "2020-10-15T21:53:10.432Z", + "contributors": [ + "fscholz", + "1986slayer" + ] + }, + "Web/CSS/grid-template": { + "modified": "2020-10-15T22:30:52.332Z", + "contributors": [ + "blueanger31" + ] + }, + "Web/CSS/grid-template-columns": { + "modified": "2020-10-15T21:53:17.222Z", + "contributors": [ + "fscholz", + "1986slayer" + ] + }, + "Web/CSS/height": { + "modified": "2019-03-23T22:21:15.320Z", + "contributors": [ + "yvonne6344" + ] + }, + "Web/CSS/ime-mode": { + "modified": "2019-01-16T15:28:05.312Z", + "contributors": [ + "teoli", + "Mgjbot", + "BobChao" + ] + }, + "Web/CSS/inheritance": { + "modified": "2019-03-23T22:48:52.230Z", + "contributors": [ + "jackblackevo", + "alk03073135" + ] + }, + "Web/CSS/line-break": { + "modified": "2020-10-15T22:24:02.776Z", + "contributors": [ + "jsgao0" + ] + }, + "Web/CSS/object-fit": { + "modified": "2019-03-23T22:27:58.659Z", + "contributors": [ + "gn00979905" + ] + }, + "Web/CSS/radial-gradient()": { + "modified": "2020-11-18T14:43:15.827Z", + "contributors": [ + "chrisdavidmills", + "linzging" + ] + }, + "Web/CSS/ruby-position": { + "modified": "2020-10-15T21:51:03.131Z", + "contributors": [ + "iigmir" + ] + }, + "Web/CSS/transform": { + "modified": "2020-10-15T21:38:21.566Z", + "contributors": [ + "allchangechallenge", + "jackblackevo", + "Sebastianz", + "CarterTsai", + "SphinxKnight", + "fscholz", + "alk03073135" + ] + }, + "Web/CSS/transform-function": { + "modified": "2019-03-23T22:49:34.155Z", + "contributors": [ + "mrstork", + "prayash", + "alk03073135" + ] + }, + "Web/CSS/transform-function/translate3d()": { + "modified": "2020-11-30T13:00:00.920Z", + "contributors": [ + "chrisdavidmills", + "iigmir" + ] + }, + "Web/CSS/transform-origin": { + "modified": "2020-10-15T22:05:18.550Z", + "contributors": [ + "willynpi" + ] + }, + "Web/CSS/transition": { + "modified": "2020-10-15T22:08:09.027Z", + "contributors": [ + "willynpi" + ] + }, + "Web/CSS/transition-duration": { + "modified": "2020-10-15T22:08:04.691Z", + "contributors": [ + "willynpi" + ] + }, + "Web/CSS/transition-timing-function": { + "modified": "2020-10-15T22:02:01.243Z", + "contributors": [ + "flyinglimao" + ] + }, + "Web/CSS/white-space": { + "modified": "2019-03-23T22:06:04.997Z", + "contributors": [ + "ymcheung", + "leannechen" + ] + }, + "Web/CSS/width": { + "modified": "2020-10-15T22:01:32.599Z", + "contributors": [ + "yutzuch" + ] + }, + "Web/Demos_of_open_web_technologies": { + "modified": "2019-03-23T22:08:13.863Z", + "contributors": [ + "h223449961", + "tigercosmos" + ] + }, + "Web/Events": { + "modified": "2019-11-28T04:54:28.795Z", + "contributors": [ + "t7yang", + "fadeawaygod", + "wbamberg", + "Septem", + "fscholz", + "jackblackevo", + "Shiyou", + "ethertank", + "louisremi" + ] + }, + "Web/Events/DOMContentLoaded": { + "modified": "2019-04-30T13:56:21.954Z", + "contributors": [ + "wbamberg", + "fscholz", + "NoctisHsu", + "jackblackevo", + "ethertank", + "CarterTsai" + ] + }, + "Web/Events/abort": { + "modified": "2019-04-30T14:18:03.298Z", + "contributors": [ + "wbamberg", + "secminhr" + ] + }, + "Web/Events/load": { + "modified": "2019-03-23T22:18:11.736Z", + "contributors": [ + "fscholz", + "Snailpool" + ] + }, + "Web/Guide": { + "modified": "2019-03-23T23:29:55.855Z", + "contributors": [ + "Rocker", + "jackblackevo", + "alk03073135", + "ethertank", + "Sheppy" + ] + }, + "Web/Guide/AJAX": { + "modified": "2019-03-24T00:02:43.850Z", + "contributors": [ + "circlepen", + "drinktea28", + "jackblackevo", + "chrisdavidmills", + "ethertank", + "fscholz", + "happysadman", + "Mgjbot", + "kourge", + "BobChao" + ] + }, + "Web/Guide/AJAX/Getting_Started": { + "modified": "2020-08-21T06:49:10.440Z", + "contributors": [ + "timjtchang", + "jackblackevo", + "chrisdavidmills", + "luxun", + "happysadman", + "Cpthk", + "Mgjbot", + "BobChao" + ] + }, + "Web/Guide/API": { + "modified": "2019-09-11T09:35:56.658Z", + "contributors": [ + "SphinxKnight", + "shing0608" + ] + }, + "Web/Guide/DOM": { + "modified": "2019-03-23T23:29:56.158Z", + "contributors": [ + "Sheppy" + ] + }, + "Web/Guide/Events": { + "modified": "2019-03-23T22:48:03.662Z", + "contributors": [ + "jackblackevo", + "gportioli" + ] + }, + "Web/Guide/Events/Creating_and_triggering_events": { + "modified": "2019-03-23T22:48:01.128Z", + "contributors": [ + "jackblackevo", + "Shiyou" + ] + }, + "Web/Guide/Events/Event_handlers": { + "modified": "2020-05-13T00:05:39.122Z", + "contributors": [ + "ginszme", + "jackblackevo" + ] + }, + "Web/Guide/Graphics": { + "modified": "2019-04-23T04:21:07.806Z", + "contributors": [ + "jackblackevo", + "pytseng" + ] + }, + "Web/Guide/HTML/Content_categories": { + "modified": "2019-03-23T22:28:17.896Z", + "contributors": [ + "iigmir" + ] + }, + "Web/Guide/HTML/Event_attributes": { + "modified": "2019-11-20T21:38:26.184Z", + "contributors": [ + "wbamberg", + "jackblackevo" + ] + }, + "Web/Guide/HTML/HTML5": { + "modified": "2019-03-24T00:15:00.017Z", + "contributors": [ + "jackblackevo", + "Shiyou", + "teoli", + "alk03073135", + "wildsky", + "sailplaneTW", + "vigia122", + "Kennyluck", + "Dwchiang" + ] + }, + "Web/Guide/HTML/HTML5/Introduction_to_HTML5": { + "modified": "2019-03-23T22:57:07.502Z", + "contributors": [ + "jackblackevo", + "kwanjaiOP" + ] + }, + "Web/Guide/Introduction_to_Web_development": { + "modified": "2019-04-23T03:25:16.725Z", + "contributors": [ + "jackblackevo", + "khhyoshida", + "happysadman" + ] + }, + "Web/Guide/Performance": { + "modified": "2019-03-23T23:28:07.518Z", + "contributors": [ + "Sheppy" + ] + }, + "Web/Guide/WOFF": { + "modified": "2019-03-23T23:28:22.570Z", + "contributors": [ + "fscholz", + "carl_tw" + ] + }, + "Web/Guide/Writing_forward-compatible_websites": { + "modified": "2019-03-24T00:17:14.604Z", + "contributors": [ + "fscholz", + "irvinfly", + "Littlebtc", + "Sonrisa", + "sycheng" + ] + }, + "Web/HTML": { + "modified": "2020-10-16T05:00:10.652Z", + "contributors": [ + "j0987397957", + "j3ygithub", + "jjyaung", + "SphinxKnight", + "lalasoqTW", + "Mr430", + "XIGUO", + "xerviam", + "willynpi", + "iigmir", + "mybaseball52", + "antonytse", + "EtienneC", + "SecondSpirit", + "thomasaria", + "jackblackevo", + "archyaloha", + "Shiyou", + "irvinfly", + "stingyong", + "sailplaneTW" + ] + }, + "Web/HTML/Applying_color": { + "modified": "2019-03-18T21:29:53.605Z", + "contributors": [ + "WuBingHsuan" + ] + }, + "Web/HTML/Attributes": { + "modified": "2019-03-23T22:49:22.885Z", + "contributors": [ + "jackblackevo", + "stingyong" + ] + }, + "Web/HTML/Block-level_elements": { + "modified": "2019-03-23T22:04:44.255Z", + "contributors": [ + "jackblackevo", + "yimingxym" + ] + }, + "Web/HTML/Element": { + "modified": "2020-06-01T13:13:14.618Z", + "contributors": [ + "iigmir", + "ltsai323", + "unnhao", + "jackblackevo", + "irvinfly", + "teoli", + "BobChao" + ] + }, + "Web/HTML/Element/a": { + "modified": "2020-10-15T21:05:46.606Z", + "contributors": [ + "iigmir", + "hinet60613", + "jackblackevo", + "teoli", + "BobChao", + "ethertank" + ] + }, + "Web/HTML/Element/blink": { + "modified": "2020-10-15T21:53:26.779Z", + "contributors": [ + "teoli", + "iigmir" + ] + }, + "Web/HTML/Element/blockquote": { + "modified": "2019-03-23T22:32:36.058Z", + "contributors": [ + "iigmir", + "Shiyou" + ] + }, + "Web/HTML/Element/br": { + "modified": "2020-10-15T22:00:58.202Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTML/Element/button": { + "modified": "2020-05-05T00:47:26.851Z", + "contributors": [ + "unnhao", + "weswithley" + ] + }, + "Web/HTML/Element/canvas": { + "modified": "2019-03-23T22:41:16.083Z", + "contributors": [ + "pig3629", + "GG9" + ] + }, + "Web/HTML/Element/code": { + "modified": "2019-03-23T22:29:09.754Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTML/Element/div": { + "modified": "2020-10-15T21:47:03.763Z", + "contributors": [ + "Shiyou", + "iigmir" + ] + }, + "Web/HTML/Element/font": { + "modified": "2020-10-15T21:44:22.712Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTML/Element/form": { + "modified": "2020-10-15T22:29:56.079Z", + "contributors": [ + "unnhao" + ] + }, + "Web/HTML/Element/frameset": { + "modified": "2019-03-23T22:28:05.345Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTML/Element/hr": { + "modified": "2019-03-23T22:23:32.127Z", + "contributors": [ + "iigmir", + "ywchiao" + ] + }, + "Web/HTML/Element/input": { + "modified": "2019-03-23T22:08:13.272Z", + "contributors": [ + "Sheppy" + ] + }, + "Web/HTML/Element/input/submit": { + "modified": "2019-03-23T22:08:05.925Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTML/Element/marquee": { + "modified": "2020-10-15T21:53:57.839Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTML/Element/meter": { + "modified": "2019-04-09T18:21:26.397Z", + "contributors": [ + "jwhitlock", + "evildeepblue" + ] + }, + "Web/HTML/Element/nav": { + "modified": "2020-10-15T21:56:36.267Z", + "contributors": [ + "iigmir", + "jackblackevo", + "h223449961" + ] + }, + "Web/HTML/Element/optgroup": { + "modified": "2019-03-23T22:28:41.892Z", + "contributors": [ + "alk03073135" + ] + }, + "Web/HTML/Element/picture": { + "modified": "2020-10-15T22:32:35.687Z", + "contributors": [ + "leannechen2" + ] + }, + "Web/HTML/Element/q": { + "modified": "2020-10-15T21:49:02.776Z", + "contributors": [ + "fscholz", + "iigmir" + ] + }, + "Web/HTML/Element/ruby": { + "modified": "2020-10-15T21:49:21.871Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTML/Element/script": { + "modified": "2020-10-15T21:41:05.397Z", + "contributors": [ + "SphinxKnight", + "t7yang", + "iigmir", + "roycrxtw", + "Shiyou" + ] + }, + "Web/HTML/Element/summary": { + "modified": "2019-03-23T22:30:12.195Z", + "contributors": [ + "Tingyu" + ] + }, + "Web/HTML/Element/table": { + "modified": "2020-10-15T21:43:36.560Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTML/Element/template": { + "modified": "2020-10-15T22:00:56.747Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTML/Element/time": { + "modified": "2019-03-23T22:32:35.538Z", + "contributors": [ + "Shiyou" + ] + }, + "Web/HTML/Forms_in_HTML": { + "modified": "2019-03-23T23:28:09.563Z", + "contributors": [ + "foxbrush" + ] + }, + "Web/HTML/Global_attributes": { + "modified": "2019-03-23T22:31:21.607Z", + "contributors": [ + "jackblackevo", + "iigmir" + ] + }, + "Web/HTML/Global_attributes/data-*": { + "modified": "2019-03-23T22:19:55.073Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTML/Global_attributes/spellcheck": { + "modified": "2019-03-23T23:43:42.545Z", + "contributors": [ + "jackblackevo", + "irvinfly", + "teoli", + "BobChao" + ] + }, + "Web/HTML/Quirks_Mode_and_Standards_Mode": { + "modified": "2019-03-23T22:31:44.412Z", + "contributors": [ + "iigmir", + "chrisdavidmills" + ] + }, + "Web/HTML/Reference": { + "modified": "2019-09-09T07:23:59.718Z", + "contributors": [ + "SphinxKnight", + "wbamberg", + "iigmir", + "TAlulu", + "irvinfly", + "stingyong" + ] + }, + "Web/HTML/Supported_media_formats": { + "modified": "2019-03-23T23:14:51.174Z", + "contributors": [ + "young3578671", + "Keeseonglee" + ] + }, + "Web/HTML/Using_the_application_cache": { + "modified": "2019-03-24T00:10:44.785Z", + "contributors": [ + "SphinxKnight", + "jackblackevo", + "teoli", + "Kennyluck", + "Mgjbot", + "Cooldll694", + "BobChao" + ] + }, + "Web/HTTP": { + "modified": "2020-05-09T15:09:07.858Z", + "contributors": [ + "mgrn", + "0807love0825", + "rayainman", + "xerviam", + "bnn00023", + "mybaseball52", + "jwhitlock", + "yyss" + ] + }, + "Web/HTTP/Authentication": { + "modified": "2019-03-18T21:31:55.684Z", + "contributors": [ + "hua-123" + ] + }, + "Web/HTTP/Basics_of_HTTP": { + "modified": "2020-03-16T05:38:40.530Z", + "contributors": [ + "mfuji09" + ] + }, + "Web/HTTP/Basics_of_HTTP/MIME_types": { + "modified": "2020-06-08T05:57:19.890Z", + "contributors": [ + "hikariTW", + "willynpi" + ] + }, + "Web/HTTP/Browser_detection_using_the_user_agent": { + "modified": "2020-09-21T11:14:16.789Z", + "contributors": [ + "iigmir", + "jwhitlock" + ] + }, + "Web/HTTP/CORS": { + "modified": "2020-10-15T21:21:52.967Z", + "contributors": [ + "kunyaoxu", + "LNDDYL", + "jackblackevo", + "iigmir", + "fscholz", + "hsinewu", + "jwhitlock", + "xgqfrms", + "yetisno", + "nfsnfs", + "foxbrush", + "DESKTOP-H9V56N1" + ] + }, + "Web/HTTP/CORS/Errors": { + "modified": "2019-05-07T03:11:46.742Z" + }, + "Web/HTTP/CORS/Errors/CORSDidNotSucceed": { + "modified": "2019-05-07T05:22:57.676Z", + "contributors": [ + "hms5232" + ] + }, + "Web/HTTP/CORS/Errors/CORSMissingAllowOrigin": { + "modified": "2019-05-07T05:23:32.648Z", + "contributors": [ + "hms5232" + ] + }, + "Web/HTTP/CORS/Errors/CORSNotSupportingCredentials": { + "modified": "2019-05-07T22:55:59.165Z", + "contributors": [ + "hms5232" + ] + }, + "Web/HTTP/Caching": { + "modified": "2019-09-07T05:43:44.819Z", + "contributors": [ + "CPMoviePHil", + "fadeawaygod" + ] + }, + "Web/HTTP/Cookies": { + "modified": "2019-03-18T21:43:21.294Z", + "contributors": [ + "jackblackevo", + "csiejoey" + ] + }, + "Web/HTTP/Headers": { + "modified": "2019-03-23T22:17:44.358Z", + "contributors": [ + "fscholz" + ] + }, + "Web/HTTP/Headers/Accept": { + "modified": "2020-10-15T22:27:22.748Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTTP/Headers/DNT": { + "modified": "2020-10-15T22:01:54.641Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTTP/Headers/Server": { + "modified": "2020-10-15T22:01:55.490Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTTP/Headers/Strict-Transport-Security": { + "modified": "2020-10-15T22:23:24.512Z", + "contributors": [ + "jasperlin1996", + "r1235613" + ] + }, + "Web/HTTP/Headers/User-Agent": { + "modified": "2020-10-15T21:52:25.725Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTTP/Headers/X-Forwarded-For": { + "modified": "2020-10-15T22:18:49.633Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTTP/Headers/X-Frame-Options": { + "modified": "2019-06-17T05:41:08.405Z", + "contributors": [ + "jackblackevo", + "jwhitlock", + "allenown", + "foxbrush" + ] + }, + "Web/HTTP/Link_prefetching_FAQ": { + "modified": "2019-03-23T22:49:36.623Z", + "contributors": [ + "imrobinized", + "jwhitlock", + "foxbrush" + ] + }, + "Web/HTTP/Methods": { + "modified": "2020-10-15T22:04:23.999Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTTP/Methods/CONNECT": { + "modified": "2020-10-15T22:08:59.762Z", + "contributors": [ + "flyinglimao" + ] + }, + "Web/HTTP/Methods/GET": { + "modified": "2020-10-15T22:16:59.594Z", + "contributors": [ + "sheiun" + ] + }, + "Web/HTTP/Methods/POST": { + "modified": "2020-10-15T22:17:01.111Z", + "contributors": [ + "sheiun" + ] + }, + "Web/HTTP/Protocol_upgrade_mechanism": { + "modified": "2019-11-03T23:58:28.570Z", + "contributors": [ + "nientsu" + ] + }, + "Web/HTTP/Server-Side_Access_Control": { + "modified": "2019-03-23T22:06:20.131Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/HTTP/Status": { + "modified": "2020-10-15T21:38:22.963Z", + "contributors": [ + "gogo.sanak", + "sideshowbarker", + "lesikolerina23", + "SphinxKnight", + "bobo.debila", + "iigmir", + "Fu_revwigs", + "slivenred", + "gamerslouis", + "tz70s", + "Hunsin", + "fscholz", + "jwhitlock", + "alk03073135" + ] + }, + "Web/HTTP/Status/100": { + "modified": "2020-10-15T22:17:55.422Z", + "contributors": [ + "Fu_revwigs" + ] + }, + "Web/HTTP/Status/101": { + "modified": "2019-04-28T12:49:13.643Z", + "contributors": [ + "Fu_revwigs" + ] + }, + "Web/HTTP/Status/200": { + "modified": "2020-10-15T22:02:32.760Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTTP/Status/201": { + "modified": "2020-10-15T22:18:06.540Z", + "contributors": [ + "Fu_revwigs" + ] + }, + "Web/HTTP/Status/202": { + "modified": "2019-05-04T10:35:23.469Z", + "contributors": [ + "Fu_revwigs" + ] + }, + "Web/HTTP/Status/203": { + "modified": "2019-05-18T10:26:00.843Z", + "contributors": [ + "Fu_revwigs" + ] + }, + "Web/HTTP/Status/204": { + "modified": "2020-10-15T22:18:45.174Z", + "contributors": [ + "Fu_revwigs" + ] + }, + "Web/HTTP/Status/205": { + "modified": "2019-05-18T10:36:04.142Z", + "contributors": [ + "Fu_revwigs" + ] + }, + "Web/HTTP/Status/206": { + "modified": "2020-10-15T22:19:35.757Z", + "contributors": [ + "Fu_revwigs" + ] + }, + "Web/HTTP/Status/300": { + "modified": "2019-06-01T11:53:52.718Z", + "contributors": [ + "Fu_revwigs" + ] + }, + "Web/HTTP/Status/301": { + "modified": "2020-10-15T22:19:36.009Z", + "contributors": [ + "iigmir", + "Fu_revwigs" + ] + }, + "Web/HTTP/Status/403": { + "modified": "2020-10-15T22:18:46.702Z", + "contributors": [ + "gamerslouis" + ] + }, + "Web/HTTP/Status/404": { + "modified": "2020-10-15T22:00:39.486Z", + "contributors": [ + "bobo.debila", + "iigmir" + ] + }, + "Web/HTTP/Status/409": { + "modified": "2019-06-23T09:33:36.008Z", + "contributors": [ + "gamerslouis" + ] + }, + "Web/HTTP/Status/411": { + "modified": "2019-06-23T09:22:09.625Z", + "contributors": [ + "gamerslouis" + ] + }, + "Web/HTTP/Status/415": { + "modified": "2019-06-23T09:29:51.676Z", + "contributors": [ + "gamerslouis" + ] + }, + "Web/HTTP/Status/418_I_m_a_teapot": { + "modified": "2020-10-15T22:00:43.617Z", + "contributors": [ + "iigmir", + "dzamlo" + ] + }, + "Web/HTTP/Status/451": { + "modified": "2020-10-15T22:02:32.084Z", + "contributors": [ + "iigmir" + ] + }, + "Web/HTTP/Status/500": { + "modified": "2020-10-15T22:00:42.137Z", + "contributors": [ + "YagoZang", + "sideshowbarker", + "lesikolerina23", + "iigmir", + "slivenred" + ] + }, + "Web/HTTP/Status/502": { + "modified": "2020-10-15T22:22:34.836Z", + "contributors": [ + "bobo.debila", + "iigmir", + "slivenred" + ] + }, + "Web/HTTP/Status/503": { + "modified": "2020-10-15T22:21:37.501Z", + "contributors": [ + "iigmir", + "slivenred", + "katsmin" + ] + }, + "Web/HTTP/Status/504": { + "modified": "2020-11-05T06:35:40.877Z", + "contributors": [ + "terrylinooo", + "sideshowbarker", + "lesikolerina23", + "iigmir", + "slivenred" + ] + }, + "Web/HTTP/data_URIs": { + "modified": "2020-06-09T11:41:01.440Z", + "contributors": [ + "jhihruei", + "jwhitlock", + "Shiyou", + "alk03073135" + ] + }, + "Web/JavaScript": { + "modified": "2020-05-24T01:05:47.129Z", + "contributors": [ + "nighet", + "SphinxKnight", + "nykevinwong", + "xerviam", + "iigmir", + "cwlin0416", + "thomasaria", + "dolphinlin", + "flyinglimao", + "jackblackevo", + "mai7855", + "Shiyou", + "wildsky", + "teoli", + "steely.wing", + "ethertank", + "sycheng", + "sailplaneTW", + "linhomeyeu", + "happysadman", + "Mgjbot", + "BobChao", + "kourge" + ] + }, + "Web/JavaScript/A_re-introduction_to_JavaScript": { + "modified": "2020-03-12T19:36:04.881Z", + "contributors": [ + "kourge", + "locker_rj45", + "Q3Q", + "weihanglo", + "teoli", + "jackblackevo", + "TpWILovePanda", + "changyuheng", + "ArvinH", + "sailplaneTW", + "linhomeyeu", + "fillano", + "fscholz", + "Mgjbot", + "Smallwow", + "BobChao" + ] + }, + "Web/JavaScript/About_JavaScript": { + "modified": "2020-03-12T19:35:23.761Z", + "contributors": [ + "Talence0329", + "jackblackevo", + "irvinfly", + "teoli", + "ethertank", + "Sonrisa", + "sycheng" + ] + }, + "Web/JavaScript/Closures": { + "modified": "2020-08-07T04:58:02.421Z", + "contributors": [ + "vincent7293", + "shuboc", + "iigmir", + "roycrxtw", + "BigHeadDoggy", + "flyinglimao" + ] + }, + "Web/JavaScript/Data_structures": { + "modified": "2020-08-01T13:14:09.974Z", + "contributors": [ + "nannxnann", + "samzzz", + "iigmir", + "jackblackevo", + "eldisa" + ] + }, + "Web/JavaScript/Enumerability_and_ownership_of_properties": { + "modified": "2020-03-12T19:44:21.130Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Equality_comparisons_and_sameness": { + "modified": "2020-03-12T19:44:59.221Z", + "contributors": [ + "jsgao0", + "flyinglimao" + ] + }, + "Web/JavaScript/EventLoop": { + "modified": "2020-03-12T19:44:52.158Z", + "contributors": [ + "xuan0123", + "jackblackevo", + "roycrxtw", + "YuCheng", + "Snailpool", + "flyinglimao", + "enzoyaaaaa" + ] + }, + "Web/JavaScript/Guide": { + "modified": "2020-10-12T05:01:38.453Z", + "contributors": [ + "ShawnLin", + "nykevinwong", + "jackblackevo", + "cwlin0416", + "jwhitlock", + "teoli", + "sycheng" + ] + }, + "Web/JavaScript/Guide/Control_flow_and_error_handling": { + "modified": "2020-03-12T19:44:28.801Z", + "contributors": [ + "akccakcctw", + "iigmir", + "dews", + "jackblackevo", + "Yuki0916", + "jwhitlock", + "Kaiyeh" + ] + }, + "Web/JavaScript/Guide/Details_of_the_Object_Model": { + "modified": "2020-03-12T19:38:25.366Z", + "contributors": [ + "wbamberg", + "SphinxKnight", + "jwhitlock", + "jackblackevo", + "teoli", + "steely.wing" + ] + }, + "Web/JavaScript/Guide/Expressions_and_Operators": { + "modified": "2020-10-12T06:55:01.538Z", + "contributors": [ + "ShawnLin", + "jackblackevo", + "Kaiyeh" + ] + }, + "Web/JavaScript/Guide/Functions": { + "modified": "2020-03-12T19:39:15.149Z", + "contributors": [ + "wbamberg", + "jwhitlock", + "Kaiyeh", + "iigmir", + "jackblackevo", + "teoli", + "thomaschen" + ] + }, + "Web/JavaScript/Guide/Grammar_and_types": { + "modified": "2020-05-26T04:33:48.056Z", + "contributors": [ + "chumicat", + "King_Tzeng", + "YiyuWu", + "nykevinwong", + "Ruiyuan34", + "jackblackevo", + "Jenhaohsiao", + "KevinHuang", + "JianHuaHe", + "jwhitlock", + "Jack_Wu", + "lynn456", + "dodo4910", + "septemhill", + "fscholz", + "victor0801x", + "ShadowV", + "teoli", + "titan.liu" + ] + }, + "Web/JavaScript/Guide/Indexed_collections": { + "modified": "2020-03-12T19:47:20.689Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Guide/Introduction": { + "modified": "2020-03-12T19:35:21.304Z", + "contributors": [ + "wbamberg", + "mingyangshih", + "jwhitlock", + "jackblackevo", + "fscholz", + "irvinfly", + "teoli", + "ethertank", + "sycheng" + ] + }, + "Web/JavaScript/Guide/Iterators_and_Generators": { + "modified": "2020-03-23T19:43:30.431Z", + "contributors": [ + "hiimeimei", + "wanjingzhang" + ] + }, + "Web/JavaScript/Guide/Keyed_collections": { + "modified": "2020-03-12T19:42:35.494Z", + "contributors": [ + "jackblackevo", + "jwhitlock", + "fscholz", + "Shiyou" + ] + }, + "Web/JavaScript/Guide/Loops_and_iteration": { + "modified": "2020-03-12T19:44:25.077Z", + "contributors": [ + "MartinChang0723", + "jackblackevo", + "AmamiyaLee" + ] + }, + "Web/JavaScript/Guide/Numbers_and_dates": { + "modified": "2020-08-17T03:02:46.243Z", + "contributors": [ + "kenchill", + "UnciaX" + ] + }, + "Web/JavaScript/Guide/Regular_Expressions": { + "modified": "2020-05-25T23:31:32.570Z", + "contributors": [ + "LeoWangJ", + "oooooo", + "Lazine", + "yosia", + "seantw", + "drinktea28", + "joshra", + "jackblackevo", + "Jiaaa1014", + "jwhitlock", + "Kustz", + "pppdog", + "m80126colin", + "Shiyou", + "teoli", + "Rplus" + ] + }, + "Web/JavaScript/Guide/Using_promises": { + "modified": "2020-03-12T19:47:23.033Z", + "contributors": [ + "HamiltonWang", + "flyinglimao" + ] + }, + "Web/JavaScript/Guide/Working_with_Objects": { + "modified": "2020-03-12T19:38:34.548Z", + "contributors": [ + "Euphokumiko", + "SphinxKnight", + "AhQi", + "jwhitlock", + "pytseng", + "jackblackevo", + "iigmir", + "jigs12", + "YuXiangYen", + "teoli", + "steely.wing" + ] + }, + "Web/JavaScript/Inheritance_and_the_prototype_chain": { + "modified": "2020-11-20T06:14:21.309Z", + "contributors": [ + "tpps88206", + "pmc12thsuki", + "osk2", + "jackblackevo", + "iigmir", + "WellyHong", + "hiiamyes", + "Snailpool" + ] + }, + "Web/JavaScript/Introduction_to_Object-Oriented_JavaScript": { + "modified": "2020-08-05T00:50:19.955Z", + "contributors": [ + "nientsu", + "cwlin0416", + "fscholz", + "jackblackevo", + "nightsnow0918", + "irvinfly", + "sailplaneTW" + ] + }, + "Web/JavaScript/JavaScript_technologies_overview": { + "modified": "2020-03-12T19:35:23.439Z", + "contributors": [ + "jackblackevo", + "fscholz", + "irvinfly", + "chiayuan" + ] + }, + "Web/JavaScript/Language_Resources": { + "modified": "2020-03-12T19:36:06.284Z", + "contributors": [ + "jackblackevo", + "fscholz", + "irvinfly", + "sailplaneTW" + ] + }, + "Web/JavaScript/Memory_Management": { + "modified": "2020-12-04T15:05:56.547Z", + "contributors": [ + "chengr4", + "ballfish", + "mybaseball52" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/JavaScript_概要": { + "modified": "2019-01-16T14:44:37.660Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/LiveConnect_概要": { + "modified": "2019-01-16T14:43:16.706Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/Unicode": { + "modified": "2019-01-16T14:44:25.337Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/以類別為基礎的語言_vs._以原型為基礎的語言": { + "modified": "2019-01-16T14:43:47.289Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/例外處理語法": { + "modified": "2019-03-24T00:00:58.152Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/例外處理語法/throw_語法": { + "modified": "2019-03-24T00:00:57.682Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/例外處理語法/try...catch_語法": { + "modified": "2020-08-31T05:59:42.160Z", + "contributors": [ + "clifflu", + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/值": { + "modified": "2019-01-16T14:44:19.901Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/再談屬性的繼承": { + "modified": "2019-01-16T14:43:20.597Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/再談屬性的繼承/實體關係的確定": { + "modified": "2019-01-16T14:43:13.719Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/再談屬性的繼承/局域值和繼承值": { + "modified": "2019-01-16T14:43:16.085Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/再談屬性的繼承/建構子中的全域資訊": { + "modified": "2019-01-16T14:43:20.683Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/再談屬性的繼承/沒有多重繼承": { + "modified": "2019-01-16T14:43:21.630Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/函數的呼叫": { + "modified": "2019-03-24T00:00:58.959Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/函數的定義": { + "modified": "2019-01-16T14:44:26.521Z", + "contributors": [ + "teoli", + "Sheppy", + "Jaric", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/區塊語法": { + "modified": "2019-01-16T13:06:24.647Z", + "contributors": [ + "teoli", + "Sheppy", + "Jaric", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/字面表達": { + "modified": "2019-01-16T14:44:20.274Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/常數": { + "modified": "2019-01-16T14:44:19.601Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/建立新的物件": { + "modified": "2019-03-24T00:01:06.649Z", + "contributors": [ + "wbamberg", + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/循環語法": { + "modified": "2019-01-16T14:44:21.815Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/循環語法/break_語法": { + "modified": "2019-03-24T00:00:58.023Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/循環語法/continue_語法": { + "modified": "2019-03-24T00:01:00.198Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/循環語法/do...while_語法": { + "modified": "2019-03-24T00:00:59.356Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/循環語法/for_語法": { + "modified": "2019-03-24T00:01:11.869Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/循環語法/label_語法": { + "modified": "2019-03-24T00:01:01.557Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/循環語法/while_語法": { + "modified": "2019-03-24T00:01:00.950Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/新物件的建立": { + "modified": "2019-03-24T00:01:06.394Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/新物件的建立/Getter_和_Setter_的定義": { + "modified": "2019-03-24T00:01:05.950Z", + "contributors": [ + "fscholz", + "jigs12", + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/新物件的建立/使用_this_取得物件的參考": { + "modified": "2019-03-24T00:01:06.045Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/新物件的建立/屬性的刪除": { + "modified": "2019-03-24T00:01:04.888Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/新物件的建立/建構子函數的使用": { + "modified": "2019-03-24T00:01:06.293Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/新物件的建立/方法的定義": { + "modified": "2019-03-24T00:01:03.034Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/新物件的建立/物件初始化子的使用": { + "modified": "2019-03-24T00:01:06.480Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/新物件的建立/物件屬性的索引": { + "modified": "2019-03-24T00:01:04.238Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/新物件的建立/針對物件的類型定義屬性": { + "modified": "2019-03-24T00:01:04.444Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/條件語法": { + "modified": "2019-01-16T14:43:51.018Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/正規表達式模式的編寫": { + "modified": "2019-03-24T00:00:58.884Z", + "contributors": [ + "wildsky", + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/正規表達式的建立": { + "modified": "2019-03-24T00:01:00.293Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/正規表達式的運用": { + "modified": "2019-01-16T14:44:21.287Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/正規表達式的運用/使用標誌的進階搜尋": { + "modified": "2019-01-16T14:44:23.103Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/正規表達式的運用/括弧子字串的比對結果的運用": { + "modified": "2019-01-16T14:44:25.974Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/正規表達式的運用/正規表達式的範例": { + "modified": "2019-03-24T00:00:59.567Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/物件和屬性": { + "modified": "2019-01-16T14:44:03.755Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/物件的操作語法": { + "modified": "2019-03-24T00:00:59.074Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/繼承": { + "modified": "2019-03-24T00:01:09.212Z", + "contributors": [ + "jsgao0", + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/職員的例子": { + "modified": "2019-03-24T00:01:18.422Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/職員的例子/更靈活的建構子": { + "modified": "2019-01-16T14:43:17.913Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/職員的例子/物件的屬性": { + "modified": "2019-03-24T00:01:21.807Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/職員的例子/物件的屬性/屬性的加入": { + "modified": "2019-03-24T00:01:15.806Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/職員的例子/物件的屬性/屬性的繼承": { + "modified": "2019-03-24T00:01:17.728Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/職員的例子/階層的建立": { + "modified": "2019-03-24T00:01:17.848Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/表達式": { + "modified": "2019-01-16T14:44:25.015Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/註解": { + "modified": "2019-01-16T14:44:18.898Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/變數": { + "modified": "2019-01-16T14:44:20.971Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/迭代器和產生器": { + "modified": "2019-03-24T00:01:19.860Z", + "contributors": [ + "wbamberg", + "teoli", + "Wladimir_Palant", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/運算子": { + "modified": "2019-01-16T14:44:25.230Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/運算子/代入運算子": { + "modified": "2019-03-24T00:01:01.353Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/運算子/位元運算子": { + "modified": "2019-01-16T14:44:24.141Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/運算子/字串運算子": { + "modified": "2019-01-16T14:44:19.884Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/運算子/比較運算子": { + "modified": "2019-01-16T14:44:28.417Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/運算子/特殊運算子": { + "modified": "2019-01-16T14:44:24.727Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/運算子/算術運算子": { + "modified": "2019-01-16T14:44:25.132Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/運算子/邏輯運算子": { + "modified": "2019-01-16T14:44:21.016Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/閉包的運用": { + "modified": "2019-01-16T14:44:07.939Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/關於": { + "modified": "2019-01-16T14:44:22.263Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/陣列的運用": { + "modified": "2019-03-24T00:01:19.124Z", + "contributors": [ + "wbamberg", + "Jaja", + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的函數": { + "modified": "2019-01-16T14:44:03.697Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的函數/Number_和_String_函數": { + "modified": "2019-03-24T00:01:05.054Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的函數/escape_和_unescape_函數": { + "modified": "2019-03-24T00:01:07.501Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的函數/eval_函數": { + "modified": "2019-01-16T14:44:04.783Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的函數/isFinite_函數": { + "modified": "2019-03-24T00:01:03.372Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的函數/isNaN_函數": { + "modified": "2019-03-24T00:01:04.794Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的函數/parseInt_和_parseFloat_函數": { + "modified": "2019-03-24T00:01:07.340Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的核心物件": { + "modified": "2019-01-16T14:44:07.734Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的核心物件/Array_物件": { + "modified": "2019-03-24T00:01:13.553Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的核心物件/Boolean_物件": { + "modified": "2019-03-24T00:01:13.158Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的核心物件/Date_物件": { + "modified": "2019-03-24T00:01:09.665Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的核心物件/Function_物件": { + "modified": "2019-03-24T00:01:12.219Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的核心物件/Math_物件": { + "modified": "2019-03-24T00:01:08.965Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的核心物件/Number_物件": { + "modified": "2019-03-24T00:01:11.242Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的核心物件/RegExp_物件": { + "modified": "2019-03-24T00:01:13.910Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Obsolete_Pages/Obsolete_Pages/Obsolete_Pages/預先定義的核心物件/String_物件": { + "modified": "2019-03-24T00:01:08.836Z", + "contributors": [ + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Reference": { + "modified": "2020-06-02T20:54:32.743Z", + "contributors": [ + "laampui", + "cwlin0416", + "jackblackevo", + "teoli", + "irvinfly", + "tjjh89017", + "Zhen.Di-Lin", + "Norbert" + ] + }, + "Web/JavaScript/Reference/Classes": { + "modified": "2020-03-12T19:42:37.772Z", + "contributors": [ + "hot50773", + "Aries0d0f", + "chloewlin", + "roycrxtw", + "akccakcctw", + "ywchiao", + "fbukevin" + ] + }, + "Web/JavaScript/Reference/Classes/constructor": { + "modified": "2020-07-23T05:05:44.137Z", + "contributors": [ + "t7yang", + "iigmir" + ] + }, + "Web/JavaScript/Reference/Classes/extends": { + "modified": "2020-10-15T22:06:07.272Z", + "contributors": [ + "Aries0d0f" + ] + }, + "Web/JavaScript/Reference/Classes/static": { + "modified": "2020-03-12T19:43:06.328Z", + "contributors": [ + "alkalineW", + "jerrychen1013", + "Robert-Rino" + ] + }, + "Web/JavaScript/Reference/Errors": { + "modified": "2020-03-12T19:44:53.537Z", + "contributors": [ + "iigmir" + ] + }, + "Web/JavaScript/Reference/Errors/Bad_return_or_yield": { + "modified": "2020-03-12T19:44:54.646Z", + "contributors": [ + "iigmir" + ] + }, + "Web/JavaScript/Reference/Errors/Invalid_array_length": { + "modified": "2020-03-12T19:49:01.235Z", + "contributors": [ + "gamerslouis" + ] + }, + "Web/JavaScript/Reference/Errors/Missing_curly_after_property_list": { + "modified": "2020-03-12T19:47:08.262Z", + "contributors": [ + "PCLIN1103" + ] + }, + "Web/JavaScript/Reference/Errors/No_properties": { + "modified": "2020-03-12T19:47:20.608Z", + "contributors": [ + "iigmir" + ] + }, + "Web/JavaScript/Reference/Errors/Not_a_function": { + "modified": "2020-03-12T19:45:02.118Z", + "contributors": [ + "iigmir" + ] + }, + "Web/JavaScript/Reference/Errors/Not_defined": { + "modified": "2020-03-12T19:44:53.089Z", + "contributors": [ + "iigmir" + ] + }, + "Web/JavaScript/Reference/Errors/Redeclared_parameter": { + "modified": "2020-03-12T19:47:17.103Z", + "contributors": [ + "iigmir" + ] + }, + "Web/JavaScript/Reference/Errors/Too_much_recursion": { + "modified": "2020-03-12T19:44:57.763Z", + "contributors": [ + "iigmir" + ] + }, + "Web/JavaScript/Reference/Errors/Unexpected_type": { + "modified": "2019-03-23T22:20:43.997Z", + "contributors": [ + "andytwmvp", + "iigmir", + "kimi1111" + ] + }, + "Web/JavaScript/Reference/Functions": { + "modified": "2020-03-12T19:41:25.162Z", + "contributors": [ + "lynn456", + "fscholz" + ] + }, + "Web/JavaScript/Reference/Functions/Arrow_functions": { + "modified": "2020-10-15T21:36:09.562Z", + "contributors": [ + "iigmir", + "ShawnLin", + "Lazine", + "xuan0123", + "bagayollow", + "ctc53", + "kuolun", + "jackblackevo", + "freddy50806", + "Aisuzuka", + "Jaja", + "tonykuo", + "yungtah", + "Snailpool", + "wkliang", + "linjimmy168", + "foxbrush" + ] + }, + "Web/JavaScript/Reference/Functions/Default_parameters": { + "modified": "2020-10-05T03:37:47.112Z", + "contributors": [ + "realspirit2017", + "Jackson45252", + "jsgao0", + "Snailpool" + ] + }, + "Web/JavaScript/Reference/Functions/Method_definitions": { + "modified": "2020-10-15T21:55:16.559Z", + "contributors": [ + "iigmir", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Functions/arguments": { + "modified": "2020-10-15T21:14:39.550Z", + "contributors": [ + "itsems", + "jackblackevo", + "akari0624", + "fscholz", + "irvinfly", + "teoli", + "happysadman" + ] + }, + "Web/JavaScript/Reference/Functions/arguments/callee": { + "modified": "2020-03-12T19:45:29.084Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Functions/get": { + "modified": "2020-10-15T22:17:05.787Z", + "contributors": [ + "iigmir" + ] + }, + "Web/JavaScript/Reference/Functions/rest_parameters": { + "modified": "2020-10-15T21:56:42.865Z", + "contributors": [ + "Kevin_Chen", + "jackblackevo", + "jsgao0" + ] + }, + "Web/JavaScript/Reference/Functions/set": { + "modified": "2020-10-15T22:17:33.994Z", + "contributors": [ + "iigmir" + ] + }, + "Web/JavaScript/Reference/Global_Objects": { + "modified": "2020-03-12T19:38:39.590Z", + "contributors": [ + "tony8382", + "chialin", + "jackblackevo", + "jsgao0", + "cwlin0416", + "teoli", + "Sheppy" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array": { + "modified": "2020-10-15T21:31:26.717Z", + "contributors": [ + "hua-123", + "kyob1010", + "Aries0d0f", + "KevinHuang", + "k940545", + "jackblackevo", + "tswenja", + "kdex", + "petercpg", + "Kaiyeh", + "cwlin0416", + "oooooo", + "m80126colin", + "lizlux" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/@@iterator": { + "modified": "2020-10-15T22:02:20.291Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/Reduce": { + "modified": "2020-10-15T21:54:40.258Z", + "contributors": [ + "Ashe_Li", + "jackblackevo", + "iigmir", + "dwatow", + "yozian" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/concat": { + "modified": "2020-10-15T21:46:28.512Z", + "contributors": [ + "jackblackevo", + "tericky" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/copyWithin": { + "modified": "2020-10-15T22:01:15.329Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/entries": { + "modified": "2020-10-15T21:47:10.197Z", + "contributors": [ + "jackblackevo", + "tericky" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/every": { + "modified": "2020-10-15T21:56:41.781Z", + "contributors": [ + "jackblackevo", + "AkanishiChi", + "jsgao0" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/fill": { + "modified": "2020-10-15T21:56:41.165Z", + "contributors": [ + "jackblackevo", + "jsgao0" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/filter": { + "modified": "2020-10-15T21:38:35.707Z", + "contributors": [ + "Jenhaohsiao", + "jackblackevo", + "iigmir", + "jsgao0", + "alk03073135" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/find": { + "modified": "2020-10-15T21:42:27.701Z", + "contributors": [ + "jackblackevo", + "iigmir", + "ALiangLiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/findIndex": { + "modified": "2020-10-15T21:51:49.109Z", + "contributors": [ + "jackblackevo", + "tooto1985", + "auver", + "Snailpool" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/flat": { + "modified": "2020-10-15T22:11:38.333Z", + "contributors": [ + "SageX", + "Euphokumiko" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/forEach": { + "modified": "2020-10-15T21:46:18.574Z", + "contributors": [ + "jackblackevo", + "iigmir", + "wangqimeng", + "nt46", + "akari0624" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/from": { + "modified": "2020-10-15T21:52:49.849Z", + "contributors": [ + "qwer5656", + "jackblackevo", + "petercpg", + "tericky" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/includes": { + "modified": "2020-10-15T22:02:19.463Z", + "contributors": [ + "SiderealArt", + "sonelin09", + "xuan311", + "vaynewang", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/indexOf": { + "modified": "2020-10-15T21:56:48.783Z", + "contributors": [ + "jackblackevo", + "jsgao0" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/isArray": { + "modified": "2020-10-15T21:34:45.216Z", + "contributors": [ + "jackblackevo", + "tericky", + "m80126colin", + "JamesWen", + "onlinemad" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/join": { + "modified": "2020-10-15T21:47:08.883Z", + "contributors": [ + "jackblackevo", + "iigmir", + "JamesWen" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/keys": { + "modified": "2020-10-15T22:02:18.808Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf": { + "modified": "2020-10-15T22:02:16.799Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/length": { + "modified": "2020-10-15T21:58:21.627Z", + "contributors": [ + "tericky", + "yenchenglai0618", + "mybaseball52" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/map": { + "modified": "2020-10-15T21:53:08.025Z", + "contributors": [ + "iigmir", + "jackblackevo", + "jWorker", + "akari0624" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/of": { + "modified": "2020-10-15T22:01:03.622Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/pop": { + "modified": "2020-10-15T21:56:21.800Z", + "contributors": [ + "jackblackevo", + "yvonne6344" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/push": { + "modified": "2020-10-15T21:42:28.441Z", + "contributors": [ + "jackblackevo", + "yvonne6344", + "iigmir", + "ALiangLiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/reverse": { + "modified": "2020-10-15T21:31:21.385Z", + "contributors": [ + "jackblackevo", + "CYBAI" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/shift": { + "modified": "2020-10-15T21:50:12.873Z", + "contributors": [ + "jackblackevo", + "marktwtn" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/slice": { + "modified": "2020-10-15T22:00:48.969Z", + "contributors": [ + "rosa", + "pig3629", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/some": { + "modified": "2020-10-15T22:02:17.128Z", + "contributors": [ + "iigmir", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/sort": { + "modified": "2020-10-15T21:31:18.682Z", + "contributors": [ + "jackblackevo", + "CYBAI" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/splice": { + "modified": "2020-10-15T21:56:28.206Z", + "contributors": [ + "jackblackevo", + "jsgao0", + "Mars-Hung" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/unshift": { + "modified": "2020-10-15T21:50:29.110Z", + "contributors": [ + "jsgao0", + "jackblackevo", + "roycrxtw", + "marktwtn" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Array/values": { + "modified": "2020-10-15T22:02:17.406Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/ArrayBuffer": { + "modified": "2019-03-24T00:11:11.336Z", + "contributors": [ + "jackblackevo", + "teoli", + "Kennyluck" + ] + }, + "Web/JavaScript/Reference/Global_Objects/ArrayBuffer/prototype": { + "modified": "2019-03-23T22:31:10.924Z", + "contributors": [ + "teoli", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/AsyncFunction": { + "modified": "2020-10-15T22:18:02.118Z", + "contributors": [ + "gamerslouis" + ] + }, + "Web/JavaScript/Reference/Global_Objects/BigInt": { + "modified": "2020-10-15T22:17:57.888Z", + "contributors": [ + "hmysjiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Boolean": { + "modified": "2019-03-23T22:06:45.293Z", + "contributors": [ + "jsgao0" + ] + }, + "Web/JavaScript/Reference/Global_Objects/DataView": { + "modified": "2019-03-23T22:31:20.723Z", + "contributors": [ + "edu1218", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Date": { + "modified": "2019-03-23T22:26:48.329Z", + "contributors": [ + "NoobTW", + "ddtet" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Date/UTC": { + "modified": "2019-03-23T22:26:04.734Z", + "contributors": [ + "ddtet" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Date/getDay": { + "modified": "2020-10-15T22:34:16.631Z", + "contributors": [ + "manny3" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Date/now": { + "modified": "2019-03-23T22:26:18.288Z", + "contributors": [ + "ddtet" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Date/prototype": { + "modified": "2019-03-23T22:26:36.902Z", + "contributors": [ + "ddtet" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Error": { + "modified": "2019-03-23T22:30:39.821Z", + "contributors": [ + "jsgao0", + "jackblackevo", + "josephmcasey" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Error/columnNumber": { + "modified": "2019-03-23T22:30:40.645Z", + "contributors": [ + "teoli", + "jerrychen1013" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Function": { + "modified": "2019-03-23T23:25:10.636Z", + "contributors": [ + "Calvin-Huang", + "jackblackevo", + "teoli", + "Bergi" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Function/apply": { + "modified": "2020-04-16T06:07:17.467Z", + "contributors": [ + "jacko1114", + "ayuha406645", + "Snailpool" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Function/bind": { + "modified": "2019-03-23T22:07:11.766Z", + "contributors": [ + "storyh66224", + "iigmir", + "nyngwang", + "aaaOOttOOaaa" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Function/call": { + "modified": "2019-03-23T23:25:00.404Z", + "contributors": [ + "jackblackevo", + "teoli", + "Zhen.Di-Lin" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Function/length": { + "modified": "2019-03-23T22:39:23.276Z", + "contributors": [ + "CYBAI", + "lessmind" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Function/prototype": { + "modified": "2019-03-23T22:30:13.335Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Infinity": { + "modified": "2020-10-15T21:47:39.391Z", + "contributors": [ + "iigmir", + "tooto1985", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/JSON": { + "modified": "2020-10-15T21:48:40.820Z", + "contributors": [ + "rolflo", + "iigmir", + "Ende93" + ] + }, + "Web/JavaScript/Reference/Global_Objects/JSON/parse": { + "modified": "2020-04-17T04:18:46.439Z", + "contributors": [ + "jacko1114", + "bigbitesaint", + "matthung0807", + "iigmir", + "kuolun" + ] + }, + "Web/JavaScript/Reference/Global_Objects/JSON/stringify": { + "modified": "2020-10-15T22:00:16.083Z", + "contributors": [ + "gyau97", + "SolomonKang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Map": { + "modified": "2020-10-15T21:51:34.887Z", + "contributors": [ + "othree", + "tainenko", + "jackblackevo", + "jsgao0" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Math": { + "modified": "2020-10-15T21:38:29.906Z", + "contributors": [ + "hmysjiang", + "jackblackevo", + "fscholz" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Math/abs": { + "modified": "2020-10-15T22:02:08.344Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Math/ceil": { + "modified": "2020-10-15T22:02:07.035Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Math/floor": { + "modified": "2020-10-15T22:02:06.863Z", + "contributors": [ + "ted31013", + "chochinlu", + "Hagen", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Math/max": { + "modified": "2020-10-15T22:03:35.771Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Math/pow": { + "modified": "2020-10-21T10:01:06.689Z", + "contributors": [ + "SvampK", + "iigmir" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Math/random": { + "modified": "2020-10-17T07:58:50.159Z", + "contributors": [ + "RocketSH" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Math/round": { + "modified": "2019-03-23T22:48:34.807Z", + "contributors": [ + "alk03073135" + ] + }, + "Web/JavaScript/Reference/Global_Objects/NaN": { + "modified": "2020-10-15T21:47:39.178Z", + "contributors": [ + "iigmir", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Number": { + "modified": "2019-03-23T22:28:21.747Z", + "contributors": [ + "jsgao0", + "sha1337" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Number/isFinite": { + "modified": "2020-10-15T22:03:26.099Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Number/isNaN": { + "modified": "2020-10-15T22:14:14.999Z", + "contributors": [ + "xguang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Number/prototype": { + "modified": "2020-10-15T21:56:46.161Z", + "contributors": [ + "jsgao0" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Number/toExponential": { + "modified": "2019-03-23T22:28:18.890Z", + "contributors": [ + "jsgao0", + "Shiyou" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Number/toFixed": { + "modified": "2020-11-18T05:27:56.696Z", + "contributors": [ + "Johnnychun", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object": { + "modified": "2020-08-22T05:49:39.644Z", + "contributors": [ + "+ono+", + "kuolun", + "jackblackevo", + "fscholz" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object/assign": { + "modified": "2020-10-15T21:51:19.104Z", + "contributors": [ + "manny3", + "lmr3796", + "mitivic", + "BruceLi", + "septemhill", + "jsgao0" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object/create": { + "modified": "2019-03-23T22:30:34.696Z", + "contributors": [ + "yuugou727", + "septemhill", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object/defineProperties": { + "modified": "2019-03-23T22:18:00.161Z", + "contributors": [ + "septemhill" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object/defineProperty": { + "modified": "2020-10-15T21:52:17.805Z", + "contributors": [ + "iigmir", + "PeterTing", + "btooom", + "jsgao0", + "septemhill" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object/freeze": { + "modified": "2020-10-15T22:00:25.623Z", + "contributors": [ + "leowu" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf": { + "modified": "2019-03-23T22:44:35.153Z", + "contributors": [ + "Shiyou", + "alk03073135" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty": { + "modified": "2019-03-23T22:48:25.371Z", + "contributors": [ + "Shiyou", + "alk03073135" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object/keys": { + "modified": "2019-03-23T22:30:46.813Z", + "contributors": [ + "yuugou727", + "roycrxtw", + "kdex", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object/preventExtensions": { + "modified": "2019-03-23T22:39:57.504Z", + "contributors": [ + "ALiangLiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object/proto": { + "modified": "2020-10-15T22:00:26.656Z", + "contributors": [ + "leowu" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Object/prototype": { + "modified": "2019-03-23T22:44:24.956Z", + "contributors": [ + "Shiyou", + "alk03073135" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Promise": { + "modified": "2020-10-15T21:50:59.376Z", + "contributors": [ + "iigmir", + "nyngwang", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Promise/all": { + "modified": "2020-10-15T21:51:02.408Z", + "contributors": [ + "nyngwang", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Promise/catch": { + "modified": "2020-10-15T21:51:02.070Z", + "contributors": [ + "nyngwang", + "Calvin-Huang", + "liuderchi", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Promise/finally": { + "modified": "2020-10-15T22:08:07.469Z", + "contributors": [ + "t7yang", + "l13013312333" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Promise/prototype": { + "modified": "2020-10-15T21:51:00.110Z", + "contributors": [ + "nyngwang", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Promise/race": { + "modified": "2020-10-15T21:51:03.822Z", + "contributors": [ + "james58899", + "nyngwang", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Promise/reject": { + "modified": "2020-10-15T21:56:03.979Z", + "contributors": [ + "nyngwang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Promise/resolve": { + "modified": "2020-10-15T21:56:02.943Z", + "contributors": [ + "nyngwang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Promise/then": { + "modified": "2020-10-15T21:51:00.608Z", + "contributors": [ + "nyngwang", + "jackblackevo", + "liuderchi" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Proxy": { + "modified": "2020-10-15T21:54:48.783Z", + "contributors": [ + "aChinKaiWu", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/RangeError": { + "modified": "2020-10-15T22:17:59.783Z", + "contributors": [ + "hmysjiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Reflect": { + "modified": "2019-03-23T22:11:01.546Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/RegExp": { + "modified": "2020-10-15T22:28:47.846Z", + "contributors": [ + "政衛" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Set": { + "modified": "2020-10-15T22:04:11.196Z", + "contributors": [ + "manny3", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Set/add": { + "modified": "2020-10-15T22:17:57.665Z", + "contributors": [ + "hmysjiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Set/clear": { + "modified": "2020-10-15T22:17:57.573Z", + "contributors": [ + "hmysjiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Set/delete": { + "modified": "2020-10-15T22:17:57.330Z", + "contributors": [ + "hmysjiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Set/entries": { + "modified": "2020-10-15T22:17:57.657Z", + "contributors": [ + "hmysjiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Set/has": { + "modified": "2020-10-15T22:17:58.294Z", + "contributors": [ + "hmysjiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/Set/values": { + "modified": "2020-10-15T22:18:02.187Z", + "contributors": [ + "hmysjiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/String": { + "modified": "2020-10-15T21:28:07.530Z", + "contributors": [ + "wbamberg", + "jackblackevo", + "jsgao0", + "iigmir", + "teoli", + "fscholz" + ] + }, + "Web/JavaScript/Reference/Global_Objects/String/match": { + "modified": "2020-10-15T22:05:42.504Z", + "contributors": [ + "YF-Tung", + "joshra" + ] + }, + "Web/JavaScript/Reference/Global_Objects/String/padStart": { + "modified": "2019-03-23T22:19:32.101Z", + "contributors": [ + "teoli", + "lychee.tw" + ] + }, + "Web/JavaScript/Reference/Global_Objects/String/prototype": { + "modified": "2020-10-15T22:02:57.359Z", + "contributors": [ + "SphinxKnight", + "bine139488" + ] + }, + "Web/JavaScript/Reference/Global_Objects/String/replace": { + "modified": "2020-10-15T21:28:07.269Z", + "contributors": [ + "oooooo", + "joshra", + "imrobinized", + "iigmir", + "jackblackevo", + "teoli", + "shyangs" + ] + }, + "Web/JavaScript/Reference/Global_Objects/String/toLowerCase": { + "modified": "2020-10-15T22:21:28.664Z", + "contributors": [ + "goden.cheng" + ] + }, + "Web/JavaScript/Reference/Global_Objects/TypedArray": { + "modified": "2020-10-15T21:47:14.859Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/URIError": { + "modified": "2020-10-15T22:17:56.619Z", + "contributors": [ + "hmysjiang" + ] + }, + "Web/JavaScript/Reference/Global_Objects/isNaN": { + "modified": "2020-10-15T21:51:29.113Z", + "contributors": [ + "bluetata", + "iigmir" + ] + }, + "Web/JavaScript/Reference/Global_Objects/null": { + "modified": "2020-03-12T19:44:24.320Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Global_Objects/parseInt": { + "modified": "2020-10-15T21:48:43.179Z", + "contributors": [ + "kcliu", + "DaiYaXu", + "iigmir", + "Shiyou" + ] + }, + "Web/JavaScript/Reference/Global_Objects/undefined": { + "modified": "2020-10-15T21:47:42.561Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Iteration_protocols": { + "modified": "2020-03-12T19:45:00.332Z", + "contributors": [ + "jackblackevo", + "nyngwang" + ] + }, + "Web/JavaScript/Reference/Lexical_grammar": { + "modified": "2020-10-15T22:00:27.351Z", + "contributors": [ + "leowu" + ] + }, + "Web/JavaScript/Reference/Operators": { + "modified": "2020-03-12T19:38:35.397Z", + "contributors": [ + "jackblackevo", + "cwlin0416", + "iigmir", + "teoli", + "Zhen.Di-Lin", + "ethertank" + ] + }, + "Web/JavaScript/Reference/Operators/Arithmetic_Operators": { + "modified": "2020-10-15T22:18:48.252Z", + "contributors": [ + "zivalee" + ] + }, + "Web/JavaScript/Reference/Operators/Bitwise_Operators": { + "modified": "2020-10-15T22:19:10.927Z", + "contributors": [ + "hmysjiang" + ] + }, + "Web/JavaScript/Reference/Operators/Comma_Operator": { + "modified": "2020-03-12T19:45:21.494Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Operators/Comparison_Operators": { + "modified": "2020-03-12T19:45:23.267Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Operators/Conditional_Operator": { + "modified": "2020-10-15T22:29:30.361Z", + "contributors": [ + "liaocCM" + ] + }, + "Web/JavaScript/Reference/Operators/Destructuring_assignment": { + "modified": "2020-10-15T21:51:08.444Z", + "contributors": [ + "DexterLeung", + "salagadoola", + "iigmir", + "jsgao0", + "jackblackevo", + "flyinglimao" + ] + }, + "Web/JavaScript/Reference/Operators/Logical_Operators": { + "modified": "2020-10-15T22:19:41.845Z", + "contributors": [ + "chunhh1012" + ] + }, + "Web/JavaScript/Reference/Operators/Object_initializer": { + "modified": "2020-03-12T19:46:20.319Z", + "contributors": [ + "cyanchu", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Operators/Operator_Precedence": { + "modified": "2020-03-12T19:45:00.937Z", + "contributors": [ + "KateWuSH", + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Operators/Optional_chaining": { + "modified": "2020-10-15T22:28:31.905Z", + "contributors": [ + "DexterLeung" + ] + }, + "Web/JavaScript/Reference/Operators/Spread_syntax": { + "modified": "2020-10-15T22:33:09.945Z", + "contributors": [ + "neko12377", + "kenchill" + ] + }, + "Web/JavaScript/Reference/Operators/async_function": { + "modified": "2020-10-15T22:12:38.986Z", + "contributors": [ + "extend1994" + ] + }, + "Web/JavaScript/Reference/Operators/await": { + "modified": "2020-03-12T19:45:41.284Z", + "contributors": [ + "kuolun", + "liuderchi", + "roycrxtw" + ] + }, + "Web/JavaScript/Reference/Operators/super": { + "modified": "2020-10-15T22:23:09.531Z", + "contributors": [ + "YunHan-Tsai" + ] + }, + "Web/JavaScript/Reference/Operators/this": { + "modified": "2020-10-15T21:48:46.137Z", + "contributors": [ + "iigmir", + "Rocker", + "chloewlin" + ] + }, + "Web/JavaScript/Reference/Operators/typeof": { + "modified": "2020-03-12T19:38:23.416Z", + "contributors": [ + "roycrxtw", + "jackblackevo", + "teoli", + "Johnny.Net" + ] + }, + "Web/JavaScript/Reference/Statements": { + "modified": "2020-10-15T21:22:18.510Z", + "contributors": [ + "simba-fs", + "Ethan.Lin", + "jackblackevo", + "stdio2017", + "cwlin0416", + "teoli", + "trevorh" + ] + }, + "Web/JavaScript/Reference/Statements/async_function": { + "modified": "2020-10-15T21:53:37.954Z", + "contributors": [ + "kevin10410", + "iigmir", + "weihanglo", + "liuderchi" + ] + }, + "Web/JavaScript/Reference/Statements/block": { + "modified": "2020-03-12T19:38:43.767Z", + "contributors": [ + "lin1987www", + "jackblackevo", + "teoli", + "irvinfly", + "tjjh89017" + ] + }, + "Web/JavaScript/Reference/Statements/break": { + "modified": "2020-10-15T21:25:32.531Z", + "contributors": [ + "jackblackevo", + "teoli", + "Littlebtc", + "tjjh89017" + ] + }, + "Web/JavaScript/Reference/Statements/const": { + "modified": "2020-10-15T21:58:04.721Z", + "contributors": [ + "iigmir", + "KevinHuang" + ] + }, + "Web/JavaScript/Reference/Statements/debugger": { + "modified": "2020-10-15T22:00:23.902Z", + "contributors": [ + "iigmir" + ] + }, + "Web/JavaScript/Reference/Statements/export": { + "modified": "2020-10-15T21:54:04.868Z", + "contributors": [ + "wangchou", + "iigmir", + "DalaneGarmin", + "MOSapeizer" + ] + }, + "Web/JavaScript/Reference/Statements/for...in": { + "modified": "2020-03-12T19:39:20.179Z", + "contributors": [ + "jackblackevo", + "teoli", + "shyangs" + ] + }, + "Web/JavaScript/Reference/Statements/function*": { + "modified": "2020-10-15T21:45:50.090Z", + "contributors": [ + "iendeavor", + "jackblackevo", + "DaomingC", + "kdex", + "ALiangLiang", + "tom76kimo" + ] + }, + "Web/JavaScript/Reference/Statements/if...else": { + "modified": "2020-12-06T07:23:20.735Z", + "contributors": [ + "rei1997", + "paiyuliu", + "jackblackevo", + "willynpi" + ] + }, + "Web/JavaScript/Reference/Statements/import": { + "modified": "2020-10-15T21:53:11.297Z", + "contributors": [ + "iigmir", + "freddy50806", + "pololin", + "kweisamx", + "RichCharlie", + "DuckBreeder" + ] + }, + "Web/JavaScript/Reference/Statements/label": { + "modified": "2020-10-15T22:15:49.920Z", + "contributors": [ + "willh" + ] + }, + "Web/JavaScript/Reference/Statements/let": { + "modified": "2020-10-15T21:45:04.003Z", + "contributors": [ + "ShawnLin", + "Zhang-Junzhi", + "iigmir", + "zxa011023", + "YamiOdymel", + "ALiangLiang" + ] + }, + "Web/JavaScript/Reference/Statements/return": { + "modified": "2020-10-15T22:02:41.359Z", + "contributors": [ + "iigmir" + ] + }, + "Web/JavaScript/Reference/Statements/switch": { + "modified": "2020-10-15T22:25:04.906Z", + "contributors": [ + "iigmir", + "Lazine" + ] + }, + "Web/JavaScript/Reference/Statements/throw": { + "modified": "2020-03-12T19:45:24.946Z", + "contributors": [ + "jackblackevo" + ] + }, + "Web/JavaScript/Reference/Statements/var": { + "modified": "2020-03-12T19:38:31.590Z", + "contributors": [ + "jackblackevo", + "teoli", + "Johnny.Net" + ] + }, + "Web/JavaScript/Reference/Strict_mode": { + "modified": "2020-03-12T19:46:40.566Z", + "contributors": [ + "WellyHong", + "Aries0d0f", + "DarkNami", + "MOSapeizer" + ] + }, + "Web/JavaScript/Reference/Template_literals": { + "modified": "2020-10-15T21:53:17.228Z", + "contributors": [ + "jackblackevo", + "xsfishxs" + ] + }, + "Web/JavaScript/Shells": { + "modified": "2020-03-12T19:45:29.748Z", + "contributors": [ + "JianHuaHe" + ] + }, + "Web/JavaScript/Typed_arrays": { + "modified": "2020-03-12T19:36:15.816Z", + "contributors": [ + "ballfish", + "jackblackevo", + "roycrxtw", + "teoli", + "Kennyluck" + ] + }, + "Web/Manifest": { + "modified": "2020-11-18T03:32:37.890Z", + "contributors": [ + "SphinxKnight", + "wifr1126q", + "t7yang", + "BwayCer" + ] + }, + "Web/MathML": { + "modified": "2019-03-23T23:22:17.865Z", + "contributors": [ + "sailplaneTW" + ] + }, + "Web/MathML/Authoring": { + "modified": "2019-03-23T23:22:11.037Z", + "contributors": [ + "fred.wang", + "sailplaneTW" + ] + }, + "Web/Media": { + "modified": "2019-03-18T21:40:43.859Z", + "contributors": [ + "willynpi", + "learnfromfail" + ] + }, + "Web/Media/Formats": { + "modified": "2020-02-18T06:39:28.429Z", + "contributors": [ + "Sheppy" + ] + }, + "Web/Media/Formats/Containers": { + "modified": "2020-02-19T03:38:30.649Z", + "contributors": [ + "JamesGoler" + ] + }, + "Web/OpenSearch": { + "modified": "2019-03-23T22:00:23.747Z", + "contributors": [ + "jackblackevo", + "iigmir", + "teoli", + "Mgjbot", + "Sam268276", + "BobChao" + ] + }, + "Web/Progressive_web_apps": { + "modified": "2019-03-18T20:52:03.723Z", + "contributors": [ + "chrisdavidmills", + "iigmir" + ] + }, + "Web/Reference": { + "modified": "2019-03-23T23:29:16.937Z", + "contributors": [ + "jackblackevo", + "Somnlent", + "Sheppy" + ] + }, + "Web/Reference/API": { + "modified": "2019-03-23T23:05:52.036Z", + "contributors": [ + "jackblackevo", + "wildsky" + ] + }, + "Web/SVG": { + "modified": "2019-01-16T17:22:30.480Z", + "contributors": [ + "ethertank", + "happysadman" + ] + }, + "Web/SVG/Attribute": { + "modified": "2019-03-23T23:26:15.897Z", + "contributors": [ + "Jeremie" + ] + }, + "Web/SVG/Attribute/fill-rule": { + "modified": "2019-03-23T23:26:22.091Z", + "contributors": [ + "panallen" + ] + }, + "Web/SVG/Attribute/stroke-dashoffset": { + "modified": "2019-03-20T22:42:12.300Z", + "contributors": [ + "EnRico.Lam", + "bing-Guo" + ] + }, + "Web/SVG/Tutorial": { + "modified": "2019-03-23T23:35:01.636Z", + "contributors": [ + "Snailpool", + "sunghau", + "ethertank", + "ziyunfei", + "Dx.Yang" + ] + }, + "Web/SVG/Tutorial/Fills_and_Strokes": { + "modified": "2019-03-23T23:34:13.639Z", + "contributors": [ + "jackblackevo", + "ethertank", + "Dx.Yang" + ] + }, + "Web/SVG/Tutorial/Getting_Started": { + "modified": "2019-03-23T23:34:51.093Z", + "contributors": [ + "jackblackevo", + "Kustz", + "ethertank", + "Dx.Yang" + ] + }, + "Web/SVG/Tutorial/Gradients": { + "modified": "2019-03-23T23:34:17.990Z", + "contributors": [ + "jackblackevo", + "iigmir", + "ethertank", + "Dx.Yang" + ] + }, + "Web/SVG/Tutorial/Introduction": { + "modified": "2019-03-23T23:34:52.348Z", + "contributors": [ + "ethertank", + "Dx.Yang" + ] + }, + "Web/SVG/Tutorial/Patterns": { + "modified": "2019-03-23T23:34:09.915Z", + "contributors": [ + "jackblackevo", + "ethertank", + "Dx.Yang" + ] + }, + "Web/SVG/Tutorial/Positions": { + "modified": "2019-03-23T23:34:48.671Z", + "contributors": [ + "Kustz", + "ethertank", + "ziyunfei", + "Dx.Yang" + ] + }, + "Web/SVG/Tutorial/路径": { + "modified": "2019-05-06T13:50:22.523Z", + "contributors": [ + "Snailpool", + "ethertank", + "ziyunfei", + "Dx.Yang" + ] + }, + "Web/SVG/教學": { + "modified": "2019-01-16T14:42:54.040Z", + "contributors": [ + "ethertank", + "happysadman" + ] + }, + "Web/Security": { + "modified": "2019-09-10T16:50:03.503Z", + "contributors": [ + "SphinxKnight", + "jackblackevo" + ] + }, + "Web/Security/Insecure_passwords": { + "modified": "2019-03-20T14:57:01.510Z", + "contributors": [ + "BaseChipmunk4", + "iigmir", + "jwhitlock" + ] + }, + "Web/Security/Mixed_content": { + "modified": "2019-03-23T23:04:08.690Z", + "contributors": [ + "jackblackevo", + "iigmir", + "a780201", + "wildsky", + "Asheesh" + ] + }, + "Web/Security/Mixed_content/How_to_fix_website_with_mixed_content": { + "modified": "2019-03-23T23:04:13.940Z", + "contributors": [ + "jackblackevo", + "iigmir", + "wildsky" + ] + }, + "Web/Security/Same-origin_policy": { + "modified": "2020-09-01T23:06:58.364Z", + "contributors": [ + "JustBelieveMe", + "jackblackevo", + "MashKao", + "teoli", + "foxbrush" + ] + }, + "Web/Security/Weak_Signature_Algorithm": { + "modified": "2019-04-23T04:20:20.884Z", + "contributors": [ + "jackblackevo", + "15182254444", + "KINGKKALING", + "Sbabey", + "leVirve" + ] + }, + "Web/Tutorials": { + "modified": "2019-09-03T07:07:31.640Z", + "contributors": [ + "lalasoqTW", + "katsmin", + "mgrn", + "KevinHuang.lds", + "sailplaneTW" + ] + }, + "Web/性能": { + "modified": "2019-12-05T10:33:09.898Z", + "contributors": [ + "zhaoy88" + ] + }, + "WebAPI": { + "modified": "2019-03-23T23:28:55.141Z", + "contributors": [ + "wbamberg", + "fscholz", + "MashKao", + "sailplaneTW" + ] + }, + "WebAPI/Permissions": { + "modified": "2019-03-23T23:28:38.156Z", + "contributors": [ + "MashKao" + ] + }, + "WebAssembly": { + "modified": "2020-10-15T22:04:56.309Z", + "contributors": [ + "Aries0d0f" + ] + }, + "WebSockets": { + "modified": "2019-10-10T16:56:50.765Z", + "contributors": [ + "teoli", + "RudyLu", + "Kennyluck" + ] + }, + "WebSockets/WebSockets_reference": { + "modified": "2019-03-24T00:11:12.133Z", + "contributors": [ + "teoli", + "Kennyluck" + ] + }, + "WebSockets/WebSockets_reference/CloseEvent": { + "modified": "2019-03-24T00:11:09.722Z", + "contributors": [ + "teoli", + "Kennyluck" + ] + }, + "WebSockets/WebSockets_reference/MessageEvent": { + "modified": "2019-03-24T00:11:11.117Z", + "contributors": [ + "teoli", + "Kennyluck" + ] + }, + "WebSockets/WebSockets_reference/WebSocket": { + "modified": "2019-03-24T00:11:12.042Z", + "contributors": [ + "NoobTW", + "YamiOdymel", + "teoli", + "Kennyluck" + ] + }, + "WebSockets/Writing_WebSocket_client_applications": { + "modified": "2019-03-24T00:11:12.716Z", + "contributors": [ + "andretw", + "Shiyou", + "ziyunfei", + "Kennyluck" + ] + }, + "Web_development": { + "modified": "2019-01-16T13:10:01.650Z", + "contributors": [ + "teoli", + "Sonrisa" + ] + }, + "Web_開發": { + "modified": "2019-03-24T00:01:02.674Z", + "contributors": [ + "happysadman" + ] + }, + "Web_開發/Historical_artifacts_to_avoid": { + "modified": "2019-03-23T22:48:17.115Z", + "contributors": [ + "iigmir", + "CodinCat", + "irvinfly", + "slhuang" + ] + }, + "XHTML": { + "modified": "2019-03-24T00:01:02.785Z", + "contributors": [ + "ethertank", + "happysadman" + ] + }, + "XPCNativeWrapper": { + "modified": "2019-03-24T00:01:38.163Z", + "contributors": [ + "ethertank", + "Clydewu" + ] + }, + "zh-tw": { + "modified": "2019-01-16T13:51:15.538Z", + "contributors": [ + "CQD" + ] + }, + "參與_Mozilla_專案": { + "modified": "2019-03-24T00:01:01.475Z", + "contributors": [ + "happysadman" + ] + }, + "建立擴充套件": { + "modified": "2019-01-16T16:02:32.252Z", + "contributors": [ + "Josesun", + "Haka" + ] + } +} \ No newline at end of file diff --git a/files/zh-tw/archive/add-ons/developing_add-ons/index.html b/files/zh-tw/archive/add-ons/developing_add-ons/index.html new file mode 100644 index 0000000000..048ba6dd7e --- /dev/null +++ b/files/zh-tw/archive/add-ons/developing_add-ons/index.html @@ -0,0 +1,50 @@ +--- +title: 開發附加元件 +slug: Archive/Add-ons/Developing_add-ons +translation_of: Archive/Add-ons/Developing_add-ons +--- +

大多數的 Mozilla 所開發的軟件,主要是透過「附加元件」來擴充其工能。 「附加元件」主要分成三大類:「擴充套件(Extensions)」 、「外掛程式(Plugin-ins)」及「佈景主題(Themes)」。本文的主要目的,是去指導及提供你所需的資訊用來去製作 Firefox 、 Thunderbird ...等等的 Mozilla 的軟體上的「附加元件」,以及提交及發佈你所製作的「附加元件」的方法。

+ + + + + + + + + + +
+

附加元件主題

+
+
+
+ 提交附加元件至 AMO
+
+ Provides helpful information for add-on developers to help them properly package and deliver their add-ons.  This includes information about addons.mozilla.org, Mozilla's add-on distribution web site.
+
+ 擴充套件
+
+ Extensions add new functionality to Mozilla applications such as Firefox, SeaMonkey and Thunderbird. They can add anything from a toolbar button to a completely new feature.
+
+ 外掛程式
+
+ Information about how to create plug-ins, which are binary components that let Mozilla based software display content they can't handle natively.
+
+
+
+
+ 佈景主題
+
+ Themes let users customize the appearance of the user interface presented by Mozilla-based applications.
+
+ 搜尋引擎外掛
+
+ Firefox supports search engine plug-ins, which enable the search box to support different search engines.
+
+ Mozilla 平台
+
+ Information about the Mozilla platform, including all of its APIs and technologies, as well as how to use them in your own projects.
+
+
+

 

diff --git a/files/zh-tw/archive/add-ons/index.html b/files/zh-tw/archive/add-ons/index.html new file mode 100644 index 0000000000..caac45ae4c --- /dev/null +++ b/files/zh-tw/archive/add-ons/index.html @@ -0,0 +1,8 @@ +--- +title: Add-ons +slug: Archive/Add-ons +translation_of: Archive/Add-ons +--- +

In progress. Archived add-ons documentation.

+ +

{{SubpagesWithSummaries}}

diff --git a/files/zh-tw/archive/add-ons/supporting_search_suggestions_in_search_plugins/index.html b/files/zh-tw/archive/add-ons/supporting_search_suggestions_in_search_plugins/index.html new file mode 100644 index 0000000000..451d3dc91c --- /dev/null +++ b/files/zh-tw/archive/add-ons/supporting_search_suggestions_in_search_plugins/index.html @@ -0,0 +1,51 @@ +--- +title: 讓搜尋模組支援搜尋建議 +slug: Archive/Add-ons/Supporting_search_suggestions_in_search_plugins +tags: + - 搜尋模組 +translation_of: Archive/Add-ons/Supporting_search_suggestions_in_search_plugins +--- +

MozSearch 格式的搜尋模組可以支援搜尋建議,當使用者在搜尋欄中逐字鍵入關鍵詞時,Firefox 2 將依據搜尋模組內指定的 URL 送出查詢並取回結果。 +

取回結果之後,Firefox 將其顯示為一個下拉選單,讓使用者從中挑選搜尋引擎建議的關鍵詞。如果使用者繼續輸入關鍵詞,則會重新取回結果並更新選單。 +

Firefox 2 中內建的 Yahoo! 與 Google 搜尋模組都支援搜尋建議功能。 +

+

搜尋模組的工作

+

搜尋模組必須額外定義一個 <Url> 元素以便支援搜尋建議功能,此元素之 type 屬性需設定為 "application/x-suggestions+json"。支援搜尋建議功能的模組都會有兩個 <Url> 元素,另一個元素指定主要的 code>text/html</code> 搜尋 URL。 +

舉例來說,Yahoo! 搜尋模組的 <Url> 長得像這樣: +

+
<Url type="application/x-suggestions+json" template="http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}"/>
+
+

如果使用者在搜尋欄中輸入「fir」,則 Firefox 會將此 URL 的 {searchTerms} 代換為「fir」後送出搜尋: +

+
<Url type="application/x-suggestions+json" template="http://ff.search.yahoo.com/gossip?output=fxjson&command=fir"/>
+
+

搜尋回來的結果將構成建議詞清單。 +

製作搜尋模組的方法可以參考製作 MozSearch 搜尋模組一文。 +

+

伺服器端的工作

+

搜尋建議功能的重點在伺服端的程式,如果你是網站設計師而想支援搜尋建議功能,則必須實做出依據搜尋字串給予進一步搜尋建議詞彙、並以 JSON 格式傳回的功能。 +

當瀏覽器想取回搜尋字串時,會對 <Url> 元素指定的 URL 送出 HTTP GET 要求;此時伺服器則需依據字串決定相關字詞為何,並以 JSON 傳回 2 到 4 個建議字詞,如下: +

+
查詢字串 +
JSON 的第一個元素是原始查詢字串,這樣 Firefox 可以得知傳回值是否與目前查閱的字詞相符。 +
+
建議字詞列表 +
建議字詞的陣列,此陣列需以「{{ mediawiki.external('」及「') }}」括起,例如 <tt>{{ mediawiki.external('\"建議詞 1\", \"建議詞 2\", \"建議詞 3\", \"建議詞 4\"') }}</tt> +
+
說明 +
此元素為選用,亦為一個陣列,分別針對每個「建議字詞列表」的建議詞設定說明,其中可以是任何搜尋引擎想提供瀏覽器顯示的資訊,例如此建議詞有多少搜尋結果等等。 +
+
Firefox 2 尚不支援「說明」功能,會忽略此傳回值。
+
查詢網址 +
此元素為選用,還是一個陣列,內容是各建議詞的替代網址。打個比方:如果除搜尋結果頁面之外還想直接提供建議詞的地圖連結,那就可以將地圖的網址列在此陣列裡。 +
+
若沒有額外指定此元素,則將依據搜尋模組 XML 中的 <Url> 元素決定查詢網址。 +
+
Firefox 2 尚不支援「查詢網址」功能,會忽略此傳回值。
+

也就是說,若搜尋詞為「fir」且不傳回說明及查詢網址,則傳回的 JSON 應該是長這樣: +

+
["fir", ["firefox", "first choice", "mozilla firefox"]]
+
+

在此範例中只涵括查詢字串及建議字詞列表兩元素,其他選用的都不列入。 +

雖然建議的字詞想放多少就可以放多少,但由於每次使用者多打一個字都會查詢一次,所以還是有所限度比較穩當。至於怎麼依據使用者的要求提出建議,就全交給你自己決定了。 +

{{ languages( { "ca": "ca/Implementaci\u00f3_de_suggeriments_en_els_connectors_de_cerca", "en": "en/Supporting_search_suggestions_in_search_plugins", "es": "es/Permitir_sugerencias_en_los_plugins_de_b\u00fasqueda", "fr": "fr/Gestion_de_suggestions_dans_les_plugins_de_recherche", "it": "it/Supportare_i_suggerimenti_nei_plugin_di_ricerca", "ja": "ja/Supporting_search_suggestions_in_search_plugins", "pl": "pl/Wsparcie_dla_podpowiedzi_wyszukiwania_w_wyszukiwarkach" } ) }} diff --git a/files/zh-tw/archive/add-ons/working_with_multiprocess_firefox/index.html b/files/zh-tw/archive/add-ons/working_with_multiprocess_firefox/index.html new file mode 100644 index 0000000000..8b685c379e --- /dev/null +++ b/files/zh-tw/archive/add-ons/working_with_multiprocess_firefox/index.html @@ -0,0 +1,235 @@ +--- +title: Working with multiprocess Firefox +slug: Archive/Add-ons/Working_with_multiprocess_Firefox +translation_of: Archive/Add-ons/Working_with_multiprocess_Firefox +--- +
+

這篇文章提供給 Firefox 擴充套件開發者;文中概述了如何讓擴充套件可以執行於多行程的 Firefox.

+
+

在多行程的 Firefox 之前的版本, chrome code (including code inserted by extensions) 和 content 執行於同一作業系統行程中,所以擴充套件可以直接存取 content:

+
gBrowser.selectedBrowser.contentDocument.body.innerHTML = "replaced by chrome code";
+

然而,在多行程的 Firefox (也稱為 Electrolysis 或 E10S),套件的程式碼與 content 將執行於不同的行程中,因此不再可能直接地存取。

+

取而代之地, the extension will need to factor code that touches content into separate scripts that are called frame scripts. Frame scripts 執行在 content 行程,並可以直接存取 content. Frame scripts 藉由 message-passing API 和套件其餘的部份通訊。

+

當套件程式碼(執行於 chrome 行程中)向套件的 frame script(執行於 content 行程中) 傳訊時,必須使用非同步訊息。

+

content 行程允許向 chrome 行程傳遞同步或非同步訊息,但是,非同步通訊是較好的選擇。

+

For more details on using the message manager and content scripts, refer to the message manager guide. The rest of this article explains how to work out if you're affected or not, provides an overview of the sorts of changes that are needed, then walks through the process of porting some simple extension patterns so they work properly with multiprocess Firefox.

+

確認你是否受到相容性影響

+

As a rule:

+ +

To know for sure, you need to test it, and setting that up is a two-step process:

+ +

Now you'll be able to test your extension in multiprocess Firefox, with no compatibility shims. At the moment you can't actually install extensions in multiprocess Firefox, so you have to install the extension, then switch on multiprocess support. This is being tracked as bug 1055808.

+

Updating your code

+

The general approach to updating your code is:

+ +

There are more details on this in the message manager documentation.

+

Backwards compatibility of the new APIs

+

With multiprocess support turned off, the e10s messaging APIs are still available and functional. They have been available in one form or another since Firefox 4; however, the original APIs are different than the current ones. Some known differences:

+ +

You should test your changes not only in nightlies with multiprocess support turned on, but also in releases you intend to support with multiprocess support turned off.

+

Examples

+

This section walks through the process of porting a few different sorts of extension. The extensions are all extremely simple, and are intended to represent fundamental extension patterns that require different handling in multiprocess Firefox.

+

You can find all the source code for these examples in the e10s-example-addons GitHub repository.

+

Run a script in all pages

+
+

See the code for this example.

+
+

The first extension runs some code on every page load. The code doesn't need to interact with any other part of the extension: it just makes some predetermined modification to the page. In this case it adds a border to the document's body.

+

It does this by attaching to a XUL overlay a version of the "On page load" code snippet:

+
var myExtension = {
+    init: function() {
+        // The event can be DOMContentLoaded, pageshow, pagehide, load or unload.
+        if(gBrowser) gBrowser.addEventListener("DOMContentLoaded", this.onPageLoad, false);
+    },
+    onPageLoad: function(aEvent) {
+        var doc = aEvent.originalTarget; // doc is document that triggered the event
+        if (doc.nodeName != "#document") return; // only documents
+        // make whatever modifications you want to doc
+        doc.body.style.border = "5px solid blue";
+    }
+}
+
+window.addEventListener("load", function load(event){
+    window.removeEventListener("load", load, false); //remove listener, no longer needed
+    myExtension.init();
+},false);
+

Because this code accesses web content directly, it won't work in multiprocess Firefox.
+

+

Porting to the message manager

+

To port this example using the message manager, we can put all the meat of the add-on in a frame script:

+
// frame-script.js
+// will run in the content process
+
+addEventListener("DOMContentLoaded", function(event) {
+  var doc = event.originalTarget;
+  if (doc.nodeName != "#document") return; // only documents
+  doc.body.style.border = "5px solid red";
+});
+
+

We'll register a chrome:// URL for the frame script:

+
// chrome.manifest
+
+content    modify-all-pages    chrome/content/
+
+

The main script, that we attach to the XUL overlay, is just a stub that uses the global message manager to load the frame script into each tab:

+
// chrome script
+// will run in the chrome process
+
+var globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
+  .getService(Ci.nsIMessageListenerManager);
+
+globalMM.loadFrameScript("chrome://modify-all-pages/content/frame-script.js", true);
+

+

Porting to the Add-on SDK

+

A good alternative for an extension like this is to port to the Add-on SDK. The Add-on SDK includes a module called page-mod which is designed to load scripts into web pages. The Add-on SDK calls these scripts content scripts.

+

In this case the main extension code creates a page-mod to load a content script into every page loaded by the user:

+
// main.js
+
+var pageMod = require("sdk/page-mod");
+var self = require("sdk/self");
+
+pageMod.PageMod({
+  include: "*",
+  contentScriptFile: self.data.url("modify-all-pages.js")
+});
+

The content script can modify the page directly:

+
// modify-all-pages.js - content script
+
+document.body.style.border = "5px solid green";
+

Run a script in the active tab

+
+

See the code for this example.

+
+

The example demonstrates how an extension can:

+ +

The example is a restartless extension that adds a button using the CustomizableUI module. When the user clicks the button, the extension runs some code that modifies the current tab. The basic infrastructure is taken from the Australis "Hello World" extension written by Jorge Villalobos.
+
+ What the code actually does is: find any <img> elements and replace their src with a link to a silly GIF randomly chosen from a list hardcoded into the extension. The silly gifs are taken from the list in the Whimsy extension.

+

The first version accesses the page directly, so it's not multiprocess compatible:

+
// bootstrap.js
+
+let Gifinate = {
+  init : function() {
+    let io =
+      Cc["@mozilla.org/network/io-service;1"].
+        getService(Ci.nsIIOService);
+
+    // the 'style' directive isn't supported in chrome.manifest for bootstrapped
+    // extensions, so this is the manual way of doing the same.
+    this._ss =
+      Cc["@mozilla.org/content/style-sheet-service;1"].
+        getService(Ci.nsIStyleSheetService);
+    this._uri = io.newURI("chrome://gifinate/skin/toolbar.css", null, null);
+    this._ss.loadAndRegisterSheet(this._uri, this._ss.USER_SHEET);
+
+    // create widget and add it to the main toolbar.
+    CustomizableUI.createWidget(
+      { id : "gifinate-button",
+        defaultArea : CustomizableUI.AREA_NAVBAR,
+        label : "Gifinate",
+        tooltiptext : "Gifinate!",
+        onCommand : function(aEvent) {
+          Gifinate.replaceImages(aEvent.target.ownerDocument.defaultView.content.document);
+        }
+      });
+  },
+
+  replaceImages : function(contentDocument) {
+      let images = contentDocument.getElementsByTagName("img");
+      for (var i = 0; i < images.length; ++i) {
+        let gif = this.gifs[Math.floor(Math.random() * this.gifs.length)];
+        images[i].src = gif;
+      }
+    },
+

+

Porting to the message manager

+

To port this example to the message manager we'll make onCommand load a frame script into the current <browser>, then listen for "request-gifs" messages from the frame script. The "request-gifs" message is expected to contain the number of GIFs we need for this page: the message listener retrieves and returns that many GIFs.

+
// bootstrap.js
+// will run in the chrome process
+
+let Gifinate = {
+  init : function() {
+    let io =
+      Cc["@mozilla.org/network/io-service;1"].
+        getService(Ci.nsIIOService);
+
+    // the 'style' directive isn't supported in chrome.manifest for bootstrapped
+    // extensions, so this is the manual way of doing the same.
+    this._ss =
+      Cc["@mozilla.org/content/style-sheet-service;1"].
+        getService(Ci.nsIStyleSheetService);
+    this._uri = io.newURI("chrome://gifinate/skin/toolbar.css", null, null);
+    this._ss.loadAndRegisterSheet(this._uri, this._ss.USER_SHEET);
+
+    // create widget and add it to the main toolbar.
+    CustomizableUI.createWidget(
+      { id : "gifinate-button",
+        defaultArea : CustomizableUI.AREA_NAVBAR,
+        label : "Gifinate Button",
+        tooltiptext : "Gifinate!",
+        onCommand : function(aEvent) {
+          Gifinate.replaceImages(aEvent.target.ownerDocument);
+        }
+      });
+  },
+
+  replaceImages : function(xulDocument) {
+    var browserMM = xulDocument.defaultView.gBrowser.selectedBrowser.messageManager;
+    browserMM.loadFrameScript("chrome://gifinate/content/frame-script.js", false);
+    browserMM.addMessageListener("request-gifs", Gifinate.getGifs);
+  },
+
+  getGifs : function(message) {
+    var gifsToReturn = new Array(message.data);
+    for (var i = 0; i < gifsToReturn.length; i++) {
+      let gif = this.gifs[Math.floor(Math.random() * this.gifs.length)];
+      gifsToReturn[i] = gif;
+    }
+    return gifsToReturn;
+  },
+
+

Again, we need to register a chrome:// URL for the frame script:

+
// chrome.manifest
+
+content gifinate frame-script.js
+

In the frame script, we get all the <img> elements and send the "request-gifs" message to the main add-on code. Because this is a frame script we can make it a synchronous message, and update the src attributes with the value it returns:

+
// frame-script.js
+// will run in the content process
+
+var images = content.document.getElementsByTagName("img");
+var response = sendSyncMessage("request-gifs", images.length);
+var gifs = response[0];
+
+for (var i = 0; i < images.length; ++i) {
+  images[i].src = gifs[i];
+}
+

The overall flow of the add-on now looks like this:
+

+

Known bugs

+

This is a list of open bugs likely to affect add-on developers migrating to multiprocess Firefox:

+ diff --git a/files/zh-tw/archive/apps/advanced_topics/index.html b/files/zh-tw/archive/apps/advanced_topics/index.html new file mode 100644 index 0000000000..1c0c5a0820 --- /dev/null +++ b/files/zh-tw/archive/apps/advanced_topics/index.html @@ -0,0 +1,76 @@ +--- +title: 進階主題 +slug: Archive/Apps/Advanced_topics +translation_of: Archive/Apps/Advanced_topics +--- +

這些文章提供了額外的資訊,關於更進階的開放網頁程式主題。

+
+
+

Apps 架構文件

+
+
+ 應用程式的架構
+
+ 大致介紹開放網頁程式計畫的設計和實作之下的架構。
+
+ 在不同平台安裝 app 的細節
+
+ 有關應用程式在特定裝置或系統上安裝或執行時有些微的差異;這篇文章會幫您了解這段差異。
+
+ Android上的開放網路應用程式
+
+ 有關開發及測試在Android上運作的開放網路應用程式的事。
+
+ App runtime release notes
+
+ 不同的平台上,網頁 app 執行時的 release notes。
+
+

其他文件

+
+
+ 建立商店
+
+ 如果您要建立自己的商店來販售及發佈開放網頁程式,這些資訊可能可以幫助您。
+
+

View All...

+
+
+
Tools for app developers
+ +
Technology reference documentation
+ +
Getting help from the community
+

If you still aren't sure how to do what you're trying to get done, feel free to join the conversation!

+ +

Don't forget about the netiquette...

+
+
+

 

diff --git a/files/zh-tw/archive/apps/index.html b/files/zh-tw/archive/apps/index.html new file mode 100644 index 0000000000..89e9dac3d6 --- /dev/null +++ b/files/zh-tw/archive/apps/index.html @@ -0,0 +1,8 @@ +--- +title: Apps +slug: Archive/Apps +translation_of: Archive/Apps +--- +

In progress. This page includes archived content for Apps, including obsolete web app content, Firefox OS app-related content, etc.

+ +

{{SubpagesWithSummaries}}

diff --git a/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/contacts/index.html b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/contacts/index.html new file mode 100644 index 0000000000..431f85c5f6 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/contacts/index.html @@ -0,0 +1,71 @@ +--- +title: 聯絡人資訊 +slug: Archive/B2G_OS/3rd_Party_App_Developer_Guide/Contacts +--- +

聯絡人資訊 (contacts)

+

Contacts API 讓您可以取得使用者手機中所儲存的聯絡人列表、聯絡人姓名、電話、… 等資訊。
+ 由於它牽涉到使用者私密資訊,目前僅開放審查通過的應用(privileged/certified)能夠使用這個 API。您的應用必須提出使用這個 API 的聲明,並且通過審查方可使用。
+
+ 權限宣告:分為 "readonly", "readwrite", "readcreate" 三種級別,分別代表「只讀取」、「讀取與修改」、「讀取與新增」。您可依照應用需求作適當的權限宣告。

+
"permissions": {
+  "contacts":{ "access": "readonly" }
+}
+

1. 讀取聯絡人列表

+
    var options = {
+      sortBy: 'familyName',
+      sortOrder: 'ascending'
+    };
+    var request = navigator.mozContacts.find(options);
+    request.onsuccess = function findSuccess() {
+      var firstContact = request.result[0];
+      console.log('name' + firstContact.name);
+      console.log('tel number' + firstContact.tel[0].value);
+      console.log('update time' + new Date(firstContact.updated));
+    };
+
+    request.onerror = function findError() {
+      console.warn('Error: cannot find any contacts - ' + request.error.name);
+    };
+

2. 新增聯絡人

+
    var myContact = {
+      'name': 'Alice Wang',
+      'givenName': 'Alice',
+      'familyName': 'Wang',
+      'tel': [{'value': '0912345678'}]
+    };
+    var contact = new mozContact();
+    contact.init(myContact);
+    var request = navigator.mozContacts.save(contact);
+    request.onerror = function onerror() {
+      console.warn('Error: save contact - ' + request.error.name);
+    }; 
+

3. 修改聯絡人資訊

+
    var options = {
+      filterBy: ['tel', 'givenName', 'familyName'],
+      filterOp: 'contains',
+      filterValue: 'Alice'
+    };
+    var request = navigator.mozContacts.find(options);
+    request.onsuccess = function findSuccess() {
+      var contact = req.result[0];
+      contact.tel[0].value = '0987654321';
+      var requestUpdate = navigator.mozContacts.save(contact);
+      requestUpdate.onerror = function onerror() {
+        console.warn('Error: update contact - ' + requestUpdate.error.name);
+      };
+    }; 
+

4. 刪除聯絡人

+
    var options = {
+      filterBy: ['id'],
+      filterOp: 'equals',
+      filterValue: '0987654321'
+    };
+    var request = navigator.mozContacts.find(options);
+    request.onsuccess = function findSuccess() {
+      var contact = req.result[0];
+      var requestRemove = navigator.mozContacts.remove(contact);
+      requestRemove.onerror = function onerror() {
+        console.warn('Error: remove contact - ' + requestRemove.error.name);
+      };
+    }; 
+

 

diff --git a/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/device_storage/index.html b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/device_storage/index.html new file mode 100644 index 0000000000..d8c6fd2916 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/device_storage/index.html @@ -0,0 +1,111 @@ +--- +title: 儲存裝置資訊 +slug: Archive/B2G_OS/3rd_Party_App_Developer_Guide/Device_Storage +--- +

儲存裝置資訊 (Device Storage)

+

DeviceStorage API 提供 SD 記憶卡內的資料存取介面,可讀取圖片檔、聲音檔、影片檔,與 SD 記憶卡的其他檔案,並檢視 SD 記憶卡空間的使用率。
+ 由於牽涉到使用者的儲存裝置資訊,目前僅開放 Privileged/Certified App 能夠使用此 API。你的 App 必須提出「使用此 API」的聲明,並且通過審查方可使用。
+
+ 權限宣告:依照檔案類型 (圖片、影片、聲音、其他) 而有不同宣告方式,這種宣告另分為「readonly」、「readwrite」、「readcreate」共 3 種級別,分別代表「唯讀」、「讀取與修改」、「讀取與創建」。你可依照 App 需求作適當的權限宣告。

+
"permissions": {
+  "device-storage:pictures": { "access": "readonly" },
+  "device-storage:music": { "access": "readcreate" },
+  "device-storage:videos": { "access": "readwrite" },
+  "device-storage:sdcard": { "access": "readonly" }
+}
+

1. 音樂檔案列表

+ +
    var type = 'music';
+    var deviceStorage = navigator.getDeviceStorage(type);
+    if (!deviceStorage) {
+      console.warn('Error: cannot get DeviceStorage for ' + type);
+      return;
+    }
+    var request = deviceStorage.enumerate();
+    request.onsuccess = function(e) {
+      var file = request.result;
+      console.log('file name ' + file.name);
+      console.log('file size ' + file.size);
+      console.log('file type ' + file.type);
+      console.log('file last Modified Date ' + file.lastModifiedDate);
+      request.continue();
+    };
+    request.onerror = function() {
+      console.warn('Error: cannot list files in SD card - ' + request.error.name);
+    };
+

2. 讀取某個 SD 卡檔案

+ +
    var type = 'pictures';
+    var deviceStorage = navigator.getDeviceStorage(type);
+    if (!deviceStorage) {
+      console.warn('Error: cannot get DeviceStorage for ' + type);
+      return;
+    }
+    var filename = 'downloads/DSC02798.JPG';
+    var request = deviceStorage.get(filename);
+    request.onsuccess = function(e) {
+      var file = request.result;
+      var url = URL.createObjectURL(file);
+      var myImage = document.getElementById('profilePhoto');
+      myImage.src = url;
+    };
+    request.onerror = function() {
+      console.warn('Error: get file from SD card - ' + request.error.name);
+    };
+

3. 寫入檔案到 SD 卡

+ +
    var type = 'sdcard';
+    var deviceStorage = navigator.getDeviceStorage(type);
+    if (!deviceStorage) {
+      console.warn('Error: cannot get DeviceStorage for ' + type);
+      return;
+    }
+    var filename = 'test-' + Math.random().toString() + '.txt';
+    var pathname = 'test-tmp/' + filename;
+    console.log('file path: ' + pathname);
+    var blob = new Blob(['hello', 'world'], {type: 'text/plain'});
+    var request = deviceStorage.addNamed(blob, pathname);
+    request.onsuccess = function(e) {
+     // try to get the file
+      var readRequest = deviceStorage.get(pathname);
+      readRequest.onsuccess = function() {
+        var file = readRequest.result;
+        var reader = new FileReader();
+        reader.onload = function(e) {
+          console.log('file content ' + e.target.result);
+        };
+        reader.readAsText(file);
+      };
+      readRequest.onerror = function() {
+        console.warn("Error: read file failure - " + request.error.name);
+      };
+    };
+    request.onerror = function() {
+      console.warn('Error: write file failure - ' + request.error.name);
+    };
+

4. SD 卡空間使用率

+ +
    var type = 'sdcard';
+    var deviceStorage = navigator.getDeviceStorage(type);
+    if (!deviceStorage) {
+      console.warn('Error: cannot get DeviceStorage for ' + type);
+      return;
+    }
+    var request = deviceStorage.stat();
+    request.onsuccess = function(e) {
+      var totalSize = e.target.result.totalBytes;
+      var freeBytes = e.target.result.freeBytes;
+      console.log('totalSize ' + totalSize + ', freeBytes ' + freeBytes);
+    };
+    request.onerror = function() {
+      console.warn('Error: cannot get stat of SD card - ' + request.error.name);
+    };
+

 

diff --git a/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/geolocation/index.html b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/geolocation/index.html new file mode 100644 index 0000000000..575d719313 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/geolocation/index.html @@ -0,0 +1,20 @@ +--- +title: 位置資訊 +slug: Archive/B2G_OS/3rd_Party_App_Developer_Guide/Geolocation +--- +

位置資訊 (geolocation)

+

Geolocation API 讓您可以取得使用者目前所在的地理位置資訊,雖然現今它已是一個 Web 開放標準的 API,但在 Firefox OS 中您必須做權限宣告才可使用。
+ 但當您使用這個 API 企圖存取使用者位置時,系統會出現一個視窗詢問使用者是否願意透露位置訊息給您的應用,並且提供一個默認選項記住使用者的選擇。
+
+ 權限宣告:需要

+
"permissions": {
+  "geolocation": {}
+}
+

範例:

+
navigator.geolocation.getCurrentPosition(function(position) {
+  console.log('latitude ' + position.coords.latitude);
+  console.log('longitude ' + position.coords.longitude);
+}, function() {
+  console.warn('Error: cannot fetch location');
+});
+
diff --git a/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/index.html b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/index.html new file mode 100644 index 0000000000..d258c076d5 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/index.html @@ -0,0 +1,90 @@ +--- +title: 第三方應用開發者指南 +slug: Archive/B2G_OS/3rd_Party_App_Developer_Guide +--- +

基本章節

+

快速入門

+

API 說明

+ +

其他技術細節

+ +

除錯與預覽

+ +

測試

+ +

應用上架

+ +

進階章節

+

樣式參考與範本

+ +

調校技巧

+ +

Gaia 系統應用 (System App) 細節

+ +

其他 Open Web 技術

+ diff --git a/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/web_activity/index.html b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/web_activity/index.html new file mode 100644 index 0000000000..8b9e1e52ad --- /dev/null +++ b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/web_activity/index.html @@ -0,0 +1,116 @@ +--- +title: Web Activity +slug: Archive/B2G_OS/3rd_Party_App_Developer_Guide/Web_Activity +--- +

Web Activity

+

許多手機上常見的功能例如:選取聯絡人、撥打電話、照相是您的 App 會需要用到的功能。您可以不必重新發明輪子,而利用「Web Activity」的技術呼叫其他的 App 來完成任務。Web Activity 可以實作兩個 App 間的切換,例如從「相機」切換到「圖片集」,或者是「簡訊」使用「聯絡人」選取一個簡訊發送對象。
+
+ 在您的 App 中只需要描述所需的操作,系統會幫您檢查手機中有哪些 App 提供這些操作。以下是一個具體的例子。這是在「相機」中的一段程式碼,用來切換到別的 App 瀏覽相片。

+
  var act = new MozActivity({
+    name: 'browse',
+    data: {
+      type: 'photos'
+    }
+  });
+  act.onerror = function(e) {
+    if (act.error.name === 'NO_PROVIDER') {
+      console.warn('Error: no activity provider');
+    }
+    else {
+      console.warn('Error: unknown activity - ' + act.error.name);
+    }
+  };
+

在這段程式碼中,「相機」新增了一個 MozActivity 物件並在參數物件中聲明該 activity 是「瀏覽(browse)」的動作,瀏覽的資料是「相片(photos)」。請注意它並非直接指定要切換到「圖片集」 ,而是由系統決定哪個 App 提供這樣的行為,若有多個 App 同時提供一樣的行為時,系統會產生一個選單讓使用者選取。
+ 參數物件的 'data' 欄位可以提供額外所需的資料內容,讓承接 activity 任務的 App 決定是否根據資料內容做其他處理。
+
+ 讓我們來看看提供 Web Activity 的 App 該如何聲明它的 activity 及相關設定。

+
"activities": {
+  "browse": {
+    "filters": {
+      "type": "photos"
+     },
+    "disposition": "window"
+  }
+}
+


+ 像「圖片集」這樣的 App 可以在它的 manifest.webapp 檔案中聲明它提供瀏覽相片的 activity,如上所示。它提供一個「瀏覽(browse)」動作的 activity,瀏覽的資料是「相片(photos)」作為篩選條件。這樣的 activity 聲明宣告,便能與上面的 MozActivity 呼叫匹配,成為能承接這個 activity 的對象之一。若手機中只有這一個 App 有這樣的 activity 宣告,那系統預設就會將這個 App 開啓,但若有多個 App 都能夠執行這個任務,系統會產生一個選單讓使用者選取。

+

"disposition": "window"

+

依照不同 App 的需求,目前在 Firefox OS 中有兩種形式的 Web Activity ,一種為「視窗切換」(window disposition) 、一種為「畫面滑入」(inline disposition)。前者視覺上是 App 之間的切換,後者則是承接 activity 的 App 會由下方滑入,覆蓋在目前 App 之上。除了視覺上的效果不同之外,「畫面滑入」的 Web Activity 在 activity 處理結束畫面關閉之後(例如選擇了一張圖片),會回到原本的 App ,而「視窗切換」的 Web Activity 則需要使用者自己手動回到主畫面 (homescreen) 或者 App 列表,才能夠切換回原本的 App 。提供 Web Activity 的 App 可以自行決定提供哪種形式讓其他 App 呼叫。
+
+ 除了在 manifest.webapp 宣告 Web Activity 之外,程式碼中當然也要有具體的實作。如下所示是「圖片集」 App 的實作程式碼:

+
  navigator.mozSetMessageHandler('activity', function activityHandler(a) {
+    var activityName = a.source.name;
+    if ( activityName === 'browse') {
+      // If this was a cold start, then the db needs to be initialized.
+      if (!photodb)
+        initDB(true);  // Initialize both the photo and video databases
+      // Always switch to the list of thumbnails.
+      setView(thumbnailListView);
+    }
+  });
+
+

當有 MozActivity 的呼叫發生時,會以系統訊息的方式通知將要被開啓的 App 。因此這個 App 必須要註冊 'activity' 的系統訊息,提供對應的回呼函示 (callback function),明白表示當 MozActivity 的呼叫發生時, App 被開啓後將如何處理這個 activity。這邊「圖片集」 App 執行初始化圖庫、以縮圖方式列出圖庫內的相片。
+ 「圖片集」 App 在 manifest.webapp 的聲明中使用 window disposition 的方式處理 activity,表示使用者並不會在完成什麼動作之後回到「相機」 App 。「圖片集」 App 就如同是被使用者手動在主畫面(homescreen)點選開啟一般,由使用者自行決定何時離開。

+

"disposition": "inline"

+

我們來看另一種形式的  Web Activity。同樣以「圖片集」 App 為例,它可以提供一個  Web Activity 供其他 App 挑選照片。挑選照片的 actvity 必須要把被挑選到的相片名稱、路徑…等等的資訊傳回給呼叫方(caller),並且在挑選動作完成後回到呼叫方的 App 。這個情況下,使用 inline disposition 的形式來實作。
+ manifest.webapp 的宣告是這樣的:

+
"activities": {
+  "pick": {
+    "filters": {
+      "type": ["image/jpeg", "image/png"]
+    },
+    "disposition": "inline",
+    "returnValue": true,
+    "href": "/index.html#pick"
+  }
+}
+


+ 它提供一個「挑選(pick)」動作的 activity,挑選的資料形態以一個陣列作為篩選條件,提供挑選 "image/jpeg" 或 "image/png" 圖檔,並且會回傳挑選的值。
+ 由於 inline disposition 的 Web Activity 是以單一畫面滑入的形式被開啓,不同於 window disposition 是整個 App 被開啓,這裡我們可以多指派一個聲明表示要處理這個  Web Activity 的頁面位置 ("href": "/index.html#pick")。
+
+ 這個頁面會有具體的程式碼實作如下:

+
  navigator.mozSetMessageHandler('activity', function activityHandler(activityRequest) {
+    var activityName = activityRequest.source.name;
+    if (activityName === 'pick') {
+      var pickType = activityRequest.source.data.type;
+      var width = activityRequest.source.data.width;
+      var height = activityRequest.source.data.height;
+      var blob = startPick(pickType, width, height);
+      if (blob) {
+        activityRequest.postResult({type: pickType, blob: blob});
+      } else {
+        activityRequest.postError('pick cancelled');
+      }
+    }
+  });
+


+ 當有 MozActivity 的呼叫發生時,「圖片集」 App 收到 'activity' 的系統訊息,回呼函示 (callback function)會被運行,它可以讀取請求此 activity 的 App 所提供的數據,例如所需的圖片類型、寬度、高度… 等,作為陳列圖片清單的參考。當使用者成功選取了一張圖片,呼叫 activityRequest.postResult 傳回挑選結果。這個結果是個物件,讓呼叫 MozActivity 的 App 能夠知道圖片相關的資訊。
+
+ 在「設定」 App 中希望能讓使用者選取一張圖片做為桌布,只需要呼叫 activity 來完成。

+
  var activityRequest = new MozActivity({
+     name: 'pick',
+     data: {
+        type: 'image/jpeg',
+        width: 320,
+        height: 480
+      }
+  });
+  activityRequest.onsuccess = function onPickSuccess() {
+    if (!activityRequest.result.blob)
+      return;
+
+    var reader = new FileReader();
+    reader.readAsDataURL(activityRequest.result.blob);
+    reader.onload = function() {
+       navigator.mozSettings.createLock().set({
+          'wallpaper.image': reader.result
+       });
+       displayImgae(reader.result);
+    };
+  };
+  activityRequest.onerror = function onPickError() {
+     console.warn('pick failed!');
+  };
+
+

在這段程式碼中,「設定」呼叫了一個 MozActivity 並在參數物件中聲明該 activity 是「挑選(pick)」的動作,挑選的是「image/jpeg」檔案,限定寬度與高度為 320 x 480。同樣的,「設定」 App 不知道實際上哪個 App 會被呼叫,它只在意當挑選動作完成時,它的 onsuccess 回呼函示會被執行,取得 blob 內容,並且畫面焦點將回到它身上,讓它可以顯示選取的圖片。系統將決定哪個 App 提供這樣的行為,若有多個 App 同時提供一樣的行為時,系統會產生一個選單讓使用者選取。
+  

diff --git "a/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/\345\260\201\345\214\205\345\274\217_(packaged)_app/index.html" "b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/\345\260\201\345\214\205\345\274\217_(packaged)_app/index.html" new file mode 100644 index 0000000000..80a905ab88 --- /dev/null +++ "b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/\345\260\201\345\214\205\345\274\217_(packaged)_app/index.html" @@ -0,0 +1,70 @@ +--- +title: 封包式 (Packaged) App +slug: Archive/B2G_OS/3rd_Party_App_Developer_Guide/封包式_(Packaged)_App +--- +
+

原文出處:https://marketplace.firefox.com/developers/docs/packaged

+
+

封包式 (Packaged) App 屬於 Open Web App,即以 ZIP 壓縮檔納入其 HTML、CSS、JavaScript、app manifest 等所有資源;取代「將資源置於 Web 伺服器之上」的方式。封包式 App 的 ZIP 壓縮檔另將 app manifest 置於其根目錄之下,且此 manifest 檔案必須命名為 manifest.webapp。

+
+

注意:截至 2013 年 1 月為止,Firefox Marketplace 上所提供的封包式 App 限定為 Firefox OS App。

+
+

 

+

封包式 App 之用途

+

若 App 會存取裝置上的 Sensitive API,則最好能透過封包式 App 而達到安全性的需求。App 均必須經過上架商城 (如 Firefox OS Marketplace) 認證方可販售。這些商城將審核 App,確認其是否可行,再以其自有金鑰完成加密簽核。再審核過安全性、隱私性、功能性等的可能問題之後,可為 App 的使用者更多添一份保障。

+

 

+

封包式 App 的類型

+

封包式 App 可分為 3 類:

+

Privileged app

+

Privileged App 是由 Firefox OS Marketplace 以特殊程序核准之後發出。如果任一 App 要存取裝置上的特定 Sensitive API,則可為使用者提供更高的安全性。此種 App 即等同 iOS 或 Android 平台上的 Native App,並具備下列特性:

+ +
"default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'"
+ +

Certified app

+

Certified App 將用於重要的系統功能,如智慧型手機上預設的撥號鍵盤,或系統設定用 App;當然亦可用於 Firefox OS 手機上的重要功能。Certified App 並不會用於第三方 App,所以大多數的 App 開發人員可略過此類 App 不管。除了所有的裝置許可均為隱式許可 (Implicit permission,意即不需要外部的使用者許可) 之外,Certified App 與 Privileged App 大部分均屬於相似的封包式 App。而 Certified App 必須取得 OEM 裝置或電信服務供應商裝置的許可,才能讓此隱式 App 使用重要 API。下列即為 Certified App 的 CSP (與 Privileged App 的 CSP 略有不同):

+
"default-src *; script-src 'self'; object-src 'none'; style-src 'self'"
+

若與 Certified App 相較,Privileged App 則針對 inline CSP 的影響而稍微放寬了限制。進一步了解其原因,可參閱預設 CSPBug 768029

+

Plain packaged app

+

當然也可讓一般 App 封裝為 ZIP 壓縮檔。在 Marketplace 簽署之後,並不會執行如 Privileged/Certified App 所需的特殊授權程序。且 Plain Packaged App 並不會使用特定的 Sensitive Web API;同時也不屬於 Privileged/Certified App 所用 CSP 管轄所及。

+

 

+

與托管式 (Hosted) App 的差異

+

封包式 App 的功能,其實與一般網站型態的 Open Web App (即所謂托管式 Hosted App) 功能相同。但封包式 App 的差異在於:

+ +
app://550e8400-e29b-41d4-a716-446655440000/index.html
+ +

與一般的托管式 App 相同,封包式 App 仍可存取 Web 伺服器上的資料庫。

+

 

+

使用 Sensitive Web API

+

現在有許多惡意 Web API,因此應謹慎存取 Web API。針對 App 所要存取的所有 Sensitive API,你應該在 manifest 檔案permissions 欄位中新增輸入項。

+

一般托管式 App 亦可存取某些 Sensitive API,但其他 API 就限定封包式 (Privileged 或 Certified) App 才可存取。可參閱 App 許可找到相關需求的表格。

+

 

+

封包式 App Firefox Marketplace

+

與托管式 App 相較,Firefox Marketplace 處理封包式 App 的方式較為不同。一旦提交自己的封包式 App 之後,其 ZIP 壓縮檔即儲存於 Marketplace 的伺服器上,且 Marketplace 隨即根據該 ZIP 壓縮檔中的 manifest 檔案,產生新的 manifest 檔案並命名為「mini-manifest」。只要使用者想安裝此 App,就會將 mini-manifest 檔案傳送至 installPackage() 函式以安裝該 App。此 mini-manifest 檔案僅用於安裝與更新作業,與 App 的執行作業無關。

+

 

+

測試封包式 App 的安裝作業

+

透過 Firefox OS 模擬器 (Firefox OS Simulator),即可輕鬆安裝封包式 App。目前 Firefox OS 模擬器亦針對各個平台而提供 WindowsOSXLinux 等不同版本。

+

安裝模擬器時,將於 Firefox 的「網頁開發者 (Web Developer)」功能表中新增「Firefox OS Simulator」項目。在開啟附加元件之後,即可透過「Add Directory」而指定本端 webapp.manifest 檔案的位置。模擬器另可將該 App 封包 (即壓縮該資料夾),再透過剛封包完畢的 App 開啟模擬器。

+

針對 Linux 與 Windows 的使用者,還需要其他步驟才能設定 Android Debug Bridge (adb),以溝通實際裝置。請參閱步驟 3:設定系統以偵測自己的裝置

+

在實際裝置上,可點選 Settings > Device Information > More Information > Developer > Remote Debugging,進而啟動遠端除錯功能。

+

任何時間點均可連上受支援的裝置。一旦連上裝置,模擬器即可偵測並顯示所接上的裝置。而在 App 列表的旁邊,可看到「push」的新按鈕。按下「push」即可將剛封包完畢的 App 傳送至裝置上。

+

 

+

更新封包式 App

+

若要進一步了解更新作業,請參閱更新 App

+

 

diff --git "a/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/\346\211\230\347\256\241\346\233\264\346\226\260\344\275\234\346\245\255_(hosting_updates)_/index.html" "b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/\346\211\230\347\256\241\346\233\264\346\226\260\344\275\234\346\245\255_(hosting_updates)_/index.html" new file mode 100644 index 0000000000..ea5b41073b --- /dev/null +++ "b/files/zh-tw/archive/b2g_os/3rd_party_app_developer_guide/\346\211\230\347\256\241\346\233\264\346\226\260\344\275\234\346\245\255_(hosting_updates)_/index.html" @@ -0,0 +1,78 @@ +--- +title: 托管更新作業 (Hosting Updates) +slug: Archive/B2G_OS/3rd_Party_App_Developer_Guide/托管更新作業_(Hosting_Updates)_ +--- +
+

本文節錄自 B2G/Updating

+
+

托管更新作業 (Hosting Updates)

+

其實亦可解釋為:用戶端針對更新檔案所進行的輪詢作業。

+

B2G 用戶端針對更新所執行的輪詢 (Poll),即針對 update manifest 檔案進行提取 (Fetching) 與剖析 (Parsing)。此檔案即稱為「update.xml」。

+

B2G 用戶端均已完成「輪詢特定伺服器上的更新」的設定,亦將查詢伺服器上特別架構而成的路徑。而我們建議透過 HTTPS 協定 (當然 HTTP 亦支援),讓用戶端查詢伺服器。若現有用戶端更改了輪詢程式碼,則只要將一筆更新傳送至此用戶端,即可針對「用戶端所輪詢過的路徑與伺服器」進行變更。

+

在下列範例中,我們假設將更新作業托管 (Hosting) 給 updates.b2g.com 伺服器。

+

則由用戶端所輪詢的 URL,主要可用下列參數呈現:

+ + + + + + + + + + + + + + + + + + + +
+

PRODUCT_MODEL

+
+

裝置型號的名稱。此為 B2G 屬性資料庫中的 ro.product.model 數值。

+
+

CHANNEL

+
+

更新「頻道」,有助於測試作業。舉例來說,我們可設定伺服器托管「nightly」、「beta」、「release」等頻道。

+
+

VERSION

+
+

此為用戶端的軟體版本,此以「18.0.2」為例。

+
+

BUILD_ID

+
+

專屬 ID,如針對特定軟體版本 (Build) 所設的時間戳記。

+
+

當然另有許多數值,可為查詢作業建構出更新用的 URL。

+

B2G 用戶端隨後將整合「本身已設定的更新主機」的數值,搭配上述的相關數值,進而建構出 URL,以於執行期間執行輪詢作業。

+

此 URL 範例可為:

+
https://updates.b2g.com/release/unagi1/18.0/20121203123456/update.xml
+
+

 

+

針對用戶端的請求,若伺服器回傳「404 Not Found」,即代表目前並無可用的更新;若回傳「200」與 manifest 檔案,則代表可能有更新。該 manifest 檔案將描述可用的新版本,亦即用戶端目前應該更新的版本。此 manifest 檔案範例為:

+
<?xml version="1.0"?>
+<updates>
+  <update type="major" appVersion="19.0" version="19.0" extensionVersion="19.0" buildID="20121210123456"
+          licenseURL="http://www.mozilla.com/test/sample-eula.html"
+          detailsURL="http://www.mozilla.com/test/sample-details.html">
+    <patch type="partial" URL="https://updates.b2g.com/release/unagi1/18.0/20121203123456/update.mar"
+           hashFunction="SHA512" hashValue="5111e033875752b7d9b32b4795152dea5ef954cb8a9d4a602dd19a923b464c43521287dcb5781faf3af76e6dc5e8a3dd9c13edea18c1f2c8f3bd89e17d103d6f"
+           size="41901319"/>
+  </update>
+</updates>
+
+

而 manifest 檔案中的欄位則描述了:

+ +

當然,使用者或用戶端裝置可能會拒絕更新作業。

+

透過這些機制,伺服器將可托管更新封裝,以利舊版用戶端的更新作業。或可僅托管「線性更新歷史紀錄 (Linear update history)」,讓用戶端必須透過單一路徑完成升級。

+

針對「版本 (Build) 伺服器」和「更新主機」之間的互動細節,仍與作業環境息息相關。本文尚不足以詳細解說完畢。

+

 

diff --git a/files/zh-tw/archive/b2g_os/add-ons/index.html b/files/zh-tw/archive/b2g_os/add-ons/index.html new file mode 100644 index 0000000000..13f42518cd --- /dev/null +++ b/files/zh-tw/archive/b2g_os/add-ons/index.html @@ -0,0 +1,282 @@ +--- +title: Firefox OS 附加元件 +slug: Archive/B2G_OS/Add-ons +translation_of: Archive/B2G_OS/Add-ons +--- +
+

重要: 僅 Firefox OS 2.5+ 支援附加元件功能。

+
+ +

「附加元件」的概念在 Web 瀏覽器的世界中眾人皆知,而我們也將這個概念帶進 Firefox OS。Firefox OS 的附加元件可以僅僅作用於單一 App 上,也可以指定作用於多個、甚至所有 App 上。本文帶您一步步撰寫自己的 Firefox OS 附加元件,同時提供一些秘訣及其他應該了解的資訊。

+ +
+

附註:本文僅重點概略翻譯。

+
+ +
+

附註:Firefox OS 附加元件採用 WebExtensions 擴充模式。此模式大部份源自於 Chrome/Blink 擴充套件機制,讓附加元件在開發時能擁有許多互通性與功能上的優勢。詳情可見持續編寫中的 WebExtensions 文件集

+
+ +

開發附加元件

+ +

Firefox OS 附加元件其實也是個內含 JavaScript / CSS / 其他必備檔案的 App,但不是拿來獨立運作,而是在描述檔中增加特別的說明來定義要在哪些 App 中使用這個附加元件。When apps are launched on a Firefox OS device that has an add-on installed, the add-on is injected into any app that matches the pattern specifed in the filter.

+ +

Firefox OS add-ons use the same syntax and structure for their code as the new school of Firefox add-ons developed using the WebExtensions API, which is itself based on the Chrome extensions model.

+ +

簡單範例

+ +

以下我們以一個簡單的例子說明 Firefox OS 附加元件的程式基礎。這個附加元件會在 system app 放上一塊看板,使用者可以點擊關閉。

+ +

firefox os screenshot showing add-on banner

+ +

這個附加元件很簡單,但用來作為入門倒是相當足夠了。你可以在 GitHub 上下載範例程式,而後用 WebIDE 裝到你的 Firefox OS 裝置上(參考 {{anch("Testing your add-on using WebIDE")}} 一節)。往後你也可以透過 Firefox Marketplace 來發表自己的附加元件。

+ +

Be aware that Firefox OS add-ons can do a lot more than what we've got listed here. The WebExtensions documentation will have more information added as time goes on.

+ +

解析 Firefox OS add-on

+ +

In this section we'll walkthrough the contents of the sample add-on repo, explaining each piece of content. 目錄結構看起來像這樣:

+ + + +

manifest.json

+ +

你應該發現了:在這個範例附加元件目錄中,有兩種類似的描述檔。第一個「manifest.json」的結構類似 Chrome 擴充套件,與 CSS、JavaScript 及其他檔案一起放在 {{anch("extensions.zip")}} 當中。It can contain a large variety of instructions (see Chrome Manifest File Format), but for now we're just going to concentrate on a simple subset:

+ +
{
+  "manifest_version": 1,
+  "name": "Add-on banner",
+  "description": "Firefox OS add-on example",
+  "version": "1.0",
+  "author": "Chris Mills",
+  "content_scripts": [{
+    "matches": ["app://system.gaiamobile.org/index.html"],
+    "css": ["css/style.css"],
+    "js": ["js/index.js"]
+  }],
+  "icons": {
+    "128": "/icons/128.png"
+  }
+}
+ +

Most of these fields are pretty self-explanatory, but we'll cover the last few.

+ +

首先以 content_scripts 指定要植入 app 的檔案 — 你可以看到這邊以 cssjs 兩欄分別指定 CSS 樣式檔及 JavaScript 程式檔。matches 欄位則是用以指定該把檔案放入哪些 app 裡,這個欄位的內容形式很多元(參考 Chrome Match Patterns),但我們先簡單指定為 app://system.gaiamobile.org/index.html,讓附加元件僅影響 system app。若想影響所有 app,可以將此欄位寫為 app://*/*

+ +
+

Note: You can reference multiple scripts and stylesheets by simply including multiple items in the arrays, for example "css": ["css/style.css", "css/more.css"].

+
+ +
+

Note: Firefox OS does not currently support the Chrome <all_urls> keyword.

+
+ +

At the bottom of the manifest we've included the icons field; see the next section for more info on this.

+ +

update.webapp

+ +

update.webapp 則是 Firefox OS 式的描述檔,基本上就是跟打包 app 時用的描述檔格式相同。(參考 Self-publishing packaged apps。)

+ +

Our update.webapp file looks like so:

+ +
{
+  "name" : "Add-on banner",
+  "description": "Firefox OS add-on example",
+  "developer": { "name": "Chris Mills" },
+  "package_path": "extension.zip",
+  "icons": {
+    "128": "/icons/128.png"
+  }
+}
+ +

Again, most of this is fairly self-explanatory.

+ +

這邊最重要的欄位該是 package_path,用以指定內含附加元件程式的包裝檔位置。

+ +

You'll notice that the icons field is included here, the same as it is in {{anch("manifest.json")}} — update.webapp is the only place you need to have the icons information at the moment, but we'd recommend you include it in both places for now, just in case things change. The icons field points to the add-on icon so it can be used inside the Gaia Settings app, and the Firefox Marketplace when it starts to host add-ons.

+ +

指定圖示

+ +

你必須在描述檔中至少指定一個圖示,否則描述檔無效。詳情可參考 Manifest 參考文件:圖示 一節。

+ +

CSS

+ +

There is nothing special about the CSS included in the example. The only thing to bear in mind is that you should make sure your add-on classnames and selectors do not conflict with any of the existing CSS in the app(s) it is applied to.

+ +

For example, we wrapped our example banner in a {{htmlelement("div")}} with class fxos-banner. But you could even consider using some kind of unique code for your classname.

+ +

JavaScript

+ +

Again, the JavaScript file that powers the add-on doesn't have any special functionality inside it (see the JavaScript source on Github.) It is injected into the apps it is applied to along with any CSS specified in the {{anch("manifest.json")}} file.

+ +
+

Note: Add-on code is injected every time an app is launched and the match specified in manifest.json pattern matches that app. It is also injected whenever add-ons are enabled. When an add-on is injected into an app because the app is launching, all add-on files are injected into the app before anything in the app is initialized, including the DOM. It is up to the add-on developer to handle the different launch cases cases (immediate injection vs. injection on launch); there is more info on this below.

+
+ +

Other main things to note are covered below.

+ +

The window object

+ +

Add-ons only share a proxied version of the content window. As a result, anything that is written to the window object from an add-on is unavailable to the app code. However, anything on the window object that is set by app code is available to add-ons. Similarly, the DOM is accessible as usual.

+ +

Injecting code at the correct time

+ +

You must be careful to properly handle cases where an add-on is injected into an app after the app has been loaded. Such a scenario can occur when an app is already running and an add-on that targets it is enabled.

+ +

in such a case, a window.onload handler won't work because the DOMContentLoaded event has already occured.

+ +

There's no good solution to this problem right now. In the interim, we recommend to check whether or not the DOM has been loaded before setting a DOMContentLoaded callback. This pattern is used in the demo:

+ +
// If injecting into an app that was already running at the time
+// the app was enabled, simply initialize it.
+if (document.documentElement) {
+  initialize();
+}
+
+// Otherwise, we need to wait for the DOM to be ready before
+// starting initialization since add-ons are usually (always?)
+// injected *before* `document.documentElement` is defined.
+else {
+  window.addEventListener('DOMContentLoaded', initialize);
+}
+
+function initialize() {
+  // ...
+}
+ +

避免重複植入

+ +

為避免附加元件的程式碼多次重複植入到同一 App 中,您必須檢查附加元件是否曾經植入過,例如這樣

+ +

you should check whether your add-on is already present, like this:

+ +
function initialize() {
+  if (document.querySelector('.fxos-banner')) {
+    // Already injected, abort.
+    return;
+  } else {
+    var body = document.querySelector('body');
+    var fxosBanner = document.createElement('div');
+    fxosBanner.classList.add('fxos-banner');
+    var bannerText = document.createElement('p');
+    var closeBtn = document.createElement('button');
+
+    fxosBanner.appendChild(bannerText);
+    fxosBanner.appendChild(closeBtn);
+    body.appendChild(fxosBanner);
+
+    closeBtn.textContent = 'X';
+    bannerText.textContent = 'Wow, you have an extension installed!';
+
+    closeBtn.onclick = function() {
+      fxosBanner.parentNode.removeChild(fxosBanner);
+    }
+  }
+}
+ +

So here we are using if (document.querySelector('.fxos-banner')) to check whether the example banner already exists. If so, then we return out of the function. If not, then the querySelector() method returns null, and we run the code block that creates the banner.

+ +

App management functions in add-ons

+ +

All Apps and Mgmt functions work on add-ons just like they do on apps. Be aware however that the latter are only available to add-ons when they are injected into a certified app that has the webapps-manager permission specified in the manifest.

+ +

In addition to these functions, an onenabledstatechange callback is exposed for add-ons being enabled and disabled. This event is fired for all add-ons, so you will have to check which add-on was enabled/disabled before performing initialization or cleanup.

+ +
navigator.mozApps.mgmt.onenabledstatechange = function(event) {
+  var app = event.application;
+  if (app.manifestURL === 'https://origin.of.manifest/manifest.webapp') {
+    var wasEnabled = app.enabled;
+    // do something with this information
+  }
+};
+ +

extension.zip

+ +
+

Note: The extension.zip file has been left in the demo repo mainly for illustrative purposes, so it is clear how the system works. You actually don't need to include the zip in your directory, as WebIDE will generate it for you when you install the add-on. The Firefox Marketplace is likely to do the same when it starts to list add-ons.

+
+ +

The extension.zip archive contains the code for the extension, and is referenced in the {{anch("update.webapp")}} package_path field — This is how Gecko finds the code to be installed. Archived inside you'll find:

+ + + +

So the manifest.json file sits inside the archive, and serves to reference the files to be injected and specify which apps to affect.

+ +

Testing your add-on using WebIDE

+ +

Mozilla's WebIDE tool is available in Firefox desktop by default. To use it for installing add-ons on your phone, follow the steps listed below:

+ +
    +
  1. Make sure you have Firefox 43 or above installed (this was Nightly at the time of writing), as add-ons are not supported in WebIDE below this version.
  2. +
  3. Open your browser and open the WebIDE tool (press the WebIDE button, or choose Tools > Web Developer > WebIDE from the menu.)
  4. +
  5. Make sure your phone has remote debugging enabled (Settings App > Developer > Set the "Debugging via USB " selection to "ADB and DevTools".)
  6. +
  7. Connect your phone to your computer via a USB cable. Make sure you don't have other phones connected at the same time.
  8. +
  9. In the WebIDE UI, press the Select Runtime option, and select your phone, which should be listed under USB Devices.
  10. +
  11. At this point, your phone should be showing an Allow USB debugging connection? prompt. Choose Allow.
  12. +
  13. Select the Open App option, then choose Open Packaged App...
  14. +
  15. In the resulting file chooser, navigate to the directory that contains your update.webapp manifest file, and press Open.
  16. +
  17. Providing there are no warnings or errors reported, you can install your add-on on the device using the "Play" button in the center (Install and Run.)
  18. +
  19. To see the add-on in action, enable it by choosing Settings app > Add-ons > Add-on example > toggle the checkbox at the top.
  20. +
+ +

Add-on settings

+ +

You can control the add-ons on your phone by going to Settings app > Add-ons; in here you'll find a list of your installed add-ons, and you can tap each entry to see more information about each add-on.

+ +

firefox os screenshot showing a list of installed add-ons in the settings appinformation screen for an individual addon, with a list of apps this add-on affects, and controls to disable and delete the add-on

+ +

Enabling/disabling and deleting add-ons

+ +

By default, add-ons will be enabled after installation when they are installed form the Firefox Marketplace. When installed via WebIDE however they will be disabled by default.

+ +

You can manually enable/disable add-ons via the checkbox at the top of each individual add-on's page (found under Settings app > Add-ons), or programmatically using the navigator.mozApps.mgmt.setEnabled() function (see this setEnabled() usage example on Github.)

+ +

You can delete an add-on entirely by tapping the Delete button found on individual app pages.

+ +

Apps affected by add-ons

+ +

You'll also notice that in the page for each individual add-on there is a section that lists which apps are affected by that add-on. Currently this doesn't seem to work (it always lists This add-on does not affect any installed apps.) This should be fixed soon (see {{Bug(1196386)}} for progress.)

+ +

權限

+ +

附加元件的權限繼承自其所植入的 App,在描述檔中想多要一點權限是行不通的,也無法以此方式增加其植入對象的權限。

diff --git a/files/zh-tw/archive/b2g_os/api/fmradio/index.html b/files/zh-tw/archive/b2g_os/api/fmradio/index.html new file mode 100644 index 0000000000..ec662a0029 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/api/fmradio/index.html @@ -0,0 +1,110 @@ +--- +title: WebFM +slug: Archive/B2G_OS/API/FMRadio +translation_of: Archive/B2G_OS/API/FMRadio +--- +

WebFM API 可存取裝置上的 FM 收音機功能。此介面可開啟/關閉 FM 收音機,亦可搜尋各個電台。

+

進入點 (Entry point)

+
if (navigator.mozFMRadio)
+  navigator.mozFMRadio.enable();
+
+

API

+
interface FM : EventTarget {
+   readonly attribute boolean enabled;
+   readonly attribute boolean antennaAvailable;
+   readonly attribute double frequency;
+   readonly attribute double frequencyUpperBound;
+   readonly attribute double frequencyLowerBound;
+   readonly attribute double channelWidth;
+
+   attribute Function onantennaavailablechange;
+   attribute Function onfrequencychange;
+   attribute Function onenabled;
+   attribute Function ondisabled;
+
+   DOMRequest enable(double frequency);
+   DOMRequest disable();
+   DOMRequest setFrequency(double frequency);
+   DOMRequest seekUp();
+   DOMRequest seekDown();
+   DOMRequest cancelSeek();
+}
+

屬性 (Attribute)

+
+
+ enabled
+
+ 表示目前是否開啟收音機
+
+ antennaAvailable
+
+ 表示是否已插上天線並可使用天線
+
+ frequency
+
+ 目前的收音機頻率
+
+ frequencyUpperBound
+
+ 以 seek 函式搜尋收音機電台的最高頻率
+
+ frequencyLowerBound
+
+ 以 seek 函式搜尋收音機電台的最低頻率
+
+ channelWidth
+
+ 頻率範圍內的頻寬,以「MHz」為單位。常用數值為 0.05、0.1 (預設)、0.2 其中之一。
+
+ 指定了某一頻率之後,就會四捨五入到 channelWidth 所指定的最接近頻率。舉例來說,若 100 Mz 為有效頻率,且 channelWidth 為 0.2,則 100.2 與 99.8 將成為有效頻率。但若是 100.15 將四捨五入為 100.2。
+
+

函式 (Method)

+
+
+ enable(frequency)
+
+ 開啟收音機並轉為指定頻率。若沒有參數 (Argument) 就呼叫此函式,將隨即丟出錯誤。作業成功或錯誤均將回傳 DOMRequest。
+
+ disable()
+
+ 關閉收音機。若回傳成功的 DOMRequest,則代表已正確關閉收音機。
+
+ setFrenquecy(frequency)
+
+ 非同步變更收音機的頻率。此數值必須位於 frequencyLowerBoundfrequencyUpperBound 之間。若嘗試設定此範圍之外,將導致錯誤。
+
+ 若回傳成功的 DOMRequest,則代表已正確變更頻率。
+
+ seekUp()
+
+ 要求收音機尋找新的頻率 (一般搜尋較目前頻率更高的頻率)。若成功搜尋到新的頻率,將隨即啟動 frequencychange 事件。若回傳成功的 DOMRequest,則代表已開始搜尋作業。一旦達到最高頻率,將回到較低頻率開始搜尋。
+
+ seekDown()
+
+ 與上方函式的功能相同,但將搜尋較目前頻率更低的頻率。一旦達到最低頻率,將回到較高頻率開始搜尋。
+
+ cancelSeek()
+
+ 取消目前的搜尋作業。若回傳成功的 DOMRequest,則代表已取消搜尋作業。
+
+

事件 (Event)

+
+
+ enabled
+
+ 開啟收音機時觸發此事件
+
+ disabled
+
+ 關閉收音機時觸發此事件
+
+ antennaavailablechange
+
+ 插上/拔除天線時觸發此事件
+
+ frequencychange
+
+ 只要變更收音機頻率,均將觸發此事件
+
+

另請參閱

+

Gaia radio app

diff --git a/files/zh-tw/archive/b2g_os/api/index.html b/files/zh-tw/archive/b2g_os/api/index.html new file mode 100644 index 0000000000..706080ff54 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/api/index.html @@ -0,0 +1,156 @@ +--- +title: B2G OS APIs +slug: Archive/B2G_OS/API +tags: + - API + - B2G API + - NeedsTranslation + - TopicStub + - b2g os api's +translation_of: Archive/B2G_OS/API +--- +

List of B2G OS APIs 

+ +

+A +B +C +D + + +F + + +H + + + + + + + + +M +N + + +P + + + + +S +T +U + + +W + + + + + + + +

diff --git a/files/zh-tw/archive/b2g_os/apps/index.html b/files/zh-tw/archive/b2g_os/apps/index.html new file mode 100644 index 0000000000..7c848f3df1 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/apps/index.html @@ -0,0 +1,45 @@ +--- +title: 製作 Firefox OS 的 apps +slug: Archive/B2G_OS/Apps +translation_of: Web/Apps/Fundamentals +--- +

Firefox OS 裝置的應用程式其實只是開啟網頁上的Web應用;它們完全由各種開放的Web技術所組成,如 JavaScript, HTML, 和 CSS。雖然我們寫給 apps 的主要文件幾乎涵蓋了您所需要知道的所有事情,這裡列了一些特別著重於開發及測試 Firefox OS的文件。

+
+
+

文件及入門教材

+
+
+ 寫一個 Firefox OS 的 Web app
+
+ 一份教您製作您的第一個 Firefox OS web 應用程式的入門指南。
+
+ 撇步及技巧
+
+ 一份我們開發者建議您的撇步及技巧集(像是對於問題的替代方案)。
+
+

全部文章...

+
+
+

尋求社群協助

+

您在 app 相關問題上需要幫助、且無法在文件中找到解法嗎?

+
    +
  • 在 layout 論壇中請教,, 其中涵蓋 CSS 和 HTML: {{ DiscussionList("dev-tech-css", "mozilla.dev.tech.layout") }} +
      +
    • 在 Mozilla IRC channel 裡面提出你的問題: #openwebapps
    • +
    +
  • +
+

請遵守網路禮節...

+

工具

+ +

View All...

+ + +
+
+

 

diff --git a/files/zh-tw/archive/b2g_os/apps/writing_a_web_app_for_b2g/index.html b/files/zh-tw/archive/b2g_os/apps/writing_a_web_app_for_b2g/index.html new file mode 100644 index 0000000000..4e612e8a87 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/apps/writing_a_web_app_for_b2g/index.html @@ -0,0 +1,25 @@ +--- +title: 寫一個 Firefox OS 的 Web app +slug: Archive/B2G_OS/Apps/Writing_a_web_app_for_B2G +translation_of: Web/Apps/Fundamentals/Quickstart +--- +

B2G apps 只是用 HTML、CSS、和 Javascript 寫的 Web apps。在網頁上發佈 Web apps 就跟發佈一般的網站一樣。為了讓網站可以像 Web app 一樣可以被安裝在行動裝置上,你只需要加上一個 manifest 以及掛上一個安裝按鈕,如以下說明。

+

建議您從下面的文章著手:

+ +

當然,您也可以無拘無束地 沉浸在 Open Web Apps 的深處

+

安裝 Web app

+

在網頁上發佈 app 和 manifest 之後,接著要讓 Gecko 知道這個訊息。像是在安裝時,Gecko 查詢 manifest 並將必須的項目加入到 home 的畫面,等等。

+

安裝 app 需要呼叫 navigator.mozApps.install() API。這裡有個安裝按鈕的範例,當您將 app 置於自己管理的位置時,這個範例可以讓您將按鈕嵌入於您自己的網頁:

+
<script>
+var manifest_url = "http://my.webapp.com/manifest.json";
+</script>
+
+<button onclick="navigator.mozApps.install(manifest_url); return false;">
+  Install this awesome app on your homescreen!
+</button>
+
+

注意:這個安裝按鈕也可以被置於像是 Mozilla Marketplace 的 app market,然而一般而言,在您自己的主要頁面上面也放一個「安裝 web app」的按鈕是非常貼心的。

+

現在請用 B2G 瀏覽器 app 瀏覽您的網站,並且點選安裝按鈕吧。

diff --git a/files/zh-tw/archive/b2g_os/architecture/index.html b/files/zh-tw/archive/b2g_os/architecture/index.html new file mode 100644 index 0000000000..a0a649e4f9 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/architecture/index.html @@ -0,0 +1,717 @@ +--- +title: Firefox OS 架構 +slug: Archive/B2G_OS/Architecture +translation_of: Archive/B2G_OS/Architecture +--- +
+

本文件是 Firefox OS 平台架構的初步概要介紹,將會簡單地向您介紹 Firefox OS 的重要概念,並解釋元件間如何互動。

+
+ +
+

注意:Firefox OS 仍算是開發中的產品。本文說明的架構仍非最後確定的架構,隨時可能修改。

+
+ +

Firefox OS 術語

+ +

在閱讀 Firefox OS 技術文件之前,建議先了解以下的詞彙:

+ +
+
B2G
+
Boot to Gecko 的縮寫。
+
Boot to Gecko
+
Firefox OS 作業系統的工程代號。此代號常常用以代表 Firefox OS。因為在本專案還未定下正式名稱之前,此代號已經用了很長的一段時間,因此常常用以代表 Firefox OS。
+
Firefox OS
+
Firefox OS 即是將 Mozilla (及其 OEM 夥伴) 的品牌與服務,套用至 Boot to Gecko 的基礎之上開發而得的最終產品。
+
Gaia
+
Firefox OS 平台的使用者介面 (UI)。 在啟動 Firefox OS 之後,都是透過 Gaia 層產出螢幕上的任何東西。Gaia 建構出鎖定畫面、主畫面,以及大家預期智慧型手機所應提供的其他標準 App。Gaia 完全使用 HTML、CSS、JavaScript 實作而成。透過實作在 Gecko 層的開放 Web API,與其底層的作業系統溝通。第三方 App 均可安裝於 Gaia 層。
+
Gecko
+
Firefox OS App 的執行環境 (Runtime),也就是本層可支援所有的開放標準:HTML、CSS、JavaScript。本層另必須確保這些 API 可正確運作於 Gecko 支援的所有 OS。意即 Gecko 另包含了網路連線堆疊、圖形堆疊、配置引擎、JavaScript 虛擬機器、移植層。
+
Gonk
+
Gonk 是 Firefox OS 平台的底層作業系統,是由 Linux 核心 (以 Android Open Source Project 為架構),與使用者空間的硬體抽象層 (Hardware abstraction layer,HAL) 所組成。核心以及許多使用者空間的函式庫,均來自常見的開放源碼專案,如 Linux、libusb、bluez 等。HAL 的某些部分是與 AOSP 共享,如 GPS 或相機。你可將 Gonk 當成是簡單的 Linux 分支版本。Gonk 又是 Gecko 的移植目標;意即有一套 Gecko 可在 Gonk 上執行,就像是 Gecko 也有 Mac OS X、Windows、Android 等版本。因為 Firefox OS 可完整控制 Gonk,所以某些不能開放給其他 OS 用的介面,還是可開發給 Gecko 使用。舉例來說,Gecko 可直接存取 Gonk 的完整電話功能堆疊,並於 Gonk 上顯示緩衝區 (Frame buffer),但是其他 OS 不能進行類似的存取。
+
Jank
+
此一詞彙常見於行動 App 領域,指在 APP 中執行了緩慢或沒有效率的程式碼,進而阻礙了 UI 更新並發商系統延遲或無回應的情形。Gaia 開發者使用不同的最佳化方法,要儘力避免此狀況發生。
+
+ +

整體架構示意圖

+ +

下圖比較了專利平台與 Firefox OS 之間的架構。

+ +

on the left is a native mobile architecture stack, on the right is the Firefox OS architecture. they are similarm except that the native stack is all proprietary device functionality, and the Firefox OS stack is all done with open source and web technologies.

+ +

Firefox OS 即減去了 OS 與 App 層之間的原生 API 層。這種統合式的設計可減輕平台負擔並簡化安全機制,卻又不致犧牲效能,也不會影響智慧型手機的使用體驗。

+ +
    +
  1. Gaia 作為裝置的核心 Web App 與 UI 層,並全以 HTML5、CSS、JavaScript 撰寫而成,並有許多 API 可供 UI 程式碼存取手機硬體與 Gecko 功能。
  2. +
  3. Gecko 即為 Firefox OS 的 Web 引擎與表現層 (Presentation layer),作為 Web 內容與底層裝置的之間介面,進而將硬體接上 HTML。Gecko 亦提供 HTML5 剖析 (Parsing) 與繪圖引擎,並透過程式設計的方式,以安全的 Web API 存取硬體功能、更新作業,以及其他核心服務。
  4. +
  5. Gonk 是 Firefox OS 堆疊中的核心層級元件,作為 Gecko 與底層硬體之間的介面。Gonk 可控制底層硬體,並將硬體功能告知 Gecko 中建構的 Web API。Gonk 可視為「黑盒子」,暗自進行所有複雜又零碎的背景作業,以於硬體層制定請求,進而控制行動裝置。
  6. +
  7. 行動裝置,就是執行 Firefox OS 的行動電話硬體。OEM 廠商則負責提供行動裝置。
  8. +
+ +

特殊 Firefox OS 架構

+ +

Firefox OS Architecture

+ +

Firefox OS 開機流程

+ +

本段將說明 Firefox OS 的開機流程,包含整個流程所牽涉的部份,以及相關部分在系統裡的位置。流程順序大致如下:最先從核心空間裡的開機載入器 (Bootloader) 開始,到原生程式碼中開始程序,進入 B2G 再到使用者空間的 Gecko,最後到 Gecko 裡的系統 App、視窗管理器、主畫面 App。而其他 App 也同樣依照上述程序執行。

+ +

+ +

開機程序

+ +

在首次啟動 Firefox OS 裝置時,就會於主要的開機載入器 (bootloader) 中開始作業。自此,就如同一般作業系統程序,更高一階的開機相關載入器會載入執行,然後往上更高一階的載入器又會被接續執行,如此下去形成一串開機載入流程鏈,直到最後程序就會將執行權交到 Linux 核心。

+ +

關於開機程序有幾點需要注意:

+ + + +

Linux 核心

+ +

Gonk 使用 Linux 核心的版本,與 Android 開放源碼專案 (Android Open Source Project,AOSP) 所衍生使用的版本非常相似,但是並未沿用幾項 AOSP 所進行的修改。除外,雖然 Lunix 基本上已經相當穩定,但仍有些製造商會自行修改。

+ +

Linux 的啟動程序已經可在網路上找到相當詳盡的文件說明,所以在此不再贅述。

+ +

Linux 核心會啟動一些基本的程序 (Process)。在執行 init.rc 中定義的程序後,會再執行 init.b2g.rc 以啟動基本核心程序,如 b2g (Firefox OS 基礎程序,內含 Gecko) 以及 rild (通話功能的相關程序,各晶片組多有不同),請見下方所述細節。和大部分的 Unix 作業系統一樣,最後會啟動使用者空間 (Userspace) 程序。

+ +

在啟動 init 程序之後,Linux 核心就會處理由使用者空間傳來的系統呼叫,並中斷來自於硬體裝置的類似呼叫。許多硬體功能均透過 sysfs 揭露給使用者空間,以下便是 Gecko 讀取電池狀態的程式碼片段

+ +
FILE *capacityFile = fopen("/sys/class/power_supply/battery/capacity", "r");
+double capacity = dom::battery::kDefaultLevel * 100;
+if (capacityFile) {
+  fscanf(capacityFile, "%lf", &capacity);
+  fclose(capacityFile);
+}
+ +

更多有關 init 程序

+ +

Gonk 中的 init 程序,將處理必要的檔案系統並產生系統服務,之後就如同程序管理一般繼續待命,並將編譯指令碼 (也就是 init*.rc 檔案);指令碼內的指令則說明在啟動不同服務時所應進行的作業。

+ +

init 程序必須處理一個相當關鍵的作業,即啟動 b2g 程序;這也是 Firefox OS 的核心。

+ +

以下為 init.rc 中用以啟動 b2g 的程式碼:

+ +
service b2g /system/bin/b2g.sh
+    class main
+    onrestart restart media
+ +
+

注意:Firefox OS 與 Android 的 init.rc 之間的差異,將各款裝置而有所不同。有時候只是附加 init.b2g.rc,但有時修改的幅度甚大。

+
+ +

使用者空間 (Userspace) 的程序架構

+ +

現在讓我們來看看高階一點的部分,到底Firefox OS的各個元件之間是如何運作互動的。下圖所描述的是Firefox OS的主要使用者空間程序。

+ +

接著可進一步了解 Firefox OS 不同元件是如何運作互動。下圖呈現 Firefox OS 的主要使用者空間程序。

+ +

Userspace diagram

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+

注意:由於 Firefox OS 尚處於開發階段,所以此示意圖可能隨時修改而非完全正確。

+
+ +

b2g 程序是主要的系統程序,能以高權限存取大部分的硬體;b2g 可溝通數據機、畫出顯示緩衝區 (Framebuffer),並與 GPS 或相機等硬體溝通。在系統內部,b2g 則執行 Gecko 層 (即以 libxul.so 所實作)。另可參考 Gecko 以了解 Gecko 層的運作方式,以及 b2g 與 Gecko 層溝通的方法。

+ +

b2g

+ +

b2g 程序會生成許多低權限的內容程序 (Content process),並透過這些程序來載入 Web 的 App 與內容。這些程序會再透過訊息傳遞系統「IPDL」溝通 Gecko 伺服器。

+ +

b2g 程序所執行的 libxul,即參照 b2g/app/b2g.js 取得預設偏好設定。透過偏好設定,程序將開啟上述的 HTML 檔案「b2g/chrome/content/shell.html」,即於 omni.ja 檔案中編譯而得。而 shell.html 則包含了 b2g/chrome/content/shell.js 檔案,將觸發 Gaia 的「system」這個 App。

+ +

rild

+ +

rild 為銜接數據機處理器的介面,也是用以建構無線介面層 (Radio Interface Layer,RIL) 的常駐程式 (Daemon)。往往是由硬體製造商所撰寫的專屬程式碼,以溝通自家的數據機硬體。rild 可讓用戶端程式碼連接 rild 本身綁定的 Unix-domain socket。可經由以下類似的 init 指令碼啟動之:

+ +
service ril-daemon /system/bin/rild
+    socket rild stream 660 root radio
+ +

rilproxy

+ +

在 Firefox OS 中,rild 用戶端即屬於 rilproxy 程序,作為 rildb2g 之間不具功能的傳送代理dumb forwarding proxy。為何需要此代理伺服器,就必須從實作細節來說明了。但簡單來說,proxy 確實有其存在的必要。可到 GitHub 上找到 rilproxy 原始碼

+ +

mediaserver

+ +

mediaserver 程序用以控制音訊與視訊的播放作業。Gecko 透過 Android 的遠端程序呼叫 (Remote Procedure Call,RPC) 和其溝通。某些可由 Gecko 撥放的媒體檔案 (如 OGG Vorbis 音訊、OGG Theora 視訊、WebM 視訊等),均是由 Gecko 解碼後直接傳送給 mediaserver 程序。其他的媒體檔案則是交由 libstagefright 解碼。libstagefright 可存取特定編碼與硬體編碼器 (Hardware encoder)。

+ +
+

注意:mediaserver 程序為 Firefox OS 的「暫時性」元件,主要是協助早期的開發作業。預計最快在 Firefox OS 2.0 階段就會移除。

+
+ +

netd

+ +

netd 程序可用來設定網路介面。

+ +

wpa_supplicant

+ +

wpa_supplicant 程序為標準 UNIX 樣式常駐程式,可處理 WiFi 存取點的連線作業。

+ +

dbus-daemon

+ +

dbus-daemon 用以建構 D-Bus 訊息匯流系統,可供 Firefox OS 進行藍牙通訊作業。

+ +

Gecko

+ +

如前所述,Gecko 即由 Web 標準 (HTMLCSSJavaScript) 建構而成,並用以打造 Firefox OS 上所顯示的一切,另可控制手機硬體。Web App 則透過安全且受控制的 Web API (同樣以 Gecko 所建構而得) 來將 HTML5 連上硬體。Web API 可透過程式設計的方式,存取底層行動裝置硬體 (如電池或振動) 的功能,或取得儲存的資料 (如行事曆或聯絡資訊)。Web 內容亦可透過content invokes the accessible Web APIs within HTML5.

+ +

App 是由相關 HTML5 網頁內容所組成。如果要撰寫 Web App 並於 Firefox OS 行動裝置上執行,則開發者也只要組合、封包、發佈此網頁內容即可。而在執行期間,即交由瀏覽器轉譯、編譯、換至此網頁內容。可參閱應用程式中心 (App Center) 進一步了解。

+ +
+

注意:如果要搜尋 Gecko 的 Codebase,則可前往 http://dxr.mozilla.org,功能比較炫、參照功能不錯,但 Repo 較有限。亦可使用傳統的 http://mxr.mozilla.org,內含較多的 Mozilla 專案。

+
+ +

Gecko 架構圖

+ +

+ + + +

和 Firefox OS 相關的 Gecko 檔案

+ +

b2g/

+ +

b2g 資料夾主要包含 Firefox OS 相關功能。

+ +
b2g/chrome/content
+ +

內含於系統 App 上運行的 Javascript 檔。

+ +
b2g/chrome/content/shell.html
+ +

Gaia 的進入點。如前所述,shell.html 會拉進 shell.js 與 settings.js。用於系統 App 的 HTML。

+ +
<script type="application/javascript;version=1.8" src="chrome://browser/content/settings.js"> </script>
+<script type="application/javascript;version=1.8" src="chrome://browser/content/shell.js"> </script>
+ +

settings.js 裡面是系統預設的設定參數。

+ +
b2g/chrome/content/shell.js
+ +

shell.js 是載入 Gaia「system」App 的第一個指令碼。

+ +

shell.js 將匯入所有必要的模組、註冊關鍵的監聽器、定義 sendCustomEvent 與 sendChromeEvent 以溝通 Gaia、提供 webapp 安裝輔助程式:indexedDB 配額、遠端除錯器、鍵盤助手、螢幕截圖工具。

+ +

不過 shell.js 最重要的功能,則是啟動 Gaia 的「system」App,然後將整體系統相關的管理作業交給該「system」App。

+ +
let systemAppFrame =
+  document.createElementNS('http://www.w3.org/1999/xhtml', 'html:iframe');
+    ...
+  container.appendChild(systemAppFrame);
+ +
b2g/app/b2g.js
+ +

此指令碼包含預先定義的設定,就像是瀏覽器的 about:config,以及 Gaia 的 pref.js。這些設定值另可透過「設定 (Settings)」App 變更,也可用 Gaia 建置指令碼中的 Gaia’s user.js 覆寫之。

+ +

/dom/{API}

+ +

新實作的 API (post-b2g) 會位於 dom/ 資料夾。舊 API 位於 dom/base,例如navigator.cpp

+ +
/dom/apps
+ +

將載入 .jsm。而 .js API 實作即如 webapp.js 安裝、getSelf 等。

+ +
dom/apps/PermissionsTable.jsm
+ +

所有的存取權限都定義在 PermissionsTable.jsm 之中。

+ +

/dom/webidl

+ +

WebIDL是用以定義 Web API 的語言,請參閱 WebIDL_bindings 了解所支援的屬性。

+ +

/hal/gonk

+ +

此目錄包含 gonk 銜接層 (Port layer) 的相關檔案。

+ +

所產生的檔案

+ +
module/libpref/src/init/all.js
+ +

內有全部的設定檔。

+ +
/system/b2g/ omni.ja and omni.js
+ +

內有裝置內資源所適用的樣式。

+ +

處理輸入事件

+ +

Gecko 內絕大多數的行動,都是由使用者的行動所觸發,可用輸入事件為代表 (如按下按鈕、觸碰裝置的螢幕等)。這些事件必須透過 nsIAppShellGonk implementation (為 Gecko 介面之一,作為 Gecko App 的主要進入點),進入到Gecko。也就是說,輸入裝置驅動程式將呼叫 nsAppShell 物件 (代表 Gecko 子系統) 上的函式,來將事件發送到使用者介面。

+ +

例如:

+ +
void GeckoInputDispatcher::notifyKey(nsecs_t eventTime,
+                                     int32_t deviceId,
+                                     int32_t source,
+                                     uint32_t policyFlags,
+                                     int32_t action,
+                                     int32_t flags,
+                                     int32_t keyCode,
+                                     int32_t scanCode,
+                                     int32_t metaState,
+                                     nsecs_t downTime) {
+  UserInputData data;
+  data.timeMs = nanosecsToMillisecs(eventTime);
+  data.type = UserInputData::KEY_DATA;
+  data.action = action;
+  data.flags = flags;
+  data.metaState = metaState;
+  data.key.keyCode = keyCode;
+  data.key.scanCode = scanCode;
+  {
+    MutexAutoLock lock(mQueueLock);
+    mEventQueue.push(data);
+  }
+  gAppShell->NotifyNativeEvent();
+}
+ +

這些事件來自於Linux標準input_event系統. Firefox OS在其上添加了一層簡單的抽象層,提供了一些像是事件過濾等不錯的功能。產生事件的程式碼在widget/gonk/libui/EventHub.cpp裡的EventHub::getEvents()方法。

+ +

Gecko接收到事件後,這些事件會透過nsAppShell發送到DOM:

+ +
static nsEventStatus sendKeyEventWithMsg(uint32_t keyCode,
+                                         uint32_t msg,
+                                         uint64_t timeMs,
+                                         uint32_t flags) {
+    nsKeyEvent event(true, msg, NULL);
+    event.keyCode = keyCode;
+    event.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_MOBILE;
+    event.time = timeMs;
+    event.flags |= flags;
+    return nsWindow::DispatchInputEvent(event);
+}
+
+ +

之後,事件有可能被Gecko處理掉或是當作DOM事件發送到網頁應用程式做進一步處裡。

+ +

影像繪圖

+ +

在最底層,Gecko利用 OpenGL ES 2.0 向包有硬體影格緩衝區(frame buffers)的GL context物件繪圖,這是由Gonk所實作的nsWindow完成:

+ +
gNativeWindow = new android::FramebufferNativeWindow();
+sGLContext = GLContextProvider::CreateForWindow(this);
+ +

FramebufferNativeWindow類別(class)是直接從Android而來,請見FramebufferNativeWindow.cpp;使用了gralloc API存取繪圖驅動,好配對影格緩衝裝置的緩衝到記憶體之中。

+ +

Gecko透過圖層(Layers)系統合成螢幕上的影像,大體而言如下:

+ +
    +
  1. Gecko將不同部分的記憶體分頁(pages)畫入記憶體緩衝,有時後這些緩衝存在系統記憶體,有時候因為Gecko會直接畫入視訊記憶體(video memory),所以這些緩衝也可能會是配對在Gecko定址空間的材質(textures) ,以上的工作主要是由BasicThebesLayer::PaintThebes()方法完成。
  2. +
  3. Gecko利用OpenGL命令將這些材質合成起來,合成工作由ThebesLayerOGL::RenderTo()方法執行。
  4. +
+ +

因為有關Gecko如何處理影像繪圖的作法已經超出本文範圍,所以本文不再做進一步討論了。

+ +

硬體抽象層(Hardware Abstraction Layer, HAL)

+ +

Gecko HAL是Gecko接口層之一,它使用高階層Gecko能取用的C++ API存取跨平台間的底層系統介面,這些API以每個平台為基礎實作在Gecko HAL之內。Gecko的Javacsript程式碼並不能看到這個HAL層。

+ +

HAL如何運作

+ +

讓我們先來看看Vibration API。這個Gecko HAL API被定義在hal/Hal.h,基本上你可以看到如下函式(為了說明需要,經過函式簽名(function signature)簡化):

+ +
void Vibrate(const nsTArray<uint32> &pattern);
+ +

Gecko呼叫這個函式來根據某個特定型態開啟震動(另外有一個對應的函式用來關閉震動)。Gonk對這個函式的實作在hal/gonk/GonkHal.cpp:

+ +
void Vibrate(const nsTArray<uint32_t> &pattern) {
+  EnsureVibratorThreadInitialized();
+  sVibratorRunnable->Vibrate(pattern);
+}
+
+ +

下面以VibratorRunnable::Run()實作的程式碼發送震動開啟請求到另一個執行緒,其中主要的迴圈部分如下:

+ +
while (!mShuttingDown) {
+  if (mIndex < mPattern.Length()) {
+    uint32_t duration = mPattern[mIndex];
+    if (mIndex % 2 == 0) {
+      vibrator_on(duration);
+    }
+    mIndex++;
+    mMonitor.Wait(PR_MillisecondsToInterval(duration));
+  }
+  else {
+    mMonitor.Wait();
+  }
+}
+
+ +

vibrator_on()便是打開震動馬達的Gonk HAL API,這個函式透過sysfs向內部核心驅動程式送出訊息,寫入值到核心物件之中。

+ +

HAL API退回替代(Fallback)實作

+ +

Gecko HAL API 跨平台支援。當為沒有震動馬達的平台(如桌上型電腦)建置Gecko,則另一個HAL退回替代API會被使用,這個替代API實作於hal/fallback/FallbackVibration.cpp:

+ +
void Vibrate(const nsTArray<uint32_t> &pattern) {
+}
+ +

沙箱(Sandbox)實作

+ +

因為大多數的網頁內容都是在低權限的內容程序運行,所以我們無法確保這些程序有權限去,例如,打開震動馬達,除此之外,為了避免出現程序爭相啟動震動的狀況出現,採用中央控制的作法較為理想。在Gecko HAL,透過sandbox作法可以達到中央控制的目標;其實sandbox也就是一個由內容程序發出到Gecko"伺服器"的代理請求,這個代理請求式透過IPDL送出。

+ +

以震動為例,這是由hal/sandbox/SandboxHal.cpp所實作的Vibrate()完成:

+ +
void Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier &id) {
+  AutoInfallibleTArray<uint32_t, 8> p(pattern);
+
+  WindowIdentifier newID(id);
+  newID.AppendProcessID();
+  Hal()->SendVibrate(p, newID.AsArray(), GetTabChildFrom(newID.GetWindow()));
+}
+ +

這會發送一個 PHal 介面定義的訊息,亦即IPDL的hal/sandbox/PHal.ipdl內所描述的。其中呼叫的函式大致如下:

+ +
Vibrate(uint32_t[] pattern);
+ +

訊息的接收端是HalParent::RecvVibrate()函式,這個函式定義在hal/sandbox/SandboxHal.cpp裡面,大致如下:

+ +
virtual bool RecvVibrate(const InfallibleTArray<unsigned int>& pattern,
+            const InfallibleTArray<uint64_t> &id,
+            PBrowserParent *browserParent) MOZ_OVERRIDE {
+
+  hal::Vibrate(pattern, newID);
+  return true;
+}
+ +

本段範例雖然有省略一些相關性不高的部分,不過確實的說明訊息傳遞是如何由Gecko到Gonk,再到Gonk HAL實作Vibrate(),最後到震動馬達驅動程式。

+ +

DOM APIs

+ +

DOM介面是網頁根本上和Gecko溝通的方法,如果想知道更多這方面的細節,請參考關於DOM。 DOM介面是用IDL定義的,其中包括了外部函式介面(foreign function interface, FFI)以及介於javascript和C++的物件模型(object model, OM) 。

+ +

像是vibration API便是透過IDL讓網頁內容使用,這部分程式碼定義在nsIDOMNavigator.idl:

+ +
[implicit_jscontext] void mozVibrate(in jsval aPattern);
+ +

mozVibrate(冠有廠商前綴的函式,這個函式背後的震動規格尚未定案)接受jsval型態的參數,也就是Javascript的值。IDL編譯器xpidl,會產生C++的介面,這個介面會由Navigator.cpp內的Navigator類別實作之。

+ +
NS_IMETHODIMP Navigator::MozVibrate(const jsval& aPattern, JSContext* cx) {
+  // ...
+  hal::Vibrate(pattern);
+  return NS_OK;
+}
+ +

這個函式最關鍵的部分在於呼叫 hal::Vibreate() 將控制權由DOM移交給Gecko HAL,自此我們便會如前所述地進入HAL層,最後到達驅動程式。在上層的 DOM 並不在意現在是在哪個平台上執行(Gonk, WIndows, Mac OS X等等),DOM 也不在意現在是內容程序的程式碼在跑或是Gecko伺服器的在跑,所有的一切都交由底層系統處理。

+ +

vibration API相對單純,適合用於說明,而SMS API 便是比較複雜的API,它用到自己的"遠端"層將內容程序和伺服器連接起來。

+ +

無線介面層(Radio Interface Layer, RIL)

+ +

The userspace process architecture段落已經提過RIL,這邊我們將更進一步檢視各個元件是如何互動運作。

+ +

和RIL有關的元件有:

+ +
+
rild
+
和特定數據機韌體溝通的背景程序(daemon)。
+
rilproxy
+
rild和Gecko b2g程序之間訊息傳遞的代理背景程序(daemon)。rilproxy的存在解決了無法和rild直接溝通的問題,因為rild只可以在radio群組內溝通。
+
b2g
+
實作Gecko的程序,又稱為chrome process。其中和RIL相關的部分有dom/system/gonk/ril_worker.js(這是一個worker執行緒,會透過rilproxy和rild溝通,並且實作了無線狀態機(radio state machine))以及nsIRadioInterfaceLayer介面(是主執行緒的XPCOM服務,主要是作為ril_worker.js和Gecko各元件,包括Gecko內容程序,之間的訊息傳遞)。
+
Gecko's content process
+
nsIRILContentHelper介面會提供XPCOM服務,有了這個服務,Gecko內容程序會使用到的DOM API,例如TelephonySMS API,便能夠和Chrome程序的無線介面溝通。
+
+ +

範例: Example: Communicating from rild to the DOM

+ +

讓我們來看看一段例子,看一下系統底層是如何和DOM程式碼溝通。當數據機接收到來電時,它會透過專屬機制通知rild,rild接著按照ril.h內定義的"open"協定發送訊息到rild客戶端,以來電通話為例,RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 訊息會被rild發送至rilporxy。

+ +

實作在rilproxy.c的rilproxy會透過以下程式碼,和rild建立連線:

+ +
ret = read(rilproxy_rw, data, 1024);
+
+if(ret > 0) {
+  writeToSocket(rild_rw, data, ret);
+}
+ +

一旦從rild那裏取回訊息後,訊息便會經由連接rilproxy和Gecko的socket傳給Gecko,Gecko是藉由IPC thread接收訊息:

+ +
int ret = read(fd, mIncoming->Data, 1024);
+// ... handle errors ...
+mIncoming->mSize = ret;
+sConsumer->MessageReceived(mIncoming.forget());
+
+ +

訊息的接收端是SystemWorkerManager,然後訊息又會被重新打包發送到{source("dom/system/gonk/ril_worker.js", "ril_worker.js")}}執行緒,這個ril_worker.js實做了RIL狀態機(RIL state machine); 這其中的過程是透過 RILReceiver::MessageReceived()函式完成:

+ +
virtual void MessageReceived(RilRawData *aMessage) {
+  nsRefPtr<DispatchRILEvent> dre(new DispatchRILEvent(aMessage));
+  mDispatcher->PostTask(dre);
+}
+ +

訊息傳遞到ril_worker.js執行緒後,onRILMessage()函數接著會被呼叫。其中呼叫方法是利用Javascript API函式JS_CallFunctionName():

+ +
return JS_CallFunctionName(aCx, obj, "onRILMessage", NS_ARRAY_LENGTH(argv),
+                           argv, argv);
+ +

onRILMessage()定義在dom/system/gonk/ril_worker.js中;然後訊息會被切割成包裹,之後每一個包裹會被送給適當的處理函式:

+ +
handleParcel: function handleParcel(request_type, length) {
+  let method = this[request_type];
+  if (typeof method == "function") {
+    if (DEBUG) debug("Handling parcel as " + method.name);
+    method.call(this, length);
+  }
+}
+
+ +

ril_worker.js對每一個請求類型有實作一個同名的處理函式,所以程式碼能夠簡單地取得請求類型名稱,然後再比對是否有對應的函式存在,如果有便呼叫對應函式起來處理。

+ +

RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED為例,下面的處理函式會被呼叫:

+ +
RIL[UNSOLICITED_RESPONSE_CALL_STATE_CHANGED] = function UNSOLICITED_RESPONSE_CALL_STATE_CHANGED() {
+  this.getCurrentCalls();
+};
+ +

當收到訊息通知後,通話狀態也跟著改變,所以狀態機接著呼叫getCurrentCall()取得目前通話狀態:

+ +
getCurrentCalls: function getCurrentCalls() {
+  Buf.simpleRequest(REQUEST_GET_CURRENT_CALLS);
+}
+ +

這樣會回傳一個請求給rild,要求目前所有進行中通話的狀態。這個請求會沿著RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 訊息之前所行進過的路走,只不過方向相反(從 ril_worker.jsSystemWorkerManager 、到 Ril.cpp、再到rilproxy,最後是 rild socket)。 rild 然後會回應請求,再回到ril_worker.js的REQUEST_GET_CURRENT_CALLS訊息處理器,整個過程是雙向溝通。

+ +

通話狀態然後會被處理,和之前的狀態比較,如果狀態有變更,ril_worker.js 會再通知在主執行緒上的nsIRadioInterfaceLayer服務:

+ +
_handleChangedCallState: function _handleChangedCallState(changedCall) {
+  let message = {type: "callStateChange",
+                 call: changedCall};
+  this.sendDOMMessage(message);
+}
+ +

nsIRadioInterfaceLayer實作在dom/system/gonk/RadioInterfaceLayer.js,而訊息是透過onmessage()收到:

+ +
 onmessage: function onmessage(event) {
+   let message = event.data;
+   debug("Received message from worker: " + JSON.stringify(message));
+   switch (message.type) {
+     case "callStateChange":
+       // This one will handle its own notifications.
+       this.handleCallStateChange(message.call);
+       break;
+   ...
+
+ +

之後訊息會透過父程序訊息管理器(Parent Process Message Manager, PPMM)送到內容程序:

+ +
handleCallStateChange: function handleCallStateChange(call) {
+  [some internal state updating]
+  ppmm.sendAsyncMessage("RIL:CallStateChanged", call);
+}
+ +

內容程序透過nsIRILContentHelper 服務的receiveMessage()從子程序訊息管理器(Child Process Message Manager, CPMM)那裡接受訊息:

+ +
receiveMessage: function receiveMessage(msg) {
+  let request;
+  debug("Received message '" + msg.name + "': " + JSON.stringify(msg.json));
+  switch (msg.name) {
+    case "RIL:CallStateChanged":
+      this._deliverTelephonyCallback("callStateChanged",
+                                     [msg.json.callIndex, msg.json.state,
+                                     msg.json.number, msg.json.isActive]);
+      break;
+ +

接著,每一個電話callback物件的nsIRILTelephonyCallback.callStateChanged()方法會被呼叫;每一個有存取window.navigator.mozTelephony API的網頁應用程式會註冊這樣一個callback物件,這個callback物件會發送事件到網頁應用程式,如現階段通話物件狀態改變或有新通話來電事件。

+ +
NS_IMETHODIMP Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
+                                          const nsAString& aNumber, bool aIsActive) {
+  [...]
+
+  if (modifiedCall) {
+    // Change state.
+    modifiedCall->ChangeState(aCallState);
+
+    // See if this should replace our current active call.
+    if (aIsActive) {
+      mActiveCall = modifiedCall;
+    }
+
+    return NS_OK;
+  }
+
+  nsRefPtr<TelephonyCall> call =
+          TelephonyCall::Create(this, aNumber, aCallState, aCallIndex);
+  nsRefPtr<CallEvent> event = CallEvent::Create(call);
+  nsresult rv = event->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("incoming"));
+  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_OK;
+}
+ +

應用程式收到事件後可以跟著進行更新使用者介面等等:

+ +
handleEvent: function fm_handleEvent(evt) {
+  switch (evt.call.state) {
+    case 'connected':
+      this.connected();
+      break;
+    case 'disconnected':
+      this.disconnected();
+      break;
+    default:
+      break;
+  }
+}
+ +

更進一步的範例請見撥號應用程式的handleEvent()

+ +

3G data

+ +

有一個 RIL 訊息會向電信服務(cellular service)發起數據請求(data call),這會啟動數據機的數據傳輸狀態。數據請求會開啟 Linux 核心的Point-to-Point Protocol (PPP) 介面裝置,這個裝置能夠透過使用者介面設定。

+ +

相關DOM APIs

+ +

以下是和 RIL 溝通相關的DOM APIs:

+ + + +

WiFi

+ +

Firefox OS 的 WiFi 後端使用 wpa_supplicant 處裡大部份工作。所以說WiFi 後端的主要工作是管理請求者(supplicant),還有輔助一些任務,例如載入 WiFi 驅動程式和開關網路介面;從根本上來看,WiFi 後端就是一個狀態機(state machine),而其狀態會跟隨請求者狀態。

+ +
+

Note: 許多 WiFi 有關的有趣東西都和 wpa_supplicant 程序可能的狀態變更息息相關。

+
+ +

WiFi 元件的實作可以分成兩份檔案:

+ +
+
dom/wifi/DOMWifiManager.js
+
實作網頁內容所看到的API;定義在 nsIWifi.idl.
+
dom/wifi/WifiWorker.js
+
實作狀態機和驅動請求者的程式碼。
+
+ +

這兩份檔案利用訊息管理員(message manager) 溝通。 後端聆聽請求訊息,比如說"連接",然後回應訊息當請求行動完成後;DOM 端聆聽回應以及狀態改變和資訊更新的訊息。

+ +
+

Note: 任何同步 DOM API 都會藉由快取資料來實作,同步訊息會盡量避免。

+
+ +

WifiWorker.js

+ +

這份檔案實作了 WiFi 介面背後的主要邏輯,由 SystemWorkerManager 喚起,然後運行在 chrome 程序裡(對多執行緒版本來說)。 WifiWorker.js 可以切成兩塊: 一個巨大無名函式與 WifiWorker;無名函式會產出 WifiManager,為本地提供 API,包含和請求者連線以及可取得的掃描結果等事件通知,它會回應請求的資訊,控管和請求者連線的細節,遵照 API 使用客戶的指示行動。

+ +

WifiManager 和 DOM 中間是 WifiWorker 物件。WifiWorker 根據事件行動並且轉傳事件給 DOM,反過來,它也會收到 DOM 傳過來的請求,並且對請求者(supplicant)採取適當的動作,WifiWorker 也會維護請求者的狀態資訊和下不步行動的資訊。

+ +

DOMWifiManager.js

+ +

實作 DOM API,負責在呼叫方和 WiFi worker 之間傳遞訊息。

+ +
+

Note: 為了避免和 chrome 程序之間同步訊息,WiFi Manager 需要根據收到的事件快取狀態。

+
+ +

有一個同步訊息,那就是當 DOM API 初始化時為了取得請求者(supplicant)當下的狀態。

+ +

DHCP

+ +

DHCP 和 DNS 由標準 Linux DHCP 客戶端,dhcpcd,負責。當網路連線中斷後,因為無法運作,Firefox OS 會終止 dhcpcd,直到又重新連上網路,dhcpcd 會被再重啟。dhcpcd 也負責設定預設路徑(route)。

+ +

Network Manager

+ +

Network Manager 負責設定 3G 數據和 WiFi 元件的網路介面。

+ +

程序與執行緒

+ +

Firefox OS 採用 POSIX threads 實現所有應用程式的執行緒,這包括了應用成程式主執行緒、Web Worker 和輔助執行緒。Nice值決定了程序和執行緒的執行優先順序,然後再依賴 Linux 核心排程器先後執行;根據程序不同的狀態會有不同的Nice值。目前有7種Nice層級:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
程序執行優先順序
優先順序Nice用於
MASTER0主 b2g process
FOREGROUND_HIGH0持有 CPU wakelock 的程式
FOREGROUND1前景(foreground)程式
FOREGROUND_KEYBOARD1鍵盤程式
BACKGROUND_PERCEIVABLE7音樂播放背景(background)程式
BACKGROUND_HOMESCREEN18主畫面程式
BACKGROUND18其他背景程式
+ +

有些層級的 Nice 值雖然一樣,不過記憶體不足時的終止行為不一樣。所有的優先順序可以在建置時調整,相關的程式碼請見b2g/app/b2g.js

+ +

一個程序(process)之內,主執行緒繼承了該程序的 Nice 值,而 Web Worker 執行緒所得到的 Nice 值為主執行緒的加一點,所以優先權較低,這麼做是為了避免耗費 CPU 資源的worker 拖慢的主執行續的運作。程序優先順趣會因為事件發生而變化,比如說當一個程式由前景轉到背景時、一個新的程式啟動、現存程式取得 CPU wakelock,一旦程序的執行優先權變動,旗下所屬的執行緒的執行優先權也會跟著變動。

+ +
+

Note: cgroups 目前沒有在資源管理用上,因為在某些裝置和核心上並不可靠。

+
+ +

 

diff --git a/files/zh-tw/archive/b2g_os/automated_testing/gaia-ui-tests/gaia_ui_tests_run_tests/index.html b/files/zh-tw/archive/b2g_os/automated_testing/gaia-ui-tests/gaia_ui_tests_run_tests/index.html new file mode 100644 index 0000000000..3924fbf5a6 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/automated_testing/gaia-ui-tests/gaia_ui_tests_run_tests/index.html @@ -0,0 +1,111 @@ +--- +title: Gaia UI Tests Run Tests +slug: Archive/B2G_OS/Automated_testing/gaia-ui-tests/Gaia_UI_Tests_Run_Tests +translation_of: Archive/B2G_OS/Automated_testing/gaia-ui-tests/Gaia_UI_Tests_Run_Tests +--- +
+

這個頁面尚未完成。請有志一同的夥伴幫忙補充。
+ 有任何意見都可以寄到 gaia-ui-automation@mozilla.org。

+
+

Running Tests

+

    Basically, we can run gaia-ui-tests on a device with marionette server, emulators, and desktop B2G. However, please notice again that you should choose the right branch of gaia-ui-tests describing your B2G the best as we talked on previous section.

+

Testing on Devices

+

    First of all, connect your device through USB to computer, and then forward the package from the phone to computer port:

+
adb forward tcp:2828 tcp:2828
+
+

    You might get weird error, such as "no permission", from the command above. In that case, you could try to do the commands below:

+
adb kill-server
+sudo adb devices
+adb forward tcp:2828 tcp:2828
+
+

    It's almost all done before you start to run your tests! Before you start to run the test, read through this warning in order to start gaia-ui-tests correctly.
+     Now, you can send this command to execute all gaiatests:

+
gaiatest <gaia_ui_tests folder>/tests/ --address=localhost:2828 --type=b2g-xfail <your manifest file location>
+
+

    Or, if you want to run solely one file, just do:

+
gaiatest <file> --address=localhost:2828 --type=b2g-xfail <your manifest file location>
+
+

    After the test, you will see all the result on pass/fail. And, for each individual test, it might have more information that you can go through. Here are some common examples you might be able to see:

+ + + + + + + + + + + + + + + + + + + + + + + +
Error Message Corresponding Actions
error: [Errno 111] Connection refusedreissue adb forward command
Element ... not visible before timeoutmake sure the element would display on the app you test
TimeoutException: Condition timed outmake sure the condition on the app is the same as your expectations
broken pipmostly bad marionette server issue
+

 

+

Testing on Emulator

+

Automatically launched emulator

+
+

TODO

+
+

Mannually launched emulator

+
+

TODO

+
+

Testing on Desktop B2G

+

    After you downloaded the Gaia UI test from GitHub, you also can use desktop build to run the tests. The Firefox OS desktop client, also called the B2G desktop client,  lets you run Gaia and Web apps in a Gecko-based environment somewhat  similar to an actual device. It doesn't emulate device hardware, so it's  not adequate for testing device APIs, and isn't a replacement for  testing on actual hardware. However, it does have a several APIs enabled  that aren't available on Firefox such as the Contacts and Settings  APIs. It can therefore be useful during the development of your  application, or while working on the Gaia user interface itself.

+

    You can download the latest build of the desktop client from this location, but make sure you download the appropriate file for your operating system.

+ +
+

Note 1: Unfortunately, due to Bug 832469 the nightly desktop builds do not currently work on Windows, so you will need either Mac or Linux to continue :

+

Note 2: If you do not have the required operating systems installed on your machine, a virtual machine is fine as well.

+
+

    Once downloaded, you will need to extract the contents to a local folder. For the purposes of the rest of this guide, I’ll refer to this location as $B2G_HOME.
+ Add the following line to your gaia/profile/user.js file,

+
user_pref('marionette.force-local', true)
+

which on :

+ +

    Because we’re running against the desktop client we must filter out all tests that are unsuitable. To run the tests, use the following command:

+
gaiatest --address=localhost:2828 --type=b2g-antenna-bluetooth-carrier-camera-sdcard-wifi-xfail <your manifest file location>
+
+

Test Variables

+

    There is one warning previously mentioned here. Please do read the warning before you setup your json test variables file.

+

    We use the --testvars option to pass in local variables, particularly those that cannot be checked into the repository. For example in gaia-ui-tests these variables can be your private login credentials, phone number or details of your WiFi connection.

+

    To use it, copy testvars_template.json to a different filename but add it into .gitignore so you don't check it into your repository.

+

    When running your tests add the argument: --testvars=(filename).json

+

Variables

+

this_phone_number (string) The phone number of the SIM card in your device. Prefix the number with '+' and your international dialing code.

+

remote_phone_number (string) A phone number that your device can call during the tests (try not to be a nuisance!). Prefix the number with '+' and your international dialing code.

+

wifi.ssid (string) This is the SSID/name of your WiFi connection. Currently this supports WPA/WEP/etc. You can add WiFi networks by doing the following (remember to replace "KeyManagement" and "wep" with the value your network supports) :

+

"wifi": { "ssid": "MyNetwork", "keyManagement": "WEP", "wep": "MyPassword" }

+

WPA-PSK: "wifi": { "ssid": "MyNetwork", "keyManagement": "WPA-PSK", "psk": "MyPassword" }

+

Marketplace: "marketplace": { "username": "MyUsername", "password": "MyPassword" }

+
+

Due to Bug 775499, WiFi connections via WPA-EAP are not capable at this time.

+
+

 

+

Test Parameters

+

    As you see in the last command we gave out on previous sections, there are many test variables for you to know. You can do this to get more information:

+
gaiatest --help
+

 

+

Test Data Prerequisites

+

Occasionally a test will need data on the hardware that cannot be set during the test setUp. The following tests need data set up before they can be run successfully:

+

test_ftu Requires a single record/contact saved onto the SIM card to test the SIM contact import

+

 

+

Go to "Writing Tests" section

+

 

diff --git a/files/zh-tw/archive/b2g_os/automated_testing/gaia-ui-tests/index.html b/files/zh-tw/archive/b2g_os/automated_testing/gaia-ui-tests/index.html new file mode 100644 index 0000000000..2c11cea761 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/automated_testing/gaia-ui-tests/index.html @@ -0,0 +1,69 @@ +--- +title: Gaia UI Tests Guidelines +slug: Archive/B2G_OS/Automated_testing/gaia-ui-tests +translation_of: Archive/B2G_OS/Automated_testing/gaia-ui-tests +--- +
+

Gaia-ui-tests 是 Mozilla 的一套用於自動測試 Gaia UI 的架構。所有的測試都是以 Python 撰寫,佐以少數的 Javascript 來與 Firefox OS 的 API 溝通。此一系列的教學文章將會描述如何設定環境、撰寫及執行測試。

+
+

Gaia-ui-tests uses Gaiatest, a Python package based around Marionette. Gaiatest is designed to wrap HTML locators, Marionette calls and API calls together for interoperble communication and functionality. Marionette is based on the W3C standard developed for the Selenium WebDriver a programming interface for browser automation. If you have used WebDriver and page/app objects before then you will find using Marionette and gaiatest easy.

+

Getting started with Gaia UI tests

+

For those keen to get started with automated testing on Gaia/Firefox OS we have a tutorial series that will help you go from nothing to writing your own tests. Once you've completed this tutorial you'll have enough knowledge of testing, Firefox OS and Marionette to get started as a Mozilla tests contributor. It is highly recommended that you complete this tutorial if you wish to become a contributor.

+
+
+ Part 1: Getting started with Marionette and Firefox OS
+
+ This article covers installing the tools you need to get started with running tests, such as B2G Desktop, Python and Marionette.
+
+ Part 2: Basic interactions with Firefox OS using Marionette
+
+ An overview of the basic commands you will use to manipulate Firefox OS via Marionette.
+
+ Part 3: Upgrading our code into a reusable test
+
+ Moving on, in this article we will assemble some basic commands into a simple test inside a Python file so they can all be run as a single entity.
+
+ Part 4: Re-using commands to set up Firefox OS
+
+ Here we look at moving some of the commands into Python methods to promote code reuse.
+
+ Part 5: Introducing a test runner
+
+ A test runner is a central feature of any good test suite, allowing you to run multiple tests and report and aggregate results. In this article we will explore the basics of Python's unittest runner.
+
+ Part 6: Using tuples, and Marionette's By class
+
+ This time around we explain how to further reduce duplication of code, by storing repeated locators in tuples and simplifying the syntax with Marionette's By class.
+
+ Part 7: Writing your own tests
+
+ Now the basics and behind you, and it is time to start to writing your own tests! Here we give you some tool recommendations to make the work easier, and suggest some tests to try your hand at writing.
+
+ Part 8: Using a base class
+
+ In its current state, our test file contains all the test runner code. This is ok for now, but as soon as you start to run many test files it will mean a lot of duplication. Here we solve this problem by abstracting the test runner code into a separate Python class.
+
+ Part 9: Reducing duplication with app objects
+
+ As a final improvement to the code's maintainability, in this article we explore abstracting code that handles interaction with specific Firefox OS apps out into Python app objects.
+
+

Advanced topics

+

One you've got the basics of writing and running tests under your belt, you way want to move on to some more involved or advanced work, such as running the full gaia-ui-tests tests suite, or logging power draw as the result of a test.

+
+
+ Running the gaia-ui-tests
+
+ Guides to running the gaia-ui-tests suite against real Firefox OS devices and B2G Desktop in a variety of configurations.
+
+ Gathering Power Draw
+
+ How to use gaiatest to log power draw while a test is running.
+
+

See also

+

Gaia-ui-tests main repository

+

Questions/Comments/Concerns

+

This project is at a fairly early stage, and your feedback would be greatly appreciated:

+ diff --git a/files/zh-tw/archive/b2g_os/automated_testing/index.html b/files/zh-tw/archive/b2g_os/automated_testing/index.html new file mode 100644 index 0000000000..66f4eb520d --- /dev/null +++ b/files/zh-tw/archive/b2g_os/automated_testing/index.html @@ -0,0 +1,77 @@ +--- +title: 測試 Boot to Gecko +slug: Archive/B2G_OS/Automated_testing +translation_of: Archive/B2G_OS/Automated_testing +--- +

因為 Boot to Gecko 還在開發中,不久的將來即將有對新硬體的支援,因此如何做測試就是很重要的事情。這個頁面提供了從多種方面測試 Boot to Gecko 的文章及資訊。

+ + + + + + + +
+

Unit testing

+ +
+
+

Miscellaneous testing topics

+
+
+ Debugging OpenGL
+
+ How to debug OpenGL code on Boot to Gecko.
+
+ Feature support chart
+
+ A chart of what features are supported by the different builds of Boot to Gecko.
+
+

Marionette for Boot to Gecko

+ +

Gaia Unit Tests

+ +

Marionette Tutorials

+ +

Writing Tests For Marionette

+ +

View All...

+
+

Getting help from the community

+

If you're working with Boot to Gecko, or developing applications you'd like to run on Boot to Gecko based devices, there are community resources to help you!

+ +
    +
  • Ask your question on the Mozilla IRC channel: #b2g
  • +
+

Don't forget about the netiquette...

+
+ + +
+

 

diff --git a/files/zh-tw/archive/b2g_os/building/index.html b/files/zh-tw/archive/b2g_os/building/index.html new file mode 100644 index 0000000000..9e5c54202c --- /dev/null +++ b/files/zh-tw/archive/b2g_os/building/index.html @@ -0,0 +1,124 @@ +--- +title: 建置 Boot to Gecko +slug: Archive/B2G_OS/Building +translation_of: Archive/B2G_OS/Building +--- +
+
+

當您已經建立好編譯的系統、第一次成功地抓了程式碼以及設定好程式碼,您就可以編譯 Boot to Gecko。

+

更新程式碼

+

如果您不是第一次編譯B2G,您需要在編譯之前先抓取最新的程式碼。您可以執行以下指令來更新B2G工具及相依套件:

+
git pull
+./repo sync
+
+

您可以藉由指定名稱來更新某部分的倉儲:

+
./repo sync gaia
+
+

repo指令也有其他您可能會有興趣的選項可用;您可執行 repo help 指令來獲取有用的資訊。

+

編譯

+
+

注意:在編譯前,您可以設置一個 .userconfig 檔案來訂製這次編譯。使用 .userconfig 檔案來客製 有更多詳細資訊。

+
+

執行 build.sh 就可以開始編譯 Boot to Gecko:

+
cd B2G
+./build.sh
+
+

是時候該再喝杯咖啡,或小睡一下了(尤其是第一次編譯)。

+

專程編譯某些模組

+

如果您只想要編譯某個模組,例如 Gecko,您可以指定名稱:

+
./build.sh gecko
+
+

您也可以用這個指令來取得您編譯的模組的列表:

+
./build.sh modules
+
+

設定要使用的處理器數目

+

B2G 的編譯 scripts 預設使用系統的 cores 數量加二作為平行工作的數量。您可以再執行 build.sh 的時候指定 -j 參數來改變這個預設值。如果您想要把編譯工作丟到背景、並且減輕 CPU 負載來做其他事情的話,這對您就很方便。當您面臨到編譯問題時,如果您一次就只執行一個編譯工作的話、設定處理器數目也可以讓您更容易讀取編譯的錯誤輸出,真的很方便。

+

舉例來說,設定同時只會有兩個工作來編譯:

+
./build.sh -j2
+
+

對於此對常見的使用案例就是防止不要平行編譯。這會讓編譯的輸出更加容易閱讀,更容易釐清編譯的問題。執行下面指令:

+
./build.sh -j1
+
+

多語系編譯

+

建立多語系的編譯版本:

+

Gaia

+
    +
  1. 決定要用哪個 Gaia 語系檔。這邊我們用 locales/languages_dev.jsonlocales/languages_all.json 當做我們 Gaia 的語系檔。
  2. +
  3. Clone the appropriate locales
  4. +
  5. http://hg.mozilla.org/gaia-l10n 複製適當的語系到目錄下;這裡我們放於 gaia-l10n/ 下。接著您會需要將列於語系檔之內的美個語系的倉儲(repo)都複製下來。
  6. +
  7. 您需要將上面步驟二目錄的絕對路徑設定在 LOCALE_BASEDIR 環境變數中。也要把步驟一中檔案的絕對路徑設定在 LOCALES_FILE 環境變數中。
  8. +
+

如例:

+
export LOCALE_BASEDIR=$PWD/gaia-l10n
+export LOCALES_FILE=$PWD/gecko/gaia/shared/resources/languages-dev.json
+
+

Gecko

+
    +
  1. 決定要用哪個 Gecko 語系檔。這邊我們用 b2g/locales/all-locales 當做我們的 Gecko 語系檔。
  2. +
  3. 複製適當的語系到目錄下;像是 gecko-l10n/ 。 + +
  4. +
  5. 複製 compare-locales.
  6. +
  7. +

    將步驟二目錄的絕對路徑設定在 L10NBASEDIR 環境變數中。將步驟一中的語系以空白分隔方式設定在 MOZ_CHROME_MULTILOCALE 環境變數中。

    +
  8. +
  9. +

    compare-locales/scripts 目錄加入到 PATH 變數、 compare-locales/lib 加入到 PYTHONPATH 變數中.

    + 如例: +
    export L10NBASEDIR=$PWD/gecko-l10n
    +export MOZ_CHROME_MULTILOCALE="ja zh-TW"
    +export PATH="$PATH:$PWD/compare-locales/scripts"
    +export PYTHONPATH="$PWD/compare-locales/lib"
    +
    +

    當您完成這些設定之後,就可以執行 build.sh 了。

    +

    看起來您也可以用 .userconfig 來做這些事情。

    +

    當我們整理好之後,可能會修改這些指令。

    +
  10. +
+

已知的錯誤

+ +

當您的 gcc 版本太新的時候會出現這個錯誤。請安裝 gcc/g++/g++-multilib 4.6.x 版本.

+

設置您的編譯環境 有更多資訊。

+
+

社群上的提醒: 用 4.7.x 加上修改一些 B2G 程式碼可能可以 (gcc 會告訴你要改哪些地方) 但是這邊就沒人能幫你了!但是不改就不會碰到這些問題。

+
+ +

如果看到這個訊息,通常是代表記憶體不夠。在執行 ./build.sh 之前請確認有足夠的記憶體,如果您的系統記憶體有4G的話,應該可以跑的很順利。

+ +

有時候(尤其是在作業系統或是編譯工具更新後)您在編譯系統執行編譯後測試時,會碰到一些靈異現象就像下面這樣:

+
Generating permissions.sqlite...
+test -d profile || mkdir -p profile
+run-js-command  permissions
+WARNING: permission unknown:offline-app
+WARNING: permission unknown:indexedDB-unlimited
+build/permissions.js:122: NS_ERROR_UNEXPECTED: Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIPermissionManager.add]
+make[1]: *** [permissions] Error 3
+make: *** [gaia/profile.tar.gz] Error 2
+

這種情況下試著刪除 gaia/xulrunner-sdk 目錄然後再重新抓程式碼:

+
rm -r gaia/xulrunner-sdk
+
+

這樣會刪掉由編譯系統自動抓取、預先編譯的 XULRunner;在下一次編譯的時候,XULRunner 會再被自動抓取一份。

+

接著的步驟

+

在編譯後,下個步驟就取決於您編譯的 Boot to Gecko 是給模擬器還是給實體手機;細節請參考下列文章:

+ diff --git a/files/zh-tw/archive/b2g_os/building_and_installing_firefox_os/firefox_os_build_process_summary/index.html b/files/zh-tw/archive/b2g_os/building_and_installing_firefox_os/firefox_os_build_process_summary/index.html new file mode 100644 index 0000000000..0dc0cd18b7 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/building_and_installing_firefox_os/firefox_os_build_process_summary/index.html @@ -0,0 +1,108 @@ +--- +title: Firefox OS 建置程序摘要 +slug: >- + Archive/B2G_OS/Building_and_installing_Firefox_OS/Firefox_OS_build_process_summary +translation_of: Archive/B2G_OS/Building_and_installing_B2G_OS/B2G_OS_build_process_summary +--- +
+

建置和安裝Firefox OS需要大量的時間,網路頻寬和電腦計算能力。不幸的是,一路上事情很容易出問題,所以此頁面列出了建置的目標和步驟,希望可以在用戶建置的過程中幫上忙至於每一步驟的細節,會在其他文件討論

+
+
+

注:Firefox OS建置過程會提及到“B2G”或“Boot2Gecko”。“Boot2Gecko”是Firefox OS專案的原始代號名稱。

+
+

建置目標:4個“映像”檔

+

建置的目標是建立4個可以被複製到Firefox OS設備的映像檔。

+ + + + + + + + + + + + + + + + + + + +
boot.imgLinux核心和根檔案系統映像檔(root filesystem image),後者提供一套可用的基本Unix工具。
system.imgFirefox的操作系統核心,包括部分Gonk,Gecko的接口,可執行b2g檔。
userdata.img +

使用者的Gecko profile以及Gaia網頁應用程式。

+
recovery.imgLinux核心和根檔案系統映像檔,另外還有簡單的工具,好讓使用戶能夠從問題中修復
+

一旦四個映像檔產生好後,它們可以被轉移到一個裝置。

+

Firefox OS是建立在Android開源專案上(Android Open Source Project, AOSP)。AOSP的ADBfastboot工具提供了十分好用的方法來存取和操作設備。值得一提的是adb reboot-bootloader命令可以讓已經連接上的裝置重開機,並且暫停至bootloader早期階段,在這個早期階段中可以下fastboot flash $partition $image命令,把映像檔複製到裝置之上

+

開機映像檔(The Boot image)

+

boot.img(開機映像檔)包含Linux核心和初始根磁碟分區,boot.img提供核心軟體工具和初始化腳本。為了效率考量,初始根磁碟分區會被複製到記憶體之中,因此被稱為“ramdisk”。boot.img將被複製到設備上的“啟動”(boot)分區,而在裝置的檔案系統運作時,ramdisk的內容是可以在根目錄底下看見,比如說下adb shell指令

+

boot.img還在根目錄下的default.prop建立了root用戶的權限

+

另外也可以通過檔案檢查,分割檔案到核心和ramdisk映像檔,修改從ramdisk映像抓出來的內容,並重新組裝ramdisk映像檔,然後重新建置boot.img,這樣來修改現存的開機映像檔 。例如請參考Alcatel One Touch Fire Hacking (Mini)指南。

+

可以在安裝開機映像檔前測試開機映像檔。首先讓裝置開機後暫停於bootloader,然後下fastboot boot /some/path/to/boot.img命令來開機進入尚未安裝的boot.img。

+

系統映像

+

系統映像檔(system.img)是Firefox OS的核心:

+ +
+

關於平台架構的更多資訊,請見Firefox OS平台指南。

+
+

system.img會被複製到system分區,而在檔案系統運作時會在/system/目錄底下。

+
+

:system.img提供了許多裝置會用到的二進位大型物件(BLOB),特別是RIL(Radio Interface Layer)的blob控制了設備上的蜂巢式行動網路(cellular radio network)。

+
+

用戶資料映像檔

+

用戶資料應像檔(userdata.img)提供了運行中載入的各種Gaia應用程式。

+

userdata.img會被複製到裝置的userdata分區,然後檔案系統運作時會在/data/目錄底下。值得一提的是/data/b2g/目錄含有使用者的Gecko profile,而/data/local/webapps/目錄則含有使用者實際可以用的網頁應用程式

+

復原映像檔

+

復原映像檔(recovery.img)包含了和boot.img相同的核心和類似的ramdisk。然而,recovery.img採用不同的初始化腳本,所以使用者會被導引到另一個介面,這個介面會有可以透過裝置實體按鍵來操作的復原指令。

+

recovery.img會被複製到recovery分區,檔案系統運作時並不會掛載復原映像檔。

+

構建過程:準備,設定,建置,安裝

+

建置和安裝Firefox OS的整個過程包括四個步驟:

+ + + + + + + + + + + + + + + + + + + +
準備取得建置需要的程式和檔案,如正確的編譯器和函式庫。
配置下載原始碼,並創建.configure檔定義環境變數,例如路徑等。
建置 +

建置使用者的Gaia個人檔案和Gaia網頁應用程式。

+
安裝在設備上安裝檔案。
+

 

+

準備

+

一開始需要準備好建置需要的程式和檔案,如正確的編譯器和函式庫

+

這個步驟可以通過手動執行或使用腳本來完成。詳情將在建置Firefox OS的先決條件頁面討論

+
+

:在UNIX和類UNIX的機器,我們可以利用which指令,搭配需要的程式名稱當作變數,來檢查這些需要的工具是否存在。

+
+

設定

+

接著我們需要複製一份Firefox OS(B2G)的原始碼,通常可以透過git從B2G專案那裡複製一份,另外我們也需要產生一份.config檔,這個檔案會定義建置用的變數。

+

設定會執行config.sh腳本。詳情請見準備進行首次B2G建置頁面。

+

configure腳本需要一個參數,指定建置的裝置種類。建置名稱是和CPU架構而非裝置相關的代碼名稱,目前可取得的代碼名稱請見這裡

+

設定步驟也將使用Android開源專案的repo工具,來下載(或更新)建置的原始碼到/repo/project目錄下。這個步驟會下載大量的檔案並且花費不少時間。

+

建置

+

建置步驟實際上將編譯所有的原始碼,並且生成的映像檔。

+

建置會執行build.sh腳本。詳情請見建置Firefox OS頁面。

+

基本上建置十分單調,這個步驟就是從AOSP工具、到Linux核心、到Gaia網頁應用程式把一切都建置起來,而且有時候很不好判斷是那一個環節出錯導致建置失敗。

+

我們可以只建置全部的某一部份,例如執行建置腳本時只帶入gecko參數,就會只建置Gecko系統,相同地,只帶入gaia參數,就只會建置Gaia。這些分別建置的部份可以分別地被安裝到裝置上。

+

另外,也可以建置之前所討論的映像檔,例如建置系統映像檔可以這樣建置./build.sh out/platform/$target/system.img,其中$target參數和設定步驟中所提供的參數相同。

+

安裝

+

安裝的步驟會將新編譯的程式碼放置到設備上。這個步驟會執行flash.sh腳本。

+

如果只要安裝那些在建置步驟中分別被建置的部份,我們可以通過在執行falsh.sh時多帶入一個參數,例如./falsj.sh gaia就只會安裝Gaia網頁應用程式。

diff --git a/files/zh-tw/archive/b2g_os/building_and_installing_firefox_os/index.html b/files/zh-tw/archive/b2g_os/building_and_installing_firefox_os/index.html new file mode 100644 index 0000000000..f01f67100c --- /dev/null +++ b/files/zh-tw/archive/b2g_os/building_and_installing_firefox_os/index.html @@ -0,0 +1,65 @@ +--- +title: 建置並安裝 Firefox OS +slug: Archive/B2G_OS/Building_and_installing_Firefox_OS +translation_of: Archive/B2G_OS/Building_and_installing_B2G_OS +--- +

由於 Firefox OS 現正積極開發中,而且仍處於預先發佈的階段。如果要確保自己安裝的是最新版本,最好能自己動手建置並安裝。透過此頁面所整理的文章,你可在模擬器或相容裝置上建置並安裝 Firefox OS,或於 Firefox 瀏覽器上安裝 Gaia 使用者介面。

+

+ + + + + + + +
+

取得並建置 Firefox OS

+
+
+ Firefox OS 必備建置條件
+
+ 首次建置 Firefox OS 時的必要步驟。
+
+ 準備首次建置 Firefox OS
+
+ 在建置 Firefox OS 之前,必須先複製 Firefox OS 的 Repo 並完成細部設定。本篇文章將解釋相關細節。
+
+ 建置 Firefox OS
+
+ 建置 Firefox OS 的方法。
+
+ 匯入 Firefox OS
+
+ 將 Firefox OS 匯入新裝置的相關資訊。
+
+

全部文章...

+
+

安裝 Firefox OS 及/或 Gaia

+
+
+ 選擇 Gaia 或 Firefox OS 的執行方式
+
+ 可於 Firefox 中執行 Gaia;亦可於行動裝置或桌面版模擬器中執行 Firefox OS。本篇指南將協助你根據自己需要,找出最適合的方式。
+
+ 在 Firefox 中執行 Gaia
+
+ 於 Firefox 桌面版瀏覽器中執行 Gaia。
+
+ 使用 Firefox OS 桌面用戶端
+
+ 執行並使用 Firefox OS 桌面用戶端;即是在桌面版應用程式中模擬 Gaia 環境。相較於 Firefox 中執行 Gaia,此種方式雖然更精確,但仍不如模擬器所達的精確度。
+
+ 使用 Firefox OS 模擬器
+
+ 本指南將說名 Firefox OS 模擬器的建置與使用方式,及使用何種模擬器的適當時機。
+
+ 於行動裝置上安裝 Firefox OS
+
+ 在實際的行動裝置上安裝 Firefox OS。
+
+ 在 SGS2 上的 Firefox OS 與 Android 雙重開機
+
+ 於 Samsung Galaxy S2 上建立 Firefox OS/Android 雙重開機環境的方法。
+
+
+

 

diff --git a/files/zh-tw/archive/b2g_os/choosing_how_to_run_gaia_or_b2g/index.html b/files/zh-tw/archive/b2g_os/choosing_how_to_run_gaia_or_b2g/index.html new file mode 100644 index 0000000000..20566a839b --- /dev/null +++ b/files/zh-tw/archive/b2g_os/choosing_how_to_run_gaia_or_b2g/index.html @@ -0,0 +1,59 @@ +--- +title: 選擇如何運作 Gaia 或 B2G +slug: Archive/B2G_OS/Choosing_how_to_run_Gaia_or_B2G +translation_of: Archive/B2G_OS/Choosing_how_to_run_Gaia_or_B2G +--- +

根據各別的需求,當您以 Boot to GEcko 或是 Gaia 使用者介面時、您會思考各種選項及組合。您可以挑出接著列出的這些選項;每個選項都需要考慮其優缺點,有些會比其他的更具延展性。

+

在 Firefox 中運作 Gaia

+

如果您很清楚您在做什麼的話,您可以複製 Gaia 的 repository 並且 在 Firefox 15 或以上版本中運作 Gaia.

+

優點

+ +

缺點

+ +

為什麼要在 Firefox 中運作 Gaia

+

有兩個很重要的理由會讓您不在行動裝置或模擬器、而是在 Firefox 上運作 Gaia;容易開始著手開發和運作、也可以使用 Firefox 中優秀的開發者工具。如同要了解 Gaia 的 hackers 一般,開發者一開始測試 apps 的 UI 和基本功能的時候會享受到這極大的好處。

+
+ Note: 在開始配送 app 之前,您絕對會需要在實體的行動裝置上做測試。
+

在桌面環境中運作 B2G (模擬器)

+

可以自己建置一個 Boot to Gecko 模擬器,並且在上面運作 Gaia。這個軟體雖然是以 Firefox 為基礎,但和行動裝置上的 Boot to Gecko 的行為非常類似。現在 Mozilla 提供 nightly 版本的模擬器給開發者,且這項工作在 bug 744008 裡持續追蹤著。如果您熟悉建置 Firefox code-base 或是 C++ 專案的話,您可以 依循這些步驟 自己建置這個應用程式。

+

優點

+ +

缺點

+ +

為什麼要運作 B2G 模擬器

+

這是一個不錯且折衷的測試和開發解決方案。對於將您的 app 或是其他程式碼放在近似行動裝置的環境中、卻不用再每次測試時都燒進手機而言,是一個不錯的方案。

+
+ Note: 在開始配送 app 之前,您絕對會需要在實體的行動裝置上做測試。
+

在行動裝置上運作 B2G

+

對於測試 B2G 或 Gaia 環境、或是您的 web app 而言,最徹底的方式是建置並將 Boot to Gecko 安裝在實體的行動裝置上。同時這也是最複雜的處理程序。

+

優點

+ +

缺點

+ +

為什麼要在行動裝置上運作 B2G

+

對於在 B2G 或 Gaia 上測試任何程式或網頁專案而言,這毫無疑問地是最精準的方式。經由在實際的行動裝置硬體上執行,您可以確認您的專案表現及顯示都相當良好,並且都可以正確地使用所有的行動裝置 APIs。另外,在您開始配送任何程式之前,您應該一定要在實體行動裝置上測試;沒這樣做的話,一定會不幸地發生一些難以預測的影響。

diff --git a/files/zh-tw/archive/b2g_os/debugging/index.html b/files/zh-tw/archive/b2g_os/debugging/index.html new file mode 100644 index 0000000000..1084a2f201 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/debugging/index.html @@ -0,0 +1,21 @@ +--- +title: 在 Boot to Gecko 上除錯 +slug: Archive/B2G_OS/Debugging +translation_of: Archive/B2G_OS/Debugging +--- +

基本上,在 B2G 有兩種除錯的方法。開發者可以在電腦上藉由 Firefox 15 以上的版本來 執行 Gaia (以及很多相容於 B2G 的 web apps )來進行高階的除錯。這樣會讓開發者可以利用 Firefox 裡面優秀的 開發工具 開發工具來幫忙除錯,就像是在抓 web app 的 bug 一樣。

+

開發者也可以在 gdb 除錯器的控制之下,使用自己的行動裝置來執行 B2G。

+

使用 Firefox 除錯 Gaia 和 web apps

+

<快馬加鞭中,請耐心等待>

+

使用 gdb 除錯 B2G

+

用 gdb 來對 Boot to Gecko 除錯很簡單。只要用 run-gdb.sh 這個 script 指令,就會重新啟動 B2G 並在 gdb 的控制之下執行:

+
./run-gdb.sh
+
+

如果 B2G 已經在執行了,而現在只想要 attach,就要執行下面這個 script 指令:

+
./run-gdb.sh attach
+
+

OOP

+

首先,用「MOZ_DEBUG_CHILD_PROCESS=1 ./run-gdb.sh」啟動 b2g,接著當啟動 OOP app 的時候,會顯示 plugin-container 的 PID。使用<./run-gdb.sh attach PID>啟動第二個 gdb instance。

+

必須在很短的時間之內啟動除錯器的第二個 instance,且在啟動的短時間之內,就要按 c 繼續。

+

更多...

+

我們需要在這裡添加更多內容。

diff --git a/files/zh-tw/archive/b2g_os/firefox_os_build_prerequisites/index.html b/files/zh-tw/archive/b2g_os/firefox_os_build_prerequisites/index.html new file mode 100644 index 0000000000..dd2fd2efb5 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/firefox_os_build_prerequisites/index.html @@ -0,0 +1,606 @@ +--- +title: Firefox OS build prerequisites +slug: Archive/B2G_OS/Firefox_OS_build_prerequisites +translation_of: Archive/B2G_OS/B2G_OS_build_prerequisites +--- +
+

在您開始取得程式碼並建立您的Firefox OS作業系統以前,需要一個設定正確的編譯環境,請參考build system這個頁面,裡面有詳細的說明。這裡簡單的提一下,您可以在64位元的Linux以及OS X上面作編譯。

+
+ +
+

: 若您計畫編譯一個Firefox OS並裝載在一隻手機上,請確認該手機在編譯動作開始時"並未"跟您的電腦連接,正確的連結時機會在詳細步驟中說明。

+
+ +

支援的裝置或模擬器

+ +

您需要一個目標來裝載您建立的Firefox OS,他可以是一個真實的裝置或是一個模擬器。我們支援數種裝置但一個裝製常常有多種的版本,這樣的情況我們只支援特定的版本。另外不同的裝置我們的支援程度也稍有不同。

+ +
+

註:Mozilla的B2G source code是一個B2G的參考實現,而手機製造商是可以自由的為他們的手機做出patch以及修改的。舉例來說,您在市場上購買的Alcatel One Touch這隻手機裡面的B2G就是一個製造商的版本。這樣B2G版本的差異安裝在上面的應用程式是沒有差異的,不過在平台這一層是有一些差別的。由於Nexus 4的版本是直接由Mozilla維護的,因此跟其他第三級支援裝置比較起來我們各版本的Gecko應該更能直接在Nexus 4上直接無問題的使用。

+
+ +

第一級支援裝置

+ +

第一級支援裝置是一些主要開發用的裝置,因此一般來說能得最快的新功能與新的bug fixes。

+ +
+
Keon
+
Keon 即為 Geeksphone Keon 裝置, 也是最初的開發機種中的一個。 請注意這個裝置上的Forefox OS是由 Geeksphone提供.
+
Inari
+
Inari 是另外一個測試裝置. 在您建立Firefox OS給ZTE Open的裝置時請使用這個configuration (configuration的細節後面會提到)。注意: 較新版本的Firefox版本可能會無法在ZTE Open手機的default boot partition中開機成功。
+
Flame
+
Flame 是 Mozilla 最新的 Firefox OS 標準參考開發裝置,除了Flame這隻手機以外,在您建立給 ZTE Open C 這個裝置的Firefox OS時請也在configuration 中選用Flame(configuration 的細節後面會提到)。 兩隻手機都用一樣的設定原因是他們都是基於 Android jellybean。
+
模擬器 (ARM 與 x86)
+
有兩種模擬器,一種是模擬ARM code,另外一種直接用x86 code執行所有的功能. 更多相關資訊請參考Learn more about installing and using the emulators.
+
請注意基本上您應該不要使用 x86 模擬器 — 這個模擬器安裝不易而且支援的程度不是很理想。
+
桌面 client 程式
+
您也可以建立一個桌面版本的Firefox OS; 這個版本是讓 Gecko 跑在一個 XULRunner 程式裡面讓您可以使用 Gaia 提供的使用者界面.
+
Flatfish
+
Flatfist 是第一隻 Firefox OS 平板版本,雖然某些功能像是Web Telephony 沒有辦法使用。在編譯 Flatfish 時,會需要一些額外的設定
+
+ +

另外雖然可能很顯而易見,還是提一下您在建立 桌面 client 程式 或任意一個 模擬器 時是不需要手機的。

+ +

第二級支援裝置

+ +

一般來說,Firefox的功能在第二級支援裝置上都是可用的,這一些裝置被許多開發者使用(特別是應用程式開發者),因此並不需要太過即時的得到Firefox OS上新的改變。

+ +
+
Samsung Nexus S
+
已知的 Nexus S 支援型號為 GT-I9020A 以及 GT-I9023,其他的型號可能可以支援
+
Samsung Nexus S 4G
+
SPH-D720 這個型號被當作第二級的支援裝置
+
+ +

第三級支援裝置

+ +

給這一些裝置的Firefox OS是可以被建立的,不過工程師並不會時常用這一些裝置做開發,因此穩定度與功能上面會明顯的比前兩級的支援裝置要不足。

+ +
+
Samsung Galaxy S2
+
只有i9100這個型號是被正式支援的。(i9100P 應該也可以支援因為差異只在 NFC 晶片)
+
Samsung Galaxy Nexus
+
現在看起來所有的型號都可以支援
+
Nexus 4
+
有一些在 IRC 上的使用者測試並成功過。 如果機器本身是 Android 4.4 也許需要降回 4.3 (Android images available from Google)
+
Nexus 5
+
一些在 IRC 上的使用者測試並成功過。
+
Tara
+
Tara 是另一之測試裝置. Tara 的 manifest 只在 master branch. 取得 Tara 的 script 為 "BRANCH=master ./config.sh tara"。
+
Unagi
+
Unagi 用來當作中低階智慧型手機的測試與開發裝置。很多 Firefox OS的開發者使用 Unagi 作開發。
+
Pandaboard
+
Pandaboard 是一片基於 OMAP 4 架構的開發板,作為在各種不同行動平台的開發使用。
+
+ +
重要: 只有基於 Android 4 (aka Ice Cream Sandwich) 以上的裝置才被支援。若您手上的裝置是上面提到的其中之一但 Android 的版本比較舊,請務必在做任何動作前先將它升級。
+ +
+

: 第二級與第三級支援裝置沒有硬體的 Home 按鈕,不過會有一個軟體的 Home 按鈕

+ +

所有第一級支援裝置都有一個硬體的 Home 按鈕,這個按鈕可以讓使用者直接回到 Home screen。現在市面上大多數基於 ICS 的 Android 裝置使用在螢幕上的觸碰按鍵。我們現在提供一個虛擬的 Home 按鈕給這一些缺少硬體按鍵的裝置。若您發現這個虛擬的 Home 按鈕沒出現,請打開 Setting 程式,然後到 Developer settings 並選取 Enable software home button

+ +

在 Firefox OS 1.4 版有另外一個 developer option 叫做 "Home gesture enabled"; 開啟這的選項表示虛擬的 Home 按鈕將消失,取而代之的是一個由螢幕下方向上滑動的手勢。

+
+ +

使用 GNU/Linux 的需求

+ +
+

重要: 即使您沒有要編譯自己的 Boot 2 Gecko,而只有要使用到 Gaia's make system,  您仍需要正確版本的 PythonNode.js

+
+ +

在 Linux 建立 Firefox OS, 您需要:

+ + + +

這其實比最低需求要高不過常常在建立 Firefox OS 的過程出現問題只是因為資源不太夠。一個常見的例子為 "arm-linux-androideabi-g++: Internal error: Killed (program cc1plus)".

+ +

下面列出個工具也必須被安裝:

+ + + +

64 位元安裝需求

+ +

這個部份列出了一些在不同的Linux發行版本中你必須執行的指令, 以利於安裝所有的需求來建構 Firefox OS.

+ +

Ubuntu 12.04 / Linux Mint 13 / Debian 6

+ +

在終端機中執行下列指令:

+ +
sudo apt-get update
+sudo apt-get install autoconf2.13 bison bzip2 ccache curl flex gawk gcc g++ g++-multilib git ia32-libs lib32ncurses5-dev lib32z1-dev libasound-dev libgconf2-dev libgl1-mesa-dev libx11-dev lzop make zip
+ +

如果您將建構 "Flame" reference device 或是 Nexus 5, 請在終端機執行以下指令:

+ +
sudo apt-get install libxml2-utils 
+ +

您可以透過這個ppa來安裝 jdk。

+ +

And see the above comments about emulator build issues!

+ +

Ubuntu 12.10 / Debian 7

+ +

在終端機中執行下列指令:

+ +
sudo apt-get install autoconf2.13 bison bzip2 ccache curl flex gawk gcc g++ g++-multilib gcc-4.6 g++-4.6 g++-4.6-multilib git ia32-libs lib32ncurses5-dev lib32z1-dev libgl1-mesa-dev libx11-dev make zip
+ +

In addition to the emulator build issues discussed above, the compiler will default to gcc-4.7, which will fail to build with an error along the following lines:

+ +

"KeyedVector.h:193:31: error: indexOfKey was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation"

+ +

To fix this, you will need to specify GCC 4.6 as the default host compiler after having retrieved the B2G sources: Read Changing the default host compiler to find out how to do it.

+ +

In a fresh Ubuntu 12.10 install, you'll get an error about unmet dependencies for ia32-libs. The following commands fix it:

+ +
sudo dpkg --add-architecture i386
+sudo apt-get update
+sudo apt-get install ia32-libs
+ +

Ubuntu 13.04

+ +

Run the following command in Terminal:

+ +
sudo apt-get install --no-install-recommends autoconf2.13 bison bzip2 ccache curl flex gawk gcc g++ g++-multilib gcc-4.6 g++-4.6 g++-4.6-multilib git ia32-libs lib32ncurses5-dev lib32z1-dev zlib1g:amd64 zlib1g-dev:amd64 zlib1g:i386 zlib1g-dev:i386 libgl1-mesa-dev libx11-dev make zip
+ +

In addition to the emulator build issues discussed above, the compiler will default to gcc-4.7, which will fail to build with an error along the following lines:

+ +

"KeyedVector.h:193:31: error: indexOfKey was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation"

+ +

To fix this, you will need to specify GCC 4.6 as the default host compiler after having retrieved the B2G sources: Read Changing the default host compiler to find out how to do it.

+ +

Ubuntu 13.10

+ +

With Ubuntu 13.10, multi-arch packages are now the main way to support multiple architectures (e.g. 32-bit on a 64-bit install).  You must tell your Ubuntu system that you want to support 32-bit packages as well:
+  

+ +
sudo dpkg --add-architecture i386
+sudo apt-get update
+ +

Once you've completed that, then you can install the necessary packages:

+ +
sudo apt-get install --no-install-recommends autoconf2.13 bison bzip2 ccache curl flex gawk gcc g++ g++-multilib gcc-4.6 g++-4.6 g++-4.6-multilib git lib32ncurses5-dev lib32z1-dev zlib1g:amd64 zlib1g-dev:amd64 zlib1g:i386 zlib1g-dev:i386 libgl1-mesa-dev libx11-dev make zip libxml2-utils
+
+sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 1
+
+sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 2
+
+sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.6 1
+
+sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 2
+
+sudo update-alternatives --set gcc "/usr/bin/gcc-4.6"
+
+sudo update-alternatives --set g++ "/usr/bin/g++-4.6" 
+ +

Ubuntu 14.04

+ +

Follow the instructions given for Ubuntu 13.10.

+ +

Fedora 17/18/19/20

+ +

Run the following command in Terminal:

+ +
sudo yum install autoconf213 bison bzip2 ccache curl flex gawk gcc-c++ git glibc-devel glibc-static libstdc++-static libX11-devel make mesa-libGL-devel ncurses-devel patch zlib-devel ncurses-devel.i686 readline-devel.i686 zlib-devel.i686 libX11-devel.i686 mesa-libGL-devel.i686 glibc-devel.i686 libstdc++.i686 libXrandr.i686 zip perl-Digest-SHA wget
+ +

In addition to the above you will need GCC 4.6.x in order to compile the project:

+ + + +

Download the right version for your Fedora installation, then install it to /opt, with the following command on Fedora 17/18:

+ +
curl -O http://people.mozilla.org/~gsvelto/gcc-4.6.4-fc18.tar.xz
+sudo tar -x -a -C /opt -f gcc-4.6.4-fc18.tar.xz
+
+ +

And with the following command for Fedora 19/20:

+ +
curl -O http://people.mozilla.org/~gsvelto/gcc-4.6.4-fc19.tar.xz
+sudo tar -x -a -C /opt -f gcc-4.6.4-fc19.tar.xz
+
+ +

You will need to specify GCC 4.6.x as the default host compiler after having retrieved the B2G sources: Read Changing the default host compiler to find out how to do it.

+ +

If build fails with the compiler complaining about not finding libmpc.so.2, install the package compat-libmpc

+ +

Arch Linux

+ +

Run the following command in Terminal:

+ +
sudo pacman -S --needed alsa-lib autoconf2.13 bison ccache curl firefox flex gcc-multilib git gperf libnotify libxt libx11 mesa multilib-devel wget wireless_tools yasm zip lib32-mesa lib32-mesa-libgl lib32-ncurses lib32-readline lib32-zlib
+ +

To install the lib32-* packages you need to have the multilib repository enabled.

+ +

B2G can only be compiled with gcc4.6.4, and because Arch Linux always has bleeding edge software you will need to install gcc46-multilib from AUR. Note that you will have to edit the PKGBUILD and add staticlibs to the options array, or gcc will be unable to compile B2G and give you a cannot find -lgcc error when compiling. You will also need to add the following to your .userconfig file:

+ +
export CC=gcc-4.6.4
+export CXX=g++-4.6.4
+ +

By default, Arch Linux uses Python3. You'll have to force it to use the old python2. You can do that by linking the python2 executable to python but this is discouraged and considered error-prone. This will also break python 3 if it is installed on your system. A better way is to use virtualenv/virtualenvwrapper:

+ +
sudo pacman -S python-virtualenvwrapper
+source /usr/bin/virtualenvwrapper.sh
+mkvirtualenv -p `which python2` firefoxos
+workon firefoxos
+
+ +

Android will complain that you need make 3.81 or make 3.82 instead of 4.0. You can download make 3.81 from AUR.  This will install the make-3.81 binary on your path, you need to create a symlink named make to a location earlier in the PATH variable for the build to use the correct version.

+ +
mkdir -p ~/bin
+ln -s `which make-3.81` ~/bin/make
+export PATH=~/bin:$PATH
+
+ +

Android also needs the Java6 SDK and Arch only has Java7.  Unfortunately the aur build is broken, but you can still download the Java 6 SDK and install it manually.  You will then need to put it in your path.

+ +
cp ~/Downloads/jdk-6u45-linux-x64.bin /opt
+su
+cd /opt
+chmod +x jdk-6u45-linux-x64.bin
+./jdk-6u45-linux-x64.bin
+exit
+ln -s /opt/jdk1.6.0_45/bin/java ~/bin/java
+
+
+ +

Gentoo Linux

+ +
Installing ccache
+ +

You will need to install ccache, a tool for caching partial builds.

+ +
# emerge -av ccache
+
+ +

Because ccache is known to frequently cause support issues, Gentoo encourages you to use it explicitly and sparingly.

+ +

To enable the required use of ccache, on the subsequent step of this guide where the ./build.sh script is called, Gentoo users should instead run the command with an explicitly extended path, ie.

+ +
PATH=/usr/lib64/ccache/bin:$PATH ./build.sh
+
+ +
Generating Partition Images
+ +

If you are building B2G for actual physical hardware, then you may at some point also wish to generate some partition images for upload to your device. (For example, to restore backed up files to the device via the fastboot utility)

+ +

The filesystem image format used in this case is YAFFS2 (Yet Another Filesystem 2). Gentoo has support for the very latest (ie. git HEAD) yaffs2-utils userland package in portage. (Note: You will also need kernel patches if you want to mount YAFFS2 images, but this is not really required since you can deconstruct and rebuild them instead.)

+ +
# emerge --autounmask-write yaffs2-utils; etc-update; emerge -av yaffs2-utils
+ +

In order to generate such an image, simply change to the parent directory of the partition filesystem tree you wish to package, and issue a command like this:

+ +
mkyaffs2image system/ system.img
+ +

使用 Mac OS X 的需求

+ +

要在Mac OS X 上建構 Firefox OS, 您必須遵循一些步驟, 以下將會詳細說明. 我們也會提出一些您可能在特殊情況下會遇到的錯誤, 以及他們的解決方法.

+ +
+

Note: Configuring and Building B2G for Keon WON'T WORK on a Mac. You'll need to use Linux to build B2G for this device.

+
+ +

版本相容性

+ +

XCode 4.2 以下的版本與 Mac OS X 10.9 (a.k.a. "Mavericks") 並不相容, 所以您可能會很驚訝地發現Firefox OS會建構錯誤. 基本上您無法在 Mac OS X 10.9 以上的版本建構 ICS emulator, 並且 flatfish 在XCode 5.x系列會無法建構.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mac OS X 10.9.x 的版本相容性
 emulator (ICS)flatfish (JB-4.2)emulator-jb (JB-4.3)emulator-kk (KitKat-4.4)
XCode 4.3.3XXXX
XCode 4.4.1XO[1]OO
XCode 4.5.2XO[1]OO
XCode 4.6.3XO[1]OO
XCode 5.0.2XXOO
XCode 5.1.1XXOO
+ +
    +
  1. 您必須將設定環境變數 BUILD_MAC_SDK_EXPERIMENTAL=1 並將其 export  以建構 flatfish.
  2. +
+ +

安裝 XCode Command Line Utilities

+ +

您必須安裝 Xcode's Command Line Utilities. 您可以只下載 Command Line Utilities, 只需要在 Apple's developer downloads page 挑選您的 OS X 版本, 然而如果您想要完整的 Xcode suite, 你可以在 Mac App Store 安裝他們

+ +

Xcode 4.3.1 (OS X 10.7 "Lion") 以及其他較新的版本如 4.4.1+ (也就是 Mac OS X 10.8 "Mountain Lion"), 並不會自動包含我們所需的 Command Line Utilities. 當您安裝 Xcode 時, 請確認進入 Preferences, then the Downloads panel, and install the Command Line Utilities. 另外, 請確認您至少有 20 GB 的硬碟空間.

+ +

Screenshot of Xcode Downloads Command Line Tools

+ +
+

Note: The Firefox OS 模擬器 需要 Core 2 Duo processor 或較新的處理器; 也就是, 一個相容於Mac OS X 10.7 "Lion"的作業系統. 您的作業系統不一定要是OS X Lion, 您只需要與其相容. 也就是您當然可以建構Firefox OS 在較舊版本的Mac 上.

+
+ +
+

Note: XCode 4.2.x or older is not compatible with Mac OS X 10.9 or above, and XCode 4.3.x has no platform SDK for 10.8. Please install a newer version. If you're also working on flatfish, please make sure any of XCode 4.4, 4.5, and 4.6 is available.

+
+ +

Run Firefox OS Mac Bootstrap

+ +

Next, open a terminal and run the following command:

+ +
curl -fsSL https://raw.github.com/mozilla-b2g/B2G/master/scripts/bootstrap-mac.sh | bash
+ +

This will pull and run a bootstrap script that makes sure you have all the prerequisites met to build the emulator. It will also prompt you for permission to install anything you're missing, and provide warnings and suggested fixes to problems. The script will check for and install the following items:

+ + + +

Xcode wrangling

+ +

If you have already upgraded to Xcode 4.4+ and get the message that Xcode is outdated, check the Xcode path with:

+ +
xcode-select -print-path
+ +

If it still points to /Developer you can update the path with:

+ +
sudo xcode-select -switch /Applications/Xcode.app
+ +

Making the Mac OS X 10.6 SDK available

+ +

You also need to have the Mac OS X 10.6 SDK available. The SDK needs to be available at

+ +
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
+ +

If it cannot be found there you will need to extract and copy it from Xcode 4.3. To do this:

+ +
    +
  1. Download the XCode 4.3 .dmg file from the Apple Developer portal (you'll need an Apple Developer account).
  2. +
  3. Download the utility Pacifist and use it to extract the 10.6 SDK from the XCode 4.3 .dmg file. Click on the "Extract Package" button, find the SDK by searching for 10.6 in the search box, then Ctrl + click on the MacOSX10.6.sdk directory and Extract it to a suitable location.
  4. +
  5. Add a symlink from the 10.6 SDK location to the /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ directory. For example, if you put the 10.6 SDK on your desktop, the comment would be
  6. +
+ +
ln -s /Users/<yourusername>/Desktop/MacOSX10.6.sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
+ +
+

Note: This is not necessary for Mac OS X 10.9 or above, because 10.6 SDK is for ICS and ICS doesn't supports Mac OS X 10.9.

+
+ +

Be aware of Mac file system case sensitivity

+ +

By default, Mac OS X ships with a case-insensitive file system.  This is problematic because the Linux kernel has a number of files with the same name, but different case.  For example, see the header files xt_CONNMARK.h and xt_connmark.h.  This results in a number of files appearing to be modified in /kernel after a fresh ./config.sh.

+ +

In many cases you can run the build just fine; for some platforms, however, you may encounter the following error:

+ +
ERROR: You have uncommited changes in kernel
+You may force overwriting these changes
+with |source build/envsetup.sh force|
+
+ERROR: Patching of kernel/ failed.
+ +

Please see bug 867259 for more discussion and possible fixes for this problem.

+ +

Alternatively, it will always be safest to build on a case sensitive file system.  The easiest way to do this is to create a separate, mountable disk image with case-sensitivity enabled.  You can do this using Apple's Disk Utility application or from the command line:

+ +
hdiutil create -volname 'firefoxos' -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 40g ~/firefoxos.sparseimage
+ +

Mount the drive with:

+ +
open ~/firefoxos.sparseimage
+ +

Change into the mounted drive with:

+ +
cd /Volumes/firefoxos/
+ +

You can then check out the code and compile from this location without worrying about case-sensitivity problems.

+ +

Mountain Lion homebrew gotcha

+ +
+
If you are on Mountain Lion and you receive an error during the installation of the dependencies via homebrew, such as:
+
+ +
+
clang: error: unable to execute command: Segmentation fault: 11
+... try reinstalling the dependency manually adding the --use-gcc flag, for example: + +
brew install mpfr --use-gcc
+
+ +

Follow Samsung Galaxy S2 extra steps

+ +

If you plan to build for the Samsung Galaxy S2, you will also need to install heimdall. See {{ anch("Installing heimdall") }} for details. This is not done for you by the bootstrap script!

+ +
Note: If you have installed the Samsung Kies tool, which is used to manage the contents of many Samsung phones, you will have to remove it before you can flash Firefox OS onto your device. You can use the standard application removal process on Windows; on Mac, the Kies install disk image has a utility to fully remove Kies from your system. Flashing will not work if you have Kies installed. If you forget to remove Kies, the build system will detect it and remind you to uninstall it. Note also that the uninstall tool does not correctly remove the folder ~/Library/Application Support/.FUS, and leaves a reference to a utility there in your user startup items list. You will want to remove these manually.
+ +

Fix libmpc dependency if broken

+ +

gcc 4.6 was built with libmpc 0.9; if you then use homebrew to update packages, libmpc gets updated to version 1.0, but homebrew doesn't rebuild gcc 4.6 after the library version changes. So you need to create a symlink to make things work again, like this:

+ +
cd /usr/local/lib/
+ln -s libmpc.3.dylib libmpc.2.dylib
+ +

Optional: Install HAX

+ +

Intel provides a special driver that lets the B2G emulator run its code natively on your Mac instead of being emulated, when you're using the x86 emulator. If you wish to use this, you can download and install it. It's not required, but it can improve emulation performance and stability.  

+ +

Before you install HAX you will need to install the Android SDK.

+ +

Install adb

+ +

The build process needs to pull binary blobs from the Android installation on the phone before building B2G (unless you're building the emulator, of course).  For this, you will need adb, the Android Debug Bridge. Our Installing ADB article explains how to get adb installed.

+ +
+

Note for future when you start to use adb: adb needs the phone's lock screen to be unlocked in order to see your phone (at least in later versions of Firefox OS). You'll probably want to disable the lock screen (we'll get to how later in the build instructions).

+
+ +

Install heimdall

+ +

Heimdall is a utility for flashing the Samsung Galaxy S2. It's used by the Boot to Gecko flash utility to replace the contents of the phone with Firefox OS, as well as to flash updated versions of B2G and Gaia onto the device. You'll need it if you want to install Firefox OS on a Galaxy S2; it is not needed for any other device. For other devices, we build and use the fastboot utility instead.

+ +
Note: Again, it's important to note that this is only required for installing Firefox OS on the Samsung Galaxy S2.
+ +

There are two ways to install heimdall:

+ + + +

Configure ccache

+ +

The B2G build process uses ccache. The default cache size for ccache is 1GB, but the B2G build easily saturates this; around 3GB is recommended. You can configure your cache by running the following command inside terminal:

+ +
$ ccache --max-size 3GB
+ +

For Linux: configure the udev rule for your phone

+ +
+

Note: This section is specific to Linux; Mac OS X has the necessary device permissions set up already.

+
+ +

Next, you need to confingure the udev rule for your phone,

+ +

You can get the USB vendor ID by running lsusb with your phone plugged in, but typically it's Google 18d1, Samsung 04e8, ZTE 19d2, Geeksphone/Qualcomm 05c6. Add this line in your /etc/udev/rules.d/android.rules file (replacing XXXX with the ID for your device):

+ +

相容的

+ +
SUBSYSTEM=="usb", ATTR{idVendor}=="XXXX", MODE="0666", GROUP="plugdev"
+ +

Take ZTE for example, the content in android.rules will be

+ +
SUBSYSTEM=="usb", ATTR{idVendor}=="19d2", MODE="0666", GROUP="plugdev"
+ +
+

If the file doesn't exist, create it. The rules.d directory is usually read only by default, so you may have to use chmod to make the directory writeable, or the file, or both.

+
+ +

Once you've saved the file, and closed it,  make the file readable:

+ +
sudo chmod a+r /etc/udev/rules.d/android.rules
+
+ +

Now that the udev rules have been updated, restart the udev daemon.

+ +

Ubuntu

+ +
sudo service udev restart
+ +

Fedora 20

+ +
sudo systemctl restart systemd-udevd.service
+ +

Finally, unplug and the USB cable but don't replug it in because we need to enable remote debugging on the phone first.

+ +

Enable remote debugging

+ +

Before you plug your phone back into your USB port, put it USB developer mode. This allows you to debug and flash the phone. To enable developer mode, on your phone enable Remote Debugging in Developer settings (this was called Developer mode on older versions.) Once the option is checked, remote debugging is enabled, and you are ready to go.

+ +

At this point, connect your phone to your computer via a USB cable (if you created the udev rule before, this will trigger udev to detect the phone and create the device node with the right permissions). Now you can check if you can list your device via the adb devices command (remember that adb can only see your phone when the lock screen is unlocked). If everything has worked ok, you should see an output similar to this (the following is for a Geeksphone Keon):

+ +
$ adb devices
+List of devices attached
+full_keon       device
+ +

If the device did not list as expect, check the file name and the script are all correct (see previous section), then restart the computer and retype the command again. Note also that if your device uses fastboot, the bootloader may identify itself with a different vendor ID than the one you see when the device boots normally.

+ +

Backup the phone system partition

+ +
+

Note: You have to do this before you build your device if you do not have an existing system backup, because some libraries will be referenced in build time. These library might be proprietary so we can't provide in our code base.

+
+ +

It is recommended that you back up the entire Android system partition on your phone.

+ +

You can use this copy of the binary blobs for Android in case you later delete your B2G tree. To do this, run:

+ +
adb pull /system <backup target dir>/system
+
+ +

 Depending on the phone, you may also need to pull the /data and/or /vendor directories:

+ +
adb pull /data <backup target dir>/data
+adb pull /vendor <backup target dir>/vendor
+
+ +

If the pull commands fail with an "insufficient permission" message, try the following:

+ + + +

On to the next step

+ +

At this point, you should be ready to fetch the Firefox OS code!

diff --git a/files/zh-tw/archive/b2g_os/index.html b/files/zh-tw/archive/b2g_os/index.html new file mode 100644 index 0000000000..7c258aaeea --- /dev/null +++ b/files/zh-tw/archive/b2g_os/index.html @@ -0,0 +1,222 @@ +--- +title: B2G OS +slug: Archive/B2G_OS +translation_of: Archive/B2G_OS +--- +
+

由 Mozilla 所開發的 Firefox OS 全新行動作業系統,即是以 Linux 與 Firefox 的核心 (Gecko 引擎) 為其架構。

+
+ +
+

開放源碼的 Firefox OS 不受任何專利技術的限制,同樣能讓 App 開發者享受 Web 的功能與靈活度,打造出絕佳的消費性 App。

+ +

對 Web 開發者而言,首要應先理解「整個使用者介面就是 Web App」,且該 Web App 又能顯示並啟動其他的 Web App。不論是專為 Firefox OS 撰寫的 App,或是對使用者介面所進行的任何修正,都能算是以 HTML、CSS、JavaScript 所建構的 Web App,且亦能存取行動裝置的硬體和服務。

+ +

從產品的角度來看,Firefox OS 即是 Mozilla 與其 OEM 夥伴,在 Boot to Gecko (B2G) 技術上所套用的品牌及支援服務。B2G 為作業系統在工程設計時所用的代號,即透過 Mozilla 與其廣大 Mozilla/開放源碼社群的貢獻者所開發。

+
+ +
+

開發 Firefox OS

+ +

專屬的 App

+ +

此為我們的 App 中心,內含資訊可協助開發者撰寫 Open Web App,並安裝於 Firefox OS 之上。

+
+ +
+
+

平台指南

+ +

平台開發者可了解 Firefox OS 平台的各個元件如何搭配及運作。

+ + +
+ +
+

建構與安裝

+ +

說明應如何於模擬器、相容裝置、桌機版模擬器上建構\安裝 Firefox OS。

+ + +
+ +
+

開發者手機

+ +

關於特定開發者手機的調整、更新、復原、購買等資訊。

+ + +
+
+ +
+
+

Firefox OS 書籍

+ +

有許多已出版與編寫中的書籍,涵蓋了 Firefox OS 多樣的開發面相。可參閱 Firefox OS 書籍

+
+ + +
+ +
+

注意:我們將透過〈Firefox OS 說明文件狀態〉頁面,持續更新 Firefox OS 相關文件。如果你也想貢獻 Firefox OS 說明文件,請參閱此頁面並看看有哪些需要調整的內容!

+
+ + + +
    +
  1. 介紹
  2. +
  3. 平台指南 +
      +
    1. 平台指南概述
    2. +
    3. 架構概述
    4. +
    5. App 架構
    6. +
    7. Gonk
    8. +
    9. Gecko
    10. +
    11. Gaia
    12. +
    13. Gaia App 指南
    14. +
    15. 安全性 +
        +
      1. Firefox OS 安全模型
      2. +
      3. 系統安全
      4. +
      5. Firefox OS 中的 App 安全
      6. +
      7. 安全的安裝\更新 App
      8. +
      +
    16. +
    17. Firefox OS 記憶體耗盡時的管理
    18. +
    19. 支援功能表
    20. +
    21. 設定清單
    22. +
    +
  4. +
  5. 建構並安裝 +
      +
    1. 建構與安裝概述
    2. +
    3. Firefox OS 建構程序摘要
    4. +
    5. 必要建構條件
    6. +
    7. 準備第一次編譯
    8. +
    9. 建構 Firefox OS
    10. +
    11. 於 OSX 上為「Flame」建構適用的 Firefox OS
    12. +
    13. 選擇 Gaia 或 Firefox OS 的執行方式
    14. +
    15. 建構 B2G 桌機用戶端
    16. +
    17. 使用 Firefox OS 模擬器
    18. +
    19. 於行動裝置上安裝 Firefox OS
    20. +
    21. 建構並套用 Firefox OS 更新封包
    22. +
    23. 執行環境 (Runtime) 工具
    24. +
    +
  6. +
  7. 開發 Firefox OS +
      +
    1. Firefox OS 開發概述
    2. +
    3. 提報 Firefox OS 的錯誤
    4. +
    5. 修改主機端的檔案
    6. +
    7. 以 .userconfig 檔案進行自訂
    8. +
    9. 自訂 b2g.sh 指令碼
    10. +
    11. 移植 Firefox OS
    12. +
    +
  8. +
  9. 開發 Gaia +
      +
    1. Gaia 開發概述
    2. +
    3. 執行 Gaia 的 Codebase
    4. +
    5. 了解 Gaia 的 Codebase
    6. +
    7. 更改 Gaia 程式碼
    8. +
    9. 測試更改過的 Gaia 程式碼
    10. +
    11. 提交 Gaia 修正檔
    12. +
    13. Gaia 版本系統入門
    14. +
    15. 自訂「建構時間」App
    16. +
    17. 市場自訂指南
    18. +
    19. 自訂 Firefox OS App 中的鍵盤
    20. +
    21. 本地化 Firefox OS
    22. +
    23. 本地化最佳實例
    24. +
    25. 「make」選擇參考
    26. +
    27. Gaia 工具參考
    28. +
    +
  10. +
  11. Firefox OS 手機指南 +
      +
    1. Firefox OS 手機指南概述
    2. +
    3. 手機與相關裝置的規格
    4. +
    5. Geeksphone
    6. +
    7. ZTE OPEN
    8. +
    9. ZTE OPEN C
    10. +
    11. Flame
    12. +
    13. 一般裝置功能
    14. +
    15. 疑難排解
    16. +
    17. 開放參考裝置的最佳實例
    18. +
    +
  12. +
  13. Firefox OS 版本說明 +
      +
    1. Firefox OS 版本說明概述
    2. +
    3. Firefox OS 2.1 for developers
    4. +
    5. Firefox OS 2.0 for developers
    6. +
    7. Firefox OS 1.4 for developers
    8. +
    9. Firefox OS 1.3 for developers
    10. +
    11. Firefox OS 1.2 for developers
    12. +
    13. Firefox OS 1.1 for developers
    14. +
    15. Firefox OS 1.0.1 for developers
    16. +
    +
  14. +
  15. 自動化測試 +
      +
    1. Firefox OS 自動化測試概述
    2. +
    3. 於 Firefox OS 執行測試作業:開發者指南
    4. +
    5. Gaia UI 測試
    6. +
    7. Gaia 整合測試
    8. +
    9. Gaia 單元測試
    10. +
    11. Gaia 效能測試
    12. +
    13. Mochitests
    14. +
    15. Reftests
    16. +
    17. WebAPI 測試
    18. +
    19. xpcshell 測試
    20. +
    21. 耐久測試
    22. +
    23. MTBF 測試
    24. +
    25. Marionette
    26. +
    27. Treeherder
    28. +
    29. Jenkins
    30. +
    +
  16. +
  17. 除錯 +
      +
    1. Firefox OS 除錯概述
    2. +
    3. Firefox OS 的開發者設定
    4. +
    5. 將 Firefox OS 裝置連上桌機
    6. +
    7. 以 Firefox 開發者工具設定 Firefox OS 的除錯作業
    8. +
    9. 裝置上的 console 記錄
    10. +
    11. 安裝並使用 ADB
    12. +
    13. 螢幕截圖
    14. +
    15. 使用 WebIDE
    16. +
    17. 使用「應用程式管理員 (App Manager)」
    18. +
    19. Firefox OS 當機回報
    20. +
    21. Firefox OS 記憶體耗盡的除錯
    22. +
    23. Firefox OS 安全性測試與除錯
    24. +
    25. 使用 gdb 為 B2G 除錯
    26. +
    27. 使用 Valgrind 為 B2G 除錯
    28. +
    +
  18. +
diff --git a/files/zh-tw/archive/b2g_os/installing_boot_to_gecko_on_a_mobile_device/index.html b/files/zh-tw/archive/b2g_os/installing_boot_to_gecko_on_a_mobile_device/index.html new file mode 100644 index 0000000000..7605d27e06 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/installing_boot_to_gecko_on_a_mobile_device/index.html @@ -0,0 +1,53 @@ +--- +title: 將 Boot to Gecko 安裝於行動裝置 +slug: Archive/B2G_OS/Installing_Boot_to_Gecko_on_a_mobile_device +translation_of: Archive/B2G_OS/Installing_on_a_mobile_device +--- +

如果您編譯給行動裝置的 Boot to Gecko 之後,您就將他安裝在行動裝置上。這篇文章會引導您進行這個動作。

+
+ Note: 第一次把 B2G 寫入手機時,手機必須安裝 Androidd 4.0 (Ice Cream Sandwich) 版本。否則這個動作就不會正常的運作。而一旦您完成第一次 B2G 的安裝之後,您就可以熟練的更新了。
+

燒錄手機

+

您只要將您的手機連結到電腦上、並打下列指令,就可以燒任何東西到手機上:

+
./flash.sh
+
+

就這樣。您編譯好的 B2G 就會被燒錄到您的行動裝置上。

+

為您的行動裝置設定 udev 規則

+

在 Linux,如果您看到這個訊息,

+
< waiting for device >
+

那或許意味著這個 fastboot 裝置和提供給 adb 裝置的不同,而那個裝置沒有被加入 udev 規則。您現在可以藉由執行 lsusb 來取得 USB 廠商的 ID,但是它會是 Google 的 ID:18d1,所以將下面這一行加入 /etc/udev/rules.d/51-android.rules 這個檔案,然後就會正常運作了:

+
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0666", GROUP="plugdev"
+
+ Note: 如果您在 Linux 上碰到一個非常有幫助的 libusb 錯誤 "-3"的話,這意味著手機需要被 root 來取得 USB 裝置的權限。請使用 sudo 再執行一次這個 script。
+

Samsung Galaxy S2 要特別注意的地方

+

如果您的手機是 Galaxy S2 且使用 heimdall 1.3.2 (最新版;可以用 heimdall version 指令檢查版本) 的話,您可能會看到一個警告訊息「FACTORYFS upload failed!」、後面接著「Heimdall flashing failed」和一些額外的資訊。實際上這是一個成功的狀況,所以您可以忽略這個建議。

+

為了要擺脫這個奇怪的行為,您可以去抓 heidmall 的 複製的原始碼、並且降級到 1.3.1 release 版 ("git checkout fbbed42c1e5719cc7a4dceeba098981f19f37c06"),接著根據 README 編譯、然後安裝,這樣就不會再看到這個錯誤訊息了。然而,這並不是必須的 (看起來比較爽就是了)。

+

heimdall 的所有版本都無法燒錄超過 100MB 的 system.img。執行下列指令:

+
ls -l ./out/target/product/galaxys2/system.img
+
+

就可以看到您的 system.img 有多大。如果太大的話,先到 IRC 找人問問求救;有幾種方法可以分兩階段來燒錄。

+

Samsung Galaxy S2 額外的步驟

+

如果您正在燒錄到 Galaxy S2 的話,需要遵守一個額外的步驟。因為使用 flash.sh script 不會自動將 Gaia 燒錄上去;您需要也打下列指令:

+
./flash.sh gaia
+
+

燒錄某個分割區(partitions)到具備 fastboot 的手機

+

您可以燒錄某個分割區 (partitions)到 fastboot 的手機 (也就是說,除了 Samsung Galaxy S2 之外的任何其他手機)。指令如下:

+
./flash.sh system
+./flash.sh boot
+./flash.sh user
+
+

更新某個模組

+

在燒錄的時候,您可以藉由指名元件名稱來更新某個 B2G 的元件。如下:

+
./flash.sh gaia
+./flash.sh gecko
+
+

接著,下一步

+

此時,您的手機應該正在運作 Boot to Gecko!是時候該體驗、寫些程式測試、或是 除些錯 了!

+
+ Note: 一個有用的技巧:如果您的 B2G 版本啟動的時候有螢幕鎖且需要密碼才能解鎖的話,預設的解鎖密碼是 0000。
+

Troubleshooting

+

如果行動裝置在安裝或更新 B2G 到新版本後不會正常運作的話,這裡還有一些技巧可以參考。

+

如果使用者介面 (Gaia) 沒有啟動

+

如果您更新您的手機導致使用者介面不會啟動的話,您可以重置手機來清除一些過期的設定或是之類的東西。這樣做可能會讓它回過魂來繼續運作。參考及使用下列指令:

+
cd gaia
+make reset-gaia
+
diff --git a/files/zh-tw/archive/b2g_os/introduction/index.html b/files/zh-tw/archive/b2g_os/introduction/index.html new file mode 100644 index 0000000000..5b0319863d --- /dev/null +++ b/files/zh-tw/archive/b2g_os/introduction/index.html @@ -0,0 +1,86 @@ +--- +title: Firefox OS 簡介 +slug: Archive/B2G_OS/Introduction +translation_of: Archive/B2G_OS/Introduction +--- +
+

Firefox OS 正將無限開拓 Web 的行動界線,且要讓擁有第一支智慧型手機的使用者,能獲得全新的網路體驗。此開放源碼的行動作業系統,即以 Linux、Open Web 標準、Mozilla 的 Gecko 技術為基礎,勢將重新定義「行動平台」。

+ +

在導入 WebAPI 以存取硬體功能,並提供直覺且豐富的智慧型手機體驗之後,Mozilla 相信 Web 必將成為開發者的絕佳機會,讓更多消費者能觸及有趣且多樣的產品。

+
+ +

目標客戶

+ +

此一系列說明文件,主要將讓 Web\平台開發者能夠進一步了解 Firefox OS 的運作方式、貢獻專案的方法,並打造自己的客製化軟體版本以利安裝於裝置之上。若是想建立並發佈自己的 Web App,亦可透過 「應用程式中心 (App Center)」Marketplace 的「專區 (Zone)」輕鬆達成。

+ +

Firefox OS 的基本承諾

+ +

對 Web\平台開發者來說,所應了解的最重要部分就是:整個使用者介面 (UI) 就是 Web App,且此 Web App 又能夠顯示並啟動其他的 Web App。不論是修改 UI、撰寫 Firefox OS 上執行的 App,甚至是存取行動裝置硬體與服務,都是透過標準的 Web 技術進行。

+ +

從產品面來看,Firefox OS 已是 Mozilla 的品牌名稱,透過 Boot to Gecko (B2G,為作業系統產品的設計代號) 而提供相關服務。Firefox OS 的 UI 稱為 Gaia,並包含了 OS 的預設 App 與系統功能。

+ +

若要進一步了解平台架構,可參閱《平台指南》。

+ +

目前與未來的規劃

+ +

現正開發 Firefox OS 2.0 版,且 1.3/1.4 版已經趨於穩定。目前市面上已有多款手機,消費者或開發者所適用的型號均有。若要進一步了解,可參閱:

+ + + +

版本週期

+ +

從 Firefox OS 1.2 開始,Firefox OS 版本週期即已儘量同步於 Gecko 與 Firefox 桌面版的版本週期 (即 6 週)。現每 3 個月即釋出新版本 Firefox OS,因此每 2 個 Gecko (Firefox 瀏覽器核心) 版本週期就會釋出 1 次新版本 Firefox OS。

+ +

舉例來說,Gecko 30 即與 Firefox OS 1.4 一同釋出 (跨過 Gecko 29);Gecko 32 即與 Firefox OS 2.0 (本為 1.5) 一同釋出 (跨過 Gecko 31)。

+ +
+

注意:可參閱我們的版本釋出排程,確認 Firefox OS 與 Gecko\桌面版 Firefox 之間的對應版本,另可參閱 Firefox OS Release Milestones 進一步了解版本管理的相關細節。

+
+ +

社群

+ +

Boot to Gecko 與 Gaia 均是由 Mozilla 內部的工程師團隊開發而得,另加上 Mozilla 外部與開放源碼社群的一同貢獻。如果你想聯繫 Firefox OS 或 Gaia 開發的社群,則可利用下列的郵件群組與 IRC 頻道。

+ +

同樣的,可使用 Bugzilla 系統提報 Firefox OS 元件的任何問題。如果你不確定哪些元件應該提報問題,歡迎隨時發問。

+ +
+

注意:如果你對 B2G/Gaia 原始碼的特定部分 (例如特定的 Gaia App) 有任何問題或意見,則可在 Firefox Modules 頁面上找到特定聯絡細節。

+
+ +

打造作業系統

+ +

B2G 作業系統是以 Mozilla 的 Gecko 繪圖引擎為基礎,並從 Linux kernel 以及稱為 Gonk 的硬體抽象層 (Hardware Abstraction Layer,HAL) 延伸。這裡所說的 Gecko,基本上就是 Firefox for Android 或 Windows 或 Mac OS X 所用的相同 Gecko。而 Gonk 就是 Gecko 所衍生的另項系統。

+ +

若要進一步打造並安裝 Firefox OS,可參閱《建立並安裝 Firefox OS》。你也可以到 Github 找到 B2G 的原始碼

+ +

貢獻 Gaia

+ +

若想為 Gaia 貢獻,其實並不需要深入了解 Web 的開發概念。如果要入門 Gaia 並執行,可參閱《入門開發 Gaia》。

+ +

還有許多有用的工具,可讓你針對 Gaia 與 Firefox OS 的 Web App 進行除錯。若要進一步了解,亦可參閱《Hacking Gaia》。

+ +

開發 Firefox OS 的 App

+ +

Firefox OS App 同樣是以標準的 Web 技術 (如 HTML、CSS、JavaScript 等等) 所打造而成。如果你本來就是 Web 開發者,就已經具備了大部分的技術。另必須知道數個特定的 JavaScript API,以利存取裝置的硬體與重要功能 (如相機、陀螺儀、光線感測器、聯絡人資訊、系統警示\通知......)。這些也同樣能參閱應用程式中心Web 平台頁面獲得更多資訊。

+ +
+

注意:如果你剛開始打造 Open Web/Firefox OS App,或想要初步了解 Web App 與傳統網頁之間的差異,可參閱《App 迅速入門指南》。

+
+ +

支援 Firefox OS 的多個版本

+ +

在開發 Firefox OS 的 App 時,必須留意消費者手上的裝置到底搭載了哪個版本 (可參閱目前可用手機表)。另請注意,更新手機平台軟體,可不像更新桌面版軟體一樣簡單。消費者往往受制於網路服務供應商。因此開發者應該讓 App 能夠支援不同的版本。舉例來說,multiline 的「Flexbox」就無法在 Firefox OS 1.3 以下的版本中執行。你可能必須使用較簡單的配置函式,或退而使用較舊的版本。

+ +

隨著有越來越多消費性的 Firefox OS 裝置上市,並搭載更高版本的 Firefox OS,這個問題很快就能解決。

+ +
+

我們目前建議能針對 Firefox OS 1.1 版本的特性來開發 App。

+
+ +
+

注意:MDN 上的《Web 平台參考頁面》,包含瀏覽器\平台的支援資訊。另可到《Apps API Reference》找到特定 App 技術的相關資訊。

+
diff --git a/files/zh-tw/archive/b2g_os/phone_guide/flame/index.html b/files/zh-tw/archive/b2g_os/phone_guide/flame/index.html new file mode 100644 index 0000000000..60b3a7ad8f --- /dev/null +++ b/files/zh-tw/archive/b2g_os/phone_guide/flame/index.html @@ -0,0 +1,50 @@ +--- +title: Firefox OS 參考平台手機「Flame」 +slug: Archive/B2G_OS/Phone_guide/Flame +translation_of: Archive/B2G_OS/Phone_guide/Flame +--- +
+

Flame 的更新檔案:我們建議你加入下方的郵件群組,即可收到軟體版本定期更新檔案,以及其他可影響 Flame 效能的檔案:https://mail.mozilla.org/listinfo/flamenews

+
+

A picture of the Flame device, showing the Firefox OS homescreen containing several app icons.

+

Available to order

+

專為開發者所設計的「Flame」參考平台手機,是 Firefox OS 相關裝置的里程碑。Flame 的硬體規格均為一時之選,包含 FWVGA 顯示功能與雙核心處理器,可協助開發者打造絕佳的內容與經驗。且單一硬體平台同樣適合測試人員,可更輕鬆的測試並找出軟體問題,不必擔心裝置型號既有的特定問題。

+

如果你手上有 Flame,也打算開始把玩、開發\發佈 App,或為 Firefox 平台有所貢獻,則應先參閱下列連結:

+ +

如果你想進一步了解作業系統的更新程序、探索手機的其他部分、將 App 送入手機,或觀看手機本身的規格,則可從下列 2 篇文章中找到相關資訊:

+ +

購買 Flame

+

Flame 銷售已經告一段落。但我們仍為 Mozilla 貢獻者保留了許多機會要免費送出手機,包含第二輪的 Foxtrot 方案。如果你想免費獲得手機,請儘速聯絡 IRC 上的 Asa Dotzler。

+

連線網路與裝置的規格

+

連線網路:

+ +

硬體:請透過手機與裝置的規格頁面找到更多硬體特色。

+

其他特色包含:

+ +

另請參閱

+ diff --git a/files/zh-tw/archive/b2g_os/phone_guide/index.html b/files/zh-tw/archive/b2g_os/phone_guide/index.html new file mode 100644 index 0000000000..7e301af2de --- /dev/null +++ b/files/zh-tw/archive/b2g_os/phone_guide/index.html @@ -0,0 +1,6 @@ +--- +title: Boot to Gecko 開發者手機指南 +slug: Archive/B2G_OS/Phone_guide +translation_of: Archive/B2G_OS/Phone_guide +--- +

如果您已經從 Mozilla 收到了可以運作 B2G 的開發者手機,或是已經有人幫您將 B2G 安裝好在您的手機上的話,這裡有一份 關於手機運作的基礎指南。我們正在改善這個部分,也希望可以快一點放更有效率的指令放上 MSN。如果您對建置/燒錄有興趣,請看 '設定和建置 Boot to Gecko' 章節,裡面有更細節的資訊。

diff --git a/files/zh-tw/archive/b2g_os/phone_guide/zte_open/index.html b/files/zh-tw/archive/b2g_os/phone_guide/zte_open/index.html new file mode 100644 index 0000000000..36ababcb56 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/phone_guide/zte_open/index.html @@ -0,0 +1,287 @@ +--- +title: The Firefox OS ZTE OPEN +slug: Archive/B2G_OS/Phone_guide/ZTE_OPEN +translation_of: Archive/B2G_OS/Phone_guide/ZTE_OPEN +--- +
+

Mozilla 與 ZTE 共同合作開發了 ZTE Open。ZTE Open 是一款為開發者和早期接受者所開發的 Firefox OS 裝置,它已解鎖、開放用於測試和實驗。

+
+ +
+

Note: 本指南不適用於 ZTE Open C 裝置,針對 ZTE Open C 請參考 ZTE Open C 頁面。

+
+ +

購買裝置

+ +

請連至 ZTE 美國、歐洲或香港 ebay 商店購買。

+ + + +

升級 Firefox OS

+ +

接下來我們將提供升級 ZTE Open 的說明指示:

+ +

一般

+ +

一般 Firefox OS 的建置、更新和測試都是透過用 USB 連接電腦和手機後,利用 ADB (Android Debugging Bridge) 以及 Fastboot 發送指令進行操作,所以我們需要安裝 ADB 以及 fastboot 到電腦上 (可至 Android Developer Toolkit 取得) ,並不需要安裝整個 Android 開發工具包,adb 以及 fastboot 可以到 /platform-tools/ 資料夾找到。

+ +

然後,請打開手機的遠端除錯選項,enable remote debugging

+ +

Firefox OS 1.1

+ +

2013/12/10,ZTE 發佈了 ZTE Open 的 Firefox OS 1.1 更新包,這個更新開啟了 fastboot, 解決了前一個發佈版本這方面的問題。

+ +

在升級到 v1.2 前,最好先升級到 v1.1。升級 v1.1 首先先到 OPEN (American StandardOPEN (European Standard) 下載升級包,請注意我們需要下載對應 OS 版本,所以從 v1.0 升級的人請下載 "V1.1.0B02(for V1.0)",下載檔案中同時也含有說明文件。接下來請解開下載檔案按照以下步驟升級你的 ZTE Open。

+ +
+

Note: 使用者資料會在 microSD 卡升級過程中被刪除,請先備份你的資料

+
+ +

以下是透過 microSD 卡升級步驟:

+ +
    +
  1. 關機、打開背蓋、取下電池背後的 microSD 記憶卡。
  2. +
  3. 將 SD 卡插入電腦。
  4. +
  5. 把下載的 US_DEV_FFOS_V1.1.0B04_UNFUS_SD.zipEU_DEV_FFOS_V1.1.0B04_UNFUS_SD.zip (看你下載的版本) 複製到 microSD 卡的 root 底下,請不要解開 zip 檔。
  6. +
  7. 卸除 SD 卡、裝回到手機上。
  8. +
  9. 同時按下音量向上鍵和電源鍵。音量向上鍵位於手機左側長條型按鍵的上半部。兩顆鍵同時按下後會進入 Firefox OS recovery 模式 (注意 Firefox logo 會先出現一陣子再進入 recovery 模式)。
  10. +
  11. 按音量上下鍵再選項間移動,請選擇 “apply update from external storage.”
  12. +
  13. 按電源鍵確認選項後會看見 microSD 卡裡的檔案列表。
  14. +
  15. 再用音量上下鍵選擇你剛剛複製過來的軔體檔 US_DEV_FFOS_V1.1.0B04_UNFUS_SD.zipEU_DEV_FFOS_V1.1.0B04_UNFUS_SD.zip,然後按電源鍵確認。
  16. +
+ +

如果一切順利的話,你會看到一連串訊息,當你看到 Install from sdcard complete.” 那就代表升級完成,請選擇 “reboot system now” 重新開機,重新開機後你將會看到手機第一次啟動的設定頁面。

+ +

Firefox OS 1.2

+ +

2014, 1月,ZTE 發佈了一版 Firefox OS v1.2 beta 版 (fastboot 開啟、擁有 root 權限),此 beta 版本基本上是由 v1.1 baseline + v1.2 Gecko 與 Gaia, 而且不需要把檔案放在 microSD 卡中。

+ +

請先確認 v1.1 已經上面說明安裝完成,接著打開 terminal 然後輸入以下指令確認連線建立成功:

+ +
adb devices -l
+
+ +

如果連線成功,你會看到類似 "roamer2    device usb:2-1.2" 的回應訊息。

+ +

請前往 ZTE 建立的 Dropbox 帳戶下載對應 OS: US 版UK 版,,Windows 使用者可以去下載特殊說明還有升級工具來協助安裝新版本。底下的說明指示無需特殊工具、適用於所有作業系統 – Linux, OS X, 和 Windows。

+ +

請解開下載好的檔案,開啟 terminal 進入到解開後的檔案資料夾。請注意以下步驟會刪除個人資料,所以請先備份好你的資料,接著輸入下列指令:

+ +
adb reboot bootloader
+ +

這個指令會讓裝置重開機,由於 fastboot 只在重開機過程中有效,請在重開機中輸入以下指令:

+ +
sudo fastboot devices
+
+ +

如果看到 "< waiting for device >" 訊息,請按下 Ctrl-C 並且再次輸入指令直到看見 "ROAMER2    fastboot" 之類的訊息回應。

+ +

接著請快速在重開機當中輸入下面指令:

+ +
fastboot flash boot boot.img
+fastboot flash userdata userdata.img
+fastboot flash system system.img
+fastboot flash recovery recovery.img
+fastboot erase cache
+fastboot reboot
+ +
+

Note: 如果一直看到 "< waiting for device >" 訊息,請嘗試在指令開頭前加上 sudo ,例如 "sudo falshboot flash boot boot.img"。

+
+ +

如果來不及輸入完指令,請從 "adb reboot bootloader" 指令開始再試一次。

+ +

一切順利的話,重開機後又會看到第一次手機啟用頁面,ZTE Open 此刻已經升級到 v1.2,進入系統後會看到許多測試 app ,請隨意自由自由刪除。

+ +
+

Note: Upgrading your ZTE Open to Firefox 1.1 or 1.2 (fastboot enabled)Frédéric Harper 所撰寫的文章也提供了有用的安裝步驟說明。

+
+ +
+

Note: ZTE Open 的 v1.2 版有一個通知欄無法展開的問題,這個問題可以藉由燒錄最新的 Firefox OS 1.2 工程版解決,請確認 ADB 安裝好了 還有 遠端除錯 開啟,然後在 terminal 輸入下面指令:
+
+ git clone -b v1.2 https://github.com/mozilla-b2g/gaia.git gaia_v1.2
+ cd gaia_v1.2
+ make reset-gaia

+
+ +

Firefox OS 1.3 and beyond

+ +

ZTE currently haven't released builds for Firefox OS 1.3 and beyond. To get these on your ZTE open you'll have to manually build and install a new Firefox OS/B2G build on it (start at the build prerequisite instructions, and treat the ZTE like it is an Inari device, for the purposes of configuration). You can recover your phone if necessary, using the procedure cited in the {{ anch("I bricked my phone") }} section.

+ +

Phone features

+ + + +
+

Note: the Hong Kong phones also support tri-band 3G Networks — HSDPA 850/1900/2100 (850/1900 for US, CA, 850/1900/2100 for Asia, AU, and 900/2100 for EU.)

+
+ +

Wireless carriers

+ +
+

Pricing information is for reference only and may not be accurate. Visit the associated link for official information.

+
+ +

US carriers

+ +

AT&T

+ + + +
Sampling of prepaid AT&T plans
+ +

Prepaid GoPhone®, Smartphone Plans

+ + + +

Aio

+ + + +
Sampling of prepaid Aio plans
+ + + +

Good2GO

+ + + +
Sampling of prepaid Good2GO plans
+ + + +

Other {{ anch("AT&T") }} MVNOs

+ +

These carriers do not offer additional 3G data.

+ + + +

T-Mobile

+ + + +

Canadian carriers

+ +

The US version of the ZTE Open also work in Canada on carriers that use the Bell/Telus network, or the Rogers network. Some regional carriers like Sasktel or MTS that have UMTS should work too.

+ +

It will not work on carriers that do not use UMTS or GSM, like Public Mobile, nor on the carriers that use the AWS band like WIND Mobile, Mobilicity, Videotron or Eastlink.

+ +

Memory card

+ +

File system

+ +

In order to be recognized by the phone, the MicroSD card must be formatted as a FAT32 file system. If a card is new or has never been reformatted, it should work as is.

+ +

Device revisions

+ +

Revision 01

+ +

Phones produced before 09/27/2013 do not have fastboot enabled and must be updated. Normally, this would be handled by Software Updates, but since some users have reported trouble with this method, ZTE have made SD card packages available to enable fastboot on earlier devices. Flash images for:

+ + + +

The zip file is linked under Downloads.  Note that you need to download the version with your OS revision in it (that is, download the "V1.1.0B02(for V1.0)" if you are upgrading from V1.0).  Once the file is downloaded and unzipped, follow the instructions in the bundled PDF to flash the package to your phone.

+ +

Related Support Forum Questions:

+ + + +

Revision 02

+ +

Phones produced on or after 09/27/2013 are fastboot enabled by default. This includes the Hong Kong phones.

+ +
+

Note: If you are unsure of your phone's revision, check it in Settings > Device Information > Software. If it is older than the following version numbers, you will need to update your phone using the above SD packages to enable fastboot.

+ + +
+ +

Device support

+ +

Once your phone has {{ anch("Device revisions","fastboot enabled") }}, you will then be able to build and install new Firefox OS/B2G builds on it (start at the build prerequisite instructions, and treat the ZTE like it is an Inari device, for the purposes of configuration), and recover your phone if necessary, using the procedure cited in the {{ anch("I bricked my phone") }} section.

+ +

If you encounter errors about setting the system time while flashing a custom build, you may need to download a modified boot image.

+ +

I bricked my phone

+ +

If you are in the process of modifying your phone and it becomes “unresponsive” you should be able to recover it using fastboot with the following simple procedure.

+ +

First remove the USB cable and then remove the battery from the phone for 30 seconds. Then reinsert the battery and press the volume up button while holding the power button for a few seconds. Next reconnect the USB cable and run the following commands from a terminal window in the directory that contains the SD package files described above (it is worth checking for an update to the SD package before you do this):

+ +
fastboot flash recovery recovery.img
+fastboot flash boot boot.img
+fastboot flash userdata userdata.img
+fastboot flash system system.img
+fastboot reboot
+
+ +

This process should recover your phone. If it doesn't seem to work, you may have to try it a second time.

+ +

Headphones not working?

+ +

We found that the headset jack is designed by a Chinese manufacturer that has compatibility problems with other brands of headsets that include microphones. You may have voice mute problems when you try to use headsets made by Apple, Samsung, HTC, and others. You can buy a 3.5 mm headset adapter that reverses the microphone and ground pins to avoid this problem. For more information, see {{ Bug("812607") }}.

+ +

Other support notes

+ +

Some customers have come across an Issue of FOTA updates failing to enable fastboot; this is still under investigation, and we are assisting ZTE to analyze every scenario. We will post more information as it is available.

+ +

If your phone was unfortunately damaged during the FOTA update because of ZTE providing false or wrong update files, you can attempt to restore it to factory settings using the appropriate SD image and instructions referenced in {{ anch("Revision 01") }}. Otherwise, send your phone back to the eBay store you purchased it from in exchange for a new one. You may contact the store owner directly via an eBay message.

+ +

See also

+ +

Official Dev Phone page on Firefox Marketplace

+ +

Draft User Manual [en-US] - PDF

diff --git a/files/zh-tw/archive/b2g_os/platform/apps_architecture/index.html b/files/zh-tw/archive/b2g_os/platform/apps_architecture/index.html new file mode 100644 index 0000000000..2524c81d0b --- /dev/null +++ b/files/zh-tw/archive/b2g_os/platform/apps_architecture/index.html @@ -0,0 +1,24 @@ +--- +title: Firefox OS apps 架構 +slug: Archive/B2G_OS/Platform/Apps_architecture +translation_of: Archive/B2G_OS/Platform/Apps_architecture +--- +
+

本文旨在說明 Firefox OS 內部如何管理和啟動應用程式,主要是針對 Firefox OS 平台開發者以及正在移植 Firefox OS 到新硬體裝置上的開發者,如果你只是一個單純 App 開發者並不會需要知道,不過有興趣的話還是可以看看了解 Firefox OS。

+
+

App 啟動程序

+

當 app 被啟動時,主畫面 app (Home screen app) 會透過 {{domxref("App")}} API 取得 app 的參照,然後呼叫 {{domxref("App.launch()")}} 方法來啟動 app。

+

Gecko 收到相關請求後會發送一個含有 app 詳細資訊的 {{domxref("mozChromeEvent")}} 到系統 app (System app),系統 app 接著會將一個 {{HTMLElement("iframe")}} 加入 DOM 樹(DOM tree)中,然後將 app 載入該 {{HTMLElement("iframe")}} 裡,直到 app 終止前這個 iframe 就是 app 的家。

+

每一支 app 都需要一個描述該 app 的 manifest 檔,app 包也需要遵照特定檔案階層,詳情請見 App manifest

+

和 Gecko 溝通

+

Gecko 和 Gaia' 系統 app 之間的溝通是經由 {{domxref("mozChromeEvent")}} 以及 {{domxref("mozContentEvent")}} 完成。 mozChromeEvents 是從 chrome 廣播到內容,而 mozContentEvents 是從內容廣播到 chrome,這些溝通主要在控管受信任 UI 的創建與終止,還有在為通知和其他任務,包括通知系統 app 啟動某個 app,提供必要的功能。

+
+

Note: 請參考 System app 文件 以取得更多有關這些事件如何運作的細節,同時也可以參考相關的原始碼 {{source("b2g/chrome/content/shell.js")}}。

+
+

延伸閱讀

+ diff --git a/files/zh-tw/archive/b2g_os/platform/gaia/gaia_apps/index.html b/files/zh-tw/archive/b2g_os/platform/gaia/gaia_apps/index.html new file mode 100644 index 0000000000..4a284db78e --- /dev/null +++ b/files/zh-tw/archive/b2g_os/platform/gaia/gaia_apps/index.html @@ -0,0 +1,78 @@ +--- +title: Gaia apps +slug: Archive/B2G_OS/Platform/Gaia/Gaia_apps +translation_of: Archive/B2G_OS/Platform/Gaia/Gaia_apps +--- +
+

Gaia 位在 Firefox OS 的上層,其中包含系統管理功能以及一系列 Firefox OS 內建 apps。所有 Gaia 的原始碼 — 即便系統和鍵盤輸入法 — 都是由 HTML5 (HTML + CSS + JavaScript) 和 Open WebAPIs 技術所建構而成的,本文旨在說明 Gaia 內建的 apps 是如何運作之。

+
+

Gaia 功能類別

+

Gaia 內不同的 apps 大致上可以分成以下幾類。

+
+

Note: 許多 app 運作說明都會連結到 Gaia Github repo 上的 README 頁面,那是因為很多 app 都還在快速開發迭代階段,常常會有更動,所以一直更新 MDN 相當不切實際,如果想要進一步獲取最新的資訊,請再參考各 README 頁面。

+
+

平台類

+

包括系統、設定、螢幕鎖定、建置腳本和藍芽 apps。

+

+

平台類 apps:

+
+
+ 系統 (System)
+
+ System app 是第一個在 Firefox OS 開機程序 中被 Gecko 載入的web app,它負責處理許許多多系統運行工作,所以不算是在一般個別 web app 的範疇內。
+
+ 瀏覽器 (Browser)
+
+ Browser app (現在算是 System 一部分) 當有相關需求時,如網頁瀏覽、搜尋或書籤標記,提供瀏覽器類的功能。
+
+ 視窗管理 (Window Management)
+
+ Firefox OS 視窗管理功能 — 包括 app 生命週期和互動、通知、動畫等等 — 由 System app 特定一塊負責。
+
+ 設定 (Settings)
+
+ Settings app 讓使用者設定裝置、回應當前活動呼叫 (帶有 configure 名稱的 Web 活動),讓其他 app 可以跳轉到 Settings app 其中的設定面板處理需要的設定任務 (例如說顯示 wifi 設定面板當數據傳輸無法使用時)。
+
+

通訊類

+

包括 Dialer, Contact, SMS apps 與 FTU apps.

+

+

生產力類

+

包括 Email, Calendar, 與 Clock apps.

+

+

生產力類 apps:

+
+
+ 日歷 (Calendar)
+
+ Firefox OS 內建 calendar app.
+
+ 時鐘 (Clock)
+
+ Firefox OS 預設 Clock app,具備鬧鈴、計時等功能
+
+ Email
+
+ Gaia e-mail app.
+
+

媒體類

+

包括 Camera, Gallery, Music, 和 Video apps 等等媒體相關功能,如桌布和轉送 DRM 鎖。

+

+

媒體類 apps:

+
+
+ 影音 (Video)
+
+ Video 是影音媒體撥放器。
+
+ 相機 (Camera)
+
+ Firefox OS 使用者透過相機照相、錄影,它也會回應 type 為pick 的 Web 活動,讓其他想使用相機功能的 app 使用相機。
+
+

其他 Gaia 特色功能

+

除了上述功能,Gaia 還有其他功能如 browser, homescreen, marketplace, test framework, PDF viewer, 和 app manager 等。

+
+
+ pdf.js
+
+ pdf.js 是 HTML5 基礎的 PDF 瀏覽器,Gaia 用其來瀏覽 PDF,請注意 pdf.js 的程式碼庫 (repo) 和 Gaia 是分開來的。
+
diff --git a/files/zh-tw/archive/b2g_os/platform/gaia/index.html b/files/zh-tw/archive/b2g_os/platform/gaia/index.html new file mode 100644 index 0000000000..d2a4886cf1 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/platform/gaia/index.html @@ -0,0 +1,68 @@ +--- +title: Gaia +slug: Archive/B2G_OS/Platform/Gaia +tags: + - B2G + - Gaia + - Mobile + - NeedsTranslation + - TopicStub +translation_of: Archive/B2G_OS/Platform/Gaia +--- +

Gaia is the user interface level of Firefox OS. Everything that appears on the screen after Firefox OS starts up is drawn by Gaia, including the lock screen, home screen, dialer, and other applications. Gaia is written entirely in HTMLCSS, and JavaScript. Its only interface to the underlying operating system and hardware is through standard Web APIs, which are implemented by Gecko.

+

Because of this design, not only can Gaia be run on Firefox OS devices, but also on other operating systems and in other web browsers (Albeit with potentially degraded functionality depending on the capabilities of the browser).

+

Third party applications onto the device installed alongside Gaia can be launched by Gaia.

+ + + + + + + +
+

Documentation about Gaia

+
+
+ Introduction to Gaia
+
+ Gaia is the user interface application for Firefox OS devices; it's simply a Web application running atop the Firefox OS software stack. This guide introduces Gaia at a high level.
+
+ Gaia hacking guide
+
+ A guide to hacking and modifying the Gaia interface.
+
+ Gaia Build System Primer
+
+ Most of the meaniful work for the build steps are performed by the scripts that live inside the build/ subdirectory of Gaia.
+
+ Gaia Hacking Tips And FAQ
+
+ A list of helpful tips and frequently asked questions around hacking on Gaia.
+
+

View All...

+
+

Getting help from the community

+

If you're working with Gaia, or developing Gaia applications, there are community resources to help you!

+
    +
  • Consult the Boot to Gecko project forum: {{ DiscussionList("dev-gaia", "mozilla.dev.gaia") }}
  • +
+

 

+
+ + +

Resources

+ +
+

 

diff --git a/files/zh-tw/archive/b2g_os/platform/gaia/introduction_to_gaia/index.html b/files/zh-tw/archive/b2g_os/platform/gaia/introduction_to_gaia/index.html new file mode 100644 index 0000000000..27c9ea5ea4 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/platform/gaia/introduction_to_gaia/index.html @@ -0,0 +1,13 @@ +--- +title: Gaia 簡介 +slug: Archive/B2G_OS/Platform/Gaia/Introduction_to_Gaia +translation_of: Archive/B2G_OS/Platform/Gaia/Introduction_to_Gaia +--- +

Gaia 是 Boot to Gecko (B2G) 的使用者介面;它只是在 B2G 裝置、模擬器、桌上型電腦版本、或是 Firefox 版本上運作的一個網頁應用程式 (Web application)。如果想要在 Gaia 上添加 apps 程式或是做一些改變的話,所有你需要了解的就是網頁科技 (Web Technologies),例如 JavaScriptHTML、和 CSS

+

Gaia 的鎖定畫面

+

鎖定畫面預設是啟動的,而預設解鎖密碼 (PIN) 是「0000」。隨著這個功能會隨著時間愈趨完整。

+

預設的 Gaia 介面

+

Gaia 的預設介面跟大家所見最典型的智慧型手機相仿,如這邊所看到的圖。

+

screenshot.png這是張 prerelease 版本作業系統的圖,有一些暫時使用的圖示(和一些測試的程式)。頂端的狀態條顯示手機正在使用哪個行動網路 (如果行動裝置沒有網路的話,會顯示「No SIM card」)、行動網路強度、WiFi 訊號強度、電池使用狀態、和現在的時間。

+

畫面的中間區域顯示應用程式的圖示;透過螢幕的圖示切換左右頁。

+

在螢幕的底部是一個底座,可以放四個最常用的應用程式。現在底座還不能修改,且被預設顯示播號 (Dialer)、訊息 (Messages)、市集 (Market)、和瀏覽器 (Browser)的程式。

diff --git a/files/zh-tw/archive/b2g_os/platform/gonk/index.html b/files/zh-tw/archive/b2g_os/platform/gonk/index.html new file mode 100644 index 0000000000..71d064ac30 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/platform/gonk/index.html @@ -0,0 +1,22 @@ +--- +title: Gonk +slug: Archive/B2G_OS/Platform/Gonk +translation_of: Archive/B2G_OS/Platform/Gonk +--- +

{{draft()}}

+
+

Gonk是Firefox OS的底層系統,包含基於Android Open Source Project (AOSP)的Linux核心以及硬體抽象層(hardware abstraction layer, HAL)。本文旨在說明Gonk的組成,更多有關FireFox OS架構以及Gonk是如何配置在其中的細節,請參考Firefox OS架構指南。

+
+

Gonk 概觀

+

在Gecko原始碼中,有一個b2g/資料夾,這個資料夾含有Gonk接口,它為網頁開啟了行動裝置的硬體能力。這其中包含了Linux核心、HAL和其他OEM特定的函式庫(library)。好機個Gonk函式庫是開放原始碼專案,如libusb, bluez等,有些HAL部分則是和Android專案共享,如GPS, camera等。

+

Gonk是裝置接口層,介於硬體和Gecko之間的配接器。Gonk是一個相對簡單的Linux發布版本,可以視為Gecko的配接目標,就像是Gecko和OS X, Windows和Android的接口。

+
+

Note: 由於不同的行動裝置有不同的晶片組與硬體規格,所以可能會有不同的Gonk發布版本。

+
+

Firefox OS專案擁有Gonk百分之百的控制權,所以能夠提供Gecko那些原本在其他作業系統上無法看到的介面,例如,Gecko可以直接存取電話系統框架和Gonk的顯示frame buffer。

+

Gonk 原始碼

+

B2G repo on Github 上有多種裝置的官方Gonk支援移植,可以視為Gonk的檔案庫。至於裝置支援列表,請見B2G/config.sh。

+

大部分Gonk相關的日常工作包括了移植Gonk到不同硬體上,還有確保Gecko能在不同硬體上順利運行。

+
+
+

 

diff --git a/files/zh-tw/archive/b2g_os/platform/index.html b/files/zh-tw/archive/b2g_os/platform/index.html new file mode 100644 index 0000000000..fe9474eed5 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/platform/index.html @@ -0,0 +1,75 @@ +--- +title: Firefox OS 平台 +slug: Archive/B2G_OS/Platform +translation_of: Archive/B2G_OS/Platform +--- +

Firefox OS 平台是由多樣的元件所組成。如果你只是要撰寫能在 Firefox OS 上執行的 App,其實不太需要通盤了解其架構。但如果你從事平台開發、平台移植,甚或只是單純好奇的話,也許會對以下說明文件感興趣。

+ + + + + + + + +
+

關於 Firefox OS 平台的說明文件

+ +
+
Firefox OS 架構概述
+
簡單概述 Firefox OS 的內部架構,可供平台開發或移植工程師初步了解 Firefox OS。
+
 
+
Firefox OS 的 App 架構
+
概述 Firefox OS 的 App 模型。
+
Gaia
+
Gaia 是 Firefox OS 裝置的使用者介面 (UI) App,也是在 Firefox OS 軟體堆疊上執行的 Web App。
+
Gonk
+
Gonk 的說明文件。Gonk 屬於 Gaia 之下的作業系統層,包含 Linux kernel 硬體抽象層 (Hardware abstraction layer),且由 Gecko 負責之間的溝通。
+
Gecko
+
Gecko 即為 Firefox、Thunderbird,以及其他許多 App 所使用的相同 Open Web 標準實作。
+
安全性
+
Firefox OS 的安全性說明文件,包含各個面相的裝置安全,適合 App 開發者、裝置整合商等參考。
+
Firefox OS 記憶體耗盡時的管理作業
+
本文將解釋 Firefox OS 記憶體不足時的管理方式,可透過記憶體清理與記憶體不足通知等功能。
+
功能支援表
+
各個 Firefox OS 版本所支援的各項功能特色。
+
Firefox OS 設定清單
+
常見的設定名稱清單,可搭配 Settings API。
+
+ +

全部文章...

+
+

尋求社群協助

+ +

如果你正在開發 Firefox OS,或是可於 Firefox OS 裝置上執行的 App,則能參閱以下社群資源!

+ +
    +
  • Boot to Gecko 論壇:{{ DiscussionList("dev-b2g", "mozilla.dev.b2g") }}
  • +
+ +
    +
  • 在「Boot to Gecko」的 IRC 頻道上提問:#b2g
  • +
+ +

請遵守網路禮節...

+ + + + + + +

相關資源

+ + +
+ +

 

diff --git a/files/zh-tw/archive/b2g_os/platform/out_of_memory_management_on_firefox_os/index.html b/files/zh-tw/archive/b2g_os/platform/out_of_memory_management_on_firefox_os/index.html new file mode 100644 index 0000000000..5b7f2045cc --- /dev/null +++ b/files/zh-tw/archive/b2g_os/platform/out_of_memory_management_on_firefox_os/index.html @@ -0,0 +1,53 @@ +--- +title: Firefox OS 記憶體管理 +slug: Archive/B2G_OS/Platform/Out_of_memory_management_on_Firefox_OS +translation_of: Archive/B2G_OS/Platform/Out_of_memory_management_on_Firefox_OS +--- +
+

Firefox OS 會運行在一些記憶體容量不大的裝置上,當程序用盡了記憶體,系統核心就必須關閉其他程序好釋放出記憶體使用。本文旨在描述記憶體關閉和記憶體不足通知如何運作、如何控制關閉那些程序,以確保當記憶體不夠時,主系統還是可以運作。

+
+

記憶體不足時會有兩個系統介入管理: Low memory killer (LMK) Low memory notifications.

+

Low memory killer

+

LMK 是 Android 核心的次系統,這個次系統負責關閉程序好騰出記憶體使用。為了決定程序關閉優先順序,每一個程序都會透過 /proc/<pid>/oom_adj or /proc/<pid>/oom_score_adj files 被賦予一個優先值,這個優先值為調整分數(adjustment score 或 oom_adj)。

+

一般來說 oom_adj 值越大,程序越容易被刪除,LMK 提供多個層級,每個層級對應到一定容量的可用記憶體以及最小 oom_adj 值。當可用記憶體掉到某一個層級,所有 oom_adj 值大於該層級 oom_adj 值的程序都有可能被關閉,LMK 會從占用最多記憶體的程序開始一個一個關閉,直到可用記憶體回復到安全層級為止。

+
+

Note: 被 LMK 關閉的背景 app 仍然以 "殭屍 app" 的形式存在在程序管理員 (task manager),下次再回到該 app,app 會被重新喚醒。目前最大殭屍 app 的數量是 10。

+
+
+

Note: 為了記憶體不足被關閉的 app 不一定就是造成記憶體不足的原因。

+
+

程序關閉優先順序

+

Firefox OS 關閉 app 的優先順序是由每個 app 給定的優先層級和相關聯的 OOM 調整分數所決定 (現有值都存在 pref):

+
    +
  1. 最先關閉的 app 是背景 app,最近最少使用的。
  2. +
  3. 第二是 homescreen app。
  4. +
  5. 接下來是使用者可察覺的背景 app (例如,在背景撥放音樂的程式,或高優先 (high-priority)、或持有 cpu wakelock 並且註冊有系統訊息處理器(system messages handler) 的 app)。
  6. +
  7. 第四是鍵盤程式。
  8. +
  9. 前景 (Foreground) app 則是第五順位被關閉的 app。
  10. +
  11. 最後則是前景高優先 (high-priority)、或持有 cpu wakelock 的前景 app。
  12. +
+
+

Note: 大部分在前景的子程序持有為 2 的oom_adj,背景子程序則持有 3 ~ 6 的 oom_adj,背景子程序到底會持有多大 oom_adj 值取決於許多因素,比如說是否撥放音月或是否屬於 homescreen app。

+
+

下面是例外:

+ +

記憶體過低通知

+

第二個釋放記憶體的機制是記憶體過低通知。當可用記憶體量低過一定的門檻值,LMK 便會向使用者空間 (userspace) 發出記憶體過低通知,系統 app 和一般使用者 app 都會等待這個通知,然後透過觀察器服務 (observer service) 發出 memory-pressure 事件回應之;這個事件 app 不會直接看見,只有 C++ 和 Chrome JS 程式碼會看到,在 Gecko 裡我們從這個事件中會盡一切可能釋放記憶體 — 通常是刪除內部快取 (images, DNS, sqlite, 等等),拋棄可以回復的物件 (比如 WebGL contexts) 還有執行垃圾回收機制。
+
+ 當碰到記憶體過低狀況時,第一個發出的 memory-pressure 事件會有 low-memory 負載,倘若經過預定的5秒後我們依然處於記憶體過低狀態,另一個 memory-pressure 事件會發出,不過這一次是帶著 low-memory-ongoing 負載,這個時候我們持續處於記憶體過低狀態,很明顯地像一些垃圾回收機制等大動作的作法也不夠了,所以其他一些更低階的記憶體釋放作法會被採行。

+

LMK 和記憶體過低通知如何協同運作

+

目前記憶體過低門檻介於 LMK 的背景 app 層級(大於)和 homescreen 層級(小於)之間,所以整體記憶體不足的反應機制如下:

+
    +
  1. 關閉最近最不常用的背景 app。
  2. +
  3. 當記憶體依然不足,發出 memory-pressure 事件通知給所有的 app。
  4. +
  5. 當記憶體依然不足,每5秒發出 memory-pressure 事件,但標記為 ongoing 讓垃圾回收機制不要回應。
  6. +
  7. 關閉 homescreen.
  8. +
  9. 關閉使用者可察覺或高優先值的背景 app。
  10. +
  11. 關閉運作中的鍵盤 app。
  12. +
  13. 關閉前景 app。
  14. +
  15. 關閉高優先值的前景 app。
  16. +
  17. 關閉 preallocated 程序。
  18. +
diff --git a/files/zh-tw/archive/b2g_os/preparing_for_your_first_b2g_build/index.html b/files/zh-tw/archive/b2g_os/preparing_for_your_first_b2g_build/index.html new file mode 100644 index 0000000000..1d165926a1 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/preparing_for_your_first_b2g_build/index.html @@ -0,0 +1,138 @@ +--- +title: 準備第一次建置 B2G +slug: Archive/B2G_OS/Preparing_for_your_first_B2G_build +translation_of: Archive/B2G_OS/Preparing_for_your_first_B2G_build +--- +

在開始建置 B2G 前,要先複製整個倉儲 (repository)並且作編譯的設定。這篇文章說明要怎麼做。

+ +

複製 B2G 倉儲(repository)

+ +

在第一次編譯前,要做的第一步就是複製 B2G 的倉儲(repository)。這個步驟將不會把所有東西抓下來!相反地,他會抓 B2G 建置系統和安裝工具。B2G 大部分的程式碼都在主要的 Mozilla Mercurial 倉儲。

+ +

用 git 來複製倉儲:

+ +
git clone git://github.com/mozilla-b2g/B2G.git
+ +

複製了之後(應該會花個幾分鐘),cd 到 B2G 的目錄:

+ +
cd B2G
+
+ +

複製 B2G 樹(tree)到一台新機器

+ +

當您有一台新電腦時(超幸運的!),您會覺得把 B2G tree 從一台電腦轉移到另一台電腦的話,生活會簡單很多。

+ +

將您就電腦的磁碟掛上(mount)到新的電腦,然後敲入下面的指令,就可以做到:

+ +
rsync -a source/ dest/
+
+ +

source 是整個原始碼樹(source tree)的完整路徑 (包括後面的斜線),而 dest 是您要複製的目的位置 (同樣也包含後面的斜線,它很重要!)。

+ +

這樣做之後,您可以跳過這篇文章剩下的部份,然後直接跳到的「建置」部份。

+ +

設定專屬於您的行動裝置的 B2G

+ +
重要:請注意只支援 Android 4 (aka. Ice Cream Sandwich) 的行動裝置。請確認您的手機運作的真的是 ICS,否則這個步驟很可能會失敗於某些非 Nexus 裝置的驅動程式。另外,如果您必須要將行動裝置燒成 ICS,請留意有些 USB hubs 和燒錄工具不相容,因此您可能需要將行動裝置連接到內建的 USB port。
+ +

擷取了核心的 B2G 建置系統之後,您需要為了要安裝的行動裝置作設定。您可以使用 config.sh 工具來擷取支援的行動裝置列表,如下:

+ +
./config.sh
+
+ +

這會顯示支援的行動裝置列表;舉例來說:

+ +
Usage: ./config.sh [-cdflnq] (device name)
+Flags are passed through to |./repo sync|.
+
+Valid devices to configure are:
+- galaxy-s2
+- galaxy-nexus
+- nexus-4
+- nexus-4-kk
+- nexus-5
+- nexus-5-l
+- nexus-s
+- nexus-s-4g
+- flo (Nexus 7 2013)
+- otoro
+- unagi
+- inari
+- keon
+- peak
+- hamachi
+- helix
+- tarako
+- dolphin
+- dolphin-512
+- pandaboard
+- vixen
+- flatfish
+- flame
+- flame-kk
+- flame-l
+- rpi (Revision B)
+- emulator
+- emulator-jb
+- emulator-kk
+- emulator-l
+- emulator-x86
+- emulator-x86-jb
+- emulator-x86-kk
+- emulator-x86-l
+> Sony Xperia devices
+- aries (Z3 Compact KK)
+- aries-l (Z3 Compact L)
+- leo-kk (Z3 KK)
+- leo-l (Z3 L)
+- scorpion-l (Z3 Tablet Compact L)
+- sirius-l (Z2 L)
+- tianchi-l (T2U L)
+- flamingo-l (E3 L)
+ +

如果您的行動裝置沒被列出,您應該馬上停止來幫忙將 B2G 移植到您的行動裝置,或是等到某個人移植完之後再安裝。我們當然比較希望您可以幫忙移植!

+ +
注意:如果因為任何原因您想要編譯某個版本的 Gecko,請在您著手之前先看 Building against a custom Gecko
+ +

設定給行動裝置

+ +

首先,連接您的裝置;設定的過程會需要存取它。

+ +

如果您的裝置有被列出,您可以再執行一次 config.sh 來開始設定的程序,這次需要指名您的行動裝置的名字。舉例來說,如果要編譯給 Samsung Google Nexus S的話,您要打:

+ +
./config.sh nexus-s
+
+ +

在設定一開始的附近您可能會需要設定使用顏色的選項,而在這之後設定程序會繼續下去。接著可以去喝個咖啡休息一下,因為這個時候您會第一次把建置 Boot to Gecko 中所有需要的程式碼都抓下來。

+ +

如果您的手機不再使用 Android 且 B2G tree 還沒裝到手機上,而您又有遵照前幾頁所說、聰明地作了一份 /system 磁區的備份的話,您可以這樣使用它:

+ +
ANDROIDFS_DIR=<absolute path to parent dir of system dir> ./config.sh <target>
+
+ +

設定來建置模擬器

+ +

如果您要編譯模擬器的話,就需要指定 "emulator" 來使用 ARM 的模擬器,或是 "emulator-x86" 來編譯 x86 模擬器。後者比較快,但也因此在表現實際行動裝置上較不準確。
+
+ 舉例來說,您要像下面這樣設定來編譯 ARM 模擬器:

+ +
./config.sh emulator
+
+ +

在設定一開始的附近您可能會需要設定使用顏色的選項,而在這之後設定程序會繼續下去。接著可以去喝個咖啡休息一下,因為這個時候您會第一次把建置 Boot to Gecko 中所有需要的程式碼都抓下來。

+ +

編譯客製的 Gecko

+ +

可能您會想要或需要以好幾種版本的 Gecko 來編譯 Boot to Gecko (manifest 中預設是一種)。您可以在您抓倉儲 (在上述的 config.sh 之前),藉由編輯 .userconfig 來做到這件事情。舉例來說,如果您要根據 mozilla-central 來編譯:

+ +
GECKO_PATH=/path/to/mozilla-central
+GECKO_OBJDIR=/path/to/mozilla-central/objdir-gonk
+
+ +
+

注意: 如果是在 Mac OS X 下客製化編譯的話,檔案系統本身會注意 mozilla-central 的大小寫。

+
+ +

您可以參考 客製化 .userconfig 設定檔 來客製化更多東西。

+ +

接著,開始編譯

diff --git a/files/zh-tw/archive/b2g_os/quickstart/app_tools/index.html b/files/zh-tw/archive/b2g_os/quickstart/app_tools/index.html new file mode 100644 index 0000000000..bc539adefa --- /dev/null +++ b/files/zh-tw/archive/b2g_os/quickstart/app_tools/index.html @@ -0,0 +1,28 @@ +--- +title: App tools +slug: Archive/B2G_OS/Quickstart/App_tools +translation_of: Archive/B2G_OS/Quickstart/App_tools +--- +
+

用什麼來建立開放式Web應用程序?答案是,"你通常會用它來建立網絡'以下是工具和資源的清單,可以幫助您開始開放式Web應用程序他們可以很容易地成您現有的Web開發工作流程,如果你有一個,或者你可以將它們周圍建立為一個新的工作流程

+
+

應用程序驗證程序

+

您的應用程序以準備好進入Firefox市場應用程序驗證器檢查你的清單,並會顯示任何錯誤,它也有可能顯示你沒有考慮過的警告

+

火狐系統模擬器

+

安裝和使用火狐系統模擬器開始和令你的應用程序運行最簡單的方法安裝模擬器,通過 工具-> Web開發 -> 火狐系統模擬器菜單。啟動後, 便會有JavaScript控制台,以便您可以從模擬器試應用程序啟動和刪除錯誤

+

應用程序管理器

+
+
+  
+
+

的測試工具被稱為應用程序管理器這個工具可以讓你通過USB火狐來連接至兼容的設備(或一個火狐系統模擬器應用程序直接存在設備上,驗證的應用程序,設備上刪除錯誤

+

Firefox的開發者工具

+
+
+
+
+ 火狐現在提供了一套開發工具,確保了極大的發展經驗,既好用,又高效率。欲了解更多有關這些工具如何運作,看看還有什麼的Mozilla所提供的,請到我們的工具區域
+
+
+
+

 

diff --git a/files/zh-tw/archive/b2g_os/quickstart/index.html b/files/zh-tw/archive/b2g_os/quickstart/index.html new file mode 100644 index 0000000000..a5bb4fa406 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/quickstart/index.html @@ -0,0 +1,51 @@ +--- +title: Build +slug: Archive/B2G_OS/Quickstart +tags: + - Apps + - NeedsTranslation + - Quickstart + - TopicStub +translation_of: Archive/B2G_OS/Quickstart +--- +
+

Quickstart information on coding open web apps.

+
+
+
+ Introduction to open web apps
+
+ What are open web apps? How they differ from regular web pages? Why is this significant? This article aims to answer these questions and more.
+
+ Your first app
+
+ This article takes you through the basic steps and additional knowledge on top of regular web development required to create installable open web apps.
+
+ Introduction to Firefox OS
+
+ An introduction to Firefox OS, Mozilla's new open web app-based mobile platform.
+
+ Introduction to manifests
+
+ An FAQ designed to answer any questions you may have about manifests, hosting apps, origins, and other such topics.
+
+ App development for web developers
+
+ If you're a web developer, how do open web apps differ from what you're used to? This article explains all.
+
+ App development for mobile developers
+
+ If you're a native mobile application developer, what advantages can open web apps bring to you, and how do they differ from what you are used to? Here are some ideas.
+
+ Developing app functionality
+
+ This page talks about the kinds of different functionality that you might want to build into your apps, with links to further information.
+
+ Payments
+
+ How do you build functionality to make people pay for installing your open web apps? Here is the lowdown.
+
+ App tools
+
+ Last for this section, we provide some links to more information on the tools available to help you develop great open web apps.
+
diff --git a/files/zh-tw/archive/b2g_os/quickstart/your_first_app/index.html b/files/zh-tw/archive/b2g_os/quickstart/your_first_app/index.html new file mode 100644 index 0000000000..d40315b16c --- /dev/null +++ b/files/zh-tw/archive/b2g_os/quickstart/your_first_app/index.html @@ -0,0 +1,265 @@ +--- +title: Your first app +slug: Archive/B2G_OS/Quickstart/Your_first_app +translation_of: Archive/B2G_OS/Quickstart/Your_first_app +--- +
+

Note: 快速入門這段章節已經取代先前舊的快速入門章節,更新為最新的及更專注於Firefox OS app essentials 文章。我們希望你將發現這份是比舊文更有用和更快學習經驗的文章。

+
+ +
+
+

開放式Web應用讓開發人員實現了期盼多年的夙願:通過Firefox OS這一首款開放式Web應用平台,可以僅僅使用HTML、CSS和JavaScript在跨平台的環境中生成可部署的應用。本手冊包含了基本的架構和應用構建指南,你能夠迅速掌握這些內容並開始創造自己的下一個偉大的應用!

+
+ +

如果你想按照本指南開發,你可以下載我們的quick start app template.  或可以藉由參閱我們的Apps template 指南,找到更多有關的內容。

+ +

App 結構

+ +

打包型 Apps VS. 托管型 Apps

+ +

開放網絡應用有兩種類型:打包型和托管型。打包型apps本質上來說就是一個包含各種HTML、CSS、JavaScript、圖像、表單等應用資源的zip文件。托管型apps在一個給定域名的服務器上運行,就像是一個獨立的網站。兩種應用都需要有有效的表單。到了要在火狐市場中列出你的app,你要上傳app zip文件或提供托管app所在的URL。

+ +
+

{{EmbedYouTube("Q7x-B13y33Q")}}

+ +
+

用Treehouse為製作夥伴: Check them out!

+
+
+ +

本指南的目的,會讓你將創建一個於本機(localhost)地址上的托管型app。一旦你的app準備好進入火狐市場,你可以選擇把它作為打包app或作為托管app啓動。

+ +

App 表單

+ +

每一個火狐app都需要一個位於根目錄下的manifest.webapp文件, 這個manifest.webapp 文件提供app有關的重要信息,如:版本、名稱、描述、圖標位址、本地字符串、指明app可以從哪兒被安裝等等。只有名稱和描述是必須的。app模板中的簡單表單如下所示:

+ +
{
+  "version": "0.1",
+  "name": "Open Web App",
+  "description": "Your new awesome Open Web App",
+  "launch_path": "/app-template/index.html",
+  "icons": {
+    "16": "/app-template/app-icons/icon-16.png",
+    "48": "/app-template/app-icons/icon-48.png",
+    "128": "/app-template/app-icons/icon-128.png"
+  },
+  "developer": {
+    "name": "Your Name",
+    "url": "http://yourawesomeapp.com"
+  },
+  "locales": {
+    "es": {
+      "description": "Su nueva aplicación impresionante Open Web",
+      "developer": {
+        "url": "http://yourawesomeapp.com"
+      }
+    },
+    "it": {
+      "description": "La tua nuova fantastica Open Web App",
+      "developer": {
+        "url": "http://yourawesomeapp.com"
+      }
+    }
+  },
+  "default_locale": "en"
+}
+ +
+

{{EmbedYouTube("dgAUgHQOm8M")}}

+ +
+

Made in partnership with Treehouse: Check them out!

+
+
+ +

 

+ +

一個基本的表單是你所需要最先上手的地方。關於表單的更多細節,見App Manifest.

+ +

App 佈局 & 設計

+ +

隨著不同設備上屏幕解析度標準的增多,響應式設計已經變得越來越重要。即使你app的主要目標平台是移動平台比如Firefox OS,其他設備很有可能也會訪問它。CSS media queries 使你可以根據設備調整佈局,如下的CSS樣例中所示的結構:

+ +
/* The following are examples of different CSS media queries */
+
+/* Basic desktop/screen width sniff */
+@media only screen and (min-width : 1224px) {
+  /* styles */
+}
+
+/* Traditional iPhone width */
+@media
+  only screen and (-webkit-min-device-pixel-ratio : 1.5),
+  only screen and (min-device-pixel-ratio : 1.5) {
+  /* styles */
+}
+
+/* Device settings at different orientations */
+@media screen and (orientation:portrait) {
+  /* styles */
+}
+@media screen and (orientation:landscape) {
+  /* styles */
+}
+ +

有許多JavaScript和CSS的框架可以用於協助響應式設計和移動app發展(Bootstrap等),選擇最適合你的app和開發樣式的框架即可。

+ +

Web APIs

+ +

JavaScript APIs正隨著設備快速開發,同時地被創造和增強。Mozilla的WebAPI 致力於為JavaScript APIs引入成打的標準移動端特性。設備支援和狀況列表可以在WebAPI 頁面中查看。在下面這個例子中,JavaScript 特徵偵測仍然是最好的例子:

+ +
// If this device supports the vibrate API...
+if('vibrate' in navigator) {
+    // ... vibrate for a second
+    navigator.vibrate(1000);
+}
+ +

在下面這個例子中,<div>的顯示樣式會根據設備的電池狀態的改變而改變:

+ +
// Create the battery indicator listeners
+(function() {
+  var battery = navigator.battery || navigator.mozBattery || navigator.webkitBattery,
+      indicator, indicatorPercentage;
+
+  if(battery) {
+    indicator = document.getElementById('indicator'),
+    indicatorPercentage = document.getElementById('indicator-percentage');
+
+    // Set listeners for changes
+    battery.addEventListener('chargingchange', updateBattery);
+    battery.addEventListener('levelchange', updateBattery);
+
+    // Update immediately
+    updateBattery();
+  }
+
+  function updateBattery() {
+    // Update percentage width and text
+    var level = (battery.level * 100) + '%';
+    indicatorPercentage.style.width = level;
+    indicatorPercentage.innerHTML = 'Battery: ' + level;
+    // Update charging status
+    indicator.className = battery.charging ? 'charging' : '';
+  }
+})();
+ +

在上面的示例代碼中,一旦你確定設備支持Battery API,你就可以為chargingchange 和 levelchange添加 event listeners 來更新元素的樣式。試試添加下面的指令到快速入門模板,你會看到你的工作效果。

+ +

時常檢查WebAPI 頁面以確保更新設備API的狀態。

+ +

Install API 功能

+ +

在我們的快速入門應用模板範例中,我們已經實現了一個安裝按鈕,可以在你把應用當作一個標準網頁來瀏覽時可以單擊它來把那個網站當作一個應用安裝在Firefox OS上。按鈕標籤並沒有什麼特別的:

+ +
<button id="install-btn">Install app</button>
+ +

按鈕的功能由Install API實現(見install.js):

+ +
var manifest_url = location.href + 'manifest.webapp';
+
+function install(ev) {
+  ev.preventDefault();
+  // define the manifest URL
+  // install the app
+  var installLocFind = navigator.mozApps.install(manifest_url);
+  installLocFind.onsuccess = function(data) {
+    // App is installed, do something
+  };
+  installLocFind.onerror = function() {
+    // App wasn't installed, info is in
+    // installapp.error.name
+    alert(installLocFind.error.name);
+  };
+};
+
+// get a reference to the button and call install() on click if the app isn't already installed. If it is, hide the button.
+var button = document.getElementById('install-btn');
+
+var installCheck = navigator.mozApps.checkInstalled(manifest_url);
+
+installCheck.onsuccess = function() {
+  if(installCheck.result) {
+    button.style.display = "none";
+  } else {
+    button.addEventListener('click', install, false);
+  };
+};
+
+ +

我們來簡要的看一下發生了什麼:

+ +

1. 我們得到一個安裝按鈕的引用並把它儲存在button變量中。
+ 2. 我們使用navigator.mozApps.checkInstalled 來檢查這個由http://people.mozilla.com  /~cmills/location-finder/manifest.webapp 這個表單來定義的應用是否已經安裝在設備上。這個測試結果被儲存在installCheck這個變量中。
+  3. 當測試被成功完成時,它的成功會完成事件被觸發,因此installCheck.onsuccess = function() { ... }會被執行。
+  4. 然後我們用一個if語句判斷installCheck.result是否存在?如果存在,以為著app已經被安裝了,我們就隱藏安裝按鈕。在應用已經被安裝的情況下不需要安裝按鈕。
+  5. 如果app沒有被安裝,為按鈕添加一個單擊事件監聽器。所以在按鈕被單擊的時候,install()函數會被執行。
+  6. 當單擊按鈕並且install()函數執行時,我們把表單檔案位置保存在一個叫manifest_url的變量中,然後利用navigator.mozApps.install(manifest_url)來安裝app,用一個installLocFind變量來儲存對那個安裝的app參考資訊。你會注意到安裝也會觸發success和error事件,所以你可以根據應用是否成功安裝來執行不同的動作。

+ +

第一次遇到可安裝web apps時,你可能想要覈實implementation state of the API 的執行狀態。

+ +

注意:可安裝開放web apps有一個「每個來源(origin,感覺就是URL的意思)就是一個app」的安全策略;基本上, 你不可以在一個來源上托管多個可安裝apps。這會讓檢測變得有一點複雜,但是仍有很多辦法解決這個問題,比如為應用創建多個子域名、用Firefox OS模擬器測試應用、或者在Firefox Aurora/Nightly上安裝測試功能,通過這種方式你可以在桌面環境上安裝開發web app。關於來源的跟多信息詳見FAQs about apps manifests

+ + +

WebRT APIs (基於權限的 APIs)

+ +

有些WebAPI雖然可以使用但是需要特定的功能開啓才具有使用的權限。應用可能會像下面這樣在manifest.webapp中記錄權限請求:

+ +
// New key in the manifest: "permissions"
+// Request access to any number of APIs
+// Here we request permissions to the systemXHR API
+"permissions": {
+    "systemXHR": {}
+}
+ +

權限分為下面三個等級:

+ +
    +
  1. +

    一般權限——不需要任何特定訪問權限的API。

    +
  2. +
  3. +

    特殊權限——只要開發者在app表單文件中設置了訪問權限就可以在應用中利用並通過可信任來源進行分發的API。

    +
  4. +
  5. +

    認證權限——控制力設備上關鍵功能的API,比如打電話和發短信的服務。這些一般不允許第三方開發者使用。

    + +

    關於應用權限等級的更多信息,請閱讀Types of packaged apps。你可以在應用權限中找到更多關於API要求權限和需要什麼樣的App permissions.。

    +
  6. +
+ +
+

有一點需要注意的很重要就是不是所有的Web API都可以在Firefox OS模擬器中執行。

+
+ +

工具 & 測試

+ +

測試在對移動應用的支持中是至關重要的。測試可安裝的開放web app有多種方式。

+ +

WebIDE 和 Firefox OS 模擬器

+ +

安裝和使用Firefox OS模擬器是啓動和運行你的應用最簡單的方式。在你安裝模擬器之後,可以通過工具->web開發者->Firefox OS模擬器菜單來啓動。模擬器啓動時會有一個Javascript控制台,這樣你就可以在模擬器中調試你的應用。

+ +

測試工具的新寵兒被稱為app管理器WebIDE。這個工具允許你通過USB鏈接桌面火狐瀏覽器和一個可兼容性設備(或者一個Firefox OS模擬器),直接將app推送到設備上,驗證app並且像運行在設備上一樣的調試。

+ +

單元測試

+ +

當在測試不同設備和版本時,單元測試就會非常有價值。jQuery的QUnit 是一個流行的客戶端測試工具,當然你也可以使用任何你喜歡的測試工具。

+ +

在設備上安裝Firefox OS

+ +

既然Firefox OS是一個開源平台,代碼和工具都可以用於在你自己的設備上構建和安裝Firefox OS。構建和安裝指南以及什麼設備可以安裝的注意事項可以在MDN上發現。

+ +

特定的Firefox OS開發者預覽版設備可以在Developer preview phone page找到更多信息。
+ 應用。

+ +

App 提交和分發

+ +

一旦你的app完成,你可以像標準網站或app一樣托管它(更多信息請閱讀Self-publishing apps ),或者可以submittedFirefox Marketplace。你的app表單將被驗證並且你可以選擇你的應用將支持的設備(比如:Firefox OS、桌面版火狐瀏覽器、移動版火狐瀏覽器、平板火狐瀏覽器)。一旦驗證通過,你可以為你的app添加更多細節(截屏、描述、價格等)並且正式在火狐市場中提交app列表。提交成功後,你的應用可以被任何人購買和安裝。

+ +

更多商場 & 上市信息

+ +

    1. 向Firefox OS商場中提交應用 Submitting an App to the Firefox OS Marketplace
+     2. 市場審查標準 Marketplace Review Criteria
+     3. 應用提交演練視頻 App Submission Video Walkthrough

+
diff --git a/files/zh-tw/archive/b2g_os/releases/1.2/index.html b/files/zh-tw/archive/b2g_os/releases/1.2/index.html new file mode 100644 index 0000000000..bc8f785f6b --- /dev/null +++ b/files/zh-tw/archive/b2g_os/releases/1.2/index.html @@ -0,0 +1,465 @@ +--- +title: Firefox OS 1.2 for developers +slug: Archive/B2G_OS/Releases/1.2 +translation_of: Archive/B2G_OS/Releases/1.2 +--- +
+

Firefox OS 1.2 is at a pre-release stage right now. Its Gecko component is based on Firefox 26 (encompassing all Gecko additions between Firefox 19 and Firefox 26; see Firefox 26 release notes for developers for the latest.) This page details the developer features newly implemented in Firefox OS 1.2.

+
+ +

Developer Tools

+ + + +

HTML

+ +

General Gecko:

+ + + +

CSS

+ +

General Gecko:

+ + + +

JavaScript

+ +

General Gecko:

+ +

EcmaScript 6 (Harmony) implementation continues!

+ + + +

Telephony-specific additions (mostly API-related)

+ + + +

DOM/API

+ +

Firefox OS-specific:

+ + + +
New WebGL 1 extensions supported in Firefox OS 1.2:
+ + + +
+
Note: availability of these extensions depends on device capabilities; not all extensions will be available on all devices.
+
+ +

General Gecko:

+ + + +

SVG

+ +

General Gecko:

+ + + +

MathML

+ +

General Gecko:

+ + + +

Network

+ +

General Gecko:

+ + + +

Worker

+ +

General Gecko:

+ + + +

Security

+ +

General Gecko:

+ + + +

XForms

+ +

General Gecko:

+ +

Support for XForms has been removed in Firefox 19.

+ +

See also

+ + + +

Older versions

+ +

+ +

+ +

+ +

Share this article: http://mzl.la/1av9ZRr

diff --git a/files/zh-tw/archive/b2g_os/releases/index.html b/files/zh-tw/archive/b2g_os/releases/index.html new file mode 100644 index 0000000000..3edbcd4c75 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/releases/index.html @@ -0,0 +1,24 @@ +--- +title: Firefox OS developer release notes +slug: Archive/B2G_OS/Releases +tags: + - Firefox OS + - NeedsTranslation + - TopicStub +translation_of: Archive/B2G_OS/Releases +--- +

Firefox OS release notes by version

+

This section provides articles covering each new release of Gaia and Gecko for Firefox OS, explaining what features were added and bugs eliminated in each update. There is also a linked summary table showing what APIs are supported by each version of Firefox OS.

+
+ {{ListSubpages("",1,0,1)}}
+

Other supporting information

+
+
+ Firefox OS API support table
+
+ Lists the different APIs available, and what versions of Firefox have support for them.
+
+ App permissions
+
+ Lists hosted, privileged and certified APIs, along with information on the permissions they need to have set in the App Manifest of your installable apps, such as the manifest permission name, app type required, description, access property, and default permission.
+
diff --git a/files/zh-tw/archive/b2g_os/running_custom_builds_in_the_app_manager/index.html b/files/zh-tw/archive/b2g_os/running_custom_builds_in_the_app_manager/index.html new file mode 100644 index 0000000000..be4fefd747 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/running_custom_builds_in_the_app_manager/index.html @@ -0,0 +1,43 @@ +--- +title: 在 WebIDE 中執行 Firefox OS/Gaia 自訂版本 +slug: Archive/B2G_OS/Running_custom_builds_in_the_App_Manager +translation_of: Archive/B2G_OS/Developing_Gaia/Running_custom_builds_in_WebIDE +--- +
+

Firefox OS 模擬器 (Firefox OS Simulator) 已於 2014 年 2 月新增功能,可執行自訂的 B2G 執行環境及/或 Gaia 設定檔 (Profile)。本文將說明相關設定方式,並透過 WebIDE 執行模擬器。

+
+
+

注意:在本文發表之時,滑鼠事件尚未能正確對應觸控事件。例如回到主畫面鈕並無法回應滑鼠點擊的動作。但只要使用 B2G Desktop 鍵盤指令,即可解決此問題。可參閱「Using the B2G Desktop client」。

+
+
+

注意:如果你能提交 Try 版本,則可在各個 B2G 桌面平台的版本路徑中產生模擬器附加元件。如此可讓模擬器搭配自訂的 Gecko,或搭配對 Gaia 上進行的修改。在某些使用條件下可選用此較簡易的方式。

+
+

必要條件

+

要在模擬器內執行自訂版本,必須齊備相關工具。

+
    +
  1. 安裝 Firefox 並確定其內有 WebIDE (工具 > 網頁開發者 > WebIDE)。
  2. +
  3. 安裝最新版 B2G Desktop Nightly,或建構自己的版本
  4. +
  5. 安裝最新版 Firefox OS 模擬器套件,即 7.0pre7.20140113 或更高版本。或可將 FXOS_SIMULATOR=1 添增到自己的 mozconfig,並使用 ./mach build && ./mach package,從自己的 B2G Desktop 原始碼來建構。
  6. +
  7. SIMULATOR=1 flag 建立 Gaia 設定檔。舉例來說,你可在自己的 Gaia 路徑中執行 make SIMULATOR=1 PROFILE_FOLDER=profile-b2g profile-b2g 指令 (請參閱 Hacking Gaia 進一步了解)。
  8. +
+

設定自己的模擬器

+

你必須完成某些設定,才能讓模擬器找到你的 B2G Desktop 與自訂的 Gaia。

+
    +
  1. 打開附加元件管理分頁 (工具 > 附加元件;或在網址列中輸入 about:addons)。
  2. +
  3. 點擊「擴充套件 (Extensions)」分頁,可列出現已安裝的套件。
  4. +
  5. 在清單中找到新的 Firefox OS 模擬器擴充套件。應該會顯示如 Firefox OS 1.3 Simulator 7.0pre.7.20140113
  6. +
  7. 點擊此擴充套件內的「選項 (Preferences)」按鈕。
    + the Firefox OS simulator preferences: Preferences, disable and remove.
  8. +
  9. 如果你要使用自訂的可執行檔 (最新的 B2G Desktop 版本),以利於 WebIDE 中執行 Firefox OS,則點擊「Select a custom runtime executable」旁邊的「Browse...」按鈕,在檔案選擇介面中找到自己的 B2G Desktop 可執行檔。如果是 Windows/Linux 環境就很好找;而在 Mac 環境中,只要安裝於 Applications 路徑下,就可於 /Applications/B2G.app/Contents/MacOS/b2g 找到。
  10. +
  11. 你也能在 WebIDE 中執行自訂的 Gaia 設定檔。同樣點擊「Select a custom Gaia profile directory」旁邊的「Browse...」按鈕,找到自訂的設定檔路徑 (應該是 gaia/profile-b2g)。
  12. +
  13. 如果要回到非自訂的模擬器,只要重新設定組態值即可。但不能單純的刪除再重新安裝模擬器附加元件。你必須開啟新的分頁,在網址列中輸入「about:config」,繼續在該頁的搜尋欄位中輸入「fxos」或「simulator」,找到如「extensions.fxos_2_0_simulator@mozilla.org.customRuntime」,或「extensions.fxos_2_0_simulator@mozilla.org.gaiaProfile」。這時按下滑鼠右鍵並點選「Reset」。最後重新啟動模擬器版本,就能使用非自訂版本的模擬器。
  14. +
+

使用自訂的模擬器

+

最後說明該如何使用自訂的模擬器。

+
    +
  1. 啟動 WebIDE (工具 > 網頁開發者 > WebIDE);或可按下「Shift + F8」。
  2. +
  3. 點擊右上方的按鈕,開啟「Runtime」選單。
  4. +
  5. 點擊「Firefox OS 1.3」按鈕 (或你安裝的任何最新版本)。即使你的 B2G desktop/Gaia 版本比較新,仍建議點選 Firefox OS 1.3 版。
  6. +
  7. 接著就會啟動模擬器,將載入 B2G Desktop 並執行你的 B2G Nightly 版本與自訂 Gaia!
  8. +
+

a screenshot of the b2g desktop simulator

diff --git a/files/zh-tw/archive/b2g_os/screencast_series_colon__app_basics_for_firefox_os/index.html b/files/zh-tw/archive/b2g_os/screencast_series_colon__app_basics_for_firefox_os/index.html new file mode 100644 index 0000000000..ae38c355ea --- /dev/null +++ b/files/zh-tw/archive/b2g_os/screencast_series_colon__app_basics_for_firefox_os/index.html @@ -0,0 +1,208 @@ +--- +title: 系列影片:Firefox OS App 開發入門 +slug: 'Archive/B2G_OS/Screencast_series:_App_Basics_for_Firefox_OS' +translation_of: 'Archive/B2G_OS/Firefox_OS_apps/Screencast_series:_App_Basics_for_Firefox_OS' +--- +
+

Firefox OS 這款作業系統,就是要將 Web 帶入行動裝置所設計。Firefox OS 不是以新技術或新開發環境所建構的全新 OS;而是以行之有年的標準化 Web 技術所打造而成。如果你本身就是 Web 開發者且想建構行動 App,那麼 Firefox OS 就能提供最適合的工具,且不會要求你改變自己以熟悉的工作流程,也不需再重新學習另一套開發環境。此系列短片是由 Mozilla 與 Telenor 在挪威共同錄製而成,將引領你入門 Firefox OS App 的開發作業。

+
+ +

你可透過本系列影片了解:

+ + + +
+

注意:每部短片均極為精簡扼要,讓你短暫休息時也能欣賞。一口氣看完整個系列也不會超過一個小時。

+
+ +

程式碼與開發環境

+ +

除了短片之外,你也能從 GitHub 下載程式碼範例。如果你想自己測試程式碼範例,就必須先設定簡易的開發環境。必備條件如下:

+ + + +

系列影片介紹

+ +

此系列短片是由 Telenor Digital 的 Jan Jongboom (@janjongboom)Sergi Mansilla (@sergimansilla),以及 Mozilla 的 Chris Heilmann (@codepo8) 於 2014 年 2 月所錄製。地點位於挪威首都奧斯陸的 Telenor Digital 辦公室內。

+ +

這三位接下來將為大家簡短介紹系列影片:

+ +

{{EmbedYouTube("835Z2RTPdQk")}}

+ +

Section 1:建構並發佈

+ +

自己的第一款 Firefox OS App

+ +

接下來 5 支短片將說明如何建構 Firefox OS App、如何在電腦和實體裝置上測試 App 並除錯、如何將 App 發佈至 Firefox Marketplace 中。這看起來好像很複雜,但其實只要你已經知道怎麼寫網站,就等於能完成 90% 的 App。

+ +

不只是網站

+ +

Firefox OS App 就是 HTML5 App;其所使用的技術本質上也與網站技術相同。你可以先寫個網站,再提供 manifest 檔案 (可參閱《App manifest》進一步了解) 即可將網站轉為 App。這個動作就等於告知 Firefox OS 你在撰寫 App,並可讓你:

+ + + +

HTML5 App 其實是透過網站強化其功能,也同樣遵循相同的規則,如:

+ + + +

若要將網頁轉為絕佳的 App,其中的差異就在於開發者就必須考量到行動裝置使用者。也代表 App 首先必須要能:

+ + + +

在大多數的情況下,開發者必須稍微讓網頁「瘦身」並簡化介面。而使用者也確實能因此獲得更好的經驗。

+ +

{{EmbedYouTube("oUbOw2cQC4k")}}

+ +
+

注意:若要進一步設計出絕佳的 HTML5 App,可參閱 MDN 上的《應用程式中心》一文。

+
+ +

App 的 Manifest 檔案

+ +

Firefox OS App 的 manifest 檔案 (你會在「應用程式管理員 App Manager」看到中文翻譯為「安裝資訊檔」),屬於簡易的 JSON 檔案,將告知作業系統該 App 的相關訊息;另外也可將網頁轉為 Open Web App。開發者可於 manifest 定義 App 不同語系的名稱,也可要求作業系統存取不同的服務與硬體。當然亦可定義該 App 適合的方向 (直幅或橫幅),亦能依需要而鎖定畫面。

+ +

{{EmbedYouTube("UTXIVg6sYtA")}}

+ +

進一步了解 manifest 檔案與相關工具:

+ + + +

應用程式管理員 (App Manager)

+ +

要想開始入門 Firefox OS,最簡單的方法就是使用「應用程式管理員 (App Manager)」。應用程式管理員也是桌面版 Firefox 的開發者工具之一,可在電腦上模擬 Firefox OS 裝置。開發者可盡情把玩 Firefox OS,也可像在實際裝置上安裝並測試 App。此外,你也能離線或上線編輯 App,進而體驗 App 並進行除錯,在模擬裝置中即時看到修改之後的結果。

+ +

{{EmbedYouTube("oyAlYjpK-PE")}}

+ +

若要進一步了解應用程式管理員:

+ + + +

在實體裝置上測試

+ +

在模擬器上測試 App 當然不錯,但畢竟會受限於模擬的環境。如果想測試 App 互動時的效能或畫面呈現方向,就需要實體裝置。實機同樣可搭配既有的開發者工具,以及「應用程式管理員 (App Manager)」。在實機上使用 App 時,可透過上述 2 種工具進一步了解 App 所發生的作業。而且 App 不必更新,也不必解除安裝,即可即時看到 App 的變化。

+ +

{{EmbedYouTube("T8sr9SHKDHE")}}

+ +

發佈至 Marketplace

+ +

Firefox Marketplace 可供開發者提交 App,並讓消費者能夠接觸到自己的作品。Marketplace 亦可發佈如 Firefox 桌面版與行動版所適用的 App。而消費者只需要簡單的幾個步驟,就能對 App 評分、提出反饋意見、購買自己所需的 App。要發佈自己的 App 真的很簡單:

+ + + +

{{EmbedYouTube("kk3gYALtE0Q")}}

+ +

App 在提交到 Marketplace 之後,均會由 Mozilla 審查團隊進行審閱,並在幾天內就會通知審查結果。如果 App 有任何問題,在提交期間就會收到相關的檢驗訊息。開發者也有可能收到詳細的問題說明,並獲得修復問題的方法。

+ +

Section 2:Firefox OS 進階說明

+ +

引言

+ +

在前幾支影片中,我們談了 Firefox OS 的基礎概念、打造自己第一個 App 的步驟、在桌機與 Firefox OS 實體裝置上進行 App 除錯,最後把自己的 App 提交到 Marketplace 上。

+ +

而接下來的影片會再進一步說明 Firefox OS App 的技術;也會談談存取功能,讓開發者能妥善利用平板電腦與智慧型手機。但這些技術目前僅適用於 Firefox OS,還未能擴及其他平台。Firefox OS 內的所有程式,都是針對標準化與開放源碼的目標所設計。也就是說,我們很快就能在其他裝置或平台上看到 Firefox OS App 的蹤跡。

+ +

Web API

+ +

智慧型手機具備 GPS、相機、加速規等的多樣高階功能。但問題是 Web 技術並無法碰觸到這些功能技術。如果要存取這些功能,就必須撰寫原生應用程式。為了克服這個問題,Mozilla 與合作夥伴定義了一系列 API,可讓開發者以安全的方式,透過 JavaScript 存取行動裝置所搭載的硬體。這些開放的 API 即所謂的 Web API,同樣也提供給他人建構更多功能。Firefox OS 也是第一個使用 Web API 的平台。開發者不需另外撰寫原生的應用程式,即可存取智慧型手機上所需的功能。

+ +

{{EmbedYouTube("QkpH_qugrPk")}}

+ +

若要進一步了解 Web API:

+ + + +

Web Activities

+ +

Web Activities 可視為 Web API 的替代方案,同樣可存取某些特定裝置的硬體。相較於 API 直接與裝置溝通,Web Activities 則是在裝置上建立所有 App 的生態系統,讓 App 彼此相互溝通。舉例來說,App 不會存取相機而是要求圖片,讓使用者可透過自己最愛用的 App 取得圖片。也就是說,App 不要求使用者存取硬體 (偏安全性的考量),而是讓使用者所信賴的 App 去取得圖片。此外,你也可以註冊特定 App 負責處理 OS 中的特定作業。Web Activities 其實就像對桌機裡的檔案按下滑鼠右鍵,你能在右鍵選單中看到有多種 App 可開啟檔案。而使用者可要求 OS 預設特定 App 開啟此一類型的檔案。Web Activities 可讓裝置上的 App 相互溝通,而不需再透過伺服器作為媒介。App 之間傳送的資料均已為最終資料。

+ +

{{EmbedYouTube("RQbCyDd9ejE")}}

+ +

進一步了解 Web Actitivies:

+ + + +

推播通知

+ +

使用 SimplePush WebAPI 的推播通知 (Push notification) 功能,可在裝置接收到特定訊息時喚醒 App。如此可在省電狀態下讓 App 保持待機,再隨時根據需求喚醒 App;此功能對行動裝置 App 格外重要。用這種方式所傳送的通知也有其優點:這種通知不會攜帶任何資料,Mozilla 不會取得 App 的資訊,而惡意攻擊者也無法監聽。

+ +

{{EmbedYouTube("F5UF4dKojzw")}}

+ +

若要進一步了解 SimplePush 所推播的通知:

+ + + +

離線功能

+ +

如果 App 無法離線作業,那可用性就會大大降低。有部分使用者也因為這個理由,比較喜歡安裝 App 之後只要開啟瀏覽器,就能在裝置的瀏覽器上查看所需的內容。其實「Web App」這個詞看起來會有「需要網路連線才能運作」的感覺。但使用者總是有無法上網的時候:飛機上必須關機、地底下收不到訊號,甚或手機內沒留任何資料。開發者應該要確保自己的 App 能離線運作。而 HTML5 即具備幾項離線作業的技術,主要就是 AppCacheDOMStorage

+ +

{{EmbedYouTube("Q_WmkCzEKho")}}

+ +

進一步了解離線功能:

+ + + +

深入了解

+ +

我們希望這一系列的影片,能夠順利帶領開發者建構出自己的第一款 Open Web App。如果你很感興趣也想了解更多細節,也有許多其他資源與管道可供你利用:

+ +

{{EmbedYouTube("UVf2EVrLpl8")}}

+ + + +

歡迎大家多多交流

+ +

影片錄製人:Chris、Sergi、Jan

diff --git a/files/zh-tw/archive/b2g_os/security/application_security/index.html b/files/zh-tw/archive/b2g_os/security/application_security/index.html new file mode 100644 index 0000000000..3e8f8d576e --- /dev/null +++ b/files/zh-tw/archive/b2g_os/security/application_security/index.html @@ -0,0 +1,124 @@ +--- +title: 應用程式安全 +slug: Archive/B2G_OS/Security/Application_security +translation_of: Archive/B2G_OS/Security/Application_security +--- +
+

本文涵蓋 Firefox OS 應用程式安全模型細節內容。

+
+

Firefox OS Web app 核心安全控制如下:

+ +

App 類別

+

Firefox OS 支援: "web", "privileged" 和 internal ("certified") 三種類別的 Web app,app 的類別宣告在 manifest 裡 (另外使用權限也在裡面) 。

+ +
+

Note: 關於 App 類別,詳細說明請見 App Manifest

+
+

App 下載

+

Firefox OS 共有兩種 App 下載機制:hosted 以及 packaged。一般 web app 兩種方式都能適用,但 privileged 和 certified apps 只能走 packaged 的方式。

+

Hosted(託管式) apps

+

Hosted app 只包含開發者網站伺服器上的 application manifest 檔案,Manifest 檔案裏面有 app 開啟時的啟動頁面路徑。從安全性角度來看 hosted app 和網頁差不多,當打開 hosted app ,載入頁面的 URL 就是網頁在伺服器上的一般 URL,如果之前有 appcache 存檔的話則會從裝置上載入。

+

Packaged(封裝式) apps

+

Packaged app 將所有的資源 (HTML, CSS, JavaScript, app manifest 等等) 包在一份 zip 檔中,而非網頁伺服器,細節請見 Packaged apps

+

App 來源

+

對於 hosted app,application manifest 檔案所在地就是其來源。

+

至於 packaged apps,其來源就是安裝當下決定的應用程式識別,而 Privileged 和 Internal apps 另外可以在 applications manifest 檔案裡用 origin 參數請求使用特定來源。

+

App 安裝

+

App 透過 Apps JavaScript API 安裝:

+ +

App manifest 和 App 來源必須一致,這樣避免了未知的第三方冒用 App;另外為了避免網站被不小心或故意被偽裝成有 app manifest,manifest 檔必須以特定 mime-type,application/x-web-app-manifest+json, 發送。

+

更新

+

更新程序請見更新 apps

+

權限

+

App 能夠被授予比一般網頁更多的權限。基本上 app 擁有和網頁同等的權限,如果 app 需要更多額外權限,那麼 app 便需要在 manifest 檔裡明白列出需要的額外權限。

+

Manifest 宣告

+

在 manifest 裡,每一個需要的額外權限必須加入供人閱讀的描述說明為何需要此額外權限,例如 app 想要 navigator.geolocation API 使用權限,manifest 裡就必須如此宣告:

+
"permissions": {
+  "geolocation":{
+    "description": "Required for autocompletion in the share screen",
+  }
+},
+
+

這樣 app 便可以如同網頁一般提示使用者來請求地理位置存取權限。更多細節請見 App manifest

+
+

Note: 目前權限使用目的並不會呈現給使用者看 — 見 bug 823385.

+
+

權限授予

+

當權限需求在 manifest 中宣告後,依據權限不同,可能會直接被同意,但也可能需要在第一次相關 API 被存取時提示使用者徵詢其同意。一般來說會影響到使用者隱私的權限會需要額外徵詢使用者同意,而且這種情況下使用者也有理由知道甚麼權限被請求使用,例如存取通訊錄前會需要徵詢,但存取 TCP 連線則不需要。權限直接同意會經過 Marketplace 安全審核程序以確保安全性。

+

權限駁回

+

使用者可以在任何時候從設定駁回先前授予的權限,但這不包括那些直接同意的權限。

+

Web App Sandbox

+

App 資料獨立

+

每一個 app 都運行在 sandbox 之中,所以所有資料都和其他 app 隔離開來,這涵蓋了 cookie、localStorage、indexedDB 以及網站權限。

+

A diagram showing three Firefox OS apps all open is separate sandboxes, so none of them can affect each other.

+

所以說即使 App A 和 App B 都開啟了指向同一來源 (如 http://www.mozilla.org) 的 {{ htmlelement("iframe") }},但他們兩者的 cookie 資料還是會不同。結果就是當用  App A 登入 Facebook 帳號,開啟了 App B 前往 Facebook 時,因為 App B 無法存取 App A 的 cookie,所以 App B 還是必須要再執行登入作業,如此一來變確保了 App 之間不互相影響、資料安全。

+

Apps 無法啟動彼此

+

App 不能利用 <iframe> 開啟另一個 App,如果 App A 開啟了一個指向 App B URL 的 iframe,這並不會啟動 App B,相反地這只會前往那個 URL 指向的網頁,任何 App B 的 cookie 都無法被存取,這就和 App B 沒有被安裝的情況一樣。

+

就算是 App A 嘗試開啟透過 packaged 式 App B 的 app:// URL,來將 App B 載入到 <iframe> 裡啟動,也會失敗,而且不論 App B 有沒有被安裝,失敗訊息都會一樣,所以說 App A 也無法推敲 App B 的安裝狀態。

+

當 App A 上層的 frame 前往 App B 所在的 URL,結果依然相同。我們永遠知道是哪個 frame 開啟哪個 app,所以說透過上層 frame 開啟其他 app 就和前述一樣會失敗,App 之間資料絕對獨立、無法被盜取。

+

動機

+

資料獨立的做法有好有壞,壞處是使用者必須每開一個 app 都要登錄一次同一個網站,或者是網站有存放一些資料於本地端,每個 app 都會儲存一份資料,同樣的資料可能被重複儲存,如果資料剛好又不小的話,將會相當佔儲存空間。

+

好處是這是比較安全的做法,app 之間不能透過第三方網站互相影響進而導致未預期的行為,或是一個 App A 移除後,另一個 App B 不會因為依賴 App B 的資料或功能而無法運作。更重要的是,資料獨立確保了惡意 app 難以利用漏洞竊取其他網站的資料。

+

最後資料獨立也確保了 app 無法得知使用者是否有裝甚麼其他 app、其他 app 的資料,保護了使用者隱私。

+

權限 Sandbox

+

如同資料在 snadbox 下是獨立隔離開來的,權限亦然。App A 打開了 http://maps.google.com 網頁,而使用者也准許永遠允許 http://maps.google.com 使用地理位置服務,但這也只限於 App A,改天換 App B 打開 http://maps.google.com 網頁,地理位置服務使用權限還是得再徵詢使用者同意。

+

如同一般網頁,每個來源的權限同樣獨立,App A 取得地理位置服務使用權限,但這不代表所有 App A 開啟的網頁都有權使用地理位置服務,如果說 App A 開啟 http://maps.google.comhttp://maps.google.com 照樣需要取得使用者同意才能使用地理位置服務。

+

瀏覽器 API Sandbox

+

對於會開啟大量 URL 的應用程式,如瀏覽器,我們引進了一個 browserContent 旗標來強化安全性,這個 browserContent 讓 app 可以有兩個 sandbox,一個供 app 本身使用,另一個給開啟的網頁使用,例如說:

+

有一個 MyBrowser app 自 https://mybrowser.com 載入,所以程式碼和資源都隸屬於這個網域。

+

當這個 app 建立一個 <iframe mozbrowser>,另一個 sandbox 便會產生,所以說 <iframe mozbrowser> 裡的 cookie、IndexedDB、localStorage 資料都會獨立隔離開來,兩者間不會互相影響。

+

從另一方面來看,如果 MyBrowser app 想要整合 Google Map 的地理位置功能,那麼從一般 <iframe> 裡載入 http://maps.google.com,便可以存取 Google Map 網站的 cookie 資料;但若是從 <iframe mozbrowser> 裡載入的話,便無法取得 Google Map 的 cookie 資料了。

+

假設另一個情況,有一個類似 Yelp、會造訪餐廳網站的 app,這個 app 只要利用 <iframe mozbrowser> 來打開餐廳網站,就可以確保餐廳網站不能含有指回這個 app 的 <iframe> (例如指回 http://yelp.com),如果有的話,該餐廳網站將只能收到 Yelp 網站的資料,而非此 Yelp app,所以該餐廳網站便無法和 Yelp app 共享資料和權限,進而攻擊 Yelp app。

+

App 安全性總結

+

下表總結各類 Firefox OS App 的格式、安裝、更新特性:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Web App 類型
類型發布權限安裝更新
WebHosted 或 Packaged較不敏感的權限,既使未驗證的網站取得也沒關係。可以從各種來源安裝依據安裝來源和發布機制可以背景更新或透過 marketplace 更新。
PrivilegedPackaged 和 Signed需要驗證和審核才可以取得特殊權限 API。從可信任的 marketplace 安裝從可信任的 marketplace 更新,需要使用者同意更新。
InternalPackaged第三方 app 無法存取高度敏感 API裝置預裝跟隨系統層級類別更新。
+
+

Note: 版本 1.0 的 Firefox OS,privileged app 只能從 Mozilla Marketplace 安裝,至於其他多種安全 marketplace 的支援尚未底定。

+
+

 

diff --git a/files/zh-tw/archive/b2g_os/security/index.html b/files/zh-tw/archive/b2g_os/security/index.html new file mode 100644 index 0000000000..468bab0472 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/security/index.html @@ -0,0 +1,70 @@ +--- +title: Firefox OS security +slug: Archive/B2G_OS/Security +tags: + - B2G + - Firefox OS + - Mobile + - NeedsTranslation + - Security + - TopicStub +translation_of: Archive/B2G_OS/Security +--- +

The following articles cover security-related topics about Firefox OS. This includes overall security features as well as application security and how the install process is kept secure.

+ + + + + + + +
+

Firefox OS security documentation

+
+
+ The Firefox OS security model
+
+ An overview of the Firefox OS security model.
+
+ System security
+
+ Details of security controls built-in to the FirefoxOS runtime.
+
+ Application security in Firefox OS
+
+ An overview of how applications are made secure on Firefox OS.
+
+ Securely installing and updating applications
+
+ How Firefox OS securely installs and updates applications.
+
+ Software permissions in Firefox OS
+
+ A guide to what types of software have permission to perform various tasks on Firefox OS.
+
+  Debugging and security testing with Firefox OS
+
+ This guide shows you the basic security testing steps, from opening a remote JavaScript debugger to setting up an intercepting HTTP(S) proxy against a desktop version of Firefox OS
+
+

View All...

+
+

Getting help from the community

+

If you're working with Firefox OS, or developing applications you'd like to run on Firefox OS devices, there are community resources to help you!

+
    +
  • Consult the Boot to Gecko project forum: {{ DiscussionList("dev-b2g", "mozilla.dev.b2g") }}
  • +
+
    +
  • Ask your question on Mozilla's Boot to Gecko IRC channel: #b2g
  • +
+

Don't forget about the netiquette...

+
+ + +
+

 

+
+
+ Firefox OS
diff --git a/files/zh-tw/archive/b2g_os/security/security_model/index.html b/files/zh-tw/archive/b2g_os/security/security_model/index.html new file mode 100644 index 0000000000..d71380833f --- /dev/null +++ b/files/zh-tw/archive/b2g_os/security/security_model/index.html @@ -0,0 +1,299 @@ +--- +title: Firefox OS 安全性概述 +slug: Archive/B2G_OS/Security/Security_model +translation_of: Archive/B2G_OS/Security/Security_model +--- +

此篇文章將概述 Firefox OS 的安全架構,可阻絕 App、平台、資料所挾帶的惡意威脅,進而保護行動裝置。Mozilla 建構了完整且多層次的安全模式,為行動電話提供絕佳的防護效果。

+

 

+

平台安全性

+

Firefox OS 平台具備多層次安全模式,可將各層次的開發風險降至最低。第一線的保護機制更整合了深度防禦 (Defense-in-depth) 策略,進而達到完整的防護機制。

+

 

+

安全架構

+

Firefox OS 將銜接網路架構的應用與其底層硬體,而其整合式技術囊括了下列層級:

+

+

行動裝置 (Mobile device) 即是執行 Firefox OS 的智慧型手機。Gonk 則包含 Linux kernel、韌體、系統函式庫、裝置驅動程式。Gecko 屬於應用程式的執行時間層,為 App提供執行框架,另建構 Web API 以存取行動裝置的功能。Gaia 則是網頁 App (包含 HTML5、CSS、JavaScript、圖片、媒體等) 套件,可隨時改善使用者經驗。

+

Gecko 扮演守門人的角色,可強制執行安全策略,避免行動裝置遭到誤用;並可作為網頁 App (位於 Gaia) 之間的中介層 (Intermediary)。Gonk 則可將行動電話底層的硬體功能,直接提供予 Gecko 使用。只有在 Gecko 放行存取請求時,網頁 App 才能透過 Web API 而存取行動電話的功能;而不會有直接存取或「走後門」的情況發生。Gecko 將強制執行許可,並阻擋未經授權的請求。

+

 

+

佈署安全系統

+

手機上的 Firefox OS 系統映像檔 (System image) 是由受信任的來源 (一般為該裝置的 OEM 廠商) 所提供,這些受信任的系統映像檔提供者負責發布檔案的組建、建置、測試以及數位簽章作業。

+

整個技術層均需經過安全驗證。由Linux 的存取控制清單 (ACL) 執行檔案系統的權限控制。系統 App 則安裝於唯讀 (僅於更新期間才暫時轉為可讀寫) 媒體之中;若是使用者相關內容的區域,則可能為讀寫性質。裝置硬體中的不同元件,均已內建了業界標準的防護機制。舉例來說,晶片製造商會加入安全防護技巧來提高安全性,我們同樣強化了核心平台 (Gecko 與 Gonk),以阻絕潛在的可能威脅,亦提升了相關編譯器的功能。可參閱執行期間的安全性進一步了解細節。

+

 

+

更新安全系統

+

Firefox OS 平台的後續升級與修正,將透過安全的 Mozilla 程序完成佈署,並確保行動電話上的系統映像保有其完整性。同樣由已知且受信任的來源 (一般為該裝置的 OEM 廠商) 提供更新作業,並負責更新封裝的組裝、建構、測試、數位簽章等作業。

+

系統更新可能牽涉 Firefox OS 部分或所有的層級。若更新作業必須變更 Gonk,則安裝作業將使用 FOTA (Firmware Over the Air)。FOTA 更新作業亦可能包含 Firefox OS 的其他層級,如 Gaia、Gecko、安全更新、裝置管理 (FOTA/韌體/驅動程式)、設定管理 (Firefox OS 的設定),還有更多修正檔。

+

若更新作業並未牽涉 Gonk,則僅需 Mozilla 系統更新公用程式 (System Update Utility) 即可完成。Firefox OS 所使用之更新架構、程序、Mozilla ARchive (MAR) 格式 (用於更新封裝),與 Firefox 桌面版產品完全相同。可參閱 https://wiki.mozilla.org/Software_Update 以進一步了解。

+

而行動電話所內建的更新服務 (亦可能由 OEM 廠商提供),將定期檢查是否有系統更新。一旦發佈系統封裝,更新服務隨即將偵測到該封裝,並提醒使用者完成安裝作業。在行動裝置安裝更新檔案之前,另將檢查裝置的儲存容量是否足夠,且將驗證下列分配空間:

+ +

更新期間應注意下列要點:

+ +

請確實完成相關檢查,讓行動電話確實完成更新作業。

+

 

+

App 的安全性

+

Firefox OS 使用深度防禦 (Defense-in-depth) 策略,可保護行動電話免受惡意應用程式的攻擊。此策略必須佈署多種機制,如根據 App 信任模式 (Trust model) 所建構的隱式許可 (Implicit permission) 層級;執行期間的沙箱執行作業 (Sandboxed execution);僅限 API 存取行動電話的底層硬體;健全的許可模型 (Permission model);安全的安裝與更新程序。若要進一步了解相關技術,可參閱應用程式安全性

+

在 Firefox OS 中的所有應用程式,均為 Web App ─ 即以 HTML5、JavaScript、CSS、媒體、其他開放式 Web 技術 (可於瀏覽器中執行的網頁,並不屬於本文所提的 Web App) 所撰寫的程式。由於這些 Web App 並非二進制 ─ 即所謂的「原生 (Native)」─ 應用,因此將由 Web API居中嚴格協調所有的系統存取作業。甚至檔案系統存取都只能透過 Web API 與後端的 SQLite 資料庫, App 不能直接存取 SD 記憶卡上的檔案。

+

Firefox OS 可限制 App 所能存取/使用的資源規模,同時又可針對多樣的 App 而支援不同的許可層級。Mozilla 嚴格控制各類 App 所能存取的 API。舉例來說,僅有 Certified App (隨手機出貨) 可存取 Telephony API。另外,Dialer App 必須存取 Telephony API 才能撥打電話,而非所有 Certified App 均可存取此 API。如此可避免安裝了任何第三方 App 之後,撥打出國際/長途電話而讓帳單金額暴增。但針對其他 OEM App,仍可選擇是否給予 Telephony API 存取權。舉例來說,電信服務商可提供系統管理應用程式,讓客戶能管理自己的帳戶,甚至能直接以電話送出電信服務帳單或支援辦公室作業。

+

 

+

受信任 (Trusted) 與未信任 (Untrusted) 的 App

+

Firefox OS 將 App 分為下列類型:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+

類型

+
+

受信任層級

+
+

說明

+
+

Certified

+
+

受高度信任

+
+

這類系統 App 經過電信服務商或 OEM (起因於裝置毀損或重要功能所產生的風險) 所核可。但僅限系統 App 與相關服務,並無第三方 App。
+ 此信任層級僅用於極少部分的重要 App,例如 SMS、藍牙、相機、電話、系統時鐘、預設的電話播號鍵盤 (為了可確實用於緊急電話)。

+
+

Privileged

+
+

受信任

+
+

由授權的商城審視、核可、數位簽章過的第三方 App。

+
+

Web (與其他 App)

+
+

未受信任

+
+

屬於一般網頁內容。包含安裝式 App (儲存於行動電話中) 與托管式 (Hosted,儲存於遠端,僅有 manifest 檔案儲存於行動裝置中) App。另外也可以從 Marketplace 取得托管式 App 的  manifest 檔案。

+
+

App 的受信任層級,某種程度上將決定其所能取用的行動電話功能。

+ +

某些作業 (如網路存取) 均先假設為所有 App 的隱式許可。一般來說,越是高敏感性的作業 (如撥打電話號碼或取得通訊錄內容),就僅有更高信任度的 App 才能執行。

+

最小權限原則 (Principle of Least Permissions)

+

針對 Web App,Firefox OS 安全架構則以《最小權限原則 (principle of least permissions)》為架構:先給予最低權限,僅在必要或合理的情況下,才選擇性的提高權限。依預設值,任一 App 均具備最低權限,以因應未受信任的網頁內容。如果 App 所呼叫的 Web API 需要額外權限,則其 manifest 檔案 (本文稍後將敘述) 必須先列舉這些額外權限。而僅在 App 的 manifest 檔案明確要求 App 授權時,Gecko 才會給予 Web API 的存取權。此外,只有在 Web App 的類型 (即上述的 Certified 或 Trusted 或 Web 分類) 符合其存取層級,Gecko 才會給予必要的授權。

+

Marketplace 對 Privileged App 的審核程序

+

若要達到 Privileged App,則 App 開發/供應商必須將之提交予經過授權的 Marketplace。而 Marketplace 隨即開始嚴格的程式碼審核程序:檢視其完整性與穩定性、審查其索取的授權是否符合其載明的用途、確認其隱式許可是否使用合宜、審核「Privileged App 的內容」與「未授權的外部內容」之間的介面,是否具備合適的緩衝,以避免權限提升 (Elevation of privilege) 的影響。Marketplace 另需負責確保 Web App 不會對其給予的權限進行惡意動作。

+

在 App 通過審核之後即許可使用,且 Marketplace 亦將以數位方式簽署其 manifest 檔案,以供行動裝置的使用者下載之。一旦 Marketplace 遭駭,數位簽章可確保駭客無法將任意內容或惡意程式碼,安裝於使用者的行動電話上。也基於此審查程序,Firefox OS 從 Marketplace 取得的 Privileged App,其可信任度亦高於一般的 (未受信任的) 網頁內容。

+

 

+

封裝式 (Packaged) 與托管式 (Hosted) App

+

Firefox OS 可用封裝式 (儲存於行動電話中) 或托管式 (儲存於遠端伺服器中,僅有 manifest 檔案儲存於行動電話中) App。而此 2 種 App 的安全管理方式亦有所不同。封裝式與托管式 App 同可作為應用程式的封閉沙箱,本文稍後將說明。

+

封裝式 (Packaged) App

+

封裝式 App 是以 ZIP 壓縮檔所構成,內含應用程式的相關資源 (HTML5、CSS、JavaScript、影像、媒體),另以 manifest 檔案提供上述資源的清單,與其對應的 雜湊值 (Hash)。由於 Certified 與 Privileged App 的 manifest 檔案均需完成數位簽章,因此Certified/Privileged App 必為封裝式 App。只要使用者取得封裝式 App,就會將 ZIP 檔案下載至行動電話中,另從 ZIP 檔案內的已知位置讀取 manifest 檔案。系統將在安裝過程中驗證 App 的資源,其他則儲存於本端的封裝內。執行期間將請求所有的顯式許可 (Explicit permission)、顯示使用者 App 的資料儲存目標,最後依預設值完成保存。

+

若要清楚指明封裝式 App 中的資源,則 URL 應以 App 開頭並使用下列格式:

+
+

app://identifier/path_within_zipfile/file.html

+
+

這裡的「app://」代表 ZIP 檔案的掛載點 (Mount point)。於行動電話上安裝 App 時,隨即產生「identifier」作為 UUID。如此可確保以 :app 的 URL 指向了特定資源,且已納入於 ZIP 檔案中。而 app: 中的路徑為相對路徑,因此可於 ZIP 檔案中允許資源的相對鏈結。

+

封裝式 App 主要用於 Certified 與 Privileged App,不過一般的 Web App 亦可作為封裝式。但這些 Web App 不會因為封裝格式,就自動提高其信任度或存取權限。

+

托管式 (Hosted) App

+

托管式 App 均儲存於網頁伺服器上,或需透過 HTTP 載入。僅有其 manifest 檔案儲存於行動電話中;其他所有檔案均儲存於遠端。僅 Privileged 與 Certified App 才能使用特定 API,以因應數位簽章作業而必須將 App 封裝。因此,即使 Web API 作業需要 Privileged/Certified App 的狀態,托管式 App 亦不需存取任何 Web API 作業。

+

從安全性的觀點來說,托管式 App 的作業方式比較像一般網頁。在該網頁伺服器上,必須以寫死 (Hard-coded) 的完整 URL 指向 App 根目錄中的起始頁面,才能載入托管式 App。一旦載入托管式 App 之後,行動電話將根據網頁瀏覽時的 URL,跟著連至相同頁面。

+

 

+

App 的 Manifest 檔案

+

Open Web App 的 manifest 檔案,將提供瀏覽器與 App 互動時的必要資訊。而 manifest 即為 JSON 檔案,至少均具備 App 的名稱與描述。可參閱 App 的 manifest 檔案常見問題以進一步了解。

+

Manifest 範例

+

下列程式碼則具備基礎設定的 manifest 範例:

+ + + + + + + +
+

1

+

2

+

3

+

4

+

5

+

6

+

7

+

8

+

9

+

10

+

11

+

12

+

13

+
+

{

+

  "name": "My App",

+

  "description": "My elevator pitch goes here",

+

  "launch_path": "/",

+

  "icons": {

+

    "128": "/img/icon-128.png"

+

  },

+

  "developer": {

+

    "name": "Your name or organization",

+

    "url": "http://your-homepage-here.org"

+

  },

+

  "default_locale": "en"

+

}

+
+

Manifest 檔案的安全性設定

+

manifest 檔案亦可具備其他設定,如下列的安全性設定:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+

欄位

+
+

說明

+
+

permissions

+
+

App 的必要許可。任何 App 需列出所要使用的 Web API,以取得使用者的許可。Privileged/Certified App 可識別大多數的許可,但托管式 App 不適用。API 必具備的屬性:

+
    +
  • description ─ 在請求使用此 API 時,此字串將指定其背後的目的地。必填。
  • +
  • access ─ 此字串將指定許可所需的存取類型。安裝時即給予隱式許可 (Implicit permission)。僅數種 API  為必填欄位。僅接受:readreadwritereadcreatecreateonly 等數值。
  • +
+
+

installs_allowed_from

+
+

App 的來源。而構成來源的陣列 (scheme+unique hostname) 則可觸發此 App 的安裝作業。另可讓 App 廠商限制僅授權過的 Marketplace (如 https://marketplace.firefox.com/) 才可安裝 App。

+
+

csp

+
+

內容安全政策 (Content Security Policy),將套用至 App 所載入的所有頁面。可強化 App 而避免遭惡意插入任何程式碼。若未指定 CSP,則 Privileged 與 Certified App 均已預設了系統定義值,其語法為:
+ https://developer.mozilla.org/en-US/docs/Apps/Manifest#csp

+

另請注意,此指令僅能增加所套用的 CSP。舉例來說,此指令並無法減少 Privileged App 所套用的 CSP。

+
+

type

+
+

App 的類型,即 Web、Privileged、Certified 等類型。

+
+

Firefox OS 要求 manifest 檔案必須為特定的 mime-type 格式 ("application/x-web-app-manifest+json"),而且必須與該 App 為相同來源的完整主機名稱 (即來源)。若「App 的 manifest 檔案」與「要求安裝 App 的頁面」兩者的來源相同,則將放寬此限制。此機制可確保不能偽裝網站並托管 App 的 manifest 檔案。

+

 

+

隔離式 (Sandboxed) 執行作業

+

本章節將說明 App 與執行作業的沙箱隔離區 (Sandbox)。

+

App 隔離區

+

Firefox OS 的安全架構,即是將隔離區作為深度防禦 (Defense-in-depth,DID) 策略,以減少風險並保護資料、平台、行動電話。在執行期間,隔離區可為 App 產生邊界與限制。各個 App 僅於自己的工作空間 (Working space) 內執行,另僅經過授權可存取的 Web API 與資料,才能存取;工作空間相關的資訊 (IndexedDB 資料庫、Cookies、離線儲存等) 亦然。請參閱 https://developer.mozilla.org/en-US/docs/Mozilla/Firefox_OS/Security/Security_model 以進一步了解。

+

下圖則簡略說明了安全模型:

+

+

在隔離各個 App 之後,所產生的影響亦僅限於其工作空間之內,而不會受到工作空間之外的干擾 (如其他 App 或資料)。

+

執行作業隔離區

+

B2G (Gecko) 在一個高授權度的系統程序 (可存取行動電話中的硬體功能) 中執行。在執行期間,各個執行環境裡的 App 皆是 B2G 系統程序的子程序。而各個子程序又具備嚴格的 OS 授權。舉例來說,子程序並無法直接讀寫檔案系統中的任意檔案。必須由 Web API 提供相關存取權限;且該權限又由 B2G 母程序所居中協調。在子程序要求授權過的 API 時,母程序將確認子程序具備必要的許可,以執行相關動作。

+

App 僅能透過 B2G 核心程序 (非其他程序或 App) 而相互溝通。App 無法於 B2G 之外獨立執行;各 App 亦無法互相開放。App 之間僅能間接「溝通」─ 例如接收器 (Listener) 程序偵測到其他程序所產生的事件,且必須由 B2G 程序居中協調。

+

僅透過 Web API 才能存取硬體

+

Web App 若要存取行動電話的功能,唯一管道只有以 Gecko 所建構的 Firefox OS Web API 。Gecko 是行動裝置與底層服務的單一出口,因此必須讓 Web API 進行呼叫作業,才能存取裝置的硬體功能。絕對沒有「原生 (Native)」的 API 或其他途徑可繞過此機制,而直接存取硬體或滲透至初階的軟體層。

+

 

+

安全架構

+

下圖則為安全架構的元件:

+

+ +

 

+

許可的管理與強化

+

針對 Web App 所需的許可 (Permission),Firefox OS 安全機制將進一步驗證並強化。
+ 僅當內容 (Content) 請求特殊許可,或當內容具備 manifest 所要求的適當許可時,系統才會發出特定許可至 App。若需要使用者進一步的授權,則某些許可亦將提出請求 (例如 App 要存取使用者目前的位置)。與傳統「角色為中心 (Role-centric)」的方式 (各個獨立角色將獲得一系列的許可)相較,這種「應用為中心 (app-centric)」的架構更能嚴密控管許可。

+

現有的 Web API 集合了一系列動作 (Action) 與接收器 (Listener)。各個 Web API 則具備必須的許可層級。每次只要呼叫 Web API,則 Gecko 檢查許可 (角色查找) 的基準為:

+ +

若該請求並不符合許可的準則,則 Gecko 隨即拒絕該請求。舉例來說,只要是受信任 App 所保留的 Web API,未受信任的 App 均無法執行。

+

 

+

要求使用者給予許可

+

除了與 Web App 隱性關連 (Implicitly associated) 的許可之外,在執行特定作業之前需要使用者給予顯式許可。針對這些作業,Web App 必須在 manifest 檔案中表示索取許可的理由 (Justification)。這種「資料使用意圖 (Data usage intention)」,可讓使用者在給予許可之後,知道 Web App 處理資料的方式,亦將了解可能的風險,進而能做出決定並控管自己的資料。

+

 

+

安全的 App 更新程序

+

+

針對 Privileged app 的升級與修正,開發/供應商必須將更新封裝提交至授權過的 Marketplace,以供 Marketplace 進一步審查。而在核准之後,隨即完成數位簽章並提供予使用者。在搭載 Firefox OS 的裝置上,亦可透過 App 更新公用程式 (暫譯 App Update Utility) 定期檢查 App 是否有可用的更新。若發現可用的更新,系統隨即會詢問使用者是否安裝。在行動裝置安裝更新檔案之前,必將驗證封裝的:

+ +

透過適當且嚴格的檢查,可確保行動電話已正確套用了更新。
+ 在開始更新程序之前,必須先下載完整的更新封裝至特定且安全的位置。安裝作業並不會覆寫任何使用者資料。

+

 

+

裝置安全性 (硬體)

+

行動裝置硬體的安全機制,一般均由 OEM 廠商所決定。舉例來說,OEM 廠商可能提供 SIM (Subscriber Identity Module) 卡的鎖定機制,另搭配 PUK (PIN Unlock Key) 密碼,以用於輸入錯誤 PIN 而遭鎖定的 SIM 卡。這部份需聯絡 OEM 廠商以了解細節。Firefox OS 則可讓使用者設定密碼與待機畫面,將於稍後說明。

+

 

+

資料安全性

+

使用者可將個人資料儲存於手機中,並可設定其隱私性,包含聯絡資訊、金融資訊 (銀行與信用卡細節)、密碼、行事曆等。Firefox OS 則針對惡意 App (竊取、挖掘、破壞私密資料) 而設計了防護機制。

+

 

+

密碼與待機畫面

+

Firefox OS 可供使用者設定行動電話的密碼,往後必須輸入正確密碼才能使用該行動電話。Firefox OS 另提供待機畫面的功能。只要設定特定時間內未使用行動電話,隨即顯示待機畫面。此時必須輸入密碼授權才能繼續使用手機。

+

 

+

隔離式 (Sandboxed) 資料

+

如之前所述,執行期間的 App 均進入隔離狀態。如此可避免 App 相互存取其內的資料;除非該筆資料已設為共享資料,且其他 App 擁有夠高的許可層級可存取之。

+

 

+

序列化 (Serialized) 資料

+

Web App 並無法直接讀寫檔案系統。相反的,僅能透過 Web API 而存取儲存媒體。Web API 另將透過 SQLite 資料庫居中協調,才能進一步讀取、寫入儲存媒體。不會直接以 I/O 進行存取作業。各個 App 均擁有自己的資料儲存媒體,將經過資料庫而序列化至磁碟中。

+

 

+

資料銷毀

+

一旦使用者取消安裝 App,則將刪除該 App 所有的相關資料,如 cookies、localStorage、Indexeddb 等。

+

 

+

隱私性

+

根據隱私權原則 (https://www.mozilla.org/privacy/),Mozilla 致力保護使用者隱私與資料,同時可參閱 Mozilla Manifesto (https://www.mozilla.org/about/manifesto.html)。而 Mozilla 的 Firefox Privacy Policy 則說明 Mozilla 將如何蒐集、利用 Mozilla Firefox 瀏覽器的使用者資訊,包含 Firefox 所傳送至網頁的資料、Mozilla 的資料保護方式、Mozilla 資料實務情況等。若要進一步了解相關細節,可參閱:

+ +

在擬定 Firefox OS 的原則時,均將使用者資料的控制權交付給使用者本身。而使用者必須自己決定個人資訊的運用方法。Firefox OS 將提供下列功能:

+ diff --git a/files/zh-tw/archive/b2g_os/security/system_security/index.html b/files/zh-tw/archive/b2g_os/security/system_security/index.html new file mode 100644 index 0000000000..edb0e64697 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/security/system_security/index.html @@ -0,0 +1,376 @@ +--- +title: 系統安全 +slug: Archive/B2G_OS/Security/System_security +translation_of: Archive/B2G_OS/Security/System_security +--- +
+

本文旨在提供 Firefox OS 系統安全模型概觀,說明系統是如何保持安全性與實施權限管理。

+
+

名詞解釋

+

在開始之前,有幾個名詞需要了解一下。

+
+
+ 網頁應用程式 (Web application)
+
+ 網頁應用程式 (web application, web app, open web app, moz app, application) 是運行在 Firefox OS (或其他支援平台)、用 HTML, JavaScript, 以及其他開源網頁技術所寫成的應用程式。所有 B2G 上使用者使用的應用程式都是網頁應用程式,例如撥號程式是一個 web app,但顯示在瀏覽中的網頁並不屬於網頁應用程式的範疇。
+
+ b2g 程序 (b2g process)
+
+ Firefox OS b2g process 通常會被叫做 "b2g" 或 "Gecko"。b2g 實際上是一個高權限 (root 權限) 應用程式,控制了所有 web app 對資源和硬體的存取。
+
+ 內容程序 (Content process)
+
+ b2g 產生的子程序,會和 b2g 溝通,代表了 web app。它擁有的權限較低 (一般使用者權限;受限的作業系統資源存取),透過 inter-process communication (IPC) 和 OS 核心溝通。
+
+ IPDL
+
+ Intercommunication Protocol Definition Language, 請參照 IPDL.
+
+ AOSP
+
+ Android Open Source Project.
+
+ System call
+
+ 一個介於使用者空間 (user space) 和核心 (kernel) 的溝通介面,使用者空間只能透過這個介面和核心溝通。
+
+ DAC, MAC
+
+ 使用者可設定的自主存取控制 (Discretionary Access Control) 和 系統強制的強制存取控制 (Mandatory Access Control)。
+
+ FOTA
+
+ 自動韌體更新機制 (Firmware Over The Air),透過無線網路"空中"更新韌體。
+
+ MSU (Mozilla System Updater), MAR (Mozilla ARchive)
+
+ 和 Firefox 桌面產品一樣的更新機制和檔案格式。
+
+

Firefox 作業系統安全模型目標與範疇

+

Firefox OS 安全模型的設計目標:

+ +

下面將說明每一個目標以及 Firefox OS 如何達成個目標。

+

權限強制

+

應用程式安全模型描述了使用者如何直接或透過受信任第三方來授予應用程式權限,這些強制加諸於內容程序 (content process) 的權限是透過限制資源存取必須經過和核心程序 (core process) 之間的 IPC call。

+ +

內容程序初始化

+

所有的 web app 都運行在低權限、分開的內容程序。當 web app 載入到一個特別的 {{HTMLElement("iframe")}} 型態: <iframe mozapp> 時 b2g 程序會啟動內容程序,這樣會將 web app 和其他內容隔離開來,而且和 web app 的 manifest 高度相關 (請參照 應用程式安全模型),內容程序會在一個稱為 "out of process" (OOP) 的容器裡啟動,這個 OOP 即是 plugin-container 程序,並且和桌面 Firefox 所用的 plugin-container 程序有著相似的原始碼。

+

風險

+ +

實作

+

在 b2g 程序裡啟動

+

順序如下:

+
    +
  1. fork()
  2. +
  3. setuid(new, different, unused user id|nobody) (無特權的使用者)
  4. +
  5. chrdir('/')
  6. +
  7. execve('plugin-container')
  8. +
+

這邊的啟動順序確保 OOP 程序運行在隔離的記憶體空間,同時只是低權限使用者,無法提高到 b2g 的高權限。

+

File descriptor (檔案描述子) 管理

+

File descriptors 的管理方法是白名單;一份受允許的 file descriptors (FDs) 清單儲存在 mFileMap 物件,在呼叫 fork() 後 (FDs 複製前) 和呼叫 execve()前 (新 web app 開始運行),LaunchApp() 函數會強制關閉不在白名單上的 FD。

+

不同於傳統的黑名單作法 (close-on-exec flag: CLOEXEC),這種做法確保不會有多餘的開啟 FD,比較可靠。

+

Content process sandboxing (沙箱,低權限內容程序)

+

風險

+ +

下表為 sandbox 開啟下可能的威脅列表,附帶前述的可能風險。

+
+

範疇: 當攻擊者以內容程序執行意外執行碼時,會出現下面的威脅,也就是說,攻擊者發現了 Gecko 的安全漏洞。

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
威脅潛在衝擊可能性因子建議對應作法
+

惡意內容程序利用核心安全漏洞

+

"2 steps attack".

+
嚴重:整個裝置都將受到控制: 內容程序只有有限的方法呼叫系統。 +
    +
  • 減少允許的系統呼叫數量到最低需要量。
  • +
  • 用預防性修正檔保護核心,例如 PaX (Protection Against eXecution).
  • +
+
+

提升到父程序權限

+

惡意內容程序利用和父程序之間的 IPDL 安全漏洞

+

"2 steps attack".

+
: 許多敏感的系統呼叫都可以被執行 (資料損失、相機存取、網路存取等等): 父程序大量的程式碼代表大範圍的可能攻擊點。少量的 IPDL 資料消毒,例如傳送指標。 +
    +
  • 以非 root / 非特權使用者執行父程序
  • +
  • 盡可能以 sandbox 方法執行父程序
  • +
+
+

惡意內容程序利用父程序攻擊核心安全漏洞

+

"3 steps attack".

+
嚴重:整個裝置都將受到控制 +

: 需要父程序有可以透過 IPDL 攻擊的 bug。

+

需要核心和父程序之間的系統呼叫可利用的漏洞 (相較內容程序,父程序有更多可行的系統呼叫)

+
+
    +
  • 以非 root / 非特權使用者執行父程序
  • +
  • 盡可能以 sandbox 方法執行父程序
  • +
  • 用預防性修正檔保護核心,例如 PaX (Protection Against eXecution)
  • +
+
+

惡意內容程序、父程序、web app 利用硬體裝置的 bug

+

"1 and 2 steps attack".

+
+

: 可以執行特別權限的作業 (如撥號、傳 SMS 簡訊等)

+

嚴重:整個裝置都將受到控制或執行硬體程式碼。

+
: 需要硬體 bug 以及 IPDL 或系統呼叫授予的硬體溝通管道 +
    +
  • 對硬體裝置實施模糊測試 (Fuzz testing)
  • +
  • 利用核心或父程序 API 修正檔避開問題 (關閉不安全的硬體功能、消毒資料等等)
  • +
+
+
+

Note:

+

* PaX (Protection Against eXecution) 是一個由 GrSecurity (docs) 所發佈的核心修正檔,實作了 PaX 以及額外的保護措施,如 UDEREF 和 SMAP。

+

* 未列出的安全性漏洞代表已被 snadbox 解決掉了。

+
+

實作內容

+

Process Model Sandbox

+
+

Note: 內容程序 (Content Processes) 就是運行中的 web app,也會被限制在 sandbox 環境。

+
+

Gecko APIs 實作

+

內容程序可見的 APIs 絕不應該直接存取檔案系統,取而代的是應該透過 IPDL,所以說會需要存取資源的 API 都需要在父程序中有一個對應的元件代表 API 存取資源。

+

實作相關部分時要特別小心,所有送到父程序的輸入都應該要先消毒,不可以相信內容程序以及來自內容程序的 IPDL 訊息。

+
+

Warning: 任何內容程序取得的受信任授權都可以被用來繞過 sandbox 所加諸的限制。

+
+

何謂 seccomp

+

Seccomp 代表 secure computing mode (安全電腦模式),目前有兩種版本:

+
    +
  1. +

    seccomp, 可見於 Linux kernel 2.6.12 以上版本:

    +
      +
    • +

      開啟 seccomp 會將程序的系統呼叫 (System call) 限制在 read, write, sigreturn, 和 exit

      +
    • +
    • +

      使用 prctl() system call

      +
    • +
    • +

      可以在指定地方、程序初始化後啟動

      +
    • +
    +
  2. +
  3. +

    seccomp-bpf, 又稱為 seccomp mode filter 或 mode 2, 可見於 Linux kernel 3.5 以上版本:

    +
      +
    • +

      如同 seccomp,但多了 BPF 過濾系統呼叫

      +
    • +
    • +

      可以使用系統呼叫白名單和啟動時傳入參數,而非單單預先寫死的作法

      +
    • +
    • +

      更有彈性,可以有"較多自由的 sandbox",對限制性較低的 sandbox 來說很有用,而且也可以移轉到限制性較高的 sandbox

      +
    • +
    • +

      多了一個安全性旗幟避免程序和子程序推翻既有權限限制

      +
    • +
    +
  4. +
+
+

Note: 基於 seccomp-bpf 更有彈性,所以我們決定採用,並且替版本低於3.5 的 kernel (涵蓋了目前大部分的 Android kernel)提供向下相容移植。目前已經有不會造成衝突、可供使用的移植包 (請見 bug 790923).

+
+

Seccomp-bpf 效能

+

seccomp-bpf 會對每一次系統呼叫造成效能負擔,目前沒有一定的效能標竿準則,但我們預估大約最高 1% 的系統呼叫負擔會產生。

+

由於我們的程序模型減少許多系統呼叫,所以實際上我們預估效能負擔將會趨近於無。

+

不過因實作細節而異, IPDL 呼叫卻可能造成效能負擔以及增加延遲,建議對於資源需求密集的 API,如 OpenGL 呼叫,可以看一下 Chromium的實作細節。和 seccomp-bpf 一樣,我們能夠最少化 IPDL 呼叫次數來最小化效能負擔。

+

實作內容

+

seccomp 在 Gecko 以 --enable-content-sandbox 開啟。.

+

預設上系統呼叫拒絕資訊不會被回報,我們可以透過 --enable-content-sandbox-reporter 打開回報機制。

+

程式碼放在 gecko/security/sandbox,白名單放在 gecko/security/sandbox/seccomp_filter.h

+

檔案系統安全強化

+

風險

+ +

實作內容

+

原則上只有使用者內容區域可以讀寫 (除非 OS 未來要求新的讀寫區域),而且一定要包含 nodevnosuidnoexec 選項。標準檔案系統掛載點限制如下:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
掛載點檔案系統選項
/rootfsread-only
/devtmpfsread-write, nosuid, noexec, mode=0755
/dev/ptsptsfsread-write, nosuid, noexec, mode=0600
/procprocread-write, nosuid, nodev, noexec
/syssysfsread-write, nosuid, nodev, noexec
/cacheyaffs2 or ext4read-write, nosuid, nodev, noexec
/efsyaffs2 or ext4read-write, nosuid, nodev, noexec
/systemext4read-only, nodev
/dataext4read-write, nosuid, nodev, noexec
/mnt/sdcardext4 or vfatread-write, nosuid, nodev, noexec, uid=1000, fmask=0702, dmask=0702
/acctcgroupread-write, nosuid, nodev, noexec
/dev/cpuctlcgroupread-write, nosuid, nodev, noexec
+
+

Note: 實際的掛載點可能有所變更

+
+

Linux DAC

+

Linux DAC represents 是一個有名的 Linux 檔案系統權限模型。

+
+

Note: 這是傳統的 user/group/others 權限模型,而非 Linux POSIX 1.e ACLs.

+
+ +

安全系統更新

+

風險

+ +

實作內容

+

Firefox OS 的更新機制使用安全的 Mozilla 程序,更新檔是由受信任,通常是 OEM 廠商,組建、測試、簽署數位簽章。

+

FOTA (Firmware over the air) 更新

+

系統更新可能涵蓋全部或部分 Firefox OS,如果更新涵蓋到 Gonk,那麼 FOTA (Firmware Over the Air) 安裝程序會被採用。FOTA 也可涵蓋到 OS 其他部分,例如裝置管理 (FOTA, firmware / drivers)、設定管理 (Firefox OS settings)、安全更新、Gaia、Gecko 等等。

+

MSU/MAR 更新

+

不牽涉到 Gonk 的更新可以透過 Mozilla 系統更新工具。Firefox OS 使用和桌面 FIrefox 一樣的更新架構、程序 Mozilla ARchive (MAR) 格式 (用於更新包)。

+

更新服務

+
+

Note: 更新服務能由 OEM 廠商提供。

+
+

手機內建的更新系統會定期檢查更新,一但發現新更新,會提示使用者安裝更新,另外安裝前也會檢查手機儲存空間以及驗證發行者身分:

+ +

下列安全性作法會用在更新程序:

+ +

縝密的更新檢查確保正常地安裝更新。

+
+

Note: 更多有關更新資訊,請見 Creating and applying Firefox OS update packages.

+
+

 

diff --git a/files/zh-tw/archive/b2g_os/simulator/index.html b/files/zh-tw/archive/b2g_os/simulator/index.html new file mode 100644 index 0000000000..3b5677a518 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/simulator/index.html @@ -0,0 +1,90 @@ +--- +title: Firefox OS 模擬器 +slug: Archive/B2G_OS/Simulator +translation_of: Archive/B2G_OS/Simulator +--- +
+

本文將針對 Firefox OS 1.2 或更高版本,說明 Firefox OS 模擬器 (Firefox OS Simulator) 相關使用方式。如果開發者目前正開發 Firefox OS 1.1 的 App,則請參閱 Firefox OS 1.1 Simulator 的相關文章。

+
+ +

Firefox OS 模擬器可於桌機中模擬 Firefox OS 裝置。開發者不用真的弄到實際設備就能夠測試 App 並進行除錯。模擬器會在視窗中以 Firefox OS 裝置的實際尺寸執行,亦包含 Firefox OS 使用者介面與已內建的 App,進而模擬多樣的 Firefox OS 裝置 API。

+ +

Firefox OS 模擬器是以 Firefox 附加元件的格式發佈,可下載並安裝於 Firefox 瀏覽器之上,接著可透過應用程式管理員 (App Manager) 來執行模擬器、將 App 送入模擬器、搭配其他開發者工具。

+ +

安裝

+ +

直接點擊下方按鈕即可安裝模擬器。現有多個版本可供安裝。我們也建議開發者能安裝所有版本,以達最佳開發靈活度。

+ +

安裝 Firefox OS Simulator

+ +

另請參閱《應用程式管理員》中的說明來啟動模擬器。一旦模擬器開始執行,開發者即可將 App 送入應用程式管理員進行除錯;就如同使用實際裝置一樣。

+ +
+

注意:模擬器 (1.2 與 1.3 版) 目前正回報 1 組錯誤的 Gecko user agent 字串:請參閱 {{ Bug("964598") }} 進一步了解。

+
+ +

模擬器的使用者介面 (UI)

+ +

模擬器將另外顯示獨立的視窗,且模擬畫面則為 320x480 像素。若要模擬觸控事件,則可按下滑鼠按鈕不放並拖曳。只要在主畫面上按下滑鼠不放並從右向左拖曳,即可看到已內建的 App,還有開發者剛送入的 App:

+ +

+ +

在模擬器視窗底部的工具列共有 2 個按鈕:

+ + + +

模擬器的限制

+ +

請注意,Firefox OS 模擬器仍無法提供完美的模擬作業。

+ +

硬體限制

+ +

模擬器除了螢幕尺寸的限制之外,也無法模擬 Firefox OS 裝置的硬體 (例如 CPU 速度或可用的記憶體容量)。

+ +

音訊/視訊編碼

+ +

下列編碼 (Codecs) 因硬體加速解碼而有所不同,因此尚未支援:

+ + + +

也就是說,若 App 或網站 (如 Youtube) 使用這些編碼,則模擬器將無法測試其中的視訊回播功能。

+ +

未支援的 API

+ +

一般來說,因為桌上型電腦無法使用支援硬體,所以可於裝置上運作的特定 API,可能無法用於模擬器之上。我們另外針對某些 API (例如 Geolocation 地理位置定位) 建構了模擬功能,未來版本亦將新增更多模擬 API。但目前仍尚未支援下列 API。如果使用了這些 API,也只會得到錯誤的報告或結果:

+ + + +

獲得協助

+ +

如果有任何問題,請透過 dev-developer-tools 郵件群組或到 #devtools on irc.mozilla.org 上發問。

+ +

啟動詳細資訊 (verbose) 記錄的方法

+ +

開發者可到網頁主控台 (Web Console) 觀看 App 的記錄訊息,並透過應用程式管理員將記錄附加到 App 上。如果想知道 App 啟動時的早期訊息,甚至早於主控台連線並開始作業的訊息,則開發者可啟動模擬器中的詳細資訊記錄功能。

+ +

可透過 about:config 並建立新的 preference 設定。依照模擬器的版本,preference 的名稱也有所差異:

+ + + +

針對「附加元件管理員 (Add-on Manager)」中的附加元件,可將字串值設為「all」、停用,再啟用。目前有關模擬器作業的額外訊息,均將出現於瀏覽器主控台 (Browser Console) 中。

diff --git a/files/zh-tw/archive/b2g_os/simulator/simulator_walkthrough/index.html b/files/zh-tw/archive/b2g_os/simulator/simulator_walkthrough/index.html new file mode 100644 index 0000000000..9e7fba8c07 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/simulator/simulator_walkthrough/index.html @@ -0,0 +1,268 @@ +--- +title: Firefox OS 模擬器簡易攻略 +slug: Archive/B2G_OS/Simulator/Simulator_Walkthrough +translation_of: Archive/B2G_OS/Simulator/Simulator_Walkthrough +--- +

這裡將透過 Firefox OS 模擬器 (Firefox OS Simulator) 對 Web Apps 進行很簡單的除錯 (但要找的 bug 有點多)。

+

整個簡易攻略分成 6 個部分,各自使用不同的診斷/除錯工具,包含 manifest 檢驗功能網頁主控台 (Web Console)JavaScript 除錯器 (JavaScript Debugger)網路監測器 (Network Monitor)樣式編輯器 (Style Editor)收據 (Receipts) 測試

+

這 6 個部分各自獨立。就算你只挑其中幾段來看,應該也能看得懂而不會有銜接上的問題。

+

manifest 檢驗功能

+
+

GitHub 上的 firefoxos-simulator-walkthrough 現有不同版本的 App。如果你想從第一段開始了解 App 的修正程序,可從 App 的 whereami-1 版本著手,逐步完成此攻略。

+

這個 App 只會顯示 1 個「Where am I?」按鈕。只要點擊按鈕,則 App 就會透過 Geolocation API 取得使用者目前的位置,並於地圖上顯示。

+

此處假設你已經安裝了 Firefox OS 模擬器 (Firefox OS Simulator),並開啟了 Dashboard。

+
+

首先我們點選「Add Directory」,將 App 新增至 Dashboard 中,再選擇 manifest 檔案。畫面如下:

+


+
+ 點選「(2 errors and 0 warnings)」就會看到:

+


+ 畫面將清楚顯示錯誤訊息。此時看到「manifest.webapp」就會發現少了 1 組「name」:

+
{
+  "description": "A simple web app",
+  "launch_path": "/index.html",
+  "icons": {
+    "128": "/style/icons/earth.png"
+  }
+}
+


+ 我們把「name」欄位加入 manifest 檔案之後儲存,再點選 Dashboard 中的「Refresh」:

+
{
+  "name": "Where am I?",
+  "description": "A simple web app",
+  "launch_path": "/index.html",
+  "icons": {
+    "128": "/style/icons/earth.png"
+  }
+}
+


+ 此時 Dashboard 應該會告知沒有錯誤,也就能執行 App:

+

+

但這時就算你按下按鈕,模擬器也不會有任何動作。我們會在下一段中使用 WebConsole 診斷此問題。

+

使用網頁主控台 (Web Console)

+
+

如果你要從這裡開始研讀攻略:

+

這一段將透過 Firefox OS 模擬器 (Firefox OS Simulator),對很簡單的 Web App 進行除錯。GitHub 上的 firefoxos-simulator-walkthrough 已有不同版本的 App。如果你想從本段開始了解 App 的修正程序,可從 App 的 whereami-2 版本著手,逐步完成此攻略。

+

這個 App 只會顯示 1 個「Where am I?」按鈕。只要點擊按鈕,則 App 就會透過 Geolocation API 取得使用者目前的位置,並於地圖上顯示。

+

但此版本的 App 不會執行任何作業。本段透過 WebConsole 診斷出問題。

+ 此處假設你已經安裝了 Firefox OS 模擬器 (Firefox OS Simulator)、開啟 Dashboard、點選 Dashboard 中的「Add Directory」而新增了 App,並點選 App 的「manifest.webapp」檔案。
+

這裡必須按下 Dashboard 上的「Connect」按鈕:

+

+

隨即自動開啟模擬器視窗並執行 App。而 Dashboard 分頁另將出現網頁主控台 (WebConsole)。

+

主控台的輸出結果會提示幾項錯誤、警告、訊息。但請注意最後一項:
+
+
+
+ 看來是 App 的程式碼「whereami.js」明顯出了問題。這裡列出程式碼的前幾行:

+
var whereami = document.getElementById('whereami');
+
+whereami.onclick = function() {
+  navigator.geolocation.getCurrentPosition(getMap, error);
+};
+


+ 若與 App 的「index.html」相較,則問題明顯是:

+
<!DOCTYPE html>
+
+<html>
+
+  <head>
+    <meta charset='utf-8'>
+    <script src="http://open.mapquestap.com/sdk/js/v7.0.s/mqa.toolkit.js"></script>
+    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
+
+  </head>
+
+  <body>
+    <button id ="where-am-i">Where am I?</button>
+    <div id="map"></div>
+    <script src="scripts/whereami.js"></script>
+    <link media="all" href="style/style.css" type="text/css" rel="stylesheet">
+  </body>
+
+</html>
+


+ 在 HTML 中的按鈕 ID 是「where-am-i」,而不是我們在前面 JavaScript 中所使用的「whereami」。所以我們修改為:

+
var whereami = document.getElementById('where-am-i');
+
+whereami.onclick = function() {
+  navigator.geolocation.getCurrentPosition(getMap, error);
+};
+

接著啟動 App 時雖然沒有問題,但仍未顯示地圖。這時主控台又出現新的訊息:

+

+

此訊息是由「whereami.js」程式碼所記錄,指出 Geolocation API 回傳了錯誤,卻沒有說明是哪種錯誤。接著我們可用 JavaScript 除錯器 (JavaScript Debugger) 找出錯誤類型。

+

使用 JavaScript 除錯器 (JavaScript Debugger)

+
+

如果你要從這裡開始研讀攻略:

+

這一段將透過 Firefox OS 模擬器 (Firefox OS Simulator),對很簡單的 Web App 進行除錯。GitHub 上的 firefoxos-simulator-walkthrough 已有不同版本的 App。如果你想從本段開始了解 App 的修正程序,可從 App 的 whereami-3 版本著手,逐步完成此攻略。

+

這個 App 只會顯示 1 個「Where am I?」按鈕。只要點擊按鈕,則 App 就會透過 Geolocation API 取得使用者目前的位置,並於地圖上顯示。

+

此版本 App 的 Geolocation API 將回傳錯誤。所以本段將透過 JavaScript 除錯器 (JavaScript Debugger) 找出到底是哪種問題。

+

此處假設你已經安裝了 Firefox OS 模擬器 (Firefox OS Simulator)、開啟 Dashboard、點選 Dashboard 中的「Add Directory」而新增了 App,並點選 App 的「manifest.webapp」檔案。

+
+

在連上 App 的網頁主控台 (WebConsole) 中,點選 Geolocation 錯誤記錄的右側鏈結:

+


+ 按下「whereami.js:8」鏈結之後,JavaScript 除錯器隨即自動載入相關檔案並跳到有問題的行數。

+

根據這篇 Geolocation API 參考所述,這裡將由錯誤處理器 (Error handler) 的 error() 屬性送入 code 物件,而我們再透過 error 物件的 code 屬性獲知此特定錯誤的詳細資訊。所以我們點選左側行數為 8 的那一行,即可於 error() 之內設定中斷點:

+

+

在 App 之內點選「Where am I?」之後,執行作業就會停在中斷點:

+

+

此時只要按下「Add watch expression」的地方並鍵入「error.code」,就會立刻看到其值為「1」:

+


+ 同樣根據 Geolocation API 參考文件所述,「1」即代表「權限已遭否決」。如果 Web Apps 尚未請求 Geolocation 權限,或使用者尚未許可該權限,都會發生這種錯誤。
+
+ 這時來看「manifest.webapp」檔案,就會看到我們尚未要求權限:

+
{
+  "name": "Where am I?",
+  "description": "A simple web app",
+  "launch_path": "/index.html",
+  "icons": {
+    "128": "/style/icons/earth.png"
+  }
+}
+


+ 接著修復如下:

+
{
+  "name": "Where am I?",
+  "description": "A simple web app",
+  "launch_path": "/index.html",
+  "icons": {
+    "128": "/style/icons/earth.png"
+  },
+  "permissions": {
+    "geolocation": {
+      "description": "Needed to tell the user where they are"
+      }
+  }
+}
+


+ 儲存「manifest.webapp」之後,再按下 Dashboard 中的「Refresh」。這裡記得要在除錯器停在中斷點時,才能繼續除錯。而當你點選「Where am I?」,App 隨即會要求你分享你的位置。而你允許分享之後仍看不到地圖,接著又在 WebConsole 中找到新的訊息:

+

+

此訊息指出 MapQuest API (在 App 中以 script 標籤所指定) 並未正確載入。接著可使用網路監測器 (Network Monitor) 找出問題。

+

使用網路監測器 (Network Monitor)

+
+

如果你要從這裡開始研讀攻略:

+

這一段將透過 Firefox OS 模擬器 (Firefox OS Simulator),對很簡單的 Web App 進行除錯。GitHub 上的 firefoxos-simulator-walkthrough 已有不同版本的 App。如果你想從本段開始了解 App 的修正程序,可從 App 的 whereami-4 版本著手,逐步完成此攻略。

+

這個 App 只會顯示 1 個「Where am I?」按鈕。只要點擊按鈕,則 App 就會透過 Geolocation API 取得使用者目前的位置,並於地圖上顯示。

+

此版本 App 的網頁主控台 (WebConsole) 將顯示「MQA is not defined」錯誤。所以本段將透過網路監測器 (Network Monitor) 找出未載入 MapQuest API 的原因。

+

此處假設你已經安裝了 Firefox OS 模擬器 (Firefox OS Simulator)、開啟 Dashboard、點選 Dashboard 中的「Add Directory」而新增了 App,並點選 App 的「manifest.webapp」檔案。

+
+
+

警告:需 Firefox 23.0 或更高版本才具備網路監測器功能。

+
+

在連上 App 的開發者工具中,點選「Network」分頁就會看到下列面板。可以看到「open.mapquestap.com」網域針對「mqa.toolkit.js」資源所發出的請求,從未完全成功過:

+

+

成功的請求均標記為綠色。如果我們點選「open.mapquestap.com網域 (深灰色) 的請求之一,點選「Timings」的細節面板,就會看到 DNS 解析 (DNS resolution) 並未成功,因此該請求從未達到「Connecting」的狀態。

+

再看到「index.html」檔案,會發現 script 標籤指向錯誤網域。

+

這裡變更 script 標籤以使用正確的網域:open.mapquestapi.com (於網域名稱內加入缺少的「i」) 之後,即可修復此錯誤。

+
<!DOCTYPE html>
+
+<html>
+
+  <head>
+    <meta charset='utf-8'>
+    <script src="http://open.mapquestapi.com/sdk/js/v7.0.s/mqa.toolkit.js"></script>
+    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
+
+  </head>
+
+  <body>
+    <button id ="where-am-i">Where am I?</button>
+    <div id="map"></div>
+    <script src="scripts/whereami.js"></script>
+    <link media="all" href="style/style.css" type="text/css" rel="stylesheet">
+  </body>
+
+</html>
+

儲存「index.html」並點選 Dashboard 中的「Refresh」。在 App 執行時按下「Where am I?」,系統就會要求你分享你的位置。在你允許分享之後,App 終於顯示地圖:
+

+

使用樣式編輯器 (Style Editor)

+
+

如果你要從這裡開始研讀攻略:

+

這一段將透過 Firefox OS 模擬器 (Firefox OS Simulator) 客製化 App 的樣式表 (Stylesheets)。 GitHub 上的 firefoxos-simulator-walkthrough 已有不同版本的 App。如果你想從本段開始了解 App 的修正程序,可從 App 的 whereami-5 版本著手,逐步完成此攻略。

+

這個 App 只會顯示 1 個「Where am I?」按鈕。只要使用者點擊按鈕,則 App 就會透過 Geolocation API 取得使用者目前的位置,並於地圖上顯示。

+

此版本的 App 已修復前述的所有錯誤。接著我們將透過樣式編輯器 (Style Editor),為執行中的 App 即時變更樣式並儲存之。

+

此處假設你已經安裝了 Firefox OS 模擬器 (Firefox OS Simulator)、開啟 Dashboard、點選 Dashboard 中的「Add Directory」而新增了 App,並點選 App 的「manifest.webapp」檔案。

+
+
+

警告:必須 Firefox 23.0 或更高版本才具備網路監測器 (目前 Firefox Beta 試用版才是 23.0 版)

+
+

在連上 App 的開發者工具中,點選「Style Editor」分頁就會看到下列面板:

+

+

點選左側樣式表清單中的「style/style.css」,並修改 CSS 規則。新的規則會立刻套用至已連線的 App 上:

+

+

現在點選樣式表「style/style.css」正下方的「Save」,即可將之儲存回專案中。

+

使用收據 (Receipts) 測試功能

+
+

如果你要從這裡開始研讀攻略:

+

這一段將透過 Firefox OS 模擬器 (Firefox OS Simulator),為 Web App 新增付款收據驗證碼。GitHub 上的 firefoxos-simulator-walkthrough 已有不同版本的 App。如果你想從本段開始了解 App 的修正程序,可從 App 的 whereami-6 版本著手,逐步完成此攻略。

+

這個 App 只會顯示 1 個「Where am I?」按鈕。只要點擊按鈕,則 App 就會透過 Geolocation API 取得使用者目前的位置,並於地圖上顯示。

+

我們要把此版本 App 變更為付費 Web App。

+

此處假設你已經安裝了 Firefox OS 模擬器 (Firefox OS Simulator)、開啟 Dashboard、點選 Dashboard 中的「Add Directory」而新增了 App,並點選 App 的「manifest.webapp」檔案。

+
+

目前你已經將 App 修改為無錯誤的 App,並已擁有合適的樣式。現在可新增付款收據驗證 (Payment Receipt Validation) 功能,確保使用者必須購買此 App。

+

Mozilla 另已提供小型的 JavaScript 函式庫,可協助 Apps 檢查自己的收據:http://github.com/mozilla/receiptverifier

+

為 App 新增 receiptverifier (把新的 script 標籤加入「index.html」檔案中):

+
<!DOCTYPE html>
+
+<html>
+
+  <head>
+    <meta charset='utf-8'>
+    <script src="https://raw.github.com/mozilla/receiptverifier/master/receiptverifier.js"></script>
+    <script src="http://open.mapquestapi.com/sdk/js/v7.0.s/mqa.toolkit.js"></script>
+    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
+
+  </head>
+
+  <body>
+    <button id ="where-am-i">Where am I?</button>
+    <div id="map"></div>
+    <script src="scripts/whereami.js"></script>
+    <link media="all" href="style/style.css" type="text/css" rel="stylesheet">
+  </body>
+
+</html>
+

接著再以「mozmarket.receipts.Verifier」API 檢查「scripts/whereami.js」中的收據 (將於按下按鈕,或於載入 App 時檢查收據):

+
...
+
+var verifier = new mozmarket.receipts.Verifier({
+  installs_allowed_from: '*',
+  typsAllowed: 'test-receipt',
+  logLevel: mozmarket.receipts.Verifier.levels.DEBUG,
+  onlog: mozmarket.receipts.Verifier.consoleLogger
+});
+verifier.clearCache();
+
+function verifyPaymentReceipts(cb) {
+  verifier.verify(function (verifier) {
+    if (verifier.state instanceof verifier.states.OK) {
+      cb(null); // valid payment
+    } else {
+      cb("invalid-payment"); // invalid payment
+    }
+  });
+  setTimeout(function checkNoReceipts() {
+    if (verifier.state instanceof verifier.states.NoReceipts) {
+      cb("no-receipts");
+    }
+  }, 2000);
+}
+
+whereami.onclick = function() {
+  verifyPaymentReceipts(function (err) {
+    if (err) {
+      alert("Invalid Payment Receipt.");
+    } else {
+      navigator.geolocation.getCurrentPosition(getMap, error);
+    }
+  });
+};
+
+

正常情況需透過 Marketplace 與 Payment 服務,以加密方式簽署收據。但目前可先用模擬器 App 項目中的「Receipts」選單,點選所要安裝的收據類型 (預設為「None」),即可為 App 安裝測試收據。

+

+

現在即可測試 App 具備「Valid」、「Invalid」、「Refunded」收據,或無收據時的行為。另可於網頁主控台觀看「receiptverifier」函式庫所產生的記錄,藉以了解相關結果:

+

+

+
+

注意:whereami-7 版本即為最終完成的 App。

+
+

 

diff --git a/files/zh-tw/archive/b2g_os/using_the_app_manager/index.html b/files/zh-tw/archive/b2g_os/using_the_app_manager/index.html new file mode 100644 index 0000000000..8486eeb959 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/using_the_app_manager/index.html @@ -0,0 +1,259 @@ +--- +title: 應用程式管理員 (App Manager) +slug: Archive/B2G_OS/Using_the_App_Manager +translation_of: Archive/B2G_OS/Using_the_App_Manager +--- +
+

「應用程式管理員 (App Manager)」為 Firefox 桌面版的新工具,具備多樣的有效工具,可透過開發者的瀏覽器,直接於 Firefox OS 手機與 Firefox OS 模擬器 (Firefox OS Simulator) 中進行 HTML5 Web App 的測試、佈署、除錯等作業。

+ +

應用程式管理員適用於 Firefox OS 1.2 或更高版本。如果你正為 Firefox OS 1.1 開發 App,則請參閱《Firefox OS 1.1 Simulator》一文。

+
+ +

{{EmbedYouTube("z1Bxg1UJVf0")}}

+ +

應用程式管理員具備下列元件:

+ + + +

快速設定:

+ +

本段將協助開發者儘快設定並執行應用程式管理員。如果你需要進一步詳細資訊,則請略過本段文章而直接觀看下一段《裝置與系統設定》。若發生任何問題,亦可參閱本文最後一段《疑難排解》。

+ +
    +
  1. 確認已安裝桌面版 Firefox 26 或更高版本
  2. +
  3. 開啟應用程式管理員 (可於網址列中鍵入 about:app-manager)
  4. +
  5. 若你手上並沒有實際的 Firefox OS 裝置: +
      +
    1. 先安裝 Firefox OS 模擬器 (Firefox OS Simulator)
    2. +
    3. 在應用程式管理員底部的工具列中,點選 Start Simulator 再點選已安裝的模擬器名稱 (已安裝的模擬器均應出現)。
    4. +
    +
  6. +
  7. 若你擁有 Firefox OS 實體裝置: +
      +
    1. 確認目前為 Firefox OS 1.2 或更高版本
    2. +
    3. 確認已在視窗系統中安裝該款手機的驅動程式
    4. +
    5. 進入裝置的「Settings」,停用「Screen Lock (Settings > Screen Lock)」並啟用「Remote Debugging (Settings > Device information > More information > Developer)」
    6. +
    7. 另為 Firefox 桌面版安裝 ADB Helper 附加元件
    8. +
    9. 使用 USB 纜線銜接裝置與電腦
    10. +
    11. 接著應可於應用程式管理員的底部看到裝置名稱,點選該裝置
    12. +
    +
  8. +
  9. 底部應顯示「Connected to: xxx」
  10. +
  11. 點選 Apps panel 並新增 App;封裝式 (Packaged) 或托管式 (Hosted) App 均可
  12. +
  13. Refresh 按鈕將驗證該 App 並安裝於裝置/模擬器中
  14. +
  15. Debug 按鈕則銜接開發者工具與執行中的 App
  16. +
  17. 若遇上任何錯誤,可參閱〈疑難排解〉章節
  18. +
+ +

裝置與系統設定

+ +

使用應用程式管理員前的第一件事,就是必須正確設定現有的系統與手機。本段將逐步說明各個步驟。

+ +

需要 Firefox 1.2 或更高版本

+ +

確認裝置目前為 Firefox OS 1.2/Boot2Gecko 1.2 或更高版本。若要檢查目前 Firefox OS 版本,可點選 Settings > Device Information > Software

+ +

如果尚未安裝必要的 Firefox OS 版本,則根據手機型號的不同,你可能必須安裝 Firefox 1.2 或更高的 nightly 版本,或自行透過原始碼進行設定與建置 (Build)。

+ +

目前可用的建置:

+ + + +

若要建構自己的 Firefox OS 1.2 或更高版本,請參閱 Building and installing Firefox OS 說明,並從 Firefox OS build prerequisites 著手開始。

+ +

遠端除錯 (Remote debugging)

+ +

接著必須啟動 Firefox OS 中的遠端除錯 (Remote debugging) 功能。點選Settings > Device information > More information > Developer,最後勾選 Remote Debugging 方塊即可。

+ +

ADB 或 ADB helper

+ +

透過 Android Debug Bridge (ADB) 處理裝置與電腦之間的連線作業。現有 2 種 ADB 執行方式:

+ + + +
+

注意:只要安裝 ADB Helper 附加元件,就不需執行此指令。

+
+ +

將裝置連上應用程式管理員

+ +

完成所有設定之後,就可將裝置連上電腦並啟動應用程式管理員:

+ +
    +
  1. 以 USB 纜線銜接裝置與電腦。
  2. +
  3. 進入 Settings > Screen Lock 並取消勾選 Lock Screen,以停用裝置的螢幕鎖定功能。一旦螢幕鎖定之後,手機與電腦的連線將隨之中斷,也就無法進行除錯作業。因此最好先停用此功能。
  4. +
  5. 啟動應用程式管理員 — 到 Firefox 桌面版中點選「工具 (Tools)」>「網頁開發者 (Web Developer)」>「應用程式管理員 (App Manager)」選單;或於網址列中鍵入 about:app-manager
  6. +
  7. 應用程式管理員分頁的底部可看到連線狀態顯示列 (如下圖所示)。只要點選「Connect to localhost:6000」按鈕即可連線裝置。
  8. +
  9. 若連線成功,裝置畫面隨即出現「An incoming request to permit remote debugging connection was detected. Allow connection?」對話框。按下「OK」鈕 (你可能必須按下手機的電源鍵,才會看到該對話框)。接著應會更新連線狀態列並顯示「Connected to B2G」。此時也將出現「Disconnect」按鈕,以利隨時中斷連線。
  10. +
+ +

+ +
+

另請注意,位於連線狀態列中的其他控制鈕,可讓你銜接模擬器與應用程式管理員 (將於下一段中說明),並更改連線所使用的通訊埠。若要更改通訊埠,則必須啟動該通訊埠的「轉發通訊埠 (Port forwarding)」功能。可參閱上述的啟動轉發通訊埠

+
+ +

使用 Firefox OS Simulator 附加元件

+ +

如果你手上還沒有實際的 Firefox OS 裝置可搭配 App Manager,也能透過 Firefox OS 模擬器 (Firefox OS Simulator) 附加元件體驗應用程式管理員。請先為自己的作業系統安裝合適的模擬器:

+ +

安裝 Firefox OS 模擬器

+ +
+

注意:目前僅有 Firefox OS 1.2 模擬器。未來將提供更多版本選擇。

+
+ +

安裝模擬器之後,請透過 about:app-manager 找到應用程式管理員分頁底部的連線狀態列,點選「Start simulator」按鈕。接著將出現至少 3 組按鈕:

+ + + +
+

注意:模擬器 (1.2 與 1.3 版) 目前回報 1 組錯誤的 Gecko user agent 字串:可參閱 {{ Bug("964598") }} 進一步了解。

+
+ +

「Apps」面板

+ +

所有要件設定完畢之後,就從「Apps」面板開始了解應用程式管理員的功能吧。先透過 Apps 面板將現有 App 送入裝置中並進行除錯:

+ + + +

視窗右側隨即顯示 App 的相關資訊,如下圖所示:

+ +

+ +

Manifest 檔案編輯器 (Manifest Editor)

+ +

從 Firefox 28 開始,「Apps」面板即包含編輯器功能,可用於 App 的 manifest 檔案:

+ +

+ +

除錯

+ +

此時點選「Update」就會更新 (或安裝) 裝置上的 App。點選「Debug」則會連上工具箱,以利直接對程式碼進行除錯:

+ +

+ +
+

注意:你可能會玩工具箱玩到上癮 — 快試著修改 DOM、CSS 等。接著就能看到裝置即時反應出更新的效果。相關更新均將儲存於已安裝的 App 程式碼中,下次再開啟裝置中的 App 就能一目了然。

+
+ +

若是 Firefox 28 之前的版本,這些工具將顯示於另一個獨立視窗中。從 Firefox 28 開始,這些工具均顯示於應用程式管理員之內的獨立分頁中;就接在「Apps」與「Device」分頁之下。此分頁將顯示目前 App 的圖示,因此極容易辨識:

+ +

+ +

錯誤

+ +

如果新增 App 失敗 (可能是 URL 錯誤,或選到了封裝式 App 的資料夾),則該頁仍會顯示所新增的 App 項目,也會包含錯誤資訊。

+ +

+ +

另外只要將滑鼠游標移至視窗左邊的 App 名稱/說明之上,在「X」按鈕出現時按下,即可在此畫面中刪除該 App。請注意此動作並不會刪除裝置中的 App。必須從裝置上手動移除 App,才會真正刪除裝置中的 App。

+ +

「Device」面板

+ +

「Device」面板將顯示已連線裝置的相關資訊。另可透過「Installed Apps」視窗中開啟裝置上的 App 並進行除錯。

+ +

+ +
+

注意:依預設值,此處並不會顯示 Certified App。可參閱 Certified App 的除錯方式

+
+ +

「Permissions」視窗將針對目前裝置上的不同 Web API,顯示必要的權限。

+ +

+ +

最後可按下「Screenshot」按鈕,即可對目前裝置的顯示項目拍下截圖。此截圖將以 Firefox 的新分頁開啟,讓你決定是否要儲存該圖。

+ +

Certified App 的除錯

+ +

目前僅限搭載 Firefox OS 1.2 開發版本的裝置,才能進行 Certified Apps 的除錯。若你手上的裝置正執行開發版本,則可將設定檔中的「 devtools.debugger.forbid-certified-apps」變更為「false」,即可開始 Certified App 的除錯。可參閱下列步驟:

+ +
    +
  1. +

    在電腦的終端/主控台上輸入下列指令,以進入裝置的 filesystem:

    + +
    adb shell
    + +

    接著命令列提示將轉為 root@android

    +
  2. +
  3. +

    接著以下列指令暫停執行 B2G:

    + +
    stop b2g
    +
  4. +
  5. +

    進入以下目錄:

    + +
    cd /data/b2g/mozilla/*.default/
    +
  6. +
  7. +

    以下列指令更改 prefs.js 檔案:

    + +
    echo 'user_pref("devtools.debugger.forbid-certified-apps", false);' >> prefs.js
    +
  8. +
  9. +

    在完成編輯並儲存檔案之後,再以下列指令重新啟動 B2G:

    + +
    start b2g
    +
  10. +
  11. +

    輸入 exit 指令以退出 Android 的 filesystem 之後,就會回到正常的終端畫面。

    +
  12. +
  13. +

    最後再次連回應用程式管理員,就能看到 Certified App 出現,即可進行除錯。

    +
  14. +
+ +
+

注意:如果你想把這個偏好設定加入自己的 Gaia 版本,則可執行 DEVICE_DEBUG=1 reset-gaia

+
+ +

在應用程式管理員中執行自訂的版本

+ +

只要透過 Firefox OS 模擬器,即可於應用程式管理員中執行自訂的 B2G Desktop 與 Gaia 版本。可參閱《Running custom Firefox OS/Gaia builds in the App Manager》進一步了解。

+ +

疑難排解

+ +

如果系統無法辨認裝置:

+ + + +

還是無法讓自己的裝置連上應用程式管理員或啟動模擬器嗎?快讓我們知道到 bugzilla 回報錯誤

diff --git a/files/zh-tw/archive/b2g_os/using_the_b2g_desktop_client/index.html b/files/zh-tw/archive/b2g_os/using_the_b2g_desktop_client/index.html new file mode 100644 index 0000000000..46fc57a972 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/using_the_b2g_desktop_client/index.html @@ -0,0 +1,180 @@ +--- +title: 使用 Firefox OS 的電腦桌面 client 程式 +slug: Archive/B2G_OS/Using_the_B2G_desktop_client +translation_of: Archive/B2G_OS/Building_the_B2G_OS_simulator +--- +

Firefox OS 的 desktop client,也被稱為 B2G desktop client,讓您可以在一個以 Gecko 為基礎的環境-有點類似實際行動裝置的環境下執行 Gaia 和 web apps。它不會模擬行動裝置的硬體,因此它並不適合拿來測試行動裝置的 API,也不能取代在實際硬體上的測試。然而,它的確擁有一些 Firefox 上所沒有 APIs,像是聯絡人(Contacts)和設定(Settings)的 Apis。因此,當我們在開發應用程式、或是在操作 Gaia 使用者介面上可以派上用場。

+ +

這篇文章不但涵蓋下載或是建置 Firefox desktop client,也包含了如何使用它。

+ +

下載 nightly 版本

+ +

如同 Firefox Nightlies 一般,Firefox OS 的 desktop client 每天都會用最新的原始碼編譯出一個版本。最新的版本將 可以從 Mozilla FTP 伺服器取得。請確定挑到最新的版本和對的封存給您的作業系統。

+ +

我們現在可以略過下面內容,直接到「執行 desktop client」。

+ +

建置 desktop client

+ +

我們需要做的地一件事情是架起 Mozilla 的標準建置環境。一旦我們有了這個環境,我們可以降低我們所需要的原始碼,並且設定建置 Firefox OS 的 desktop client。

+ +

第一次下載原始碼

+ +

在我們要放置程式碼的目錄(資料夾)中,讓我們將包含所有 Gecko 的 mozilla-central 倉儲 (repository)給複製下來。

+ +
 hg clone http://hg.mozilla.org/mozilla-central
+
+ +

更新程式碼

+ +

當我們之後編譯後來的版本時,我們要確定我們有最新的原始碼。下列就是如何拉到最新的更新的指令:

+ +
cd mozilla-central
+hg pull -u
+
+ +

建立 mozconfig

+ +

接著,我們要在 mozilla-central 目錄下新增一個檔案 mozconfig 來設定建置系統去編譯 Boot to Gecko client 程式而不是 Firefox:

+ +
mk_add_options MOZ_OBJDIR=../build
+mk_add_options MOZ_MAKE_FLAGS="-j9 -s"
+
+ac_add_options --enable-application=b2g
+ac_add_options --disable-libjpeg-turbo
+
+# This option is required if you want to be able to run Gaia's tests
+ac_add_options --enable-tests
+
+# turn on mozTelephony/mozSms interfaces
+# Only turn this line on if you actually have a dev phone
+# you want to forward to. If you get crashes at startup,
+# make sure this line is commented.
+#ac_add_options --enable-b2g-ril
+ +

建置(編譯)

+ +

現在我們已經準備好要在目錄 mozilla-central 裡面、透過下面的指令來編譯 desktop client。

+ +
./mach build
+ +

編譯好的 client 會被放在 ../build/dist 目錄下 (基本上是依照 mozconfig 檔案裡面的 MOZ_OBJDIR 參數所指定的值)。

+ +

執行 desktop client

+ +

預設 desktop client 會顯示空的畫面,因為它並不知道一開始要載入哪個 web app 來當做系統 app。系統 apps 和 Firefox OS 中預設會有的 apps 就被稱為 Gaia。

+ +

下載 Gaia

+ +

第一次下載 Gaia、讓我們從 GitHub 上複製原始碼的倉儲 (repository):

+ +
 git clone https://github.com/mozilla-b2g/gaia
+ +

為了更新成 Gaia 的一個已存在的版本,我們可以從 GitHub 拉最新的更新:

+ +
cd gaia
+git pull
+
+ +

產生 profile

+ +

接著我們需要設定 desktop client 中 Gaia 的 apps。這包括包裝行動裝置上也有的 Gaia apps,以及設定系統 apps 的權限。我們透過產生一個 profile 來做這些事情。接著的指令會做這些事情:新的 profile 包含一個客製的擴充以及其他 B2G 正常運作所需的設定。所以在 gaia 目錄裡執行下面的指令:

+ +
cd gaia
+make
+
+ +

這應該會在 gaia 目錄下面建立一個 profile 目錄。

+ +

在 Linux 上執行

+ +

只要在啟動 b2g 執行檔的時候加上 profile 參數,就可以使用我們剛剛產生的 profile 來啟動 desktop client 。如果是自己編譯的話,執行檔的位置會在早先下載下來的 tarball 裡面,如果是自己編譯的話,就會在 ../build/dist/bin 的目錄裡。

+ +
.../b2g -profile gaia/profile
+
+ +

您可能會碰到惱人的 rendering 問題。只要在 gaia/profile/prefs.js 裡面加上下面這行就可以避開這個問題:

+ +
user_pref("layers.acceleration.disabled", true);
+
+ +

在 Mac 上執行

+ +

在 Mac 上,b2g 執行檔的位置和需要指定 profile 的絕對路徑,因此指令比較複雜:

+ +
.../B2G.app/Contents/MacOS/b2g -profile /full/path/to/gaia/profile
+
+ +

指令的選項(或參數)

+ +

在使用 desktop client 時,你可以使用一些指令的參數來調校執行時的體驗。您可以用 -help 這個參數來列出參數的列表。這一節涵蓋一些特別的參數。

+ +

明確指定螢幕大小

+ +

您可以用 --screen 來指定您想要模擬的行動裝置的螢幕大小:

+ +
b2g --screen=<width>x<height>[@<dpi>]
+ +

<width>, <height>, and <dpi> 都是相當不用解釋的參數:行動裝置以 pixels 為單位的長和寬以及 DPI 解析度。舉例來說:

+ +
b2g --screen=320x480
+b2g --screen=320x480@160
+
+ +

或者,您可以使用某些行動裝置的名字來模擬他們的螢幕大小和解析度:

+ + + +

開啟 JavaScript console

+ +

在您開啟 B2G 的 desktop client 時,您可以藉由加上 -jsconsole 這個記號來開啟
+ JavaSCript console。在編譯之後,只要:

+ +
.../b2g -jsconsole -profile /path/to/your/profile
+ +

如果您已經在 Mac 上安裝了 nightly 版本的話,您可以照著下面的指令:

+ +
/Applications/B2G.app/Contents/MacOS/b2g -jsconsole -profile /path/to/your/profile
+ +

在 B2G 啟動時,指定開啟一個應用程式

+ +

您現在可以指定一個應用程式在 b2g desktop client 開始運作時,自動執行起來。這會在其他系統程式被掛載起來之後,馬上讓指定的應用程式被執行起來。只要加上 --runapp 這個參數、後面在加上要執行應用程式的名字,就可以做到了。如下:

+ +
 .../b2g -profile /path/to/your/gaia/profile --runapp email
+ +

在尋找要執行的 app 之前,指定的名字要被正規化為全部小寫、且不能帶有 - 和空白的符號。接著這個正規化過的名字會被拿來和 app 的 manifest 的名字做比較。

+ +

舉例來說,現在 email app 的名字是「E-mail」,但是因為正規化的效果, --runapp email 這個參數是 ok可以執行的。

+ +

如果您加了 --runapp 參數但是卻沒有帶後面的 app 名字、或是帶了空的名字的話,b2g client 會列出一串列表,其中包括已知的應用程式和簡短的使用訊息。

+ +
+

Note:--runapp 參數會有關閉螢幕鎖的副作用,且不會再度啟用螢幕鎖。這是假設您不會用這個指令加上 profile 來測試螢幕鎖,否則您會重新打開這個選項。如果這個行為會造成問題的話,也歡迎提供 patch 來改變這個它。

+
+ +

Usage tips

+ +

這一節提供一些在使用 B2G desktop client 時,有幫助的技巧。

+ + + +

Next steps

+ +

現在您有一個執行 Boot to Gecko 的 desktop 版本了,您可以在上面測試、開發以及做其他事情:

+ + diff --git a/files/zh-tw/archive/b2g_os/using_the_b2g_emulators/index.html b/files/zh-tw/archive/b2g_os/using_the_b2g_emulators/index.html new file mode 100644 index 0000000000..6dccacbe06 --- /dev/null +++ b/files/zh-tw/archive/b2g_os/using_the_b2g_emulators/index.html @@ -0,0 +1,69 @@ +--- +title: 使用 B2G 模擬器 +slug: Archive/B2G_OS/Using_the_B2G_emulators +translation_of: Archive/B2G_OS/Using_the_B2G_emulators +--- +

這篇文章提供簡潔的指南,包括使用 Boot to Gecko 模擬器時需要知道的一些重要的事情。這不意味著這是一個完整的使用手冊;相反地,它只告訴您一些有用的事情,讓您不必自己去學。

+

這篇指南假設您已經編譯了一個模擬器;如果您還沒編譯的話,請跳回「建置和安裝 Boot to Gecko」!

+

關於 B2G 模擬器

+

有兩種 B2G 模擬器。第一種是 x86 行動裝置的模擬器,使用 "emulator-x86" 設定以 config.sh 編譯而成。雖然這遠比模擬 ARM 處理器快多了,但是它執行的沒有那麼接近一個實體行動裝置的結果。而第二種則是 ARM 行動裝置的模擬器,使用 "emulator" 的設定編譯。

+

一旦你選擇、設定及編譯模擬器,就使用者而言,剩下來要做的事情都是一樣的,所以這篇導覽剩下的共同部分是兩種模擬器都適用的。

+
+ Note: 在 Mac OS X 上,B2G 模擬器需要 Core 2 Duo 或更快 CPU;也就是說,一個相容於 Mac OS X 10.7 "Lion" 的系統。你不必一定得使用 Lion,只是要在和 Lion 相容的系統上面執行就可以了。
+

啟動模擬器

+

執行下列指令,就可以打開 B2G 模擬器了:

+
./run-emulator.sh
+
+

這個指令將會會您操作所有模擬器的起始作業。現在就耐心等模擬器啟動以及 Boot to Gecko 在上面開始運作起來。啟動會花好幾分鐘,所以請耐心等候。

+

當模擬器掛了

+

有時候模擬器會啟動失敗。歡迎來到尖端科技的前緣。這裡有一些派的上用場的技巧,可用來解決問題。

+

確定 adb server 是不是還活著

+

adb server 處理與模擬的行動裝置之間的互動,而這裡常常出問題的原因是 adb server 不是沒在執行就是故障。

+
+

Note: 舉例來說,如果您使用 B2G 版本所編譯出的 adb 的話,它的位置會在 $B2G/out/host/<platform>/bin 目錄裡。在 Mac 上的話,則是在 $B2G/out/host/darwin-x86/bin 目錄下。

+
+

使用下列指令來看 adb 是否還在運作中:

+
ps aux | grep adb
+
+

If it's there, do this to kill it, because it's probably not working correctly.

+
adb kill-server
+
+

If it's not there, do this:

+
adb start-server
+
+

接著試試看再執行模擬器一次看看。如果還是沒辦法運作的話, 就是時候到 irc.mozilla.org 使用 #b2g 搜尋尋求幫助了。

+

抹掉 configuration 設定值

+

有時候,在模擬的行動裝置上使用過期的設定檔的設定值也會讓它暴走。你可以砍掉 indexedDB 資料庫來解決這個問題,如下:

+
    +
  1. 確定 adb 在執行中,如同 Make sure the adb server is running 中所描述的一般。
  2. +
  3. 啟動模擬器。
  4. +
  5. 先打開電腦裡的 terminal,然後切換到編譯模擬器的主目錄 (root code build directory),接著打:「out/host/<platform>/bin/adb -e shell」;在 Mac 上使用「out/host/darwin-x86/bin/adb -e shell」。
  6. +
  7. 現在你已經在 adb 的 shell 裡面、且可以直接在模擬器的行動 裝置上執行 shell 指令 (commands)了。讓我們使用「stop b2g」來停止裝置上的 B2G。
  8. +
  9. 刪除 indexedDB 資料庫:rm -rf /data/local/indexedDB
  10. +
  11. 在模擬的行動裝置上重新啟動 B2G:start b2g
  12. +
+

希望此時您所打開 Gaia 介面一切都恢復正常。

+

設定模擬器

+

如果您想要調整模擬器更接近您想要模擬的裝置的話,有幾個選項可以改改看。這一節提供一些關於「如何調校」的基本資訊。您可以編輯 run-emulator.sh (觀念上還是複製一份來編輯)這個 script 來調校模擬器的設定。這裡指會討論到一些最常用到的參數;您可以 連到 qemu 網站 來看其他部分的細節。

+
+ Tip: 您可以為每個想要模擬的裝置建立一個 run-emulator.sh 的複製版本;這會您比較容易以不同的設定啟動模擬器。
+

改變外觀

+

模擬器預設會以 HVGA 模式啟動;VGA 的一半、也就是 320x480 pixels 的外觀。在啟動時,我們可以給模擬器加上 -skin 的參數來指定外觀。您可以編輯 run-emulator.sh 來切換成不同的顯示模式來執行模擬器。可以使用的外觀列表如下:

+ +

外觀的存放位置在 B2G/development/tools/emulator/skins 目錄。外觀的格式很簡單;如果您打開來看的話,他們只是一些資料夾,裝著一些使用者介面物件的 PNG 檔案以及一個描述使用者介面的配置及螢幕區域的文字檔 layout。如果需要建立客製化的外觀的話,是還蠻簡單的。

+

改變記憶體的大小

+

另一個您可能想要/需要改變的選項就是行動裝置的記憶體大小。預設是 512MB;然而,如果您要模擬的行動裝置的記憶體比較大或小的話,或許對您而言,將記憶體調整成一樣的大小是很重要的,這樣才能確定您的 app 會在您想要執行的基礎裝置上執行。您可以將 -memory 參數的數值修改成您需要的數字(以 MB 為單位),就可以改變執行時的記憶體大小。除了預設的 512MB 之外,您可能會想要以 256MB 和 1024MB 來做測試。

+

而如果想要改變模擬裝置的儲存容量大小的話 (就是 local 資料的儲存空間,像是行動電話的內建快閃記憶體或是電腦的硬碟),可以改變 -partition-size 參數的數值。預設是 512MB,但是您可以改成任何大小 (以 MB 為單位)來模擬想要測試的行動裝置。

+

網路連線

+

如果因為某些原因,您沒辦法將您的模擬器連上網際網路 (internet)的話,您可以從命令提示字元來執行下面的指令 (commandline):

+
adb shell setprop net.dns1 10.0.2.3
diff --git a/files/zh-tw/archive/b2g_os/web_telephony_api/index.html b/files/zh-tw/archive/b2g_os/web_telephony_api/index.html new file mode 100644 index 0000000000..c9e0c9516b --- /dev/null +++ b/files/zh-tw/archive/b2g_os/web_telephony_api/index.html @@ -0,0 +1,25 @@ +--- +title: Web Telephony +slug: Archive/B2G_OS/Web_Telephony_API +translation_of: Archive/B2G_OS/Web_Telephony_API +--- +

WebTelephony API 可透過 JavaScript 程式碼,讓網頁內容處理一般音訊電話。

+

透過 window.navigator.mozTelephony 即可存取此 API。另請參閱下列的完整介面列表:

+

DOM 介面

+ +

範例程式碼與介紹

+
+ +
+

另可參閱

+ diff --git a/files/zh-tw/archive/b2g_os/writing_apps_for_boot_to_gecko/index.html b/files/zh-tw/archive/b2g_os/writing_apps_for_boot_to_gecko/index.html new file mode 100644 index 0000000000..a38efda16e --- /dev/null +++ b/files/zh-tw/archive/b2g_os/writing_apps_for_boot_to_gecko/index.html @@ -0,0 +1,12 @@ +--- +title: 寫 Boot to Gecko 的 apps +slug: Archive/B2G_OS/Writing_apps_for_Boot_to_Gecko +translation_of: Archive/B2G_OS/Firefox_OS_apps/Building_apps_for_Firefox_OS +--- +

B2G apps 不外乎是安裝於 B2G 手機的 Open Web apps

+ +
+ Note: B2G 現在和 Fennec 用相同的 UA (User Agent) 來分辨。例如:"Mozilla/5.0 (Android; Mobile; rv:15.0) Gecko/15.0 Firefox/15.0a1".
diff --git a/files/zh-tw/archive/css3/index.html b/files/zh-tw/archive/css3/index.html new file mode 100644 index 0000000000..85374e3a65 --- /dev/null +++ b/files/zh-tw/archive/css3/index.html @@ -0,0 +1,584 @@ +--- +title: CSS3 +slug: Archive/CSS3 +translation_of: Archive/CSS3 +--- +

CSS3層疊樣式表語言的最新版且目標是為了延伸 CSS2.1。它有許多久違的新東西,像是圓角、陰影、漸層、或是動畫, 還有像是多列, 有彈性的盒子或是網格佈局之類的。 實驗的部分會有供應商前綴且應該在生產環境中盡可能地避免,使用那些未來可能會改變的語法或語義都要格外小心。

+ +

模組及標準化程序

+ +

CSS Level 2 需要 9 年(2002年八月~2011年六月),以達到建議的狀態。 This was due to the fact that a few secondary features hold back the whole specification. In order to accelerate the standardization of non-problematic features, the CSS Working Group of the W3C, in a decision referred as the Beijing doctrine , divided CSS in smaller components called modules . Each of these modules is now an independent part of the language and moves towards standardization at its own pace. While some modules are already W3C Recommendations, other still are early Working Drafts. New modules are also added when new needs are identified.

+ +

CSS Modules and Snapshots as defined since CSS3 Formally, there is no CSS3 standard per se . Each module being standardized independently, the standard CSS consists of CSS2.1 amended and extended by the completed modules, not necessary all with the same level number. At each point of time, a snapshot of the CSS standard can be defined, listing CSS2.1 and the mature modules.

+ +

The W3 consortium periodically publishes such snapshots, like in 2007 or 2010.

+ +

Though today no module with a level greater than 3 is standardized, this will change in the future. Some modules, like Selectors 4 or CSS Borders and Backgrounds Level 4 already have an Editor's Draft, though they haven't yet reached the First Published Working Draft status.

+ +

CSS 模組狀態

+ +

穩定模組

+ +

A few CSS modules are already fairly stable and have reached one of the three recommendation level of the CSSWG: Candidate Recommendation, Proposed Recommendation or Recommendation. These can be used without prefixed and are pretty stable, though a few features can still be dropped at the Candidate Recommendation stage.

+ +

These modules extend and amend the CSS2.1 specification which build the core of the specification. Together with it, they are the current snapshot of the CSS specification.

+ + + + + + + + + + + +
{{ SpecName("CSS3 Colors", "", "") }}{{ Spec2("CSS3 Colors") }}  自 2011 年 6 月 7 號起
+

增加 {{ cssxref("opacity") }} 屬性,還有 hsl(), hsla(), rgba() 和 rgb() 函式來創造 {{cssxref("<color>")}} 值。它也定義了關鍵字 currentColor 唯有效的顏色。

+ +

現在透明色是一個真實的顏色(因為支援了 alpha 通道)。若想要使用透明度,請使用 rgba(0,0,0,0.0)

+ +

關鍵字 system-color 不應該繼續使用,因為他已經被棄用。

+
+ + + + + + + + + + + +
{{ SpecName("CSS3 Selectors", "", "") }}{{ Spec2("CSS3 Selectors") }} 自 2011 年 9 月 29 號起
+

Adds:

+ +
    +
  • Substring matching attribute selectors, E[attribute^="value"] , E[attribute$="value"] , E[attribute*="value"] .
  • +
  • New pseudo-classes: {{ cssxref(":target") }}, {{ cssxref(":enabled") }} and {{ cssxref(":disabled") }}, {{ cssxref(":checked") }}, {{ cssxref(":indeterminate") }}, {{ cssxref(":root") }}, {{ cssxref(":nth-child") }} and {{ cssxref(":nth-last-child") }}, {{ cssxref(":nth-of-type") }} and {{ cssxref(":nth-last-of-type") }}, {{ cssxref(":last-child") }}, {{ cssxref(":first-of-type") }} and {{ cssxref(":last-of-type") }}, {{ cssxref(":only-child") }} and {{ cssxref(":only-of-type") }},{{ cssxref(":empty") }}, and {{ cssxref(":not") }}.
  • +
  • Pseudo-elements are now characterized by two colons rather then one: :after becomes {{ cssxref("::after") }}, :before becomes {{ cssxref("::before") }}, :first-letter becomes {{ cssxref("::first-letter") }}, and :first-line becomes {{ cssxref("::first-line") }}.
  • +
  • The new general sibling combinator ( h1~pre ).
  • +
+
+ +

The next iteration of the Selectors specification is already in progress, though it still hasn't reached the First Public Working Draft stage.

+ + + + + + + + + + + +
{{ SpecName("CSS3 Namespaces", "", "") }} +

{{ Spec2("CSS3 Namespaces") }} 自 2011 年 9 月 29 日起

+
+

Adds the support for the XML Namespaces by defining the notion of CSS qualified name , using the ' | ' syntax and adding the {{ cssxref("@namespace") }} CSS at-rule.

+
+ + + + + + + + + + + +
{{ SpecName("CSS3 Media Queries", "", "") }}{{ Spec2("CSS3 Media Queries") }} 自 2012 年 6 月 19 日起
+

Extends the former media type ( print, screen, ) to a full language allowing queries on the device media capabilities like only screen and (color) .

+ +

Media queries are not only used in CSS document but also in some attributes of HTML Elements, like the {{ htmlattrxref("media","link") }} attribute of the {{ HTMLElement("link") }} element.

+
+ +

The next iteration of this specification is in the work, allowing to tailor a Web site regarding the input methods available on the user agent, with new media features like hover or pointer. Detection of EcmaScript support, using the script media features is also proposed.

+ + + + + + + + + + + +
{{ SpecName("CSS3 Style", "", "") }}{{ Spec2("CSS3 Style") }} 自 2013 年 11 月 7 日起
Formally defines the syntax of the content of the HTML style global attribute.
+ + + + + + + + + + + +
{{ SpecName("CSS3 Backgrounds", "", "") }}{{ Spec2("CSS3 Backgrounds") }}
+

Adds:

+ +
    +
  • Support, on backgrounds, for any type of {{cssxref("<image>")}}, and not only for uri() defined ones.
  • +
  • Support for multiple background images.
  • +
  • The {{ cssxref("background-repeat") }} space and round values, and for the 2-value syntax of this CSS property.
  • +
  • The {{ cssxref("background-attachment") }} local value.
  • +
  • The CSS {{ cssxref("background-origin") }}, {{ cssxref("background-size") }}, and {{ cssxref("background-clip") }} properties.
  • +
  • Support for curved border corners, with the CSS {{ cssxref("border-radius") }}, {{ cssxref("border-top-left-radius") }}, {{ cssxref("border-top-right-radius") }}, {{ cssxref("border-bottom-left-radius") }}, and {{ cssxref("border-bottom-right-radius") }} properties.
  • +
  • Support for the use of an {{cssxref("<image>")}} as the border with the CSS {{ cssxref("border-image") }}, {{ cssxref("border-image-source") }}, {{ cssxref("border-image-slice") }}, {{ cssxref("border-image-width") }}, {{ cssxref("border-image-outset") }}, and {{ cssxref("border-image-repeat") }} properties.
  • +
  • Support for shadows of the element with the CSS {{ cssxref("box-shadow") }} property.
  • +
+
+ +

The CSS4 iteration of the Backgrounds and Borders specification is already in progress, though it still hasn't reached the First Public Working Draft stage, it plans to add the ability to clip a border (with the CSS {{ cssxref("border-clip") }}, {{ cssxref("border-clip-top") }}, {{ cssxref("border-clip-right") }}, {{ cssxref("border-clip-bottom") }}, and {{ cssxref("border-clip-left") }} properties) or to control the shape of the border in a corner (using the CSS {{ cssxref("border-corner-shape") }} property).

+ + + + + + + + + + + +
{{ SpecName("CSS3 Multicol", "", "") }}{{ Spec2("CSS3 Multicol") }}
Adds support for easy multi-column layouts using the CSS {{ cssxref("columns") }}, {{ cssxref("column-count") }}, {{ cssxref("column-fill") }}, {{ cssxref("column-gap") }}, {{ cssxref("column-rule") }}, {{ cssxref("column-rule-color") }}, {{ cssxref("column-rule-style") }}, {{ cssxref("column-rule-width") }}, {{ cssxref("column-span") }}, {{ cssxref("column-width") }}, {{ cssxref("break-after") }}, {{ cssxref("break-before") }}, and {{ cssxref("break-inside") }}.
+ + + + + + + + + + + +
{{ SpecName("CSS3 Speech", "", "") }}{{ Spec2("CSS3 Speech") }}
Defines the speech media type, an aural formatting model and numerous properties specific for speech-rendering user agents.
+ + + + + + + + + + + +
{{ SpecName("CSS3 Images", "", "") }}{{ Spec2("CSS3 Images") }}
+

Defines the {{cssxref("<image>")}} data type.

+ +

Extends the url() syntax to support image slices using media fragments.

+ +

Adds:

+ +
    +
  • The dppx unit to the {{cssxref("<resolution>")}} data type.
  • +
  • The image() function as a more flexible alternative to url() to define an image from an url.
    + At risk : due to insufficient browser support, standardization of the image() function may be postponed to the next iteration of this module .
  • +
  • Support for linear-gradient(), repeating-linear-gradient(), radial-gradient() and repeating-radial-gradient().
  • +
  • The ability to define how a replaced element should fit in its element, using the CSS {{ cssxref("object-fit") }} property.
    + At risk : due to insufficient browser support, standardization of the {{ cssxref("object-fit") }} and property may be postponed to the next iteration of this module .
  • +
  • The ability to override the resolution and orientation of an external image using the CSS {{ cssxref("image-resolution") }} and {{ cssxref("image-orientation") }} properties.
    + At risk : due to insufficient browser support, standardization of the {{ cssxref("image-resolution") }} and {{ cssxref("image-orientation") }} properties may be postponed to the next iteration of this module .
  • +
+
+ +

The CSS Image Values and Replaced Content Level 4 which will supersede CSS Image Level 3 is in development and is a {{Spec2("CSS4 Images")}}.

+ + + + + + + + + + + +
{{ SpecName("CSS3 Values", "", "") }}{{ Spec2("CSS3 Values") }}
+

Makes initial and inherit keywords usable on any CSS property.

+ +

Formally defines the CSS data types of CSS 2.1, that were implicitely defined by their grammar token and some textual precisions.

+ +

Adds:

+ +
    +
  • Definition for new font-relative length units: rem and ch .
  • +
  • Definition for viewport-relative length units: vw, vh, vmax, and vmin .
  • +
  • Precision about the real size of the absolute length units, which are not really absolute, but defined in relation with the reference pixel .
  • +
  • Definition for {{ cssxref("<angle>") }}, {{cssxref("<time>")}}, {{cssxref("<frequency>")}}, {{cssxref("<resolution>")}}.
  • +
  • Normative value to the definition of {{cssxref("<color>")}}, {{cssxref("<image>")}}, and {{ cssxref("<position>") }}.
  • +
  • Definition for the {{ cssxref("calc", "calc()") }}, {{ cssxref("attr", "attr()")}}, and toggle() functional notations.
    + At risk: due to insufficient browser support, standardization of the calc(), attr(), and toggle() functional notations may be postponed to the next iteration of this module.
  • +
+
+ +

Several types definition, like <ident> and <custom-ident>, have been deferred to CSS Values and Units Module Level 4.

+ + + + + + + + + + + +
{{ SpecName("CSS3 Flexbox", "", "") }}{{ Spec2("CSS3 Flexbox") }}
Add a flexbox layout to the CSS {{ cssxref("display") }} property and several new CSS properties to control it: {{ cssxref("flex") }}, {{ cssxref("flex-align") }}, {{ cssxref("flex-direction") }}, {{ cssxref("flex-flow") }}, {{ cssxref("flex-item-align") }}, {{ cssxref("flex-line-pack") }}, {{ cssxref("flex-order") }}, {{ cssxref("flex-pack") }}, and {{ cssxref("flex-wrap") }}.
+ + + + + + + + + + + +
{{ SpecName("CSS3 Conditional", "", "") }}{{ Spec2("CSS3 Conditional") }}
Adds features for conditional processing of parts of style sheets, conditioned on capabilities of the browser or the document the style sheet is being applied to. It consists mainly in allowing nested at-rules inside {{ cssxref("@media") }} and the adding of a new CSS at-rule, {{ cssxref("@supports") }}, and a new DOM method {{domxref("CSS.supports()")}}.
+ + + + + + + + + + + +
{{ SpecName("CSS3 Text-decoration", "", "") }}{{ Spec2("CSS3 Text-decoration") }}
+

Extends:

+ +
    +
  • the CSS {{ cssxref("text-decoration") }} property by making it a shorthand for the CSS {{ cssxref("text-decoration-line") }}, {{ cssxref("text-decoration-color") }}, and {{ cssxref("text-decoration-style") }} properties. And adds the {{ cssxref("text-decoration-skip") }}, and {{ cssxref("text-underline-position") }} properties.
  • +
+ +

Adds:

+ +
    +
  • Support for East-Asian-script emphasis marks with the CSS {{ cssxref("text-emphasis") }}, {{ cssxref("text-emphasis-style") }}, {{ cssxref("text-emphasis-color") }}, and {{ cssxref("text-emphasis-position") }} properties.
  • +
  • Support for script shadows with the CSS {{ cssxref("text-shadow") }} property.
  • +
+ +

Precises:

+ +
    +
  • The paint order of the decorations.
  • +
+ +

At risk: due to insufficient browser support, standardization of the text-decoration-skip, line positioning rules and the ability to place both emphasis marks and ruby above the same base text may be postponed to the next iteration of this module.

+
+ + + + + + + + + + + +
{{ SpecName("CSS3 Fonts", "", "") }}{{ Spec2("CSS3 Fonts") }}
+

Amends the CSS2.1 Font matching algorithm to be closer to what is really implemented.

+ +

Adds:

+ +
    +
  • Support for downloadable fonts via the CSS {{ cssxref("@font-face") }} at-rule.
  • +
  • The control of the contextual inter-glyph spacing via the CSS {{ cssxref("font-kerning") }} property.
  • +
  • The choice of language-specific glyphs via the CSS {{ cssxref("font-language-override") }} property.
  • +
  • The choice of glyphs with specific OpenType features via the CSS {{ cssxref("font-feature-settings") }} property.
  • +
  • The control of the aspect ratio to use when fallback fonts are selected via the CSS {{ cssxref("font-size-adjust") }} property.
  • +
  • The choice of alternative font faces using the CSS {{ cssxref("font-stretch") }}, {{ cssxref("font-variant-alternates") }}, {{ cssxref("font-variant-caps") }}, {{ cssxref("font-variant-east-asian") }}, {{ cssxref("font-variant-ligatures") }}, {{ cssxref("font-variant-numeric") }}, and {{ cssxref("font-variant-position") }} properties. It also extends the related CSS {{ cssxref("font-variant") }} shorthand property and introduces the {{ cssxref("@font-features-values") }} at-rule.
  • +
  • The control of the automatic generation of an oblique or bold face when none are found via the CSS {{ cssxref("font-synthesis") }} property.
  • +
+
+ + + + + + + + + + + +
{{ SpecName("CSS3 Syntax", "", "") }}{{ Spec2("CSS3 Syntax") }}
Precises how charsets are determined; minor changes in parsing and tokenization algorithms.
+ +

Modules in the refining phase

+ +

Specifications that are deemed to be in the refining phase are already fairly stable. Though changes are still expected, they shouldn't create incompatibilities with current implementations; they should mainly define behavior in edge cases.

+ + + + + + + + + + + +
{{ SpecName("CSS3 Basic UI", "", "") }}{{ Spec2("CSS3 Basic UI") }}
+

Adds:

+ +
    +
  • The ability to tweak the box model using the CSS {{ cssxref("box-sizing") }} property.
    + At risk: due to insufficient browser support, standardization of the padding-box value may be postponed to the next iteration of this module .
  • +
  • Allow the styling of forms according their content using the CSS {{ cssxref(":indeterminate") }}, {{ cssxref(":default") }}, {{ cssxref(":valid") }}, {{ cssxref(":invalid") }}, {{ cssxref(":in-range") }}, {{ cssxref(":out-of-range") }}, {{ cssxref(":required") }}, {{ cssxref(":optional") }}, {{ cssxref(":read-only") }}, and {{ cssxref(":read-write") }} pseudo-classes and the {{ cssxref("::value") }}, {{ cssxref("::choices") }}, {{ cssxref("::repeat-item") }}, and {{ cssxref("::repeat-index") }} pseudo-elements.
    + At risk: due to insufficient browser support, standardization of the pseudo-elements {{ cssxref("::value") }}, {{ cssxref("::choices") }}, {{ cssxref("::repeat-item") }}, and {{ cssxref("::repeat-index") }} may be postponed to the next iteration of this module .
  • +
  • Support for icons, defined by the CSS {{ cssxref("icon") }} property simultaneously with the new icon value of the CSS {{ cssxref("content") }} property.
    + At risk: due to insufficient browser support, standardization of the {{ cssxref("icon") }} property and the icon value may be postponed to CSS4.
  • +
  • Support for the CSS {{ cssxref("outline-offset") }} property giving more control on the position of the outline.
  • +
  • Support for the CSS {{ cssxref("resize") }} property allowing Web authors to control if and how elements should be resized.
  • +
  • Support for the CSS {{ cssxref("text-overflow") }} property defining how text overflows, if needed.
    + At risk: due to insufficient browser support, the 2-value syntax of this property as well as the support for {{cssxref("<string>")}} values may be postponed to the next iteration of this module .
  • +
  • The ability to define the hotspot of a cursor as well as the new none, context-menu, cell, vertical-text, alias, copy, no-drop, not-allowed, nesw-resize, nwse-resize, col-resize, row-resize, all-scroll, zoom-in, zoom-out, extending the {{ cssxref("cursor") }} property.
  • +
  • The ability to specify the sequential navigation order (that is the tabbing order ) using the CSS {{ cssxref("nav-index") }}, {{ cssxref("nav-up") }}, {{ cssxref("nav-right") }}, {{ cssxref("nav-left") }}, {{ cssxref("nav-down") }} properties.
    + At risk: due to insufficient browser support, standardization of the navigation properties may be postponed to the next iteration of this module .
  • +
  • The ability to control the usage of an IME editor, using the CSS {{ cssxref("ime-mode") }} property.
    + At risk: due to insufficient browser support, standardization of the {{ cssxref("ime-mode") }} property may be postponed to the next iteration of this module .
  • +
+
+ +

An early list of what could be in the next iteration of the CSS Basic User Interface Module is available.

+ + + + + + + + + + + +
{{ SpecName("CSS3 Transitions", "", "") }}{{ Spec2("CSS3 Transitions") }}
Allows the definition of transitions effects between two properties values by adding the CSS {{ cssxref("transition") }}, {{ cssxref("transition-delay") }}, {{ cssxref("transition-duration") }}, {{ cssxref("transition-property") }}, and {{ cssxref("transition-timing-function") }} properties.
+ + + + + + + + + + + +
{{ SpecName("CSS3 Animations", "", "") }}{{ Spec2("CSS3 Animations") }}
Allows the definition of animations effects by adding the CSS {{ cssxref("animation") }}, {{ cssxref("animation-delay") }},{{ cssxref("animation-direction") }}, {{ cssxref("animation-duration") }}, {{ cssxref("animation-fill-mode") }}, {{ cssxref("animation-iteration-count") }}, {{ cssxref("animation-name") }}, {{ cssxref("animation-play-state") }}, and {{ cssxref("animation-timing-function") }} properties, as well as the {{ cssxref("@keyframes") }} at-rule.
+ + + + + + + + + + + +
{{ SpecName("CSS3 Transforms", "", "") }}{{ Spec2("CSS3 Transforms") }}
+

Adds:

+ +
    +
  • the support of bi-dimensional transforms to be applied to any element using the CSS {{ cssxref("transform") }} and {{ cssxref("transform-origin") }} properties. The supported transforms are: matrix(), translate(), translateX(), translateY(), scale(), scaleX(), scaleY(), rotate(), skewX(), and skewY().
  • +
  • the support of tri-dimensional transforms to be applied to any element by adding the CSS {{ cssxref("transform-style") }}, {{ cssxref("perspective") }}, {{ cssxref("perspective-origin") }}, and {{ cssxref("backface-visibility") }} properties and extended the {{ cssxref("transform") }} property with the following transforms are: matrix 3d(), translate3d(), translateZ()scale3d(), scaleZ(), rotate3d(), rotateX() ,rotateY(), rotateZ(), and perspective().
  • +
+ +

Note: this specification is a merge of CSS 2D-Transforms, CSS 3D-Transforms and SVG transforms.

+
+ + + + + + + + + + + +
{{ SpecName("CSS3 Fragmentation", "", "") }}{{ Spec2("CSS3 Fragmentation") }}
Defines how partitions of a Web page should happen, that is page, column breaks, and widows and orphans handling. +

Adds:

+ +
    +
  • Support for defining the behavior of decorations, that is borders and background colors or images, when a box is breaked (at a page, column or line-break) with the CSS {{ cssxref("box-decoration-break") }} property.
  • +
+
+ + + + + + + + + + + +
{{ SpecName("CSS3 Text", "", "") }}{{ Spec2("CSS3 Text") }}
+

Extends:

+ +
    +
  • the CSS {{ cssxref("text-transform") }} property with the value full-width.
  • +
  • the CSS {{ cssxref("text-align") }} property with the value start, end, start end, and match-parent for a better support of documents with multiple directionalities of text.
  • +
  • the CSS {{ cssxref("text-align") }} property with a {{cssxref("<string>")}} value to align on that character. This is useful to align number on the decimal point.
  • +
  • the CSS {{ cssxref("word-spacing") }} and {{ cssxref("letter-spacing") }} properties with range constraints to control flexibility in justification.
  • +
+ +

Adds:

+ +
    +
  • Control on how whitespaces are displayed using the CSS {{ cssxref("text-space-collapse") }} and {{ cssxref("tab-size") }} properties.
  • +
  • Control on line breaks and word boundaries using the CSS {{ cssxref("line-break") }}, {{ cssxref("word-break") }}, {{ cssxref("hyphens") }}, {{ cssxref("text-wrap") }}, {{ cssxref("overflow-wrap") }}, and {{ cssxref("text-align-last") }} properties.
  • +
  • Control on how justification is happening, in order to support more type of scripts, using the CSS {{ cssxref("text-justify") }} property.
  • +
  • Control on edge effect using the CSS {{ cssxref("text-indent") }} and {{ cssxref("hanging-punctuation") }} properties.
  • +
+
+ +

A few features present in early CSS Text Level 3 draft have being postponed to the next iteration of this module .

+ + + + + + + + + + + +
{{ SpecName("CSS3 Variables", "", "") }}{{ Spec2("CSS3 Variables") }}
Defines a mechanism allowing to define variables in CSS.
+ +

Modules in the revising phase

+ +

Modules that are in the revising phase are much less stable than those in the refining phase. Often the syntax is still under scrutiny and may evolve a lot, in a non-compatible way. Alternative syntax are tested and often implemented.

+ + + + + + + + + + + +
{{ SpecName("CSS3 Writing Modes", "", "") }}{{ Spec2("CSS3 Writing Modes") }}
Defines the writing modes of both horizontal and vertical scripts and precises how the CSS {{ cssxref("direction") }} and {{ cssxref("unicode-bidi") }} properties interact with the new CSS {{ cssxref("text-orientation") }} property, and extends them where needed.
+ +

Modules in the exploring phase

+ + + + + + + + + + + +
{{ SpecName("CSS4 Images", "", "") }}{{ Spec2("CSS4 Images") }}
+

Extends:

+ +
    +
  • the image() functional notation to describe the directionality of the image (rtl or ltr), allowing for bidi-sensitive images.
  • +
  • the {{ cssxref("image-orientation") }} property by adding the keyword from-image, allowing to follow EXIF data stored into images to be considered.
  • +
+ +

Adds:

+ +
    +
  • the image-set() functional notation to allow the definition to equivalent images at different resolution allowing for resolution-negotiated selection of images.
  • +
  • the element() functional notation allowing the use of part of the page as image.
  • +
  • the cross-fade() functional notation allowing to refer to intermediate images when transitioning between two images and defines the interpolation between two images.
  • +
  • the conic-gradient() and repeating-conic-gradient() functional notation describing a new type of gradient.
  • +
  • the {{cssxref("image-rendering")}} property that allow to define how resize of the object should be handled.
  • +
+
+ + + + + + + + + + + +
{{ SpecName("CSS3 Device", "", "") }}{{ Spec2("CSS3 Device") }}
Adds a new at-rule, {{ cssxref("@viewport") }}, allowing to specify the size, zoom factor, and orientation of the viewport that is used as the base for the initial containing block.
+ + + + + + + + + + + +
{{ SpecName("CSS3 Grid", "", "") }}{{ Spec2("CSS3 Grid") }}
Add a grid layout to the CSS display property and several new CSS properties to control it: {{cssxref("grid")}}, {{cssxref("grid-area")}}, {{cssxref("grid-auto-columns")}}, {{cssxref("grid-auto-flow")}}, {{cssxref("grid-auto-position")}}, {{cssxref("grid-auto-rows")}}, {{cssxref("grid-column")}}, {{cssxref("grid-column-start")}}, {{cssxref("grid-column-end")}}, {{cssxref("grid-row")}}, {{cssxref("grid-row-start")}}, {{cssxref("grid-row-end")}}, {{cssxref("grid-template")}}, {{cssxref("grid-template-areas")}}, {{cssxref("grid-template-rows")}}, and {{cssxref("grid-template-columns")}}.
+ + + + + + + + + + + +
{{ SpecName("CSS3 GCPM", "", "") }}{{ Spec2("CSS3 GCPM") }}
Adds the ability to tailor printed version of a document by allowing to control header, footer but also references tables like indexes or tables of content.
+ + + + + + + + + + + +
{{ SpecName("CSS3 Exclusions and Shapes", "", "") }}{{ Spec2("CSS3 Exclusions and Shapes") }}
Extends the floats mechanism to define exclusion regions in any positioning scheme. Adds the notion of shapes, in which content must flows.
+ + + + + + + + + + + +
{{ SpecName("CSS3 Lists", "", "") }}{{ Spec2("CSS3 Lists") }}
Extends the list counter mechanism so that list markers can be styled and Web developers can define new list counter schemes.
+ + + + + + + + + + + +
{{ SpecName("CSS3 Regions", "", "") }}{{ Spec2("CSS3 Regions") }}
Defines a new mechanism allowing content to flow across, eventually non-contiguous, multiple areas called regions.
+ +

 

diff --git a/files/zh-tw/archive/index.html b/files/zh-tw/archive/index.html new file mode 100644 index 0000000000..6766a22f6e --- /dev/null +++ b/files/zh-tw/archive/index.html @@ -0,0 +1,21 @@ +--- +title: 過時內容的存檔 +slug: Archive +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive +--- +

在 MDN,我們盡量避免直接刪除內容,因為那些內容可能對要找出遺留平台、作業系統、瀏覽器相關資料的人而言很有用:也許你的目標人群在用很老舊的硬體、使他們的瀏覽器無法升級到最新版本;或著因為某些「原因」,你的公司要用非常老舊的軟體、而你建置的網路內容需要在那個軟體上運行;也可能是你對過時的功能或 API 歷史與運行方法感到興趣。

+ +

出於很多原因,老文件非常有用。因此,我們開闢了這個地方,用以保存老文件。這裡的內容不該用作建置面向現代瀏覽器的新網站或 apps 參考。這裡存在的目的,只有作為歷史參考。

+ +
+

給編者的筆記:我們要盡可能維持子頁面的組織化、而不該把所有東西都丟到一個大資料夾。試著給內容歸類。另外,只把非常老舊的內容移到這裡。若可能有人切實需要還在使用的軟體資訊,就不該移這裡。在你把任何內容移動到這裡以前,最好在 MDN Web Docs 頻道討論。

+
+ +

{{SubpagesWithSummaries}}

+ +

子頁面

+ +

{{ListSubpages("/zh-TW/docs/Archive", 2, 0, 1)}}

diff --git a/files/zh-tw/archive/mdn/index.html b/files/zh-tw/archive/mdn/index.html new file mode 100644 index 0000000000..f99cd4e169 --- /dev/null +++ b/files/zh-tw/archive/mdn/index.html @@ -0,0 +1,18 @@ +--- +title: MDN Archive +slug: Archive/MDN +tags: + - Archive + - MDN +translation_of: Archive/MDN +--- +

{{MDNSidebar}}

+ +
+

Obsolete
+ 此文件已過時。

+
+ +

The documentation listed below is archived, obsolete material about MDN itself.

+ +

{{LandingPageListSubpages}}

diff --git a/files/zh-tw/archive/mdn/persona_sign-ins/index.html b/files/zh-tw/archive/mdn/persona_sign-ins/index.html new file mode 100644 index 0000000000..7c65870878 --- /dev/null +++ b/files/zh-tw/archive/mdn/persona_sign-ins/index.html @@ -0,0 +1,28 @@ +--- +title: MDN and Persona sign-ins +slug: Archive/MDN/Persona_sign-ins +tags: + - '3081911' +translation_of: Archive/MDN/Persona_sign-ins +--- +
{{MDNSidebar}}
+

Please link your GitHub account to your MDN profile now so you can continue to sign in to MDN.

+
+ +

Currently, MDN lets contributors sign in using two different authentication providers: Mozilla Persona and GitHub. Starting on November 1, 2016, we will remove Persona as an option for logging in. Therefore, you must enable Github authentication on your profile to avoid losing login access to MDN.

+ +

We recognize that this is an inconvenience, and we do apologize for it. Unfortunately, this is out of our control.

+ +

Why is Persona being removed?

+ +

Mozilla has shut down the Persona project, and its servers will be turned off in November, 2016. You can learn more about Mozilla's decision to shut down Persona on the Mozilla wiki.

+ +

When will Persona be removed?

+ +

We will disable Persona as an authentication provider on November 1, 2016; in other words, the last day you'll be able to sign in to MDN using Persona will be October 31, 2016. We will be issuing increasingly frequent and increasingly urgent notifications to add a GitHub account to your MDN profile starting now. Please do this as soon as you can, in order to avoid any risk of losing access to your MDN account.

+ +

Will MDN offer another authentication provider?

+ +

We would very much like to do so, but have not yet identified another provider which meets our requirements; in addition, we don't currently have the developer resources to integrate another provider. For the time being, your only option to keep contributor access to MDN is to link your MDN profile to your GitHub account.

+ +

Keep in mind, of course, that you don't need to sign in to MDN in order to read our content. But if you have an account for contributing, and wish to be able to contribute at any time in the future, be sure to add a GitHub account to your profile as soon as you can, before October 31, 2016.

diff --git a/files/zh-tw/archive/meta_docs/custom_classes/index.html b/files/zh-tw/archive/meta_docs/custom_classes/index.html new file mode 100644 index 0000000000..0aa624f2fd --- /dev/null +++ b/files/zh-tw/archive/meta_docs/custom_classes/index.html @@ -0,0 +1,189 @@ +--- +title: 自訂 CSS 類別 +slug: Archive/Meta_docs/Custom_classes +tags: + - MDC_專案 +translation_of: Archive/Meta_docs/Custom_classes +--- +

 以下是 MDC Wiki 上自行定義的樣式類別,若你也想新增類別,請聯絡 Dria

+ +

現有 CSS 類別

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
樣式使用結果
div.tip顯示網頁內容中的小技巧文字。
div.bug顯示網頁內容中的程式錯誤文字。
.float-left製作向左浮動的元素(通常是圖片)。
.float-right製作向右浮動的元素(通常是圖片)。
.figure這個樣式目前還沒有實際作用,是為日後使用準備的。
.standard-table標準的表格樣式。
.standard-table td.header標準表格的標題樣式。
.fullwidth-table寬度設定為 100% 的表格(就像現在這個表格一樣)。
.fullwidth-table td.header寬度設為 100% 之表格的標題樣式。
div.breadcrumbs頁面導覽的樣式。
div.breadcrumbs a.breadcrumbs頁面導覽字串中連結部分的樣式。
div.breadcrumbs span.breadcrumbs頁面導覽字串中目前頁面標題的樣式。
div.side-note-left div.side-note-right用以建立文章內的邊欄。此區域之寬度將佔其母元素(通常就是文件本體)的 50%。若要建立邊欄請使用這個樣式,以確保內容顯示上容易閱讀。
div.highlight在區段左側放上 3 個像素寬的藍色邊框。/td>
.highlightred將文字改以紅色顯示。
.highlightblue將文字改以藍色顯示。
.highlightgreen將文字改以綠色顯示。
+ +

範例

+ +

標示部分程式碼

+ +

通常我們會讓程式碼以特別的區塊顯示,這可以利用 span 搭配 MediaWiki 系統「行前空一格就自動縮排」的功能。須注意的是在 <pre> 區段中不能用 span 元素,因為此時 MediaWiki 會直接把 span 元素當成要顯示的內容而輸出。

+ +
<span class="highlightred">這樣是沒用的</span>
+
+ +

這種狀況下就應該將程式碼縮排,然後在其中使用 span 元素。如果程式中有空白行,該行也必須縮排,否則系統會認為空白行的前後為分開的兩個區段。

+ +
像這樣,
+   程式碼的空白行並沒有縮排,
+
+ +
   所以就顯示成兩個區段了。
+
+ +

顯然這樣跟我們想要的有所差異,所以你應該這麼做:

+ +
像這樣,
+   空白行前也加了個空白字元以示縮排,
+
+   這樣系統就將其顯示為同一個區段。
+
+ +

導覽

+ +

 

+ + + +

table.standard-table

+ +

<tr> <td>此為</td> <td>table.standard-table</td> <td>的範例</td> </tr> </table>

+ +

table.fullwidth-table

+ + + + + + + +
表格標題 1</td> +

<th>表格標題 2</td> <th>表格標題 3</td>

+
+ +

<tr> <td>此為</td> <td>table.fullwidth-table</td> <td>的範例</td> </tr> </table>

+ +

DIV 區段

+ +
小技巧
+ +

小技巧區段以 div class="note" 標示,例如:

+ +
這就是個小技巧
+ +
程式錯誤
+ +

已知的程式錯誤可用 div class="bug" 標示參照,內含 bugzilla 上的對應資訊連結,例如:

+ +
Bug 176320:彈出視窗 innerWidth 及 innerHeight 的最小值
+ +
警告
+ +

請使用 div class="warning" 來標示文件中的警告文字,很快我們會為此樣式加上圖示等特殊效果。

+ +
此段為警告文字
+ +
注釋
+ +

請使用 div class="note" 來標示文件中的注釋文字。

+ +
這是注釋,雖然沒什麼意思但還是個注釋。
+ +
標示區段
+ +

以下為 div class="highlight" 的範例:

+ +
+

此為以 CSS 標示區段的範例,您可用這個方法讓某個程式碼區段更加顯眼。這個樣式最先是為 XUL 教學而加進 MDC 的。

+ +
而這是
+   標示之區段中
+   文字預先格式化的
+      範例
+
+
+ + + + + + + +
表格標題 1</td> +

<th>表格標題 2</td> <th>表格標題 3</td>

+
diff --git a/files/zh-tw/archive/meta_docs/index.html b/files/zh-tw/archive/meta_docs/index.html new file mode 100644 index 0000000000..52de2c8447 --- /dev/null +++ b/files/zh-tw/archive/meta_docs/index.html @@ -0,0 +1,12 @@ +--- +title: MDN "meta-documentation" archive +slug: Archive/Meta_docs +tags: + - Archive + - MDN + - NeedsTranslation + - TopicStub +translation_of: Archive/Meta_docs +--- +

Here you'll find archived "meta-documentation"; that is, documentation about how to write documentation on MDN. The articles here are obsolete and should no longer be referenced; we are retaining them here for reference while we migrate some content to new places, but very little of this is useful.

+

{{LandingPageListSubpages}}

diff --git a/files/zh-tw/archive/misc_top_level/creating_a_web_based_tone_generator/index.html b/files/zh-tw/archive/misc_top_level/creating_a_web_based_tone_generator/index.html new file mode 100644 index 0000000000..590a003de0 --- /dev/null +++ b/files/zh-tw/archive/misc_top_level/creating_a_web_based_tone_generator/index.html @@ -0,0 +1,91 @@ +--- +title: 製作一個 Web 上的音調產生器 +slug: Archive/Misc_top_level/Creating_a_Web_based_tone_generator +translation_of: Archive/Misc_top_level/Creating_a_Web_based_tone_generator +--- +

這是一個簡單的音調產生器的範例。requestSoundData() 是產生音頻樣本的函式,這個函式在經過某個特定的時間間隔會透過 setInterval() 被呼叫。mozWriteAudio() 是在被呼叫時,把樣本寫入音頻串流的函式。為了確保總是有可以播放的樣本,這個範例設置了一個 500 ms 的緩衝。mozCurrentSampleOffset() 是一個用來知道正在被播放的樣本所在位置的函式,這的函式被這個範例用來確保我們填進緩衝的總是正在被播放後的 500 ms。

+
<!DOCTYPE html>
+<html>
+  <head>
+    <title>JavaScript 音頻寫入範例</title>
+  </head>
+  <body>
+    <input type="text" size="4" id="freq" value="440"><label for="hz">Hz</label>
+    <button onclick="start()">play</button>
+    <button onclick="stop()">stop</button>
+
+    <script type="text/javascript">
+      function AudioDataDestination(sampleRate, readFn) {
+        // 音頻輸出的初使化
+        var audio = new Audio();
+        audio.mozSetup(1, sampleRate);
+
+        var currentWritePosition = 0;
+        var prebufferSize = sampleRate / 2; // 緩衝 500ms
+        var tail = null;
+
+        // 這個函數會被定期呼叫以填充音頻輸出緩衝
+        setInterval(function() {
+          var written;
+          // 看看之前也沒有留下未被寫入的資料
+          if(tail) {
+            written = audio.mozWriteAudio(tail);
+            currentWritePosition += written;
+            if(written < tail.length) {
+              // 並非所有資料都被寫入了,把剩下的存下來...
+              tail = tail.slice(written);
+              return; // ... 並結束這個函式
+            }
+            tail = null;
+          }
+
+          // 看看是不是有需要再加新資料至音頻輸出
+          var currentPosition = audio.mozCurrentSampleOffset();
+          var available = currentPosition + prebufferSize - currentWritePosition;
+          if(available > 0) {
+            // 從回撥函式(callback)要一些音效資料
+            var soundData = new Float32Array(parseFloat(available));
+            readFn(soundData);
+
+            // 寫這些資料
+            written = audio.mozWriteAudio(soundData);
+            if(written < soundData.length) {
+              // 不是所有資料都被寫入了,存下剩下的部份。
+              tail = soundData.slice(written);
+            }
+            currentWritePosition += written;
+          }
+        }, 100);
+      }
+
+      // 控制並製造聲音
+
+      var frequency = 0, currentSoundSample;
+      var sampleRate = 44100;
+
+      function requestSoundData(soundData) {
+        if (!frequency) {
+          return; // 已被靜音
+        }
+
+        var k = 2* Math.PI * frequency / sampleRate;
+        for (var i=0, size=soundData.length; i<size; i++) {
+          soundData[i] = Math.sin(k * currentSoundSample++);
+        }
+      }
+
+      var audioDestination = new AudioDataDestination(sampleRate, requestSoundData);
+
+      function start() {
+        currentSoundSample = 0;
+        frequency = parseFloat(document.getElementById("freq").value);
+      }
+
+      function stop() {
+        frequency = 0;
+      }
+  </script>
+  </body>
+</html>
+
+

{{ languages( { "en": "en/Creating_a_Web_based_tone_generator"} ) }}

diff --git a/files/zh-tw/archive/misc_top_level/index.html b/files/zh-tw/archive/misc_top_level/index.html new file mode 100644 index 0000000000..0959a3b10b --- /dev/null +++ b/files/zh-tw/archive/misc_top_level/index.html @@ -0,0 +1,8 @@ +--- +title: Misc top level +slug: Archive/Misc_top_level +translation_of: Archive/Misc_top_level +--- +

In progress. These pages were moved from the top level of MDN in a spate of furious reorganization.

+ +

{{SubpagesWithSummaries}}

diff --git a/files/zh-tw/archive/misc_top_level/same-origin_policy_for_file_colon__uris/index.html b/files/zh-tw/archive/misc_top_level/same-origin_policy_for_file_colon__uris/index.html new file mode 100644 index 0000000000..b0fd952355 --- /dev/null +++ b/files/zh-tw/archive/misc_top_level/same-origin_policy_for_file_colon__uris/index.html @@ -0,0 +1,18 @@ +--- +title: '檔案同源政策 (Same-origin policy for file: URIs)' +slug: 'Archive/Misc_top_level/Same-origin_policy_for_file:_URIs' +translation_of: 'Archive/Misc_top_level/Same-origin_policy_for_file:_URIs' +--- +

在 Gecko 1.8 之前,任兩份檔案都會被視為同源(same-origin),換句話說本機端的任一份HTML檔可以讀取任一份檔案。

+ +

自 Gacko 1.9 起,檔案讀取檔案開始受到限制:唯有當主檔案父資料夾是被讀取檔案的祖先資料夾 (ancestor directory) 的情況之下,檔案讀取才會被允許,但資料夾載入並非以此規範。

+ +

舉例來說,我們從 index.html 進入同一層資料夾的另一個 foo.html 檔,而這個 foo.html 檔想要讀取 bar.html 檔,只有當 bar.html 存放於 index.html 所在資料夾或是 index.html 所在資料夾底下的子資料夾中,foo.html 才能讀取 bar.html。

+ +

檔案同源政策會影響到包括 XMLHttpRequest, XSLT, 與 XBL 等同源政策的檢查。

+ +

至於跨 window 的 DOM 存取,基本上各檔案都被視為不同源,除了以下例外:若是檔案 B 被另一個檔案 A 載入(例如透過 iframe 或 window.open()),而檔案 A、B 遵照此份檔案同源政策可以被判定屬於同源,那麼當發生跨 window 的 DOM 存取時,也可以視為同源。

+ +

比如說 /home/user/subdir/foo.html 是一個 frameset,而它下嵌了 另一個 /home/user/subdir/subdir2/bar.html 的 frame, 那麼 foo.html 和 bar.html 可以視為同源,但如果 bar.html 的位置變成 /home/user/bar.html,那麼 foo.html 和 bar.html 便不可以視為同源。

+ +

另外當使用者想要關閉這些檔案同源政策檢查,可以變更 security.fileuri.strict_origin_policy 偏好設定為從預設 true 到 false。

diff --git a/files/zh-tw/archive/mozilla/creating_a_microsummary/index.html b/files/zh-tw/archive/mozilla/creating_a_microsummary/index.html new file mode 100644 index 0000000000..40afef30b6 --- /dev/null +++ b/files/zh-tw/archive/mozilla/creating_a_microsummary/index.html @@ -0,0 +1,214 @@ +--- +title: 製作即時摘要 +slug: Archive/Mozilla/Creating_a_microsummary +tags: + - 即時摘要 +translation_of: Archive/Mozilla/Creating_a_microsummary +--- +

+ 即時摘要來源(microsummary generator)內含一組從網頁中製出即時摘要的指令,而網頁能在 <head> 元素中放入 <link rel="microsummary"> 以指定適用的摘要來源。即時摘要來源檔案中如含有適用頁面列表,則也可以獨立安裝。

+

+ 在這份教學文件中,我們將建立 Spread Firefox 首頁的即時摘要來源,藉以顯示目前 Firefox 的總下載數。 (例: Fx 下載數: 174475447)。

+

+ 接下來我們會用一份 XSLT 樣式表將該網頁轉換為即時摘要、指定此摘要來源的適用頁面並了解摘要來源傳佈方式,讓使用者能下載及安裝。在這份文件中每階段新增的程式碼會以粗體顯示,方便您辨識。

+

+ 開始

+

+ 摘要來源是 XML 文件的一種,而其根元素為 <generator>、名稱空間 (namespace) 需指定為 http://www.mozilla.org/microsummaries/0.1,所以要建立一份摘要來源就先得在空的純文字檔中放入 XML 宣告及空的 <generator> 標籤:

+
<?xml version="1.0" encoding="UTF-8"?>
+<generator xmlns="http://www.mozilla.org/microsummaries/0.1">
+</generator>
+
+

+ 命名

+

+ 每個即時摘要來源都必須有個名字,該名稱以 name 屬性記載、明確說明此摘要來源所建立的摘要主題。由於我們要建立的摘要來源將顯示 Firefox 總下載數,所以便命名為「Firefox 下載計數」:

+
<?xml version="1.0" encoding="UTF-8"?>
+<generator xmlns="http://www.mozilla.org/microsummaries/0.1"
+           name="Firefox 下載計數">
+</generator>
+
+

+ 加上 XSLT 樣式表

+

+ 即時摘要來源檔案中必須含有一份 XSLT 樣式表,以便將網頁依樣式表設定轉換為即時摘要。同一份資料碰上不同的 XSLT 樣式便能轉換為「相貌」不同的文件,這便是 XSLT 威力所在。

+

+ 以下示範以 <template> 元素在摘要來源中添加 XSLT 樣式表:

+
<?xml version="1.0" encoding="UTF-8"?>
+<generator xmlns="http://www.mozilla.org/microsummaries/0.1"
+           name="Firefox 下載計數">
+  <template>
+    <transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
+    </transform>
+  </template>
+</generator>
+
+

+ 即時摘要來源中可以放任何形式的 XSLT,設定為產生超文件也行,但 Firefox 目前只會顯示純文字內容。

+

+ 設定輸出格式

+

+ 由於 XSLT 樣式表會產岀文字摘要,所以 XSLT 的 <output> 元素需設定如下:

+
<?xml version="1.0" encoding="UTF-8"?>
+<generator xmlns="http://www.mozilla.org/microsummaries/0.1"
+           name="Firefox 下載計數">
+  <template>
+    <transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
+      <output method="text"/>
+    </transform>
+  </template>
+</generator>
+
+

+ 使用 XSLT <template>

+

+ XSLT 處理器會分別比對 XSLT 樣式表中每組 <template> 元素及文件中的節點。當 <template>match 屬性設定與節點相符,處理器便依設定轉換文件。

+

+ 這種處理方式可以循序檢查網頁中每個節點,依據設定條件顯示內容,非常有用。不過本例只是要顯示 Spread Firefox 網站上的即時摘要,僅用一個 <template> 元素來找一回根元素下的內容即可:

+
<?xml version="1.0" encoding="UTF-8"?>
+<generator xmlns="http://www.mozilla.org/microsummaries/0.1"
+           name="Firefox 下載計數">
+  <template>
+    <transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
+      <output method="text"/>
+      <template match="/">
+      </template>
+    </transform>
+  </template>
+</generator>
+
+

+ 加上下載次數

+

+ 若想將下載次數放到 XSLT 輸出的文件中,我們得在 XSLT 中的 template 元素加上 <value-of> 元素,而此 template 元素的 select 屬性中指定的 XPath 必須指向涵括計數器的節點。

+

+ XPath 是用來指定 HTML/XML 文件節點的語言,也有基本的節點內容處理函式。要得知能指向此節點的 XPath 陳述式,最輕鬆的方法就是使用 XPath Checker 擴充套件

+

+ 安裝 XPath Checker 並重新啟動 Firefox 之後,先到 Spread Firefox 首頁去,找到 Firefox 下載次數(網頁右邊欄最下方的數字),在上頭按下右鍵,於快捷選單中選擇 View XPath。此時 XPath Checker 會開啟一個新視窗,其中 XPath 欄位包含方才所選節點的 XPath 陳述式: id('download-count')

+

+ 在 XSLT 的 <template> 元素中加上一個 <value-of> 元素,其中 select 屬性便設為此 XPath 陳述式,如下:

+
<?xml version="1.0" encoding="UTF-8"?>
+<generator xmlns="http://www.mozilla.org/microsummaries/0.1"
+           name="Firefox 下載計數">
+  <template>
+    <transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
+      <output method="text"/>
+      <template match="/">
+        <value-of select="id('download-count')"/>
+      </template>
+    </transform>
+  </template>
+</generator>
+
+

+ 加上文字

+

+ 為了在即時摘要中加上 Fx 下載數: 這段文字,我們必須將 <text> 元素放到 <template> 元素中文字該出現的地方。以下範例便放進一個內容為 Fx 下載數:<text> 元素:

+
<?xml version="1.0" encoding="UTF-8"?>
+<generator xmlns="http://www.mozilla.org/microsummaries/0.1"
+           name="Firefox 下載計數">
+  <template>
+    <transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
+      <output method="text"/>
+      <template match="/">
+        <text>Fx 下載數: </text>
+        <value-of select="id('download-count')"/>
+      </template>
+    </transform>
+  </template>
+</generator>
+
+

+ 此處須留心 XSLT 標籤之間的空白字元並不會出現在輸出結果中,不像 HTML 會合併顯示為一個空格,所以要在字串後多加上一個空白以便區隔下載次數及字串。

+

+ 這麼一來,這個轉換 Spread Firefox 首頁為即時摘要的 XSLT 樣式便完成了。

+

+ 指定摘要來源的適用範圍

+

+ 摘要來源的轉換樣式已大工告成,接下來要指定此樣式適用的網頁。如果我們是 Spread Firefox 的網站管理員,可以在網頁上的 <head> 元素中直接加入 <link rel="microsummary"> 標籤,以便指定此網頁對應的摘要來源:

+
<head>
+  ...
+  <link rel="microsummary" href="path/to/our/generator.xml">
+</head>
+
+

+ 不過,由於我們並非該站網管,所以就得在檔案中規定此摘要來源的適用網頁,然後把摘要來源檔放到網路上供人下載。為了要指定適用網頁範圍,我們在 <generator> 元素中放上 <pages> 元素:

+
<?xml version="1.0" encoding="UTF-8"?>
+<generator xmlns="http://www.mozilla.org/microsummaries/0.1"
+           name="Firefox 下載計數">
+  <template>
+    <transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
+      <output method="text"/>
+      <template match="/">
+        <text>Fx 下載數: </text>
+        <value-of select="id('download-count')"/>
+      </template>
+    </transform>
+  </template>
+  <pages>
+  </pages>
+</generator>
+
+

+ <pages> 元素中可以放進多個 <include><exclude> 元素。元素正如其名,<include> 元素能以規則運算式(regular expression)指定適用網頁,而 <exclude> 元素則以規則運算式指定不適用網頁。

+

+ 若無另加規定,則摘要來源預設不適用所有網頁。也就是說,你必須明確指定摘要來源之適用範圍,但如無必要可不必以 <exclude> 排除其他網頁。

+

+ 此處加上個 <include> 元素指定 Spread Firefox 首頁為適用範圍:

+
<?xml version="1.0" encoding="UTF-8"?>
+<generator xmlns="http://www.mozilla.org/microsummaries/0.1"
+           name="Firefox 下載計數">
+  <template>
+    <transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
+      <output method="text"/>
+      <template match="/">
+        <text>Fx 下載數: </text>
+        <value-of select="id('download-count')"/>
+      </template>
+    </transform>
+  </template>
+  <pages>
+    <include>http://(www\.)?spreadfirefox\.com/(index\.php)?</include>
+  </pages>
+</generator>
+
+

+ 不熟悉規則運算式的話,可以參考建立即時摘要的規則運算式一文。

+

+ 安裝即時摘要來源

+

+ 現在萬事俱備,只差讓人能下載此摘要來源的機制。我們得先將摘要來源檔上傳到網路,接著再以一段 JavaScript 連結呼叫 Firefox 的 window.sidebar.addMicrosummaryGenerator() 方法以便下載安裝。

+

+ 舉例而言,如果摘要來源檔的位置在 http://people.mozilla.com/~myk/micro...-generator.xml,而我們希望使用者能從 http://people.mozilla.com/~myk/micro...ial/index.html 上下載安裝,就應該在 index.html 網頁上加上此段程式碼:

+
 <button onclick="window.sidebar.addMicrosummaryGenerator('http://people.mozilla.com/~myk/microsummaries/tutorial/sfx-generator.xml')">安裝 SpreadFirefox 首頁即時摘要來源!</button>
+
+

+ 不過,如果是不支援即時摘要的瀏覽器,按下此按鈕之後會產生 JavaScript 錯誤,所以我們應該幫使用者點忙、檢查他們的瀏覽器是否支援即時摘要,若不支援則顯示說明訊息:

+
<script>
+  const warning = "不好意思ㄋㄟ,你得用支援即時摘要的瀏覽器 (如 Firefox 2.0) 才能安裝這玩意喔!";
+  function addGenerator(url) {
+    if (typeof window.sidebar == "object" &&
+        typeof window.sidebar.addMicrosummaryGenerator == "function")
+      window.sidebar.addMicrosummaryGenerator(url);
+    else
+     alert(warning);
+  }
+</script>
+<button onclick="addGenerator('http://people.mozilla.com/~myk/microsummaries/tutorial/sfx-generator.xml')">安裝 SpreadFirefox 首頁即時摘要來源!</button>
+
+

+ 附帶一提:

+ +

+ 結語

+

+ 現在你應該瞭解怎麼製作能顯示 Firefox 下載次數的即時摘要了。試著將 Spread Firefox 首頁存為書籤,然後在新增書籤對話方塊中按下名稱下拉式選單、選擇即時標題之後的項目即可。

+

+ 其他關於即時摘要的相關資訊,可以參考 Microsummaries 主題頁

diff --git a/files/zh-tw/archive/mozilla/drag_and_drop/index.html b/files/zh-tw/archive/mozilla/drag_and_drop/index.html new file mode 100644 index 0000000000..b963b08118 --- /dev/null +++ b/files/zh-tw/archive/mozilla/drag_and_drop/index.html @@ -0,0 +1,142 @@ +--- +title: Drag and Drop +slug: Archive/Mozilla/Drag_and_drop +tags: + - NeedsTranslation + - TopicStub + - XUL +translation_of: Archive/Mozilla/Drag_and_drop +--- +

{{ Next("Drag and Drop JavaScript Wrapper") }}

+

{{ deprecated_header("gecko1.9.1") }}

+
+ As of Gecko 1.9.1 (Firefox 3.5), these APIs are officially deprecated the newer, simpler, portable API should be used in their place.
+

This section describes how to implement objects that can be dragged around and dropped onto other objects.

+

The Drag and Drop Interface

+

Many user interfaces allow one to drag particular objects around within the interface. For example, dragging files to other directories, or dragging an icon to another window to open the document it refers to. Mozilla and XUL provide a number of events that can handle when the user attempts to drag objects around.

+

A user can start dragging by holding down the mouse button and moving the mouse. The drag stops when the user releases the mouse. Event handlers are called when the user starts and ends dragging, and at various points in-between.

+

Mozilla implements dragging by using a drag session. When a user requests to drag something that can be dragged, a drag session should be started. The drag session handles updating the mouse cursor and where the object should be dropped. If something cannot be dragged, it should not start a drag session. Because the user generally has only one mouse, only one drag session is in use at a time.

+

Note that drag sessions can be created from within Mozilla itself or from other applications. Mozilla will translate the data being dragged as needed.

+

The list below describes the event handlers that can be called, which may be placed on any element. You only need to put values for the handlers where you need to do something when the event occurs.

+
+
+ ondrag {{ Fx_minversion_inline(3) }}
+
+ Called periodically throughout the drag and drop operation.
+
+ ondraggesture 
+
+ Called when the user starts dragging the element, which normally happens when the user holds down the mouse button and moves the mouse. The script in this handler should set up a drag session.
+
+ ondragstart {{ Fx_minversion_inline(3) }} 
+
+ An alias for ondraggesture; this is the HTML 5 spec name for the event and may be used in HTML or XUL; however, for backward compatibility with older versions of Firefox, you may wish to continue using ondraggesture in XUL.
+
+ ondragover 
+
+ This event handler is called for an element when something is being dragged over top of it. If the object can be dropped on the element, the drag session should be notified.
+
+ ondragenter 
+
+ Called for an element when the mouse pointer first moves over the element while something is being dragged. This might be used to change the appearance of the element to indicate to the user that the object can be dropped on it.
+
+ ondragexit 
+
+ Called for an element when the mouse pointer moves out of an element while something is being dragged. The is also called after a drop is complete so that an element has a chance to remove any highlighting or other indication.
+
+ ondragdrop 
+
+ This event handler is called for an element when something is dropped on the element. At this point, the user has already released the mouse button. The element can simply ignore the event or can handle it some way, such as pasting the dragged object into itself.
+
+ ondragend {{ Fx_minversion_inline(3) }} 
+
+ Called when the drag operation is finished.
+
+

There are two ways that drag and drop events can be handled. This first involves using the drag and drop XPCOM interfaces directly. The second is to use a JavaScript wrapper object that handles some of this for you. The code for this wrapper can be found in a file named {{ Source("toolkit/content/nsDragAndDrop.js nsDragAndDrop.js") }} which is contained in the widget-toolkit (or global) package.

+

XPCOM Drag and Drop interfaces

+

Two interfaces are used to support drag and drop. The first is a drag service, nsIDragService and the second is the drag session, nsIDragSession.

+

The nsIDragService is responsible for creating drag sessions when a drag starts, and removing the drag session when the drag is complete. The function invokeDragSession should be called to start a drag inside an ondraggesture event handler. Once this function is called, a drag has started.

+

The function invokeDragSession takes four parameters, as described below:

+
invokeDragSession(element,transferableArray,region,actions)
+
+
+
+ element 
+
+ A reference to the element that is being dragged. This can be retrieved by getting the property event.target during the event handler.
+
+ transferableArray 
+
+ An array of nsITransferable objects, one for each item being dragged. An array is used because you might want to drag several objects at once, such as a set of files.
+
+ region 
+
+ A region used for feedback indication. This should usually be set to null.
+
+ actions 
+
+ The actions that the drag uses. This should be set to one of the following constants, or several added together. The action can be changed during the drag depending on what is being dragged over.
+
+
+
+ nsIDragService.DRAGDROP_ACTION_NONE 
+
+
+
+ Used to indicate that no drag is valid.
+
+ nsIDragService.DRAGDROP_ACTION_COPY 
+
+ The item being dragged should be copied to its dropped location.
+
+ nsIDragService.DRAGDROP_ACTION_MOVE 
+
+ The item being dragged should be moved to its dropped location.
+
+ nsIDragService.DRAGDROP_ACTION_LINK 
+
+ A link (or shortcut or alias) to the item being dragged should be created in the dropped location.
+
+
+
+

The interface {{ interface("nsIDragService") }} also provides the function getCurrentSession which can be called from within the drag event handlers to get and modify the state of the drag. The function returns an object that implements {{ interface("nsIDragSession") }}.

+

The interface nsIDragSession is used to get and set properties of the drag that is currently occuring. The following properties and methods are available:

+
+
+ canDrop 
+
+ Set this property to true if the element the mouse is currently over can accept the object currently being dragged to be dropped on it. Set the value to false if it doesn't make sense to drop the object on it. This should be changed in the ondragover and ondragenter event handlers.
+
+ dragAction 
+
+ Set to the current action to be performed, which should be one or more of the constants described earlier. This can be used to provide extra feedback to the user.
+
+ numDropItems 
+
+ The number of items being dragged. For example, this will be set to 5 if five bookmarks are being dragged.
+
+ getData(transfer,index) 
+
+ Get the data being dragged. The first argument should be an nsITransferable object to hold the data. The second argument, index, should be the index of the item to return.
+
+ sourceDocument 
+
+ The document where the drag started.
+
+ sourceNode 
+
+ The DOM node where the drag started.
+
+ isDataFlavorSupported(flavor) 
+
+ Returns true if the data being dragged contains data of the specified flavor.
+
+

{{ Next("Drag and Drop JavaScript Wrapper") }}

+
+

Original Document Information

+ +
diff --git a/files/zh-tw/archive/mozilla/firefox/index.html b/files/zh-tw/archive/mozilla/firefox/index.html new file mode 100644 index 0000000000..c87802d82f --- /dev/null +++ b/files/zh-tw/archive/mozilla/firefox/index.html @@ -0,0 +1,8 @@ +--- +title: Firefox +slug: Archive/Mozilla/Firefox +translation_of: Archive/Mozilla/Firefox +--- +

In progress. Out-of-date information about the Firefox project.

+ +

{{SubpagesWithSummaries}}

diff --git a/files/zh-tw/archive/mozilla/firefox/using_microformats/index.html b/files/zh-tw/archive/mozilla/firefox/using_microformats/index.html new file mode 100644 index 0000000000..6e7260a691 --- /dev/null +++ b/files/zh-tw/archive/mozilla/firefox/using_microformats/index.html @@ -0,0 +1,78 @@ +--- +title: Firefox 3 Using Microformat +slug: Archive/Mozilla/Firefox/Using_microformats +translation_of: Archive/Mozilla/Firefox/Using_microformats +--- +

Microfotmats 讓網站可以提供語意化的資料給瀏覽器,這是為了讓瀏覽器不需知道如何剖析(parse)文件就可以呈現網頁資訊的摘要。Firefox 3 實做了一個全域的 microformats 物件(global microformats object) 以提供 microformats 的存取。這個物件與其 API 簡化了尋找、讀取 microfotmats 的工作。

+

載入 microformats API

+

Microformats 物件是用 Firefox 3 新加入的 JavaScript script loader 建立的。要使用這個 API,你首先需要載入這個物件:

+
Components.utils.import("resource://gre/modules/Microformats.js");
+

一旦載入了這個 microformats API,你就可以使用列在這裡的方式來管理 microformats,詳見 Parsing microformats in JavaScript

+

預先定義好的 microformats

+

Firefox 3 實做了好幾種常見的 microformats,以下是其定義:

+
+
+ adr
+
+ 代表住址 (例如一條街或郵寄住址)。
+
+ geo
+
+ 代表使用緯度、經度表示的地理位置。
+
+ hCard
+
+ 代表個人的聯絡方式。
+
+ hCalendar
+
+ 代表行事曆上的一個約會。
+
+ tag
+
+ 用於新增標籤給其他 microformats。 +

方式

+

add()

+

新增一個 microformat 到一個 microformat module。

+

如果指定的名稱和現存的 microformat 相同,這個原來存在的 microformat 會被新增的所取代。

+
add(name, definition);
+
Parameters
+

 

+
+
+ name
+
+ 新增到 microformat module 的 microformat 名稱。
+
+ definition
+
+ 描述 microformat 的 JavaScript 結構,詳見 Describing microformats in JavaScript
+
+

count()

+

計算文件中符合我們指定的類型的 microformats 的數量

+
numMicroformats = Microformats.count(name, rootElement, recurseFrames)
+
Parameters
+

 

+
+
+ name
+
+ 要計算的 microformat 名稱。
+
+ rootElement
+
+ 可加可不加。代表由此開始搜尋的 DOM 元素,預設是 content.document (換句話說,也就是整份文件)。
+
+ recurseFrames
+
+ 可加可不加。如果是 true,搜尋時會連 child frames 一起搜尋,預設是 true
+
+
回傳值 (Return value)
+

是一個整數值,代表符合指定類型的 microformats 數量。

+

debug()

+

get()

+

getNamesFromNode()

+

getParent()

+

isMicroformat()

+
+
diff --git a/files/zh-tw/archive/mozilla/index.html b/files/zh-tw/archive/mozilla/index.html new file mode 100644 index 0000000000..0acec76e6d --- /dev/null +++ b/files/zh-tw/archive/mozilla/index.html @@ -0,0 +1,10 @@ +--- +title: Archived Mozilla and build documentation +slug: Archive/Mozilla +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive/Mozilla +--- +

These articles are archived, obsolete documents about Mozilla, Gecko, and the process of building Mozilla projects.

+

{{SubpagesWithSummaries}}

diff --git a/files/zh-tw/archive/mozilla/marketplace/apis/index.html b/files/zh-tw/archive/mozilla/marketplace/apis/index.html new file mode 100644 index 0000000000..ead011ed63 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/apis/index.html @@ -0,0 +1,36 @@ +--- +title: 公用程式函式庫與 API +slug: Archive/Mozilla/Marketplace/APIs +translation_of: Archive/Mozilla/Marketplace/APIs +--- +
+

如果要將 Firefox Marketplace 的功能寫進 App 與 Web 頁面之中,就必須透過 Marketplace Utility Libraries、Web API、Marketplace API。本文將說明上述方式、使用時機,並提供進一步的說明文件連結。

+
+ +

Marketplace Utility Library

+ +

Marketplace Utility Library 可讓開發者避開複雜的 Web API 與 Marketplace API,進而簡化每天的程式撰寫作業。目前雖然只有 1 組函式庫,但隨著 Marketplace 功能不斷擴充,將會陸續提供其他函式庫:

+ + + +

Web API

+ +

Marketplace App 必須透過 Web API 才能提供特定功能:

+ + + +

Marketplace API

+ +

針對大多數的一般 App 撰寫需要,其實並用不到 Marketplace API。但某些 Activities (如設立自己的 App 商店) 就需要此 API。但根據開發者自己的需求,也許 Marketplace Utility Library 還是比較好用。

+ +

Marketplace API 的相關說明文件,均已置於 readthedocs.org 的這個網址上。如果你需要進一步了解這些 API,亦可加入 dev-marketplace 郵件群組。

+ +
+

Marketplace API 說明文件,均記錄了正在開發中的 Marketplace API。所以內含的 API 細節尚未公開於 Marketplace 之上。

+
+ +

 

diff --git a/files/zh-tw/archive/mozilla/marketplace/faq/index.html b/files/zh-tw/archive/mozilla/marketplace/faq/index.html new file mode 100644 index 0000000000..ba8aa7493a --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/faq/index.html @@ -0,0 +1,154 @@ +--- +title: Firefox Marketplace 常見問題 +slug: Archive/Mozilla/Marketplace/FAQ +translation_of: Archive/Mozilla/Marketplace/FAQ +--- +
+

本篇文章將解答 Firefox Marketplace 多個常見的發佈問題。

+
+ +

帳戶管理

+ +

我該如何變更開發者帳戶的資訊?

+ +

進入 Firefox Marketplace 並登入自己的帳戶,將滑鼠游標置於齒輪圖示 (即設定選單) 之上,點選「Edit Account Settings」即可。

+ +

我該如何變更開發者付款的資訊?

+ +

進入 Firefox Marketplace 並登入自己的帳戶,將滑鼠游標置於齒輪圖示 (即設定選單) 之上。點選「My Apps」之後,找到你想變更付款資訊的 App,再點擊「Set Up Payments」即可。

+ +

我該到哪找到自己的銷售報表與對帳資訊?

+ +

進入 Firefox Marketplace 並登入自己的帳戶,將滑鼠游標置於齒輪圖示 (即設定選單) 之上。點選「My Apps」之後,找到你需要相關資料的 App 即可。

+ +

如果我們是多人組成的開發團隊或公司,該如何管理帳戶資訊?

+ +

進入 Firefox Marketplace 並登入自己的帳戶,將滑鼠游標置於齒輪圖示 (即設定選單) 之上。點選「My Apps」之後,找到你想變更團隊細節的 App 即可。

+ +

我該如何重新命名 App?

+ +

如果你想在 Marketplace 審查之後變更 App 的名稱,就必須再次提交 App 通過審查才行。請參閱更新 App 以進一步了解。

+ +

我該如何進入 Firefox Marketplace 除錯設定?

+ +

登入之後進入 Firefox Marketplace,在搜尋列中輸入「:debug」。

+ +

接著你就會看到自己 Marketplace 帳戶的除錯畫面。你可在此畫面中清除 Marketplace 網站、提交記錄、檢視設定、活動記錄等等相關的 cookies 與 localStorage。

+ +

如果我把 App 提交到自己目前所在地以外的地方,我該如何檢視這些 App?

+ +

如果你自己目前所在之處或擁有手機 SIM 卡的地區,和你 App 發佈地區並不相同,則可透過下列步驟檢視該 App:

+ +
    +
  1. 進入 Firefox Marketplace 除錯設定 (可參閱上一題)。
  2. +
  3. 透過「Region Override」與「Carrier Override」選項,選出自己的所在地區或營運商 (只要選完就會立刻更新這些設定)。
  4. +
  5. 重新整理/載入 Marketplace。
  6. +
+ +

你可以先試著為 App 隨便選個分類,確認系統更新過了相關設定。

+ +

App 提交與審查程序

+ +

我該如何提交新的 App?

+ +

可參閱《將 App 提交至 Firefox Marketplace》中的詳細步驟。

+ +

App 核准程序為何?

+ +

請參閱《Marketplace 審查準則》以了解審查程序的相關準則。

+ +

是否有快速審查程序?所採用的準則是否不同?

+ +

如果開發者正好有絕佳的商機需求,或必須儘快釋出重要修復檔案,即可申請快速審查 App。若需 Marketplace 進行快速審查,可寄發電子郵件到 mozilla.appreview,或加入 irc.mozilla.org 中的「#app-reviewers」IRC 頻道。我們會儘快完成快速審查,但不保證審查人員能配合任何特定時間。

+ +
+

注意:對 App 審查團隊來說,「App 快速審查」也算是額外的工作之一。若你有興趣協助我們的審查作業,歡迎透過 Firefox App 審查者申請表申請。

+
+ +

我的 App 需要遵守內容政策嗎?

+ +

當然!請參閱《Marketplace 審查準則》中的〈內容〉一章,了解 Mozilla 的內容政策。

+ +

如果 App 遭退回或移除,我該如何上訴?

+ +

如果想為遭退回的 App 上訴,則可直接回覆 App 退回通知的電子郵件 (所有 Marketplace 通知郵件的末端,均告知開發者可直接回覆該電子郵件以提出問題);或可透過 irc.mozilla.org 上的「#app-reviewers」IRC 頻道向我們溝通。

+ +

付款

+ +

Firefox Marketplace 如何運作付款作業?

+ +

Mozilla 提供多種付款方式,包含付費 App、免費增值 (Freemium) App、App 內部付費機制 (In-app payments)。若需進一步資訊,可參閱《Marketplace Payments guide》。

+ +

開發者收益的拆帳方式為何?

+ +

開發者將收到預扣增值稅 (Value Added Tax,VAT) 與費用之後金額的 70%。我們先假設美金訂價 $.99 (Tier 10),歐元訂價則為 €.89;而增值稅率為 20% (根據英國標準增值稅率) 為例,則預扣增值稅之後的價格為 €.74,亦約為 $.99 (有時匯兌之後的價格點數可能變高,有時也會變低)。開發者最後將收到 €.74 的七成金額。

+ +

若需價格點數與訂價的相關資訊,可參閱《制定 App 的價格》。

+ +

Mozilla 也會拆得一部分的帳嗎?

+ +

會。為了維持 Firefox Marketplace 的運作、持續強化 App 平台、支付每次購買行為所產生的交易費用。Mozilla 將收取預扣增值稅後金額的三成,再拆分給 Mozilla、行動網路營運商、付款服務供應商 (如 Bango) 共三方收取。

+ +

我一定要使用 Firefox Marketplace 的付款系統嗎?

+ +

若要讓消費者從 Firefox Marketplace 下載付費 App,就必須使用 Firefox Marketplace 付款系統。我們不會要求 In-app payments 也同樣使用 Marketplace 付款系統,但目前 Firefox OS 中僅建構了 navigator.mozPay() 函式 (用於 In-app payments),而該函式就採用 Firefox Marketplace 付款系統。我們以後會讓開發者針對 In-app payments 選用任何付款系統。

+ +

將自己的 App 放上 Firefox Marketplace 後的交易費用?

+ +

需支付預扣稅額訂價的 30%。換句話說,因為 Marketplace 提供的含稅價格點數已經納入了增值稅 (針對需課增值稅的地區),所以在完成交易之後隨即扣除增值稅,讓開發者取得訂價金額的 70%。

+ +

我需要自行設定銷售稅或增值稅率嗎?

+ +

不用。針對需課稅的地區,Marketplace 的價格點數均已包含了增值稅。而銷售稅的部分,均另由付款服務供應商列入帳單之中。

+ +

我該如何分開付款?

+ +

Firefox Marketplace 目前尚未提供分開付款的功能。

+ +

我能提交免費 App 嗎?會向我收費嗎?

+ +

當然。歡迎開發者在 Firefox Marketplace 中提交免費 App,且 Mozilla 不會對免費 App 收取任何費用。

+ +

付費 App 還能搭配 In-app payments 嗎?

+ +

可以。

+ +

退款程序為何?

+ +

根據付款方式的不同,退款程序可能由電信營運商、信用卡公司,或付款服務供應商 (如 Bango) 進行。若消費者選用電信帳單代繳的方式,則依照電信營運商的退款政策處理。目前尚無營運商提供退款服務。Bango 則是針對信用卡提供前端支援服務。任何退款均將從開發者的收益之中扣除。

+ +

服務條款與開發者協議均提供了退款政策。一般來說,Marketplace 不會支付退款,但會要求 Bango 進行退款程序。若消費者選用電信帳單代繳的方式,就必須要求電信營運商退款並修正電信帳單。

+ +

如何處理詐騙的購買行為?

+ +

尚待完善討論。

+ +

Marketplace 如何處理多樣的幣別?

+ +

根據消費者所選的所在地區,即顯示該地區的預設幣別。另針對付款作業,若消費者目前身處於原本設定的地區之外,就會根據他們收取帳單的地區 (即 SIM 卡所在地),或根據其所在位置收款。如此可避免詐欺行為。

+ +

付款時程為何?開發者多久能收到銷售 App 的應得款項?

+ +

根據付款服務供應商而有所不同;而目前仍由 Bango 負責所有地區的付款作業。開發者可直接與 Bango 洽詢,且每個月均會收到自行對帳用的發票。因為行動服務營運商必須向消費者收取並匯出相關款項,所以支付日期也各有差異。各個國家又會有所不同。而消費者如果採用信用卡付款,都能讓開發者迅速收取款項。若選用電信帳單代繳方式,可能需時 30 ~ 90 天不等。

+ +

開發者應如何處理退款?

+ +

請參閱《Marketplace payments》中的〈Refunds〉一章。

+ +

Firefox Marketplace 可進行臨時銷售或變更訂價嗎?

+ +

我們正規劃價格點數的變更功能,讓開發者能針對「試用期」或「正式銷售」而設定不同的價格。

+ +

開發者能銷售 Firefox 的附加元件 (add-ons) 嗎?

+ +

目前 Firefox Marketplace 僅供銷售 App。我們希望很快就能提供其他內容的銷售服務。

+ +

技術問題

+ +

誰將可托管 App?

+ +

開發者可在自己的伺服器上托管 App 的所有檔案。但將 App 提交到 Firefox Marketplace 之後,就必須提供 App 的 manifest 檔案網址,以利 Marketplace 進行讀取並檢驗。開發者另可上傳圖示、截圖等元素,以能順利在 Firefox Marketplace 推銷自己的 App。可參閱《將 App 提交至 Firefox Marketplace》進一步了解。

+ +

如何從 App 直接啟動 Marketplace?

+ +

開發者可透過 Web Activities,從自己的 App 或網站啟動 Marketplace。而 Marketplace 所支援的 activities 均記錄於 Github 之上

diff --git a/files/zh-tw/archive/mozilla/marketplace/index.html b/files/zh-tw/archive/mozilla/marketplace/index.html new file mode 100644 index 0000000000..5ce3b790b0 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/index.html @@ -0,0 +1,159 @@ +--- +title: Firefox Marketplace +slug: Archive/Mozilla/Marketplace +tags: + - Apps + - B2G + - Firefox OS + - Marketplace + - Mobile + - NeedsTranslation + - TopicStub +translation_of: Archive/Mozilla/Marketplace +--- +
Firefox Marketplace 為開放且非專利的線上商城,針對以 HTML5 所撰寫的 Web App 所建構。若開發者準備在 Firefox Marketplace 上發佈 App,均可於此專區中找到相關資訊。另有其他指南可帶領你成功打造 App、提供其他選項、將自己的心血轉為實質收益、發佈\更新 App,更有函式庫與 API 可確實發揮 Marketplace 的特色。
+ +
+
+

透過標準的 Web 技術、語言、工具,Firefox Marketplace 可供你發佈免費\付費的 Open Web App。這些可為封裝式 (Packaged) App,於 Firefox 中執行;或可為托管\架設式 (Hosted) App,置於你自己的伺服器之上。已上架的 App 則可用於 Firefox 桌機版、Android 裝置、Firefox OS 手機。而使用者可透過 App 的精選、分類、搜尋等區塊,輕鬆找到自己喜愛的 App。接著就能立刻安裝免費 App,或透過目前持續成長中的信用卡付款\電信帳單代收的功能,購買付費 App。

+ +
+
+

準備發佈 App

+ +
+
不論你撰寫 App 是純粹好玩或想創造收益,你都會希望有許多人發現、使用、享受你的作品。本章節將解釋該如何拓展能見度,並建立消費者社群。
+
+ +

App 發佈選項

+ +
+
到底要用封裝式或托管\架設式 App?了解應如何發表自己 App 的內容。且除了 Firefox OS 之外,亦可讓 App 躍上 Android 裝置與桌上型電腦。
+
建立自己的 App 商城
+
你不一定要透過 Firefox Marketplace 發佈自己的 App。了解應如何建立自己的 App 商城,或為其他開發者的 App 建立商城。
+
+ +

轉為實質收益

+ +
+
如果你負責撰寫 App,則可透過本章節了解 Open Web App 與 Firefox Marketplace 所提供的收益選項。另亦提供 App 內付款 (In-app payments) 的詳細資訊。
+
+
+ +
+

發佈 App

+ +
+
快向世界發佈你的 App。了解應如何讓 Firefox Marketplace 發佈 App,包含 App 提交程序、審查程序、更新程序、了解上架後的效益,並觀看消費者的反應意見。
+
+ +

App 開發工具

+ +
+
Firefox Marketplace 函式庫與 API
+
概略了解目前可用的函式庫與 API,為自己在 Marketplace 上的 App 添增功能。
+
Firefox OS 的「應用程式管理員 (App Manager)」
+
從桌上型電腦為 Open Web App 測試、佈署、除錯的主要工具。
+
App 開發工具
+
完整工具清單,可供你有效率的開發 Open Web App 並樂在其中。
+
+
+
+
+
+ + + +
    +
  1. 準備發佈 App + +
      +
    1. 介紹
    2. +
    3. 決定所要撰寫的東西
    4. +
    5. 了解目標消費者
    6. +
    7. 選擇自己的營運模式
    8. +
    9. 撰寫高品質 App
    10. +
    11. 當地語系的 App
    12. +
    13. 推銷自己的 App
    14. +
    15. 建立自己的群組
    16. +
    +
  2. +
  3. 發佈選項 +
      +
    1. 介紹
    2. +
    3. 封裝式 (Packaged) App
    4. +
    5. 托管\架設式 (Hosted) App
    6. +
    7. 要封裝抑或托管?
    8. +
    9. 適合 Android 的 Open Web App
    10. +
    11. 適合桌上型電腦的 Open Web App
    12. +
    13. 自行發佈 App
    14. +
    15. 建立自己的商城
    16. +
    +
  4. +
  5. 產生實質收益 +
      +
    1. 介紹
    2. +
    3. 用自己的 App 創造收益
    4. +
    5. App 付款指南
    6. +
    7. 應用程式內付款 (In-app payments) +
        +
      1. 介紹
      2. +
      3. 透過 mozPay
      4. +
      5. 透過 fxPay
      6. +
      +
    8. +
    9. 驗證收據
    10. +
    11. App 定價表
    12. +
    13. 付款服務狀態
    14. +
    +
  6. +
  7. App 發佈概述 +
      +
    1. 介紹
    2. +
    3. 提交作業檢查清單
    4. +
    5. Marketplace 審查準則
    6. +
    7. 為 App 添增子網域
    8. +
    9. 策略與指南 +
        +
      1. 介紹
      2. +
      3. Marketplace 截圖準則
      4. +
      5. 隱私權政策
      6. +
      7. App 測試與疑難排解
      8. +
      +
    10. +
    +
  8. +
  9. 提交 App +
      +
    1. 概述
    2. +
    3. Step 1:登入
    4. +
    5. Step 2:上傳
    6. +
    7. Step 3:列出細節
    8. +
    9. Step 4:後續步驟
    10. +
    11. Step 5:App 評分
    12. +
    13. Step 6:制定 App 的價格 +
        +
      1. 介紹
      2. +
      3. 付款帳戶
      4. +
      5. Bango
      6. +
      7. Boku
      8. +
      9. 用「升級」的方式推廣
      10. +
      11. fxPay 的 App 產品
      12. +
      +
    14. +
    15. Step 7:定義團隊成員
    16. +
    17. Step 8:檢視列表
    18. +
    19. Step 9:編輯其他本地化的內容
    20. +
    +
  10. +
  11. 管理並更新已發佈的 App +
      +
    1. 介紹
    2. +
    3. App 的狀態
    4. +
    5. 更新 App
    6. +
    7. App 狀態
    8. +
    +
  12. +
  13. 函式庫與 API
  14. +
  15. Firefox Marketplace 常見問題
  16. +
diff --git a/files/zh-tw/archive/mozilla/marketplace/marketplace_apis/index.html b/files/zh-tw/archive/mozilla/marketplace/marketplace_apis/index.html new file mode 100644 index 0000000000..372284a029 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/marketplace_apis/index.html @@ -0,0 +1,69 @@ +--- +title: Firefox Marketplace API +slug: Archive/Mozilla/Marketplace/Marketplace_APIs +translation_of: Archive/Mozilla/Marketplace/Marketplace_APIs +--- +
+

提供 Firefox Marketplace API 的主要參考文章,可協助你進行 App 提交作業、設定 App 的付款帳戶,及其他更多相關重要步驟。

+
+
+
+
+
+ Marketplace 公用程式函式庫
+
+ 可協助你順利進行 Firefox Marketplace 的相關作業。你可將內含的 JavaScript 函式庫用於自己的 App 之內,以輕鬆處理應用程式內付款 (In-app payments) 並驗證付款收據。
+
+ Submission API
+
+ Submission API 可讓你檢驗並更新 App,並在安裝之前提取 App 的可用資訊。
+
+ Payment API
+
+ Payment API 可讓你取得 In-app payments 的資訊,以及不同國家的訂價情形。
+
+ 其他 Marketplace API
+
+ Firefox Marketplace API 的完整說明文件。
+
+
+
+
Tools for app developers
+ +
Technology reference documentation
+ +
Getting help from the community
+

If you still aren't sure how to do what you're trying to get done, feel free to join the conversation!

+ +

Don't forget about the netiquette...

+
+
+

 

diff --git a/files/zh-tw/archive/mozilla/marketplace/monetization/app_payments_guide/index.html b/files/zh-tw/archive/mozilla/marketplace/monetization/app_payments_guide/index.html new file mode 100644 index 0000000000..a1f464f224 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/monetization/app_payments_guide/index.html @@ -0,0 +1,48 @@ +--- +title: 建構付費 App +slug: Archive/Mozilla/Marketplace/Monetization/App_payments_guide +translation_of: Archive/Marketplace/Monetization/App_payments_guide +--- +
+

Firefox Marketplace 的消費者有兩種需要付款的情形:
+ 1). 購買 App 需付款 (付費 App)
+ 2). 在安裝 App 之後另外購買某樣東西需付款;即 App 內付款機制 (In-app payment)
+ 本文即提供付費 App 所需的程式碼與作業流程,另外將有另一篇文章說明 In-app payments

+
+

選擇封裝方式 (Packaged Hosted)

+

在了解付款方式之前,先決定自己的 App 應該是封裝式 (Packaged),或架設/托管式 (Hosted)。如果想處理為封裝式 App,就必須遵守內容安全政策 (Content Security Policy,CSP)。可參閱下列說明以進一步了解。

+ +

建構付費 App

+
+

任何 App 都能設定為付費 App,也都能是封裝式或架設/托管式 App;完全不需特別的權限。在將 App 提交到 Firefox Marketplace 時,只要勾選使其成為付費 App 即可。但開發者需讓 App 驗證自己的銷售收據,才能確認收到帳款。接下來就是應進行的步驟。

+

installs_allowed_from 添增到 manifest.webapp

+

首先必須將 installs_allowed_from 欄位添增到 App 的 manifest 檔案中。另給予如下的 Firefox Marketplace 網址:

+
"installs_allowed_from": [ "https://marketplace.firefox.com" ]
+

這個步驟屬於收據驗證作業的一部分,才能讓系統確認 App 來自於收款的商店。

+
+

驗證收據

+

只要從 Marketplace 售出 App 之後,隨即會產生該筆銷售的數位收據。開發者應該為自己的 App 植入程式碼,讓 App 執行時能一併驗證銷售收據。我們強烈建議,但不強制驗證收據。此查核作業可避免消費者安裝了 App 卻未付費。

+

Mozilla 另負責維護 JavaScript 輔助函式庫 (Helper),即所謂的 receiptverifier,只要少量程式碼即可驗證收據。只要將下列 receiptverifier 函式庫加入 App 即可:

+ +

再將下列程式碼加入 App (更改內文以符合自己的 App),即可驗證收據:

+
mozmarket.receipts.Prompter({
+  storeURL: "https://marketplace.firefox.com/app/your-app",
+  supportHTML: '<a href="mailto:you@yourapp.com">email you@yourapp.com</a>',
+  verify: true
+});
+

正常只要啟動 App 就會開始驗證收據。如果確認收據有效,即可釋放 App 的資源;反之可停止 App 執行。

+
+

注意:若要進一步建立自己的收據驗證器,可參閱驗證收據

+
+

另可參閱

+ diff --git a/files/zh-tw/archive/mozilla/marketplace/monetization/app_pricing/index.html b/files/zh-tw/archive/mozilla/marketplace/monetization/app_pricing/index.html new file mode 100644 index 0000000000..4d7c3fbc32 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/monetization/app_pricing/index.html @@ -0,0 +1,3698 @@ +--- +title: 制定 App 的價格 +slug: Archive/Mozilla/Marketplace/Monetization/App_pricing +translation_of: Archive/Marketplace/Monetization/App_pricing +--- +
+

本文將為開發者說明在 Firefox Marketplace 中制定 App 價格與收款的方法。因為開發者可能在 Firefox Marketplace 中跨國制定不同的價格,所以定價方式有點複雜。本文即提供相關資訊,如訂價、拆帳、課稅、付款方式、應收帳款、防止詐騙等等。

+
+ +

以「價格點數」定價

+ +

在 Firefox Marketplace 中,開發者必須透過固定的「價格點數 (Price point)」完成定價。開發者可選擇任一價格點數,而該價格點數隨即套用為各地區通用貨幣的等值定價。針對開發者所選定 App 或應用程式內部付費 (In-app Payments) 的販售地區,當地消費者就能透過系統得知 App 的定價。價格點數範圍從 US$0.10 (點數 1) 到 US$49.99 (點數 140)。Firefox Marketplace 中的 App 與 In-app Payments,均適用價格點數的定價方式。

+ +

範例:若 App 設定為「10」價格點數,則在流通美金的地區就是售價 US$0.99 (未含當地銷售稅);流通歐元的地區就是售價 €0.89 (已含歐洲增值稅)。在哥倫比亞的電信帳單代繳售價為 COP$2060.00 (包含哥倫比亞區的增值稅),信用卡繳款的售價則為 US$0.99。

+ +

價格點數表

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Price pointAustriaBelgiumBrazilChileColombiaCyprusEstoniaFinlandFranceGermanyGreeceHungaryIrelandItalyLatviaLithuaniaLuxembourgMaltaMexicoNetherlandsPeruPolandPortugalSlovakiaSloveniaSpainUnited KingdomUnited StatesUruguayVenezuelaRest of World
VAT/Tax included in priceunknownunknownnoyes&nbsp;(19%)yes&nbsp;(16%)unknownunknownunknownunknownyes&nbsp;(19%)yes&nbsp;(23%)yes&nbsp;(27%)unknownyes&nbsp;(22%)unknownunknownunknownunknownyes&nbsp;(16%)unknownyes&nbsp;(18%)yes&nbsp;(23%)unknownunknownunknownyes&nbsp;(21%)yes&nbsp;(20%)noyes&nbsp;(22%)yes&nbsp;(12%)no
Tier 0 + + €0 + + + + €0 + + + + $0 + + + + $0 + + + + $0 + + + + €0 + + + + €0 + + + + €0 + + + + €0 + + + + €0 + + + + €0 + + + + Ft&nbsp;0 + + + + €0 + + + + €0 + + + + €0 + + + + €0 + + + + €0 + + + + €0 + + + + $0 + + + + €0 + + + + $0 + + + + 0&nbsp;zł + + + + €0 + + + + €0 + + + + €0 + + + + €0 + + + + £0 + + + + $0 + + + + $0 + + + + $0 + + + + $0 + [1] + +
Tier 1 + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + €0.1 + [2] + + + + €0.1 + [2] + + + + Ft&nbsp;25 + [2] + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + 0.49&nbsp;zł + [2] + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + +
Tier 5 + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + €0.25 + [2] + + + + €0.25 + [2] + + + + Ft&nbsp;70 + [2] + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + $3.75 + [2] + + + + n/a + + + + n/a + + + + 0.98&nbsp;zł + [2] + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + +
Tier 7 + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + €0.4 + [2] + + + + €0.4 + [2] + + + + Ft&nbsp;135 + [2] + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + $7.51 + [2] + + + + n/a + + + + n/a + + + + 1.99&nbsp;zł + [2] + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + + + + n/a + +
Tier 10 + + €0.89 + [1] + + + + €0.89 + [1] + + + + $0.99 + [1] + + + + $0.99 + [1] + + + + $2060 + + + + €0.89 + [1] + + + + €0.89 + [1] + + + + €0.89 + [1] + + + + €0.89 + [1] + + + + €0.89 + + + + €0.89 + + + + Ft&nbsp;270 + + + + €0.89 + [1] + + + + €0.89 + [1] + + + + €0.89 + [1] + + + + €0.89 + [1] + + + + €0.89 + [1] + + + + €0.89 + [1] + + + + $15 + + + + €0.89 + [1] + + + + $0.99 + [1] + + + + 3.99&nbsp;zł + + + + €0.89 + [1] + + + + €0.89 + [1] + + + + €0.89 + [1] + + + + €0.89 + [1] + + + + £0.75 + [1] + + + + $0.99 + [1] + + + + $0.99 + [1] + + + + $0.99 + [1] + + + + $0.99 + [1] + +
Tier 20 + + €1.89 + [1] + + + + €1.89 + [1] + + + + $1.99 + [1] + + + + $1.99 + [1] + + + + $4150 + + + + €1.89 + [1] + + + + €1.89 + [1] + + + + €1.89 + [1] + + + + €1.89 + [1] + + + + €1.89 + + + + €1.89 + + + + Ft&nbsp;545 + + + + €1.89 + [1] + + + + €1.89 + [1] + + + + €1.89 + [1] + + + + €1.89 + [1] + + + + €1.89 + [1] + + + + €1.89 + [1] + + + + $30 + + + + €1.89 + [1] + + + + $1.99 + [1] + + + + 7.69&nbsp;zł + + + + €1.89 + [1] + + + + €1.89 + [1] + + + + €1.89 + [1] + + + + €1.89 + [1] + + + + £1.5 + [1] + + + + $1.99 + [1] + + + + $1.99 + [1] + + + + $1.99 + [1] + + + + $1.99 + [1] + +
Tier 30 + + €2.79 + [1] + + + + €2.79 + [1] + + + + $2.99 + [1] + + + + $2.99 + [1] + + + + $6240 + + + + €2.79 + [1] + + + + €2.79 + [1] + + + + €2.79 + [1] + + + + €2.79 + [1] + + + + €2.79 + + + + €2.79 + + + + Ft&nbsp;820 + + + + €2.79 + [1] + + + + €2.79 + [1] + + + + €2.79 + [1] + + + + €2.79 + [1] + + + + €2.79 + [1] + + + + €2.79 + [1] + + + + $45 + + + + €2.79 + [1] + + + + $2.99 + [1] + + + + 11.59&nbsp;zł + + + + €2.79 + [1] + + + + €2.79 + [1] + + + + €2.79 + [1] + + + + €2.79 + [1] + + + + £2.25 + [1] + + + + $2.99 + [1] + + + + $2.99 + [1] + + + + $2.99 + [1] + + + + $2.99 + [1] + +
Tier 40 + + €3.79 + [1] + + + + €3.79 + [1] + + + + $3.99 + [1] + + + + $3.99 + [1] + + + + $8320 + + + + €3.79 + [1] + + + + €3.79 + [1] + + + + €3.79 + [1] + + + + €3.79 + [1] + + + + €3.79 + + + + €3.79 + + + + Ft&nbsp;1095 + + + + €3.79 + [1] + + + + €3.79 + [1] + + + + €3.79 + [1] + + + + €3.79 + [1] + + + + €3.79 + [1] + + + + €3.79 + [1] + + + + $60 + + + + €3.79 + [1] + + + + $3.99 + [1] + + + + 15.49&nbsp;zł + + + + €3.79 + [1] + + + + €3.79 + [1] + + + + €3.79 + [1] + + + + €3.79 + [1] + + + + £3 + [1] + + + + $3.99 + [1] + + + + $3.99 + [1] + + + + $3.99 + [1] + + + + $3.99 + [1] + +
Tier 50 + + €4.69 + [1] + + + + €4.69 + [1] + + + + $4.99 + [1] + + + + $4.99 + [1] + + + + $10420 + + + + €4.69 + [1] + + + + €4.69 + [1] + + + + €4.69 + [1] + + + + €4.69 + [1] + + + + €4.69 + + + + €4.69 + + + + Ft&nbsp;1360 + + + + €4.69 + [1] + + + + €4.69 + [1] + + + + €4.69 + [1] + + + + €4.69 + [1] + + + + €4.69 + [1] + + + + €4.69 + [1] + + + + $75 + [1] + + + + €4.69 + [1] + + + + $4.99 + [1] + + + + 19.5&nbsp;zł + + + + €4.69 + [1] + + + + €4.69 + [1] + + + + €4.69 + [1] + + + + €4.69 + [1] + + + + £3.75 + [1] + + + + $4.99 + [1] + + + + $4.99 + [1] + + + + $4.99 + [1] + + + + $4.99 + [1] + +
Tier 60 + + €6.59 + [1] + + + + €6.59 + [1] + + + + $6.99 + [1] + + + + $6.99 + [1] + + + + $14600 + [1] + + + + €6.59 + [1] + + + + €6.59 + [1] + + + + €6.59 + [1] + + + + €6.59 + [1] + + + + €6.59 + + + + €6.59 + + + + Ft&nbsp;1900 + + + + €6.59 + [1] + + + + €6.59 + [1] + + + + €6.59 + [1] + + + + €6.59 + [1] + + + + €6.59 + [1] + + + + €6.59 + [1] + + + + $105 + [1] + + + + €6.59 + [1] + + + + $6.99 + [1] + + + + 26.99&nbsp;zł + + + + €6.59 + [1] + + + + €6.59 + [1] + + + + €6.59 + [1] + + + + €6.59 + [1] + + + + £5.25 + [1] + + + + $6.99 + [1] + + + + $6.99 + [1] + + + + $6.99 + [1] + + + + $6.99 + [1] + +
Tier 70 + + €9.49 + [1] + + + + €9.49 + [1] + + + + $9.99 + [1] + + + + $9.99 + [1] + + + + $20840 + [1] + + + + €9.49 + [1] + + + + €9.49 + [1] + + + + €9.49 + [1] + + + + €9.49 + [1] + + + + €9.49 + + + + €9.49 + + + + Ft&nbsp;2720 + + + + €9.49 + [1] + + + + €9.49 + [1] + + + + €9.49 + [1] + + + + €9.49 + [1] + + + + €9.49 + [1] + + + + €9.49 + [1] + + + + $150 + [1] + + + + €9.49 + [1] + + + + $9.99 + [1] + + + + 38.79&nbsp;zł + + + + €9.49 + [1] + + + + €9.49 + [1] + + + + €9.49 + [1] + + + + €9.49 + [1] + + + + £7.5 + [1] + + + + $9.99 + [1] + + + + $9.99 + [1] + + + + $9.99 + [1] + + + + $9.99 + [1] + +
Tier 80 + + €11.59 + [1] + + + + €11.59 + [1] + + + + $12.49 + [1] + + + + $12.49 + [1] + + + + $26070 + [1] + + + + €11.59 + [1] + + + + €11.59 + [1] + + + + €11.59 + [1] + + + + €11.59 + [1] + + + + €11.59 + + + + €11.59 + + + + Ft&nbsp;3400 + [1] + + + + €11.59 + [1] + + + + €11.59 + [1] + + + + €11.59 + [1] + + + + €11.59 + [1] + + + + €11.59 + [1] + + + + €11.59 + [1] + + + + $185 + [1] + + + + €11.59 + [1] + + + + $12.49 + [1] + + + + 48.49&nbsp;zł + + + + €11.59 + [1] + + + + €11.59 + [1] + + + + €11.59 + [1] + + + + €11.59 + [1] + + + + £9.5 + [1] + + + + $12.49 + [1] + + + + $12.49 + [1] + + + + $12.49 + [1] + + + + $12.49 + [1] + +
Tier 90 + + €14.19 + [1] + + + + €14.19 + [1] + + + + $14.99 + [1] + + + + $14.99 + [1] + + + + $31280 + [1] + + + + €14.19 + [1] + + + + €14.19 + [1] + + + + €14.19 + [1] + + + + €14.19 + [1] + + + + €14.19 + + + + €14.19 + + + + Ft&nbsp;4080 + [1] + + + + €14.19 + [1] + + + + €14.19 + [1] + + + + €14.19 + [1] + + + + €14.19 + [1] + + + + €14.19 + [1] + + + + €14.19 + [1] + + + + $225 + [1] + + + + €14.19 + [1] + + + + $14.99 + [1] + + + + 57.99&nbsp;zł + [1] + + + + €14.19 + [1] + + + + €14.19 + [1] + + + + €14.19 + [1] + + + + €14.19 + [1] + + + + £11.25 + [1] + + + + $14.99 + [1] + + + + $14.99 + [1] + + + + $14.99 + [1] + + + + $14.99 + [1] + +
Tier 100 + + €18.99 + [1] + + + + €18.99 + [1] + + + + $19.99 + [1] + + + + $19.99 + [1] + + + + $41720 + [1] + + + + €18.99 + [1] + + + + €18.99 + [1] + + + + €18.99 + [1] + + + + €18.99 + [1] + + + + €18.99 + + + + €18.99 + + + + Ft&nbsp;5450 + [1] + + + + €18.99 + [1] + + + + €18.99 + [1] + + + + €18.99 + [1] + + + + €18.99 + [1] + + + + €18.99 + [1] + + + + €18.99 + [1] + + + + $300 + [1] + + + + €18.99 + [1] + + + + $19.99 + [1] + + + + 77.49&nbsp;zł + [1] + + + + €18.99 + [1] + + + + €18.99 + [1] + + + + €18.99 + [1] + + + + €18.99 + [1] + + + + £15 + [1] + + + + $19.99 + [1] + + + + $19.99 + [1] + + + + $19.99 + [1] + + + + $19.99 + [1] + +
Tier 110 + + €23.59 + [1] + + + + €23.59 + [1] + + + + $24.99 + [1] + + + + $24.99 + [1] + + + + $52160 + [1] + + + + €23.59 + [1] + + + + €23.59 + [1] + + + + €23.59 + [1] + + + + €23.59 + [1] + + + + €23.59 + + + + €23.59 + + + + Ft&nbsp;6800 + [1] + + + + €23.59 + [1] + + + + €23.59 + [1] + + + + €23.59 + [1] + + + + €23.59 + [1] + + + + €23.59 + [1] + + + + €23.59 + [1] + + + + $375 + [1] + + + + €23.59 + [1] + + + + $24.99 + [1] + + + + 96.99&nbsp;zł + [1] + + + + €23.59 + [1] + + + + €23.59 + [1] + + + + €23.59 + [1] + + + + €23.59 + [1] + + + + £18.75 + [1] + + + + $24.99 + [1] + + + + $24.99 + [1] + + + + $24.99 + [1] + + + + $24.99 + [1] + +
Tier 120 + + €28.39 + [1] + + + + €28.39 + [1] + + + + $29.99 + [1] + + + + $29.99 + [1] + + + + $62580 + [1] + + + + €28.39 + [1] + + + + €28.39 + [1] + + + + €28.39 + [1] + + + + €28.39 + [1] + + + + €28.39 + + + + €28.39 + + + + Ft&nbsp;8170 + [1] + + + + €28.39 + [1] + + + + €28.39 + [1] + + + + €28.39 + [1] + + + + €28.39 + [1] + + + + €28.39 + [1] + + + + €28.39 + [1] + + + + $450 + [1] + + + + €28.39 + [1] + + + + $29.99 + [1] + + + + 116.49&nbsp;zł + [1] + + + + €28.39 + [1] + + + + €28.39 + [1] + + + + €28.39 + [1] + + + + €28.39 + [1] + + + + £22.5 + [1] + + + + $29.99 + [1] + + + + $29.99 + [1] + + + + $29.99 + [1] + + + + $29.99 + [1] + +
Last updated: 1519101168023.
+ + +

制定自己產品的價格

+ +

如果要為自己的 App 或 In-app 產品定價,就必須選擇價格點數與想要銷售的地區。對 App 來說,選擇銷售國家並不會限制其他國家的消費者購買 App,只會決定 App 所將上架的國家 (可能不只一個國家)。即使消費者身處其他國家,只要付款方式亦適用 App 的上架國家,就同樣可購買該 App。

+ +

價格點數表如何運作?

+ +

Marketplace 將針對各種幣別預先設定匯率,再轉換為美金以外的計價並四捨五入,以更為貼近市場友善的數字。四捨五入的價格與外幣匯率的波動,都代表美金以外的定價不會隨時等值於美金現價。除非需穩定多國換匯之後的相對價格,否則美金以外的定價均將保持不動。Mozilla 也不會刻意常常調整定價,且最快每六個月才會調價一次。價格點數一般均保持在美金定價的 1% ~ 2% 之內。而由於某些國家定價另納入了增值稅,因此可能超出此範圍。

+ +

含稅價與未稅價的價格點數

+ +

顯示於不同地區的價格可能含稅或未稅。含稅價代表該價格已含稅 (一般為增值稅,VAT) 並顯示給消費者知道。未稅價則代表稅額 (若有對應稅額) 將另外再加至顯示的價格中。

+ +

各國家與地區的增值稅略有不同,但一般均依照 App 販售國家 (由電信營運商收取) 的增值稅率而定;或是在英國適用增值稅的地區以信用卡付款,則為 20% 增值稅率。一旦消費者確定付款之後,就會根據其付款資訊中登記地區的幣別,或目前所在地區的幣別計算。

+ +

如果消費者所在地區顯示的是未稅價,則當地稅額與費用將再加入 App 售價之中。消費者可能要收到發票,或由銀行/電信營運商寄發對帳單之後,才會看到實際的稅額。

+ +

如何拆帳?

+ +

在將自己設定為「開發者」的付款帳戶之後,即可選擇往後收款的幣別。目前支援的付款幣別包含美金 ($)、歐元 (€)、英鎊 (£)。若是含稅價格,則開發者在正常情況下會收到「消費者購買 App 金額扣除稅額與特定費用」的 70%。若是未稅價格,則會收到「消費者針對 App 定價表付款」的 70%;應付稅額另再加到消費者實際付款額之中。由於匯率浮動與增殖稅率的差異,各地區的實收金額也有所變動。

+ +

而上述金額的另外 30%,將由 Mozilla、電信營運商、第三方支付供應商拆帳。其內包含商業交易程序的相關交易與服務費用。根據目前既定的分配方式,Mozilla 約將收取 5% ~ 7.5%。

+ +
+

若選用電信帳單代繳方式,則開發者所能收到的款項可能又有差異。請到付款狀態了解相關細節,進一步了解該國電信營運商的拆帳規定。

+
+ +

付款方式:電信帳單代繳與信用卡

+ +

透過 Firefox Marketplace 販售自己 App 的絕佳優點之一,就是能直接讓消費者透過行動電話帳單付款。對信用卡尚未普及的新興市場而言,此特色絕對是目前行動付款的重要媒介。

+ +

目前為止,電信營運商必須與 Mozilla 簽訂合約之後,才能在所屬地區提供電信帳單代繳的服務。消費者必須申請該電信營運商的 SIM 卡並預繳特定金額,以順利支付 App 或 In-app Payment 的款項。當然,消費者亦可透過信用卡購買 App。

+ +

針對客戶透過自己行動電話號碼付費的機制,某些電信營運商另設有最低與最高額度,而且各家營運商均有不同。若 App 定價超出該額度,則款項預設轉為信用卡支付;但又並非所有消費者均擁有信用卡。又有些地區並無法和營運商值接建立帳單服務,而必須透過信用卡付款,如此就限定需以美金、歐元、英鎊購買 App。

+ +
+

注意:針對信用卡部分,目前最低收費款項為 10 價格點數 (即美金 $0.99 元整);而最高款項為美金 $30.00 元整。接受 Visa® 與 MasterCard® 信用卡。

+
+ +

慎防詐騙

+ +

第三方支付供應商應已有多種防止詐騙的方式。為了減少詐騙行為,目前僅限消費者實際所在地銀行發行的信用卡,才能用以支付 App 購買款項。因此,消費者若持巴西境內銀行所發行的信用卡,就只能在巴西國內使用該信用卡,而不能跑到哥倫比亞境內購買 App。

+ +

取得自己的收益:設定收款帳戶

+ +

開發者若要能確實收到自己 App 或 In-app Payments 所創造的營收,必須先針對自己所選擇的 App 販售地區,開好當地支付供應商所提供的帳戶。各家支付供應商都具備服務條款,與 Mozilla 的服務條款不盡相同。開發者必須同意供應商的條款之後,才能透過 Firefox Marketplace 銷售自己的 App 或取得 In-app Payments 款項。

+ +

你也可在 Firefox Marketplace 中設定開發者的收款帳戶。先找到 App 的「Compatibility & Payments」之後,針對你所選擇的販售地區新增收款帳戶即可。

+ +
+

注意:Bango 則是 Firefox Marketplace 的支付供應商。

+
+ +

收取屬於自己的款項

+ +

開發者可直接與支付供應商往來,以順利取得屬於自己的款項。你會收到「自行對帳發票 (Self Billing Invoice,SBI)」,其中將列舉開發者銷售總額、消費者退費總額、開發者實際收取總額。若你的 App 販售地區可退增值稅,則總額也將包含增值稅額。

+ +

你可透過自己在 Firefox Marketplace 中的開發者帳戶,找到支付供應商的付款入口網頁。由於各國電信營運商入帳時程各有不同,且消費法規也可能影響退款速度,所以帳戶的收款條件與時程也有所差異。請自行了解第三方支付供應商的相關條件與說明。

+ +

稅額

+ +

本章節將說明銷售稅的處理方式。

+ +

增值稅 (Value Added Tax,VAT)

+ +

Bango 可針對當地的稅捐機關,處理增值稅 (VAT) 的退稅問題。根據各個國家與地區的法律規定,相關徵稅與退稅的條件均有不同。開發者可向會計師或稅捐機關諮詢。而自行對帳發票 (SBI) 將根據增值稅稅前金額,開立發票給 Bango。開發者到時候觀看支付清單即可了解運作情形。如果開發者身處不屬於「販售者需支付增值稅」的地區,則應該會收到當地稅捐機關的退稅。相關細節請向會計師諮詢。

+ +

預扣稅額與換匯費用

+ +

Bango 可支付美金 ($)、歐元 (€)、英鎊 (£),讓開發者自行選擇適合的幣別。Bango 可能會因法條規範,為開發者預扣或繳付當地稅額,因此會從支付帳款中扣除應付稅額。各國的預扣稅率均不相同,也可能必須支付換匯費用。在將當地貨幣換成等值的美金、歐元、英鎊時,就可能產生 1.9% ~ 2.5% 的換匯費用。這項費用對開發者並不友善,而 Mozilla 也正研究是否有替代方案。

+ +

開發者的收益

+ +

因所在國家、當地貨幣、付款方式的不同,開發者販售 App 所獲得的收益也有所差異。可參閱付款狀態以進一步了解各國的付款細節。

diff --git a/files/zh-tw/archive/mozilla/marketplace/monetization/in-app_payments/index.html b/files/zh-tw/archive/mozilla/marketplace/monetization/in-app_payments/index.html new file mode 100644 index 0000000000..35e3fe4117 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/monetization/in-app_payments/index.html @@ -0,0 +1,332 @@ +--- +title: 應用程式內部付費 (In-app payments) +slug: Archive/Mozilla/Marketplace/Monetization/In-app_payments +translation_of: Archive/Marketplace/Monetization/In-app_payments_section/mozPay_iap +--- +
+

navigator.mozPay API 可讓網頁內容執行數位貨品的付款作業,並能接收由付款服務商所傳來的購買確認訊息。我們也針對此 API 建構了 Web 付款服務商,讓你能取得數位貨品的款項。本文將說明該如何使用 navigator.mozPay API 與 Web 付款服務商的服務,以達到應用程式內付款 (In-app payments)。

+
+

另外現正開發「fxPay」付款處理機制。FxPay 不會要求開發者必須架設伺服器以進行購買行為驗證,可算是更完整的付款方式。

+
+
+

In-app payments 概述

+

讓你為自己的 App 添加 In-app payments 機制,與其運作的方法:

+ +

navigator.mozPay API 目前限用於 Firefox OS。你同樣可透過 Firefox OS 應用程式管理員 (App Manager) 測試此 API。

+
+

注意:如果是在 Firefox OS 1.2 裝置上測試,只要該裝置內並無 SIM 卡,則 mozPay 呼叫將失敗。但消費者只要裝入 SIM 卡就可解決此問題。目前市面上販售的 Firefox OS 裝置均未安裝 Firefox 1.2。若要進一步了解,可參閱 bug 989022

+
+

逐步設定 In-app payment

+

接著說明該如何設定 In-app payment。

+

取得測試用的付款金鑰 (Payment Key)

+

在登入至 Firefox Marketplace 開發者交流中心時,可前往 In-App Payment Keys 頁面取得應用程式金鑰與安全金鑰以利測試。雖然金鑰只能讓你模擬 In-app payments,但已足以因應相關測試。在將自己的 App 提交至 Marketplace 審核之前,應該先多嘗試相關模擬。請參閱付款模擬的相關說明。

+

取得真正的付款金鑰

+

在將自己的 App 提交至 Firefox Marketplace 開發者交流中心時, 系統將要求你設定付款條件。此時請選擇 App 的價格 (你也可能想免費提供),接著勾選你接受 In-app payments 的選項。在設定自己的銀行帳戶之後,前往「Manage In-App Payments」頁面取得應用程式金鑰與安全金鑰,才能執行真正的付款作業。

+

透過隱私設定或類似檔案,可在自己的 App 伺服器中儲存應用程式安全金鑰。

+
+ 重要:請確認沒有任何人可讀取你的應用程式安全金鑰。絕對不要在用戶端披露該項資訊。
+

設定 App

+

先假設你在設計某個 Open Web App 的冒險遊戲,而你想販售「魔力獨角獸」物品,讓玩家能擁有遊戲優勢。你可設定美金 $1.99、歐元 €1.89,或任何幣值均可。接著將說明該如何設定後端伺服器,並撰寫前端程式碼而透過 navigator.mozPay 銷售產品。

+

設定自己的伺服器以簽署 JWT

+

因為用來簽署的應用程式安全金鑰絕對不能公開,所以你必須在伺服端簽署 JSON Web Tokens (JWTs);而非用戶端。回到剛剛冒險遊戲要賣魔力獨角獸的例子,你要在自己的伺服器上建立如 /sign-jwt 的網址。如此可建立 JSON 物件以定義產品名稱、定價等。可參閱 Web Payment API 規格以了解完整的 JWT 格式。範例如下:

+
{
+  "iss": APPLICATION_KEY,
+  "aud": "marketplace.firefox.com",
+  "typ": "mozilla/payments/pay/v1",
+  "iat": 1337357297,
+  "exp": 1337360897,
+  "request": {
+    "id": "915c07fc-87df-46e5-9513-45cb6e504e39",
+    "pricePoint": 10,
+    "name": "Magical Unicorn",
+    "description": "Adventure Game item",
+    "icons": {
+      "64": "https://yourapp.com/img/icon-64.png",
+      "128": "https://yourapp.com/img/icon-128.png"
+    },
+    "productData": "user_id=1234&my_session_id=XYZ",
+    "postbackURL": "https://yourapp.com/payments/postback",
+    "chargebackURL": "https://yourapp.com/payments/chargeback",
+    "defaultLocale": "en",
+    "locales": {
+      "de": {
+        "name": "Magisches Einhorn",
+        "description": "Adventure Game Artikel"
+      }
+    }
+  }
+}
+

Web Payment API 規格將詳細解釋格式。此處列出幾個重點:

+ +

在 Python (使用 PyJWT) 程式碼中,你可簽署並編碼上述的請求路徑如下:

+
import jwt
+signed_request = jwt.encode(request_dict, application_secret, algorithm='HS256')
+

此程式碼將為 JWT (使用應用程式安全金鑰) 進行簽章,並使用 HMAC SHA 256 演算法。在編碼過後就如下列:

+
eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.IntcImF1ZFwiOiBcIm1hcmtldHBsYWNlLm1vemlsbGEub3JnXCIsIFwiaXNzXCI6IFwiQVBQLTEyM1wiLCBcInJlcXVlc3RcIjoge1wiY3VycmVuY3lcIjogXCJVU0RcIiwgXCJwcmljZVwiOiBcIjAuOTlcIiwgXCJuYW1lXCI6IFwiVmlydHVhbCAzRCBHbGFzc2VzXCIsIFwicHJvZHVjdGRhdGFcIjogXCJBQkMxMjNfREVGNDU2X0dISV83ODkuWFlaXCIsIFwiZGVzY3JpcHRpb25cIjogXCJWaXJ0dWFsIDNEIEdsYXNzZXNcIn0sIFwiZXhwXCI6IFwiMjAxMi0wMy0yMVQxMTowOTo1Ni43NTMxNDFcIiwgXCJpYXRcIjogXCIyMDEyLTAzLTIxVDEwOjA5OjU2LjgxMDQyMFwiLCBcInR5cFwiOiBcIm1vemlsbGEvcGF5bWVudHMvcGF5L3YxXCJ9Ig.vl4E31_5H3t5H_mM8XA69DqypCqdACVKFy3kXz9EmTI
+

如上面章節所述,在 JWT 經過編碼/簽章之後,即可透過其用戶端碼而供你的 App 所使用。

+

設定購買按鈕

+

現在你已經有後端可為自己的產品產生 JWT 了。接著透過 navigator.mozPay 提供前端程式碼的撰寫範例。請確實在自己的 App 中提供按鈕,以利消費者購買產品。例如:

+
<button id="purchase">Purchase Magical Unicorn</button>
+

點選購買按鈕之後,你的 App 應會簽署 JSON Web Token (JWT) 並呼叫 navigator.mozPay。下列為 jQuery 使用範例:

+
$('#purchase button').click(function() {
+  // The purchase is now pending...
+  $.post('/sign-jwt', {})
+    .done(function(signedJWT) {
+      var request = navigator.mozPay([signedJWT]);
+      request.onsuccess = function() {
+        waitForPostback();
+      };
+      request.onerror = function() {
+        console.log('navigator.mozPay() error: ' + this.error.name);
+      }
+    })
+    .fail(function() {
+      console.error('Ajax post to /sign-jwt failed');
+    });
+});
+
+function waitForPostback() {
+  // Poll your server until you receive a postback with a JWT.
+  // If the JWT signature is valid then you can dispurse the Magical Unicorn
+  // product to your customer.
+  // For bonus points, use Web Sockets :)
+}
+

上列程式碼將送出 Ajax 請求至你伺服器上的 /sign-jwt 網址。該網址所簽署的 JSON blob 將包含產品/價格資訊,並以純文字檔回傳 JWT。而 Ajax 處理器 (Handler) 將傳送該 JWT 進入 navigator.mozPay 並等待,直到付款服務商將購買確認訊息送至你的伺服器上。若送過來的 JWT 簽章通過驗證為有效,你就可將虛擬商品交付給消費者。

+

於伺服器上處理 Postback

+

在正式販售出出自己的 App 產品之前,必須先等待 Marketplace 回傳購買確認訊息;此及所謂的「Postback」。此由 marketplace.firefox.com 傳送出「POST」確認通知 (即 1 組 JWT),至原始付款請求所指定的 request.postbackURL

+

而此「POST」具備 application/x-www-form-urlencodedContent-Type,且亦可於 notice 參數中找到此 JWT。在你的伺服器框架中,你可透過如 request.POST['notice'] 來存取此 JWT。

+

此 JWT 通知具備所有的付款請求欄位與 1 組交易 ID,並以 Firefox Marketplace 開發者交流中心取得的應用程式安全金鑰而完成簽章。當你收到 Postback 並驗證簽章之後,隨即完成購買程序。若你無法辨別 JWT 的簽章,就可能不是 Marketplace 所傳送的 JWT,你可逕行忽略。

+

Web Payment API 規格即解釋了 Postback 的細節。Postback 內含原始請求,且添增的新反應參數亦包含 Mozilla 的特定交易 ID。範例如下:

+
{
+  "iss": "marketplace.firefox.com",
+  "aud": APPLICATION_KEY,
+  "typ": "mozilla/payments/pay/postback/v1",
+  "exp": 1337370900,
+  "iat": 1337360900,
+  "request": {
+    "id": "915c07fc-87df-46e5-9513-45cb6e504e39",
+    "pricePoint": 10,
+    "name": "Magical Unicorn",
+    "description": "Adventure Game item",
+    "icons": {
+      "64": "https://yourapp.com/img/icon-64.png",
+      "128": "https://yourapp.com/img/icon-128.png"
+    },
+    "productData": "user_id=1234&my_session_id=XYZ",
+    "postbackURL": "https://yourapp.com/payments/postback",
+    "chargebackURL": "https://yourapp.com/payments/chargeback",
+    "defaultLocale": "en",
+    "locales": {
+      "de": {
+        "name": "Magisches Einhorn",
+        "description": "Adventure Game Artikel"
+      }
+    }
+  },
+  "response": {
+    "transactionID": "webpay:84294ec6-7352-4dc7-90fd-3d3dd36377e9",
+    "price": {"amount": "0.99", "currency": "CAD"}
+  }
+}
+

列出 Postback 的幾項重點:

+ +

回應 Postback

+

App 必須透過純文字的 HTTP 回應 (其內僅含交易 ID),對 Postback 做出回應。例如:

+
HTTP/1.1 200 OK
+Content-Type: text/plain
+
+webpay:84294ec6-7352-4dc7-90fd-3d3dd36377e9
+

於伺服器上處理 Chargeback

+

如果交易過程發生問題 (如消費者帳戶的餘額不足),則 Marketplace 將傳送退款通知 (即 POST 過的 JWT)。Chargeback 與 Postback 同樣都會傳送到 App,但 Chargeback 送達的時間較晚。該 POST 具備 application/x-www-form-urlencodedContent-Type,且可於 notice 參數中找到該 JWT。下列為解碼後的 Chargeback 通知範例:

+
{
+  "iss": "marketplace.firefox.com",
+  "aud": APPLICATION_KEY,
+  "typ": "mozilla/payments/pay/chargeback/v1",
+  "exp": 1337370900,
+  "iat": 1337360900,
+  "request": {
+    "id": "915c07fc-87df-46e5-9513-45cb6e504e39",
+    "pricePoint": 10,
+    "name": "Magical Unicorn",
+    "description": "Adventure Game item",
+    "icons": {
+      "64": "https://yourapp.com/img/icon-64.png",
+      "128": "https://yourapp.com/img/icon-128.png"
+    },
+    "productData": "user_id=1234&my_session_id=XYZ",
+    "postbackURL": "https://yourapp.com/payments/postback",
+    "chargebackURL": "https://yourapp.com/payments/chargeback",
+    "defaultLocale": "en",
+    "locales": {
+      "de": {
+        "name": "Magisches Einhorn",
+        "description": "Adventure Game Artikel"
+      }
+    }
+  },
+  "response": {
+    "transactionID": "webpay:84294ec6-7352-4dc7-90fd-3d3dd36377e9",
+    "reason": "refund"
+  }
+}
+

此 JWT 和 Postback 類似,可於 Web Payment API 規格中參閱其定義細節。此處列出幾項重點:

+ +
+

注意:目前 in-app payments 尚未支援退款作業。

+
+

App 必須透過純文字的 HTTP 回應 (其內僅含交易 ID),對 Chargeback 做出回應。舉例來說:

+
HTTP/1.1 200 OK
+Content-Type: text/plain
+
+webpay:84294ec6-7352-4dc7-90fd-3d3dd36377e9
+

Postback/chargeback 錯誤

+

若 App 伺服器是以不成功的狀態碼回應 HTTP 請求,則 Mozilla 的 Web Payment Provider 將重新嘗試 URL 數次。若仍未能接收成功回應,則 App 開發者就會收到通知,且該 App 將暫時停用。若 App 伺服器未能以交易 ID 回應 Postback 或 Chargeback,就會將該伺服器處理為錯誤並會重新嘗試。

+

使用 HTTPS Postback/chargeback 網址

+

於正式環境中執行 App 時,可依需要而嘗試使用安全的 HTTPS 網址。如此一來,在將 Postbacks 從 Mozilla 伺服器傳輸至自己的 App 伺服器時,可避免 Postback 資料遭他人讀取。目前並未強制使用 HTTPS 來保護付款請求,其實 JWT 簽章即可達到相同效果。

+
+

注意:若你並未使用安全的 HTTPS Postback 網址,則請確認自己的付款請求並未包含個人識別資訊,以免遭第三方所攔截。舉例來說,需確認自己的 productData 值並未揭露任何高敏感性的使用者資料。Mozilla 預設的付款請求亦未包含任何個人識別資訊。

+
+

Postback/chargeback IP

+

如果你依照上述方式而確實檢查了 JWT 簽章,就不需為 Firefox Marketplace 伺服器 (傳送 postback/chargeback 通知給你) 的 IP 設定許可清單。但如果你想再另加額外保險 (例如防止鍵盤側錄),則 Marketplace 也能從下列 IP 位址寄發 postback/chargeback 通知給你。只要這些 IP 位址變更,都會發佈到 dev-marketplace 郵件群組之中。

+
63.245.216.100
+

模擬付款

+

上面的「概述」部分提到,你可從 Firefox Marketplace 開發者交流中心取得特殊的應用程式金鑰 (Application Key) 與應用程式安全金鑰 (Application Secret),進而模擬 In-app payments。而這個安全金鑰亦可簽署如下的客製 JWT:

+
{
+  "iss": APPLICATION_KEY,
+  "aud": "marketplace.firefox.com",
+  "typ": "mozilla/payments/pay/v1",
+  "iat": 1337357297,
+  "exp": 1337360897,
+  "request": {
+    "id": "915c07fc-87df-46e5-9513-45cb6e504e39",
+    "pricePoint": 10,
+    "name": "Magical Unicorn",
+    "description": "Adventure Game item",
+    "icons": {
+      "64": "https://yourapp.com/img/icon-64.png",
+      "128": "https://yourapp.com/img/icon-128.png"
+    },
+    "productData": "user_id=1234&my_session_id=XYZ",
+    "postbackURL": "https://yourapp.com/payments/postback",
+    "chargebackURL": "https://yourapp.com/payments/chargeback",
+    "simulate": {
+      "result": "postback"
+    }
+  }
+}
+

額外的 request.simulate 屬性可要求 Payment Provider 模擬相關結果,而不會真正收費。使用者介面亦不會要求登入或 PIN 碼。在開發 App 時,可透過此屬性而確認「購買」鈕已正確掛上 navigator.mozPay,且自己的伺服器可正確運作 Postbacks 與 Chargebacks 的網址。

+

下列範例將模擬 1 筆成功的購買作業,並傳送簽署過的通知至你的 Postback 網址:

+
{
+  ...
+  "request": {
+    ...
+    "simulate": {
+      "result": "postback"
+    }
+  }
+}
+

下列則模擬 1 筆 Chargeback 退款:

+
{
+  ...
+  "request": {
+    ...
+    "simulate": {
+      "result": "chargeback",
+      "reason": "refund"
+    }
+  }
+}
+

將如同真正的購買作業一般,將有 1 筆 JWT 通知傳送到你的處理器,但不會有隨機產生的 transactionID。模擬作業亦可使用 non-HTTPS 網址。

+
+

注意:模擬的付款 JWT 不該用於正式的服務環境中,否則你的消費者將免費取得產品。

+
+

除錯

+

如果你並未正確使用 in-app payment API,則付款畫面將顯示錯誤訊息,以協助使用者進行後續步驟。付款畫面亦將提供錯誤程式碼,協助開發者找出相關錯誤。你可透過 Mozilla 的 Error Legend API,在自己慣用的程式語言中觀看錯誤代碼。舉例來說,錯誤代碼 INVALID_JWT 即表示 JWT 簽章無效,或 JWT 格式混亂。

+

保護應用程式安全金鑰

+
+

警告:請確認沒有任何人可讀取你的應用程式安全金鑰。絕對不要在用戶端披露該項資訊

+
+

撤銷遭盜用的應用程式安全金鑰

+

雖然遭盜用的機率極低,但你的安全金鑰仍可能外洩或遭盜用,這時應儘快進行下列撤銷步驟:

+
    +
  1. 登入 Firefox Marketplace
  2. +
  3. 前往「My Submissions」並找到自己的 App。
  4. +
  5. 前往「Manage In-App Payments」頁面;就是產生自己所屬憑證 (Credentials) 的相同頁面。
  6. +
  7. 點擊「Reset Credentials」按鈕。
  8. +
+

在重設自己的憑證之後,其他人就無法以舊憑證處理付款作業。你會看到新的應用程式金鑰與安全金鑰,並可立刻用來處理自己 App 中的付款流程。

+

若要回報任何安全性問題,請填寫 Payments/Refunds 分類下的錯誤

+

程式碼函式庫

+

下列為 Mozilla 的 navigator.mozPay 專屬函式庫:

+ +

Here are some generic JSON Web Token (JWT) libraries for encoding/decoding and signature verification:

+ +

範例程式碼

+ +

尋求協助

+ +

類似的付款系統

+ diff --git a/files/zh-tw/archive/mozilla/marketplace/monetization/index.html b/files/zh-tw/archive/mozilla/marketplace/monetization/index.html new file mode 100644 index 0000000000..ed0b227445 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/monetization/index.html @@ -0,0 +1,80 @@ +--- +title: 讓 App 產生實質收益 +slug: Archive/Mozilla/Marketplace/Monetization +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive/Marketplace/Monetization +--- +
+

你努力打造出自己的 App,又該如何在發佈之後取得實質收益呢?不論你選用 Marketplace 付款或應用程式內部付費機制 (In-app payments),本頁將提供所有相關的 App 付款資訊。

+
+
+
+
+
+ 用自己的 App 獲益
+
+ 透過自己 App 獲益的相關要素介紹,包含所需的工具。
+
+ Marketplace 付款
+
+ 了解 App 將如何搭配 Firefox Marketplace,以強化自己的銷售模式 (如果你的是付費 App,更能提升自己的收入)。
+
+ In-app payments
+
+ 說明應如何在自己的 Web App 中建構 In-app payments
+
+ 檢驗收據
+
+ 檢驗自己 App 購買收據的時機與方式。
+
+ App 定價列表
+
+ 內有價格點數 (Price point),可讓開發者為自己的付費 App 設定售價,並根據不同的幣別各對應不同的價格點數;另有處理 App 付款的相關資訊。
+
+ 付款狀態
+
+ 提供目前有哪些國家已經設定 Marketplace 的 App 付款服務完畢,基本上也代表這些國家已可銷售付費 App。
+
+
+
+
Tools for app developers
+ +
Technology reference documentation
+ +
Getting help from the community
+

If you still aren't sure how to do what you're trying to get done, feel free to join the conversation!

+ +

Don't forget about the netiquette...

+
+
+

 

diff --git a/files/zh-tw/archive/mozilla/marketplace/monetization/introduction_monetization/index.html b/files/zh-tw/archive/mozilla/marketplace/monetization/introduction_monetization/index.html new file mode 100644 index 0000000000..1c5993a876 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/monetization/introduction_monetization/index.html @@ -0,0 +1,77 @@ +--- +title: 介紹 ─ 應如何讓 App 創造收益 +slug: Archive/Mozilla/Marketplace/Monetization/Introduction_Monetization +translation_of: Archive/Marketplace/Monetization/Introduction_Monetization +--- +
+

你努力打造出自己的 App,又該如何在發佈之後取得實質收益呢?不論你選用 Marketplace 付款,或是應用程式內部付費機制 (In-app payments),本頁將提供所有相關的 App 付款資訊。

+
+
+
+
+
+ 用自己的 App 創造收益
+
+ 將說明該如何用自己的 App 創造收益,包含付費式 App、定價、付款作業處理。
+
+ App 付款指南
+
+ 說明付費式 App 的相關技術。
+
+ 應用程式內付款 (In-app payments)
+
+ 說明該如何在自己的 Web App 中建構 In-app payments 功能。
+
+ 檢驗收據
+
+ 檢驗自己 App 購買收據的時機與方式。你可自行建構檢驗機制,亦可使用現有的函式庫。
+
+ 制定 App 的價格
+
+ 可為自己的 App 選擇固定的「價格點數 (Price points)」,且價格點數跨不同幣別也有所差異。本文將提供 App 付費資訊。
+
+ 付款服務狀態
+
+ 總結目前有哪些國家已經支援我們的 App 付款服務。另提供可發佈 App 上架的國家列表。
+
+
+
+
Tools for app developers
+ +
Technology reference documentation
+ +
Getting help from the community
+

If you still aren't sure how to do what you're trying to get done, feel free to join the conversation!

+ +

Don't forget about the netiquette...

+
+
+

 

diff --git a/files/zh-tw/archive/mozilla/marketplace/monetization/payments_status/index.html b/files/zh-tw/archive/mozilla/marketplace/monetization/payments_status/index.html new file mode 100644 index 0000000000..25726a4fb5 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/monetization/payments_status/index.html @@ -0,0 +1,30 @@ +--- +title: 付款服務狀態 +slug: Archive/Mozilla/Marketplace/Monetization/Payments_Status +translation_of: Archive/Marketplace/Monetization/App_pricing +--- +
+

Firefox Marketplace 付款服務均以「國家」為單位進行,且各國有不同的定價與付款方式。本文列出已開始 Marketplace 付款服務的國家,並附上進一步資訊的連結。

+
+
+

注意:另請參閱《制定 App 的價格》以了解價格點數,並可透過 API 取得

+
+

各國的付款服務

+

下列為 Marketplace 目前提供付款服務的國家。我們亦隨時努力於更多國家提供付款服務。若需要現已支援付款服務的國家清單,可參閱《制定 App 的價格》。

+

App 支付

+

下列頁面將提供各國的付款服務資訊。另請注意,目前出帳作業僅支援當地貨幣;信用卡付款僅接受英鎊、美金、歐元計價。

+ +

進一步了解收費費率

+

若要進一步了解收費費率,請至 Firefox Marketplace 找到你自己的 App 頁面。點擊「相容性與付款 (Compatibility & Payments)」→「新增、管理或檢視您的付款帳號中的交易 (Add manage or view transactions for your payment account)」→「檢視交易 (View Transactions)」連結,即如下所示。

+

Transactions link

diff --git a/files/zh-tw/archive/mozilla/marketplace/monetization/profiting_from_your_app/index.html b/files/zh-tw/archive/mozilla/marketplace/monetization/profiting_from_your_app/index.html new file mode 100644 index 0000000000..b66295dcee --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/monetization/profiting_from_your_app/index.html @@ -0,0 +1,95 @@ +--- +title: 用自己的 App 創造收益 +slug: Archive/Mozilla/Marketplace/Monetization/Profiting_from_your_app +translation_of: Archive/Marketplace/Monetization/Profiting_from_your_app +--- +
+

開發 Web App 不只有趣,也是將自己熱情轉為實質收益的絕佳方式!本篇文章將介紹 App 付款的相關主題、說明目前已經建構的付款類型 ─ 包含付款購買 App 與應用程式內部付費 (In-app payments),以及該如何處理不同國家內所發生的交易。

+
+ +

Firefox Marketplace 是專為 Web App 開發者所設計的絕佳市集,可支援付費/免費 App 與 In-app payments、多款裝置平台的 App,還有更多特色。Firefox Marketplace 具備高競爭力的定價系統,讓消費者能選用自己喜歡的付款方式。並由付款服務供應商處理付款程序,可透過消費者的信用卡或行動電話帳單收取款項。

+ +
+

注意:可參閱《Marketplace 常見問題》的〈付款〉一章,了解 Marketplace 付款方面的常見問題。

+
+ +

設定付費 App

+ +

完全可由開發者自行決定 App 收費與否,而且將 App 提交至 Firefox Marketplace 的程序極為相似。Firefox Marketplace 目前支援二種 App 付款模式:

+ + + +

若將 App 定位為付費 App,則開發者會有不同的選擇並需制定價格;消費者也會在開始下載時完成付費。另請注意,因為必須經過 Marketplace 驗證並正確安裝 App,所以目前僅有 Firefox OS 才支援付費 App。在建構付費 App 時,可參閱《App 付款指南》進一步了解其內部的必要程式碼。

+ +

如果開發者是透過 Marketplace 收款,則消費者付款之後即可收到電子收據。開發者必須負責查驗電子收據,確認自己的 App 已正確收款。一般只要啟動 App 時就完成了查驗作業。可參閱《查驗收據》以進一步了解。

+ +

Mozilla 強烈建議開發者應在收費之前,讓消費者能預覽/試用 App 的功能。只要同時提供單一 App 的免費與付費版本,或透過 In-app payments 都能達到上述目的。

+ +

In-app payments

+ +

In-app payments 讓消費者可在 App 中付款,亦即透過 App 而靈活收取多樣數位版商品與服務的款項。且 In-app payments 讓開發者強化現有 App 即可獲得更高收益;而消費者也不需再另外購買新的 App。

+ +

舉例來說,In-app payments 可用於:

+ + + +

Mozilla 與 Google 的 In-Apps Payments 系統運作模式極為相似。Firefox Marketplace 系統如下:

+ + + +

Firefox Marketplace 另提供 JavaScript 公用程式函式庫,可協助完成購買程序。

+ +

免費增值 (Freemium) App

+ +

若開發者想將付費版本的 App 拿掉數項功能而成為免費版本,以供消費者可預覽/試用該 App,則 Mozilla 也同樣支援此一需求。開發者可在「免費版 App」的「詳細資訊」區塊中,找到「upsell」加入付費升級的功能,即可銜接免費與付費版本的 App 並簡化此「免費增值」模式。

+ +

退款

+ +

一旦消費者要求退款,則可能由 Mozilla、付款服務供應商,或電信營運商授權退款作業。根據各地的消費規範、信用卡退款政策、電信營運商退款政策等的差異,退款授權方式亦有所不同。此外,Mozilla 並無法處理 In-app payments 的退款作業。

+ +

一旦 App 購買行為退款完畢,所對應的收據也隨即失效。因此,開發者應隨時查驗收據以確保 App 是否正確授權批准。若任何 App 發生不尋常的大量退款要求,將由 Mozilla 進一步查驗。

+ +
+

注意:應用程式內部付費 (In-app payments)》提供 In-app payments 作業的豐富訊息與範例程式碼。目前 In-app payment 程序尚在實測階段,請隨時參閱更新訊息。

+
+ +
+

注意:若 App 使用 In-app payments 機制,則 Mozilla 建議該 App 可設定為免費下載 App。當然付費 App 同樣可使用此機制。

+
+ +

定價與款項給付

+ +

App 內部應使用正確的程式碼,且最好透過 Marketplace 檢驗 App 較為穩當。但你心裡可能還是會想著系統是如何跨國處理這些款項。

+ +

Firefox Marketplace 所列出的 App,都是由付款服務供應商負責販售。這些付款服務供應商將負責處理交易、收取營業稅與增值稅 (VAT)、確認符合當地消費法規、相關出納/退款作業,以及其他應盡的零售作業。Mozilla 則是提供買家 (即 App 使用者) 與賣家 (App 開發者) 的交流場所,但完全不參與交易活動。而 Bango 則是 Firefox Marketplace 的付款服務開發商。

+ +

付款處理商另負責買家 (即 App 使用者) 與賣家 (App 開發者) 之間的交易過程,包含信用卡處理在內的大小事。付款處理商一般會逐筆交易收取服務費用。開發者必須透過 Firefox Marketplace 開發者交流中心 (Firefox Marketplace Developer Hub),於各家付款處理商建立自己的帳戶。

+ +

為了維持 Firefox Marketplace 的運作、不斷提升 App 平台、實踐我們的使命,Mozilla 與合作夥伴將針對各筆交易拆帳,並另外支付交易費用。目前,若開發者是透過 Marketplace 進行交易,則每筆 App 或 In-app 銷售活動均可獲得 70% 的銷售金額 (此為必要費用與稅後總額,均已包含於消費者所看到價格之中)。而 Mozilla 與合作夥伴則收取 30%。

+ +

Firefox Marketplace 未來將支援更多國家、語言、幣別。我們亦將設法提供多個語系的 Marketplace,並搭配各國所適用的付款方式。

+ +

進一步了解:

+ + diff --git a/files/zh-tw/archive/mozilla/marketplace/monetization/validating_a_receipt/index.html b/files/zh-tw/archive/mozilla/marketplace/monetization/validating_a_receipt/index.html new file mode 100644 index 0000000000..8ad877280b --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/monetization/validating_a_receipt/index.html @@ -0,0 +1,132 @@ +--- +title: 驗證收據 +slug: Archive/Mozilla/Marketplace/Monetization/Validating_a_receipt +translation_of: Archive/Marketplace/Monetization/Validating_a_receipt +--- +
+

如果你的是付費 App,就應該檢查消費者的收據是否有效。如果開發者完全不檢查,則可能會有消費者購買 App 之後立刻退款,就變成免費取得 App 了;或可能直接從你的網站參照 manifest 檔案,就能安裝 App。如果開發者要建構收據驗證機制,可參閱本文提供的程式碼與作業流程。

+
+

收據 (Receipt) 即為消費者的 App 購買證明。收據將經由付款處理機制 (由消費者完成的交易) 產生確認資料 (Affirmation),以取得特定的數位產品。在消費者付費購買 Firefox Marketplace 上的 App 之後,收據就隨即傳送到消費者的裝置之中。位於消費者裝置上的收據,將用在 mozApps.install() 函式的第二組參數之上。Firefox Marketplace 將使用該筆收據資料,進而呼叫 install() 以完成 App 的安裝。

+

驗證收據的時機

+

開發者必須決定 App 該何時驗證收據。一般都是在消費者啟動 App 時開始驗證。如果是屬於長時間執行 App,則可以定時/定期進行驗證。例如影片串流 App 就可以每隔 20 分鐘檢查收據 1 次。

+

另請注意,如果消費者為離線狀態,App 也就無法驗證收據。開發者可決定 App 在離線時所進行的作業。為了避免打擾某些消費者,開發者可停止強制的收據驗證作業 (消費者可能進入隧道而暫時離線),只要等消費者上線時再次檢查即可。

+

如何驗證收據

+

最簡單就是使用 Firefox Marketplace 的驗證服務即可。如果你的 App 屬於「HTML-only」,也就是伺服器只會提供靜態檔案,則可使用 Mozilla 的「receiptverifier」JavaScript 函式庫。此函式庫基本上只會將 receiptverifier.js 指令碼加入 App 之中,並使用 verifyReceipts() 函式。可參閱上述連結以進一步了解。

+

收據內容

+

Open Web App 所使用的收據,均為可攜式、可驗證的「Token」購買證明,即所謂 JSON Web Token (JWT) 的數位簽署 JSON 資料架構,且此格式可讓所有用戶端與伺服器讀取。許多程式語言均提供 JWT 函式庫。

+

應接受的收據

+

收據就是付款的證明,但 App 開發者可決定自己想要的收據類型。以下是你該檢查的要項:

+ +

receipt verifier 函式庫可進行其中數項檢查。

+

測試用收據

+

在開發期間,Firefox Marketplace 即可協助發出測試用收據,以供完整測試 App 的相關付款程序。可透過 Firefox 開發者交流中心 (Firefox Developer Hub) 的公用程式頁面產生測試用收據。此種收據將具備「test-receipt」的 typ。且 App 只會在開發期間接收這類收據,一旦上架之後就停止接收;否則消費者可略過 App 銷售程序,直接使用測試用收據。

+

receipt verifier 函式庫預設不會接收 test-receipts

+

收據驗證

+

在沒有 JWT 函式庫的情況下,開發者也能在收據的 verify 欄位中,找到驗證服務的對應網址,並將收據傳送給驗證服務。各個 App 均具備不同的 Firefox Marketplace 驗證服務網址。

+

下列範例程式碼可於收據中顯示 verify 網址。該程式碼將用於 Firefox 的「網頁主控台 (Web console)」開發者工具。

+
var request = navigator.mozApps.getSelf();
+request.onsuccess = function() {
+  // Get the app's receipt and decode it
+  console.log(atob(request.result.receipts[0].split('~')[1].split('.')[1]));
+};
+

為了取得 verify 網址,此範例將近行下列作業:

+ +

接著是上述程式碼結果的完整範例。此即為扣除 JWT 部分的完整收據。

+
{
+  "product": {
+    "url": "http://example.com",
+    "storedata": "id=111111"
+  },
+  "iss": "https://marketplace.mozilla.org",
+  "verify": "https://receiptcheck.marketplace.mozilla.org/verify/111111", // The verify URL
+  "detail": "https://marketplace.mozilla.org/en-US/purchases/111111",
+  "reissue": "https://marketplace.mozilla.org/en-US/app/example/purchase/reissue",
+  "user": {
+    "type": "directed-identifier",
+    "value": "1234-abcd99ef-a123-456b-bbbb-cccc11112222"
+  },
+  "exp": 1353028900,
+  "iat": 1337304100,
+  "typ": "purchase-receipt",
+  "nbf": 1337304100
+}
+

在開發者取得 verify 網址之後,就可透過 POST 函式,在訊息主體之內傳送完整的 JWT。驗證服務的回應即如上方所述。下列程式碼片段 (snippet),將從上列範例中取得 App 第一筆收據的完整 JWT。

+
request.result.receipts[0]
+

請注意,上述程式碼並不會處理 JWT 的加密部分。如果你要透過 Marketplace 驗證收據,則收據將檢查本身的加密簽章。

+
+

注意:可在 Kumar McMillan 提供的 Private Yacht 範例中,找到其他更高擴充性的收據驗證範例。

+
+

App 盜版問題

+

即使你驗證了自己付費 App 的收據,還是可能有人繞過收據機制而盜用 App。上列的收據驗證函式並無法避免此問題。

+

如果想要更好的防盜版機制,就必須設定代理伺服器,將之作為 App 與 Firefox Marketplace 之間的媒介。代理伺服器可檢查收據、IP 位址,還有更多物件。如果單一收據來自於不同的 IP 位址,且能一樣執行正確動作,則伺服器就可進行類似通知的作業。如果是大型、複雜、使用伺服器處理功能的 App,就能達到更適當、更正確的設定。

+

此 Python 程式碼仍是開發中的專案,可提供某些代理伺服器的靈感。Django Receipts 則是測試用的代理伺服器,可驗證收據。開發者最好不要直接將之作為正式運行的代理伺服器,但可進行測試以了解相關機制。另可參閱更多資訊,讓自己了解收據驗證作業。

+

收據欄位

+

收據應包含下列欄位:

+
+
+ typ
+
+ 可供識別收據類型的字串,必為以下之一: +
    +
  • purchase-receipt ─ 交易完成之後隨即發出的收據。這類收據應隨時能由 App 接收。
  • +
  • developer-receipt ─ 由 App 開發者所發出的收據。一般是開發者交由自己使用的 App 商店所發出。這類收據有效期較短。
  • +
  • reveiwer-receipt ─ 由 App 審查者所發出的收據。一般是 App 審查者透過其所位於的商店發出。這類收據只需要在審查期間接收即可,有效期較短。
  • +
  • test-receipt ─ 在開發期間用以測試 App 所發出的收據。只要是開發期間以外,均不應該接收這類收據,有效期較短。
  • +
+
+
+ product
+
+ JSON 物件在識別產品時,包含收據所囊括的範圍,以及任何特定商店的資料。包含下列欄位: +
    +
  • url ─ 代表該網址的根網域 (root of a domain),且沒有最後的斜線 (例如「https://someapp.com」)。一般這樣就代表了 Web App。如果是以根網域開頭的其他網址,則代表「App 內購買」。只要開發者或收據開立者覺得方便,則可使用各種路徑規則 (Path scheme)。
  • +
  • storedata ─ 此字串為 App 所獨有,將提供給收據驗證器 (Verifier) 所用。
  • +
+
+
+ user
+
+ 針對完成購買作業的消費者,此 JSON 物件包含了使用者 ID,並包含下列欄位: +
    +
  • type ─ 此字串內有「directed-identifier」值。
  • +
  • value ─ 此字串即為消費者的專屬 ID。消費者每次購買 App,都會擁有不同的 ID。
  • +
+
+
+ iss
+
+ 發出收據的商店,其所屬之網域。
+
+ nbf
+
+ 完成購買程序之後,顯示「Not-before」的時間戳記。時間戳記是從 1970-01-01T00:00:00Z (UTC, RFC 3339) 開始的秒數。
+
+ iat
+
+ 發出收據之後,顯示「Issued-at」的時間戳記。此時間戳記的格式如同 nbf。可透過此數值決定收據的存在時間。
+
+ exp
+
+ (選填) 代表收據過期的時間戳記。此時間戳記的格式如同 nbf
+
+ detail
+
+ (選填) 網址包含額外人、機均可讀取的購買細節。如果另提供購買行為的交易記錄或退款功能,則本頁亦應包含相關函式。
+
+ verify
+
+ (選填) 由經過授權的 App 使用此網址,以驗證收據。另請注意,Firefox Marketplace 一定會為 App 提供此欄位。如果開發者想自己建立 App 的商城,就可能不需使用此欄位。
+
+ reissue
+
+ (選填) 網址可重新發出新收據。
+
diff --git a/files/zh-tw/archive/mozilla/marketplace/options/hosted_apps/index.html b/files/zh-tw/archive/mozilla/marketplace/options/hosted_apps/index.html new file mode 100644 index 0000000000..69614f7cf4 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/options/hosted_apps/index.html @@ -0,0 +1,69 @@ +--- +title: 托管\架設式 (Hosted) App +slug: Archive/Mozilla/Marketplace/Options/Hosted_apps +translation_of: Archive/Mozilla/Marketplace/Options/Hosted_apps +--- +
+

托管\架設式 (Hosted) App 即為 Open Web App,將其所有資源 (HTML、CSS、JavaScript、manifest 檔案等) 儲存於 Web 伺服器上。本文將簡介托管\架設式 App,另有相關連結讓你從開發者的角度進一步了解相關資訊。

+
+ +

與一般網站相同,托管的 Open Web App 亦透過 Web 伺服器提供其所有內容,另於 App 的根目錄中提供 App 的 manifest 檔案。manifest 檔案則具備 App 的詳細資料,如相關說明、代表 App 的圖示等等。且不論是 Firefox OS 裝置、Android 裝置,或桌上型電腦,這些詳細資料都會用於 App 的安裝作業。一旦安裝完畢,App 就會從原本的托管伺服器動態載入其內容,並可存取 Web 上的其他資源,如 Web 伺服器上的資料庫。

+ +

Firefox OS 安全模型中,托管式 App 均定義為 Web App,意即這類 App 無法利用 Privileged 與內部 (即 Certified) API。若要利用這些 API,則必須以封裝式 (Packaged) App 的方式來提供 App。

+ +
+

注意:Firefox Marketplace 僅支援 Firefox OS 的付費托管式,以及 Firefox OS、Firefox for Android、Firefox 的免費托管式 App。目前正開發所有平台的付費 App 支援功能。

+
+ +

App 托管選擇

+ +

開發者可自行選擇 App 的托管之處。如果你還沒選擇托管方式,則可考慮本段說明的常見托管選擇。

+ +

GitHub

+ +

如果你的 Open Web App 為靜態內容 (HTML/CSS/JavaScript,但無伺服器端的處理作業),那GitHub Pages 應該是你的不二選擇。如果你的 manifest 檔案是 .webapp 為附檔名,則 GitHub 就能用 correct MIME type 提供 manifest 檔案。

+ +

一般托管解決方案

+ +

動態的 Open Web App 需要伺服器端的處理作業,所以你可用任何常見的托管選擇 (像是你自己架設或可存取的 Web 伺服器)。你必須先確認 Web 伺服器具備相關功能。另有許多托管服務供應商已針對托管式 App 的需求 (如 HerokuGoogle App EngineAmazon App Hosting),量身打造出 Web 伺服器。

+ +
+

注意:之前在安裝 Open Web App 時,必須滿足「一組來源僅能提供一個 App」的安全規範。但這項條件到 Firefox 34/Firefox OS 2.1 (可參閱此 FAQ 以獲得更多資訊) 已經移除。如果你仍要支援較舊版本,則可試試看在不同來源托管不同的 App (如測試\正式版本)。其中一個方法就是為 App 建立不同的子網域,或可透過 WebIDE 測試 App。可參閱〈manifest 檔案常見問題〉以進一步了解。

+
+ +

測試托管式 App

+ +

若要將托管式 App 安裝至 Firefox OS 模擬器或實體裝置上,以利進行測試,請參閱《應用程式管理員 (App Manager)》。你也可觀看《自行發佈 App》中所說明的步驟,透過 Web 伺服器將 App 安裝到裝置之上。

+ +

發佈托管式 App

+ +

現有 2 種方式可發佈托管式 App:1). 透過 Firefox Marketplace 或 2). 自行發佈。

+ +

發佈於 Firefox Marketplace

+ +

你可參閱《App 發佈流程》,了解應如何將托管式 App 提交到 Firefox Marketplace 之上。

+ +

在你提交自己的托管式 App 之後,Marketplace 隨即根據你放在 Web 伺服器上的 manifest 檔案,產生新的「mini-manifes」檔案。只要消費者決定要安裝 App,則 mini-manifest 就會傳送到 Apps.install() 函式以安裝該 App。mini-manifest 僅會用於 App 的安裝與更新作業,並不會用於 App 執行期間。

+ +

自行發佈

+ +

你當然也能在 Firefox Marketplace 以外發佈托管式 App,也就是透過自己架設的 Web 伺服器。可參閱《自行發佈 App》。

+ +

更新托管式 App

+ +

共有 2 種方式可更新托管式 App:

+ + + +

若要進一步了解在 Firefox Marketplace 上更新 App 的方法,可參閱《更新 App》;若是自行發佈的 App,則可參閱《自行發佈 App》。

+ +

另請參閱

+ + diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/adding_a_subdomain/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/adding_a_subdomain/index.html new file mode 100644 index 0000000000..27d7c108df --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/adding_a_subdomain/index.html @@ -0,0 +1,40 @@ +--- +title: 為 App 添增子網域 +slug: Archive/Mozilla/Marketplace/Publishing/Adding_a_subdomain +translation_of: Archive/Mozilla/Marketplace/Publishing/Adding_a_subdomain +--- +
+

一組來源網域僅限容納一個 App。但若要打破此限制,則可為 App 新增子網域。每個子網域就代表不同的來源,例如 app1.example.com 或 app2.example.com。建立子網域很簡單,而且大多數的網域托管服務供應商也都不額外收費。服務供應商一般會免費提供特定數量的子網域。以下即為子網域的新增範例。

+
+

新增子網域的常見步驟

+
    +
  1. 登入托管服務供應商的管理介面,找到自己所使用的網域。
  2. +
  3. 找到設定網域的頁面。
  4. +
  5. 找到可新增子網域的功能。
  6. +
  7. 新增子網域、指定子網域檔案的儲存路徑、儲存你所完成的變更。
  8. +
  9. 將自己的 App 檔案放進你在上個步驟所指定的伺服器路徑中。
  10. +
  11. 實際以瀏覽器開啟該路徑,檢驗新的子網域已確實產生。
  12. +
+

接著將說明該如何透過特定托管工具新增子網域。

+

以 cPanel 新增子網域

+

這裡提供 cPanel 建立子網域的範例。cPanel 是 Web 托管控制台,已有多家托管服務供應商採用。每個開發者的 cPanel 頁面可能因設定方式而略有不同。這裡僅提供整個介面的基本概念。

+
    +
  1. 登入 cPanel。
  2. +
  3. 往下捲動找到「Domains」區塊。 +

    +
  4. +
  5. 點擊「Subdomains」即開啟「Subdomains」頁面。 +

    +
  6. +
  7. 在「Subdomain」文字框中輸入子網域名稱。我們這裡先以「newsubdomain」為例。
  8. +
  9. 再點入「Document Root」文字框。隨著顯示的路徑,就是儲存新子網域檔案的路徑。我們這裡先以「/public_html/newsubdomain」為例。如果開發者想把 App 檔案儲存到其他位址,亦可依自己需要更改。假設你的 App 檔案位於「public_html/gamedev_com/games/coolgame/」,則可於「Document Root」文字框中鍵入該路徑。Document root
  10. +
  11. 點擊「Create」按鈕,即可收到確認訊息。
  12. +
  13. 將 App 檔案放進你指定的子網域路徑中。我們這裡先使用名為「index.html」的簡單 HTML,將顯示「This is on a new subdomain!」。
  14. +
  15. 確認新的子網域現已存在。開啟瀏覽器並輸入新的網域名稱。根據我們所使用的範例,即如下圖所示: +

    New subdomain in browser

    +
  16. +
+

以 Go Daddy 新增子網域

+

可觀看此影片,為 Go Daddy 所托管的網域添增子網域。

+
+  
diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/creating_a_store/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/creating_a_store/index.html new file mode 100644 index 0000000000..968dce2720 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/creating_a_store/index.html @@ -0,0 +1,22 @@ +--- +title: 設立自己的 App 商店 +slug: Archive/Mozilla/Marketplace/Publishing/Creating_a_store +translation_of: Archive/Marketplace/Options/Creating_a_store +--- +
+

任何 Web 網站若具備豐富的圖片與互動經驗,則 Web 瀏覽器可透過Mozilla 的 App 專案平台,將這類網站識別為「Web App」,進而能跨裝置安裝並同步這些網站。開發者現可透過此項特性,將已發佈的 App 整理到目錄與商店中。接著說明相關步驟。

+
+

與瀏覽器整合

+

App 平台即提供「navigator.mozApps」這個 JavaScript 物件,可作為商店與瀏覽器之間的溝通橋樑。

+

Web App 是根據其網域所辨識而得。而一個來源網域就只會有一個 App。針對目錄或商店,開發者可透過 App Installation API 與 App Management API,讓瀏覽器觸發 apps.install 函式並提示 App 的安裝作業,另提供 App 的 manifest 檔案網址,以及任何想要補充的後設資料 (metadata)。開發者可存取此筆後設資料,以查閱消費者的購買資訊、確認單一登入狀態 (SSO),或其他服務。

+

使用 getInstalled()

+

只要 App 是根據你的網域而安裝於目前的瀏覽器上,均可透過 navigator.mozApps.getInstalled() 函式取得此類 App 的清單。另請注意,開發者不會看到其他網域所安裝的 App,只會看到放在自己網域中的 App。

+

開發者可透過此函式而了解消費者安裝的 App 是否符合你的預期。即使消費者是以新帳戶登入你的網站,亦可透過「resync」功能而再次安裝既有的 App。

+

到底該不該托管?

+

針對托管式 App,商店只需該網站的 manifest 網址,即可觸發 App 的安裝作業 (apps.install)。該 App 檔案不一定要儲存於商店或目錄之下。

+

如果 App 沒有伺服器的邏輯元件 (也就是完全以用戶端 JavaScript、HTML、CSS 所建構的 App),開發者就可能會想建構出托管功能。此時必須為各 App 指派不同的網域名稱,並針對各 App 的 manifest 檔案建構伺服邏輯,才能使用托管功能。

+

如果你現在正自行托管 App 邏輯,則可輕鬆維護和消費者之間的會話 (Session),進而追蹤消費者的喜好、購買證明,或其他服務。如果你要針對遠端網站提供服務,就必須完成額外作業,才能支援分散式的認證系統。

+
+

注意:Firefox Marketplace API 內含的功能,讓開發者只耗費最小程度的心血,即可迅速設立自己的 App 商店。

+
+

 

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/index.html new file mode 100644 index 0000000000..280345b59e --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/index.html @@ -0,0 +1,9 @@ +--- +title: Publishing +slug: Archive/Mozilla/Marketplace/Publishing +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive/Mozilla/Marketplace/Publishing/Introduction +--- +

Marketplace publishing

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/introduction/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/introduction/index.html new file mode 100644 index 0000000000..0cdc397b2e --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/introduction/index.html @@ -0,0 +1,87 @@ +--- +title: 介紹 — App 發佈流程 +slug: Archive/Mozilla/Marketplace/Publishing/Introduction +translation_of: Archive/Mozilla/Marketplace/Publishing/Introduction +--- +
+ 你到這裡應該已經知道該如何打造成功的 App、選擇 App 發佈平台 (甚或發佈到 Firefox OS 以外的平台)、撰寫並側試過自己的程式碼。現在應該著手將 App 發表給全球的使用者知道,並於 Firefox Marketplace 上發佈。本文將引導你完成相關程序,讓你順利於 Firefox Marketplace 上發佈自己的 Open Web App,並能隨時更新檔案及有用的附加資訊。
+
+  
+
+
+

發佈指南

+
+
+ 提交作業檢查清單
+
+ 提交 App 前的準備工作。
+
+ Marketplace 審查
+
+ 審查 App 時的程序與準則。
+
+ 設定付費 App 與應用程式內付款 (In-app payment)
+
+ Marketplace 的相關功能,可設定付費式 App 與應用程式內的付款項目。另將說明 Firefox Marketplace 是如何使用第三方的付費服務,並建立廠商的帳戶。
+
+

策略與指南

+
+
+ 圖示 (應用程式中心)
+
+ 根據 Firefox OS 的不同版本,取得詳細的圖示尺寸。
+
+
+
+ 圖示設計 (Mozilla 風格指南)
+
+ 你的 App 或 In-app 產品圖示,必須符合圓形或方形設計。進一步參閱 Mozilla 風格指南。
+
+
+
+ 隱私權政策
+
+ 如果你的 App 會取得使用者的個人資料,就必須另外具備隱私權政策。指南內所提供的資訊,均必須納入你的 App 隱私權政策之中。
+
+
+
+ 擷圖指南
+
+ 若要讓自己的 App 在 Marketplace 順利上架,所提供的擷圖必須符合相關規範。
+
+ App 測試與疑難排解
+
+ 帶領你設定測試環境、實際測試  App,並解決你所發現的問題或錯誤。
+
+
+
+

提交 App

+
+
+ App 提交程序指南
+
+ 你已經準備好發佈第一個 App;也可能要以自己沒用過的方式封裝/發佈 App。到這裡了解該如何將 App 提交到 Firefox Marketplace 之上。
+
+

更新 App

+
+
+ 更新 App
+
+ 不論是要添增新功能或是修正錯誤 (當然最好不要是錯誤),定期提供 App 更新檔,才能保持 App 的能見度。本文將說明應如何透過 Firefox Marketplace 遞交 App 的更新檔案。
+
+

管理已發佈的 App

+
+
+ App 管理指南
+
+ 在發佈 App 之後,你可能想更改某個地方,或了解消費者對該 App 的接受度為何。本文將帶領你變更 App 的狀態、檢視統計資料、檢查於 Firefox Marketplace 上所獲得的評價。
+
+

更多工具

+
+
+ 為自己的 App 添增子網域
+
+ 如果要從自己的網站上提供超過 1 個的架設/托管式 (Hosted) App,就必須逐一建立子網域。本文將說明添增子網域的方式。
+
+
+
diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/managing_your_apps/app_statistics/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/managing_your_apps/app_statistics/index.html new file mode 100644 index 0000000000..6454ca8f31 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/managing_your_apps/app_statistics/index.html @@ -0,0 +1,66 @@ +--- +title: App 統計資料 +slug: Archive/Mozilla/Marketplace/Publishing/Managing_your_apps/App_Statistics +translation_of: Archive/Mozilla/Marketplace/Publishing/Managing_your_apps/App_Statistics +--- +
+

Firefox Marketplace 可提供 App 的多樣統計資料。本文將說明應如何取得自己 App 在 Firefox Marketplace 上的統計資料、報表資料的呈現方式,另可審閱報表內的特定資訊、可用的報表,並使用已匯出的報表資料。

+
+ +

取得 App 的狀態

+ +

若要取得任何已發佈 App 的狀態,須先到 Firefox Marketplace 點擊「開發者交流中心 (Developer Hub)」,再進入「我的提交 (My Submissions)」。所有已發佈的 App 都能看到 (1)「統計資訊 (Statistics)」連結。

+ +

In My Submissions, for each published app you will find a link to the app's stats page

+ +

報表介紹

+ +

在開啟了 App 的統計資訊之後,就會進入下方的統計資料表。此頁將摘要呈現目前可用的統計報表資料。

+ +

The stats dashboard provides a visual summary of your app's stats and links to the 5 reports

+ +

開發者可在此頁看到下列報表:

+ + + +

每組報表均為相同的基礎架構,如下所示:

+ +

All reports follow the same basic structure with date selector, region selector (Installs report only) graph, JSON export option and daily summary.

+ +
    +
  1. 日期選擇 — 可設定報表應顯示的開始\結束日期。
  2. +
  3. 地區選擇 (僅 Installs 報表) — 可設定報表應顯示全世界活動資料,或個別國家\地區的資料。 +
    在本文撰寫期間,此功能因資料加總功能的問題,先予以關閉。可參閱 Bug 1028448
    +
  4. +
  5. 「更新」按鈕 — 依照目前日期與地區設定,重新整理報表內容。
  6. +
  7. 按每日顯示的活動圖表。
  8. +
  9. JSON 匯出選項。
  10. +
  11. 其他按每日顯示的活動圖表。
  12. +
+ +

使用匯出的資料

+ +

你可能想在其他試算表應用中使用匯出的資料。目前尚無主流的試算表應用程式 (Microsoft 的 Excel、Apple 的 iWorks Numbers、OpenOffice 的 Calc) 能支援 JSON 格式的資料匯入功能。解決方案就是將 JSON 轉檔為 CSV 格式。此檔案格式可用於大多數的試算表應用程式。目前有許多 JSON to CSV 的線上轉檔功能:

+ + + +

此外還有下列資源提供程式碼,讓你能針對不同的試算表應用程式,建立自動匯入功能:

+ + diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/marketplace_screenshot_criteria/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/marketplace_screenshot_criteria/index.html new file mode 100644 index 0000000000..76f2576eff --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/marketplace_screenshot_criteria/index.html @@ -0,0 +1,80 @@ +--- +title: Marketplace 截圖準則 +slug: Archive/Mozilla/Marketplace/Publishing/Marketplace_screenshot_criteria +translation_of: >- + Archive/Mozilla/Marketplace/Publishing/Policies_and_Guidelines/Marketplace_screenshot_criteria +--- +
+

在將 App 提交至 Firefox Marketplace 時,開發者必須提供 1 幅或更多截圖以供使用。Marketplace 另提供此類截圖的非硬性規範,可作為開發者截圖時的準則。如果 App 截圖均未能符合本篇文章所載明的規範,則可能會要求開發者提交新的截圖。

+
+

截圖概述

+ +

截圖重點

+ +

總而言之,截圖應該以 App 為重點,而不是 App 周圍的情境。

+

尺寸與格式

+

截圖可為 JPG 與 PNG 格式。若是較能保有原來解析度的 PNG-24 最好。如果是 JPG 格式,則應儘量使用最小幅度的壓縮並設定為最高圖像品質。

+

建議尺寸

+ + + + + + + + + + + + + + + + + + + + + +
裝置規格建議的解析度
手機 +

320x480 的倍數、720x1280 的倍數;或 480x320 的倍數、1280x720 的倍數

+
平板電腦1024x768 的倍數、1280x800 的倍數
桌上型電腦1280x800 的倍數、1440x900 的倍數
+

範例

+

不要出現與 App 無關的圖素,如廣告或商標。

+

+

不要提供「手拿著裝置」的照片,或將截圖編輯到實體裝置之上。

+

+

截圖不需使用/添加裝置的邊框、不必要的文字、其他不必要的特色。

+

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/packaged_apps/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/packaged_apps/index.html new file mode 100644 index 0000000000..cf9937c110 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/packaged_apps/index.html @@ -0,0 +1,75 @@ +--- +title: 封裝式 (Packaged) App +slug: Archive/Mozilla/Marketplace/Publishing/Packaged_apps +translation_of: Archive/Mozilla/Marketplace/Options/Packaged_apps +--- +

封裝式 (Packaged) App 屬於 Open Web App,即以 ZIP 壓縮檔納入其 HTML、CSS、JavaScript、manifest 檔案等所有資源,不像之前必須將資源置於網路伺服器之中。本篇文章將為開發者提供封裝式 App 的相關說明 。

+

封裝式 App 為 ZIP 壓縮檔,內含 Open Web App 能夠運作的所有資源,並將 manifest 檔案置於其根目錄之下,且此 manifest 檔案將提供 App 本身的說明、圖示等資訊,以利辨識出已安裝的 App。此封包接著可將 App 安裝到 Firefox OS 裝置、Android 裝置桌機之中。一旦在裝置上安裝 App 之後,仍可存取 Web 上的資源,如伺服器上的資料庫。

+

封裝式 App 另可分為三類:Web App、Privileged App、Certified App。封裝式 App 可作為任何形式的 Open Web App;Privileged 與 Certified App 則是透過數位簽章的方式,啟動 Privileged 與 Certified API。Privileged App 簽章之後即成為 Marketplace 審查流程的一部分;Certified App 則是由裝置製造商或電信營運商進行簽章。

+

封裝式 App 除了能使用 Privileged 與 Certified API 之外,也能在安裝之後更快取得裝置的資源,達到更快的首次啟動速度。基於這些特色,我們也針對 Firefox OS 裝置、Android 裝置桌機,均建議以封裝式 App 的形式提供 Open Web App。

+
+

注意:目前 Firefox Marketplace 上所支援的付費封裝式 App,僅限為 Firefox OS App。而免費封裝式 App 已可支援 Firefox OS、行動版 Firefox (Firefox for Android)、桌面版 Firefox。現正開發可支援所有平台的付費 App。

+
+
+

注意:你會在 Firefox 開發者工具的「應用程式管理員 (App Manager)」看到「manifest」中文翻譯為「安裝資訊檔」。

+
+

App 的類型

+

封裝式 App 可分為 Web App、Privileged App、Certified App,且均可對應 Firefox OS 不同程度的 App 安全性模式。接著將提供進一步資訊。

+

Web app

+

Web App 不會使用 Privileged 或 Certified API。在提交到 Marketplace 之後,App 的封包隨即簽章完成,但仍尚未執行 Privileged 或 Certified App 所使用的特殊授權程序。也因此 Web App 不能使用 Privileged 或 Certified API。這些 App 也不需要 Privileged 與 Certified App 所必備的內容安全政策 (CSP)。

+

這種封裝式 App 的 manifest.webapp 檔案中,不需要 type 欄位。其 type (web) 的預設值就是正確的值。

+

Web App 可自行發佈,或可透過 Firefox Marketplace 發佈。Web App 亦可透過架設/托管式 App 的機制對外提供。

+

Privileged app

+
+
+  
+
+ Privileged app 是由 Firefox OS Marketplace 以特殊程序核准之後發出。如果任一 App 要存取裝置上的特定 Sensitive API,則可為使用者提供更高的安全性。此種 App 即等同 iOS 或 Android 平台上的原生 App。若要指定為 Privileged App,必須在其 manifest.webapp 檔案中添增 type 欄位並設定為 privileged。App 所要存取的 privileged API,均必須加入 manifest 檔案的 permissions 欄位中。
+
+ Firefox OS、Web runtimes for Android、桌機,將針對 Privileged App 強制使用下列 CSP
+
+
+
+
"default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'"
+

Privileged App 僅能透過 Firefox Marketplace 發佈。

+
+
+  
+
+

Certified app

+
+
+  
+
+
+

一般第三方開發者並不會接觸到 Certified App;且 Certified App 也不會透過 Firefox Marketplace 發佈。這類 API 的長遠目標,就是要讓本身的憑證更完善、更具公信力,進而也能作為 Privileged API。如果你不是很想架構特定的 API,也可直接在 dev-webapps 郵件群組中反應。

+
+
+
+ Certified App 將透過 Certified API 而存取重要的系統功能,如智慧型手機上預設的撥號鍵盤,或系統設定 App。與 Privileged App 相較,並不會用於第三方 App,所以大多數的 App 開發者可忽略此類 App。除了所有的裝置許可均為隱式許可 (Implicit permission,意即不需要外部的使用者許可) 之外,Certified 與 Privileged App 大部分均屬於相似的封裝式 App。而 Certified App 必須取得 OEM 裝置或電信營運商裝置的許可,才能讓此隱式 App 使用重要 API。若要將 App 指定為 Certified App,則需於其 manifest.webapp 檔案中添增 type 欄位並設定為 certified
+
+ Firefox OS 則針對 Certified App 建構了下列 CSP: +
"default-src *; script-src 'self'; object-src 'none'; style-src 'self'"
+ 與 Certified App 相較,Privileged App 則是針對 inline CSP 的影響而稍微放寬了限制。進一步了解其原因,可參閱預設 CSPBug 768029
+
+ OEM 廠商與電信營運商均已將 Certified App 安裝到裝置之上。
+
+  
+
+

測試封 App

+

如果要透過 Firefox OS 模擬器 (Firefox OS Simulator),測試 Firefox OS 裝置在安裝封裝式 App 的情形,可參閱《應用程式管理員 (App Manager)》。開發者也能透過《App 發佈方式》中的步驟,從一般網頁伺服器上安裝該 App 到裝置上。另請注意,如果你要自己發佈 App,就只能安裝封裝式 Web App。

+

發佈封裝式 App

+

有兩種方式可發佈封裝式 App:透過 Firefox Marketplace 或自行發佈。

+

透過 Firefox Marketplace 發佈

+

可參閱 App Publishing,將封裝式 App 提交到 Firefox Marketplace 之上。

+

在提交封裝式 App 時,其 zip 檔案即儲存於 Marketplace 伺服器之上,且 Marketplace 將根據封裝式 App 的 zip 檔案中的 manifest,產生新的「mini-manifest」檔案。在消費者安裝 App 時,隨即將 mini-manifest 傳送至 Apps.installPackage() 函式以安裝該 App。僅安裝與更新程序才會使用 mini-manifest。App 執行期間並不會使用此檔案。

+

自行發佈

+

當然也能在 Firefox Marketplace 之外,也就是自己的網路伺服器上發佈封裝式 App。可參閱《自行發佈 App》。

+

更新封式 App

+

若要進一步了解更新作業,請參閱《更新 App》。

+

更多資訊

+ diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/policies_and_guidelines/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/policies_and_guidelines/index.html new file mode 100644 index 0000000000..d914835648 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/policies_and_guidelines/index.html @@ -0,0 +1,10 @@ +--- +title: Policies and Guidelines +slug: Archive/Mozilla/Marketplace/Publishing/Policies_and_Guidelines +tags: + - NeedsTranslation + - Structure + - TopicStub +translation_of: Archive/Mozilla/Marketplace/Publishing/Policies_and_Guidelines +--- +

This section contains Firefox Marketplace policies and guidelines

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/policies_and_guidelines/introduction/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/policies_and_guidelines/introduction/index.html new file mode 100644 index 0000000000..230c5d714a --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/policies_and_guidelines/introduction/index.html @@ -0,0 +1,39 @@ +--- +title: 簡介 ─ 政策與指南 +slug: Archive/Mozilla/Marketplace/Publishing/Policies_and_Guidelines/Introduction +translation_of: Archive/Mozilla/Marketplace/Publishing/Policies_and_Guidelines/Introduction +--- +
本文將提供 Firefox Marketplace 所用的多項政策與指南。
+ +
下列政策與指南均為 Firefox Marketplace 所用:
+ +
 
+ +
+
+

政策

+ +
+
隱私權政策
+
如果 App 需用到消費者的個人資料,就必須提供隱私權政策。
+
+
+ +
+

指南

+ +
+
隱私權政策
+
如果 App 需用到消費者的個人資料,則相關指南可提供 App 隱私權政策中所需的資訊。
+
+ +
+
截圖指南
+
為 App 截圖的相關指南,且截圖亦可用於 Marketplace 上架展示。
+
App 測試與疑難排解
+
相關資訊將說明測試環境的設定方式,以利測試 App 並解決可能發現的問題。
+
+
+
+ +

 

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/pricing/introduction/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/pricing/introduction/index.html new file mode 100644 index 0000000000..6c505166dd --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/pricing/introduction/index.html @@ -0,0 +1,57 @@ +--- +title: 簡介 — 制定 App 的價格 +slug: Archive/Mozilla/Marketplace/Publishing/Pricing/Introduction +translation_of: Archive/Marketplace/Publishing/Pricing/Introduction +--- +
+

本文將陸續新增相關內容,請隨時注意更新資訊。

+
+ +
要讓自己的 App 透過 Firefox Marketplace 獲得收益很簡單:為自己的帳戶設定 1 或更多的付款服務供應商,再設定 App 價格與發售國家 (免費 App 也能讓消費者升級為付費版本)。如果你要使用「應用程式內付款 (In-app payment)」功能,就必須取得 API 金鑰並定義 App 內販售的產品。本文將帶領你在 Firefox Marketplace 中設定付費的Open Web App 及其內部販售產品,另提供有用的相關資訊。
+ +
 
+ +
+
+

設定付費 App

+ +
+
付費帳戶
+
設定帳戶的付款服務供應商,才能收取 App 售出及其內部付款的收益。
+
訂價 (敬請期待)
+
設定 App 價格與銷售國家等選項。
+
以「升級」方式推廣
+
免費 App 亦可升級為付費 App。
+
+ +

更多資訊

+ +
+
 
+
檢驗收據
+
該如何檢查消費者是否付款購買 App。
+
價格點數
+
依國家訂價的相關資訊。
+
+
+ +
+

設定應用程式內付款

+ +
+
取得自己的 API 金鑰 (敬請期待)
+
為自己的 App 取得 API 金鑰。
+
定義應用程式內販售的產品
+
於 Marketplace 上設定 fxPay 的應用程式內產品。
+
+ +

更多資訊

+ +
+
檢驗收據
+
該如何檢查消費者是否付款購買 App 內販售的產品。
+
+
+
+ +

 

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/pricing/payment_accounts/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/pricing/payment_accounts/index.html new file mode 100644 index 0000000000..e6938f4336 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/pricing/payment_accounts/index.html @@ -0,0 +1,61 @@ +--- +title: 付款帳號 +slug: Archive/Mozilla/Marketplace/Publishing/Pricing/Payment_Accounts +translation_of: Archive/Marketplace/Publishing/Pricing/Payment_Accounts +--- +
+

如果要在 Firefox Marketplace 設定付款 App 或應用程式內付款 (In-app payment) 產品,首先就是設定 1 家或更多的付款服務供應商。本文將說明 Firefox Marketplace 搭配多家供應商的理由、提交程序中所應完成的設定,另提供各家供應商的帳號資訊。

+
+ +

付款服務供應商

+ +

目前配合 Firefox Marketplace 活躍中的付款服務供應商就是「Bango」,當然 Firefox Marketplace 未來將支援其他供應商。付款服務供應商可新增其他付款選項,如付款類型、電信營運商、收款國家等。另間「Boku」供應商很快就會加入 Marletplace。供應商另可透過 Marketplace 讓消費者選用其服務;但目前尚未有供應商支援此一選項。

+ +
+

在交易付費 App 時,均必須透過  Firefox Marketplace 中的付款服務供應商之一。如果 App 亦提供應用程式內付款的產品,也可配合其他供應商,但開發者必須自行滿足必要的推銷與技術需求。

+
+ +

供應商的功能

+ +

所有的付款服務供應商必須達到下列:

+ + + +

設定自己的付款帳號

+ +

 Marketplace 提交程序的「相容性與付款 (Compatibility & Payments)」頁面上,找到「付款帳號 (Payment Accounts)」區塊並設定付款服務供應商。

+ +

The Payment Accounts section of the Compatibility and Pricing page

+ +

在設定付款帳號與供應商兩者時,所需的資訊有所不同。但同樣必備的資訊如下:

+ + + +
+

在大多數的情況下,付款服務供應商也有在其他國家運作,因此會透過某些形式的國際銀行轉帳作業支付款項給開發者。這類交易都會需要收款銀行的識別代碼。常用的代碼有:

+ + + +

其實只要透過 Google 查詢自己開戶的銀行名稱與匯款代碼 (可能是 SWIFT 或 BIC 或 IBAN),往往都能找到銀行的相關資訊。可在你開戶銀行的網站上尋找「跨國轉帳」、「收取海外匯款」或類似字眼。此外還有某些工具可協助你找到相關代碼:

+ + +
+ +

以下連結可找到付款服務供應商的設定資訊:

+ + diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/pricing/promote_as_upgrade_to_free_version/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/pricing/promote_as_upgrade_to_free_version/index.html new file mode 100644 index 0000000000..d0eb6c32a4 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/pricing/promote_as_upgrade_to_free_version/index.html @@ -0,0 +1,26 @@ +--- +title: 建議升級 App 的免費版本 +slug: >- + Archive/Mozilla/Marketplace/Publishing/Pricing/Promote_as_upgrade_to_free_version +translation_of: Archive/Marketplace/Publishing/Pricing/Promote_as_upgrade_to_free_version +--- +
+

談到 App 的相容性與付款選項時,可讓 App 的免費版本升級為付費版本,並透過 Firefox Marketplace 提出此一推銷建議。此一選項可供消費者先體驗功能有所限制的 App,在決定是否購買完整功能的版本。或是免費版本會顯示廣告,付費版本則無廣告;或可為其他類似的組合。本文章說明設定方式,並讓 Firefox Marketplace 顯示升級資訊。

+
+ +

在「相容性與訂價 (Compatibility & Pricing)」頁面底部,可看到「以升級至免費版本促銷 (Promote as upgrade to free version)」區塊。而在「這個付費版本升級此附加元件 (This is a paid upgrade of)」方塊中,你可選擇要哪些免費 App 可升級為付費 App。一旦選擇對應的免費版本 App 之後,就點擊「儲存變更 (Save Changes)」。

+ +

Promote as upgrade to free version section of the Compatibility & Pricing page

+ +

一旦 App 通過審查並發佈於 Firefox Marketplace 之上,則免費 App 列表中就會出現下列附加資訊:

+ + + +

若要進一步了解 App 的銷售方式,可參閱〈選擇自己的商業模式〉。

+ +

 

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/privacy_policies/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/privacy_policies/index.html new file mode 100644 index 0000000000..80c1bc6b62 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/privacy_policies/index.html @@ -0,0 +1,28 @@ +--- +title: 隱私權政策制定指南 +slug: Archive/Mozilla/Marketplace/Publishing/Privacy_policies +translation_of: >- + Archive/Mozilla/Marketplace/Publishing/Policies_and_Guidelines/Privacy_policies +--- +

隱私權極難以界定,且牽涉到法律、社會規範、使用者期望等複雜的概念。不論是 App、網站、網頁、附加元件的開發者,都必須謹慎對待使用者的隱私權以獲得信賴。Mozilla 集結相關指南並制定極佳的隱私權政策,以協助開發者建構出注重隱私權的 App。但請注意,本文並無法取代真正律師所提供的實質法律服務。

+

隱私權政策

+

隱私權政策用以闡述你對資料的處理方式。關鍵在於開發者蒐集使用儲存共用揭露個人資訊的方法。Mozilla 則集結成隱私權政策範本,讓開發者能簡單說明自己的隱私權政策。

+
https://github.com/flamsmark/privacy-policy-template
+
+

首先請參閱 README。此範本僅可協助你制定部分的隱私權政策。Mozilla 前提是協助開發者能更輕鬆制定隱私權政策,但無法保證此範本已經面面俱到。至少此範本能讓你注意到主要的隱私權問題並進一步思考。敬請使用該範本並自行強化不足的部份。

+

此範本也是很好的實作機會 (某些情況下必須兼顧適法性的問題)。開發者可透過隱私權政策讓消費者知道自己的資訊將何去何從。全世界有這麼多不同的國家,對使用者資料的蒐集、使用、儲存、揭露方式的要求也有所差異。開發者應透過律師了解不同的隱私權政策,並確實讓消費者得知自己應熟悉的要點。

+

Mozilla Marketplace 的隱私權要求

+

如果任一 App 或附加元件 (Add-on) 將蒐集消費者的資料,則開發者就必須提供隱私權政策並將之列於 Mozilla Marketplace 之中。

+

設計 App 的隱私權要點

+ diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/publish_options/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/publish_options/index.html new file mode 100644 index 0000000000..c7b213c18c --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/publish_options/index.html @@ -0,0 +1,145 @@ +--- +title: 自行發佈 App +slug: Archive/Mozilla/Marketplace/Publishing/Publish_options +translation_of: Archive/Mozilla/Marketplace/Options/Self_publishing +--- +
+

開發者可能不想透過 Firefox Marketplace 發佈 App,例如你只想提供給組織內的成員、執行測試版 App,或只是自己試好玩的。本篇文章將說明開發者如何在 Firefox Marketplace 之外自行發佈 App。

+
+

 

+

Open Web App 可透過 {{ domxref("Apps.install") }} 或 {{ domxref("Apps.installPackage") }},安裝到 Firefox OS、執行 Firefox for Android 的裝置,或是執行桌面版 Firefox 的桌機之上。而這些 API 均會送出 manifest 檔案的網址,其內將敘述所將安裝的 App。因此要自行發佈 App 就必須滿足下列基本要求:

+
    +
  1. 伺服器必須裝載 App 的 manifest 檔案
  2. +
  3. 伺服器必須裝載 (架設/托管式) App,或 (封裝式) App 的 ZIP 檔案
  4. +
  5. 置於網站上的程式碼必須觸發合適的 {{ domxref("Apps.install") }} 或 {{ domxref("Apps.installPackage") }}
  6. +
+

限制

+

在自己發佈 Open Web App 之前,必須注意下列限制:

+ +

自行發佈封裝式 App

+

只要在伺服器上架設/托管 ZIP 檔案與其 mini-manifest,就能自行發佈封裝式 App。而 mini-manifest 必須置於 ZIP 相同的目錄之下,以利安裝程序能識別 App。接著可建立指令碼以觸發 {{ domxref("Apps.installPackage") }},送出 mini-manifest 的細節。可參閱下方以了解:

+
    +
  1. +

    將 App 的內容壓縮為 ZIP 並命名為 package.zip。 此檔案應容納 App 的所有資源檔案,並包含 (主要) manifest 檔案。

    +
    +

    重要:請注意封裝式 App 所要壓縮的內容,不要包含檔案本身的目錄。如果你連母目錄都壓縮進去,則 manifest 檔案就位於錯誤地方,整個封裝式 App 隨即無效。

    +
    +
  2. +
  3. 建立名為 manifest.webapp 的檔案,並加入以下內容。此檔案即所謂的 mini-manifest,也是封裝式 App 壓縮檔內的精簡版 manifest 檔案。而 {{ domxref("Apps.installPackage") }} 將使用 mini-manifest,以進行 App 的安裝程序。若要進一步了解細節,可參閱下方的 Mini-manifest 欄位
    +
    {
    +    "name": "My sample app",
    +    "package_path" : "http://my-server.com/my-app-directory/package.zip",
    +    "version": "1",
    +    "developer": {
    +        "name": "A. Developer",
    +        "url": "http://my-server.com"
    +    }
    +}
    +
  4. +
  5. 建立可安裝 App 的指令碼。這裡我們使用了名為「index.html」的簡易 HTML 檔案。但你也可將指令碼新增至按鈕,或使用任何適當的函式,以於自己的網站上觸發作業。此頁面上的 JavaScript 將呼叫 Packaged App installer API ({{ domxref("Apps.installPackage") }}),並針對安裝作業的成功與否進行回呼 (Callback)。 +
    <html>
    +  <body>
    +    <p>Packaged app installation page</p>
    +    <script>
    +      // This URL must be a full url.
    +      var manifestUrl = 'http://my-server.com/my-app-directory/manifest.webapp';
    +      var req = navigator.mozApps.installPackage(manifestUrl);
    +      req.onsuccess = function() {
    +        alert(this.result.origin);
    +      };
    +      req.onerror = function() {
    +        alert(this.error.name);
    +      };
    +    </script>
    +  </body>
    +</html>
    +
  6. +
  7. 將「package.zip」、「package.manifest」、「index.html」複製到你指定的目錄中 (此範例則為 my-app-directory),即可在自己的伺服器或網站上設定檔案。
  8. +
  9. 以相容設備 (如 Firefox OS 手機) 安裝 App。只要開啟 index.html 檔案 (此範例的路徑為 http://my-server.com/my-app-directory/index.html)  就會看到系統詢問是否要安裝該 App。繼續執行安裝步驟直到完畢,接著網頁指令就會顯示安裝作業是否成功。
  10. +
+
+

秘訣:你可於本端架設/托管 1 個封裝式 App,並於裝置中進行測試。伺服器與裝置必須位於同一個網路之上,而伺服器必須能接收本端網路的請求。你只要在 mini-manifest 檔案的 package_path 中加入絕對路徑即可。只要用相同的方式,正常情況就已經納入絕對路徑 (可參閱下方)。如果要使用非標準通訊埠,例如 http://10.10.12.1:8080/package.zip,則記得應納入通訊埠的資訊。

+
+

Mini-manifest 檔案的欄位

+

如果要在 Firefox Marketplace 發佈 App,就不需擔心該如何建立 mini-manifest 檔案;Firefox Marketplace 可為開發者代勞。Marketplace 將使用 manifest 檔案中的相關資訊。可參閱《App 的 manifest 檔案》一文。

+

如果要自行發佈 App,也就必須自行建立 mini-manifest 檔案。最好就是複製「主要」的 manifest 檔案,並依需求將之更新。先複製完整內容就能輕鬆建立 mini-manifest 檔案,因其內的 nameversiondeveloperlocales 欄位必須完全相同。開發者亦可添增其他內容。mini-manifest 檔案專屬的欄位則包含 package_pathrelease_notessize

+
+
+ package_path (必填)
+
+ 儲存 App 壓縮檔的絕對路徑 (需為完整的網址,如  http://my-server.com/my-app-directory/manifest.webapp)
+
+ release_notes (選填)
+
+ App 版本資訊。在 Firefox Marketplace 的提交過程中,就必須提供此項資訊。
+
+
+
+ size (選填)
+
+ 以 byte 計算的 App 壓縮檔容量。而 {{ domxref("Apps.installPackage") }} 將使用此項資訊,才能在安裝過程中顯示安裝進度。
+
+

以下提供範例:

+
{
+  "name": "My app",
+  "package_path": "http://thisdomaindoesnotexist.org/myapp.zip",
+  "version": "1.0",
+  "size": 172496,
+  "release_notes": "First release",
+  "developer": {
+    "name": "Developer Name",
+    "url": "http://thisdomaindoesnotexist.org/"
+  },
+  "locales": {
+    "fr-FR": {
+      "name": "Mon application"
+    },
+    "se-SE": {
+      "name": "Min balla app"
+    }
+  },
+  "icons": {
+    "16": "/icons/16.png",
+    "32": "/icons/32.png",
+    "256": "/icons/256.png"
+  }
+}
+

此範例中的其他欄位包含:

+
+
+ name (必填)
+
+ App 的名稱,最長 128 個字元。
+
+ version (選填)
+
+ App 的目前版本。
+
+ developer  (選填)
+
+ 開發者的資訊,內含 nameurl 欄位。而 mini-manifest 與 manifest 檔案中的開發者資訊必須相同。
+
+ locales (選填)
+
+ 語系資訊,必須為 xx-YY 格式。
+
+ icons (選填)
+
+ App 所使用的圖示。
+
+

若要進一步了解 manifest 檔案,可參閱《App 的 manifest 檔案》。

+

自行發佈架設/托管式 App

+

與封裝式 App 相較,如果你建立內容的方式,就與 Firefox Marketplace 發佈的方式相同,則自行發佈架設/托管式 (Hosted) App 就更簡單了。基本上就是為自己的 App 建立 manifest 檔案。接著加入程式碼以觸發 {{ domxref("Apps.install") }}。此程式碼必須與上述封裝式 App 所用的相同。唯一不同點在於,你可對 manifest 檔案設立相對的參考位置。

+

另請參閱

+ +

 

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/submission_checklist/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/submission_checklist/index.html new file mode 100644 index 0000000000..5f029ca0c3 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/submission_checklist/index.html @@ -0,0 +1,72 @@ +--- +title: 提交作業檢查清單 +slug: Archive/Mozilla/Marketplace/Publishing/Submission_checklist +translation_of: Archive/Mozilla/Marketplace/Publishing/Submission_checklist +--- +
+

在將自己的 App 提交到 Firefox Marketplace 之前,當然該確認是否已經掌握了所有必要資源。本文則提供檢查項目與相關資訊的連結。

+
+

提交作業檢查清單

+

要完成 Firefox Marketplace 的提交程序,你需要:

+

針對封裝式 (Packaged) App

+ +

針對架設/托管式 (Hosted) App

+ +
+

在將 App 提交到 Firefox Marketplace 之前,可使用「測試應用程式驗證」工具來測試 manifest 檔案的正確性。

+
+
+

注意:你會在「應用程式管理員 (App Manager)」看到「manifest」中文翻譯為「安裝資訊檔」。

+
+

針對所有 App (必備)

+

架設/托管式、封裝式 App 的共通必要條件:

+ +

針對付費 App 或應用程式內付款 (In-app payments)

+ +

針對所有 App (非必備)

+

架設/托管式、封裝式 App 的建議條件:

+ +

另外還有......

+

......你應該:

+ diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/submit/enter_your_apps_details/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/enter_your_apps_details/index.html new file mode 100644 index 0000000000..88211b4b18 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/enter_your_apps_details/index.html @@ -0,0 +1,129 @@ +--- +title: 輸入 App 上架時所顯示的詳細資訊 +slug: Archive/Mozilla/Marketplace/Publishing/Submit/Enter_your_apps_details +translation_of: Archive/Mozilla/Marketplace/Publishing/Submit/Enter_your_apps_details +--- +
+

在將 App 上傳到 Firefox Marketplace 之後,應更新 App 的詳細資訊以利於 Marketplace 頁面上顯示。

+
+ +
+

此步驟將針對 App 的預設語系版本 (英文),編輯相關細節 (如網址與說明等)。如果你有其他語系版本,或是要針對其他國家\語系而修改詳細資訊,仍必須透過標準的「編輯資訊 (Edit Listing)」選項 (可參閱 step 9)。

+
+ +
+

注意:你可能會看到「manifest 檔案」的正體中文翻譯為「安裝資訊檔」。

+
+ +

現在進入「提交 App、編輯 App 詳細資訊」的頁面。

+ +

Edit app details page header

+ +

如頁面中所示,你在 manifest 檔案中提供的 App 詳細資訊,會由系統預先填入大部分的頁面空格之中。

+ +

App 圖示與網址

+ +

在 manifest 檔案中提供的 App 圖示與說明,再加上檔案儲存網頁的網址,都已經列於此頁面的第一區塊內。Marketplace 將根據 App 名稱而自動產生網址,並逕行修改以成為專屬網址。你可以點擊 (1)「開啟詳細資訊頁面 (Open details page)」以檢視 Marketplace 的細節頁面,也能點擊 (2)「編輯 (Edit)」以編輯圖示與Marketplace 的網址。

+ +

When the page first loads your app name and icon are displayed (based on the manifest content) along with the URL generated by Marketplace

+ +

若要更改 App 的圖示,就點擊 (1) 的圖示就能瀏覽電腦上的其他圖檔。若要更改 App 詳細資訊的頁面名稱,可於 (2) 的 App 網址方塊中輸入新的值。如果你輸入目前已存在的頁面名稱,就會出現警告訊息,直到你修改完畢並點擊「繼續 (Continue)」為止。而且必須修改成有效的 App 詳細資訊頁面網址,否則就無法離開此頁面。

+ +

You can (1) change the app's icon and (2) enter your own page name for the app

+ +

App 說明

+ +

接著下個區塊則顯示 App 的相關說明,也是直接取自於 manifest 檔案而來。你也可以依照自己需要而在「說明 (Description)」方塊中編輯說明。只要拖曳方塊右下角,就能拉大整個編輯方塊的面積。此為必填欄位。

+ +

You can create a description over 1024 characters and include some HTML tags to improve formatting.

+ +

與 manifest 檔案所提供的說明不同,這裡讓你編輯的說明內容可以:

+ + + +

App 分類

+ +

Marketplace 是以「分類 (Category)」提供 App 完整列表。開發者必須為自己的 App 勾選至少一項分類,當然也可以視需要而勾選他項適合的分類。舉例來說,如果 App 可擷取、編輯、分享照片,你當然可以勾選「Photo & Video」與「Social」兩種分類。

+ +

You must pick one, but can pick 2, categories that match your app'scontent

+ +

隱私權政策

+ +

開發者必須提供 App 的隱私權政策,即使 App 聲稱不會蒐集個人資料,也同樣必須提供。如果 App 會蒐集消費者的個人詳細資訊,就必須提供詳盡的政策 (網頁連結或純文字均可)。你可到《隱私權政策指南》 找到的撰寫資訊。而上述「說明」欄位所支援的 HTML 標籤,也同樣可用在政策撰寫時的格式。這裡一樣拖曳 (1) 方塊的右下角,能拉大編輯方塊的面積空間。

+ +

A privacy policy must be provided, even if its only to say that no personal data is collected by the app

+ +

App 資訊與支援服務連結

+ +

如果有 App 首頁與支援服務頁面的網址,亦可一併提供。但你至少須提供電子郵件位址,以利消費者聯絡後續支援服務。

+ +

Link can be provided to any information or support pages for the app, however a support email address must be provided

+ +
+

支援服務的電子郵件位址,即納入 App 於 Marketplace 上架時的公開清單中。建議你應提供專屬的電子郵件位址,而不要使用一般的免費郵件位址。

+
+ +

是否支援 Flash

+ +

如果你針對 Adobe Flash 而開發 Web App 的內容,則請在這裡點選「Yes」代表使用了 Adobe Flash。反之則點選「No」。

+ +

Indicate whether your app has need for Flash support

+ +

截圖與影片

+ +

現在可為自己的 App 加上截圖與影片了。點擊 (1)「新增螢幕截圖或影片 (Add a screenshot or video)」,就能瀏覽電腦的檔案,找到對應的檔案並點選即可。若添增超過 1 支以上的檔案,就能拖曳 (2) 檔案以變更 Marketplace 中呈現的順序。亦可點擊 (3) 的刪除圖示,移除你不想要的檔案。

+ +

截圖可為 PNG 或 JPG 格式,影片則為 WebM 格式。建議手機截圖為 320 x 480 px 尺寸。另可參閱《Marketplace 截圖準則》,以及《Promoting your app》的〈Videos〉進一步了解。

+ +

Click Add a screenshot or video to add a new item. reorder added items and delete any unwanted items

+ +

設定發佈方式

+ +

你可決定在 App 通過 Firefox Marketplace 的審查之後,是要立刻上架 (發佈 App 並讓任何人都能在 Marketplace 中看到,另將納入搜尋結果),或是暫時不要發佈 (不發佈App。提醒開發者可稍後調整 App 上架情形)。

+ +

Selected whether your app will be added to Marketplace as soon as it's been approved or whether you will set its visibility after approval

+ +

點選「不要自動發佈我的程式 (Do not publish my app)」將可:

+ + + +

「不要自動發佈我的程式」將有更多詳細資訊供你選擇,敬請期待。

+ +
+

在你完成這一步驟之後,就無法編輯此選項。往後若要修改此選項,就必須提供 App 的更新檔才行。

+
+ +

給審查人員看的註記

+ +

最後,你可提供額外資訊給 App 審查人員觀看。特別一提,如果 App 所搭配的 Web 服務需要消費者登入才可使用,則你應提供暫時性的帳戶給審查人員試用此服務。只要拖曳方塊右下角,就能拉大整個編輯方塊的面積。

+ +

Add comments to assist the reviewer review your app

+ +
+

在你完成這一步驟之後,就無法編輯此選項。往後若要修改此選項,就必須提供 App 的更新檔才行。

+
+ +

下一步

+ +

點擊「繼續 (Contiune)」即可進到下個程序:下一步

+ +

Click Continue to proceed to the next step

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/submit/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/index.html new file mode 100644 index 0000000000..a6e3468169 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/index.html @@ -0,0 +1,10 @@ +--- +title: Submit +slug: Archive/Mozilla/Marketplace/Publishing/Submit +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive/Mozilla/Marketplace/Publishing/Submit +--- +

This section describes the process for submitting an app to Firefox Marketplace

+

Residual details: https://developer.mozilla.org/en-US/Marketplace/Publishing/Submit/Submitting_an_app

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/submit/load_your_app/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/load_your_app/index.html new file mode 100644 index 0000000000..7c657ed720 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/load_your_app/index.html @@ -0,0 +1,134 @@ +--- +title: 將 App 上傳到 Firefox Marketplace +slug: Archive/Mozilla/Marketplace/Publishing/Submit/Load_your_app +translation_of: Archive/Mozilla/Marketplace/Publishing/Submit/Load_your_app +--- +
+

在登入自己的開發者帳戶並同意開發者協定之後,就能輸入 App 的細節,再讓  Firefox Marketplace 識別其 manifest 檔案。

+
+ +
+

注意:你可能會看到「manifest 檔案」之正體中文翻譯為「安裝資訊檔」。

+
+ +

概述

+ +

現在你進入「提交 App (Submit an App )」頁面,可進行:

+ + + +

收益方式

+ +

你首先應對 App 所提供的資訊,就是其收益方式。

+ +
    +
  1. 針對自己的 App,點選 (1)「免費 (Free)」或「付費/應用程式內付款 (Paid / in-app)」分頁。
  2. +
  3. Select either Free if the app is free to download and use, or Paid / In-app of the app has to be purchased or contains any in-app payment options
  4. +
+ +
+

如果你想先讓消費者免費下載 App,再透過 App 內部付費產品獲得收益,請點選「付費 / 應用程式內付款」。

+
+ +
+

只要你點選「付費/應用程式內付款」並完成提交程序之後,就無法再將該 App 改回免費提供。但原本就點選「免費」的 App 可隨時更改為付費形式。

+
+ +

平台相容性

+ +

在選擇了免費\付費 App 之後,就該定義 App 所將賴以執行的作業系統與瀏覽器。

+ +
    +
  1. 選擇 App 相容的平台
    + Select the OS and browser implementations the app is designed to work on.
  2. +
+ +

各個平台所支援的收益方式如下。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 FreePaid /In-app
Firefox OS
Firefox for Desktop 
Firefox Mobile
+ (Firefox for Android on screen 7" or less)
 
Firefox Tablet
+ (Firefox for Android on screen over 7")
 
+ +

上傳 App

+ +

現在為 Firefox Marketplace 說明 App 類型:

+ +
    +
  1. 如果為托管\架設式 App,(1) 須先輸入 App 的 manifest 檔案所在之伺服器位址 (須為完整的 URL),再點擊 (2)「驗證 (Validate)」。
    + Enter the URL for the manifest of a Hosted App
    +
    + Marketplace 就會驗證你的 manifest 檔案。 +
      +
    • 驗證完畢,點擊「繼續 (Continue)」。
    • +
    • 若 manifest 檔案的驗證結果出現錯誤或警告,也會提供完整報告的連結。請看過報告之後修正錯誤,再重新提交 manifest 檔案進行驗證。
      + If there are errors or warning as a result of validating the app's manifest a link is provided to a full report
    • +
    +
  2. +
  3. 如果為封裝式 App,則點擊「封裝 (Packaged)」分頁並點選「選擇檔案... (Select a file...)」。接著就會開啟電腦的檔案瀏覽功能,找到 App 的 zip 檔案並上傳。
    + Click Select a file to upload a packaged app's ZIP file
    + Marketplace 現已可驗證 App 的封包。 +
      +
    • 驗證完畢,點擊「繼續 (Continue)」。
    • +
    • 若封包 (ZIP) 的驗證結果出現錯誤或警告,也會提供完整報告的連結。請看過報告之後修正錯誤,再重新封包檔案之後提交以利驗證。
      + If there are errors or warning as a result of validating the app's manifest a link is provided to a full report
    • +
    +
  4. +
+ +

了解 App 最低限度的 API 需求

+ +

在 App 驗證完成之後,就會出現「應用程式最低需求 (App Minimum Requirements)」頁面。一開始將顯示最常用的 API 需求清單。如果有找不到的 App 需求,則點擊 (1)「檢視全部 (View all)」,再 (2) 勾選所要的需求方塊。

+ +
+

消費者的裝置若不支援本頁中所選的需求,則 Marketplace 將隱藏你的 App。

+
+ +

An automatically populated list of app requirements displays, click View all and add any that have been missed

+ +

下一步

+ +

接著可點擊「繼續 (Continue)」完成下個程序。

+ +

When the details have been added to the page, clicking Continue moves onto the next step.

+ +

若要了解接下來的步驟,可繼續閱讀:輸入 App 的細節

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/submit/next_steps/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/next_steps/index.html new file mode 100644 index 0000000000..47ef08f0d5 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/next_steps/index.html @@ -0,0 +1,16 @@ +--- +title: App 提交程序的下一步 +slug: Archive/Mozilla/Marketplace/Publishing/Submit/Next_steps +translation_of: Archive/Mozilla/Marketplace/Publishing/Submit/Next_steps +--- +
+

現在你已經上傳了自己的 App,也更新了詳細資訊。接著讓你先了解接下來將完成的步驟。

+
+ +

an interface screen on the Firefox Marketplace at the start of stage 4, where you are told you can enter some more information, starting with submitting a content rating for your app.

+ +

如果你的 App 有其他語言版本,你可能想在繼續下一步之前,再補充 Marketplace 上的其他詳細資訊。這時可點擊「編輯資訊 (Edit Listing)」,或參閱《Edit other localizations》進一步了解。不論如何,當然還是跟著流程一步步完成比較簡單。

+ +

下一步

+ +

這時可點擊「繼續 (Continue)」以進到下一步驟:《取得 App 內容分級》。

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/submit/overview/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/overview/index.html new file mode 100644 index 0000000000..8c00d35b23 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/overview/index.html @@ -0,0 +1,128 @@ +--- +title: Firefox Marketplace 概述 +slug: Archive/Mozilla/Marketplace/Publishing/Submit/Overview +translation_of: Archive/Mozilla/Marketplace/Publishing/Submit/Overview +--- +
+

若要讓自己的 App 在 Firefox Marketplace 上架,就必須將 App 提交到 Marketplace 並通過審查。本頁將簡述 App 提交程序。另可參閱其他頁面以了解其他步驟。

+
+ +
+

若要進一步了解各個步驟,請逐一參閱各個步驟之連結,並從 Step 1 開始整個程序。而此頁下方亦提供步驟關係圖。

+
+ +

另可觀看提交程序影片:http://vid.ly/8k2n4w

+ +

提交程序

+ +

接著就開始將 App 提交到 Firefox Marketplace 之上:

+ +
+
Step 1 - 登入自己的開發者帳戶
+
+ +
+
Step 2 - 上傳 App
+
「提交應用程式」頁面上: +
    +
  • 設定免費\付費 App。
  • +
  • 選擇 App 對應的平台。
  • +
  • 選擇該 App 為托管\架設式 (Hosted) 或是封裝式 (Packaged): +
      +
    • 若為托管\架設式 App,應在其 manifest 檔案中提供連結。
    • +
    • 若為封裝式 App,請上傳 package.zip 檔案,且在驗證完畢之後,確認是否符合最低 API 需求。
    • +
    +
  • +
  • 點擊「繼續」
  • +
+ +
+

注意:你可能會看到「manifest 檔案」之正體中文翻譯為「安裝資訊檔」。

+
+
+
Step 3 - 輸入 App 的詳細資訊
+
+

「編輯 App 詳細資訊」頁面:

+ +
    +
  • 依自己需要而修改 App 網址。
  • +
  • 依自己需要而修改 App 相關說明 (manifest 檔案中所載)。
  • +
  • 選擇 1 到 2 種分類。
  • +
  • 提供隱私權政策。
  • +
  • 若有首頁與支援服務網站,亦請提供。
  • +
  • 提供支援服務的電子郵件位址。
  • +
  • 說明該 App 是否須 Flash 支援功能。
  • +
  • 上傳至少 1 張畫面截圖或影片。
  • +
  • 提供額外說明\註記給 App 審查人員看 (如果 App 需要登入細節,應另外說明其理由)。另請注意,只有在你提交新版本 App 時,才能修改這些註記。
  • +
  • 設定 App 是否在通過審查之後立刻上架。另請注意,只有在你提交新版本 App 時,才能修改此項設定。
  • +
  • 點擊「繼續」
  • +
+
+
Step 4 - 參閱「下一步」的細節
+
「下一步 (Next Steps)」頁面上點擊「繼續」
+
Step 5 - 取得內容分級
+
「內容分級」頁面: +
    +
  • 點擊「建立 IARC 分級憑證 (Create an IARC Ratings Certificate)」以取得新的分級,另於 IARC 網站上完成分級問卷。
  • +
  • 若要進入已取得之分級,須提供 Submission IDSecurity Code
  • +
+
+
Step 6 - 更新 App 目前對應的販售國別與付款細節
+
Step 6a - 若為免費 App (且無 In-app purchases):
+
在左側選單中點擊「相容性 (Compatibility)」。依自己需要而更改 App 即將販售的國別。
+
Step 6b - 若為付費 App (或免費 App 但有 In-app payments):
+
在左側選單點擊「相容性與付款 (Compatibility & Payments)」 +
    +
  • 設定你的付款服務供應商帳戶,如 Bango 與 Boku。
  • +
  • 設定 App 價格。確認 App 是否提供應用程式內付款的產品,並選擇即將販售 App 的國別。
  • +
  • 如果本為免費 App,須付費之後才能升級為較完整功能的「專業版」App,請先設定為免費 App。
  • +
+
+
Step 6c - 若 App 包含應用程式內付款的產品:
+
+
    +
  • 在左側選單點擊「應用程式內付款 (In-App Payments)」,取得 API 金鑰與安全金鑰。(請注意,只要為 App 添增 API 金鑰與安全金鑰之後,就必須為 App 提交更新檔。可參閱 In-app payments 進一步了解)
  • +
  • 如果你使用 fxPay,則在左側選單點擊「In-App Products」,並逐一定義你的應用程式內付款產品。
  • +
+
+
Step 7 - 設定開發團隊成員 (選填)
+
在左側選單點擊「團隊成員 (Team Members)」,並依自己的需要添增團隊成員資訊。
+
Step 8 - 檢視清單 (選填)
+
在左側選單點擊「檢視清單 (View Listing)」,檢視自己在 Marketplace 上的 App 清單。
+
Step 9 - 編輯其他本地化清單 (選填)
+
在左側選單點擊「編輯清單 (Edit Listing)」,針對 App 的本地化內容而修改 App 的網址、說明、分類,或新增 Firefox Marketplace 所支援任何語系的細節。
+
+ +

到此為止,你的 App 已進入審查程序。在左側選單點擊「狀態與版本 (Status and Version)」即可了解目前的審查進度。只要 App 提供應用程式內付款的產品,就必須加入 API 金鑰,且須在發佈 App 之前提交更新檔案。

+ +

流程圖

+ +

 

+ +

+ +

下一步?

+ +

提交 App 完畢之後,你可能會需要:

+ + diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/submit/sign-in_to_your_developer_account/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/sign-in_to_your_developer_account/index.html new file mode 100644 index 0000000000..e46dbad938 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/submit/sign-in_to_your_developer_account/index.html @@ -0,0 +1,52 @@ +--- +title: 登入 Firefox Marketplace 上的開發者帳戶 +slug: >- + Archive/Mozilla/Marketplace/Publishing/Submit/Sign-in_to_your_developer_account +translation_of: >- + Archive/Mozilla/Marketplace/Publishing/Submit/Sign-in_to_your_developer_account +--- +
+

在將 App 提交到 Firefox Marketplace 之前,必須先申請開發者帳戶,登入之後再接受開發者協定。

+
+ +

開啟開發者交流中心 (Developer Hub)

+ +
    +
  1. 以瀏覽器開啟 Firefox Marketplace
  2. +
  3. 到 Firefox Marketplace 頁面底部點擊 (1) 開發者交流中心Footer of the Firefox Marketplace home page showing the link to the Developer Hub
  4. +
+ +

開始 App 提交程序

+ +
    +
  1. 在交流中心的首頁上,找到 (1) 提交您的應用程式至 Marketplace (Submit your app to the Marketplace)。
    + Developer Hub home page showing the Submit your app to the Marketplace button
  2. +
  3. 這時會出現「請登入」對話框,點擊 (1) 登入 / 註冊 (Sign in / Sign up)。
    + The Developer Hub please sign in dialog displayed over the Marketplace Developer Agreement
  4. +
  5. 接下來就看你是否註冊過 Mozilla Persona: +
      +
    • 如果你沒用過 Persona,建議你註冊:
      + The first dialog of the Create Persona process你可到這裡進一步了解 Persona +
        +
      1. 輸入電子郵件位址並點擊「Next」。
      2. +
      3. 輸入新的密碼並再次確認,點擊「Done」。
      4. +
      5. 到你剛剛提供的電子郵件信箱收取確認信。此郵件內含「Confirm your account now」的確認連結,點擊此連結。
      6. +
      7. 在接下來的頁面 (跟上述 step 2 顯示的頁面相同) 上點擊「登入 / 註冊」。
      8. +
      +
    • +
    • 如果你已經註冊過 Persona,就請確認你想登入為開發者帳戶的電子郵件位址。
      + Sign in with an existing Persona identity
      + 點擊「Sign in」。
    • +
    +
  6. +
  7. 就會看到開發者協定 (Developer Agreement)。
    + Read the developer agreement, select the option to receive information by email if you wish and agree to the agreement +
      +
    1. 請閱讀過開發者協定。
    2. +
    3. 同意往後接收 App Developer 新聞與問卷 (當然還是看你本身意願)
    4. +
    5. 點擊「同意並繼續 (Agree and Continue)」。
    6. +
    +
  8. +
+ +

接著就能進到下一步:上傳你的 App

diff --git a/files/zh-tw/archive/mozilla/marketplace/publishing/updating_apps/index.html b/files/zh-tw/archive/mozilla/marketplace/publishing/updating_apps/index.html new file mode 100644 index 0000000000..57fb423374 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/publishing/updating_apps/index.html @@ -0,0 +1,27 @@ +--- +title: 更新 App +slug: Archive/Mozilla/Marketplace/Publishing/Updating_apps +translation_of: Archive/Mozilla/Marketplace/Publishing/Updating_apps +--- +
+

本篇文章將針對已發佈的 App (自行發佈或於 Firefox Marketplace 上發佈),說明相關更新步驟。

+
+
+

注意:如果 App 已通過 Marketplace 審查,而開發者想更改 App 的名稱,就必須再次提交 App 並重新審查。

+
+

更新托管式 (Hosted) App

+

托管式 App 本質就是網頁,因此同樣依 Web 快取的常規而運作。但開發者亦可選用如 HTML5 AppCache 的進階機制以加快啟動速度。先了解這二點之後,更新 App 所使用的一般資源大概就沒有需要特別注意的地方了。

+

但 Open Web App 在處理 manifest 檔案時就不太一樣了。某些 manifest 的變動必須經過使用者許可。但根據 Web runtime 實作的不同,較難以確定是否會啟動更新作業。

+

如果要能確實解決此問題,開發者可於 manifest 檔案中添加「version」欄位。只要檢查 navigator.mozApps.getInstalled() 函式所回傳的值,即可了解目前的版本。如果消費者並未安裝最新版本,則可透過 navigator.mozApps.install() 觸發更新作業。

+

Web runtime 並不會使用 version 的值,所以開發者可使用任何喜歡的版號設定格式。

+

另請注意,如果因更改 manifest 檔案而發生錯誤或毀損,則一旦將 manifest 檔案提交到 Firefox Marketplace 就會發現。嚴重錯誤將導致 App 無法出現在 Marketplace 之中。若是較不嚴重的錯誤,就可能會自動標定該 App 需要重新審查。

+

更新封裝式 (Packaged) App

+

封裝式 App 與托管式 App 的更新程序有所不同。在更新封裝式 App 時,開發者必須將 App 的新版 zip 檔案上傳至 Firefox Marketplace。更新過的 App 同樣要先通過審查,才能再發佈至 Marketplace 之上。如此將於 Firefox OS 手機上觸發更新作業。消費者亦可透過「Settings」App 要求進行更新。

+

若想進一步了解封裝式 App 的更新程序,可參閱下一章節。

+

更新封裝式 App 相關細節

+

接著提供封裝式 App 更新時的相關細節。如果你打算建構 App 商城,就可能必須特別注意。

+ diff --git a/files/zh-tw/archive/mozilla/marketplace/submission/index.html b/files/zh-tw/archive/mozilla/marketplace/submission/index.html new file mode 100644 index 0000000000..2ac47dd745 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/submission/index.html @@ -0,0 +1,9 @@ +--- +title: Submission +slug: Archive/Mozilla/Marketplace/Submission +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive/Mozilla/Marketplace/Submission +--- +

Marketplace submission

diff --git a/files/zh-tw/archive/mozilla/marketplace/submission/marketplace_review_criteria/index.html b/files/zh-tw/archive/mozilla/marketplace/submission/marketplace_review_criteria/index.html new file mode 100644 index 0000000000..efabe33036 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/submission/marketplace_review_criteria/index.html @@ -0,0 +1,80 @@ +--- +title: Marketplace 審查準則 +slug: Archive/Mozilla/Marketplace/Submission/Marketplace_review_criteria +translation_of: Archive/Mozilla/Marketplace/Publishing/Marketplace_review_criteria +--- +
+

開發者若要透過 Firefox Marketplace 發佈 App,則必須先滿足本篇文章的所有條件。相關條件是為了均衡 Firefox Marketplace 開發者與消費者的需求所設計。開發者需要公平、一致、審查嚴格但不嚴苛的平台,以安心作為 App 的開發基礎;消費者希望 App 安全無虞、可在裝置上順利運作、確實進行 App 本身所載明的功能。下方所列的 App 條件,就是為了兼顧相關需求所設計。

+
+

先列出 Mozilla 的 App 審查原則:

+ +

安全性

+

可到這裡參閱 App 安全架構的相關細節:https://wiki.mozilla.org/Apps/Security

+ +

隱私性

+ +

內容

+ +

內容指南

+

Firefox Marketplace 將不會接受涉及下列內容的 App。且下方均為說明性的列表而非絕對的定義。Mozilla 亦將視情況而隨時更新。若 App 違反本內容指南所提及的任何內容,Mozilla 均有權立刻將該 App 自 Firefox Marketplace 中撤除。

+ +

功能性

+ +

使用性

+ +

黑名單政策

+

Mozilla 希望永遠都不會動用到黑名單機制,但仍保留將 App 撤除下架的權利。但只要發現已發佈的 App 違反安全性、隱私性、內容規範,或是嚴重影響系統/網路效能,我們將立刻撤除該 App。在將 App 列入黑名單之前,Mozilla 均將通知該 App 的開發者 (除非我們握有特定證據,否則會假設所有開發者都是善良好公民),並由 App 審查團隊提供完整協助,妥善溝通我們所發現的錯誤並儘力解決。以下特定情況絕對會將 App 列入黑名單並撤除下架:

+ diff --git a/files/zh-tw/archive/mozilla/marketplace/submission/pre-submission_checklist/index.html b/files/zh-tw/archive/mozilla/marketplace/submission/pre-submission_checklist/index.html new file mode 100644 index 0000000000..3299054ee5 --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/submission/pre-submission_checklist/index.html @@ -0,0 +1,36 @@ +--- +title: App 測試與疑難排解 +slug: Archive/Mozilla/Marketplace/Submission/Pre-submission_checklist +translation_of: >- + Archive/Mozilla/Marketplace/Publishing/Policies_and_Guidelines/Testing_and_troubleshooting +--- +
+

本文將說明 App 測試與疑難排解時的注意事項。

+
+

設定自己的測試環境

+

開發者可安裝多種工具,針對 Firefox OS/Open Web App 執行真正有效的測試。我們建議至少安裝下列工具:

+ +

最理想的情況,當然是能用實際裝置測試自己的 App。可參閱開發者手機指南

+

測試

+

雖然 Open Web App 與網頁,均使用相同的技術和發佈方式,但因為 App 環境並不具備如 Chrome 瀏覽器的網址列或返回按鈕;且 Firefox OS 裝置也不像 Android 有實體的退回按鈕,所以使用者經驗是截然不同。以下步驟可讓開發者確保 App 達到絕佳的使用者經驗。

+
    +
  1. 安裝 App。確認 App 的圖示有出現在主畫面上,且 App 的名稱完整未遭截斷。
  2. +
  3. 啟動 App。確認能正確偵測、顯示螢幕尺寸與方向。
  4. +
  5. 確認消費者可馬上看到你的 App,而不是看到你的首頁。請記住,若消費者是從 Firefox Marketplace 上安裝你的 App,也就是購買了 App 的功能。不需再次傳送 App 功能的登錄頁面給消費者才對。理想的 App 應該讓消費者能第一眼就看到「Getting Started」或「Login」頁面。
  6. +
  7. 從頭到尾執行過 App 的主要功能。特別注意瀏覽作業的最末端,還有內容縮放時的問題。
  8. +
  9. 確認內容連結將導向 App 之外 (如連至其他網頁或 Twitter)。若要開啟新的視窗或框架,也要讓消費者能順利返回你的 App。
  10. +
  11. 在桌面版瀏覽器中,可使用適應性設計 (Responsive Design) 檢視模式檢查 App 在不同螢幕尺寸中的情況。建議檢查 320x480 ~ 1260x800 的解析度。
  12. +
+

疑難排解

+ diff --git a/files/zh-tw/archive/mozilla/marketplace/submission/rating_your_content/index.html b/files/zh-tw/archive/mozilla/marketplace/submission/rating_your_content/index.html new file mode 100644 index 0000000000..0446f0240f --- /dev/null +++ b/files/zh-tw/archive/mozilla/marketplace/submission/rating_your_content/index.html @@ -0,0 +1,117 @@ +--- +title: 取得 App 內容分級 +slug: Archive/Mozilla/Marketplace/Submission/Rating_Your_Content +translation_of: Archive/Mozilla/Marketplace/Publishing/Submit/Rating_Your_Content +--- +
+

Mozilla 與國際年齡分級聯盟 (International Age Rating Coalition,IARC) 合作,將所有 App 均納入適用年齡分級規範。Mozilla 關心使用者,並認為使用者應能自行選擇適合自己的內容。凡 Firefox Marketplace 內的所有 App 均必須完成 IARC 分級。Mozilla 絕對在乎、愛護所有的 App,也必須要求所有 App 或遊戲完成內容分級。在 2014 年 5 月 15 日之後,只要是未完成內容分級的 App 均將強制從 Marketplace 下架。 而 IARC 另提供免費工具讓開發者進行內容分級。

+
+ +

有關 IARC 分級工具

+ +

IARC 是由多間國際級的分級委員會合力運作,針對以數位方式發佈於全球的 App 與遊戲,提供了相關工具作為內容分級的基準。只要填寫簡單表格,就會立刻收到所有分級委員會所制定的分級規範。此份規範不僅可協助消費者了解 App 的內容,亦可讓開發者不需個別取得各國的內容分級,進而大幅縮減成本與不便。

+ +

所支援的國際分級系統

+ +

透過單一的分級精靈功能,即可產生不同系統、國家、所在地區的內容分級。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
分級系統支援國家
Classificação Indicativa Brazil
ESRBCanada, Mexico, United States
PEGIAustria, Denmark, Hungary, Latvia, Norway, Slovenia, Belgium, Estonia, Iceland, Lithuania, Poland, Spain, Bulgaria, Finland, Ireland, Luxembourg, Portugal, Sweden, Cyprus, France, Israel, Malta, Romania, Switzerland, Czech Republic, Greece, Italy, Netherlands, Slovak Republic, United Kingdom
USKGermany
通用其他所有國家適用
+ +

內容分級包含哪些項目?

+ +

分級系統將提供消費者三種資訊:

+ + + +

分級程序僅需幾分鐘且完全免費,並已整合至 Firefox Marketplace 提交程序與開發者主控頁 (Developer Dashboard) 中。任何 App 均必須先完成分級,Mozilla 才能進行後續審查作業。消費者可在 App 說明頁面上看到 App 對應所在地區的分級,並取得自己想進一步了解的相關資訊。

+ +

讓自己的 App 取得內容分級

+ +

IARC 即提供免費的遊戲分級工具,且大多數的 App 都能輕鬆又快速的完成分級。接著來看看分級程序。

+ +
+

注意:Mozilla 並不接受其他系統的分級認證。即使 App 已經完成其他系統的內容分級,開發者仍需要完成 IARC 認證程序。

+
+ +
    +
  1. 登入 Firefox Marketplace 開發者網站。你必須以開發者的身分登入,才會看到分級工具。
  2. +
  3. +

    在 App 提交程序期間,就會進入 IARC 分級工具:

    + +

    Demonstrates where in the app submission flow where ratings can be entered.

    + +

    或可從開發者主控頁中找到分級工具:

    + +

    +
  4. +
  5. +

    開始分級程序:

    + +

    + +

    或可輸入現有分級的資訊:

    + +

    +
  6. +
  7. +

    填寫簡單的問卷:

    + +

    +
  8. +
  9. +

    添加 App 額外資訊:

    + +

    +
  10. +
  11. +

    預覽並確認分級資訊:

    + +

    +
  12. +
  13. +

    回到開發者主控頁就會看到分級資訊。接著就可準備上架!

    +
  14. +
+ +
+

注意:開發者接著會收到電子郵件,內含分級認證與安全碼。請自行保留相關記錄備查。

+
+ +

更多資訊

+ +

如果開發者對分級程序、分級問卷填寫方式,或對分級結果有任何疑問,請寄發電子郵件至 dev-questions@globalratings.com 向 IARC 團隊詢問。另可前往全球分級網站獲得更多資訊。

+ +

其他任何問題,可聯繫 Mozilla 的 App 審查團隊 mozilla.appreview

diff --git a/files/zh-tw/archive/mozilla/migrate_apps_from_internet_explorer_to_mozilla/index.html b/files/zh-tw/archive/mozilla/migrate_apps_from_internet_explorer_to_mozilla/index.html new file mode 100644 index 0000000000..857b8f22eb --- /dev/null +++ b/files/zh-tw/archive/mozilla/migrate_apps_from_internet_explorer_to_mozilla/index.html @@ -0,0 +1,1070 @@ +--- +title: 轉換網頁程式:從 IE 到 Mozilla +slug: Archive/Mozilla/Migrate_apps_from_Internet_Explorer_to_Mozilla +tags: + - 待翻譯 +translation_of: Archive/Mozilla/Migrate_apps_from_Internet_Explorer_to_Mozilla +--- +

這篇文章描述 IE 與 Mozilla 瀏覽器之間在程式上的差異,協助您將 IE-only 網頁改寫為 Mozilla 通用網頁。

+

簡介

+

Netscape 當初決定要製作 Mozilla 瀏覽器時刻意決定要支援 W3C 標準,因此 Mozilla 並不能完全回溯相容 Netscape Navigator 4.x 及 Microsoft Internet Explorer 的自有程式。舉例來說,Mozilla 不支援稍候會討論的 <layer> 標籤。此外,有些在 W3C 標準觀念尚未普及前製作的瀏覽器(如 Internet Explorer 4)內含各式怪異的花招,我們稱為怪癖(Quirk),而為了相容這些舊瀏覽器的模式便稱為 Quirks 模式。本文稍後也會討論 Mozilla 的 Quirks 模式。

+

我也會闡述其他 Mozilla 支援、但還沒有 W3C 相關規格的非標準技術,如 XMLHttpRequest 及 Rich-text 編輯功能。此處指的 W3C 規格包括:

+ +

跨瀏覽器程式小技巧

+

雖然這世上有所謂的 Web 標準,但不同的瀏覽器作法依然大不相同(即使是同一個瀏覽器,也可能因為作業系統差別而相異)。許多瀏覽器(如 Internet Explorer)在 W3C 規格形成前便提供某些功能,卻在標準制訂後忘了修改既有支援程式以符合標準。

+

在我闡述 Mozilla 與 Internet Explorer 相異之處前,我會先講點小技巧,讓你的 Web 應用程式容易擴充、在未來略事修改便能相容新瀏覽器。

+

不同瀏覽器下的某相同功能,往往也有不同的 API,所以在某些程式中你會發現不少 if() else() 程式區段,以便區分不同的瀏覽器。以下程式是寫給 Internet Explorer 用的:

+
. . .
+
+var elm;
+
+if (ns4)
+  elm = document.layers["myID"];
+else if (ie4)
+  elm = document.all["myID"]
+
+

上面這段程式稱不上容易擴充,如果你要多相容一種瀏覽器就得改寫一次。

+

要排除遇到新的瀏覽器就要重寫網頁碼的情形,最容易的方法,就是把功能「抽」出來。與其使用一堆 if() else(),不如將常用的程式片段獨立為一個函式以提高效率。如此一來不但程式易讀,要支援更多瀏覽器也方便些:

+
var elm = getElmById("myID");
+
+function getElmById(aID){
+  var element = null;
+
+  if (isMozilla || isIE5)
+    element = document.getElementById(aID)
+  else if (isNetscape4)
+   element = document.layers[aID]
+  else if (isIE4)
+    element = document.all[aID];
+
+  return element;
+}
+
+

以上的程式仍得處理瀏覽器偵測的問題,通常這要靠 useragent 字串來解決,例如:

+
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031016
+
+

雖然 useragent 字串提供瀏覽器的詳細資訊,但處理這段字串的程式碰上新瀏覽器時還是有可能出錯,此時便需修改程式。

+

如果瀏覽器種類無關緊要(好比你已經把不支援的瀏覽器全都擋在門外了),那麼依據瀏覽器的能力來判別會比較好一點。通常可以用 JavaScript 來測試必備的功能,舉例來說,與其使用這樣的程式碼:

+
if (isMozilla || isIE5)
+
+

還不如換條路走:

+
if (document.getElementById)
+
+

這樣也可以讓其他支援此方法的瀏覽器(如 Opera 或 Safari)正常使用,無須更動程式。

+

而依據 useragent 字串辨識瀏覽器也並非一無是處,例如在檢查瀏覽器是否符合最低需求或除錯時都有其用途。

+

JavaScript也允許順序條件語言(inline conditional statements)以助於代碼的可讀性:

+

JavaScript 也支援判斷句簡寫法,協助你將程式寫得更易讀:

+
var foo = (condition) ? conditionIsTrue : conditionIsFalse;
+
+

舉例而言,要取用某元素,可以寫為:

+
+function getElement(aID){
+  return (document.getElementById) ? document.getElementById(aID)
+                                   : document.all[aID];
+}
+
+

Mozilla 與 Internet Explorer 的差別

+

首先,我要討論Mozilla和IE在表現HTML行為上的差別。

+

工具提示(tooltips)

+

老牌的瀏覽器透過在超連結和利用 alt 屬性值的 HTML 中導入工具提示來作為工具提示的內容。 最新的 W3C HTML specification 建立了 title 這個屬性,它包含超連結的詳細說明。 現代的瀏覽器會使用 title 的屬性來顯示工具提示,而且 mozilla 只支援 title 屬性,並不支援 alt 屬性。

+

HTML 特殊字元(entities)

+

HTML 標籤可以是一些在 W3 standards body 中已定義的字元。 您可以利用它們的數值或字符來代替字元。 舉例來說,您可以利用 &#160; 或等同的字符參考資料 &nbsp; 來代替空白鍵。

+

有一些很老很老的瀏覽器,像是 Internet Explorer ,它們允許在特殊字元後面拿走;(分號(:

+
&nbsp Foo
+&nbsp&nbsp Foo
+
+

Mozilla 依然會把 &nbsp 當作空白鍵,既使這樣違反了 W3C 標準(W3C specification)。 但如果 &nbsp 後面直接跟上一些其他的字元,瀏覽器就不會轉換它。 範例:

+
&nbsp12345
+
+

這行程式碼在 Mozilla 中就不會被執行,因為它違反了 W3 標準(W3 standard)。請使用正確的格式(&nbsp;)來避免瀏覽器與瀏覽器之間的差異性。

+

DOM 差異

+

文件物件模型(The Document Object Model,簡稱DOM)是一個裝載著文件元素的樹狀結構。你可以熟練地透過已成為 W3C 標準的 JavaScript API 來操作 DOM。然而在 W3C 標準建立以前, Netscape 4 和 IE 4 實作了一些類似的 API。 Mozilla 僅在使用 W3C 標準無法達成這些 API 的效果時才予以實作。

+

存取元素

+

如果你想以跨瀏覽器的方式來取得某個元素的參考,請使用document.getelementById(aID) 方法,這個方法不僅可以在 IE 5.0+ 和 Mozilla 上正常運作,它還是 DOM Level 1 的規範。

+

Mozilla 不能夠以 document.elementName 或是元素名稱來存取元素,而 IE 可以(名為全域名稱污染)。 Mozilla 也不支援 Netscape 4 的 document.layers 和 IE 的 document.all。 而 document.getElementById 可以讓你取得某個元素,你還可以使用 document.layersdocument.all 指定一個 tag 名稱來取得一串文件元素,像是全部的 <div> 元素。

+

在 W3C DOM Level 1 的規範中,JavaScript 應透過 getElementsByTagName() 取得相同標籤(tag)下的元素。這個方法會傳回一個陣列,同時這個方法也可以呼叫 document 或其他節點下的元素。如果你想取得,你可以透過 getElementsByTagName("*") 來取得整個 DOM 下的元素陣列。

+

就如下面表格一,DOM Level 1 經常被用來移動或者隱藏元素。當一個 HTML 元素可以隨意移動時,Netscape 4 所使用的 <layer> 標籤就不被 Mozilla 支援,你可以使用如同 Internet Explorer 的 <div>。根據 HTML 規範,這個標籤可以在 Mozilla 正常運行的。

+

 

+

表格一 - 用於存取元素的方法

+ + + + + + + + + + + + + + + +
方法描述
document.getElementById( aId )回傳文件中 ID 值為 aId 元素的。
document.getElementsByTagName( aTagName )回傳文件中標籤名稱為 aTagName 的元素
+

縱橫 DOM

+

Mozilla 支援透過 JavaScript 存取 DOM 樹狀圖的 W3C DOM APIs (詳見表格二)。透過他可以讀取文件中的任何一個節點。Internet Explorer 也支援這個 APIs,同時也支援一些過時的方法,像是 children

+

 

+

表格二 - 縱橫 DOM 的方法

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
屬性/方法描述
childNodes回傳一個該元素下所有子節點的陣列。
firstChild回傳該元素下的第一個子節點。
getAttribute( aAttributeName )回傳 aAttributeName 的值。
hasAttribute( aAttributeName )回傳一個關於節點 aAttributeName 是否有屬性的布林值。
hasChildNodes()回傳一個關於該節點下是否仍含有子節點的布林值。
lastChild回傳該元素下的最後一個子節點。
nextSibling回傳當下節點後的下一個節點。
nodeName回傳一個當下節點名稱的字串。
nodeType回傳該節點的類型。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
數值描述
1元素節點(Element Node)
2屬性節點(Attribute Node)
3文字節點(Text Node)
4CDATA 段落節點(CDATA Section Node)
5實體參引節點(Entity Reference Node)
6實體節點(Entity Node)
7處理指令(Processing Instruction Node)
8註解節點(Comment Node)
9文件節點(Document Node)
10文件型別(Document Type Node)
11文件片段(Document Fragment Node)
12記法節點(Notation Node)
+
+     *譯注:目前參照 中央研究院計算中心曾士熊先生提供 SGML 名詞部份的翻譯內容,其中並不包含「文件片段(Document Fragment Node)」
+
+
nodeValue回傳當下節點的值。當節點中存在文字或文段,如文字和註解節點時,此方法會回傳他們的字串值。當節點為屬性節點(attribute node)時,此方法將會回傳屬性值。除此之外,其餘的節點類型都會回傳 null。 
ownerDocument回傳存在於當下節點的 document 物件。
parentNode回傳當前節點的父節點。
previousSibling回傳在該節點之前的節點。
removeAttribute( aName )從當前的節點中移除 aName 屬性。
setAttribute( aName, aValue )將 aName 屬性的值更改為 aValue。
+

在 Internet Explorer 中有個不正常的怪癖(quirk),上表中有許多方法會略過自動產生的空白文字節點。請注意,在 Mozilla 中這些並不會略過,所以有時候你必須區別開這些節點。每一個節點都有它的 nodeType 屬性。舉例來說,元素節點的類型是 1;而文字節點是 3、註解節點是 8(詳見表格二 - nodeType)。最好區別開這些空白文字節點的辦法就是指處裡節點類型為 1 的子節點:

+
HTML部分:
+  <div id="foo">
+    <span>Test</span>
+  </div>
+
+JavaScript部分:
+  var myDiv = document.getElementById("foo");
+  var myChildren = myXMLDoc.childNodes;
+  for (var i = 0; i < myChildren.length; i++) {
+    if (myChildren[i].nodeType == 1){
+      // 元素節點
+    }
+  }
+
+

內容建立及處理

+

Mozilla 支援一些比較舊的動態增加 DOM 內容的方法,像是

+
document.writedocument.open 和 document.close。
+
+

Mozilla 也支援 Internet Explorer 的 innerHTML 方法,這個方法可以用來處理所有的節點。即使這個方法無效,Mozilla 還支援 outerHTML (這個方法包含該元素,它與 innerHTML 有一定的差異) 和 innerText (用於存取或修改節點的文字,功能與 Mozilla 裡的 textContent 差不多)。

+

Internet Explorer 中存在著許多不規範也不被 Mozilla 的內容處理方法,包括回傳參數、插入數值和插入元素到節點中。像是 getAdjacentElementinsertAdjacentHTML 等。表格三中敘述了 W3C 定義的內容處理方法,它們適用於所有的 DOM 節點。

+

 

+

表格三 - Mozilla 使用的內容處理方法

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
方法描述
appendChild( aNode )建立一個新的子節點,並回傳新子節點的參照值。
cloneNode( aDeep )複製該節點並且傳回複製後的節點。如果 aDeep 的值「成立」,那個這個方法會把該節點下所有的子節點複製到新的節點。
createElement( aTagName )建立並回傳一個沒有母節點(即上層沒有節點)的節點。該節點的名稱為 aTagName 。
createTextNode( aTextValue )建立並回傳一個沒有母節點的文字節點,該節點值為 aTextValue。
insertBefore( aNewNode, aChildNode )把 aNewNode 插入到 aChildNode 之前。(兩者都必須在當前的節點下)
removeChild( aChildNode )移除 aChildNode 並回傳一個參照值。
replaceChild( aNewNode, aChildNode )用 aChildNode 替代 aNewNode,並且回傳一個移除節點的參照值。
+

文件片段

+

因為效能的緣故,你可以在記憶體中創建 document 而非在現存的 DOM 上做動作。 DOM Level 1 Core 引入了 document fragments,這是一個輕量化的 document 且支援了部份既有可用的 document interface。舉例來說,他雖不支援 getElementById 但卻支援 appendChild 。你可以很容易的按照現存的的 document 來創建  document fragments 。

+

在 Mozilla 中,要創造新的 document fragments 只需要使用 document.createDocumentFragment(),之後你便可取得一個空的 document fragment。

+

Internet Explorer 在實做 document fragment 上並未按照標準的 W3C standard 。倘若你在 IE 中調用此功能,只能拿回一個 regular document 而非 document fragment。

+

JavaScript 差異

+

Mozilla 與 Internet Explorer 之間最大的差別就是 JavaScript。 這些問題通常存在於瀏覽器所公佈的 JavaScript APIs,像是 DOM hooks。 這兩種瀏覽器各自佔有一部份 JavaScript 核心的差異性;這些遇到的問題通常也和時間有關。

+

JavaScript 日期差異

+

getYear 這個函數是唯一 Date 中的不同點。根據 ECMAScript specification(JavaScript 也遵循這個 specification),這個函式不是 Y2k-compliant 。假設在 2004 年時執行 new Date().getYear(),它會回傳 "104" 。根據 ECMAScript specification , getYear 會回傳年份減去 1900,原意是回傳 "98" 來表示 1998。getYear 在 ECMAScript Version 3 時被 getFullYear() 所代替。 當 mozilla 繼續遵循規範時,Internet Explorer 已經把 getYear() 修改成像 getFullYear() 的工作方式,使它成為Y2k-compliant。

+

JavaScript 執行差異

+

不同的瀏覽器使用不同的方法執行 JavaScript。舉例來說,下面的程式碼假設當 script 執行的時候 div 節點已經存在於 DOM:

+
...
+<div id="foo">Loading...</div>
+
+<script>
+  document.getElementById("foo").innerHTML = "Done.";
+</script>
+
+

無論如何,這都不能夠確定元素(elements)是否存在。要確認所有的元素都存在,您應該將 onload 事件擺在 <body> 標籤:

+
<body onload="doFinish()">
+
+<div id="foo">Loading...</div>
+
+<script>
+  function doFinish() {
+    var element = document.getElementById("foo");
+	  element.innerHTML = "Done.";
+  }
+</script>
+...
+
+

像這樣與時間相關的問題也和硬體有關-較慢的系統可以顯示出較快的系統中隱藏的臭蟲(bugs)。 window.open 是一個具體的例子:  

+
<script>
+  function doOpenWindow(){
+    var myWindow = window.open("about:blank");
+    myWindow.location.href = "http://www.ibm.com";
+  }
+</script>
+
+

這段程式碼的問題是: window.open 的時程是非同步的-它不會阻擋 JavaScript 的執行,直到所有的新視窗載入完畢。 因此,您應該在在載入新視窗完畢後才執行 window.open 。 您可以透過 在新視窗中利用 onload 執行 window.opener 來回到原本開啟新視窗的視窗(母體)。

+

JavaScript 產生之 HTML 差異

+

  在 JavaScript 中,我們可以透過 document.write 來從字串產生 HTML 程式碼。但這有個值得注意的地方在於,要是你的內嵌碼中中含有 <script> tag 會發生什麼事?當你的目標頁面處於 <a href="#html_modes">strict rendering mode</a> 下時,它將會解析位於  <script> 和  </script>  中的內容。讓我們看個例子:

+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+...
+<script>
+  document.write("<script>alert("Hello")</script>")
+</script>
+
+

  因為目前處於 strict mode 下,Mozilla 的解析器 (parser) 將會查看介於 <script> 和 </script>中的內容。這是因為在 strict mode 下解析器並不認得任何語言。但假如處在 quirks mode 下,解析器卻識得 JavaScript 語法。而事實上,Internet Explorer 總是處於 quirks mode 下 - 它並不真正之支援 XHTML。一個比較兩全其美的作法是將該內容分割成兩個部份:

+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+...
+<script>
+  document.write("<script>alert("Hello")</" + "script>")
+</script>
+
+

JavaScript 除錯

+

Mozilla provides several ways to debug JavaScript-related issues found in applications created for Internet Explorer. The first tool is the built-in JavaScript console, shown in Figure 1, where errors and warnings are logged. You can access it in Mozilla by going to Tools -> Web Development -> JavaScript Console, or in Firefox (the standalone browser product from Mozilla) at Tools -> JavaScript Console.

+

 

+

Figure 1. JavaScript console

+
+ Javascript Console
+

The JavaScript console can show the full log list or just errors, warnings, and messages. The error message in Figure 1 says that at aol.com, line 95 tries to access an undefined variable called is_ns70. Clicking on the link will open Mozilla's internal view source window with the offending line highlighted.

+

The console also allows you to evaluate JavaScript. To evaluate the entered JavaScript syntax, type in 1+1 into the input field and press Evaluate, as Figure 2 shows.

+

 

+

Figure 2. JavaScript console evaluating

+
+ JavaScript Console evaluating
+

Mozilla's JavaScript engine has built-in support for debugging, and thus can provide powerful tools for JavaScript developers. Venkman, shown in Figure 3, is a powerful, cross-platform JavaScript debugger that integrates with Mozilla. It is usually bundled with Mozilla releases; you can find it at Tools -> Web Development -> JavaScript Debugger. For Firefox, the debugger isn't bundled; instead, you can download and install it from the Venkman Project Page. You can also find tutorials at the development page, located at the Venkman Development Page.

+

 

+

Figure 3. Mozilla's JavaScript debugger

+
+ Mozilla's JavaScript debugger
+

The JavaScript debugger can debug JavaScript running in the Mozilla browser window. It supports such standard debugging features as breakpoint management, call stack inspection, and variable/object inspection. All features are accessible through the user interface or through the debugger's interactive console. With the console, you al can execute arbitrary JavaScript in the same scope as the JavaScript currently being debugged.

+

CSS 差異

+

與 Internet Explorer 和其他的瀏覽器比較之下, Mozilla 擁有最強大的 Cascading Style Sheets 4(即 CSS) 支援, 包含大部份的 CSS1、CSS2 和部份的 CSS3 。

+

對於下列敘述的問題, Mozilla 會在 JavaScript 控制台中發出警告。 如果您遇到了 CSS 的相關問題,請確認 JavaScript 控制台。

+

CSS 檔無法套用:MIME Type 問題

+

CSS 定義的相關檔沒有被讀取是 CSS 的相關問題中最常見的。 這通常是伺服器將 CSS 檔案送出了錯誤的 MIME Type 。 CSS 說明書 ( CSS specification ) 中提到:「 CSS 檔案應該被作為 text/css mimetype 。」 當網頁處於嚴格的規範模式 ( strict standards mode )時, Mozilla 將遵循並只載入以 text/css 作為 mimetype 的 CSS 檔案。 在 Internet Explorer 中,無論 mimetype 是甚麼, CSS 檔案都會被載入。 當網頁的 doctype ( document type,檔案類型 ) 在網頁的開頭被指定時,他們會進入嚴格的標準模式。 要解決這個問題,您可以修改正確的 mimetype 或移除 doctype。 我們會在下個章節中討論更多關於 doctype。

+

CSS 單位

+

有很多網路應用程式都不在他們的 CSS 中加上單位,尤其是利用 JavaScript 設定 CSS 的時候。 當網頁不執行在標準模式時,Mozilla 不會回報錯誤。 因為 Internet Explorer 並非真正的支援 XHTML ,它不在乎有沒有具體的單位描述。 如果網頁處於嚴格的標準描述下,並且沒有使用單位,那麼 Mozilla 將忽略以下的 style :

+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+  <body>
+    // works in strict mode
+    <div style="width:40px; border:1px solid black;">
+      Text
+    </div>
+
+    // will fail in strict mode
+    <div style="width:40; border:1px solid black;">
+      Text
+    </div>
+  </body>
+</html>
+
+

因為上述的範例中有一個規範的 doctype (檔案類型),所以網頁將執行在嚴格的標準模式下。 第一個 div 標籤會套用 40 像素的寬度,因為它有單位,但是第二個 div 標籤將不會套用指定的寬度,因此會套用預設的 100% 寬度。 透過 JavaScript 設定寬度將會得到一樣的結果。

+

JavaScript 及 CSS

+

既然 Mozilla 支援 CSS 標準,它同時也支援透過 JavaScript 設定 CSS 的 CSS DOM。 您可以透過 style 標籤讀取、移除和修改 CSS 的屬性規則:

+
<div id="myDiv" border:1px solid black;">
+  Text
+</div>
+
+<script>
+  var myElm = document.getElementById("myDiv");
+  myElm.style.width = "40px";
+</script>
+
+

您可以利用這種方式來延伸 css 的屬性。再次強調,如果網頁處於標準模式,您必須加上單位,否則 Mozilla 將忽略指令。 當您要查詢變數時,透過 .style.width 來達成,在 Mozilla 和 Internet Explorer 中,傳回的值中會包含單位,也就是傳回了一串字串。 您可以利用 parseFloat("40px") 將字串轉換成數值。

+

CSS 溢出部分(overflow)差異

+

CSS 增加了溢出(overflow)的概念,它允許您定義如何處理溢出部份;舉例來說,當 div 內容指定的高度高於 div 的高度時, CSS 規範(CSS standard)中定義了如果程式中沒有定義溢出的相關設定, div 的內容將會溢出。 但是 Internet Explorer 仍然不會遵循相關規範,並且會為了留住內容而擴張 div 的高度。 下面的例子表現了這個差異性:

+
<div style="height:100px; border: 1px solid black;">
+  <div style="height:150px; border: 1px solid red; margin:10px;">
+    a
+  </div>
+</div>
+
+

就像你在圖片四看到的,Mozilla 依照了 CSS 規範做出了判斷。 規範中提到了在這個情況下,因為 div 的內部高過它的母體,所以它溢出到了按鈕的地方。 如果您這麼愛 Internet Explorer 的行為,就不要在母體(即 div )加上 height 這個屬性。

+

 

+

圖片四:div溢出部份

+
+ DIVdiv溢出部份
+

hover(滑鼠移上某元素)效果差異

+

在一些網站上存在著 Internet Explorer 的非標準 CSS hover。 在 Mozilla 中,通常當滑鼠滑入的時候,利用改變 Text Style 來顯示它自己。 這是因為 a:hover ,在 Internet Explorer 中的 CSS 解析器對應 HTML 中錨點(anchor)的是 <a href="" />,而不是 <a name="" /> 由於作者將錨點設定標記(anchor-setting markup)套用進了區塊,所以造成了文字的顏色變化:

+
CSS:
+  a:hover {color:green;}
+
+HTML:
+  <a href="foo.com">This text should turn green when you hover over it.</a>
+
+  <a name="anchor-name">
+    This text should change color when hovered over, but doesn't in Internet Explorer.
+  </a>
+
+

Mozilla 遵循 CSS 說明書 ( CSS specification )並且在這個例子中會把顏色變成綠色。 您可以使用這兩種方法來讓 Mozilla 擁有像 Internet Explorer 的效果,並且當滑鼠滑入時不會改變文字的顏色:

+ +

Quirks 模式、標準模式

+

  在舊的瀏覽器上 (如 Internet Explorer 4),網頁可能會被以一種被不完全正確的方式渲染網頁。當 Mozilla 企圖成為一個和標準相容的瀏覽器的情況下,它採取三種不同方式來處理在這些不太合標準的渲染方式下開發的既有網頁。你可以在  Mozilla 瀏覽器中的  View -> Page Info (或 Ctrl-i) 下查看目前處於哪種模式。而該採取怎樣的模式則取決於該頁面的 doctype。

+

  Doctypes (document type declarations) 看起來是:

+

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

+

  藍色部份稱為 public identifier,而綠色部份是為 system identifier (以 URI 方式描述)。

+

Standards Mode (標準模式)

+

  Standards mode 是最嚴謹的渲染模式。它將完全按照 W3C HTML 以及 CSS specification 來處理,並且不支援任何除此之外的寫法。 Mozilla 會在以下情形中使用此模式:

+ +

Almost Standards mode (近乎標準模式)

+

Mozilla introduced almost standards mode for one reason: a section in the CSS 2 specification breaks designs based on a precise layout of small images in table cells. Instead of forming one image to the user, each small image ends up with a gap next to it. The old IBM homepage shown in Figure 5 offers an example.

+

 

+

Figure 5. Image gap

+
+ Image Gap
+

Almost standards mode behaves almost exactly as standards mode, except when it comes to an image gap issue. The issue occurs often on standards-compliant pages and causes them to display incorrectly.

+

Mozilla uses almost standards mode for the following conditions:

+ +

You can read more about the image gap issue.

+

Quirks Mode (怪癖模式)

+

  以目前情況來說,網路上充斥著許多不完全符合標準規範的網頁。這些不合標準的網頁,卻和有著 bug 的瀏覽器配合的很好。舉例來說,在以前Netscape 居市場領導地位時,便有著 bug。而 IE 誕生石,為了能和那些網頁相容,「繼承」了這些 bug 們。對於在之後才來到市場上的新一代瀏覽器們來說,這些 bug 們便被稱為 quirks (但他們大都能向下相容於這些網頁)。值得注意的是,因為這些既有網頁並非按照規格設計,所以新瀏覽器在渲染時得花上更多時間。不幸的是,絕大多數的網頁都有賴新瀏覽器們以此模式渲染。

+

Mozilla 會在以下情況使用此模式:

+ +

For further reading, check out: List of Quirks and List of Doctypes and What Modes They Cause.

+

 

+

事件差異

+

  Mozilla 和 Internet Explorer 在 events 的這個部分幾乎是完全不同的。 Mozilla event model 遵循 W3C 以及 Netscape model。但在 Internet Explorer 中,倘若一個 function 被 event 所觸發,那麼我們可以用 window.event 來接觸到該 event 物件 - 這必須被特別指定為參數傳入。Mozilla 則會直接傳遞該 event 物件到 event handlers 中。一個跨瀏覽器 (cross-browser) 的 event handling 範例如下:

+
<div onclick="handleEvent(event)">Click me!</div>
+
+<script>
+  function handleEvent(aEvent) {
+    // if aEvent is null, means the Internet Explorer event model,
+    // so get window.event.
+    var myEvent = aEvent ? aEvent : window.event;
+  }
+</script>
+
+

  此外,event 物件產生時所擁有的 properties 和 functions 在 Mozilla and Internet Explorer 也可能有不同的名字。請參見 Table 4。

+

 

+

Table 4. Mozilla/Internet Explorer event property 比較表

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Internet Explorer NameMozilla NameDescription
altKeyaltKeyBoolean property that returns whether the alt key was pressed during the event.
cancelBubblestopPropagation()Used to stop the event from bubbling farther up the tree.
clientXclientXThe X coordinate of the event, in relation to the client.
clientYclientYThe Y coordinate of the event, in relation to the client.
ctrlKeyctrlKeyBoolean property that returns whether the Ctrl key was pressed during the event.
fromElementrelatedTargetFor mouse events, this is the element from which the mouse moved away.
keyCodekeyCodeFor keyboard events, this is a number representing the key that was pressed. It is 0 for mouse events.
returnValuepreventDefault()Used to prevent the event's default action from occurring.
screenXscreenXThe X coordinate of the event, in relation to the screen.
screenXscreenYThe Y coordinate of the event, in relation to the screen.
shiftKeyshiftKeyBoolean property that returns whether the Shift key was pressed during the event.
srcElementtargetThe element to which the event was originally dispatched.
toElementcurrentTargetFor mouse events, this is the element to which the mouse moved.
typetypeReturns the name of the event.
+

加上事件控制式

+

  Mozilla 支援了兩種方式來附加 events 到 JavaScript 中。第一種是所有瀏覽器都支援的,直接將 event properties 連接到物件上。下例為設定一個 click event handler,一個 function reference 被設定到物件的 onclick property:

+
<div id="myDiv">Click me!</div>
+
+<script>
+  function handleEvent(aEvent) {
+    // if aEvent is null, means the Internet Explorer event model,
+    // so get window.event.
+    var myEvent = aEvent ? aEvent : window.event;
+  }
+
+  function onPageLoad(){
+    document.getElementById("myDiv").onclick = handleEvent;
+  }
+</script>
+
+

Mozilla fully supports the W3C standard way of attaching listeners to DOM nodes. You use the addEventListener() and removeEventListener() methods, and have the benefit of being able to set multiple listeners for the same event type. Both methods require three parameters: the event type, a function reference, and a boolean denoting whether the listener should catch events in their capture phase. If the boolean is set to false, it will only catch bubbling events. W3C events have three phases: capturing, at target, and bubbling. Every event object has an eventPhase attribute indicating the phase numerically (0 indexed). Every time you trigger an event, the event starts at the DOM's outermost element, the element at the top of the DOM tree. It then walks the DOM using the most direct route toward the target, which is the capturing phase. When the event reaches the target, the event is in the target phase.  After arriving at the target, it walks up the DOM tree back to the outermost node; this is bubbling. Internet Explorer's event model only has the bubbling phase; therefore, setting the third parameter to false results in Internet Explorer-like behavior:

+
<div id="myDiv">Click me!</div>
+
+<script>
+
+  function handleEvent(aEvent) {
+    // if aEvent is null, it is the Internet Explorer event model,
+    // so get window.event.
+    var myEvent = aEvent ? aEvent : window.event;
+  }
+
+  function onPageLoad() {
+    var element = document.getElementById("myDiv");
+    element.addEventListener("click", handleEvent, false);
+  }
+</script>
+
+

One advantage of addEventListener() and removeEventListener() over setting properties is that you can have multiple event listeners for the same event, each calling another function. Thus, to remove an event listener requires all three parameters be the same as the ones you use when adding the listener.

+

Mozilla does not support Internet Explorer's method of converting <script> tags into event handlers, which extends <script> with for and event attributes (see Table 5). It also does not support the attachEvent and detachEvent methods. Instead, you should use the addEventListener and removeEventListener methods. Internet Explorer does not support the W3C events specification.

+

 

+

Table 5. Event method differences between Mozilla and Internet Explorer

+ + + + + + + + + + + + + + + + + + +
Internet Explorer MethodMozilla MethodDescription
attachEvent(aEventType, aFunctionReference)addEventListener(aEventType, aFunctionReference, aUseCapture)Adds an event listener to a DOM element.
detachEvent(aEventType, aFunctionReference)removeEventListener(aEventType, aFunctionReference, aUseCapture)Removes an event listener to a DOM element.
+

Rich-text 編輯

+

While Mozilla prides itself with being the most W3C standards-compliant browser, it does support nonstandard functionality, such as innerHTML and rich text editing, if no W3C equivalent exists.

+

Mozilla 1.3 introduced an implementation of Internet Explorer's designMode feature, which turns an HTML document into a rich text editor field. Once turned into the editor, commands can run on the document through the execCommand command. Mozilla does not support Internet Explorer's contentEditable attribute for making any widget editable. You can use an iframe to add a rich text editor.

+

Rich-text 差異

+

Mozilla supports the W3C standard of accessing iframe's document object through IFrameElm.contentDocument, while Internet Explorer requires you to access it through document.frames{{ mediawiki.external('\"name\"') }} and then access the resulting document:

+
function getIFrameDocument(aID) {
+  var rv = null;
+
+  // if contentDocument exists, W3C compliant (Mozilla)
+  if (document.getElementById(aID).contentDocument){
+    rv = document.getElementById(aID).contentDocument;
+  } else {
+    // IE
+    rv = document.frames[aID].document;
+  }
+  return rv;
+}
+
+

Another difference between Mozilla and Internet Explorer is the HTML that the rich text editor creates. Mozilla defaults to using CSS for the generated markup. However, Mozilla allows you to toggle between HTML and CSS mode using the useCSS execCommand and toggling it between true and false. Internet Explorer always uses HTML markup.

+
Mozilla (CSS):
+  <span style="color: blue;">Big Blue</span>
+
+Mozilla (HTML):
+  <font color="blue">Big Blue</font>
+
+Internet Explorer:
+  <FONT color="blue">Big Blue</FONT>
+
+

Below is a list of commands that execCommand in Mozilla supports:

+

 

+

Table 6. Rich text editing commands

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Command NameDescriptionArgument
boldToggles the selection's bold attribute.---
createlinkGenerates an HTML link from the selected text.The URL to use for the link
deleteDeletes the selection.---
fontnameChanges the font used in the selected text.The font name to use (Arial, for example)
fontsizeChanges the font size used in the selected text.The font size to use
fontcolorChanges the font color used in the selected text.The color to use
indentIndents the block where the caret is.---
inserthorizontalruleInserts an <hr> element at the cursor's position.---
insertimageInserts an image at the cursor's position.URL of the image to use
insertorderedlistInserts an ordered list (<ol>) element at the cursor's position.---
insertunorderedlistInserts an unordered list (<ul>) element at the cursor's position.---
italicToggles the selection's italicize attribute.---
justifycenterCenters the content at the current line.---
justifyleftJustifies the content at the current line to the left.---
justifyrightJustifies the content at the current line to the right.---
outdentOutdents the block where the caret is.---
redoRedoes the previous undo command.---
removeformatRemoves all formatting from the selection.---
selectallSelects everything in the rich text editor.---
strikethroughToggles the strikethrough of the selected text.---
subscriptConverts the current selection into subscript.---
superscriptConverts the current selection into superscript.---
underlineToggles the underline of the selected text.---
undoUndoes the last executed command.---
unlinkRemoves all link information from the selection.---
useCSSToggles the usage of CSS in the generated markup.Boolean value
+

For more information, visit Rich-Text Editing in Mozilla.

+

 

+

XML 差異

+

Mozilla 對 XML 與相關的技術有很完整的支援,如對 XSLT 與 Web services 等。它也支援一些 Internet Explorer 非標準的延伸,例如 XMLHttpRequest。

+

Mozilla has strong support for XML and XML-related technologies, such as XSLT and Web services. It also supports some nonstandard Internet Explorer extensions, such as XMLHttpRequest.

+

掌控 XML

+

如同對於標準 HTML,對於可各方面控制 XML 檔的 DOM 的支援,Mozilla 也是依 W3C 所定的 XML DOM 規格。Mozilla 與 Internet Explorer 在 XML DOM 上的不同處大多在於 Internet Explorer 非標準的處理方式。一個常見的差異是對空白字元節點的處理。 通常在建立 XML 時,XML 節點間會有空白。 Internet Explorer 用 XMLNode.childNodes[] 時不會包括這些空白節點,但在 Mozilla 上這些節點會在 array 裡。

+

  在 HTML 標準上,Mozilla 支援了 W3C XML DOM 規範,但  Internet Explorer 則否。Mozilla 和 Internet Explorer 的一些差異很大部分是肇始於後者的非規範行為。在這其中,最廣為人知的應該就是如何去處理 white space text nodes 了。通常在 XML 文檔產生後,會在 XML node 間包含著一些 white space。當你使用 XMLNode.childNodes[] 時,Internet Explorer 將不會包含這些 white space nodes。但在 Mozilla 中,這些 nodes 仍會出現在 array 中。

+
XML:
+  <?xml version="1.0"?>
+  <myXMLdoc xmlns:myns="http://myfoo.com">
+    <myns:foo>bar</myns:foo>
+  </myXMLdoc>
+
+JavaScript:
+  var myXMLDoc = getXMLDocument().documentElement;
+  alert(myXMLDoc.childNodes.length);
+
+

The first line of JavaScript 的第一行載入 XML 檔並用 documentElement 來存取它的 root 元素 (myXMLDoc)。第二行顯示子節點的數目。根據 W3C 規格,接在一起的空白與換行字符組成一個文字節點。在 Mozilla 上 myXMLdoc 節點有三個子:一個有換行字符與兩個空白的文字節點、myns:foo 節點、與另一個有換行字符的文字節點。Internet Explorer 並不遵循這個,因此上面的程式碼會顯示 "1",表示只有 myns:foo 節點。所以,如要迴走子節點並掠過文字節點,要分辨這些節點。

+

The first line of JavaScript loads the XML document and accesses the root element (myXMLDoc) by retrieving the documentElement. The second line simply alerts the number of child nodes. Per the W3C specification, the white spaces and new lines merge into one text node if they follow each other. For Mozilla, the myXMLdoc node has three children: a text node containing a new line and two spaces; the myns:foo node; and another text node with a new line. Internet Explorer, however, does not abide by this and will return "1" for the above code, namely only the myns:foo node. Therefore, to walk the child nodes and disregard text nodes, you must distinguish such nodes.

+

As mentioned earlier, every node has a nodeType attribute representing the node type. For example, an element node has type 1, while a document node has type 9. To disregard text nodes, you must check for types 3 (text node) and 8 (comment node).

+
XML:
+  <?xml version="1.0"?>
+  <myXMLdoc xmlns:myns="http://myfoo.com">
+    <myns:foo>bar</myns:foo>
+  </myXMLdoc>
+
+JavaScript:
+  var myXMLDoc = getXMLDocument().documentElement;
+  var myChildren = myXMLDoc.childNodes;
+
+  for (var run = 0; run < myChildren.length; run++){
+    if ( (myChildren[run].nodeType != 3) &&
+          myChildren[run].nodeType != 8) ){
+      // not a text or comment node
+    }
+  }
+
+

XML data islands

+

Internet Explorer has a nonstandard feature called XML data islands, which allow you to embed XML inside an HTML document using the nonstandard HTML tag <xml>. Mozilla does not support XML data islands and handles them as unknown HTML tags. You can achieve the same functionality using XHTML; however, because Internet Explorer's support for XHTML is weak, this is usually not an option.

+

One cross-browser solution is to use DOM parsers, which parse a string that contains a serialized XML document and generates the document for the parsed XML. Mozilla uses the DOMParser class, which takes the serialized string and creates an XML document out of it. In Internet Explorer, you can achieve the same functionality using ActiveX. A new Microsoft.XMLDOM generates and has a loadXML method that can take in a string and generate a document from it. The following code shows you how:

+
IE XML data island:
+  ..
+  <xml id="xmldataisland">
+    <foo>bar</foo>
+  </xml>
+
+Cross-browser solution:
+  var xmlString = "<xml id=\"xmldataisland\"><foo>bar</foo></xml>";
+
+  var myDocument;
+
+  if (document.implementation.createDocument){
+    // Mozilla, create a new DOMParser
+    var parser = new DOMParser();
+    myDocument = parser.parseFromString(xmlString, "text/xml");
+  } else if (window.ActiveXObject){
+    // Internet Explorer, create a new XML document using ActiveX
+    // and use loadXML as a DOM parser.
+    myDocument = new ActiveXObject("Microsoft.XMLDOM")
+    myDocument.async="false";
+
+    myDocument.loadXML(xmlString);
+  }
+
+

XML HTTP request

+

Internet Explorer allows you to send and retrieve XML files using MSXML's XMLHTTP class, which is instantiated through ActiveX using new ActiveXObject("Msxml2.XMLHTTP") or new ActiveXObject("Microsoft.XMLHTTP"). Since there is no standard method of doing this, Mozilla provides the same functionality in the global JavaScript XMLHttpRequest object. The object generates asynchronous requests by default.

+

After instantiating the object using new XMLHttpRequest(), you can use the open method to specify what type of request (GET or POST) you use, which file you load, and if it is asynchronous or not. If the call is asynchronous, then give the onload member a function reference, which is called once the request has completed.

+

Synchronous request:

+
  var myXMLHTTPRequest = new XMLHttpRequest();
+  myXMLHTTPRequest.open("GET", "data.xml", false);
+
+  myXMLHTTPRequest.send(null);
+
+  var myXMLDocument = myXMLHTTPRequest.responseXML;
+
+

Asynchronous request:

+
  var myXMLHTTPRequest;
+
+  function xmlLoaded() {
+    var myXMLDocument = myXMLHTTPRequest.responseXML;
+  }
+
+  function loadXML(){
+    myXMLHTTPRequest = new XMLHttpRequest();
+
+    myXMLHTTPRequest.open("GET", "data.xml", true);
+
+    myXMLHTTPRequest.onload = xmlLoaded;
+
+    myXMLHTTPRequest.send(null);
+  }
+
+

Table 7 features a list of available methods and properties for Mozilla's XMLHttpRequest.

+

 

+

Table 7. XMLHttpRequest methods and properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
void abort()Stops the request if it is still running.
string getAllResponseHeaders()Returns all response headers as one string.
string getResponseHeader(string headerName)Returns the value of the specified header.
functionRef onerrorIf set, the references function will be called whenever an error occurs during the request.
functionRef onloadIf set, the references function will be called when the request completes successfully and the response has been received. Use when an asynchronous request is used.
void open (string HTTP_Method, string URL)
+
+ void open (string HTTP_Method, string URL, boolean async, string userName, string password)
Initializes the request for the specified URL, using either GET or POST as the HTTP method. To send the request, call the send() method after initialization. If async is false, the request is synchronous, else it defaults to asynchronous. Optionally, you can specify a username and password for the given URL needed.
int readyStateState of the request. Possible values: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ValueDescription
0UNINITIALIZED - open() has not been called yet.
1LOADING - send() has not been called yet.
2LOADED - send() has been called, headers and status are available.
3INTERACTIVE - Downloading, responseText holds the partial data.
4COMPLETED - Finished with all operations.
+
string responseTextString containing the response.
DOMDocument responseXMLDOM Document containing the response.
void send(variant body)Initiates the request. If body is defined, it issent as the body of the POST request. body can be an XML document or a string serialized XML document.
void setRequestHeader (string headerName, string headerValue)Sets an HTTP request header for use in the HTTP request. Has to be called after open() is called.
string statusThe status code of the HTTP response.
+

XSLT 差異

+

Mozilla supports XSL Transformations (XSLT) 1.0. It also allows JavaScript to perform XSLT transformations and allows running XPATH on a document.

+

Mozilla requires that you send the XML and XSLT file holding the stylesheet with an XML mimetype (text/xml or application/xml). This is the most common reason why XSLT won't run in Mozilla but will in Internet Explorer. Mozilla is strict in that way.

+

Internet Explorer 5.0 and 5.5 supported XSLT's working draft, which is substantially different than the final 1.0 recommendation. The easiest way to distinguish what version an XSLT file was written against is to look at the namespace. The namespace for the 1.0 recommendation is http://www.w3.org/1999/XSL/Transform, while the working draft's namespace is http://www.w3.org/TR/WD-xsl. Internet Explorer 6 supports the working draft for backwards compatibility, but Mozilla does not support the working draft, only the final recommendation.

+

If XSLT requires you to distinguish the browser, you can query the "xsl:vendor" system property. Mozilla's XSLT engine will report itself as "Transformiix" and Internet Explorer will return "Microsoft."

+
<xsl:if test="system-property('xsl:vendor') = 'Transformiix'">
+  <!-- Mozilla specific markup -->
+</xsl:if>
+<xsl:if test="system-property('xsl:vendor') = 'Microsoft'">
+  <!-- Internet Explorer specific markup -->
+</xsl:if>
+
+

Mozilla also provides JavaScript interfaces for XSLT, allowing a Web site to complete XSLT transformations in memory. You can do this using the global XSLTProcessor JavaScript object. XSLTProcessor requires you to load the XML and XSLT files, because it needs their DOM documents. The XSLT document, imported by the XSLTProcessor, allows you to manipulate XSLT parameters. XSLTProcessor can generate a standalone document using transformToDocument(), or it can create a document fragment using transformToFragment(), which you can easily append into another DOM document. Below is an example:

+

 

+
var xslStylesheet;
+var xsltProcessor = new XSLTProcessor();
+
+// load the xslt file, example1.xsl
+var myXMLHTTPRequest = new XMLHttpRequest();
+myXMLHTTPRequest.open("GET", "example1.xsl", false);
+myXMLHTTPRequest.send(null);
+
+// get the XML document and import it
+xslStylesheet = myXMLHTTPRequest.responseXML;
+
+xsltProcessor.importStylesheet(xslStylesheet);
+
+// load the xml file, example1.xml
+myXMLHTTPRequest = new XMLHttpRequest();
+myXMLHTTPRequest.open("GET", "example1.xml", false);
+myXMLHTTPRequest.send(null);
+
+var xmlSource = myXMLHTTPRequest.responseXML;
+
+var resultDocument = xsltProcessor.transformToDocument(xmlSource);
+
+

After creating an XSLTProcessor, you load the XSLT file using XMLHttpRequest. The XMLHttpRequest's responseXML member contains the XML document of the XSLT file, which is passed to importStylesheet. You then use the XMLHttpRequest again to load the source XML document that must be transformed; that document is then passed to the transformToDocument method of XSLTProcessor. Table 8 features a list of XSLTProcessor methods.

+

 

+

Table 8. XSLTProcessor methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
void importStylesheet(Node styleSheet)Imports the XSLT stylesheet. The styleSheet argument is the root node of an XSLT stylesheet's DOM document.
DocumentFragment transformToFragment(Node source, Document owner)Transforms the Node source by applying the stylesheet imported using the importStylesheet method and generates a DocumentFragment. owner specifies what DOM document the DocumentFragment should belong to, making it appendable to that DOM document.
Document transformToDocument(Node source)Transforms the Node source by applying the stylesheet imported using the importStylesheet method and returns a standalone DOM document.
void setParameter(String namespaceURI, String localName, Variant value)Sets a parameter in the imported XSLT stylesheet.
Variant getParameter(String namespaceURI, String localName)Gets the value of a parameter in the imported XSLT stylesheet.
void removeParameter(String namespaceURI, String localName)Removes all set parameters from the imported XSLT stylesheet and makes them default to the XSLT-defined defaults.
void clearParameters()Removes all set parameters and sets them to defaults specified in the XSLT stylesheet.
void reset()Removes all parameters and stylesheets.
+
+

原文資訊

+ +
diff --git a/files/zh-tw/archive/mozilla/persona/branding/index.html b/files/zh-tw/archive/mozilla/persona/branding/index.html new file mode 100644 index 0000000000..2793b91f88 --- /dev/null +++ b/files/zh-tw/archive/mozilla/persona/branding/index.html @@ -0,0 +1,42 @@ +--- +title: 品牌資源 +slug: Archive/Mozilla/Persona/branding +translation_of: Archive/Mozilla/Persona/User_interface_guidelines +--- +

「使用 Persona 登入」按鈕

+

圖片

+

登入按鈕有三種版本、三種配色:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 Sign in with your EmailSign in with PersonaSign in
+

CSS-Based

+

Sawyer Hollenshead 製作了一套精美的 CSS-based 按鈕。下載 (.zip)

+

更多資訊

+

您可在 Sean Martell's style primer 找到更多有關 Persona 視覺設計的資訊。

diff --git a/files/zh-tw/archive/mozilla/persona/index.html b/files/zh-tw/archive/mozilla/persona/index.html new file mode 100644 index 0000000000..5345e5f569 --- /dev/null +++ b/files/zh-tw/archive/mozilla/persona/index.html @@ -0,0 +1,125 @@ +--- +title: Persona +slug: Archive/Mozilla/Persona +translation_of: Archive/Mozilla/Persona +--- +
+

       保持聯繫或取得協助!

+ +

追蹤 我們的 blog,加入 我們的郵件列表,或在 IRC 裡頭 #identity 頻道找到我們。

+
+ +

Mozilla Persona 是一個跨瀏覽器的 Web 登入驗證系統,其基本設計精神為易於使用以及易於實作。它可以使用於當今主要的各種瀏覽器環境中,你可以現在就開始使用它。

+ +

為什麼你應該套用 Persona 在你的網站上呢?

+ +
    +
  1. Persona 完全消除了特定網站的密碼,讓使用者們與網站們從創立、管理以及安全地保存密碼的責任中解放出來。
  2. +
  3. Persona 易於使用。只需要兩次點擊,一位 Persona 使用者即可登入某個新網站,諸如:VoostThe Times Crossword ,避開了造訪新網站又要再申請一組帳號密碼的麻煩事。
  4. +
  5. Persona 易於實作。開發人員只需要花一個下午的時間,即可將 Persona 套用到一個網站中。
  6. +
  7. 更棒的是,不會被鎖定。開發人員可以取得造訪網站的所有使用者已驗證過的電子郵件信箱,而使用者可以使用任何一個或多個電子郵件信箱在 Persona 中。
  8. +
+ +

而且,Persona 未來將會變得越來越棒:它是基於開放去中心化的通訊協定,被設計規劃成可直接整合到各個瀏覽器中,以及可由電子郵件服務提供者直接提供支援。今天採用並導入 Persona 的網站將直接體驗到這些未來的改進項目,不需要再更動其程式碼。

+ +
備註:Persona 正在很活躍地開發中。歡迎造訪我們的 blog 來認識更多心功能,或是加入我們的郵件群組(英文)給予我們更多建議與回饋!
+ +

動手導入 Persona 到你的網站中

+ + + + + + + + + + + + +
+

開始動手!

+ +
+
為什麼是 Persona?
+
認識更多關於在你的網站上採用 Persona 的原因,以及它與其他身分驗證系統的差異比較。
+
快速指南
+
這是一份快捷的攻略,馬上學習如何在你的網站中加入 Persona 功能。
+
+
+

Persona API 參考資料

+ +
+
navigator.id API
+
這是一份關於 navigator.id 物件的參考資料,Web 開發人員可以用來將 Persona 整合到網站中。
+
Verification (驗證) API
+
這份參考資料是關於建構在https://verifier.login.persona.org/verify 的遠端驗證 API。
+
+
+

導引指南

+ +
+
安全考量
+
實作與技巧用以確保你的 Persona 佈署是安全的。
+
瀏覽器相容性
+
確切得知有哪些瀏覽器有支援 Persona。
+
國際化
+
了解 Persona 如何處理不同的各國語言。
+
+
+

資源

+ +
+
函式庫與套件
+
尋找你愛好的程式語言、web framework、blog 或是內容管理系統 (CMS) 的函式庫或套件 (plugin)。
+
The Persona cookbook
+
給 Persona 網站參考的範例程式碼。包含有 C# (MVC3)、PHP、Node.JS 等等各種語言。
+
品牌資源
+
Persona 登入按鈕,以及方便你的使用者識別的 Persona 圖形資源。
+
+
+ +

 

+ + + + + + + + +
+

給身分識別提供者 (Identity Provider) 的資訊

+ +

如果你是電子郵件服務提供者,或是身分識別服務提供者,請參考以下資訊獲知如何整合並成為一個 Persona 身分識別提供者 (IdP)。

+ +
+
IdP 概述
+
Persona 身份識別提供者概述。
+
實作 IdP
+
這是一份詳細的技術指南,關於如何成為身分識別提供者 (IdP)。
+
.well-known/browserid
+
.well-known/browserid 文件的結構與用途概述。這份文件檔案被 IdPs 用於廣播通知其支援此通訊協定。
+
+
+

Persona 專案

+ +
+
專有名詞對照表
+
BrowserID 和 Persona 定義的專有名詞。
+
FAQ
+
常見問題集。
+
通訊協定概述
+
BrowserID 通訊協定的底層技術性概述。
+
加密
+
一瞥 Persona 和 BrowserID 背後的密碼學概念。
+
規格
+
在這裡可以挖到更多更深的技術性細節。
+
Persona 網站
+
為了讓 Persona 運作,我們在 https://login.persona.org 設立了三種服務:一個身分識別提供者,一個可移動可轉移的 {{ domxref("navigator.id") }} API 實作,以及一個身分判定 (identity assertion) 驗證服務。
+
Persona 原始程式碼
+
我們將 Persona 網站背後的程式碼放在 GitHub 上。非常歡迎送 Pull requests 給我們!
+
+
+ +

 

diff --git a/files/zh-tw/archive/mozilla/persona/internationalization/index.html b/files/zh-tw/archive/mozilla/persona/internationalization/index.html new file mode 100644 index 0000000000..b4ec357352 --- /dev/null +++ b/files/zh-tw/archive/mozilla/persona/internationalization/index.html @@ -0,0 +1,51 @@ +--- +title: Internationalization +slug: Archive/Mozilla/Persona/Internationalization +tags: + - Persona +translation_of: Archive/Mozilla/Persona/Internationalization +--- +

Persona 的本土化如何呢?

+

將來,使用 Persona 登入網站的使用者界面(UI)將被直接集成至瀏覽器中,並且隨著瀏覽器自己的本土化來本土化。。而不支援集成的瀏覽器,Persona 的使用者界面即由一系列來自 login.persona.org 的對話框所組成。這些對話框的翻譯由來自社群的自願者進行,並且有超過 45 種語言可用於這些產品中

+

Persona 如何選擇語言?

+

Persona 服務通過來自瀏覽器請求頭部訊息中的 Accept-Language 來選擇語言。Accept-Language 頭部訊息所使用的語言與 mozilla.org 所使用的為一致:

+
    +
  1. 對於每個 Accept-Language 中的語言標籤: +
      +
    • 確保我們有完整的該語言標籤的語言,則為精準配對該語言標籤
    • +
    • 確保我們有該語言標籤中的第一個部分,則精準配對第一部分
    • +
    +
  2. +
  3. 若沒辦法通過規則 1 來配對,則退而使用 en-US 。但是,通常 en 或 en-US 幾乎會被大多數瀏覽器作為最後一個傳送的 accept-lang 頭部資訊。
  4. +
+

舉例來說,下列下列表格列出了不同的 Accept-Language 會選擇的語言,假設支援下列語言: en-US, es, es-MX:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Accept-Language HeaderPersona 選擇的語言
es-AR,es;q=0.8,en-us;q=0.5es
es-MX,es;q=0.8,en-us;q=0.5es-MX
es-es,en-us;q=0.5en-US
es-esen-US
+

目前還沒辦法讓網站強制將對話框設為某一種語言。這是因為 Persona UI 的邏輯是(以及未來在本機上實現的,也會是)設計為作為瀏覽器的使用者界面的一部分,所以其語言應該要同瀏覽器的語言一致。

+

我可以如何協助?

+

Persona 使用了 Mozilla Verbatim 來協助志願者建立新的翻譯。若您想幫助,請參閱開始使用 Verbatim 並看看 Verbatim 上的「BrowserID」計劃

+

 

diff --git a/files/zh-tw/archive/mozilla/persona/quick_setup/index.html b/files/zh-tw/archive/mozilla/persona/quick_setup/index.html new file mode 100644 index 0000000000..d21858329f --- /dev/null +++ b/files/zh-tw/archive/mozilla/persona/quick_setup/index.html @@ -0,0 +1,137 @@ +--- +title: 快速指南 +slug: Archive/Mozilla/Persona/Quick_Setup +translation_of: Archive/Mozilla/Persona/Quick_Setup +--- +

要把 Persona 登入系統加到你的網站,只需要五個步驟:

+
    +
  1. 在你的網頁中引入 Persona 的 JavaScript 函式庫。
  2. +
  3. 加上「登入」和「登出」按鈕。
  4. +
  5. 監聽登入和登出行為。
  6. +
  7. 驗證使用者的身分 (credential)。
  8. +
  9. 檢視最佳導入實例。
  10. +
+

你應該能在一個下午就建置完成並開始執行,另外重要的事情是:如果你要在你的網站上開始使用 Persona,請花點時間訂閱 Persona 通知 郵件清單。它的流量非常低,只會用於通知你關於變更公告或是安全問題等可能對你的網站造成影響的議題。

+

步驟1:引入 Persona 函式庫

+

Persona 被設計為跨瀏覽器且可在全部主要桌面和移動瀏覽器中工作。

+

在未來我們期望瀏覽器提供 Persona 的原生支援,但我們同時提供了一個 JavaScript 函式庫完整實作了使用者介面和客戶端部分的協議。透過包含這個函式庫,你的使用者將可以用 Persona 登入,無論他們的瀏覽器是否有原生支援。

+

一旦頁面中的這個函式庫載入完成,你需要的 Persona 函式({{ domxref("navigator.id.watch()", "watch()") }}、{{ domxref("navigator.id.request()", "request()") }} 和 {{ domxref("navigator.id.logout()", "logout()") }})會在全域物件 navigator.id 中可用。

+

要包含 Persona JavaScript 函式庫,你可以把這個 script 標籤放進你頁面的首部:

+
<script src="https://login.persona.org/include.js"></script>
+
+

必須在每個使用 {{ domxref("navigator.id") }} 中函式的頁面裡包含這個標籤。因為 Persona 始終在開發中,你不應該自行管理 include.js 檔。

+

步驟2:加入登入/登出按鈕

+

因為 Persona 被設計為一個 DOM API,你必須在使用者按下你網站上的登入或登出按鈕時呼叫函式。要開啟 Persona 對話視窗並提示使用者登入,你應該呼叫 {{ domxref("navigator.id.request()") }} 。而登出要呼叫 {{ domxref("navigator.id.logout()") }} 。

+

例如:

+
var signinLink = document.getElementById('signin');
+if (signinLink) {
+signinLink.onclick = function() { navigator.id.request(); };
+};
+
+var signoutLink = document.getElementById('signout');
+if (signoutLink) {
+signoutLink.onclick = function() { navigator.id.logout(); };
+};
+
+

那些按鈕的是什麼樣子的?查看我們的品牌資源頁面中的預製圖片和基於 CSS 的按鈕!

+

步驟3:監視登入/登出行為

+

要把 Persona 封裝成函式,你需要告訴它當使用者登入/登出時做甚麼。呼叫 {{ domxref("navigator.id.watch()") }} 函式就可以實作,它支援三處:

+
    +
  1. +

    你網站目前使用者的 loggedInEmail ,如果沒有則為 null 。你應該在渲染頁面的時候動態產生它。

    +
  2. +
  3. +

    當觸發 onlogin 行為的時候呼叫的函式。這個函式會被傳遞一個必須認證的「身分斷言」參數。

    +
  4. +
  5. +

    當觸發 onlogout 行為的時候呼叫的函式。這個函式不會被傳遞任何參數。

    +
  6. +
+
+

注意:你必須總是在呼叫 {{ domxref("navigator.id.watch()") }} 時同時包含 onloginonlogout

+
+

例如,如果你現在認為 Bob 已經登入到你的網站,你會這樣做:

+
var currentUser = 'bob@example.com';
+
+navigator.id.watch({
+loggedInUser: currentUser,
+onlogin: function(assertion) {
+// 一個使用者已經登入!這是你需要做的:
+// 1. 把斷言發送到後端驗證並建立一個工作階段。
+// 2. 更新你的 UI。
+$.ajax({ /* <-- 本例使用了 jQuery,但你也可以用你想用的 */
+type: 'POST',
+url: '/auth/login', // 這是你網站上的一個 URL
+data: {assertion: assertion},
+success: function(res, status, xhr) { window.location.reload(); },
+error: function(res, status, xhr) { alert("登入失敗" + res); }
+});
+},
+onlogout: function() {
+// 一個使用者已經登出!這是你需要做的:
+// 銷毀使用者的工作階段並重新導向使用者或做後端的呼叫。
+// 同樣,讓 loggedInUser 在下個頁面載入時變為 null。
+// (這是一個字面的 JavaScript null。不是 false、 0 或 undefined。null。)
+$.ajax({
+type: 'POST',
+url: '/auth/logout', // 這是你網站上的一個 URL
+success: function(res, status, xhr) { window.location.reload(); },
+error: function(res, status, xhr) { alert("登出失敗" + res); }
+});
+}
+});
+
+

在本例中,onloginonlogout 都通過向你網站的後端發送非同步 POST 請求來實作。後端隨後通常用設定或刪除工作階段 cookie 中的資訊來登入或登出使用者。之後,如果一切都核對無誤,頁面重新載入來考慮帳號的新登入狀態。

+

你當然可以用 AJAX 來不用重新載入或重新導向來實作,但這超出了本教學的範疇。

+

必須在每個有登入/登出按鈕的頁面上呼叫這個函式。要為使用者支持 Persona 加強功能,諸如自動登入和全域登出,你應該在網站上的每個頁面都呼叫這個函式。

+

步驟4:驗證使用者證書

+

Persona 用「身分斷言」來代替密碼,那是一種類似一次性、單一網站的、使用者郵件地址捆綁的密碼。當使用者想要登入時,你的 onlogin 回調會傳入一個該使用者的斷言來呼叫。在你登入他們前,你必須驗證斷言的有效性。

+

在你的伺服器上而不是使用者瀏覽器上執行的 JavaScript 中驗證斷言是極度重要的,因為那很容易偽造。上面的例子用 jQuery 的 $.ajax() 輔助函式來把斷言通過 POST/auth/login 來呈遞給後端。

+

一旦你的伺服器取得了斷言,你如何驗證它?最簡單的方法是用 Mozilla 提供的輔助服務。簡單地把斷言以兩個參數 POSThttps://verifier.login.persona.org/verify

+
    +
  1. assertion: 使用者提供的身分斷言。
  2. +
  3. audience: 你網站的主機名稱和連接埠。你必須在後端硬編碼這個值;不要從使用者提供的任何資料中派生這個值。
  4. +
+

例如,如果你是 example.com,你可以用下面的命令行來測試斷言:

+
$ curl -d "assertion=<ASSERTION>&audience=https://example.com:443" "https://verifier.login.persona.org/verify"
+
+

如果它是有效的,你會得到像這樣的一個 JSON 回應:

+
{
+"status": "okay",
+"email": "bob@eyedee.me",
+"audience": "https://example.com:443",
+"expires": 1308859352261,
+"issuer": "eyedee.me"
+}
+
+

你可以閱讀驗證服務 API來獲知更多關於驗證服務的內容。一個 /api/login 實作的使用了 PythonFlask web 框架和 Requests HTTP 函式庫的例子看起來是這樣:

+
@app.route('/auth/login', methods=['POST'])
+def login():
+# 請求必須包含我們要驗證的斷言
+if 'assertion' not in request.form:
+abort(400)
+
+# 把斷言發送給 Mozilla 的驗證服務
+data = {'assertion': request.form['assertion'], 'audience': 'https://example.com:443'}
+resp = requests.post('https://verifier.login.persona.org/verify', data=data, verify=True)
+
+# 驗證器回應了嗎?
+if resp.ok:
+# 處理回應
+verification_data = json.loads(resp.content)
+
+# 檢查斷言是否有效
+if verification_data['status'] == 'okay':
+# 設置一個安全工作階段 cookie 來登入使用者
+session.update({'email': verification_data['email']})
+return resp.content
+
+# 哎喲,有什麼東西不對,放棄
+abort(500)
+
+

工作階段管理可能很像你現有的登入系統。首先的大區別是在驗證使用者身分採用了檢查斷言而不是檢查密碼。另一個不同是確保使用者的郵件地址有效來用於 {{ domxref("navigator.id.watch()") }} 的 loggedInEmail 參數

+

登出很簡單:你只需要移除使用者的工作階段 cookie。

+

步驟5:回顧最佳實踐

+

一旦所有的東西都工作正常並且你已經成功登入和登出你的網站,你應該花一會時間來回顧安全可靠地使用 Persona 的最佳實踐

+

如果你在做一個要作為生產環境的網站,你會想要編寫整合測試來模擬用 Persona 登入或登出使用者。要改善 Selenium 中的這個行為,請考慮使用 bidpom 函式庫。mockmyid.compersonatestuser.org 這兩個網站也可能會有用。

+

最後,不要忘記登記加入 Persona 通知 郵件清單,這樣會通知你任何安全問題或 Persona API 的向後相容變更。這個清單的流量非常低:它只用於通知會對你的網站造成負面影響的變更。

diff --git a/files/zh-tw/archive/mozilla/persona/remote_verification_api/index.html b/files/zh-tw/archive/mozilla/persona/remote_verification_api/index.html new file mode 100644 index 0000000000..7d84cc21b6 --- /dev/null +++ b/files/zh-tw/archive/mozilla/persona/remote_verification_api/index.html @@ -0,0 +1,171 @@ +--- +title: 遠端驗證 API +slug: Archive/Mozilla/Persona/Remote_Verification_API +translation_of: Archive/Mozilla/Persona/Remote_Verification_API +--- +

概覽

+

當使用者嘗試登入至網站時,瀏覽器會產生一名為「斷言」的資料結構,其實質上就是一個加密過的電子郵件位置。瀏覽器傳送這個斷言至網站上,使用者登入前,網站必須驗證斷言的有效性。

+

斷言可以在本地端或是通過在下列位置的 API 來進行驗證:https://verifier.login.persona.org/verify。這個頁面介紹了如何使用 API 。

+

方法

+

HTTP POST 請求至 https://verifier.login.persona.org/verify

+

參數

+
+
+ assertion
+
+ 使用者所提供之斷言。作為傳入 {{ domxref("navigator.id.watch()") }} 中 onlogin 函數的第一個參數。
+
+ audience
+
+ 您網站的通訊協定、網域名稱、與通訊埠。例如:「https://example.com:443
+
+

回傳值

+

呼叫後會傳統一個包含 status 元素的 JSON 結構,其值可能為「okay」或是「failure」。 依據 status 的值的不同,可能會包含下列表中的額外元素。

+

"okay"

+

該斷言有效。

+

在這種情況下,JSON 結構會包含下列附加元素:

+ + + + + + + + + + + + + + + + + + + +
"email"斷言中包含的登入者的郵件位置。
"audience"Audience 的值包含了斷言。Expected to be your own website URL.
"expires"斷言有效期的資料,expressed as the primitive value of a Date object: that is, the number of milliseconds since midnight 01 January, 1970 UTC.
"issuer"The hostname of the identity provider that issued the assertion.
+

"failure"

+

該斷言無效。這種情況下 JSON 結構將會包含一個附加的元素:

+ + + + + + + +
"reason"一字串解釋驗證為何失敗。
+

範例

+

node.js

+

該範例為使用 express.js 的 Node.js 伺服器。

+
var express = require("express"),
+    app = express.createServer(),
+    https = require("https"),
+    querystring = require("querystring");
+/* ... */
+
+// Audience 必須符合您瀏覽器的位置列上顯示的,
+// 包含通訊協定、主機名稱、以及通訊埠。
+var audience = "http://localhost:8888";
+
+app.post("/authenticate", function(req, res) {
+  var vreq = https.request({
+    host: "verifier.login.persona.org",
+    path: "/verify",
+    method: "POST"
+  }, function(vres) {
+    var body = "";
+    vres.on('data', function(chunk) { body+=chunk; } )
+        .on('end', function() {
+          try {
+            var verifierResp = JSON.parse(body);
+            var valid = verifierResp && verifierResp.status === "okay";
+            var email = valid ? verifierResp.email : null;
+            req.session.email = email;
+            if (valid) {
+              console.log("assertion verified successfully for email:", email);
+              res.json(email);
+            } else {
+              console.log("failed to verify assertion:", verifierResp.reason);
+              res.send(verifierResp.reason, 403);
+            }
+          } catch(e) {
+            console.log("non-JSON response from verifier");
+            // bogus response from verifier!
+            res.send("bogus response from verifier!", 403);
+
+          }
+        });
+  });
+
+  vreq.setHeader('Content-Type', 'application/x-www-form-urlencoded');
+
+  var data = querystring.stringify({
+    assertion: req.body.assertion,
+    audience: audience
+  });
+
+  vreq.setHeader('Content-Length', data.length);
+  vreq.write(data);
+  vreq.end();
+
+  console.log("verifying assertion!");
+});
+
+
+

via Lloyd Hilaiel

+

PHP

+
$url = 'https://verifier.login.persona.org/verify';
+$assert = filter_input(
+    INPUT_POST,
+    'assertion',
+    FILTER_UNSAFE_RAW,
+    FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH
+);
+//使用 $_POST 超全域陣列供 PHP < 5.2 並撰寫您自己的篩選其
+$params = 'assertion=' . urlencode($assert) . '&audience=' .
+           urlencode('http://example.com:80');
+$ch = curl_init();
+$options = array(
+    CURLOPT_URL => $url,
+    CURLOPT_RETURNTRANSFER => TRUE,
+    CURLOPT_POST => 2,
+    //CURLOPT_SSL_VERIFYPEER => true,   //This currently blocks connection to 'https://verifier.login.persona.org/verify'
+    CURLOPT_SSL_VERIFYPEER => 0,
+
+    CURLOPT_SSL_VERIFYHOST => 2,
+    CURLOPT_POSTFIELDS => $params
+);
+curl_setopt_array($ch, $options);
+$result = curl_exec($ch);
+curl_close($ch);
+echo $result;
+

Via Christian Heilmann

+

Java

+
@Override
+protected void doPost(final HttpServletRequest req,
+   final HttpServletResponse resp) throws ServletException,
+   IOException {
+
+   final String audience = req.getServerName();
+   final String assertion = req.getParameter("assertion");
+   final Verifier verifier = new Verifier();
+   final BrowserIDResponse personaResponse = verifier.verify(assertion,audience);
+   final Status status = personaResponse.getStatus();
+
+   if (status == Status.OK) {
+     /* Authentication with Persona was successful */
+     String email = personaResponse.getEmail();
+     log.info("{} has sucessfully signed in", email);
+     HttpSession session = req.getSession(true);
+     session.setAttribute("email", email);
+
+   } else {
+     /* Authentication with Persona failed */
+     log.info("Sign in failed...");
+
+   }
+}
+
+

Via Javier

+

 

+

注意:If you send the assertion and audience parameters as a JSON-object, they must not be URL-encoded. If they are sent as regular HTTP POST parameters, as in the example above, they must be URL-encoded.

diff --git a/files/zh-tw/archive/mozilla/persona/why_persona/index.html b/files/zh-tw/archive/mozilla/persona/why_persona/index.html new file mode 100644 index 0000000000..e6b3b97ded --- /dev/null +++ b/files/zh-tw/archive/mozilla/persona/why_persona/index.html @@ -0,0 +1,30 @@ +--- +title: 為什麼是 Persona? +slug: Archive/Mozilla/Persona/Why_Persona +translation_of: Archive/Mozilla/Persona/Why_Persona +--- +

現行的使用者帳號和密碼系統不是個長久之計:使用者每造訪一個新網站新服務就得建立並記住一組新的、複雜的密碼,然後每一個網站系統都必須要夠安全地存放這些密碼。儘管如此,最近的事故中也顯示了即使是有規模、有聲望的大型網路公司也還是會在密碼安全上失誤出錯,讓他們的使用者資訊暴露在風險中。

+

Persona 是一個開放的、分散式的、web 規模的身分識別系統,用以取代一個網站一組密碼的局面。它解決了如 OpenID 這類系統的易用性與隱私相關等缺點,而且不訴諸於如 Facebook Connect 這類型中心化系統架構。

+

Persona 擺脫了每站一密碼

+

Persona 讓使用者在完成一個簡單的、一次性的身分識別處理流程後,只需要兩次點擊即可登入網站,而不再需要每站一密碼了。這是安全、可靠的,並且植基於公開金鑰密碼學的基礎上。使用者的瀏覽器產生一組加密過的「身分判定」來取代密碼,它的有效期只存在幾分鐘而且只能用於單一網站上。因為沒有網站特定的密碼,網站使用 Persona 也就不需要擔心如何安全地儲存密碼或是擔心失去或洩漏密碼資料庫了。

+

如此快速簡便的步驟,將讓使用者更快樂地造訪新網站。

+

Persona 使用電子郵件信箱地址作為身分識別

+

Persona 使用電子郵件信箱地址作為身分的識別方式,而不使用任意形式或自訂形式的用戶名稱作為身分識別。這帶給了使用者與開發人員諸多的好處:

+

使用者使用電子郵件信箱地址的好處

+ +

開發者使用電子郵件信箱地址的好處

+ +

更不用說電子郵件已經是個完整地,橫跨無數服務提供者的,數以億計帳戶的分散式系統。

+

Persona 與其他單一登入 (Single Sign-On) 服務有何不同?

+

Persona 安全、可靠、而且簡單。它保護了使用者的隱私、使用者的控制權、使用者的選擇,而這些是其它登入服務無法或不願意做到的。

+

許多社群網站,例如 Facebook 或 Google+,需要使用者使用真實姓名,並且限制使用者僅能使用單一帳號。藉由建構於電子郵件信箱地址的架構,Persona 允許使用者用以區分它們工作用、家用、學校用等不同的身份識別。

+

Persona 是開放的,也是分散式的:任何一位擁有電子郵件信箱地址的人都可以登入使用 Persona。除此之外,任何人也可以建立他們自己的身份識別服務或委由其他專業機構建立服務,就像使用電子郵件一般。這與需要單一且中心化帳號的社群網站登錄服務的做法剛好相反。

+

Persona 也採用較為新穎的做法來保護使用者的隱私,藉由將瀏覽器置入成為驗證過程當中的一環:瀏覽器從使用者的電子郵件提供者獲取認證身份,然後瀏覽器轉頭將此認證轉呈給網站。電子郵件提供者無法追蹤使用者,但是網站仍可藉由密碼學等驗證技術取得使用者的身份認證,並信任此使用者身份。其它大部份系統,即使是像 OpenID 如此的分散式系統,仍需要網站在背景連接通訊 (phone home) 才允許使用者登入。

diff --git a/files/zh-tw/archive/mozilla/xpinstall/index.html b/files/zh-tw/archive/mozilla/xpinstall/index.html new file mode 100644 index 0000000000..907f839dc4 --- /dev/null +++ b/files/zh-tw/archive/mozilla/xpinstall/index.html @@ -0,0 +1,65 @@ +--- +title: XPInstall +slug: Archive/Mozilla/XPInstall +tags: + - NeedsTranslation + - TopicStub + - XPInstall + - XPInstall_API_reference +translation_of: Archive/Mozilla/XPInstall +--- +

Parts of this page show the use of the XPInstall API. The majority of this API is now deprecated and as of Gecko 1.9 no longer available. Extension, Theme, and plug-in developers must switch away from install.js based packages to the new packaging scheme with an install.rdf manifest. In particular plugin developers should see how to package a plugin as an extension.

+
<?xml version="1.0" encoding="UTF-8"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+  <Description about="urn:mozilla:install-manifest">
+    <!-- properties -->
+  </Description>
+</RDF>
+
+ +
Cross-Platform Install (XPInstall) is a technology used by Mozilla Application Suite, Mozilla Firefox, Mozilla Thunderbird and other XUL-based applications for installing extensions. An XPI (pronounced "zippy" and derived from XPInstall) installer module is a ZIP file that contains an install script or manifest (entitled install.js or install.rdf) at the root of the file.
+ + + + + + + + +
+

Documentation

+ +
+
XPInstall API Reference
+
XPInstall API Reference.
+
Learn XPI Installer Scripting by Example
+
This article uses the installer script from browser.xpi install package as the basis for discussing XPI installations in general.
+
Creating XPI Installer Modules
+
This article describes the packaging scheme of the Mozilla and offers a tutorial for creating a new package that can then be redistributed, installed, and made available to users.
+
Install Wizards (aka: Stub Installers)
+
+ +

View All...

+
+

Community

+ +
    +
  • View Mozilla forums... {{ DiscussionList("dev-platform", "mozilla.dev.platform") }}
  • +
+ +

Tools

+ + + + + + +
+ +

 

diff --git a/files/zh-tw/archive/mozilla/xpinstall/scripting_by_example/index.html b/files/zh-tw/archive/mozilla/xpinstall/scripting_by_example/index.html new file mode 100644 index 0000000000..7d95c88d75 --- /dev/null +++ b/files/zh-tw/archive/mozilla/xpinstall/scripting_by_example/index.html @@ -0,0 +1,244 @@ +--- +title: XPI 安裝腳本範例教學 +slug: Archive/Mozilla/XPInstall/Scripting_by_example +tags: + - XPInstall + - 待翻譯 +translation_of: Archive/Mozilla/XPInstall/Scripting_by_example +--- +

本文以 browser.xpi 安裝套件為基礎,討論一般的 XPI 安裝程序。安裝腳本 installer script 雖短,但含括了 XPInstall API 大部分的重要功能,且可做為其他一般用途套件的安裝腳本樣本。本文在 unix 下安裝,不過各平台的安裝方式大同小異,你可以此變化安裝在各種 Mozilla 支援的平台。

+ +

關於 browser.xpi

+ +

browser.xpi 是 Mozilla 瀏覽器安裝主要元件的 XPI 封存檔。Mozilla 跨平台安裝以 XPI 格式作為組織、壓縮、以及軟體自動化安裝及更新的用途。XPI 的格式同 ZIP 及 JAR,為 PKZIP 壓縮後的檔案,只是內含可供管理安裝方式的腳本。本文目標即為此安裝腳本installer script(通常稱為 install.js)的教學。

+ +

任何能解 ZIP 壓縮檔的工具都能開啟 XPI 檔,先來看看裡面有什麼東西:

+ +
install.js
+bin\
+  chrome\
+  components
+  defaults\
+  icons\
+  plugins\
+  res\
+
+ +

Note that this high-level structure parallels the directory structure of the installed browser very closely:

+ +

mozilla directory on linux

+ +

As you will see in the installation script, the contents of the archive are installed onto the file system in much the same way that they are stored in the archive itself, though it's possible to rearrange things arbitrarily upon installation--to create new directories, to install files in system folders and other areas.

+ +

綜覽安裝腳本

+ +

XPI install scripts are written in JavaScript using XPInstall Engine syntax defined in the XPInstall API Reference.

+ +

Most installation scripts, including the one discussed here, take the following basic form (in pseudo-code and with links to the sections in which these installation steps are documented):

+ +

節譯:大部分的安裝腳本都採以下的概念依流程安裝:

+ +
initInstall();
+if (verify_space()) {
+   err = add_dirs_and_files;
+   register_files;
+
+   if (err==SUCCESS) { performInstall() };
+   else { cancelInstall() };
+}
+
+ +

As you can see in the code listing, the verification process at the top is on lines 1 to 18; the file addition process, here part of the main installation block, is on lines 24 to 41; the registration part of the main installation block is on lines 42-58; and the execution at the end of the main block is on lines 59 to 71. If you choose not to register the installed software or do the verifications at the front end of the installation, then at a minimum, the install scripts mustinitialize, add the files to be installed, and execute.

+ +

Note also that when you call methods on the Install--as you do so often in installation scripts (getFolder, initInstall, addFile, and performInstall are all examples of common Install object methods)--the Install object is implicit; like the window object in regular web page scripts, the Install object does not need to be prefixed to the method.

+ +

初始化

+ +

All installations must begin with initInstall(). The initInstall() method on the Install object creates a new installation for the specified software and version. In the browser.xpi installation, this function appears at line 20: var err = initInstall("Netscape Seamonkey", "Browser", "6.0.0.2000110807");

+ +

如果你在 initInstall() 之前呼叫 Install 物件中的方法,會導致錯誤。

+ +

The initInstall method takes the following parameters: the display name of the package, the name of the package as it appears in the client registry, and the version, which can be expressed as a number or as an InstallVersion object. In the example above, "Netscape Seamonkey" is the display name, "Browser" is the registry name, and the version is "6.0.0.2000110807." See initInstall in the XPInstall API Reference for more information on the initialization process.

+ +

檢驗安裝目標

+ +

The first thing the installation script does when it's executed is to check that there is adequate disk space for the software to be installed, where the verifyDiskSpace function is called as a condition of the main installation block that starts at line 24).

+ +
 // 先檢查磁碟剩餘空間
+ function verifyDiskSpace(dirPath, spaceRequired)
+ {
+   var spaceAvailable;
+   // 取得安裝磁碟之剩餘空間
+   spaceAvailable = fileGetDiskSpaceAvailable(dirPath);
+
+   // 將剩餘空間單位化為 KB
+   spaceAvailable = parseInt(spaceAvailable / 1024);
+   // 開始檢查
+   if(spaceAvailable < spaceRequired)
+   {
+      logComment("Insufficient disk space: " + dirPath);
+      logComment("  required : " + spaceRequired + " K");
+      logComment("  available: " + spaceAvailable + " K");
+      return(false);
+   }
+   return(true);
+ }
+
+ +

In the verifyDiskSpace block, fileGetDiskSpaceAvailable is called with dirPath as its expected input. This input is defined in line 22, where getFolder() is used to assign a value to the communicatorFolder variable representing the "Program" folder on the local system:

+ +
var communicatorFolder = getFolder("Program");
+spaceAvailable = fileGetDiskSpaceAvailable(dirPath);
+
+ +

spaceRequired, the other expected input to the verifyDiskSpace function, is given as 17311 kilobytes on line 19. Inside the function, the two sizes are compared and if the available space is larger than the required space, the installation proceeds.

+ +

為 Install 物件加入檔案及內含檔案的目錄

+ +

一旦確保程式可以開始安裝,就該把想放的檔案加入安裝程序。在 browser.xpi 中,此程式段位於 26 到 41 行:

+ +
  err = addDirectory("Program",
+                     "6.0.0.2000110807",
+                     "bin",              // jar source folder
+                     communicatorFolder, // target folder
+                     "",                 // target subdir
+                     true );             // force flag
+
+  logComment("addDirectory() returned: " + err);
+
+  // 建立 plugins 目錄
+  var pluginsFolder = getFolder("Plugins");
+  if (!fileExists(pluginsFolder))
+  {
+      var ignoreErr = dirCreate(pluginsFolder);
+      logComment("dirCreate() returned: " + ignoreErr);
+  }
+  else
+      logComment("Plugins folder already exists");
+
+ +

本例檔案都放在單一目錄中, 所以採用 Install 物件的 addDirectory 方法將壓縮檔目錄中的檔案一併加入。addDirectoryaddFile 兩種方法都要指定來源與目的路徑,在此例中是把「bin」目錄中的檔案列為來源,並要求於程式正式呼叫 performInstall 時將檔案安裝到 communicatorFolder 目錄(此變數於第 22 行指定為「Program」)。

+ +

"Program" is one of a short list of keywords that can be used in place of full path names in methods such as addFile. "Program" represents the directory where software itself is installed (e.g., C:\Program Files\ on win32 systems), as opposed to supporting directories like "Components", "Chrome", or "Temporary" (see getFolder in the XPInstall API Reference for a list of keywords).

+ +

登記軟體

+ +

對於一個軟體來說,有時候需要同時在作業系統和 Netscape 6 平台上進行登記「登錄碼」。當你安裝了一個新的 chrome 像是 browser.xpi 時,你需要讓 chrome 登錄碼把這些更新登記在起來;如此一來,面板(skin)、使用者介面(user preference)、檔案清單(packaging list)、本地化文件(localization bundle)就會自動與新的軟體對應。

+ +

對於在 win32 作業系統上登記軟體,XPInstall API 提供兩個特別的物件-WinProfileWinReg。它們能夠對 Windows 使用者資料和 Windows 登錄碼進行對應的操作。browser.xpi 安裝腳本並不強制你使用這些物件。關於在 win32 平台上和其他作業系統登記軟體,詳情可以參考 XPInstall API Reference。

+ +

而要利用 chrome 登錄碼登記基於 Netscape 6 的新軟體,像是一些外掛(plug-in)、元件(component)、佈景主題(theme)和套件(package),你需要使用 Install 物件中的 registerChrome 函數。如果執行成功,這個函數會回傳一個「0」並且將這筆紀錄寫進 chrome 的子目錄「installed-chrome.txt」這個檔案當中以便以後其他的 chrome 能夠同步更新千變萬化的 RDF 檔案。

+ +
 var cf = getFolder("Chrome");
+ registerChrome(CONTENT | DELAYED_CHROME, getFolder(cf,"toolkit.xpi"),"content/global/");
+ registerChrome(CONTENT | DELAYED_CHROME, getFolder(cf,"browser.xpi"),"content/communicator/");
+ registerChrome(CONTENT | DELAYED_CHROME, getFolder(cf,"browser.xpi"),"content/editor/");
+ registerChrome(CONTENT | DELAYED_CHROME, getFolder(cf,"browser.xpi"),"content/navigator/");
+ registerChrome(SKIN | DELAYED_CHROME, getFolder(cf,"modern.jar"),"skin/modern/communicator/");
+ registerChrome(SKIN | DELAYED_CHROME, getFolder(cf,"modern.jar"),"skin/modern/editor/");
+ ...
+
+ +

在第 42 行至 58 行,只要有不同的資料夾中存在需要紀錄在 chrome 紀錄碼中的內容, registerChrome 就會被呼叫。 In lines 42-58, registerChrome is called as many times as there are different directories that contain content that needs to be registered with the chrome registry. Note that in the first few lines of this process, new content from the XPI is being registered, and in the remainder, it is new skin information. In this most common form of the registerChrome function (it can also be used to support the now-deprecatedmanifest.rdf style of installation archive), the three parameters represent, in order, the chrome SWITCH used to indicate what kind of software is being registered, the target destination of the software (e.g., the "Chrome" folder in the example above), and the path within the XPI (or JAR theme archive) where the contents.rdf file is located.

+ +

See registerChrome in the XPInstall API Reference for more information about registering new packages with the chrome registry.

+ +

開始安裝

+ +

Once you have added all the files to the installation, the final step is to actually execute the installation. Note that until this point, the install calls you have been making on the Install object are preliminary only. Recall that an install process takes the following general form:

+ +
initInstall();
+if (verify_space()) {
+   err = add_dirs_and_files;
+   register_files;
+
+   if (err==SUCCESS) { performInstall() };
+   else { cancelInstall() };
+}
+
+ +

In this arrangement, the actual execution of the installation is checked against the errors returned from the addition of files to the installation, which may itself have been conditioned on some verification of version and necessary disk space.

+ +

The actual install code used to execute the installation appears in theinstall.js file as follows:

+ +
if (err==SUCCESS)
+  {
+     err = performInstall();
+        logComment("performInstall() returned: " + err);
+  }
+
+  else
+  {
+     cancelInstall(err);
+	 logComment("cancelInstall() due to error: " + err);
+  }
+}
+else
+   cancelInstall(INSUFFICIENT_DISK_SPACE);
+
+ +

performInstall is the function used to execute the install once it has been initialized and loaded, and it is the last step to installing the software. Note that in the example above, the installation is cancelled if the error code from the file addition process returns success (0), and also cancelled outside the main block if the earlier verification process is not successful.

+ +

Note also the comments that indicate the success of various steps in the process--including the performInstall and cancelInstall steps--are written to the install log using the logComment, described in the following section.

+ +

安裝紀錄

+ +

Logging is an important feature of the XPInstall API that can help you streamline and debug your installations. In the example in the Executing the Installation section and in many places in the installation script, the logComment API is used to write data to a log file that can then be reviewed when things don't go as planned.

+ +

The install log is created in the product directory by default (where the browser executable is). If the installation doesn't have proper permission, the install log is written to the user's profile directory. Respectively, these directories correspond to the "Program" and "Current User" keywords for the getFolder method.

+ +

更進一步

+ +

What does all this mean to you? How can this information be adapted for your own installations? In this final section, we describe the application of the XPInstall technology described here in the creation and deployment of a very simple installation script and installation archive (XPI).

+ +

Say you have a simple executable and a README file that goes with it, and you want to make it available for installation from a XPI. After putting these two files in a XPI (which, as described above, is simply a ZIP file with an install.js script at the top and a suffix of '.xpi'), the next step is to add an installation script to the XPI.

+ +

Minimally, the installation script must:

+ + + +

Here is an example of small but complete installation script.

+ +
var xpiSrc = "cd_ripper.exe";
+var xpiDoc = "README_cdrip";
+
+initInstall("My CD Ripper", "cdrip", "1.0.1.7");
+f = getFolder("Program");
+setPackageFolder(f);
+addFile(xpiSrc);
+addFile(xpiDoc);
+
+if (0 == getLastError())
+	performInstall();
+else
+	cancelInstall();
+
+ +

The example above shows this minimal installation. This install script does not include any version or disk space checking, very little error checking, only a single executable, no registration, and no commenting. It does, however, take the executable and the README file and install them on the user's system. Note also that for the installation script in a XPI to be automatically triggered from a web page, you must use a "trigger script." The following InstallTrigger function, called from an event handler on a regular web page, will point to the remotely-hosted XPI (called here 'cdrip.xpi') and trigger its installation:

+ +
function putIt()
+{
+  xpi={'CD_Ripper':'cdrip.xpi'};
+  InstallTrigger.install(xpi);
+}
+...
+
+<a href="#" onclick="putIt();">install the CD Ripper Now!</a>
+
+ +

See the InstallTrigger object in the XPInstall API Reference for more information on triggering installations.

+ +
+

原文資訊

+ + +
diff --git a/files/zh-tw/archive/mozilla/xul/index.html b/files/zh-tw/archive/mozilla/xul/index.html new file mode 100644 index 0000000000..ac13916ad4 --- /dev/null +++ b/files/zh-tw/archive/mozilla/xul/index.html @@ -0,0 +1,99 @@ +--- +title: XUL +slug: Archive/Mozilla/XUL +tags: + - XUL +translation_of: Archive/Mozilla/XUL +--- +

 

+ +
XUL 指南
+這份指南將協助你開始學習 XUL,原始創作來自於 XULPlanet。
+ +
XUL (XML User Interface Language,XML 使用者介面語言) 是 Mozilla 以 XML 為基礎的語言,可以讓你打造豐富功能且跨平台的應用程式,不論是否有連線到網際網路。這些應用程式可以輕鬆地自訂文字、圖案以及排版,因此可以很方便地為不同市場區塊發表不同品牌形象或本地化。已經熟悉 Dynamic HTML (DHTML) 的 Web 開發人員將可以很快地學會 XUL,並且馬上開始開發應用程式。 用 Firefox 或其他以 Gecko 為基礎的瀏覽器開啟 XUL 週期表 ,你將會看到一些 XUL 範例。
+ + + + + + + + +
+

文件

+ +
+
XUL 參考文獻
+
請參照這份 prefwindow MDC 文件。
+
+ +
+
XUL 控制項
+
快速瀏覽 XUL 控制項。
+
+ +
+
第一次玩 XUL 就上手
+
介紹 XUL 幾項重要功能與元件。
+
+ +
+
選單和彈出選單指南
+
選單和彈出式面板的指南。
+
+ +
+
XUL 模板指南
+
一份詳細討論 XUL 模板的指南,是個從資料源產生內容的方法指引。
+
+ +
+
XUL 的拖曳處理
+
如何使用拖曳操作。
+
+ +
+
為 Firefox 1.5 改寫 XUL 應用程式
+
一份關於 Firefox 1.5 所做變更的清單,會影響到使用 XUL 開發人員。
+
+ +

所有文件...

+
+

社群

+ +
    +
  • 查閱 Mozilla 討論區...
  • +
+ + + + + +

工具

+ + + +

所有工具...

+ +

相關主題

+ +
+
JavaScript, XBL, CSS, RDF, Extensions, XULRunner
+
+
+ +

Categories

+ +

Interwiki Language Links

diff --git a/files/zh-tw/archive/mozilla/xul/template_guide/index.html b/files/zh-tw/archive/mozilla/xul/template_guide/index.html new file mode 100644 index 0000000000..643bdaea0e --- /dev/null +++ b/files/zh-tw/archive/mozilla/xul/template_guide/index.html @@ -0,0 +1,5 @@ +--- +title: Template Guide +slug: Archive/Mozilla/XUL/Template_Guide +--- +

這個頁面無內容。您可以通過貢獻來豐富 MDN 的內容

diff --git a/files/zh-tw/archive/mozilla/xul/the_joy_of_xul/index.html b/files/zh-tw/archive/mozilla/xul/the_joy_of_xul/index.html new file mode 100644 index 0000000000..ab1da2e93c --- /dev/null +++ b/files/zh-tw/archive/mozilla/xul/the_joy_of_xul/index.html @@ -0,0 +1,49 @@ +--- +title: The Joy of XUL +slug: Archive/Mozilla/XUL/The_Joy_of_XUL +tags: + - XUL +translation_of: Archive/Mozilla/XUL/The_Joy_of_XUL +--- +

 

+

建議的讀者群:想要更加認識 XUL 且想瞭解為什麼 Mozilla 會採用 XUL 的應用開發人員與管理者。

+

翻譯原則:由於考量到預設讀者群應該有某種程度的原文專有名詞的認識基礎,故盡可能保留原文專有名詞,或採用加註的方式呈現。如果文中有對稱關係,則採用對稱保留或加註。

+

 

+

序論

+

XUL (發音〝/zu:l/〞) 是 Mozilla 以 XML 為基礎的使用者介面語言,讓你盡情地開發各式各樣的跨平台應用程式,不論是否在連線到網際網路的狀態皆可。這些應用程式可以藉由簡單地變更文字,圖案與版面佈局,來達到客製化的目的,因此可以輕易地本土化以推廣到各種市場去。如果您已經是熟習 Dynamic HTML (DHTML) 的網頁設計師,那您將可以很快地學會 XUL 並且可以馬上開始動手建構應用程式了。

+

這份文件將介紹一些比較吸引人的理由給網頁設計師,來應用 XUL 以及 Mozilla 相關技術來撰寫跨平台的應用程式。這也將充分說明 Mozilla 要設計 XUL 的動機,以及為什麼 Mozilla 平台是使用 XUL 建構起來的。XUL 的重要特色與優勢將會接著以支援 Mozilla 技術的方式來呈現。最後,有個關於 "使用 XUL 所撰寫之 Calendar" 的小小個案研討,作為補充。

+

重要特色與優勢

+ +
強大、以元件為基礎的標示語言 XUL 的目標是建造跨平台的應用程式,以別於原本拿來設計網頁的 DHTML。因此,XUL 設計為應用程式的加工組件(application artifacts),如︰視窗(windows)、標籤(labels)、按鈕(buttons)等,用來取代頁面(pages)、大標題(heading levels)、連結(hypertext links)等。

事實上,許多開發人員已經嘗試在他們的 DHTML 網頁應用程式中達到圖形界面的效果,但這其中的代價就是複雜以及效能,而且沒有任何標準可以支援。

以現有標準為基礎 XUL 是立基於 W3C 標準 XML 1.0 的一個 XML 語言。使用 XUL 的應用程式是建構於這些 W3C 標準技術之上︰HTML 4.0、CSS 1 & 2、DOM Levels 1 & 2、JavaScript 1.5,包括 ECMA-262 Edition 3 (ECMAscript)、XML 1.0。

mozilla.org 正進一步地尋求 W3C 為 eXtensible Binding Language (XBL) 標準化。(參考下面的〝支援技術〞)。

平台可攜性 如同 HTML,XUL 被設計成與平台無關的,可以很容易地讓應用程式在任何存在 Mozilla 的作業系統上面使用。想想看現在有多麼廣泛的平台支援 Mozilla,這是以 XUL 技術來開發應用程式當中,最令人讚嘆的特色。

因為 XUL 提供了使用者介面組成元件的抽象層,因此實現了這個保證︰一經寫就,處處執行 (write-once, run-anywhere)。所有 Mozilla 核心應用程式的使用者介面都是用 XUL 所撰寫的,並且該單一程式碼,在所有 Mozilla 平台上都支援。

分離介面呈現與程式流程 大部分網頁應用程式沒落的主因就是,把使用者介面跟程式流程緊緊的結合在一起了。這在一個團隊的環境中是個頗為難的問題,因為這兩部分所需的技能通常是分散在不同的人身上。

XUL 很清楚地分離出應用程式的各個組成︰程式流程 ("content" 以 XUL、XBL 與 JavaScript 組成)、外觀 ("skin" 以 CSS 和圖像組成)、與特定語言的文字標籤 ("locale" 以 DTD 以及在 .properties 檔案中的對應字串)。XUL 應用程式的佈局與外觀可以自由地改變,獨立程式與流程之外。甚至,應用程式可以本地化為任何語言或地區,完全獨立於程式流程或外觀。

對應用程式作各種分離所得的結果是︰程式設計師可以很容易地維護程式,設計師可以輕鬆地變更設計樣式,而各個語言的翻譯人員也可以自行完成翻譯工作。這樣子獨立的工作流程,相較於以 HTML 為基礎的應用程式更容易協同工作,也減少了整個系統在穩定性與品質上的衝擊。

輕鬆自訂、本地化、打品牌 另一個由分離程式流程,介面呈現和語言文字所直接造成的特點,即是不同的使用者或使用群可以很容易的修改成所需要的樣子。

程式開發人員可以只維護應用程式的主要程式碼,然後藉由使用不同的外觀介面 (skin) 來自訂圖示與品牌觀感給他們不同的顧客群。一個以英文介面撰寫與開發的應用程式,可以被翻譯成法文給相同需求的顧客使用。當這些改變被廣泛地使用在這個應用程式的時候,他們也可以從程式流程與介面呈現之中獨立出來,來分享給所有的自訂版本。

+

支援技術

+

這裡有一些 Mozilla 所用來支援 XUL 撰寫跨平台網頁應用程式的技術。

+ +
XBL eXtensible Bindings Language (XBL) 是一種標記語言 (markup language),定義了新的物件元素以及給 XUL 構件 (widget) 的 "bindings"。藉由 XBL,開發人員可以為 XUL 構件定義新的內容,為 XUL 構件添加事件處理,加入新的介面屬性與方法。事實上,XBL 將使得開發人員得以利用自訂現有的標籤 (tag) 或是新增他們所需要的標籤來擴充 XUL。

藉由使用 XBL,開發人員可以輕易地建構出所想要的使用者介面物件,如︰進度表、別緻的彈出式選單、甚至是工具列或搜尋表單。這些自訂物件可以在指定標籤與其屬性之後,使用在各個 XUL 應用程式當中。

Overlays Overlay 是用來描述使用介面之額外內容的 XUL 檔案。他們是一種增添使用介面的通用機制,用以增加額外的元件,覆蓋掉 XUL 檔案中不再支援的使用者介面,並且可以重新利用使用者介面當中的一些片段。

Overlay 對於自訂與擴充現有應用程式而言是個很強大的機制,因為他們是以兩種相關但卻又幾乎完全不同的方式在運作著。某種程度上看來,Overlay 其他語言所謂的〝引入(include)〞檔案,因為一個應用程式可能指定在其定義中引入一個 Overlay。但是 Overlay 也可以只用於外觀上,使得設計人員可以在某個應用程式上頭使用 Overlay,而不需要改變其原始程式。

在實作上,這使得開發人員只需對其應用程式維護一組程式碼,然後再為客戶應用各自自訂的外型,或是引入特別的功能,而這些都完全獨立於主程式碼。這導致整個解決方案的簡化,與降低維護成本。

Overlay 對於那些想要為 Mozilla 增添新功能但又希望保有著作權的軟體開發人員而言還有個特點。這兩種執照聲明︰Netscape Public License (NPL) 和 Mozilla Public License (MPL) 都要求那些有對原始程式 (Mozilla 所提供的那些原始程式碼) 做過修改的開發人員,要釋放出他們變更之後的程式碼給他們的顧客。Overlay 可以在變更著作權的情況下用來為 Mozilla 增添新的功能,而不會污染了最原始的開放原始程式碼。

XPCOM/XPConnect XPCOM 與 XPConnect 都是加強技術,將外部函數庫與 XUL 應用程式整合在一起。

XPCOM,代表的是跨平台組成物件模型 (Cross Platform Component Object Model),是個用來撰寫跨平台與軟體模組化的一個架構。XPCOM 的組成元件可以用 C、C++ 和 JavaScript 來撰寫,並且可以在這些環境下來開發︰C、C++、JavaScript、Python、與 Perl 擴充集。

XPConnect 這個技術是用來製造出簡單的 XPCOM 與 JavaScript 之間的溝通。XPConnect 允許 JavaScript 物件正大光明地存取與運用 XPCOM 物件。他也讓 JavaScript 物件可以表示成 XPCOM 相容介面以供 XPCOM 物件呼叫使用。

將兩者合在一起,XPCOM 和 XPConnect 使得開發人員可以設計那些需要使用編譯式語言的效能或是存取作業系統等級的 XUL 應用程式。

XPInstall XPInstall,Mozilla 的跨平台安裝技術,提供了一個標準的方式將 XUL 應用程式的各個元件包裝成一個安裝檔案,來讓 Mozilla 可以下載並且執行之。

XPInstall 讓使用者可以毫不費力地從網際網路或是公司主機來安裝新的 XUL 應用程式。要安裝一個新的應用程式,使用者只要在網頁上或是電子郵件訊息中的超連結點一下滑鼠,然後在安裝對話方塊中允許安裝新的應用程式即可。

+

個案研討: A Mozilla Calendar Application

+

這個小型的個案研討將敘述 OEone 公司 (http://www.oeone.com) 如何將他的 Calendar 應用程式整合成為 Mozilla 的核心產品. Calendar 包含了 XUL 前端使用介面與以 C 寫成的 XPCOM 元件函式庫 libical , 該函式庫主要是供日期運算以及行事曆資料的儲存. 原本 Calendar 只有在 Linux 上開發, 但是都會成功地在一週之內移植到 Macintosh 和 Windows 平台上.

+

XUL 提供了許多的使用者介面元件. Calendar 的使用者介面完完全全都是用 XUL 所完成的, JavaScript? 還有 CSS, 都可以證明這樣的開發平台所帶來的強大與彈性. 他使用了簡單的 XUL 元件, 例如 boxes, grids, 和 stacks 來構成週, 日, 和月的瀏覽介面. 一開始 Calendar 還沒有利用到 XBL, 因為開發人員還沒完全清楚地掌握這整個開發技術. 但是 Calendar 的未來計畫已經包含了要將這些使用者介面的元件轉換成 XBL widgets 來簡化開發工作.

+

XPCOM/XPConnect 讓整合現有程式碼成為可能. 一個擁有完整行事曆功能的開放原始碼函式庫, libical (http://www.softwarestudio.org/libical/), 被 Calendar 專案所採用. Libical 以開放原始碼的方式實做了 IETF 的 iCalendar 行事曆與排程協定. (RFC 2445, 2446, 及 2447). 他有 iCal 元件並提供了 C API 來操作這些元件的屬性, 參數以及其子元件. 這個函式庫藉由撰寫一個 XPCOM wrapper 來整合操作其使用介面. 為了增進應用程式的效能, 也將程式從 JavaScript 轉移成 XPCOM 元件.

+

外觀呈現與程式寫作的分離, 修改起來超有彈性. 原本的使用者介面使用了大量的圖形檔案來呈現月和週的顯示. 而在開發人員學習了更多關於 XUL 的細節之後, 改用一些較為精巧的元件來呈現這個使用介面. 這不僅加快了顯示的速度, 也節省了許多記憶體與磁碟存取的資源. 他們幾乎重寫整個顯示月和週的使用者介面, 但對於主程式方面則絲毫不受影響, 不需要做任何的改變.

+

轉移 XUL 的應用程式到其他作業平台, 壓根兒不重要. Calendar 原本是個 Linux 上的應用程式, 也沒想過要轉移到其他平台上面去. 但是當原來的開發者 (OEone Corporation) 將原始程式碼貢獻給 Mozilla 專案的時候, Calendar 就必須要想辦法轉移到 Windows 和 Macintosh 的平台上面去. XUL 應用程式的使用者介面不用做任何平台轉移的修改, 因為他可以幾乎不做任何變更就可以在這兩個新的平台上運作. 相類似地, 因為使用者介面是用 JavaScript 寫成的, 互動操作方面的程式也不需要做修改, 不過, 因為 libical 函式庫是由 C 所寫成的, 所以比較需要做修改, 才能轉移到其他平台上面去使用.

+

很幸運地, 現有的 libical 函式庫已經有 Macintosh 平台上的版本可以用了, 藉由 XPCOM 這個跨平台的基石, 在 Macintosh 上的行事曆在幾天之內就完成移植了. 可是那時候還沒有 Win32 上面的版本可以直接拿來用, 所以開發人員需要把 libical 移植到 Windows 平台上面來. 不到一個星期, 這項工作也完成了, 因此 Mozilla 可以在這三個平台上使用行事曆了: Linux, Macintosh, 和 Windows.

+

XPInstall 對於開發者和使用者都很方便. Calendar 沒有被包含在 Mozilla 1.0 裡面一起發行, 因此沒有被當成標準配備而包含在固定的 nightly release builds 裡面. 對於有能力自行編譯 Mozilla 的開發人員而言, 他們可以自己設定相關的環境變數, 並且自己編譯 Calendar 來使用. 但是對於許多想要試看看 Calendar 的 Mozilla 使用者來說, 編譯這件事實在是遙不可及. 但是藉由 XPInstall, 開發者就可以很輕易地包裝各個版本的 Calendar, 然後只要在網路上點擊一個連結就可以直接進行安裝.

+

結論

+

Mozilla, 那出色的 XUL, 使用與 desktop 應用程式相同且豐富的使用者介面與使用體驗, 為開發跨平台的應用程式帶來令人讚嘆的全心體驗. 對於使用 W3C 標準來設計 web 應用程式的設計師們, 可以輕鬆地利用以往的經驗直接轉換到 desktop 應用程式.

+

在 web 成為散佈應用程式供使用者在不同電腦上使用的標準之前, 這個跨平台的問題需要藉由 客戶端-伺服端 (client-server) 的工具來解決. 但這總是會有版權的問題, 開發人員需要支付一筆可觀的金額來購買執行程式時所需要之函式庫的版權, 也同時被廠商給綁住了. Mozilla 為這些跨平台的工具, 提供了相同價值觀但卻是使用開放原始碼版權的選擇.

+

身為快速成長的跨平台技術, XUL 可以填滿一些有趣的技術空缺, 例如那些透過網路存取分散式物件的 Java J2EE 和 Microsoft .Net. 動態的應用程式搭配可以自由變換的使用者介面表達, 這都是依循標準, 具有擴充性, 而且可以很方便的透過網際網路來散播.

+

XUL 模糊了 desktop 和 web 應用程式的分界, 因為他在這兩個世界裡面都有良好的根基. 將 web 應用程式轉換成 XUL 將獲得許多好處, 可以有高度的介面彈性, 在各種支援的平台上擁有一致的操作環境, 而且仍然可以存取你原有的資源, 例如共享的函式庫, 以及本地端的檔案系統.

+

不論你是需要將現有的網頁應用程式轉移到 desktop 而尋求可以讓你輕鬆移轉到多重平台的技術, 或是將你的勁酷功能整合進瀏覽器, XUL 都會是個很值得的選擇.

+

Reference Material

+
  1. XUL Planet - Samples, Tutorials and Language-References to XUL and XBL http://www.xulplanet.com/
  2. Introduction to a XUL Document, Dan Matejka <danm@netscape.com> http://www.mozilla.org/xpfe/xptoolkit/xulintro.html
  3. XBL - Extensible Binding Language 1.0, David Hyatt <hyatt@netscape.com> http://www.mozilla.org/projects/xbl/xbl.html
  4. XBL - XML Binding Language (W3C Note), David Hyatt < hyatt@netscape.com> http://www.w3.org/TR/xbl/
  5. XUL Overlays, Ian Oeschger <oeschger@netscape.com> and David Hyatt <hyatt@netscape.com> http://www.mozilla.org/xpfe/xptoolkit/overlays.html
  6. XPCOM Part 1: An introduction to XPCOM, Rick Parrish <rfmobile@swbell.net> http://www-106.ibm.com/developerwork.../co-xpcom.html
  7. XPConnect (Scriptable Components), John Bandhauer <jband@netscape.com> http://www.mozilla.org/scriptable/
  8. 為 Mozilla 建立新的套件(Package), Ian Oeschger <oeschger@netscape.com> http://www.mozilla.org/docs/xul/xuln..._packages.html
  9. Mozilla Calendar 專案網站, 由 Mike Potter 所維護 <mikep@oeone.com> http://www.mozilla.org/projects/calendar/
  10. +
+
+

原始文件資訊

+ +

翻譯文件資訊

+ +
+

zh_tw:The Joy of XUL

+ +

{{ languages( { "en": "en/The_Joy_of_XUL", "fr": "fr/Les_joies_de_XUL", "ja": "ja/The_Joy_of_XUL", "pl": "pl/Zabawa_j\u0119zykiem_XUL" } ) }}

diff --git a/files/zh-tw/archive/mozilla/xul/xul_reference/index.html b/files/zh-tw/archive/mozilla/xul/xul_reference/index.html new file mode 100644 index 0000000000..337bb2938a --- /dev/null +++ b/files/zh-tw/archive/mozilla/xul/xul_reference/index.html @@ -0,0 +1,344 @@ +--- +title: XUL 參考文件 +slug: Archive/Mozilla/XUL/XUL_Reference +tags: + - XUL +translation_of: Archive/Mozilla/XUL/XUL_Reference +--- +

« XUL Reference «

+ + + + + + + + + + + + +
全部 XUL 元件 (按字母排序)
+

action
+ arrowscrollbox
+ assign
+ bbox
+ binding
+ bindings
+ box
+ broadcaster
+ broadcasterset
+ button
+ browser
+ checkbox
+ caption
+ colorpicker
+ column
+ columns
+ commandset
+ command
+ conditions
+ content
+ datepicker
+ deck
+ description
+ dialog
+ dialogheader
+ dropmarker
+ editor
+ grid
+ grippy
+ groupbox
+ hbox
+ iframe
+ image
+ key
+ keyset
+ label
+ listbox
+ listcell
+ listcol
+ listcols
+ listhead
+ listheader
+ listitem

+
+

member
+ menu
+ menubar
+ menuitem
+ menulist
+ menupopup
+ menuseparator
+ notification
+ notificationbox
+ observes
+ overlay
+ page
+ panel
+ param
+ popupset
+ preference
+ preferences
+ prefpane
+ prefwindow
+ progressmeter
+ query
+ queryset
+ radio
+ radiogroup
+ resizer
+ richlistbox
+ richlistitem
+ row
+ rows
+ rule
+ scale
+ script
+ scrollbar
+ scrollbox
+ scrollcorner
+ separator
+ spacer
+ spinbuttons
+ splitter
+ stack
+ statusbar

+
+

statusbarpanel
+ stringbundle
+ stringbundleset
+ tab
+ tabbrowser (從 Firefox 3/Gecko 1.9 開始支援)
+ tabbox
+ tabpanel
+ tabpanels
+ tabs
+ template
+ textnode
+ textbox
+ textbox (Firefox autocomplete)
+ textbox (Mozilla autocomplete)
+ timepicker
+ titlebar
+ toolbar
+ toolbarbutton
+ toolbargrippy
+ toolbaritem
+ toolbarpalette
+ toolbarseparator
+ toolbarset
+ toolbarspacer
+ toolbarspring
+ toolbox
+ tooltip
+ tree
+ treecell
+ treechildren
+ treecol
+ treecols
+ treeitem
+ treerow
+ treeseparator
+ triple
+ vbox
+ where
+ window
+ wizard
+ wizardpage

+
+ +

XUL 參考文件

+ +

« XUL Reference «

+ + + + + + + + + + + + +
XUL 元件 (按分類)
+

WINDOWS

+ +

dialog
+ overlay
+ page
+ window
+ wizard
+ wizardpage
+ preference
+ preferences
+ prefpane
+ prefwindow

+ +

WINDOW STRUCTURE

+ +

browser
+ tabbrowser
+ editor
+ iframe
+ titlebar
+ resizer
+ statusbar
+ statusbarpanel
+ dialogheader
+ notification
+ notificationbox

+ +

MENUS AND POPUPS

+ +

menubar
+ menu
+ menuitem
+ menuseparator
+ menupopup
+ panel
+ tooltip
+ popupset

+ +

TOOLBARS

+ +

toolbar
+ toolbarbutton
+ toolbargrippy
+ toolbaritem
+ toolbarpalette
+ toolbarseparator
+ toolbarset
+ toolbarspacer
+ toolbarspring
+ toolbox

+ +

TABS AND GROUPING

+ +

tabbox
+ tabs
+ tab
+ tabpanels
+ tabpanel
+ groupbox
+ caption
+ separator
+ spacer

+
+

CONTROLS

+ +

button
+ checkbox
+ colorpicker
+ datepicker
+ menulist
+ progressmeter
+ radio
+ radiogroup
+ scale
+ splitter
+ textbox
+ textbox (Firefox autocomplete)
+ textbox (Mozilla autocomplete)
+ timepicker

+ +

TEXT AND IMAGES

+ +

description
+ label
+ image

+ +

LISTS

+ +

listbox
+ listitem
+ listcell
+ listcol
+ listcols
+ listhead
+ listheader
+ richlistbox
+ richlistitem

+ +

TREES

+ +

tree
+ treecell
+ treechildren
+ treecol
+ treecols
+ treeitem
+ treerow
+ treeseparator

+ +

 

+
+

LAYOUT

+ +

box
+ hbox
+ vbox
+ bbox
+ deck
+ stack
+ grid
+ columns
+ column
+ rows
+ row
+ scrollbox

+ +

TEMPLATES

+ +

action
+ assign
+ binding
+ bindings
+ conditions
+ content
+ member
+ param
+ query
+ queryset
+ rule
+ template
+ textnode
+ triple
+ where

+ +

SCRIPTING

+ +

script
+ commandset
+ command
+ broadcaster
+ broadcasterset
+ observes
+ key
+ keyset
+ stringbundle
+ stringbundleset

+ +

HELPER ELEMENTS

+ +

arrowscrollbox
+ dropmarker
+ grippy
+ scrollbar
+ scrollcorner
+ spinbuttons

+
+ +

其他 XUL 列表

+ + diff --git a/files/zh-tw/archive/mozilla/xulrunner/index.html b/files/zh-tw/archive/mozilla/xulrunner/index.html new file mode 100644 index 0000000000..f2e5e0b75c --- /dev/null +++ b/files/zh-tw/archive/mozilla/xulrunner/index.html @@ -0,0 +1,88 @@ +--- +title: XULRunner +slug: Archive/Mozilla/XULRunner +tags: + - NeedsTranslation + - NeedsUpdate + - TopicStub + - XUL + - XULRunner +translation_of: Archive/Mozilla/XULRunner +--- +
Getting Started with XULRunner
+A short introduction to XULRunner.
+ +
XULRunner is a Mozilla runtime package that can be used to bootstrap XUL+XPCOM applications that are as rich as Firefox and Thunderbird. It provides mechanisms for installing, upgrading, and uninstalling these applications. XULRunner also provides libxul, a solution which allows the embedding of Mozilla technologies in other projects and products.
+ + + + + + + + +
+

Releases

+ +
+

Until version 41, XULRunner could be downloaded from ftp.mozilla.org.

+ +

Firefox (from version 3) ships with a private XULRunner package, which can run any compatible XULRunner application using the -app switch: firefox -app application.ini is equivalent to xulrunner -app application.ini

+ +

Older builds are also available.

+
+ +

Overview

+ + + +

Documentation

+ +
+
Getting Started with XULRunner
+
Short tutorial on building desktop applications with XULRunner.
+
XUL Tutorial
+
Once you have a working XULRunner application, use the XUL tutorial to expand it into a fantastic XUL application.
+
XULRunner tips
+
A collection of tips for working with XULRunner.
+
Deploying XULRunner
+
An introduction on how to package your application with XULRunner.
+
XULRunner Hall of Fame
+
Tracks all available applications based on XULRunner.
+
Build Documentation
+
Learn how to get the source and build it.
+
Debug Documentation
+
Steps to configure Venkman to debug your App
+
XULRunner Guide
+
A fairly complete, but outdated, introduction and tutorial for XULRunner which collates much of the documentation found here.
+
+ +

View all...

+
+

Community

+ + + + + + + +

See also

+ + +
+ +

 

diff --git a/files/zh-tw/archive/mozilla/xulrunner/xulrunner_tips/index.html b/files/zh-tw/archive/mozilla/xulrunner/xulrunner_tips/index.html new file mode 100644 index 0000000000..c51ae6a0ee --- /dev/null +++ b/files/zh-tw/archive/mozilla/xulrunner/xulrunner_tips/index.html @@ -0,0 +1,213 @@ +--- +title: XULRunner秘技 +slug: Archive/Mozilla/XULRunner/XULRunner_tips +translation_of: Archive/Mozilla/XULRunner/Tips +--- +

XULRunner Frequently Asked Questions. Work in progress.

+

Extension Manager

+

To be able to install any extensions, you first need to enable the Extension Manager in application.ini. XULRunner 1.8.0 does not load extensions from the application directory; only the XULRunner directory and the user profile directory are checked. However, it seems that with XULRunner 1.9 the XULRunner directory is ignored, while the profile and application directories are checked. The following prefs must also be set to make the XPInstall dialog, extension manager, and theme manager work:

+
pref("xpinstall.dialog.confirm", "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul");
+pref("xpinstall.dialog.progress.skin", "chrome://mozapps/content/extensions/extensions.xul?type=themes");
+pref("xpinstall.dialog.progress.chrome", "chrome://mozapps/content/extensions/extensions.xul?type=extensions");
+pref("xpinstall.dialog.progress.type.skin", "Extension:Manager-themes");
+pref("xpinstall.dialog.progress.type.chrome", "Extension:Manager-extensions");
+pref("extensions.update.enabled", true);
+pref("extensions.update.interval", 86400);
+pref("extensions.dss.enabled", false);
+pref("extensions.dss.switchPending", false);
+pref("extensions.ignoreMTimeChanges", false);
+pref("extensions.logging.enabled", false);
+pref("general.skins.selectedSkin", "classic/1.0");
+// NB these point at AMO
+pref("extensions.update.url", "chrome://mozapps/locale/extensions/extensions.properties");
+pref("extensions.getMoreExtensionsURL", "chrome://mozapps/locale/extensions/extensions.properties");
+pref("extensions.getMoreThemesURL", "chrome://mozapps/locale/extensions/extensions.properties");
+
+

If your application is based on Gecko 2.0, you need to register a component through the new component registration because the extension manager uses FUEL, namely Application.restart(), to restart your xulrunner-based application after any change (installation, removal, enabling, disabling) in the extensions' list:

+
    +
  1. copy files fuelApplication.js and fuelApplication.manifest from browser/fuel/src for instance into your components/ directory
  2. +
  3. tweak the line #include ../../../toolkit/components/exthelper/extApplication.js in your copy of fuelApplication.js as needed
  4. +
  5. make sure to declare the FUEL module and the two files in your components/Makefile.in as in browser/fuel/src/Makefile.in
  6. +
  7. rebuild...
  8. +
+

Useful Chrome URLs

+

Most of these require branding.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
WindowURLWindow Type
Extension Managerchrome://mozapps/content/extensions/extensions.xul?type=extensionsExtension:Manager-extensions
Theme Managerchrome://mozapps/content/extensions/extensions.xul?type=themesExtension:Manager-themes
JavaScript Consolechrome://global/content/console.xulglobal:console
about:configchrome://global/content/config.xul  
+

Developer Extensions

+

Venkman

+ +

DOM Inspector

+

To add DOM Inspector 2.0.* to your XULRunner 1.9.0.* application follow these steps:

+ +
content  inspector                       jar:inspector.jar!/content/inspector/ xpcnativewrappers=no
+locale   inspector           en-US       jar:inspector.jar!/locale/en-US/inspector/
+skin     inspector           modern/1.0  jar:inspector.jar!/skin/modern/inspector/
+skin     inspector           classic/1.0 jar:inspector.jar!/skin/classic/inspector/
+
+overlay  chrome://inspector/content/popupOverlay.xul   chrome://inspector/content/viewers/dom/popupOverlay.xul
+overlay  chrome://inspector/content/commandOverlay.xul chrome://inspector/content/viewers/styleRules/commandOverlay.xul
+overlay  chrome://inspector/content/keysetOverlay.xul  chrome://inspector/content/viewers/dom/keysetOverlay.xul
+overlay  chrome://inspector/content/popupOverlay.xul   chrome://inspector/content/viewers/styleRules/popupOverlay.xul
+overlay  chrome://inspector/content/commandOverlay.xul chrome://inspector/content/viewers/dom/commandOverlay.xul
+
+

To launch DOM Inspector in your application, you need to open its main window, with a command like this:

+
window.open("chrome://inspector/content/inspector.xul", "", "chrome");
+
+

Alternatively, the DOM Inspector may also be added as an extension:

+
    +
  1. (if you already have inspector installed for another application you can skip to the next step)
    + Follow the instructions above through "Unzip the package."
  2. +
  3. Create a file in the extensions directory of your application with the same name as the DOM Inspector ID (inspector@mozilla.org) containing one line of text -- the exact path to the root directory of DOM inspector (where the install.rdf is) like this one: +
    /home/username/.mozilla/firefox/numbersandletters/extensions/inspector@mozilla.org/
    +
  4. +
  5. Now create a javascript file with the following code and include it in the main window of your application: +
    function startDOMi()
    +{
    +  // Load the Window DataSource so that browser windows opened subsequent to DOM
    +  // Inspector show up in the DOM Inspector's window list.
    +  var windowDS = Components.classes["@mozilla.org/rdf/datasource;1?name=window-mediator"]
    +                                   .getService(Components.interfaces.nsIWindowDataSource);
    +  var tmpNameSpace = {};
    +  var sl = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
    +    .createInstance(Components.interfaces.mozIJSSubScriptLoader);
    +  sl.loadSubScript("chrome://inspector/content/hooks.js", tmpNameSpace);
    +  tmpNameSpace.inspectDOMDocument(document);
    +}
    +
    +
  6. +
  7. Now create a hook in your application window to start DOM Inspector, like this one: +
    <button label="Start Inpector" oncommand="startDOMi()"/>
    +
  8. +
  9. Start your application and DOM Inspector will be installed.
  10. +
+

Note: I use this method of installing extensions into all of my Mozilla applications. This way I have one directory where I keep all my Mozilla extensions, and each application (Firefox, Thunderbird) simply contains a few small, one line files pointing to the location of the extensions. (I keep them in source control to be sure I can maintain compatibility)

+

Component Viewer

+

Need custom build, first of all. What else?

+

Extension Developer's Extension

+

Extension Developer's Extension is a useful tool, featuring Live XUL Editor and JavaScript Shell. To install the extension into your application you'll need to hack its install.rdf (see above). You'll probably also want to create menuitems that let you open the JS Shell and other tools provided by the extension.

+

Branding

+

Branding is a chrome package containing product-specific information (e.g. the product name, vendor, and logo). Some XULRunner components (in particular, the Extension Manager) depend on branding, in the sense that they expect to find certain strings in chrome://branding/locale/brand.dtd and chrome://branding/locale/brand.properties. In order to satisfy these dependencies, you can save Firefox's brand.dtd/brand.properties to chrome/locale/branding folder, modify them appropriately, and register a locale provider for branding by adding the following line to your chrome manifest:

+
locale branding en-US chrome/locale/branding/
+
+

The location you put the branding files in doesn't matter, as long as you register it appropriately in the manifest. In addition, a branding content package must be registered to include the application logos:

+
content branding chrome/branding/
+
+

3 files should be provided in this folder: about.png, icon48.png and icon64.png. See Firefox for example.

+

Making Windows display correct application name and icon when buttons are grouped

+

By default, the task bar on Windows might group windows belonging to the same process into one button to save space. This button is usually called "xulrunner.exe" and has XULRunner's icon. There are two approaches to display the branding of your application instead:

+ +

Reading command line arguments

+

See Chrome: Command Line. Command line arguments are handled via nsICommandLineHandler, as usual.

+

Preferences needed for file download dialogs

+

To use the unknown-content-type and file-downloads dialogs from a <browser> element, you need to add the following prefs:

+
pref("browser.download.useDownloadDir", true);
+pref("browser.download.folderList", 0);
+pref("browser.download.manager.showAlertOnComplete", true);
+pref("browser.download.manager.showAlertInterval", 2000);
+pref("browser.download.manager.retention", 2);
+pref("browser.download.manager.showWhenStarting", true);
+pref("browser.download.manager.useWindow", true);
+pref("browser.download.manager.closeWhenDone", true);
+pref("browser.download.manager.openDelay", 0);
+pref("browser.download.manager.focusWhenStarting", false);
+pref("browser.download.manager.flashCount", 2);
+//
+pref("alerts.slideIncrement", 1);
+pref("alerts.slideIncrementTime", 10);
+pref("alerts.totalOpenTime", 4000);
+pref("alerts.height", 50);
+
+

If you are missing preferences that a dialog requires, you will get the following errors:

+
Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIPrefBranch.getBoolPref]
+
+Error: dialog has no properties
+Source File: chrome://mozapps/content/downloads/u...ontentType.xul
+Line: 1
+
+

Enabling Password Manager

+

These preferences seem to be the default in Firefox, however, they are missing in XULRunner. Without these settings Password Manager will not store login details.

+
pref("signon.rememberSignons", true);
+pref("signon.expireMasterPassword", false);
+pref("signon.SignonFileName", "signons.txt");
+
+

You also need to get an instance of the login manager service, which internally initializes the system:

+
Components.classes["@mozilla.org/login-manager;1"].getService(Components.interfaces.nsILoginManager);
+
+

Using Firefox 3 to run XULRunner applications

+

Firefox 3 contains the XULRunner runtime. It has an -app command-line switch to run a specified XUL application instead of starting the browser.

+

On Windows:

+
  firefox.exe -app path\to\application.ini
+
+

On Linux:

+
  firefox -app path/to/application.ini
+

On the Mac:

+
  /Applications/Firefox.app/Contents/MacOS/firefox-bin -app /path/to/application.ini
+
+

Note that at least on the Mac, you need to use a full path. Partial paths don't seem to work.

+

Troubleshooting

+

Window title missing

+

If the title of your XUL <window> is blank, even though you specified a title attribute, make sure the extension on your XUL file is .xul rather than .xml

+

Default Theme

+

To create a default theme you need to create a folder in the extensions folder with an install.rdf in it.  As of Oct. 2008, the folder needs to have the same name as the one in Firefox 3.0. 

+

\MyApp\Extensions\{972ce4c6-7e08-4474-a285-3208198ce6fd}\install.rdf

+

It should also have an <em:internalName>classic/1.0</em:internalName> as that is the default theme in Firefox.

+

{{ languages( { "ja": "ja/XULRunner_tips", "fr": "fr/Astuces_XULRunner" } ) }}

diff --git a/files/zh-tw/archive/themes/index.html b/files/zh-tw/archive/themes/index.html new file mode 100644 index 0000000000..a440be2e7a --- /dev/null +++ b/files/zh-tw/archive/themes/index.html @@ -0,0 +1,11 @@ +--- +title: Themes +slug: Archive/Themes +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive/Themes +--- +

Archived theme documentation.

+ +

{{Listsubpages("/en-US/docs/Archive/Themes", 10)}}

diff --git a/files/zh-tw/archive/web/e4x/index.html b/files/zh-tw/archive/web/e4x/index.html new file mode 100644 index 0000000000..7ba42421ff --- /dev/null +++ b/files/zh-tw/archive/web/e4x/index.html @@ -0,0 +1,6 @@ +--- +title: E4X +slug: Archive/Web/E4X +translation_of: Archive/Web/E4X +--- +

This page was auto-generated because a user created a sub-page to this page.

diff --git a/files/zh-tw/archive/web/e4x/processing_xml_with_e4x/index.html b/files/zh-tw/archive/web/e4x/processing_xml_with_e4x/index.html new file mode 100644 index 0000000000..3c8b4cb442 --- /dev/null +++ b/files/zh-tw/archive/web/e4x/processing_xml_with_e4x/index.html @@ -0,0 +1,229 @@ +--- +title: 使用 E4X 處理 XML +slug: Archive/Web/E4X/Processing_XML_with_E4X +translation_of: Archive/Web/E4X/Processing_XML_with_E4X +--- +

{{Warning("E4X 已廢棄不用。 It's been disabled by default for chrome in Firefox 17, and completly removed in Firefox 21. 請使用 DOMParser/DOMSerializer 或 a non-native JXON algorithm 替代。")}}

+

使用 E4X 處理 XML

+

JavaScript 在 1.6 版本中首次引入,E4X 引入原生的 XML 物件以供 JavaScript 語言使用,並新增用來在 JavaScript 的代碼中嵌入照字面表達的 XML 文件的語法。

+

E4X 的完整定義可以在 Ecma-357 規範 中找到。本章提供實踐中的語言概要;但這並不是全面的參考資料。

+

相容性的問題

+

在主要的瀏覽器支援 <script> 元素以前,對於嵌入到頁面裡的 JavaScript 存有一種常見的做法,就是使用 HTML 的註解標籤將其包夾,避免瀏覽器直接把 <script> 裡的 JavaScript 代碼顯示在使用者眼前。如今已無須這麼做,不過仍殘存在部分遺留下來的代碼中。為了向後相容的需要,E4X 預設會忽略註解和 CDATA 區段。你可以給你的 <script> 標籤加上 e4x=1 參數以解除這項限制︰

+
<script type="text/javascript;e4x=1">
+...
+</script>
+
+

XML 物件的建立

+

E4X 提供兩種建立 XML 物件的方式。第一種是傳入字串給 XML 建構子︰

+
 var languages = new XML('<languages type="dynamic"><lang>JavaScript</lang><lang>Python</lang></languages>');
+
+

第二種是直接在你的 Script 中嵌入 XML︰

+
 var languages = <languages type="dynamic">
+   <lang>JavaScript</lang>
+   <lang>Python</lang>
+ </languages>;
+
+

在這兩種情況裡,產生都會是 E4X XML 物件,他提供了方便的語法用以存取並更新其內夾藏著的資料。

+

XML 物件在外觀上和行為上都和普通的 JavaScript 物件很類似,但有兩件事並不相同。E4X 引入的新語法只能用在 E4X XML 物件上。雖然新語法被設計成對 JavaScript 設計者而言較熟悉的形式,但 E4X 並不提供從 XML 到原生 JavaScript 物件的完整對應;只是看起來很像而已。

+

可以把變數加入到 XML 的字面中用來建立元素的名稱(或是內容)。

+
var h = 'html';
+var text = "Here's some text";
+var doc = <{h}><body>{text}</body></{h}>;
+alert(doc.toXMLString());
+// 產生的是
+<html>
+  <body>Here's some text</body>
+</html>
+
+

屬性的運用

+

當你需要動態的建立標記的時候,XML 字面語法明顯更勝 XML 建構子。使用 E4X 可輕易的在標記中嵌入動態值。只需使用花括弧 ({}) 包夾要建立的屬性值,並省略一般會加上的引號標記,變數和表達式即可用於建立屬性值,如同下例所示︰

+
 var a = 2;
+ var b = <foo bar={a}>"hi"</foo>;
+
+

開始執行時,變數的值會被求出,並自動在適當的位置加上引號。前面的例子產生的 XML 物件看起來就像這樣︰<foo bar="2">"hi"</foo>

+

在屬性的替換方面,雙引號會被跳脫成 &quot;,單引號則按平常方式處理。

+
var b = 'He said "Don\'t go there."';
+var el = <foo a={b}/>;
+alert(el.toXMLString());
+// 產生︰<foo a="He said &quot;Don't go there.&quot;"/>
+
+

小於和 & 符號也會被跳脫成各自的等價實體。由於大於符號不會被跳脫,因此如果包含了 CDATA 結束序列 (]]>),就有可能產生 XML 錯誤。

+

通常不會直接在字面(或變數)的屬性內容之中作修改(例如,bar="a{var1}{var2}")。如果有必須使用 JavaScript 表達式計算變數來替代的內容的話(例如,bar={'a'+var1+var2}),在元素字面之前先定義新的變數,在變數中包含完整的修改內容,然後在字面中含入這個變數,或在字面之後取回屬性並將其修改(見下)。

+

可如同屬性值一般的修改屬性的名稱︰

+
var a = 'att';
+var b = <b {a}='value'/>;
+alert(b);
+// Gives:
+<b att="value"/>
+
+
+

…但之後就不能修改表達式(例如,<b {a}>)。

+

執行上面的例子之後,參考 XML 物件的語言變數與 XML 文件中的 <languages> 結點一致。這個結點只有一個屬性︰type,這個屬性可用各種方式來存取並更新︰

+
 alert(languages.@type); // 警報 "dynamic"
+ languages.@type = "agile";
+ alert(languages.@type); // 警報 "agile"
+
+
 alert(languages.toString());
+ /* 警報:
+   <languages type="agile"><lang>JavaScript</lang><lang>Python</lang></languages>
+ */
+
+

注意,如果想要把取回的屬性與其他的字串作比較,就有必要先把屬性作轉換,即使屬性有可能會在其他地方被轉換成字串(例如插入到文字框中)。

+
if (languages.@type.toString() === 'agile') {
+ ...
+}
+
+

XML 物件的運用

+

XML 物件提供一系列的方法用來查閱並更新其中的內容。這類物件亦支援 JavaScript 的點 (.) 和 [] 符號,但不是用來存取物件的屬性,E4X 覆蓋了這些運算子,改用來存取元素的子結點︰

+
var person = <person>
+  <name>Bob Smith</name>
+  <likes>
+    <os>Linux</os>
+    <browser>Firefox</browser>
+    <language>JavaScript</language>
+    <language>Python</language>
+  </likes>
+</person>;
+
+alert(person.name); // Bob Smith
+alert(person['name']); // Bob Smith
+alert(person.likes.browser); // Firefox
+alert(person['likes'].browser); // Firefox
+
+

如果你使用多於一個以上的元素來存取的話,你會得到 XMLList

+
alert(person.likes.language.length()); // 2
+
+

和 DOM 一樣,* 可以用來存取所有的子結點︰

+
alert(person.likes.*.length()); // 4
+
+

. 運算子會直接存取指定結點的子結點,.. 運算子則會存取所有的子結點,不論嵌入的有多深︰

+
alert(person..*.length()); // 11
+
+

length() 方法在此返回 11,因為元素結點和文字結點兩者都被包含在 XMLList 的結果中。

+

用來表示 XML 元素的物件提供一系列實用的方法,部分方法的解說見下︰TODO: Add all of the methods to the JavaScript reference, link from here

+
alert(person.name.text()) // Bob Smith
+
+var xml = person.name.toXMLString(); // 內含 XML 的字串
+
+var personCopy = person.copy(); // XML 物件的深層複製
+
+var child = person.child(1); // 第二個子結點;目前是 <likes> 元素
+
+

XMLLists 的運用

+

除了 XML 物件以外,E4X 也引入了 XMLList 物件。XMLList 是用來表示附有編號的 XML 物件的集合;例如,元素的列表。接續上面的例子,我們可以在頁面上存取 XMLList<lang> 元素如下︰

+
 var langs = languages.lang;
+
+

XMLList 提供 length() 方法,可用來查出內含元素的數目︰

+
 alert(languages.lang.length());
+
+

注意,有別於 JavaScript 陣列的 length 屬性,這個 length 是方法,不是屬性,而且必須使用 length() 來呼叫。

+

我們可以迭代所有相配的元素,就像這樣︰

+
 for (var i = 0; i < languages.lang.length(); i++) {
+     alert(languages.lang[i].toString());
+ }
+
+

在此我們使用同一個語法存取陣列中的已編號項。雖然這部分很類似普通的陣列,但 XMLList 並不支援 Array 的方法,如 forEach,且陣列的通用功能,如 Array.forEach() 也不相容於 XMLList 物件。

+

我們也可以使用在 JavaScript 1.6 中所引入的 for each...in 語法,他已支援 E4X 的部分︰

+
 for each (var lang in languages.lang) {
+     alert(lang);
+ }
+
+

for each...in 也可以用在普通的 JavaScript 物件,迭代出內含在物件中的值(不是鍵)。如同 for...in非常不建議 和陣列一起使用。

+

可以使用下面的 XML 字面語法來建立 XMLList,而無須建立格式正確的 XML 文件︰

+
 var xmllist = <>
+   <lang>JavaScript</lang>
+   <lang>Python</lang>
+ </>;
+
+

+= 運算子可用來把新的元素附加到文件中的 XMLList

+
 languages.lang += <lang>Ruby</lang>;
+
+

注意,有別於由普通的 DOM 方法所返回的結點列表,XMLList 只是靜態的,而且不會自動更新以反映在 DOM 中的改變。如果你在既有的 XML 物件底下建立 XMLList 作為子集,XMLList 並不會反映 XML 物件的改變;你需要重新建立 XMLList 以取得最近的更新︰

+
 var languages = <languages>
+   <lang>JavaScript</lang>
+   <lang>Python</lang>
+ </languages>;
+
+ var lang = languages.lang;
+ alert(lang.length()); // 警報 2
+
+ languages.lang += <lang>Ruby</lang>;
+ alert(lang.length()); // 仍舊警報 2
+
+ lang = languages.lang; // 重新建立 XMLList
+ alert(lang.length()); // 警報 3
+
+

搜尋和過濾

+

E4X 提供特殊的運算子用來在通過指定條件的文件內部選取結點。這種過濾動作是由括弧裡面的表達式所指定的︰

+
var html = <html>
+  <p id="p1">First paragraph</p>
+  <p id="p2">Second paragraph</p>
+</html>;
+
+alert(html.p.(@id == "p1")); // 警報 "First paragraph"
+
+

在表達式前面比對路徑的結點(在本例中即 p 元素)會在表達式求值之前先加上作用域的限縮。就如同已經用 with 語法 指定了一樣。

+

因此,過濾器也可以依據在目前元素中內含的單一結點的值來執行︰

+
var people = <people>
+  <person>
+    <name>Bob</name>
+    <age>32</age>
+  </person>
+  <person>
+    <name>Joe</name>
+    <age>46</age>
+  </person>
+</people>;
+
+alert(people.person.(name == "Joe").age); // 警報 46
+
+

也可以使用 JavaScript 函數當作過濾器的表達式︰

+
function over40(i) {
+    return i > 40;
+}
+
+alert(people.person.(over40(parseInt(age))).name); // 警報 Joe
+
+

命名空間的處理

+

E4X 也全面考慮到命名空間。任何代表結點或屬性的 XML 物件都提供了可返回 QName 物件的 name() 方法,使加上命名空間的元素的查詢更為容易。

+

預設

+
default xml namespace = "http://www.w3.org/1999/xhtml";
+// 目前還沒有必要在 HTML 標記裡指定命名空間
+var xhtml = <html><head><title></title></head><body>
+            <p>text</p></body></html>;
+alert(xhtml.head); // 目前還沒有必要在此處的子元素中指定命名空間
+

非預設

+
var xhtml = <html xmlns="http://www.w3.org/1999/xhtml">
+	<head>
+		<title>Embedded SVG demo</title>
+	</head>
+	<body>
+		<h1>Embedded SVG demo</h1>
+		<svg xmlns="http://www.w3.org/2000/svg"
+			viewBox="0 0 100 100">
+			<circle cx="50"
+				cy="50"
+				r="20"
+				stroke="orange"
+				stroke-width="2px"
+				fill="yellow" />
+		</svg>
+	</body>
+</html>;
+
+alert(xhtml.name().localName); // 警報 "html"
+alert(xhtml.name().uri); // 警報 "http://www.w3.org/1999/xhtml"
+
+

若要存取非預設命名空間內部的元素,首先建立 Namespace 物件把特定的命名空間的 URI 加以封裝︰

+
var svgns = new Namespace('http://www.w3.org/2000/svg');
+
+

目前可以在 E4X 中使用 namespace::localName 代替一般的元素指定子來作查詢︰

+
var svg = xhtml..svgns::svg;
+alert(svg); // 顯示文件中的 <svg> 部分
+
+

參閱

+ +

{{ languages( { "en": "en/Core_JavaScript_1.5_Guide/Processing_XML_with_E4X", "zh-cn": "cn/Core_JavaScript_1.5_Guide/Processing_XML_with_E4X", "fr": "fr/Guide_JavaScript_1.5/Traitement_de_XML_avec_E4X", "ja": "ja/Core_JavaScript_1.5_Guide/Processing_XML_with_E4X" } ) }}

diff --git a/files/zh-tw/archive/web/index.html b/files/zh-tw/archive/web/index.html new file mode 100644 index 0000000000..6f60d315ff --- /dev/null +++ b/files/zh-tw/archive/web/index.html @@ -0,0 +1,12 @@ +--- +title: Archived open Web documentation +slug: Archive/Web +tags: + - Archived + - NeedsTranslation + - TopicStub + - Web +translation_of: Archive/Web +--- +

The documentation listed below is archived, obsolete material about open Web topics.

+

{{SubpagesWithSummaries}}

diff --git a/files/zh-tw/archive/web_standards/index.html b/files/zh-tw/archive/web_standards/index.html new file mode 100644 index 0000000000..1fed929d5f --- /dev/null +++ b/files/zh-tw/archive/web_standards/index.html @@ -0,0 +1,76 @@ +--- +title: Web Standards +slug: Archive/Web_Standards +translation_of: Archive/Web_Standards +--- +
In progress. Web standards are carefully designed to deliver the greatest benefits to the greatest number of web users while ensuring the long-term viability of any document published on the Web. Designing and building with these standards simplifies and lowers the cost of production, while delivering sites that are accessible to more people and more types of Internet devices. Sites developed along these lines will continue to function correctly as traditional desktop browsers evolve, and as new Internet devices come to market. {{ Ref(1) }}
+ + + + + + + + +
+

Documentation

+ +
+
Migrate apps from Internet Explorer to Mozilla
+
Ever have trouble getting your Internet Explorer-specific Web applications to work with Mozilla? This article covers common issues associated with migrating applications to the open source Mozilla-based browser.
+
Using Web Standards in your Web Pages
+
This article provides an overview of the process for upgrading the content of your web pages to conform to the W3C web standards.
+
Choosing Standards Compliance Over Proprietary Practices
+
In the development world, there is a need for standards because applications are designed across multiple development groups.
+
The Business Benefits of Web Standards
+
This article discusses how adhering to web standards, and leaving behind proprietary markup and technologies, can contribute to a company's business goals.
+
+ +

View All...

+
+

Community

+ +
    +
  • View Mozilla forums...
  • +
+ +

{{ DiscussionList("dev-web-development", "mozilla.dev.web-development") }}

+ + + +

Tools

+ + + +

View All...

+ +

Examples

+ + + + + +
+
CSS, DHTML, HTML, Web Development, XHTML, XML
+
+
+ +
+

{{ endnote(1) }} - The Web Standards Project

+ +

{{ languages( { "ca": "ca/Est\u00e0ndards_web", "de": "de/Web-Standards", "es": "es/Est\u00e1ndares_Web", "fr": "fr/Standards_du_Web", "ja": "ja/Web_Standards", "ko": "ko/Web_Standards", "pl": "pl/Standardy_WWW", "pt": "pt/Normas_Web" } ) }}

diff --git a/files/zh-tw/archive/web_standards/rdf_in_fifty_words_or_less/index.html b/files/zh-tw/archive/web_standards/rdf_in_fifty_words_or_less/index.html new file mode 100644 index 0000000000..c9d003f911 --- /dev/null +++ b/files/zh-tw/archive/web_standards/rdf_in_fifty_words_or_less/index.html @@ -0,0 +1,85 @@ +--- +title: 50 字解說 RDF +slug: Archive/Web_Standards/RDF_in_Fifty_Words_or_Less +translation_of: Archive/Web_Standards/RDF_in_Fifty_Words_or_Less +--- +

 

+ +

好吧,可能比 50 字還要多一點,但重點十分簡單(並且已經幫諸位只想看重點的成功人士標為粗體)。資源描述架構,或稱為「RDF」(Resource Description Framework),其實是指兩件事。

+ +
首先,RDF 是種圖像式模型,用以描述網路上的資源(如網頁內容、電子郵件訊息等),以及這些資源之間的關係。
+ +

不過這到底是什麼意思?對 Mozilla 開發者來說,這代表 RDF 資料模型(就是那個「圖像」)可以用來組織、整合網路上的資源。

+ +

舉「書籤」為例。目前大部分的網頁瀏覽器讓你將書籤歸入資料夾的樹狀結構,每個書籤則指向一個網頁的 URI(通用資源定義符,Uniform Resource Identifier)。

+ +

但網頁只是眾多網路資源的其中一項,其他還有如電子郵件內容、新聞群組的訊息(或整個新聞群組)、搜尋引擎的探索結果... 等等。基本上,若說這些其他資源不能存入書籤、與其他書籤擺在一起以資料夾整理,也沒什麼道理。甚至還應該可以建立一個「智慧型」資料夾,點選後就動態找出符合某些條件的內容。

+ +

一個「書籤」尚且應有眾多相關的屬性:您可能想自己定義一些書籤的「分類規則」、依據麥金塔的「hot」、「warm」、「cool」色彩標準上色;又或許,您想標示某個書籤與另一個書籤有關,還可能想將其同時放入多個不同的資料夾。

+ +

RDF 圖像提供絕佳資料模型,可以建立上述的「通用」書籤服務:這種圖像可以指向任意資源、亦能以幾乎任何想得到的方式組織。

+ +

別那麼快下結論,還有...

+ +
第二,RDF 是種串接式的語法。這種語法讓圖像式的資料模型可以透過「代理人」溝通。
+ +

這又是什麼意思?基本上,這代表 RDF 資料模型可以跨越網路來交流,其圖像內容還可以在收到遠端服務的資訊時動態變更。

+ +

我們再回到書籤的例子。就說我有個書籤的「資料夾」,其實指向我的電子郵件收件匣:一旦點選這個資料夾,哇喔,所有昨晚收下來的郵件都列出來了!

+ +

不過這是怎麼辦到的?其實這個「收件資料夾」指向一個網路資源,此資源內含更多的 RDF 來拓展資源版圖。此「網路資源」為一個指向 CGI 的 URI(像是 http://www.mozilla.org/smart-mail/get-mail.cgi?user=waterson&folder=inbox),此 CGI 會建立串接 RDF、就像是把一張圖片以 XML 方式表達一樣:

+ +
 <rdf:RDF
+     xmlns:rdf="http://www.w3.org/TR/WD-rdf-syntax#"
+     xmlns:sm="http://www.mozilla.org/smart-mail/schema#">
+   <rdf:Description
+     about="http://www.mozilla.org/smart-mail/get-mail.cgi?user=waterson&folder=inbox">
+     <sm:message id="4025293">
+        <sm:recipient>
+          Chris Waterson "waterson@netscape.com"
+        </sm:recipient>
+        <sm:sender>
+          Aunt Helga "helga@netcenter.net"
+        </sm:sender>
+        <sm:received-by>x-wing.mcom.com</sm:received-by>
+        <sm:subject>Great recipe for Yam Soup!</sm:subject>
+        <sm:body>
+          http://www.mozilla.org/smart-mail/get-body.cgi?id=4025293
+        </sm:body>
+     </sm:message>
+     <sm:message id="4025294">
+        <sm:recipient>
+          Chris Waterson "waterson@netscape.com"
+        </sm:recipient>
+        <sm:sender>
+          Sarah Waterson "waterson.2@postbox.acs.ohio-state.edu"
+        </sm:sender>
+        <sm:received-by>x-wing.mcom.com</sm:received-by>
+        <sm:subject>We won our ultimate game</sm:subject>
+        <sm:body>
+          http://www.mozilla.org/smart-mail/get-body.cgi?id=4025294
+        </sm:body>
+     </sm:message>
+   </rdf:Description>
+ </rdf:RDF>
+
+ +

收到上面這堆怪物之後,RDF 引擎會將 RDF 資料放在圖像中的適當位置。負責實際繪出書籤介面的 Tree 控制項此時將收到通知,知道應該繪出 Aunt Helga 關於 Yam Soup 之信件的一些圖示。

+ +

其實,這正是 SmartMail 運作的原理。

+ +

聯絡: Chris Waterson (waterson@netscape.com)

+ +
+

原始文件資訊

+ + +
+ +

Interwiki Language Links

+ +

{{ languages( { "fr": "fr/RDF_en_cinquante_mots", "it": "it/RDF_in_cinquanta_parole_o_meno", "ja": "ja/RDF_in_Fifty_Words_or_Less", "ko": "ko/RDF_in_Fifty_Words_or_Less", "zh-TW": "zh_tw/50_字解說_RDF" } ) }}

diff --git a/files/zh-tw/code_snippets/index.html b/files/zh-tw/code_snippets/index.html new file mode 100644 index 0000000000..095e91dae2 --- /dev/null +++ b/files/zh-tw/code_snippets/index.html @@ -0,0 +1,190 @@ +--- +title: Code snippets +slug: Code_snippets +tags: + - Add-ons + - Code snippets + - Extensions + - NeedsTranslation + - TopicStub +translation_of: Archive/Add-ons/Code_snippets +--- +

This is a quick list of useful code snippets (small code samples) available for developers of extensions for the various Mozilla applications. Many of these samples can also be used in XULRunner applications, as well as in actual Mozilla code itself.

+

These examples demonstrate how to accomplish basic tasks that might not be immediately obvious.

+

General

+
+
+ Examples and demos from MDN articles
+
+ A collection of examples and demos from articles.
+
+ Windows code
+
+ Opening and manipulating windows
+
+ Toolbar
+
+ Toolbar related code
+
+ Sidebar
+
+ Sidebar related code
+
+ XML
+
+ Code used to parse, write, manipulate, etc. XML
+
+ File I/O
+
+ Code used to read, write and process files
+
+ Drag & Drop
+
+ Code used to setup and handle drag and drop events
+
+ Dialogs
+
+ Code used to display and process dialog boxes
+
+ Alerts and Notifications
+
+ Modal and non-modal ways to notify users
+
+ Preferences
+
+ Code used to read, write, and modify preferences
+
+ JS XPCOM
+
+ Code used to define and call XPCOM components in JavaScript
+
+ Running applications
+
+ Code used to run other applications
+
+ <canvas> related
+
+ WHAT WG Canvas-related code
+
+ Signing a XPI
+
+ How to sign an XPI with PKI
+
+ Threads
+
+ Performing background operations and delaying execution while background operations complete
+
+ Miscellaneous
+
+ Miscellaneous useful code fragments
+
+ HTML to DOM
+
+ Using a hidden browser element to parse HTML to a window's DOM
+
+

JavaScript libraries

+

Here are some JavaScript libraries that may come in handy.

+
+
+ StringView
+
+ A library that implements a StringView view for JavaScript typed arrays. This lets you access data in typed arrays using C-like string functions.
+
+

Browser-oriented code

+
+
+ Tabbed browser code (Firefox/SeaMonkey)
+
+ Basic operations, such as page loading, with the tabbed browser, which is the heart of Mozilla's browser applications
+
+ Cookies
+
+ Reading, writing, modifying, and removing cookies
+
+ Page Loading
+
+ Code used to load pages, reload pages, and listen for page loads
+
+ Interaction between privileged and non-privileged code
+
+ How to communicate from extensions to websites and vice-versa.
+
+ Downloading Files
+
+ Code to download files, images, and to monitor download progress
+
+ Password Manager
+
+ Code used to read and write passwords to/from the integrated password manager
+
+ Bookmarks
+
+ Code used to read and write bookmarks
+
+ JavaScript Debugger Service
+
+ Code used to interact with the JavaScript Debugger Service
+
+

SVG

+
+
+ General
+
+ General information and utilities
+
+ SVG Animation
+
+ Animate SVG using JavaScript and SMIL
+
+ SVG Interacting with Script
+
+ Using JavaScript and DOM events to create interactive SVG
+
+ Embedding SVG in HTML and XUL
+
+ Using SVG to enhance HTML or XUL based markup
+
+

XUL Widgets

+
+
+ HTML in XUL for Rich Tooltips
+
+ Dynamically embed HTML into a XUL element to attain markup in a tooltip
+
+ Label and description
+
+ Special uses and line breaking examples
+
+ Tree
+
+ Setup and manipulation of trees using XUL and JS
+
+ Scrollbar
+
+ Changing style of scrollbars. Applies to scrollbars in browser and iframe as well.
+
+ Autocomplete
+
+ Code used to enable form autocomplete in a browser
+
+ Boxes
+
+ Tips and tricks when using boxes as containers
+
+ Tabbox
+
+ Removing and manipulating tabs in a tabbox
+
+

Windows-specific

+
+
+ Finding Window Handles (HWND) (Firefox)
+
+ How to use Windows API calls to find various kinds of Mozilla window handles. Window handles can be used for IPC and Accessibility purposes.
+
+ Using the Windows Registry with XPCOM
+
+ How to read, write, modify, delete, enumerate, and watch registry keys and values.
+
+ +

The content at MozillaZine Example Code is slowly being moved here, but you can still find useful examples there for now.

diff --git a/files/zh-tw/code_snippets/tabbed_browser/index.html b/files/zh-tw/code_snippets/tabbed_browser/index.html new file mode 100644 index 0000000000..b8a3b14fff --- /dev/null +++ b/files/zh-tw/code_snippets/tabbed_browser/index.html @@ -0,0 +1,398 @@ +--- +title: Tabbed browser +slug: Code_snippets/Tabbed_browser +translation_of: Archive/Add-ons/Tabbed_browser +--- +

您將在此尋獲協助您運用Firefox的多頁籤瀏覽器的一些程式碼片段,註解將提示您應該在什麼地方插入您自己的程式碼。

+

 

+

一般來說這些片段會包含其初始化的程式碼。基本假設是這些程式碼片段將於瀏覽器視窗內容中執行,最佳做法是以 load listener 來運行。若您要從瀏覽器視窗以外的地方來操作頁籤,您必須先取得任意一個瀏覽器視窗,詳見: Working with windows in chrome code

+

多世界詮釋算什麼,多 browser 詮釋才夠暈

+

"browser" 有很多意思。把整個 Firefox 稱為 browser 再為理所當然不過,但是 Firefox 有頁籤,每個頁籤本身也都是 browser。無論是一般所指的 web page browser,還是 XUL 裡的 {{ XULElem("browser") }} element,通通叫做 browser。在本文件和其它某些 Firefox 文件裡, browser 還有另一個意思,就是 Firefox XUL window 裡的 tabbrowser element。

+

如何存取 browser

+

從主視窗

+

從 global ChromeWindow 中運行的程式碼,例如套疊 (overlay) 於 browser.xul 的 extension,可以用全域變數 gBrowser 來存取 {{ XULElem("tabbrowser") }} element

+
// gBrowser 只存在於 browser window (browser.xul)
+gBrowser.addTab(...);
+
+

如果 gBrowser 未定義,代表您的程式碼要不是太早運行,就是並非從 browser window 中運行。在 browser window 還沒完全載入之前 gBrowser 根本還不存在。若要在視窗一打開時存取 gBrowser ,請在 event listener 中使用它,並 listen 'load' 事件。

+

若您的程式是 sidebar 或 dialog 而無法存取主視窗,那就要先獲取主視窗才能使用 gBrowser ,詳見: Working with windows in chrome code.

+

從腮巴 (sidebar) 存取 browser

+

若您的附加元件基本上是一坨屎 (sidebar) ,那就:

+
var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                       .getInterface(Components.interfaces.nsIWebNavigation)
+                       .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
+                       .rootTreeItem
+                       .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                       .getInterface(Components.interfaces.nsIDOMWindow);
+
+mainWindow.gBrowser.addTab(...);
+
+

從呆鴨肉 (dialog) 存取 browser

+

若您的程式基本上運行於某種呆鴨肉 (dialog) ,而且是從 browser window 直接甩出來的精選優質肥美呆鴨肉,那就:

+
window.opener.gBrowser.addTab(...);
+
+

如果 window.opener 搞不定,那就用以下的程式碼先取得最近打開的 browser window :

+
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+                   .getService(Components.interfaces.nsIWindowMediator);
+
+var mainWindow = wm.getMostRecentWindow("navigator:browser");
+mainWindow.gBrowser.addTab(...);
+

如何以 URL 開啟新 tab

+
// Add tab
+gBrowser.addTab("http://www.google.com/");
+
+// Add tab, then make active
+gBrowser.selectedTab = gBrowser.addTab("http://www.google.com/");
+
+

操作新頁籤的內容

+

若要操作新開啟頁籤的內容,就要等它載入完。

+
// 醬子不行啊 .. 人家還沒準備好
+var newTabBrowser = gBrowser.getBrowserForTab(gBrowser.addTab("http://www.google.com/"));
+alert(newTabBrowser.contentDocument.body.innerHTML);
+
+// BETTER WAY
+var newTabBrowser = gBrowser.getBrowserForTab(gBrowser.addTab("http://www.google.com/"));
+newTabBrowser.addEventListener("load", function () {
+  newTabBrowser.contentDocument.body.innerHTML = "<div>hello world</div>";
+}, true);
+
+

onLoad handler 中的 event target 是個 'tab' XUL element。 關於 getBrowserForTab(),參見: tabbrowser

+

如何精準地在 window 或 tab 開啟 URL

+

chrome://browser/content/utilityOverlay.js 中有許多方法例如 openUILinkInopenUILink, 讓 tab 開啟 URL 變簡單。

+
+
+ openUILinkIn( url, where, allowThirdPartyFixup, postData, referrerUrl )
+
+ where 可以是: +
    +
  • "current" 目前 tab (要是 browser window 連個鬼都沒的話就開新視窗)
  • +
  • "tab" 新的 tab (一樣,鬼都沒有就開新視窗)
  • +
  • "tabshifted" 也是新 tab,但若預設選定新 tab 則會在背景開啟,若預設相反則行為相反 (這就是為什麼叫 shifted)
  • +
  • "window" 新視窗
  • +
  • "save" 直接存檔 (不會提示檔名喔!)
  • +
+
+
+ openUILink( url, e, ignoreButton, ignoreAlt, allowKeywordFixup, postData, referrerUrl )
+
+  
+
+

下列程式碼將開啟 URL 並依照什麼鬼滑鼠鍵和什麼鬼熱鍵(例:Ctrl)被按下來開新視窗、開新 tab 或是開在現有的 tab 。這是用於 {{ XULElem("menuitem") }} 的程式碼,而在其它的 XUL elements 上也沒什麼兩樣,但只限 browser.xul 的 overlay 。

+

XUL:

+
<menuitem oncommand="myExtension.foo(event)" onclick="checkForMiddleClick(this, event)" label="Click me"/>
+
+

JS:

+
var myExtension = {
+  foo: function(event) {
+    openUILink("http://www.example.com", event, false, true);
+  }
+}
+

如何優柔寡斷地開啟 URL

+
var gSessionStore = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+
+// 生一個新 tab 但是沒載入內容
+var url = "https://developer.mozilla.org";
+var tab = gBrowser.addTab(null);
+gSessionStore.setTabState(tab,
+  '{\
+    "entries":[\
+      {\
+        "url":"' + url + '",\
+        "title":"' + url + '"\
+      }\
+    ],\
+    "lastAccessed":0,\
+    "index":1,\
+    "hidden":false,\
+    "attributes":{},\
+    "image":null\
+  }'
+);
+
+

tab 再利用

+

與其每次需要就再開新的 tab,若已有 tab 開啟了欲前往的 URL,最佳做法就是試著重用它。遵循這個做法可使您的附加元件開啟最少的 tab。

+
依 URL/URI 來重用
+

附加元件常見的一項功能是,當 user 按下某個按鈕或連結就從browser window 中將 user 導向至某個 chrome:// 開頭的 URI (像是 help 或 about 這種) 或者一個外部的 HTML (on-line http(s)://) 。接下來的程式碼展示如何重用已顯示所欲前往 URL/URI 的頁籤,如果沒有現存的,則會開個新的。

+
function openAndReuseOneTabPerURL(url) {
+  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+                     .getService(Components.interfaces.nsIWindowMediator);
+  var browserEnumerator = wm.getEnumerator("navigator:browser");
+
+  // Check each browser instance for our URL
+  var found = false;
+  while (!found && browserEnumerator.hasMoreElements()) {
+    var browserWin = browserEnumerator.getNext();
+    var tabbrowser = browserWin.gBrowser;
+
+    // Check each tab of this browser instance
+    var numTabs = tabbrowser.browsers.length;
+    for (var index = 0; index < numTabs; index++) {
+      var currentBrowser = tabbrowser.getBrowserAtIndex(index);
+      if (url == currentBrowser.currentURI.spec) {
+
+        // The URL is already opened. Select this tab.
+        tabbrowser.selectedTab = tabbrowser.tabContainer.childNodes[index];
+
+        // Focus *this* browser-window
+        browserWin.focus();
+
+        found = true;
+        break;
+      }
+    }
+  }
+
+  // Our URL isn't open. Open it now.
+  if (!found) {
+    var recentWindow = wm.getMostRecentWindow("navigator:browser");
+    if (recentWindow) {
+      // Use an existing browser window
+      recentWindow.delayedOpenTab(url, null, null, null, null);
+    }
+    else {
+      // No browser windows are open, so open a new one.
+      window.open(url);
+    }
+  }
+}
+
+
依其它準則來重用
+

有時候您可能想重用某個先前已由您的附加元件開啟的頁籤,管它目前 URL/URI 是什麼,只要不是其他的元件開啟的。您的確可以為所欲為,只要在第一次開啟時給它一個自訂屬性。之後要重用它的時候,就從所有已開啟的頁籤找出這個有自訂屬性的頁籤,變更其 URL/URI 並 focus 或 select 該頁籤。要是連個屁都沒有 (可能被 user 關了或是根本沒開過),那就開個新的然後給它這個自訂屬性。

+
function openAndReuseOneTabPerAttribute(attrName, url) {
+  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+                     .getService(Components.interfaces.nsIWindowMediator);
+  for (var found = false, index = 0, tabbrowser = wm.getEnumerator('navigator:browser').getNext().gBrowser;
+       index < tabbrowser.tabContainer.childNodes.length && !found;
+       index++) {
+
+    // Get the next tab
+    var currentTab = tabbrowser.tabContainer.childNodes[index];
+
+    // Does this tab contain our custom attribute?
+    if (currentTab.hasAttribute(attrName)) {
+
+      // Yes--select and focus it.
+      tabbrowser.selectedTab = currentTab;
+
+      // Focus *this* browser window in case another one is currently focused
+      tabbrowser.ownerDocument.defaultView.focus();
+      found = true;
+    }
+  }
+
+  if (!found) {
+    // Our tab isn't open. Open it now.
+    var browserEnumerator = wm.getEnumerator("navigator:browser");
+    var tabbrowser = browserEnumerator.getNext().gBrowser;
+
+    // Create tab
+    var newTab = tabbrowser.addTab(url);
+    newTab.setAttribute(attrName, "xyz");
+
+    // Focus tab
+    tabbrowser.selectedTab = newTab;
+
+    // Focus *this* browser window in case another one is currently focused
+    tabbrowser.ownerDocument.defaultView.focus();
+  }
+}
+
+

該函式應如此這般調用:

+
openAndReuseOneTabPerAttribute("myextension-myattribute", "http://developer.mozilla.org/").
+
+

如何砍掉 tab

+

下列程式碼將砍掉目前選擇的 tab。

+
gBrowser.removeCurrentTab();
+
+

另有一個更廣用的 removeTab 方法,以 XUL {{ XULElem("tab") }} element 為唯一的參數。

+

如何改變 active tab

+

左三圈 .. ok,並沒有三圈 .. 選定向左一個 tab:

+
gBrowser.tabContainer.advanceSelectedTab(-1, true);
+
+

右三圈 (喔 .. 抱歉)

+
gBrowser.tabContainer.advanceSelectedTab(1, true);
+
+

如何偵測 page load

+

另見: Code snippets:On page load

+
function examplePageLoad(event) {
+  if (event.originalTarget instanceof HTMLDocument) {
+    var win = event.originalTarget.defaultView;
+    if (win.frameElement) {
+      // Frame within a tab was loaded. win should be the top window of
+      // the frameset. If you don't want do anything when frames/iframes
+      // are loaded in this web page, uncomment the following line:
+      // return;
+      // Find the root document:
+      win = win.top;
+    }
+  }
+}
+
+// do not try to add a callback until the browser window has
+// been initialised. We add a callback to the tabbed browser
+// when the browser's window gets loaded.
+window.addEventListener("load", function () {
+  // Add a callback to be run every time a document loads.
+  // note that this includes frames/iframes within the document
+  gBrowser.addEventListener("load", examplePageLoad, true);
+}, false);
+
+...
+// When no longer needed
+gBrowser.removeEventListener("load", examplePageLoad, true);
+...
+
+

tab 增減通知

+
function exampleTabAdded(event) {
+  var browser = gBrowser.getBrowserForTab(event.target);
+  // browser is the XUL element of the browser that's been added
+}
+
+function exampleTabMoved(event) {
+  var browser = gBrowser.getBrowserForTab(event.target);
+  // browser is the XUL element of the browser that's been moved
+}
+
+function exampleTabRemoved(event) {
+  var browser = gBrowser.getBrowserForTab(event.target);
+  // browser is the XUL element of the browser that's been removed
+}
+
+// During initialization
+var container = gBrowser.tabContainer;
+container.addEventListener("TabOpen", exampleTabAdded, false);
+container.addEventListener("TabMove", exampleTabMoved, false);
+container.addEventListener("TabClose", exampleTabRemoved, false);
+
+// When no longer needed
+container.removeEventListener("TabOpen", exampleTabAdded, false);
+container.removeEventListener("TabMove", exampleTabMoved, false);
+container.removeEventListener("TabClose", exampleTabRemoved, false);
+
+
+

{{ gecko_callout_heading("1.9.1") }}

+

Starting in Gecko 1.9.1 {{ geckoRelease("1.9.1") }}, there's an easy way to listen on progress events on all tabs.

+
+

{{ h2_gecko_minversion("Notification when a tab's attributes change", "2.0") }}

+

自 Gecko 2.0 起,您可以 listen TabAttrModified event 來得知 tab 之 attribute 異動。event listener 可能收到 tab 異動的 attribute 如下:

+ +
function exampleTabAttrModified(event) {
+  var tab = event.target;
+  // Now you can check what's changed on the tab
+}
+
+// During initialization
+var container = gBrowser.tabContainer;
+container.addEventListener("TabAttrModified", exampleTabAttrModified, false);
+
+// When no longer needed
+container.removeEventListener("TabAttrModified", exampleTabAttrModified, false);
+
+

{{ h2_gecko_minversion("Notification when a tab is pinned or unpinned", "2.0") }}

+

自 Gecko 2.0 起,tab 可以被 "釘選";也就是說這類 tab 變成一種特殊的 application tabs ("app tabs"),可以被釘在 tab 列的開頭而且只顯示為 favicon。透過 TabPinnedTabUnpinned 事件可以得知 tab 被釘了或被拔了。

+
function exampleTabPinned(event) {
+  var browser = gBrowser.getBrowserForTab(event.target);
+  // browser is the XUL element of the browser that's been pinned
+}
+
+function exampleTabUnpinned(event) {
+  var browser = gBrowser.getBrowserForTab(event.target);
+  // browser is the XUL element of the browser that's been pinned
+}
+
+// Initialization
+
+var container = gBrowser.tabContainer;
+container.addEventListener("TabPinned", exampleTabPinned, false);
+container.addEventListener("TabUnpinned", exampleTabUnpinned, false);
+
+// When no longer needed
+
+container.removeEventListener("TabPinned", exampleTabPinned, false);
+container.removeEventListener("TabUnpinned", exampleTabUnpinned, false);
+
+

如何偵測 tab 選定

+

下列程式碼用來得知 browser 中的 tab 被選定:

+
function exampleTabSelected(event) {
+  var browser = gBrowser.selectedBrowser;
+  // browser is the XUL element of the browser that's just been selected
+}
+
+// During initialisation
+var container = gBrowser.tabContainer;
+container.addEventListener("TabSelect", exampleTabSelected, false);
+
+// When no longer needed
+container.removeEventListener("TabSelect", exampleTabSelected, false);
+
+

如何取得已選定 tab 裡的內文(document)

+

下列程式碼用來獲取選定 tab 中的內文(document),於 browser window scope 中運作,例如從 browser window 的 overlay 。

+
gBrowser.contentDocument;
+
+

+
content.document
+
+

若程式碼是從由 browser window 所開啟的 window 或 dialog,可用以下程式碼獲取已選定 tab 裡所顯示的內文:

+
window.opener.content.document
+
+

若程式從並非自 browser window 所開啟的 window 或 dialog 中運行,則可用 {{ interface("nsIWindowMediator") }} 獲取最近所使用的 browser window 中已選定 tab 裡的內文。

+
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+                   .getService(Components.interfaces.nsIWindowMediator);
+var recentWindow = wm.getMostRecentWindow("navigator:browser");
+return recentWindow ? recentWindow.content.document.location : null;
+
+

另見: Working with windows in chrome code.

+

如何遍歷 browser

+

要遍歷 tabbrowser 中所有的 browser,要先取得任意一個 browser 的 window。如果程式碼是從 browser.xul overlay 執行 (譬如 toolbar button 或者 menu click handler),可以用預定義的 window 變數。但若是從獨自的 window 執行 (例如 settings/options dialog) 則要用 {{ interface("nsIWindowMediator") }} 來取得任意一個 browser 的window。

+

有了一個 window 後再用 win.gBrowser 取得其 <tabbrowser/> element,其中 win 就是上個步驟中所得到的 browser window 。 如果程式是從 browser.xul overlay 執行的話,可以不必寫 window.gBrowser 直接用 gBrowser 就好。很奇怪沒錯,在所有的 IDE 當中也沒有 gBrowser 這個東西,但是別忘了您是在開發 Firefox 的 extension , 這是它本身的 object model 。

+

最後一步,利用 gBrowser.browsers.length 得知 browser 的數量,並用 gBrowser.getBrowserAtIndex() 取得 <browser/> element。範例:

+
var num = gBrowser.browsers.length;
+for (var i = 0; i < num; i++) {
+  var b = gBrowser.getBrowserAtIndex(i);
+  try {
+    dump(b.currentURI.spec); // dump URLs of all open tabs to console
+  } catch(e) {
+    Components.utils.reportError(e);
+  }
+}
+

透過 DOM Inspector 或參見 {{ source("toolkit/content/widgets/browser.xml","browser.xml") }} 得知對應的 XBL bindings ( 不然參見 {{ XULElem("browser") }} 及 {{ XULElem("tabbrowser") }} 也行),您將可了解 <browser/><tabbrowser/> elements 有哪些方法可用。

+

如何取得觸發 http-on-modify-request notification 的 browser

+

關於http-on-* notification 請參見 Observer notifications

+

請注意,部份 HTTP requests 與 tab 無關;例如 RSS feed updates、extension manager requests 以及 XPCOM components 所發出的 XHR requests 等。在這些情況中,下列程式碼將返回 null 。

+
+ 注意:該程式碼使用之 getInterface(Components.interfaces.nsIDOMWindow) 應更新為 {{interface("nsILoadContext")}} ,參見範例
+
observe: function (subject, topic, data) {
+  if (topic == "http-on-modify-request") {
+    subject.QueryInterface(Components.interfaces.nsIHttpChannel);
+    var url = subject.URI.spec; /* url being requested. you might want this for something else */
+    var browser = this.getBrowserFromChannel(subject);
+    if (browser != null) {
+      /* do something */
+    }
+  }
+},
+
+getBrowserFromChannel: function (aChannel) {
+  try {
+    var notificationCallbacks =
+      aChannel.notificationCallbacks ? aChannel.notificationCallbacks : aChannel.loadGroup.notificationCallbacks;
+
+    if (!notificationCallbacks)
+      return null;
+
+    var domWin = notificationCallbacks.getInterface(Components.interfaces.nsIDOMWindow);
+    return gBrowser.getBrowserForDocument(domWin.top.document);
+  }
+  catch (e) {
+    dump(e + "\n");
+    return null;
+  }
+}
+
+

{{ languages( { "fr": "fr/Extraits_de_code/Onglets_de_navigation", "ja": "ja/Code_snippets/Tabbed_browser", "pl": "pl/Fragmenty_kodu/Przegl\u0105danie_w_kartach" } ) }}

diff --git "a/files/zh-tw/core_javascript_1.5_\346\255\243\350\246\217\350\241\250\351\201\224\345\274\217\347\232\204\345\273\272\347\253\213/index.html" "b/files/zh-tw/core_javascript_1.5_\346\255\243\350\246\217\350\241\250\351\201\224\345\274\217\347\232\204\345\273\272\347\253\213/index.html" new file mode 100644 index 0000000000..c7fe61614d --- /dev/null +++ "b/files/zh-tw/core_javascript_1.5_\346\255\243\350\246\217\350\241\250\351\201\224\345\274\217\347\232\204\345\273\272\347\253\213/index.html" @@ -0,0 +1,9 @@ +--- +title: Core JavaScript 1.5 正規表達式的建立 +slug: Core_JavaScript_1.5_正規表達式的建立 +--- +

 

+ +

This page was auto-generated because a user created a sub-page to this page.

+ +

 

diff --git a/files/zh-tw/cross-site_xmlhttprequest/index.html b/files/zh-tw/cross-site_xmlhttprequest/index.html new file mode 100644 index 0000000000..9ffdd6ca6e --- /dev/null +++ b/files/zh-tw/cross-site_xmlhttprequest/index.html @@ -0,0 +1,108 @@ +--- +title: Cross-site XMLHttpRequest +slug: Cross-site_XMLHttpRequest +--- +

Firefox 3 支援了 W3C Access Control working draft,這讓你可以對其他網站作 XMLHttpRequests 以取得其他網站的資料,並加以管理,在自己建立的網站中,混入來自多個其他網站的內容。

+

Firefox 3 支援 Cross-site XMLHttpRequest

+

概觀

+

W3C 存取控制(The W3C Access Control)的架構讓客戶端文件對於誰可以、誰不可以向它們發出「以瀏覽器為基礎的 request」(例如 XMLHttpRequest)有更好的控制。 +

除此之外,這個 access control scheme 讓網路應用程式擁有允許「跨站要求(cross-site request)」的能力。理論上,這讓你在部署好存取控制點(Access Control Point)後,可以由 yoursite.com 的一個頁面透過 XMLHttpRequest 向 google.com 要求一份文件。這個層級的控制,讓管理網站內容的人員在決定是否「讓他們的使用者建立混合不同網站內容的網頁(mashup)或網站應用程式」時更有彈性。 +

+

用法

+

在 Firefox 3,要使用 W3C 存取控制(W3C Access Controls)有兩個方法。第一個是透過「加入新的存取控制檔頭」(在任何 Resouece Type 都能運用此方式,但你對網站伺服器必須有較高的控制權),另一個是透過「存取控制處理指示」(The Access-control Processing Instruction)(僅能用於 XML 文件)。 +

+

存取控制檔頭(Access-Control Headers)

+

這是在允許跨站的 XMLHttpRequests 時最有彈性的作法。如果你在你的 Request Response 中加入額外的存取控制檔頭,像下面這樣,你就可以給予 mozilla.org 上的任何網路應用程式擁有存取的權限。 +

+
Access-Control: allow <mozilla.org>
+

存取控制檔頭讓你有能力可以依據來源、要求方式(request method)來決定是否給予、或拒絕別人存取特定資源。 +

例如,下面這些都是有效的存取控制檔頭: +

+
 // 任何人都可以存取這項資源 - 沒有限制
+ Access-Control: allow <*>
+
+ // 任何人都不可以存取這項資源 - 沒有例外
+ Access-Control: deny <*>
+
+ // 只有在 'mozilla.org' 上面的網站可以存取這項資源
+ // (這也包含了 sub-domains)
+ Access-Control: allow <mozilla.org>
+
+ // 除了 developer.mozilla.org 以外,其他所有 mozilla.org 的 sub-domain 都可以存取這項資源
+ Access-Control: allow <mozilla.org> exclude <developer.mozilla.org>
+
+ // 只有這個 domain、在這個 port、運用此方式的 request 可以存取這項資源
+ Access-Control: allow <developer.mozilla.org:80> method GET, POST
+
+

W3C Access Control working draft 有更多例子可看。 +

+
例子
+

XML Processing Instruction

+

XML 有「include 額外命令讓 XML processor 針對它特別處理」的能力。The Access Control draft 就是利用這種特性指定了一種額外的命令,讓 XML 文件變成可以在遠端被跨站存取。 +

例如: 使用下列存取控制處理指示 (access-control processing instruction)會給 mozilla.org 上的任何網站有存取 XML 文件的能力: +

+
 <?access-control allow="mozilla.org"?>
+
+

這裡有一些使用存取控制處理指示(access-control processing instruction)來給予 XML 文件存取權限的簡單例子: +

+
 // 任何人都可以存取這項資源 - 沒有限制
+ <?access-control allow="*"?>
+
+ // 任何人都不可以存取這項資源 - 沒有例外
+ <?access-control deny="*"?>
+
+ // 只有在 'mozilla.org' 上面的網站可以存取這項資源
+ // (這也包含了 sub-domains)
+ <?access-control deny="mozilla.org"?>
+
+  // 除了 developer.mozilla.org 以外,其他所有 mozilla.org 的 sub-domain 都可以存取這項資源
+ <?access-control allow="mozilla.org" exclude="developer.mozilla.org"?>
+
+ // 只有這個 domain、在這個 port、運用此方式的 request 可以存取這項資源
+ <?access-control allow="developer.mozilla.org" method="GET POST"?>
+
+

你可以在 W3C Access Control working draft 中找到更多例子。 +

+
例子
+

這個簡單的例子從一個網站向另一個網站要求 XML 檔。這個 XML 檔包含了「存取控制的處理指示」(Access-control processing instruction),這些指示給予任何向伺服器發出要求的網站存取的權限。如果你複製 ac.html 到你自己的伺服器,你就會看到 request 仍然可以作用(因為所有網站都被允許向它發出請求)。 +

ac.html +

+
 <html>
+ <head>
+ <script>
+ window.onload = function(){
+   var xhr = new XMLHttpRequest();
+   xhr.open("GET", "http://dev.jquery.com/~john/xdomain/test.xml", true);
+   xhr.onreadystatechange = function(){
+     if ( xhr.readyState == 4 ) {
+       if ( xhr.status == 200 ) {
+         document.body.innerHTML = "My Name is: " +
+           xhr.responseXML.getElementsByTagName("name")[0].firstChild.nodeValue;
+       } else {
+         document.body.innerHTML = "ERROR";
+       }
+     }
+   };
+   xhr.send(null);
+ };
+ </script>
+ </head>
+ <body>
+ Loading...
+ </body>
+ </html>
+
+

test.xml +

+
 <?xml version="1.0" encoding="UTF-8"?>
+ <?access-control allow="ejohn.org"?>
+ <simple><name>John Resig</name></simple>
+
+

延伸閱讀

+ +
+
+{{ languages( { "en": "en/Cross-Site_XMLHttpRequest", "fr": "fr/Requ\u00eates_XMLHttpRequest_inter-sites", "ja": "ja/Cross-Site_XMLHttpRequest", "pl": "pl/\u017b\u0105dania_XMLHttpRequest_przesy\u0142ane_mi\u0119dzy_witrynami" } ) }} diff --git "a/files/zh-tw/dom_\350\247\200\345\257\237\345\231\250/index.html" "b/files/zh-tw/dom_\350\247\200\345\257\237\345\231\250/index.html" new file mode 100644 index 0000000000..9b597bb306 --- /dev/null +++ "b/files/zh-tw/dom_\350\247\200\345\257\237\345\231\250/index.html" @@ -0,0 +1,5 @@ +--- +title: DOM 觀察器 +slug: DOM_觀察器 +--- +
diff --git a/files/zh-tw/dragdrop/index.html b/files/zh-tw/dragdrop/index.html new file mode 100644 index 0000000000..8113a786ec --- /dev/null +++ b/files/zh-tw/dragdrop/index.html @@ -0,0 +1,5 @@ +--- +title: DragDrop +slug: DragDrop +--- +This page was auto-generated because a user created a sub-page to this page. diff --git a/files/zh-tw/extensions/index.html b/files/zh-tw/extensions/index.html new file mode 100644 index 0000000000..63a7457aaa --- /dev/null +++ b/files/zh-tw/extensions/index.html @@ -0,0 +1,9 @@ +--- +title: Extensions +slug: Extensions +--- +

 

+ +

This page was auto-generated because a user created a sub-page to this page.

+ +

 

diff --git a/files/zh-tw/extensions/using_the_dom_file_api_in_chrome_code/index.html b/files/zh-tw/extensions/using_the_dom_file_api_in_chrome_code/index.html new file mode 100644 index 0000000000..e4bd4f169c --- /dev/null +++ b/files/zh-tw/extensions/using_the_dom_file_api_in_chrome_code/index.html @@ -0,0 +1,49 @@ +--- +title: 使用 DOM 檔案 API 再FireFox外觀代碼上 +slug: Extensions/Using_the_DOM_File_API_in_chrome_code +translation_of: Extensions/Using_the_DOM_File_API_in_chrome_code +--- +

{{ gecko_minversion_header("6.0") }}

+ +

如果你想使用如果你想使用 DOM 檔案 API 在FireFox外觀代碼上面,你可以沒有任何限制的這樣做。事實上你得到了一個特別的功能。你可以建立你可以建立 {{ domxref("File") }} 物件 specifying the path of the file on the user's computer. This only works from privileged code, so web content can't do it. This protects users from the inherent security risks associated with allowing web content free access to the contents of their disks. If you pass a path to the {{ domxref("File") }} constructor from unprivileged code (such as web content), an exception will be thrown.

+ +

Accessing a file by hard-coded pathname

+ +

To reference a file by its path, you can simply use a string literal:

+ +
var file = File("path/to/some/file");
+
+ +

Accessing files in a special directory

+ +

You can also use the directory service to obtain and build the path to a file to access. For example, let's say your add-on needs to access a file in the user's profile. You can do so like this:

+ +
var dsFile = Components.classes["@mozilla.org/file/directory_service;1"]
+                    .getService(Components.interfaces.nsIProperties)
+                    .get("ProfD", Components.interfaces.nsIFile);
+
+dsFile.append("myfilename.txt");
+
+var file = File(dsFile.path);
+
+ +

This uses the directory service to locate the profile directory ("ProfD"), then appends the name of the file we want to work with by calling {{ ifmethod("nsIFile", "append") }}. Finally, we instantiate the {{ domxref("File") }} object by passing the string returned by {{ ifmethod("nsIFile", "path") }} to the {{ domxref("File") }} constructor.

+ +

You can even simplify this further! You can actually pass the {{ interface("nsIFile") }} object itself directly to the File constructor, resulting in the following code:

+ +
var dsFile = Components.classes["@mozilla.org/file/directory_service;1"]
+                    .getService(Components.interfaces.nsIProperties)
+                    .get("ProfD", Components.interfaces.nsIFile);
+
+dsFile.append("myfilename.txt");
+
+var file = File(dsFile);
+ +

See also

+ + diff --git "a/files/zh-tw/firefox_2_\344\275\210\346\231\257\344\270\273\351\241\214\344\271\213\346\233\264\345\213\225/index.html" "b/files/zh-tw/firefox_2_\344\275\210\346\231\257\344\270\273\351\241\214\344\271\213\346\233\264\345\213\225/index.html" new file mode 100644 index 0000000000..2bf1c7150c --- /dev/null +++ "b/files/zh-tw/firefox_2_\344\275\210\346\231\257\344\270\273\351\241\214\344\271\213\346\233\264\345\213\225/index.html" @@ -0,0 +1,884 @@ +--- +title: Firefox 2 佈景主題之更動 +slug: Firefox_2_佈景主題之更動 +tags: + - 佈景主題 + - 待翻譯 +translation_of: Archive/Themes/Theme_changes_in_Firefox_2 +--- +

本文涵括使佈景主題相容 Firefox 2 的各種修改須知。

+ +

 

+ +

與瀏覽器更動相關

+ +

瀏覽器中有許多更動甚至刪除的檔案,所以佈景主題可能需要修改才能正確套用。此表格列出 XUL 及相對應的 CSS 檔案更動處,供您編修查照。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
檔案名稱CSS 檔細節
feeds/addFeedReader.xulfeeds/addFeedReader.css新檔案,提供添加新消息來源閱讀工具的使用介面。
feeds/subscribe.xhtmlfeeds/subscribe.css新檔案,提供訂閱消息來源(RSS)的介面。
preferences/downloads.xul-自 Firefox 2 起移除。
preferences/general.xul-自 Firefox 2 起移除。
safebrowsing/warning-overlay.xulsafebrowsing/browser-protection.css新檔案,為使用者瀏覽疑似詐騙網站時覆蓋瀏覽器的警告介面。
search/engineManager.xulengineManager.css新檔案,為搜尋引擎管理員視窗的介面。
+ +

預設佈景主題的更動

+ +

以下列出 Firefox 2 預設佈景主題的變動之處,您可依循本表找出該修改的地方。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
檔案變動描述
browser/bookmarks/addBookmark.css加入與即時摘要相關的 CSS 更動部份。
browser/bookmarks/bookmarksProperties.css新檔案,內含與即時摘要相關的 CSS。
browser/browser.css需為即時摘要、搜尋欄、書籤選單項目圖示及其他部分修改之。
browser/dropmark-nav-small.png新檔案,為使用小圖示時上下一頁旁的下拉選單圖示。
browser/dropmark-nav.png新檔案,為上下一頁旁的下拉選單圖示。
browser/engineManager.css新檔案,搜尋引擎管理員所用的 CSS。
browser/feeds/addFeedReader.css新檔案,新增消息來源閱讀工具的視窗所用之 CSS。
browser/feeds/feedIcon.png新檔案,RSS 圖示。
browser/feeds/feedIcon16.png新檔案,RSS 圖示的 16x16 像素版。
browser/feeds/subscribe.css新檔案,訂閱消息來源時視窗的 CSS。
browser/Go-rtl.png新檔案,網址列尾端的「Go」三角箭頭圖示。
browser/preferences/preferences.css選項視窗的樣式檔。
browser/safebrowsing/browser-protection.css新檔案,控制瀏覽疑似詐騙網站時出現的警告訊息及網址列圖示樣式。
browser/safebrowsing/close16x16.png新檔案,詐騙網站警告視窗的關閉鈕。
browser/safebrowsing/dim.png新檔案,瀏覽疑似詐騙網站時,會覆蓋在整個頁面上使頁面內容變暗的檔案,應為半透明圖以便使用者辨識頁面的內容。
browser/safebrowsing/tail.png新檔案,詐騙網站警告視窗的「尾巴」,藉以製成談話泡泡的樣子。
browser/safebrowsing/warning16x16.png新檔案,網址列詐騙網站警告圖示的 16x16 像素版。.
browser/safebrowsing/warning24x24.png新檔案,此為顯示於詐騙網站警告視窗中的圖示。
browser/search-bar-background-mid.png新檔案,搜尋欄中間的背景。搜尋欄本身及尾端的圖已經拆開分別繪製。
browser/search-bar-background.png已移除。
browser/Search-bar.png已移除。
browser/Search-go-rtl.png新檔案,搜尋欄的搜尋圖示,此為顯示於左側的版本。
browser/Search-go.png新檔案,搜尋欄右側的搜尋圖示。
browser/Search-provider-bkgnd-rtl.pngNew file; the background drawn behind the search provider icon when it's located at the left end of the search bar.
browser/Search-provider-bkgnd.pngNew file; the background drawn behind the search provider icon when it's located at the right end of the search bar.
global/about.cssNew file; CSS used in the application's about box.
global/alltabs-box-bkgnd.pngNew file; the background for the "all tabs" drop-down menu at the right side of the tab bar.
global/alltabs-box-overflow-bkgnd.pngNew file; the background for the "all tabs" drop-down menu when there are enough tabs to activate tab bar scrolling.
global/browser.cssRevised to support new styles for the main browser window.
global/globalBindings.xmlUpdated to support changes to the tab bar, including per-tab close buttons.
global/icons/alltabs.pngNot actually used; left over from earlier drafts of the theme.
global/inactivetab-left.png已移除。
global/inactivetab-right.png已移除。
global/menu.cssUpdated to include new styles.
global/notification.cssNew file; defines styles used by the notification strip that appears at the top of browser windows to present notices such as "a popup was blocked."
global/scrollbox/autorepeat-arrow-dn-dis.gifNew file; icon displayed for a disabled autorepeat down arrow in a scroll box.
global/scrollbox/autorepeat-arrow-dn.gifNew file; icon displayed for an autorepeat down arrow in a scroll box.
global/scrollbox/autorepeat-arrow-up-dis.gifNew file; icon displayed for a disabled autorepeat up arrow in a scroll box.
global/scrollbox/autorepeat-arrow-up.gifNew file; icon displayed for an autorepeat up arrow in a scroll box.
global/scrollbox.cssNeeds to be updated to include new styles.
global/tab-arrow-end-bkgnd.pngNew file; the background for the scrolling tab bar arrow at the right side of the tab bar.
global/tab-arrow-end.pngNew file; the arrow drawn in the scrolling tab bar box at the right end of the tab bar.
global/tab-arrow-start-bkgnd.pngNew file; the background for the scrolling tab bar arrow at the left side of the tab bar.
global/tab-arrow-start.pngNew file; the arrow drawn in the scrolling tab bar box at the left end of the tab bar.
global/tab-left.png新檔案,為分頁標籤的左緣。
global/tab-middle.png新檔案,為分頁標籤中間部分。
global/tab-right.png新檔案,為分頁標籤的右緣。
global/tabbrowser-tabs-bkgnd.png新檔案,為分頁列上標籤後方的背景圖。
global/toolbar.css需更新,將新的樣式資訊加入。
mozapps/extensions/about.cssUpdated with a simplified set of style names, since several styles were identical.
mozapps/extensions/extensions.cssCSS for the add-ons manager window. Updated to support the new features of the Firefox 2 add-ons manager.
mozapps/extensions/itemDisabledFader.pngNew file; a translucent PNG used as an overlay on top of items that are disabled in the add-ons manager.
mozapps/extensions/itemEnabledFader.pngNew file; a translucent PNG used as an overlay on top of items that are enabled in the add-ons manager.
mozapps/extensions/notifyBadges.pngNew file; contains the icons used ito badge the icons for add-ons in the add-on manager window to indicate their status. These look like this in the default theme: +

Image:notifyBadges.png

+ +
    +
  • The first icon (green here) indicates that an add-on has an update available.
  • +
  • The second icon (yellow here)appears to be used for blocklisted items; trying to confirm.
  • +
  • The third icon (red here) indicates that an add-on is disabled, either by the user or because it's incompatible with the application.
  • +
  • The fourth icon (blue here)(not sure what this one means).
  • +
+
mozapps/extensions/question.pngNew file; used in the Add-ons Manager when you check for updates. If no updates are found, this icon is displayed at the left side of the message strip that appears across the top of the window.
mozapps/extensions/update.css本檔案為更新精靈的樣式,其中的樣式資訊因應重新設計的更新精靈而較之前少。
mozapps/extensions/viewButtons.pngNew file; contains icons for each of the views that may be available in the add-ons manager. In the default theme, these look something like this: +

Image:viewButtons.png
+ The top row contains dimmed versions of the icons below them. The first icon is for the extensions view. The second is for themes. The third is for locales, the fourth is for plugins, the fifth is for updates, and the sixth is for installs.

+
mozapps/prefFirefox 2 已經用不到這個目錄了,應予移除。
+ +

Changes in browser

+ +

bookmarks/addBookmark.css

+ +

addBookmarks.css 檔的最開頭應該加上下列幾行:

+ +
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+@namespace html url("http://www.w3.org/1999/xhtml");
+
+ +

還有些與即時摘要相關的 CSS 也要加上,以便調整即時摘要選取工具的樣式。這個選取工具僅在頁面有即時摘要時才以可編輯式下拉選單呈現,否則就長得跟一般文字輸入區相同。

+ + + +

此檔案將為 addBookmark2.xul 調整樣式。

+ +

bookmarks/bookmarksProperties.css

+ +

這是 Firefox 2 新增的檔案,其 CSS 碼應該跟你剛才加到 addBookmark.css 裡的一樣。此檔案為 bookmarksProperties.xul 調整樣式。

+ +
註: 這個 CSS 應該會另外開一篇檔案展示範例內容,以便往後其他相關文件參照。
+ +

browser.css

+ +

以下是 Firefox 2 之後不再使用的樣式,應予移除:

+ + + +

而以下是 Firefox 2 佈景主題應加上的樣式:

+ + + +

可能還有其他的樣式也要一併修改一下。

+ +

searchbar.css

+ +

以下是 Firefox 2 不再使用的樣式,應予移除:

+ + + +

以下是 Firefox 2 應加上的樣式:

+ + + +

同樣的,你可能也需要更動其他部分。

+ +

preferences/preferences.css

+ +

以下是 Firefox 2 不再使用的樣式,應予移除:

+ + + +

以下是 Firefox 2 佈景主題應加上的樣式:

+ + + +

你依然可能得修改其他部分。

+ +

feeds/addFeedReader.css

+ +

這是 Firefox 2 中的新檔案,用於調整新增消息來源閱讀工具視窗樣式,即 browser/feeds/addFeedReader.xul。

+ + + +

feeds/subscribe.css

+ +

這是 Firefox 2 的新檔案,用以調整訂閱消息來源視窗的樣式,即 browser/feeds/subscribe.xhtml。

+ + + +

預設佈景主題中也含有 a{{ mediawiki.external('href') }} imgbodyh1h2html 等樣式規則。

+ +

safebrowser/browser-protection.css

+ +

這個 Firefox 2 的新檔案用以調整偵測詐騙網站功能的樣式。下列樣式一定要設定好、在使用者碰上疑似詐騙網站時提醒他們:

+ + + +

而以下樣式則調整碰上疑似詐騙網站時網址列的小圖示,安全跟警告各有不同:

+ + + +

engineManager.css

+ +

此檔案為 Firefox 2 新增,要調整的樣式如下:

+ + + +

Changes in global

+ +

about.css

+ +

此檔案為 Firefox 2 新增、用以調整「關於 Mozilla Firefox」視窗的樣式。檔案中至少要有下列樣式資訊:

+ + + +

預設的佈景主題則額外調整了 bodyhtmlimgulul > li

+ +

browser.css

+ +

Firefox 2 已不使用下列樣式,應予移除:

+ + + +

而以下則是 Firefox 2 佈景主題該新增的樣式:

+ + + +

除此之外,依然可能要調整相關的樣式。

+ + + +

這是 Firefox 2 用不上的樣式,應予刪除:

+ + + +

而 Firefox 2 佈景主題還應該加上下列樣式:

+ + + +

若有相關樣式,可能得另外調整。

+ +

notification.css

+ +

此外 Firefox 2 新增的檔案,用以調整阻擋彈出視窗、提示安裝 plugin 等的訊息列樣式。至少應定義下列樣式:

+ + + +

scrollbox.css

+ +

請為 Firefox 2 佈景主題的這個檔案加上下列樣式:

+ + + +

You may wish to make changes to other styles as well.

+ + + +

或許也要更動其他相關的部分。

+ +

mozapps 更動處

+ +

extensions/about.css

+ +

Firefox 2 已經用不著以下樣式了,應予刪除:

+ + + +

此外應新增下列樣式:

+ + + +

其他關聯的樣式也可能需要變動。

+ +

extensions/update.css

+ +

Firefox 2 已經用不著以下樣式了,應予刪除:

+ + + +

此外應新增下列樣式:

+ + diff --git "a/files/zh-tw/firefox_3.5_\346\212\200\350\241\223\346\226\207\344\273\266/index.html" "b/files/zh-tw/firefox_3.5_\346\212\200\350\241\223\346\226\207\344\273\266/index.html" new file mode 100644 index 0000000000..0d151ee276 --- /dev/null +++ "b/files/zh-tw/firefox_3.5_\346\212\200\350\241\223\346\226\207\344\273\266/index.html" @@ -0,0 +1,240 @@ +--- +title: Firefox 3.5 技術文件 +slug: Firefox_3.5_技術文件 +tags: + - Firefox + - Firefox 3.5 +--- +

Firefox 3.5 加入很多新功能,當然也加強了對各式網際標準的支援程度。這篇文章大致說明改進的部份、詳細的說明可見英文版原文。

+

限於人力,大部分的文章都是英文版。如果您有興趣,請協助翻譯。

+

3.5 技術面新功能

+

網站、網際程式部份

+

加強支援 HTML 5

+
+
+ 在 Firefox 中操作影片、音效
+
+ Firefox 3.5 支援 HTML 5 的 audiovideo 元素。藉由原生支援,影片、音效可以經由 JavaScript 直接操作 (播放、暫停等)。目前只支援 Ogg 及 WAV 兩種格式的影音檔,未來可能支援其他的格式。
+
+ 離線資源
+
+ Firefox 3.5 現在完整支援 HTML 5 的離線資源規格。需注意的是,在 Firefox 3 雖已經支援部份規格、但由於推出後 HTML 5 離線資源規格已然修改,是以毋需再針對 Firefox 3 設計相關程式。3.5 支援的是最新的規格。
+
+ 拖放事件
+
+ HTML 5 拖放 (drag & drop) API 提供在網站內 (甚至跨網站) 拖放物件的相關功能。同時,這也讓 Mozilla 相關的程式擴充套件有了比較簡單的 API 可以使用。
+
+

新增功能:CSS 部份

+
+
+ 動態下載字形
+
+ 新支援的 @font-face 樣式規則,網頁可以藉此提供字形讓使用者動態下載、以設計師所期待的最佳字形檢視網頁。
+
+ CSS 媒介判讀
+
+ Firefox 3.5 現在支援 CSS 媒介判讀 (media queries),可以讓不同的媒介使用不同的樣式規則。
+
+ 更新 ::before::after 行為以符合 CSS 2.1
+
+ ::before::after 兩個擬態元素 (pseudo-element) 已經更新,以便完整支援 CSS 2.1 相關規格。新增關於 positionfloatlist-style-* 及部份 display 特性。
+
+
+
+ opacity
+
+ Mozilla 先前提供的 -moz-opacity 特性已經停止支援,請改用標準的 opacity 特性。
+
+ text-shadow
+
+ Firefox 3.5 開始支援 text-shadow 特性,可以為網頁上的文字加上陰影效果。
+
+ word-wrap
+
+ 此特性可設定是否允許某行文字溢出版面時自動調整斷行。
+
+ -moz-box-shadow
+
+ -moz-border-image
+
+ -moz-column-rule
+
+ -moz-column-rule-width
+
+ -moz-column-rule-style
+
+ -moz-column-rule-color
+
+ -moz-column-gap
+
+ Firefox 3.1 開始新增上述 Mozilla 擴充特性。
+
+ -moz-nativehyperlinktext 色彩值
+
+ 新的色彩設定值,顯示為系統的預設連結色彩。
+
+ -moz-window-shadow-moz-system-metric(mac-graphite-theme) 特性
+
+ 為了方便佈景主題製作而新增的 CSS 特性。
+
+ -moz-appearance 支援新設定值
+
+ -moz-appearance 開始支援 -moz-win-glass-moz-mac-unified-toolbar 兩種新設定值。
+
+ CSS 變形
+
+ Firefox 3.5 開始支援 CSS 變形特性,詳情請見 -moz-transform-moz-transform-origin
+
+ :nth-child
+
+ :nth-last-child
+
+ :nth-of-type
+
+ :nth-last-of-type
+
+ :first-of-type
+
+ :last-of-type
+
+ :only-of-type
+
+ Firefox 3.5 開始支援上述選取符。
+
+

新增功能:DOM 部份

+
+
+ DOM 背景工作序
+
+ Firefox 3.5 支援 DOM 背景工作緒 (workers),方便網際應用程式以多執行緒方式執行。
+
+ 地理位置
+
+ Firefox 3.5 支援地理資訊 (Geolocation) API,在安裝有相關元件 (Geolocation provider)並啟用的狀態下、允許網際應用程式取得使用者目前的所在地。
+
+ 在 Firefox 中使用 JSON
+
+ DOM 已經整合對 JSON 的支援。
+
+
+
+ 以選取符取用 DOM 元素
+
+ 選取符 API 讓開發人員以類似 CSS 的選取符指定 DOM 元素方便操作。
+
+ NodeIterator 物件
+
+ NodeIterator 提供在DOM子樹中對節點列表進行往返(iterating)的支援。
+
+ MozAfterPaint 事件
+
+ 新 DOM 事件,在視窗重繪時觸發。
+
+ MozMousePixelScroll 事件
+
+ 新 DOM 事件,允許偵測滑鼠滾輪事件,且是以像素為單位、非以往的「行」。
+
+

新增功能:JavaScript

+
+
+ Object.getPrototypeOf()
+
+ 傳回指定物件的原型。
+
+ 字串物件的「修剪」方法
+
+ String 物件現在可藉 trim()trimLeft()trimRight() 等方法清除空白部份。
+
+

其他新功能

+
+
+ ICC 色彩校正
+
+ Firefox 3.5 現在支援圖片的 ICC 色彩校正。
+
+ script 元素支援 defer 屬性
+
+ 此屬性讓瀏覽器可以決定是否要等待此段腳本執行完畢後再繼續分析、繪制網頁。
+
+ 控制預讀 DNS
+
+ Firefox 3.5 提供預讀 DNS 功能,不必等到真的按下連結、就可以先行處理本頁裡各連結網址的域名查詢,讓使用者感覺更快。本文說明操作這個行為的方法,包括如何停用、如何調整此功能。
+
+

新增功能:Canvas 部份

+
+
+ canvas 元素中的 HTML 5 text API
+
+ Canvas 元素開始支援 HTML 5 text API。
+
+ canvas 支援陰影效果
+
+ 此版開始支援 Canvas 陰影效果。
+
+ moz-opaque 屬性
+
+ 增加 moz-opaque DOM 屬性,指定 canvas 是否需要使用透明效果。如果一開始就確定不會有透明效果、那麼繪製的效率便能最佳化。
+
+

新增功能:SVG 部份

+
+
+ 在 HTML 內容中套用 SVG 特效
+
+ 你現在可以在 HTML 及 XHTML 內容中套用 SVG 特效。
+
+

其他改良要點

+ +

XUL 及套件開發相關

+

如果您曾開發擴充套件,那麼請先閱讀為 Firefox 3.5 更新套件(英文),裡頭說明了新版本對套件可能衍生的影響。

+

新元件、函式

+
+
+ 跨網域 HTTP 存取控制
+
+ 當伺服器提供相關支援,則 Firefox 3.5 可以操作包含 XMLHttpRequest 在內的跨網域 HTTP 存取方式。
+
+ XMLHttpRequest 進度事件
+
+ 讓擴充套件得以監控相關進度。
+
+ 支援隱密瀏覽模式
+
+ Firefox 3.5 支援隱密瀏覽模式,不會紀錄使用者的活動。擴充套件如需支援隱密模式,可以參考這份文件。
+
+ Firefox 3.5 安全相關變動
+
+ Firefox 3.5 安全性相關的變動說明。
+
+ Firefox 3.5 佈景主題變動
+
+ Firefox 3.5 佈景主題相關的變動說明。
+
+

其他值得一提的改良、改變

+ +

{{ languages( { "en": "en-US/Firefox/Releases/3.5"} ) }}

diff --git a/files/zh-tw/firefox_3_animated_png_support/index.html b/files/zh-tw/firefox_3_animated_png_support/index.html new file mode 100644 index 0000000000..8ed0584144 --- /dev/null +++ b/files/zh-tw/firefox_3_animated_png_support/index.html @@ -0,0 +1,39 @@ +--- +title: Firefox 3 Animated PNG support +slug: Firefox_3_Animated_PNG_support +translation_of: Mozilla/Tech/APNG +--- +

Firefox 3 支援 Animated PNG

+ +

參考資料

+ +

延伸閱讀

+ diff --git a/files/zh-tw/firefox_3_drag_and_drop_events/index.html b/files/zh-tw/firefox_3_drag_and_drop_events/index.html new file mode 100644 index 0000000000..03cca49700 --- /dev/null +++ b/files/zh-tw/firefox_3_drag_and_drop_events/index.html @@ -0,0 +1,33 @@ +--- +title: Firefox 3 Drag and Drop Events +slug: Firefox_3_Drag_and_Drop_Events +translation_of: Archive/Mozilla/Drag_and_drop/Drag_and_drop_events +--- +

Firefox 3 加入了兩個新的 events 讓你可以決定 drag 什麼時候開始、什麼時候結束。這些 events 是 HTML 5 規格書的草稿中新加入的。

+

 

+
+
+ drag
+
+ drag operation 開始時送出。
+
+ dragend
+
+ drag operation 結束時送出。
+
+

如想知道更多,請看 [Drag and Drop.]

+

這裡有個例子可以參考:

+ +

參考資料

+
    +
  1. Drag and Drop events 原始網頁
  2. +
+

延伸閱讀

+
    +
  1. WHATWG HTML 5 Working Draft
  2. +
  3. Drag and Drop
  4. +
  5. nsIDragService
  6. +
diff --git "a/files/zh-tw/firefox_\344\270\255\347\232\204\351\233\242\347\267\232\350\263\207\346\272\220/index.html" "b/files/zh-tw/firefox_\344\270\255\347\232\204\351\233\242\347\267\232\350\263\207\346\272\220/index.html" new file mode 100644 index 0000000000..0b1180d3ca --- /dev/null +++ "b/files/zh-tw/firefox_\344\270\255\347\232\204\351\233\242\347\267\232\350\263\207\346\272\220/index.html" @@ -0,0 +1,48 @@ +--- +title: Firefox 中的離線資源 +slug: Firefox_中的離線資源 +tags: + - HTML5 離線 + - application cache +--- +

 

+

原文 : Using Application Cache

 

介紹

  HTML5 提供了 cache 機制,使得網路應用程式能較不受到網路狀態的影響。開發人員可以藉由 Application Cache (AppCache) 的介面來定義哪些資源應當被瀏覽器儲存起來 - 如此一來即使網路斷線使用者依舊可以取得這些資源。同時,應用程式也能正確的運行即使使用者按下了「重新載入」的按鈕。

  大抵來說,使用 Application Cache 可以取得下列好處:

  • 離線瀏覽:使用者可以在斷線/離線時瀏覽你的網站
  • 網站加速:善用 AppCache 就可以減少載入重複資源的狀況,進而加速網站讀取速度
  • 減少伺服器的負擔:瀏覽器僅只有在伺服器上資源發生變動時才重新抓取資料

application cache 運作的機制

啟動 application cache

  啟動 AppCache 的方法很簡單,你只需要在你程式頁面中,html 元素裡指名 manifest 的位置即可,這裡有個簡單範例:

<html manifest="example.appcache"> 
+  ...
+</html>
+

manifest 指向了一個 cache manifest 的檔案,他指出了在你的應用程式中哪些資源該當被瀏覽器儲存以作為快取。

  你應該在每一個你希望瀏覽器替你儲存資源的頁面加上 manifest。瀏覽器不會自作主張的去儲存 manifest 指定以外的資源。事實上,你並不需要列出所有你想要被快取的頁面,瀏覽器會儲存使用者曾經瀏覽過的所有頁面以及你指名的那些資源。

  某些瀏覽器 - 例如 FireFox - 會在使用者第一次讀取有使用 Application Cache 的時候提醒他們。提示訊息可能會是這樣:

This website (www.example.com) is asking to store data on your computer for offline use. [Allow] [Never for This Site] [Not Now]

The term "offline(-enabled) applications" sometimes refers specifically to applications that the user has allowed to use offline capabilities.

讀取文件

  Application Cache 的運作是基於讀取 manifest 檔案:

  • 倘若 application cache 存在,瀏覽器會直接取用本地端的快取而非經由網路請求資源。這可以加速網頁讀取。
  • 倘若 cache manifest 檔案被更新了,瀏覽器會下載新版的 manifest 並且依此and the resources listed in the manifest. This is done in the background and does not affect performance significantly.

  其運作流程如下:

  1. 當瀏覽器造訪一個有使用 AppCache 的網站時 (根據 <html> 判定),若發現自己並沒有本地快取,就按照該 manifest 建立第一版的本地快取。
  2. 在接下來的瀏覽行為中,倘然觸及被快取的資源,瀏覽器將會直接自本地端給予回應。在此同時,瀏覽器也會傳送一個確認的事件給 window.applicationCache 物件,其會按照 HTTP cache rules 取回 manifest 檔案。
  3. 假使目前本地擁有的 manifest 已經是最新,瀏覽器將會送一個「不需更新」的事件給 applicationCache 物件。所以假設任何一個在伺服器端被你註明要被快取住的物件更動了,務必改動 manifest 檔案,如此一來使用者的瀏覽器才知道要重新下載所有的資源。
  4. 當 manifest 更新後,所有列在其中的資源會由 applicationCache.add()透過 HTTP caching rules 被重新抓取至本地的暫存快取。當一個檔案被抓到本地快取後,瀏覽器會送出 progress 的事件到 applicationCache 物件。如果發生了錯誤,瀏覽器會送出 error 事件並停止更新。
  5. 當所有資源都被成功的取得後,他們便會被真正地移到離線時也能存取的快取區。此時,cached 事件會被發送給 applicationCache 物件。此時瀏覽器已經能顯示畫面了,未來只有當使用者重新整理頁面、手動操作或被其他程式驅動才會重新從快取中讀到瀏覽器。

清除 application cache

  在 Chrome 中,使用者可以藉由選擇 preferences 中 Clear browsing data... 清除 application cache 的內容 (此外,也可以造訪 chrome://appcache-internals/ )。Safari 中也有類似的設計,你可以選用 preference 中的 Empty cache 達到一樣的目的 (但 safari 此時可能會要求你重啟瀏覽器)。

  而 Firefox 則將這些資料放置在一般的硬碟快取中 (非在 Firefox 的 profile 中):

  • Windows Vista/7: C:\Users\<username>\AppData\Local\Mozilla\Firefox\Profiles\<salt>.<profile name>\OfflineCache
  • Mac/Linux: /Users/<username>/Library/Caches/Firefox/Profiles/<salt>.<profile name>/OfflineCache

使用者可以透過檢查 about:cache 中 Offline cache device 下的資訊來得知目前狀態。

  使用者可以清除特定網站的快取藉由 Tools -> Options -> Advanced -> Network -> Offline 中的 "Remove..." 按鈕。補充一下,以下兩個方法無法清除快取

  • Clear Recent History (bug 538595)
  • Options -> Advanced -> Network -> Offline data -> Clear Now (bug 538588)

相關資訊亦可參考  clearing the DOM Storage data 。

  Application cache 也會有失效的時候。當伺服器端移除了 manifest 後,瀏覽器會自動清除所有在本地端的快取,並且發送 obsoleted 的事件給 applicationCache 物件。這會使得 application cache 的狀態變為 OBSOLETE。

關於 cache manifest file

如何引用 cache manifest file

  在 manifest 中定義資源的路徑可以分為兩種 - 相對路徑及絕對路徑 (絕對路徑:起始點是 application 所在的那層目錄)。並且,manifest 的 MIME 格式必須為 text/cache-manifest。

cache manifest file 的起始點

  Manifest 文件中的資源必須以 URI 格式表示。所有列於 manifest 中的資源,他們的 scheme、host以及 port 都得和 manifest 文件一樣。

範例 1: 一個簡單的 cache manifest file

  這是一個簡單的範例, example.appcache, 我們假設他屬於 www.example.com

CACHE MANIFEST
+# v1 - 2011-08-13
+# This is a comment.
+http://www.example.com/index.html
+http://www.example.com/header.png
+http://www.example.com/blah/blah
+

  一個 manifest 檔案可以有三種不同的段落 - CACHENETWORK 以及 FALLBACK (容後再敘)。在 example.appcache 中我們並未指定段落名,是以所有資源會被以預設方式解析,也就是「需要被加到快取」(意義上屬於 CACHE 段)。如前所提到,資源可以用相對或絕對路徑表示(例如可以把 http://www.example.com/index.html 改為 index.html)。

  在這裡要特別指出被放置在註解中的「v1」字樣。顯然他表達的是版本資訊。但在 manifest 中這樣的表達方式有大用。假設今天 header.png 改變了,你只需要改動版本資訊 (或註解中的內容),則此 manifest 就會被認為有改變而使得瀏覽器重新抓取快取。當然你可以改動檔案中的其他部分,可是改變版本號是比較建議的方式。

重要提醒: 請勿將 manifest 檔案本身也列在 manifest 內容中,否則將使瀏覽器無法辦別 manifest 是否已被更新。這將使整個 application cache 機制失效。

cache manifest file 中的分類段落: CACHENETWORK, and FALLBACK

  在 manifest 中我們可以有三種不同的段落: CACHE、 NETWORK 以及 FALLBACK。

CACHE:
這是預設的段落。列於 CACHE 段落下的資源列表將在使用者第一次造訪時就被加到快取中。
NETWORK:
列於這個段落的資源表示一定得透過網路抓取而不從快取取得。可以使用萬用字元表示內容。
FALLBACK:
FALLBACK 指出了一種替代關係。在這個段落裡的每一行都有兩種 URI,其一指名有網路連線時使用的資源,第二個則是斷線時使用。這兩個 URI 的根目錄必須是相對於 manifest。可以使用萬用字元表示內容。

  這三種不同段落可以以任意順序出現在 manifest 中,並且都可出現多次而無次數限制。

範例 2: 稍微複雜點的 cache manifest file

  這裡我們來看看稍微複雜點的 manifest。他存在於一個虛擬的網站 www.example.com

CACHE MANIFEST
+# v1 2011-08-14
+# This is another comment
+index.html
+cache.html
+style.css
+image1.png
+
+# Use from network if available
+NETWORK:
+network.html
+
+# Fallback content
+FALLBACK:
+/ fallback.html
+

  這個範例中使用了 NETWORK 以及 FALLBACK:

  • NETWORK:network.html 只能透過網路取回而不從快取。
  • FALLBACK:倘若沒有網路連線就使用 fallback.html (這裡寫法意思是說無法讀取到網站的/ ,也就是無法顯示網站)

cache manifest file 的結構

  Cache manifest 檔案應該被定義成 text/cache-manifest 的 MIME 格式。而所有被定義成 text/cache-manifest MIME 格式的檔案將被以本章所規範的語法解析。

  首先,Cache manifests 必須是一個 UTF-8 格式的文字檔。檔案中可以被嵌入 BOM (Byte-Order Mark)字元,舉例來說,換行會被表示成 「line feed (U+000A)」、「 carriage return (U+000D)」或 「carriage return 及 line feed both」。

  第二,cache manifest 的第一行必須是「CACHE MANIFEST」字串 (CACHE 和 MANIFEST 中間的那個空白是一個 U+0020 符號),其後可以任意加入 space 或 tab 字符。以這一行來說,其他被加入的字串將會被忽略。

  最後,檔案中的剩餘部份是由零至多個下列所述的項目構成:

Blank line
空白行。你可以任意用 space 或 tab 去產生新的一行。
Comment
註解。指的是以 # 起始的行。要注意 # 只在該行有效,你不能在後附加上其他行 (若你有多行註解,請在每行起始都加上 #)。
Section header
段落標頭。這裡指的是在前面我們討論過 CACHE、 NETWORK 以及 FALLBACK:
Section header Description
CACHE: 其後內容指出哪些資源需要被加到瀏覽器的快取中
NETWORK: 其後內容指出哪些資源一定得從網路取得
FALLBACK: 其後內容指出資源在有網路連線及斷線時的替代關係
段落標頭行可以含有空白,但要記得在最後加上 「:」字元。
Section data
段落資料。其格式隨著不同段落而有所不同。在 CACHE 段落,每一行必須是符合規則的 URI 或 IRI (IRI 類似於 URI,但可使用 unicode),此外,在 CACHE 段落中不得使用萬用字元,但可自由使用空白 (前提自然是不能破壞 URI/IRI 內容)。而在 NETOWKR 段落中,其內容為符合規則之 URI/IRI,並可以使用萬用字元。最後,在 FALLBACK 段落,其每一行的構成是先寫出合於規則的 URI/IRI,接著寫出倘若網路不通時該用何資源取代。
注意:倘若使用相對路徑的 URI,那麼其相對的位置是「cache manifest 檔案的 URI」。

  Cache manifest 檔是以上述三種段落來依序判讀,是以每一段落可出現一次以上。甚至你也可以寫出內容為空的段落。

Application cache 中的資源

  Application cache 總是含有至少一個資源,並以 URI 形式敘述。下面列出資源種類,manifest 中的資源必屬其中。

Master entries
這是一個瀏覽的入口,其引用了 manifest 檔案。
Explicit entries
描述 CACHE 段落的入口。
Network entries
描述 NETWORK 段落的入口。
Fallback entries
描述 FALLBACK 段落的入口。
注意: R同一種資源可以屬於多種不同種類,例如一個 entry 可以同時是 explicit entry 和 fallback entry。

 關於這些資源種類,下面會有更詳細的說明。

Master entries

  Master entries 是一種在他們 {{ HTMLElement("html") }} element 中含有 {{ htmlattrxref("manifest","html") }} attribute 的 HTML 檔。舉例來說,如果我們說我們有一個 http://www.example.com/entry.html 的 HTML 檔,其內容為:

<html manifest="example.appcache">
+  <h1>Application Cache Example</h1>
+</html>
+

如果 entry.html 並未被列在 example.appcache 中,幫妳拜訪 entry.html 時,他就會被加到 application cache 中,並被指明為一個 master entry。

Explicit entries

  這指出了哪些檔案需要被存到快取中。

Network entries

  這指出了哪些檔案一定得透過網路取得。可以看成是列出了一張線上白名單 (online whitelist),提示了有些東西必須得透過網路向伺服器抓取。這有很多好處,其中一個好處是可以避開些安全漏洞,避免某些認證結果從本地端讀取而造成危險 (如果這個認證結果被竄改的話 ... )。

  這裡有個例子,你可以要求執行的腳本一定得透過網路向伺服器抓取:

CACHE MANIFEST
+NETWORK:
+/api
注意: Simply有人可能會覺得「一定向伺服器抓取資料」的這件事也可以透過把他們放置在 master entry 達成,但事實上 master entry 會被加入到 application cache 中。

Fallback entries

   Fallback entry 的使用時機在於網路可能斷線。直接看例子,當我們說有個 manifest (http://www.example.com/example.appcache),其檔案內容是:

CACHE MANIFEST
+FALLBACK:
+example/bar/ example.html
+

任何企圖抓取 http://www.example.com/example/bar/ 或其子資料夾的請求若是失效,瀏覽器會讀取 example.html 作為替代。

Cache 的狀態

  每一個 application cache 都有一個 state,表明目前在瀏覽器端的狀態。共用同一個 manifest URI 的 cache 擁有一樣的狀態。狀態的種類如下:

UNCACHED
這是特殊的一個狀態,代表 cache 物件尚未初始化。
IDLE
代表 cache 並非處於更新中的狀態。
CHECKING
目前正在向伺服器端抓取 manifest 檔案以確認是否接下來要有更新資源的動作。
DOWNLOADING
因為 manifest 的更新,資源已經被下載到本地端的快取中。
UPDATEREADY
有一個新版的 application cache 是可用的狀態。這搭配著 updateready 的事件。相對於 cached 事件,他的意思是有新版的更新已經在本地,但尚未呼叫 swapCache()函式。
OBSOLETE
Application cache 群組現在處於過時的狀態。

測試 cache manifest 的更新

  你可以經由撰寫 JavaScript 程式來關注是否 manifest 檔有所更新。但未免在你漏失在 Listener 完成註冊之前就完成的事件,務必檢查 window.applicationCache.status。如下所示:

function onUpdateReady() {
+  alert('found new version!');
+}
+window.applicationCache.addEventListener('updateready', onUpdateReady);
+if(window.applicationCache.status === window.applicationCache.UPDATEREADY) {
+  onUpdateReady();
+}

   倘若你想手動的去測試 manifest 檔案是否更新,你可以使用 window.applicationCache.update()。

注意 !!!

  • 當 application cache 的機制被啟動,程式撰寫員無法簡單的透過更新資源本身就取得目前伺服器上最新的版本 (或許你已經自本地端快取讀出資源了!)。你必須在瀏覽器讀取資源之前就更新 manifest 檔。這個動作可以透過 window.applicationCache.swapCache() 達到,但在此刻已經被讀取的資源將不受影響。最好的方式是重新刷新頁面。
  • 一個好的主意是是為你伺服器上所有副檔名為 appcache 的檔案設定為已經失效 (set expires headers)。這可以避免 manifest 被加到快取中的風險。以 Apache 為例,你可以這麼做:
    ExpiresByType text/cache-manifest "access plus 0 seconds"

支援 Application Cache 的瀏覽器們

{{ CompatibilityTable() }}

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 4.0 3.5 10.0 10.6 4.0
Feature Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support 2.1 {{ CompatUnknown() }} {{ CompatNo() }} 11.0 3.2

附註:先於 3.5 版以前的FireFox 忽略了 manifest 檔案中 NETWORK 以及 FALLBACK 的部分。

參考資料

{{ HTML5ArticleTOC() }}

{{ languages( { "es": "es/Recursos_offline_en_firefox", "fr": "fr/Ressources_hors_ligne_dans_Firefox", "ja": "ja/Offline_resources_in_Firefox", "pl": "pl/Zasoby_offline_w_Firefoksie", "zh-tw": "zh_tw/Offline_resources_on_Firefox" } ) }}

+
diff --git a/files/zh-tw/games/index.html b/files/zh-tw/games/index.html new file mode 100644 index 0000000000..aa2ab96a05 --- /dev/null +++ b/files/zh-tw/games/index.html @@ -0,0 +1,85 @@ +--- +title: 遊戲開發 +slug: Games +translation_of: Games +--- +
{{GamesSidebar}}
+ +
+

遊戲絕對是最受歡迎的電腦功能之一。而相關技術不斷推陳出新,讓玩家在任何相容標準的網路瀏覽器上,也能盡情享受畫質更優、效能更好的遊戲。

+
+ +
{{EmbedGHLiveSample("web-tech-games/index.html", '100%', 820)}}
+ +
+
+

web 遊戲開發

+ +

歡迎來到 MDN 遊戲開發中心!我們將給想要開發遊戲的 web 開發者,提供 web 遊戲開發相關的資源。你會找到很多有用的教學與技術文章,所以請盡情瀏覽。

+ +

我們也涵蓋了參考的章節,你可以從那裡找到遊戲開發最需要用到的一些 API。

+ +
注:建立遊戲會需要用上一些 web 的核心技術,如 HTML、CSS、JavaScript。學習專區會是個很好的學習區域。
+
+ +
+

從原生到 Web

+ +

如果你是原生介面開發者(例如,你寫 C++ 的遊戲)、對於怎麼把遊戲移植到 Web 有興趣的話,請看看我們的工具 Emscripten:這是個 LLVM 轉到 JavaScript 的編譯器,它使用了 LLVM 位元碼(例如,使用 Clang 從 C/C++ 產生。其他語言亦可)並編譯到能在 Web 運行的 asm.js

+ +

要入門請參見:

+ + +
+
+ +
+
+

示例

+ +

需要 web 遊戲的示例,請參考我們的 示例頁。也請參考下 openwebgames.com 以獲取更多資源與示範!

+
+
+ +

+ +

參見

+ +
+
+
+
Build New Games
+
A collaborative site featuring a large number of open web game development tutorials. Has not been very active recently, but still holds some nice resources.
+
Creative JS
+
A collection of impressive JavaScript techniques and experiments, not specific to games, but helpful nonetheless. Has not been very active recently, but still holds some nice resources.
+
Game programming patterns
+
An online book, written by Bob Nystrom, which discusses programming patterns in the context of game development with the aim of helping game developers produce more effective and efficient code.
+
Gamedev.js Weekly
+
Weekly newsletter about HTML5 game development, sent every Friday. Contains the latest articles, tutorials, tools and resources.
+
HTML5 Game Devs Forum
+
Forums for developers, framework creators and publishers. Ask questions, get feedback and help others.
+
+
+ +
+
+
HTML5 Game Engine
+
List of the most popular HTML5 game frameworks along with their rating, features and samples.
+
JSBreakouts
+
Compare JavaScript Breakout clones in different frameworks to help you choose the right one for you.
+
Tuts+ Game Development
+
Tutorials and articles about game development in general.
+
HTML5 Gamedev Starter
+
Starter for the new game developers, a curated list of links to various, useful resources around the web.
+
js13kGames
+
JavaScript coding competition for HTML5 game developers with the file size limit set to 13 kilobytes. All the submitted games are available in a readable form on GitHub.
+
Mozilla Hacks blog
+
Games category on the Mozilla Hacks blog containing interesting gamedev related articles.
+
+
+
+
diff --git a/files/zh-tw/games/introduction/index.html b/files/zh-tw/games/introduction/index.html new file mode 100644 index 0000000000..c140521931 --- /dev/null +++ b/files/zh-tw/games/introduction/index.html @@ -0,0 +1,122 @@ +--- +title: Web 遊戲開發介紹 +slug: Games/Introduction +tags: + - Firefox OS + - Games + - Guide + - Mobile +translation_of: Games/Introduction +--- +
{{GamesSidebar}}
{{IncludeSubnav("/zh-TW/docs/Games")}}
+ +
現有 Web 環境已成為多元的平台,不只可建構令人驚艷的高品質遊戲,也是發佈這些遊戲的重要媒介。
+ +
 
+ +
可供撰寫的遊種類......
+ +

現有的 Web 技術再搭配最新版瀏覽器,就能打造出絕佳的 Web 遊戲,而且我們講的可不是用 Flash® 寫的簡單卡牌遊戲,或是多人的社交遊戲而已。卻是可打趴一堆平面遊戲的 3D 動作射擊或角色扮演遊戲。多虧 JavaScript 的即時 (Just-in-time,JIT) 技術與新 API 雙雙大幅提升其效能,你所撰寫的遊戲已可於瀏覽器 (或支援 HTML5 的裝置,即如 Firefox OS) 中執行,卻又不致犧牲任何效能。

+ +

HTML5 遊戲平台

+ +

如同 Mozilla 常說的「Web 即是平台」,你可將 Web 想像為較佳的遊戲平台。接著就來看看 Web 平台的核心:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能技術
音效Web Audio API
圖形WebGL (OpenGL ES 2.0)
輸入觸控事件Gamepad API、裝置感測器、WebRTCFull Screen APIPointer Lock API
程式語言JavaScript(或 C/C++ 可透過Emscripten 編譯為 JavaScript)
網路連線WebRTC 及/或 WebSockets
儲存功能IndexedDB 或雲端
WebHTMLCSSSVGSocial API(還有更多!)
+ +

 

+ +

商業案例

+ +

不論你是獨立或大型遊戲工作室的開發者,你都應該將 Web 作為自己下一個遊戲專案的系統。先來看看 Web 能對你提供多少優勢:

+ +
    +
  1. +
    Web 無遠弗屆,而用 HTML5 撰寫的遊戲可自由在桌機、平板電腦、智慧電視、智慧型手機上執行。
    +
  2. +
  3. 可獲得更好的行銷與露出機會。你不再限制於某個 App 商店才能推廣自己的 App;反而能透過 Web 上的所有媒體推銷遊戲,並利用 Web 的串連與分享效率接觸到新客戶。
  4. +
  5. 你能控制「付款」這個重要的作業。之前只要你的遊戲放在某個生態系統中,就必須支付超過 30% 的收益給該系統。但現在你可選擇自己喜歡的 App 訂價與付款服務。
  6. +
  7. 同樣的,你也能自行控制 App 的更新頻率,而不再需要枯等別人審核你的重要修正檔,還不知道今天還明天才能上架。
  8. +
  9. 控制你的分析方式!你能蒐集自己所需的資料,或可選擇你所愛用的第三方,進而獲得你的銷售資訊以及所觸及的消費族群;不需再讓別人幫你決定分析方法。
  10. +
  11. 你能進一步管理自己與消費者之間的關係,不再受限於 App 商城的機制而取得篩選過的反饋意見。也不需再經過中間人,就能以自己的方式和消費者直接交流。
  12. +
  13. 玩家隨時隨地都能暢玩你的遊戲。因為 Web 無所不在,消費者能在自己的手機、平板電腦、家裡桌機、辦公室電腦,或任何地方觀看遊戲進度。
  14. +
+ +

遊戲開發者所應知道的 Web 技術

+ +

我們要為開發者提供 API 的相關資訊,了解 Web 帶來的絕妙開發功能。
+ 以下只列舉出其中數項:

+ +
+
+
Full Screen API
+
此簡易 API 可讓遊戲全螢幕運作,提供玩家絕佳的動作體驗。
+
Gamepad API
+
如果要讓遊戲搭配搖桿或其他類型的控制器,就用這個 API。
+
HTMLCSS
+
這兩種技術可用以建立遊戲的使用者介面,並設定其風格與配置方式。部分的 HTML 即為 {{HTMLElement("canvas")}} 元素,可直接建構 2D 圖形。
+
HTML audio
+
{{HTMLElement("audio")}} 元素可輕鬆播放簡易音效與音樂。如果需要進一步效果,可參閱 Web Audio API 達到真正的音訊處理效能!
+
IndexedDB
+
此強大的資料儲存 API,可將使用者的資料保存於電腦或其他裝置之上,亦可於本端儲存遊戲資料與其他資訊;如此可避免每次都需再下載資料一次。即使目前處於無網路連線的狀態 (例如飛機上長達數個小時的旅程...),也同樣可以玩遊戲 。
+
JavaScript
+
JavaScript 就是 Web 上使用的程式語言,可於現有瀏覽器上達到絕佳速度,且目前還在不斷的提升。你可寫出遊戲的程式碼,或可透過如 EmscriptenAsm.js 的技術,輕鬆移植現有的遊戲。
+
Pointer Lock API
+
Pointer Lock API 可鎖定遊戲介面中的滑鼠或其他指向裝置。取代之前的絕對游標定位,現可接收座標差而得到更精確的使用者動作,並避免使用者突然在他處輸入,卻遺漏了重要動作。
+
SVG (Scalable Vector Graphics,可縮放向量圖形)
+
可建構向量圖形,根據裝置畫面的解析度而順暢調整。
+
Typed Array (具型別陣列)
+
JavaScript 的具型別陣列,可讓你在 JavaScript 中存取原始的二進位資料。如此可讓你設定 GL 紋理 (Texture)、遊戲資料,或其他物件。甚至非原生 JavaScript 格式的亦可處理。
+
Web Audio API
+
此 API 可透過 JavaScript 程式碼控制音訊的回播、合成、操作等作業,讓你建構絕妙音效並即時播放音樂。
+
WebGL
+
可於 Web 內容中建立高效能、硬體加速的 3D (與2D) 圖像。此為 Web 所支援的 OpenGL ES 2.0 實作。
+
WebRTC
+
WebRTC (Real-Time Communications) API 可控制音訊與視訊資料 (包含視訊會議),並能在兩名使用者之間來回傳輸其他應用程式的資料。想讓玩家能一邊爆怪物的頭還一邊交談?就用這個 API 吧。
+
WebSockets
+
WebSocket API 可讓你的 App 或網站連上伺服器,進而即時來回傳輸資料。適用於多人遊戲、聊天服務等。
+
Web Workers
+
Workers 可讓你分配背景執行緒,執行本身所屬的 JavaScript 程式碼,藉以利用新的多核心處理器。
+
XMLHttpRequest and File API
+
整合的 XMLHttpRequest 與 File API,可你從 Web 伺服器接收或傳送所需的任何資料 (別因為「XML」搞混了)。如此能順利下載新的遊戲關卡與圖片,藉以來回傳輸非即時的遊戲狀態資訊。
+
+
+ +

 

diff --git a/files/zh-tw/games/techniques/index.html b/files/zh-tw/games/techniques/index.html new file mode 100644 index 0000000000..66edeebd82 --- /dev/null +++ b/files/zh-tw/games/techniques/index.html @@ -0,0 +1,32 @@ +--- +title: Techniques for game development +slug: Games/Techniques +tags: + - Games + - Guide + - NeedsTranslation + - TopicStub +translation_of: Games/Techniques +--- +
{{GamesSidebar}}
{{IncludeSubnav("/en-US/docs/Games")}}
+ +
+

This page lists essential core techniques for anyone wanting to develop games using open web technologies.

+
+ +
+
Using async scripts for asm.js
+
Especially when creating medium to large-sized games, async scripts are an essential technique to take advantage of, so that your game's JavaScript can be compiled off the main thread and be cached for future game running, resulting in a significant performance improvement for your users. This article explains how.
+
Optimizing startup performance
+
How to make sure your game starts up quickly, smoothly, and without appearing to lock up the user's browser or device.
+
Using WebRTC peer-to-peer data channels
+
In addition to providing support for audio and video communication, WebRTC lets you set up peer-to-peer data channels to exchange text or binary data actively between your players. This article explains what this can do for you, and shows how to use libraries that make this easy.
+
Efficient animation for web games
+
This article covers techniques and advice for creating efficient animation for web games, with a slant towards supporting lower end devices such as mobile phones. We touch on CSS transitions and CSS animations, and JavaScript loops involving {{ domxref("window.requestAnimationFrame") }}.
+
Audio for Web Games
+
Audio is an important part of any game — it adds feedback and atmosphere. Web-based audio is maturing fast, but there are still many browser differences to negotiate. This article provides a detailed guide to implementing audio for web games, looking at what works currently across as wide a range of platforms as possible.
+
2D collision detection
+
A concise introduction to collision detection in 2D games.
+
Tilemaps
+
Tiles are a very popular technique in 2D games for building the game world. These articles provide an introduction to tilemaps and how to implement them with the Canvas API.
+
diff --git a/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.html b/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.html new file mode 100644 index 0000000000..62a57f6440 --- /dev/null +++ b/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.html @@ -0,0 +1,98 @@ +--- +title: 讓球碰到牆壁後反彈 +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls +--- +
{{GamesSidebar}}
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls")}}

+ +
+

這是 Gamedev Canvas tutorial中的第三步 你可以在以下的連結中查看原始碼Gamedev-Canvas-workshop/lesson3.html.

+
+ +

很好我們現在可以讓球移動了, 但目前他會在移動到邊緣後消失, 這使我們少了點樂趣! 為了解決這個問題我們稍後會加入一些碰撞處理 ( later ) 使球可以再碰到邊緣時反彈.

+ +

簡單的碰撞偵測

+ +

為了偵測碰撞的發生,我們將檢查球是否接觸(相撞)牆壁,如果有碰到,我們將改變球的行進方向。

+ +

為了方便計算,我們定義一變數 ballRadius 代表球的半徑。在你程式碼宣告變數的地方加入以下內容:

+ +
var ballRadius = 10;
+ +

接著更新繪製球的 drawBall() 函數,加入以下內容:

+ +
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
+ +

從頂部和底部反彈

+ +

總共有四面牆壁會與球發生碰撞 — 首先處理上方的牆壁,我們在每個影格檢查球是否有接觸到 Canvas 上方壁面 —如果是的話,我們將扭轉球的運動,所以它將開始在相反的方向移動,並保持在可見邊界。記住坐標係從左上角開始,我們可以得到這樣的東西:

+ +
if(y + dy < 0) {
+    dy = -dy;
+}
+ +

如果球位置的Y值低於零,改變Y軸上的運動的方向,通過設置它等於本身,扭轉。如果球是向上移動的速度為每幀的2個像素,現在它將移動“了”的速度為- 2像素,這實際上等於在每幀的2個像素的速度向下移動。

+ +

上面的代碼將處理球反彈的頂部邊緣,所以現在讓我們想想下邊緣:

+ +
if(y + dy > canvas.height) {
+    dy = -dy;
+}
+ +

如果球的Y位置大於畫布的高度(請記住,我們計算從左上角的Y值,所以頂部邊緣開始在0和底部邊緣是在480像素,畫布的高度),然後通過反轉的Y軸運動的底部邊緣,如前。
+ 我們可以將這兩個語句為一個節省代碼冗長:

+ +
if(y + dy > canvas.height || y + dy < 0) {
+    dy = -dy;
+}
+ +

如果兩個語句中的一個是真的,則反轉球的運動。

+ +

從左邊和右邊反彈

+ +

我們有頂部和底部邊緣覆蓋,所以讓我們想想左,右的。它實際上是非常相似的,你所要做的就是重複X而不是Y的陳述:

+ +
if(x + dx > canvas.width || x + dx < 0) {
+    dx = -dx;
+}
+
+if(y + dy > canvas.height || y + dy < 0) {
+    dy = -dy;
+}
+ +

在這一點上你應該插入上面的代碼塊到draw()功能,在關閉括號。

+ +

球不斷地消失在牆上!

+ +

測試你的代碼在這一點上,你會留下深刻的印象-現在我們有一個球,反彈了所有四個邊緣的畫布!然而,我們有另一個問題-當球擊中每一個牆,它下沉到它略有改變方向:

+ +

+ +

這是因為我們計算的牆壁和球的中心的碰撞點,而我們應該做它的圓周。球應該反彈後,如果接觸牆,而不是當它已經在牆上的一半,所以讓我們調整我們的陳述有點包括。更新您添加到的最後一個代碼:

+ +
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
+    dx = -dx;
+}
+if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
+    dy = -dy;
+}
+ +

當球的中心與牆的邊緣之間的距離與球的半徑完全相同時,它會改變運動方向。從邊緣減去一個半徑的寬度以及添加到另一個方向給我們在碰撞檢測在中球彈回牆壁的印象。

+ +

比較你的程式碼

+ +

讓我們用剛剛所學的再次檢查完成的程式碼,並把玩一下:

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/redj37dc/","","370")}}

+ +
+

Exercise: 每次球撞到牆上時嘗試改變球的顏色為隨機的顏色。

+
+ +

下一步

+ +

我們現在已經進入了舞台,我們的球是移動和停留在遊戲板上。 在第四章中,我們將討論實現一個可控制的球拍 - 參見 Paddle and keyboard controls.

+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls")}}

diff --git a/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.html b/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.html new file mode 100644 index 0000000000..a9ffc103a7 --- /dev/null +++ b/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.html @@ -0,0 +1,118 @@ +--- +title: 建立Canvas並畫出 +slug: >- + Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it +tags: + - 2D + - Beginner + - Canvas + - Games + - HTML + - JavaScript + - Tutorial +translation_of: >- + Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball")}}

+ +
+

這是Gamedev Canvas tutorial十個步驟的第一步。你可以這份教學的原始碼,當你完成這份教學你的程式碼應該跟Gamedev-Canvas-workshop/lesson1.html差不多。

+
+ +

在開始撰寫遊戲功能之前,我們先建構在遊戲中負責渲染的基礎結構。渲染可透過HTML的{{htmlelement("canvas")}} 元件完成。

+ +

遊戲的HTML

+ +

當整個遊戲透過{{htmlelement("canvas")}} 元件渲染時,HTML檔案結構就會相當簡單。用你最喜歡的文字編輯器打開新的HTML檔,將它命名為index.html並存在適當的位置上,再將下面的的程式碼貼到index.html中:

+ +
<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8" />
+    <title>Gamedev Canvas Workshop</title>
+    <style>
+    	* { padding: 0; margin: 0; }
+    	canvas { background: #eee; display: block; margin: 0 auto; }
+    </style>
+</head>
+<body>
+
+<canvas id="myCanvas" width="480" height="320"></canvas>
+
+<script>
+	// JavaScript code goes here
+</script>
+
+</body>
+</html>
+
+ +

在header中設定了文字編碼、以及{{htmlelement("title")}}和一些CSS樣式。在body中包含{{htmlelement("canvas")}}與{{htmlelement("script")}},前者將用來渲染遊戲畫面,後者將用來撰寫JavaScript程式控制渲染。{{htmlelement("canvas")}}元件有個id為myCanvas方便當作參考(reference,如許多程式語言中的變數)讓我們設定它的寬度為480 pixels與高度320 pixels,這份教學中全部的JavaScript 程式碼都會寫在<script>開始標記與</script>結束標記中間。

+ +

Canvas基礎

+ +

為了能夠順利渲染圖形在{{htmlelement("canvas")}}元件中,獲得{{htmlelement("canvas")}}元件的參考。請將下列的程式碼加在<script>開始標記的後面。

+ +
var canvas = document.getElementById("myCanvas");
+var ctx = canvas.getContext("2d");
+ +

我們將{{htmlelement("canvas")}}元件的參考存成變數canvas為了未來使用。建立ctx變數儲存"2D渲染環境",ctx變數實際拿來繪製Canvas的工具。

+ +

以下片段的程式範例在canvas上印出紅色正方形。將以下的程式加在上面J的avaScript程式碼之後,再用瀏覽器打開index.html測試。

+ +
ctx.beginPath();
+ctx.rect(20, 40, 50, 50);
+ctx.fillStyle = "#FF0000";
+ctx.fill();
+ctx.closePath();
+ +

所有的指令都介於{{domxref("CanvasRenderingContext2D.beginPath()","beginPath()")}}與{{domxref("CanvasRenderingContext2D.closePath()","closePath()")}}。我們用{{domxref("CanvasRenderingContext2D.rect()","rect()")}}定義了一個矩形,{{domxref("CanvasRenderingContext2D.rect()","rect()")}}中前兩個數值代表左上角的座標。在上面的情況中,矩形距離左邊20 pixels,距離畫面上方40 pixels,50 pixels寬,50 pixels高,形成完美的正方形。{{domxref("CanvasRenderingContext2D.fillStyle","fillStyle")}}屬性所儲存的顏色會被{{domxref("CanvasRenderingContext2D.fill()","fill()")}}方法用來塗滿正方形,在此為塗上紅色。

+ +

不僅矩形— 以下的程式碼印出綠色的圓形。試著將程式碼加在JavaScript底部,存檔在重新整理瀏覽器中的index.html:

+ +
ctx.beginPath();
+ctx.arc(240, 160, 20, 0, Math.PI*2, false);
+ctx.fillStyle = "green";
+ctx.fill();
+ctx.closePath();
+ +

如同你看到的我們再次使用了{{domxref("CanvasRenderingContext2D.beginPath()","beginPath()")}}與{{domxref("CanvasRenderingContext2D.closePath()","closePath()")}}。在它們中間最重要的程式碼是{{domxref("CanvasRenderingContext2D.arc()","arc()")}}。{{domxref("CanvasRenderingContext2D.arc()","arc()")}}用到六個參數(依序介紹):

+ + + +

{{domxref("CanvasRenderingContext2D.fillStyle","fillStyle")}}看起來與之前不同,原因就像CSS一樣可以用16進位、顏色關鍵字、rgba()函式等其他可用的顏色指定方法。

+ +

不但有{{domxref("CanvasRenderingContext2D.fill()","fill()")}}填滿圖形,還有 {{domxref("CanvasRenderingContext2D.stroke()","stroke()")}} 專門為外輪廓線上色。也試著加入下面的JavaScript程式碼吧:

+ +
ctx.beginPath();
+ctx.rect(160, 10, 100, 40);
+ctx.strokeStyle = "rgba(0, 0, 255, 0.5)";
+ctx.stroke();
+ctx.closePath();
+ +

上面的程式碼印出藍色邊框的空心矩形,由於在rgba()函式的alpha通道,藍色邊框呈現半透明。

+ +

比較你的程式碼

+ +

這裡第一課的有全部原始碼,在JSFiddle上實際運行:

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/x62h15e2/","","370")}}

+ +
+

Exercise: 練習改變物體的大小和顏色

+
+ +

下一步

+ +

現在我們已經設定基本的HTML並且學了一些canvas知識 ,讓我們接著下去第二章實做如何在遊戲中移動球

+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball")}}

diff --git a/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/index.html b/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/index.html new file mode 100644 index 0000000000..38815969bc --- /dev/null +++ b/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/index.html @@ -0,0 +1,57 @@ +--- +title: 只使用 JavaScript 的 2D 打磚塊遊戲 +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Tutorial +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript +--- +
{{GamesSidebar}}
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

{{Next("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it")}}

+ +

本文將帶你逐步做出簡單的 MDN 打磚塊遊戲。除了只用 JavaScript 寫成之外,也透過 HTML5 的 {{htmlelement("canvas")}} 繪製。

+ +

每個步驟均提供可測試修改的實際範例,讓你能看到各個步驟所產生的影響。你將了解該如何使用 {{htmlelement("canvas")}} 元件完成基礎的遊戲機制,例如繪製 (Render)、移動圖形、碰撞偵測、操控機制、輸贏狀態等。

+ +

若要能充分了解此一系列文章,你應具備基礎至中等的 JavaScript 知識。結束此教學之後即可寫出自己的簡易網頁遊戲。

+ +

Gameplay screen from the game MDN Breakout where you can use your paddle to bounce the ball and destroy the brick field, with keeping the score and lives.

+ +

課程細節

+ +

所有課程和其他不同版本的 MDN打磚塊遊戲,均可至 GitHub 找到:

+ +
    +
  1. 建立 Canvas 並繪製
  2. +
  3. 讓球移動
  4. +
  5. 讓球反彈
  6. +
  7. 搖桿和鍵盤控制
  8. +
  9. 判斷遊戲結束
  10. +
  11. 建立磚塊場地
  12. +
  13. 碰撞偵測
  14. +
  15. 更新分數並判斷輸贏
  16. +
  17. 滑鼠控制
  18. +
  19. 結束
  20. +
+ +

若一開始就單純使用 JavaScript,將能學到紮實的網頁遊戲開發知識。往後則可自由選擇你自己愛用的框架 (Framework) 來完成專案。
+ 框架同樣是由 JavaScript 寫成的工具。因此在用框架開發之前,能先了解程式語言本身將有助於了解框架內部所發生的事。框架可加快開發速度並代勞遊戲中某些無聊的部份,但若遊戲運作得不如預期,你都可試著除錯或撰寫純 JavaScript 的解決方案。

+ +
+

注意:如果你對 2D 網頁遊戲開發的遊戲函式庫有興趣,可參考此〈使用剖析器 (Phaser) 的打磚塊遊戲〉系列相關文章 。

+
+ +
+

注意:此系列文章也能當做行動遊戲開發工作坊的教材。如果你想講解一般的遊戲開發,則可利用此教學為基礎的〈Gamedev Canvas Content Kit〉。

+
+ +

下一步

+ +

好吧!讓我們開始第一章 — 建立 Canvas 並繪製。

+ +

{{Next("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it")}} 

diff --git a/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.html b/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.html new file mode 100644 index 0000000000..37514c9c59 --- /dev/null +++ b/files/zh-tw/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.html @@ -0,0 +1,136 @@ +--- +title: 讓球移動 +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball +--- +
{{GamesSidebar}}
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls")}}

+ +
+

這一篇是Gamedev Canvas tutorial十個步驟中的第二步。當完成此步驟你的程式碼應該會與Gamedev-Canvas-workshop/lesson2.html差不多

+
+ +

完成上一個步驟,你已經知道如何畫出一顆球,現在讓他動起來吧。藉由繪製球在螢幕上然後再清除,然後在每個影格中繪製球在偏移一點點的位置上(如果在同一個位置上就等於沒動),造成物體移動的感覺,就如同電影中物體移動的方式。

+ +

定義一個繪製用的迴圈

+ +

為了固定更新 canvas 繪圖區域的每一個影格,我們需要定義一個繪製函式(drawing function),它將會重複執行,用不同的變數改變球的位置或其他物的位置。重複執行一個函式,其中使用 JavaScript timing function,像是 {{domxref("WindowTimers.setInterval()", "setInterval()")}} 或是 {{domxref("window.requestAnimationFrame()", "requestAnimationFrame()")}}.

+ +

除了前兩行的 JavaScript,其餘的都刪除,並將以下的程式碼加入在前兩行之後。draw()函數每十毫秒會被setInterval執行一次:

+ +
function draw() {
+    // drawing code
+}
+setInterval(draw, 10);
+ +

因為 setInterval 無限循環的特性, draw() 函數將會每 10 毫秒被呼叫一次除非我們將它停止。 現在,讓我們來把球畫出來 — 將以下程式碼加入到 draw() 函數內:

+ +
ctx.beginPath();
+ctx.arc(50, 50, 10, 0, Math.PI*2);
+ctx.fillStyle = "#0095DD";
+ctx.fill();
+ctx.closePath();
+
+ +

現在將你的程式碼更新 — 球將會在每個影格被重新繪製.

+ +

讓球動起來

+ +

由於球並沒有移動,你沒有辦法察覺到它正不斷的被重新繪製。讓我們稍作修改。首先,取代掉原本寫死的位置(50,50),我們宣告變數 x 和 y 讓球從 Canvas 正中央的底部出發,接著利用x和y來定義球應該被畫在哪裡。

+ +

首先將下面兩行程式碼加到你的 draw() 函數用以定義 x 和 y :

+ +
var x = canvas.width/2;
+var y = canvas.height-30;
+
+ +

接著修改 draw() 函數,在 {{domxref("CanvasRenderingContext2D.arc()","arc()")}} 方法裡使用了變數 x 和 y,就像下面被強調的那行程式碼:

+ +
function draw() {
+    ctx.beginPath();
+    ctx.arc(x, y, 10, 0, Math.PI*2);
+    ctx.fillStyle = "#0095DD";
+    ctx.fill();
+    ctx.closePath();
+}
+
+ +

再來是最重要的部分: 在每個影格被繪製出來後,我們想要對 x 和 y 增加一數值,讓球看起來好像在移動一樣。讓我們來定義這個數值為 dx 以及 dy,並且分別設為 2 以及 -2。將以下程式碼添加到你定義 x 和 y 的地方:

+ +
var dx = 2;
+var dy = -2;
+
+ +

最後,在每個影格中我們利用 dx 和 dy 來更新 x 和 y 的數值,球就會在每次更新後被畫到不同的位置。將最後兩行程式碼加到你的 draw()函數內:

+ +
function draw() {
+    ctx.beginPath();
+    ctx.arc(x, y, 10, 0, Math.PI*2);
+    ctx.fillStyle = "#0095DD";
+    ctx.fill();
+    ctx.closePath();
+    x += dx;
+    y += dy;
+}
+ +

儲存你的程式碼並在瀏覽器重新整理。程式正常運作,雖然球似乎留下的他的蹤跡:

+ +

+ +

在每個影格開始前清除 canvas

+ +

由於我們在每個影格繪製新的球之前並沒有把舊的清除掉,讓他看起來像留下了一條痕跡。別擔心,其實是有方法可以把 canvas 清除掉: {{domxref("CanvasRenderingContext2D.clearRect()","clearRect()")}}. 這個方法需要 4個參數:  前兩個參數代表了長方形左上角的 x和 y座標,後兩個參數代表了長方形右下角的 x 和 y 座標。之前在這長方形範圍內所繪製的東西將會被清除掉。

+ +

將以下強調的程式碼加到 draw() 函數內:

+ +
function draw() {
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    ctx.beginPath();
+    ctx.arc(x, y, 10, 0, Math.PI*2);
+    ctx.fillStyle = "#0095DD";
+    ctx.fill();
+    ctx.closePath();
+    x += dx;
+    y += dy;
+}
+
+ +

將程式碼儲存並重新整理瀏覽器,這次球沒有再留下痕跡了。每 10 毫秒 canvas 會被清除,球將會被畫在指定的位置上,且 x 和 y 會更新以用在下一個影格.

+ +

整理程式碼

+ +

再接續幾個章節我們會持續增加 draw() 函數內的指令,讓我們儘可能的維持程式的簡潔度。讓我們把繪製球的程式碼獨立為一個函數。

+ +

將原本的 draw() 函數拆成以下兩個函數:

+ +
function drawBall() {
+    ctx.beginPath();
+    ctx.arc(x, y, 10, 0, Math.PI*2);
+    ctx.fillStyle = "#0095DD";
+    ctx.fill();
+    ctx.closePath();
+}
+
+function draw() {
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    drawBall();
+    x += dx;
+    y += dy;
+}
+ +

比較你的程式碼

+ +

以下為到目前為止完整的程式碼,你可以核對並試著操作以幫助你更瞭解他的運作方式:

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/3x5foxb1/","","415")}}

+ +
+

Exercise: 練習改變球的移動速度或行進方向。

+
+ +

下一步

+ +

我們繪製了球並且讓他可以移動,但他仍會消失在 canvas 的邊緣。在第三章我們將會實作 讓球碰到牆壁後反彈.

+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls")}}

diff --git a/files/zh-tw/games/tutorials/index.html b/files/zh-tw/games/tutorials/index.html new file mode 100644 index 0000000000..d0ce8dfdf2 --- /dev/null +++ b/files/zh-tw/games/tutorials/index.html @@ -0,0 +1,25 @@ +--- +title: Workflows for different game types +slug: Games/Tutorials +tags: + - Canvas + - Games + - JavaScript + - NeedsTranslation + - TopicStub + - Web + - Workflows +translation_of: Games/Tutorials +--- +
{{GamesSidebar}}
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

This page contains articles that highlight different workflows for effectively creating different types of web games, whether you want to create a 2D or 3D game from scratch, or port a C++ or Flash game over to open web technologies.

+ +
+
2D breakout game using pure JavaScript
+
In this step-by-step tutorial you'll implement a simple breakout clone using pure JavaScript. Along the way you will learn the basics of using the {{htmlelement("canvas")}} element to implement fundamental game mechanics like rendering and moving images, collision detection, control machanisms, and winning and losing states.
+
2D breakout game using Phaser
+
In this step-by-step tutorial you'll implement the same breakout clone as the previous tutorial series, except that this time you'll do it using thePhaser HTML5 game framework. This idea here is to teach some of the fundamentals (and advantages) of working with frameworks, along with fundamental game mechanics.
+
2D maze game with device orientation
+
This tutorial shows how to create a 2D maze game using HTML5, incorporating fundamentals such as collision detection and sprite placement on a {{htmlelement("canvas")}}. This is a mobile game that uses the Device Orientation and Vibration APIs to enhance the gameplay and is built using the Phaser framework.
+
diff --git "a/files/zh-tw/gecko_dom_\345\217\203\350\200\203/tcpsocket/index.html" "b/files/zh-tw/gecko_dom_\345\217\203\350\200\203/tcpsocket/index.html" new file mode 100644 index 0000000000..a8ed5411b5 --- /dev/null +++ "b/files/zh-tw/gecko_dom_\345\217\203\350\200\203/tcpsocket/index.html" @@ -0,0 +1,140 @@ +--- +title: TCPSocket API +slug: Gecko_DOM_參考/TCPSocket +translation_of: Archive/B2G_OS/API/TCPSocket +--- +

此處將以 JavaScript 格式存取原始的 TCP socket API。此 API 目前僅可用於 FirefoxOS 許可/認證的 App。

+

進入點 (Entry point)

+
var TCPSocket = navigator.mozTCPSocket;
+if(TCPSocket){
+  // ...
+}
+

API

+
interface TCPSocket{
+  readonly attribute DOMString host;
+  readonly attribute unsigned short port;
+  readonly attribute boolean ssl;
+  readonly attribute unsigned long bufferedAmount;
+  readonly attribute DOMString binaryType;
+
+  readonly attribute DOMString readyState;
+  readonly attribute DOMString CONNECTING;
+  readonly attribute DOMString OPEN;
+  readonly attribute DOMString CLOSING;
+  readonly attribute DOMString CLOSED;
+
+  TCPSocket open(DOMString host, unsigned short port, [object options]);
+  void suspend();
+  void resume();
+  void close();
+  boolean send(in jsval data);
+
+  attribute onopen;
+  attribute ondrain;
+  attribute ondata;
+  attribute onerror;
+  attribute onclose;
+};
+

屬性 (Attributes)

+
+
+ host
+
+ Socket 所要連接的 Host。
+
+ port
+
+ Socket 所要連接的 Port。
+
+ ssl
+
+ Socket 是否經過 SSL 加密。
+
+ bufferedAmount
+
+ 位於 Socket 緩衝區內,尚未傳送資料的位元數。
+
+ readyState
+
+ Socket 狀態。可能為 {CONNECTING, OPEN, CLOSING, CLOSED}。
+
+

常數 (Constants)

+
+
+ CONNECTING
+
+ 該數值表示 Socket 的連結狀態。尚未無法傳送資料。
+
+ OPEN
+
+ 該數值表示 Socket 的開啟狀態。已可傳送資料。
+
+ CLOSING
+
+ 該數值表示 Socket 的關閉中狀態。
+
+ CLOSED
+
+ 該數值表示 Socket 的已關閉狀態。
+
+

函式 (Method)

+
+
+ open(host, port [, options])
+
+ 所回傳的新 TCP Socket,均已於指定的 port 連上指定的 hostOptions 將作為正規物件。以下為可用選項:
+
+ +
+
+ send(data)
+
+ 將緩衝所要傳送至網路的資料。若可安全緩衝更多資料,則將回傳 true。若是回傳 false,即代表將緩衝更多資料。但若要達到較佳效能 (保持較小緩衝),則應等待下個 drain 事件以緩衝更多資料。
+
+ suspend()
+
+ 暫停 data 事件。
+
+ resume()
+
+ 繼續 data 事件。若於 Socket 並未暫停的情況下而呼叫此方式,隨即將丟出錯誤。
+
+ close()
+
+ 關閉 TCP Socket。
+
+

事件 (Events)

+

透過 on* 屬性,可將 Event Listener 附加至 Socket。

+
+
+ open
+
+ 在此事件之後,Socket 即準備好傳送/接收資料。
+
+ drain
+
+ Socket 中可緩衝更多資料。
+
+ error
+
+ 發生錯誤。在 open 事件之前,將拒絕連結作業 (不會發生 close 事件)。在 open 事件之後,就會遺失連結作業 (事件之後隨即觸發 close 事件)
+
+ data
+
+ 已接受到某些資料。事件的物件將包含 data 屬性,以利檢索資料。在建立 Socket 時,即已設定資料型態。
+
+ close
+
+ 已關閉 Socket。
+
+

敘述 (Description)

+

此 API 僅可用於 FirefoxOS 許可/認證過的 App。而其指涉的 Host 與 Port 均必須由 app manifest 所提及。

+

僅限認證過的 App 可用 1024 以下的 Port。

+

另請參閱

+ diff --git a/files/zh-tw/glossary/404/index.html b/files/zh-tw/glossary/404/index.html new file mode 100644 index 0000000000..d655abe4c5 --- /dev/null +++ b/files/zh-tw/glossary/404/index.html @@ -0,0 +1,16 @@ +--- +title: '404' +slug: Glossary/404 +tags: + - Glossary + - HTTP Errors +translation_of: Glossary/404 +--- +

404 為標準回應碼,代表 {{Glossary("Server", "伺服器")}} 沒辦法找到要求的資源。

+ +

深入了解

+ + diff --git a/files/zh-tw/glossary/502/index.html b/files/zh-tw/glossary/502/index.html new file mode 100644 index 0000000000..c8541f0ce4 --- /dev/null +++ b/files/zh-tw/glossary/502/index.html @@ -0,0 +1,20 @@ +--- +title: '502' +slug: Glossary/502 +tags: + - '502' + - HTTP 錯誤 + - 術語表 +translation_of: Glossary/502 +--- +

這是一個{{Glossary("HTTP")}} 錯誤代碼,表示“網關錯誤”。

+ +

一個伺服器({{Glossary("Server", "server")}})可以在一個客戶端(譬如網頁瀏覽器)和其他上游伺服器之間充當網關或代理(中間人)。當你請求訪問一個鏈接({{Glossary("URL")}}),網關伺服器可以從上游伺服器傳達你的請求。"502" 意味著上游伺服器返回了一個無效的響應。

+ +

正常情況下上游伺服器是不會宕機的(如沒有提供對網關/代理的相應),簡單來説就是作爲網關/代理不明白相同的數據交換協議。 因特網協議({{Glossary("Protocol", "protocols")}})是非常明確的,所以 502 通常意味著有一臺或者多臺機器沒有正確或者完整的程式。

+ +

了解更多

+ + diff --git a/files/zh-tw/glossary/abstraction/index.html b/files/zh-tw/glossary/abstraction/index.html new file mode 100644 index 0000000000..ba011d5bee --- /dev/null +++ b/files/zh-tw/glossary/abstraction/index.html @@ -0,0 +1,14 @@ +--- +title: 抽象化 +slug: Glossary/Abstraction +translation_of: Glossary/Abstraction +--- +

在{{Glossary("computer programming")}} 領域中,抽象化可用來減少軟體系統複雜度,讓設計及使用效率提升。用簡單的 {{Glossary("API", "APIs")}}隱藏背後複雜的系統機制。

+ +

了解更多

+ +

一般知識

+ + diff --git a/files/zh-tw/glossary/accessibility/index.html b/files/zh-tw/glossary/accessibility/index.html new file mode 100644 index 0000000000..5e51a1b7f9 --- /dev/null +++ b/files/zh-tw/glossary/accessibility/index.html @@ -0,0 +1,31 @@ +--- +title: Accessibility +slug: Glossary/Accessibility +tags: + - 術語 +translation_of: Glossary/Accessibility +--- +

網頁無障礙化 (A11Y) 指的是儘管有物理和技術上的限制,能夠保持網站可用最佳的方法。網頁無障礙化是透過{{Glossary("WAI","Web Accessibility Initiative")}} (WAI)在{{Glossary("W3C")}}被正式定義和討論的。

+ +

了解更多

+ +

基本知識

+ + + +

學習網頁無障礙化

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/adobe_flash/index.html b/files/zh-tw/glossary/adobe_flash/index.html new file mode 100644 index 0000000000..8e09c12f7b --- /dev/null +++ b/files/zh-tw/glossary/adobe_flash/index.html @@ -0,0 +1,28 @@ +--- +title: Adobe Flash +slug: Glossary/Adobe_Flash +tags: + - Flash + - 術語表 + - 過時技術 +translation_of: Glossary/Adobe_Flash +--- +

Flash 是一個由 Adobe 開發的過時網路技術。它能展現出富有表現力的 Web 程式、向量圖形、還有各種多媒體。Adobe Flash 需要在{{Glossary("瀏覽器")}}安裝相對應的擴充套件後才能使用。

+ + diff --git a/files/zh-tw/glossary/ajax/index.html b/files/zh-tw/glossary/ajax/index.html new file mode 100644 index 0000000000..b93f5acf21 --- /dev/null +++ b/files/zh-tw/glossary/ajax/index.html @@ -0,0 +1,25 @@ +--- +title: AJAX +slug: Glossary/AJAX +tags: + - AJAX + - 術語表 +translation_of: Glossary/AJAX +--- +

AJAX(Asynchronous {{glossary("JavaScript")}} And {{glossary("XML")}}、非同步 JavaScript 與 XML)是結合了 {{glossary("HTML")}}、{{glossary("CSS")}}、JavaScript 、{{glossary("DOM")}}、還有 XMLHttpRequest {{glossary("object")}},以建立更複雜的網頁程式實做。AJAX 可以允許網頁只更新需要的部分,而無須重新載入整個頁面。另外,AJAX 也能讓你非同步工作,意思是說程式碼能在網頁試圖重新載入時持續運行(與同步(synchronously)相對比──它會在運行的時候封鎖程式碼運作,直到網頁重新載入成功為止)。

+ +

了解更多

+ +

基本知識

+ + + +

技術資訊

+ + diff --git a/files/zh-tw/glossary/algorithm/index.html b/files/zh-tw/glossary/algorithm/index.html new file mode 100644 index 0000000000..d035e75838 --- /dev/null +++ b/files/zh-tw/glossary/algorithm/index.html @@ -0,0 +1,6 @@ +--- +title: 演算法 +slug: Glossary/Algorithm +translation_of: Glossary/Algorithm +--- +

演算法(algorithm)是包含了程式功能該如何執行的一連串指示。

diff --git a/files/zh-tw/glossary/api/index.html b/files/zh-tw/glossary/api/index.html new file mode 100644 index 0000000000..ee9802015a --- /dev/null +++ b/files/zh-tw/glossary/api/index.html @@ -0,0 +1,34 @@ +--- +title: API +slug: Glossary/API +tags: + - API + - 術語表 +translation_of: Glossary/API +--- +

一個API (Application Programming Interface)是指存在于軟體程式中為軟體與其他項目,如其他軟體或硬體,實現互動的一系列功能和規則。

+ +

在網頁開發,一個 API 通常指的是一系列的代碼功能(如: {{glossary("method","methods")}}, {{Glossary("property","properties")}}, events, and {{Glossary("URL","URLs")}})爲了方便程式開發者使用他們的 apps 通過用戶的網頁瀏覽器組件,或與用戶計算機上的其他軟體或硬件, 或與第三方網站和服務實現互動。

+ +

例如:

+ + + +

了解更多

+ +

基本知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/apple_safari/index.html b/files/zh-tw/glossary/apple_safari/index.html new file mode 100644 index 0000000000..6e0dcdc760 --- /dev/null +++ b/files/zh-tw/glossary/apple_safari/index.html @@ -0,0 +1,27 @@ +--- +title: Apple Safari +slug: Glossary/Apple_Safari +tags: + - Safari + - 瀏覽器 + - 術語表 +translation_of: Glossary/Apple_Safari +--- +

Safari 是一個來自蘋果開發的網頁瀏覽器({{Glossary("Browser","Web browser")}})同時被捆綁發行在 Mac OS X 和 IOS 平臺。它是基於開源的 WebKit 引擎.

+ +

了解更多

+ +

基礎知識

+ + + +

技術資訊

+ + diff --git a/files/zh-tw/glossary/argument/index.html b/files/zh-tw/glossary/argument/index.html new file mode 100644 index 0000000000..d08a26e0c8 --- /dev/null +++ b/files/zh-tw/glossary/argument/index.html @@ -0,0 +1,24 @@ +--- +title: 引數 +slug: Glossary/Argument +tags: + - CodingScripting + - JavaScript + - 術語表 +translation_of: Glossary/Argument +--- +

引數(argument)是作爲{{Glossary("function","函式")}}輸入的{{Glossary("primitive","原始型別")}}{{glossary("value","值")}}或著{{Glossary("object","物件")}}。

+ +

了解更多

+ +

基礎知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/aria/index.html b/files/zh-tw/glossary/aria/index.html new file mode 100644 index 0000000000..ef57c54ddf --- /dev/null +++ b/files/zh-tw/glossary/aria/index.html @@ -0,0 +1,17 @@ +--- +title: ARIA +slug: Glossary/ARIA +tags: + - 無障礙化 + - 術語表 +translation_of: Glossary/ARIA +--- +

ARIA(Accessible Rich {{glossary("Internet")}} Applications,可訪問的富網際網路應用程式)是一個 {{Glossary("W3C")}} 規範,用已對 {{Glossary("HTML")}} 添加語義和元數據,以迎合需要輔助技術的用戶。

+ +

例如:你可以給一個 {{HTMLElement("p")}} {{glossary("tag","標籤")}}添加 role="alert" 屬性提醒視覺障礙用戶,這裏的訊息很重要並對時間敏感(針對非視覺障礙用戶,你可能本來會用文字顔色傳達這種事)。

+ +

了解更多

+ + diff --git a/files/zh-tw/glossary/arpa/index.html b/files/zh-tw/glossary/arpa/index.html new file mode 100644 index 0000000000..8c8d4769be --- /dev/null +++ b/files/zh-tw/glossary/arpa/index.html @@ -0,0 +1,18 @@ +--- +title: ARPA +slug: Glossary/ARPA +tags: + - ARPA + - 術語表 +translation_of: Glossary/ARPA +--- +

.arpa (地址和路由參數區域)是一個{{glossary("TLD","top-level domain")}} 用於網際網路基建意圖,特別是反向 DNS 查找 (如:根據給出的 {{glossary("IP address")}} 查找 {{glossary('domain name')}})。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/arpanet/index.html b/files/zh-tw/glossary/arpanet/index.html new file mode 100644 index 0000000000..e4a8aaf166 --- /dev/null +++ b/files/zh-tw/glossary/arpanet/index.html @@ -0,0 +1,17 @@ +--- +title: Arpanet +slug: Glossary/Arpanet +tags: + - 網路結構 + - 術語表 +translation_of: Glossary/Arpanet +--- +

ARPAnet (高級研究代理網路)是一個早期的計算機網路,構建於 1969 年作為一個強大的媒介用於傳輸敏感軍事數據和連接米國各地主要的研究團體。ARPAnet 首先運行NCP (網路控制協定) 隨後運行網際網路的第一版協定或{{glossary("TCP")}}/{{glossary("IPv6","IP")}} 套件,使 ARPAnet 成為新生代網際網路{{glossary("Internet")}}的重要組成部分。ARPAnet 被關閉在 1990 年代的早期。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/array/index.html b/files/zh-tw/glossary/array/index.html new file mode 100644 index 0000000000..fc8d84a3fd --- /dev/null +++ b/files/zh-tw/glossary/array/index.html @@ -0,0 +1,31 @@ +--- +title: 陣列 +slug: Glossary/array +tags: + - 術語表 + - 陣列 +translation_of: Glossary/array +--- +

陣列是個有序資料的集合(按程式語言不同,資料型態可以是{{Glossary("primitive","原始型別")}}或{{Glossary("object","物件")}})。陣列是用來把複數的值存進一個變數裡。與只能存一個值的變數,呈現強烈的對比。

+ +

每一個陣列中的元素,都附有一個能讀相對應元素的數字,稱做數字索引(numeric index)。在 JavaScript 中,陣列的索引開始於數字 0 且能透過不同的{{Glossary("Method", "方法")}}來操作。

+ +

JavaScript 中的陣列:

+ +
var myArray = [1, 2, 3, 4];
+var catNamesArray = ["Jacqueline", "Sophia", "Autumn"];
+//Arrays in JavaScript can hold different types of data, as shown above.
+ +

了解更多

+ +

常規知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/ascii/index.html b/files/zh-tw/glossary/ascii/index.html new file mode 100644 index 0000000000..3d75607b2c --- /dev/null +++ b/files/zh-tw/glossary/ascii/index.html @@ -0,0 +1,16 @@ +--- +title: ASCII +slug: Glossary/ASCII +tags: + - ASCII + - 編碼方式 + - 術語表 +translation_of: Glossary/ASCII +--- +

ASCII (米國信息交換標準碼)是計算機用來轉換字母、數字、符號和控制代碼轉換為數字形式的最流行的編碼方法之一。自 2007 以來, {{Glossary("UTF-8")}} 在網頁上取代了它。

+ +

了解更多

+ +

基礎知識

+ +

維基百科上的 {{Interwiki("wikipedia", "ASCII")}}

diff --git a/files/zh-tw/glossary/asynchronous/index.html b/files/zh-tw/glossary/asynchronous/index.html new file mode 100644 index 0000000000..807ac2cd14 --- /dev/null +++ b/files/zh-tw/glossary/asynchronous/index.html @@ -0,0 +1,19 @@ +--- +title: Asynchronous 非同步 +slug: Glossary/Asynchronous +translation_of: Glossary/Asynchronous +--- +

非同步(Asynchronous,又稱異步)指的是各方在方便或可能時,才接收並處理訊息,而不是立刻這麼做的通訊環境。

+ +

你可以用人類的溝通環境來比喻:例如電子郵件,寄件者傳送電郵、收件者會在方便時才回覆。他們不用馬上就那麼做。

+ +

它也可以用來描述一個程式性的通信環境,例如 {{domxref("Ajax")}} 就是個請求 HTTP 少量數據的非同步機制。結果會在響應完成時發回,而不是立刻發送。

+ +

了解更多

+ +

技術資訊

+ + diff --git a/files/zh-tw/glossary/atag/index.html b/files/zh-tw/glossary/atag/index.html new file mode 100644 index 0000000000..fc0e1f23c4 --- /dev/null +++ b/files/zh-tw/glossary/atag/index.html @@ -0,0 +1,24 @@ +--- +title: ATAG +slug: Glossary/ATAG +tags: + - ATAG + - 術語表 +translation_of: Glossary/ATAG +--- +

ATAG (編輯工具可訪問性{{glossary("Accessibility")}}指南)是一個{{Glossary("W3C")}} 為創建可訪問内容構建可訪問性編輯工具的建議。

+ +

了解更多

+ +

基礎知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/attribute/index.html b/files/zh-tw/glossary/attribute/index.html new file mode 100644 index 0000000000..01a8cba491 --- /dev/null +++ b/files/zh-tw/glossary/attribute/index.html @@ -0,0 +1,18 @@ +--- +title: Attribute +slug: Glossary/Attribute +tags: + - 標簽屬性 + - 術語表 +translation_of: Glossary/Attribute +--- +

Attribute (標籤屬性)用於擴充 HTML {{Glossary("tag")}},可改變標籤行為或提供額外資訊。HTML 標籤屬性的正確格式為 name=value(以屬性名稱對上屬性值)。

+ +

了解更多

+ +

技術參考

+ + diff --git a/files/zh-tw/glossary/bandwidth/index.html b/files/zh-tw/glossary/bandwidth/index.html new file mode 100644 index 0000000000..49cb9be330 --- /dev/null +++ b/files/zh-tw/glossary/bandwidth/index.html @@ -0,0 +1,16 @@ +--- +title: Bandwidth +slug: Glossary/Bandwidth +tags: + - 基礎知識 + - 帶寬 + - 術語表 +translation_of: Glossary/Bandwidth +--- +

帶寬是指通過數據連接在一定時期内可以傳輸的數據信息量,通常以每秒比特數的倍數為單位,也就是bps,如:兆位每秒(Mbps)或吉比特每秒(Gbps)。

+ +

了解更多

+ + diff --git a/files/zh-tw/glossary/blink/index.html b/files/zh-tw/glossary/blink/index.html new file mode 100644 index 0000000000..96c25980de --- /dev/null +++ b/files/zh-tw/glossary/blink/index.html @@ -0,0 +1,20 @@ +--- +title: Blink +slug: Glossary/Blink +tags: + - Glossary + - Infrastructure + - Layout +translation_of: Glossary/Blink +--- +

Blink 是一套開放原始碼的瀏覽器排版引擎,由 Google 作為 Chromium 專案的一部份(所以也是 Chrome 的一部份)所打造。更仔細地講,Blink 是 {{glossary("WebKit")}} 當中處理排版、描繪、{{Glossary("DOM")}} 的 WebCore 程式庫的衍生版本。

+ +

了解更多

+ +

一般知識

+ + diff --git a/files/zh-tw/glossary/block/css/index.html b/files/zh-tw/glossary/block/css/index.html new file mode 100644 index 0000000000..c9da6a9cb5 --- /dev/null +++ b/files/zh-tw/glossary/block/css/index.html @@ -0,0 +1,22 @@ +--- +title: 區塊 (CSS) +slug: Glossary/Block/CSS +tags: + - Block + - CSS + - HTML + - display + - 術語表 +translation_of: Glossary/Block/CSS +--- +

在網頁上一個區塊是一個 {{glossary("HTML")}}元素({{glossary("element")}})它會出現一個新的行,例:在前面的元素之下和後面的元素之前(通常稱爲塊級元素)。擧個例子, {{htmlelement("p")}} 標簽就是一個默認的塊級元素,而 {{htmlelement("a")}} 標簽則是一個内聯元素— 你可以在 HTML 源代碼放一些相鄰的鏈接,他們將會并列渲染在相同的行。

+ +

使用 {{cssxref("display")}} 屬性你可以隨意改變大多數元素的顯示方式,不論是内聯還是區塊(其中還有很多其他的選項); blocks 也同樣會受到定位方案和 {{cssxref("position")}} 屬性的影響。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/block/index.html b/files/zh-tw/glossary/block/index.html new file mode 100644 index 0000000000..8f17177e82 --- /dev/null +++ b/files/zh-tw/glossary/block/index.html @@ -0,0 +1,13 @@ +--- +title: Block +slug: Glossary/Block +tags: + - Disambiguation + - Glossary + - NeedsTranslation + - TopicStub +translation_of: Glossary/Block +--- +

The term block can have several meanings depending on the context. It may refer to:

+ +

{{GlossaryDisambiguation}}

diff --git a/files/zh-tw/glossary/boolean/index.html b/files/zh-tw/glossary/boolean/index.html new file mode 100644 index 0000000000..c748ca87ac --- /dev/null +++ b/files/zh-tw/glossary/boolean/index.html @@ -0,0 +1,52 @@ +--- +title: 布林 +slug: Glossary/Boolean +tags: + - JavaScript + - 布林 + - 資料型態 +translation_of: Glossary/Boolean +--- +

在電腦科學中,布林值是一種其值僅能為的邏輯資料型別,它是編程語言裡在邏輯上表達真或假的方式。如果沒有這種能力,很多功能會無法實現。舉個例子,JavaScript中的 if 語句 的判斷條件會利用布林值來決定接下來的代碼是否要被執行。又如JavaScript中的 for 循環,如果沒有一個能夠解釋成不林值的判斷條件,循環將不知道是否要繼續循環或停止。

+ +
***JavaScript if Statement***
+if(boolean conditional) {
+   //coding
+}
+
+if(true) {
+  console.log("boolean conditional resolved to true");
+} else {
+    console.log("boolean conditional resolved to false");
+  }
+
+
+
+***JavaScript for Loop***
+for(control variable; boolean conditional; counter) {
+  //coding
+}
+
+for(var i=0; i<4; i++) {
+  console.log("I print only when the boolean conditional is true");
+}
+
+ +

 

+ +

 

+ +

了解更多

+ +

常規知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/bootstrap/index.html b/files/zh-tw/glossary/bootstrap/index.html new file mode 100644 index 0000000000..1fa3eca197 --- /dev/null +++ b/files/zh-tw/glossary/bootstrap/index.html @@ -0,0 +1,16 @@ +--- +title: Bootstrap +slug: Glossary/Bootstrap +translation_of: Glossary/Bootstrap +--- +

Bootstrap 是自由的 {{Glossary("HTML")}}, CSS, {{Glossary("JavaScript")}} 開源框架。該框架旨在快速建立響應式網站。

+ +

起初 Bootstrap 被稱為 Twitter Blueprint,並且由 Twitter 的內部團隊開發。它支援響應式設計、提供已經設計好能直接使用的設計樣板、或著針對該樣板,做出需要的自訂更動。在開發過程中,由於 Bootstrap 已經與當代瀏覽器,還有最新版 {{glossary("Microsoft Internet Explorer", "Internet Explorer")}} 相容,在使用 Bootstrap 開發時也不需要多操心相容性問題。

+ + diff --git a/files/zh-tw/glossary/browser/index.html b/files/zh-tw/glossary/browser/index.html new file mode 100644 index 0000000000..323e5f26dd --- /dev/null +++ b/files/zh-tw/glossary/browser/index.html @@ -0,0 +1,24 @@ +--- +title: 瀏覽器 +slug: Glossary/Browser +translation_of: Glossary/Browser +--- +

網頁瀏覽器是種從 {{Glossary("World Wide Web","Web")}} 擷取並顯示頁面的程式,且讓用戶透過 {{Glossary("hyperlink","hyperlinks")}} 來進入其他頁面。

+ +

更進一步了解

+ +

一般知識

+ + + +

下載瀏覽器

+ + diff --git a/files/zh-tw/glossary/browsing_context/index.html b/files/zh-tw/glossary/browsing_context/index.html new file mode 100644 index 0000000000..77fa42eb7f --- /dev/null +++ b/files/zh-tw/glossary/browsing_context/index.html @@ -0,0 +1,22 @@ +--- +title: 瀏覽上下文 +slug: Glossary/Browsing_context +tags: + - 瀏覽上下文 + - 術語表 +translation_of: Glossary/Browsing_context +--- +

瀏覽上下文是一個瀏覽器({{glossary("browser")}})展示文檔({{domxref("Document")}})的環境(正常來説是一個現在的標簽,但也有可能是一個窗體或是一個框架裏面的頁面)

+ +

每個瀏覽上下文都有一個特定的活動文檔來源{{glossary("origin")}}並按順序列出所有文檔的歷史記錄。

+ +

瀏覽上下文之間的通訊被嚴格限制。衹有瀏覽上下文來自于同樣的來源,一個廣播信道({{domxref("BroadcastChannel")}})才能被打開和使用。

+ +

了解更多

+ +

技術參考

+ + diff --git a/files/zh-tw/glossary/buffer/index.html b/files/zh-tw/glossary/buffer/index.html new file mode 100644 index 0000000000..f211c0106c --- /dev/null +++ b/files/zh-tw/glossary/buffer/index.html @@ -0,0 +1,17 @@ +--- +title: 緩衝區 +slug: Glossary/buffer +tags: + - 緩衝區 + - 術語表 +translation_of: Glossary/buffer +--- +

緩衝區是物理記憶軟體中的一個存儲區,用於在數據從一個地方傳輸到另一個地方時臨時存儲數據。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/cache/index.html b/files/zh-tw/glossary/cache/index.html new file mode 100644 index 0000000000..ca193a9570 --- /dev/null +++ b/files/zh-tw/glossary/cache/index.html @@ -0,0 +1,14 @@ +--- +title: Cache 快取 +slug: Glossary/Cache +translation_of: Glossary/Cache +--- +

快取(cache, web cache, HTTP cache)是暫時存放 HTTP 回應的組件。只要滿足特定要求,就能在接下來的 HTTP 請求派上用場。

+ +

深入理解

+ +

一般知識

+ + diff --git a/files/zh-tw/glossary/cacheable/index.html b/files/zh-tw/glossary/cacheable/index.html new file mode 100644 index 0000000000..f8e744e1d3 --- /dev/null +++ b/files/zh-tw/glossary/cacheable/index.html @@ -0,0 +1,59 @@ +--- +title: 可緩存 +slug: Glossary/cacheable +tags: + - 緩存 + - 術語表 +translation_of: Glossary/cacheable +--- +

可緩存的響應是可被緩存的HTTP 響應,它被存儲以供稍後檢索和使用,從而將新的請求保存在伺服器。不是所有的 HTTP 響應都可以被緩存,可以被緩存的 HTTP 響應需滿足如下列條件:

+ + + +

請注意一些不緩存請求/響應到指定的 URI 可能會導致相同 URI 上以前的緩存響應失效。例如,  {{HTTPMethod("PUT")}} 到 pageX.html 將使相同 URI 下所有的 {{HTTPMethod("GET")}} 或 {{HTTPMethod("HEAD")}} 請求緩存失效。

+ +

同樣的,如果請求的方法和響應的狀態都可以被緩存,那請求的響應也都將可以被緩存:

+ +
GET /pageX.html HTTP/1.1
+(…)
+
+200 OK
+(…)
+
+ +

{{HTTPMethod("PUT")}} 請求不能被緩存. 此外,它還將導致所有來源為 {{HTTPMethod("HEAD")}} or {{HTTPMethod("GET")}} 相同的 URI 緩存數據無效 :

+ +
PUT /pageX.html HTTP/1.1
+(…)
+
+200 OK
+(…)
+
+ +

指定的 {{HTTPHeader("Cache-Control")}} 頭部在響應中可以阻止緩存:

+ +
GET /pageX.html HTTP/1.1
+(…)
+
+200 OK
+Cache-Control: no-cache
+(…)
+ +

了解更多

+ +

基礎知識

+ + + +

技術資訊

+ + diff --git a/files/zh-tw/glossary/callback_function/index.html b/files/zh-tw/glossary/callback_function/index.html new file mode 100644 index 0000000000..3bfcdf6dd3 --- /dev/null +++ b/files/zh-tw/glossary/callback_function/index.html @@ -0,0 +1,36 @@ +--- +title: 回呼函式 +slug: Glossary/Callback_function +translation_of: Glossary/Callback_function +--- +

回呼函式(callback function)是指能藉由參數(argument)通往另一個函式的函式。它會在外部函式內調用、以完成某些事情。

+ +

以下是簡單的範例:

+ +
function greeting(name) {
+  alert('Hello ' + name);
+}
+
+function processUserInput(callback) {
+  var name = prompt('輸入你的名字:');
+  callback(name);
+}
+
+processUserInput(greeting);
+ +

這是個{{glossary("synchronous","同步")}}回呼的例子,因為它是立即執行的。

+ +

但請注意,回呼常用來延續{{glossary("asynchronous","非同步")}}行動完成後的程式執行:這就叫做非同步回呼(asynchronous callbacks)。例如說我們的 maps-example.html 範例(也請參見這個)用了 Google Maps API 與 Geolocation API 來把你設備的位置,顯示到地圖上。

+ +

因為我們透過非同步取得 GPS 的設備坐標(我們不知道數據何時會被回傳),{{domxref("Geolocation.getCurrentPosition()")}} 方法把一個匿名回呼函式作為參數,它會回傳一個坐標數據以充當參數。該函式會在回傳坐標數據後執行。

+ +

深入理解

+ +

一般常識

+ + diff --git a/files/zh-tw/glossary/canvas/index.html b/files/zh-tw/glossary/canvas/index.html new file mode 100644 index 0000000000..f28d6a36af --- /dev/null +++ b/files/zh-tw/glossary/canvas/index.html @@ -0,0 +1,34 @@ +--- +title: Canvas +slug: Glossary/Canvas +tags: + - HTML + - JavaScript +translation_of: Glossary/Canvas +--- +
+

一個 {{Glossary("HTML")}} {{HTMLElement("canvas")}} 元素提供一個空的圖區使特定的  {{Glossary("JavaScript")}} {{Glossary("API","APIs")}} 可以在上面繪圖(像是 Canvas 2D 或 {{Glossary("WebGL")}}).

+ +

了解更多

+ +

常規知識

+ + + +

學習資源

+ + + +

技術參考

+ + +
diff --git a/files/zh-tw/glossary/character/index.html b/files/zh-tw/glossary/character/index.html new file mode 100644 index 0000000000..5fb45cd212 --- /dev/null +++ b/files/zh-tw/glossary/character/index.html @@ -0,0 +1,22 @@ +--- +title: 字元 +slug: Glossary/Character +tags: + - 字串 + - 編碼腳本 + - 詞彙表 +translation_of: Glossary/Character +--- +

一個字元包含符號(字母、數字、標點符號)和不會顯示的"控制字元"(例如:回車符或連字號)。 {{glossary("UTF-8")}}是最常見的字元組合,它包含了人類最常使用的字形。

+ +

了解更多

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/character_encoding/index.html b/files/zh-tw/glossary/character_encoding/index.html new file mode 100644 index 0000000000..ed37fb7be6 --- /dev/null +++ b/files/zh-tw/glossary/character_encoding/index.html @@ -0,0 +1,25 @@ +--- +title: 字元編碼 +slug: Glossary/character_encoding +tags: + - 字彙表 +translation_of: Glossary/character_encoding +--- +

字元編碼提供了一套編碼系統,使不同的電腦系統或編譯環境可以存在並處理存在於其他語言當中的特殊字元。

+ +

例如在HTML中,我們通常使用以下程式碼來宣告一個UTF-8的字元編碼:

+ +
+
<meta charset="utf-8">
+ +

這使我們可以在HTML檔案中使用幾乎所有人類使用的語言,並且會正常顯示。

+
+ +

學習更多

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/character_set/index.html b/files/zh-tw/glossary/character_set/index.html new file mode 100644 index 0000000000..0bbdcf4f19 --- /dev/null +++ b/files/zh-tw/glossary/character_set/index.html @@ -0,0 +1,30 @@ +--- +title: 字符集 +slug: Glossary/character_set +tags: + - 字符 + - 術語表 +translation_of: Glossary/character_set +--- +

字符集 是能讓電腦知道如何解讀{{Glossary("字符")}}的編碼系統。解讀範圍包括字母、數字、標點符號、還有空白等。

+ +

早期各國出於各自的語言考量,而開發各自的字符集:例如日文的漢字 JIS(有 Shift-JIS、EUC-JP 等)、繁體中文的 Big5、俄文的 KOI8-R 等等。不過支持多語言的 {{Glossary("Unicode")}},逐漸成了最通用的字符集。

+ +

如果字符集使用不當(像是用 Unicode 閱覽 Big5 編碼的文章),可能會看到一大堆破碎的文字。這些破碎的文字,一般被俗稱為{{Interwiki("wikipedia", "亂碼")}}。

+ + diff --git a/files/zh-tw/glossary/chrome/index.html b/files/zh-tw/glossary/chrome/index.html new file mode 100644 index 0000000000..899af323a1 --- /dev/null +++ b/files/zh-tw/glossary/chrome/index.html @@ -0,0 +1,8 @@ +--- +title: Chrome +slug: Glossary/Chrome +translation_of: Glossary/Chrome +--- +

不要和 {{glossary("Google Chrome")}} 混淆,"chrome" 代表除了網頁本身之外任何可視的 {{glossary("瀏覽器")}} 外觀(例如:工具列、功能列、分頁)。

+ +

 

diff --git a/files/zh-tw/glossary/cipher_suite/index.html b/files/zh-tw/glossary/cipher_suite/index.html new file mode 100644 index 0000000000..5ae0281c08 --- /dev/null +++ b/files/zh-tw/glossary/cipher_suite/index.html @@ -0,0 +1,25 @@ +--- +title: 密碼套件 +slug: Glossary/Cipher_suite +tags: + - 安全性 + - 密碼學 + - 術語表 +translation_of: Glossary/Cipher_suite +--- +

密碼套件是包括了密鑰交換算法, 身份認證方法,批量加密密碼({{Glossary("cipher")}})和消息認證碼的組合.

+ +

在密碼系統({{Glossary("cryptosystem")}})裏像 {{Glossary("TLS")}}, 客戶端和伺服器在它們開始安全的通訊之前必須同意密碼套件。 典型的密碼套件如ECDHE_RSA_WITH_AES_128_GCM_SHA256 或 ECDHE-RSA-AES128-GCM-SHA256, 具有如下特徵:

+ + + +

了解更多

+ + diff --git a/files/zh-tw/glossary/ciphertext/index.html b/files/zh-tw/glossary/ciphertext/index.html new file mode 100644 index 0000000000..d6e9f3be4c --- /dev/null +++ b/files/zh-tw/glossary/ciphertext/index.html @@ -0,0 +1,18 @@ +--- +title: 密文 +slug: Glossary/Ciphertext +tags: + - 安全性 + - 私密性 + - 術語表 +translation_of: Glossary/Ciphertext +--- +

在密碼學({{glossary("Cryptography")}})中, 密文是傳達信息的加密信息,正常情況下無法解讀除非使用正確的密碼({{glossary("cipher")}})和秘密(通常叫做{{glossary("key")}}) 來解密({{glossary("decryption","decrypted")}})才可以再現原來的明文({{glossary("cleartext")}})。一個密文的安全性 以及包含信息的保密性依賴于安全的密碼和保持 key 的秘密性。 

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/class/index.html b/files/zh-tw/glossary/class/index.html new file mode 100644 index 0000000000..7effd1c427 --- /dev/null +++ b/files/zh-tw/glossary/class/index.html @@ -0,0 +1,22 @@ +--- +title: Class(類) +slug: Glossary/Class +tags: + - Class + - 術語表 + - 面向對象 + - 類 +translation_of: Glossary/Class +--- +

在物件導向編程({{glossary("OOP","object-oriented programming")}})中,一個類(Class)定義了一個 {{glossary("object","object")}} 的性質。類是一個定義了對象的屬性 ({{glossary("property","properties")}}) 和方法 ({{glossary("method","methods")}}) 的模板,繪製其他更多具體實例對象的「藍圖」。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/closure/index.html b/files/zh-tw/glossary/closure/index.html new file mode 100644 index 0000000000..6631d17d02 --- /dev/null +++ b/files/zh-tw/glossary/closure/index.html @@ -0,0 +1,23 @@ +--- +title: 閉包 +slug: Glossary/Closure +tags: + - 術語表 + - 閉包 +translation_of: Glossary/Closure +--- +

定義可執行範圍({{glossary("scope")}})的綁定:在 {{glossary("JavaScript")}}, {{glossary("function","functions")}}會創建一個閉包上下文

+ +

了解更多

+ +

基礎知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/cms/index.html b/files/zh-tw/glossary/cms/index.html new file mode 100644 index 0000000000..c1b6ef5afa --- /dev/null +++ b/files/zh-tw/glossary/cms/index.html @@ -0,0 +1,14 @@ +--- +title: CMS 內容管理系統 +slug: Glossary/CMS +translation_of: Glossary/CMS +--- +

内容管理系统(Content Management System,CMS)是個能讓用戶發布、組織、變更、還有移除各種內容的軟體。所謂的內容,可以包含文字、嵌入式圖像,視頻,音頻、互動程式碼。

+ +

深入了解

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/compile/index.html b/files/zh-tw/glossary/compile/index.html new file mode 100644 index 0000000000..e65dfd2a32 --- /dev/null +++ b/files/zh-tw/glossary/compile/index.html @@ -0,0 +1,23 @@ +--- +title: 編譯 +slug: Glossary/Compile +tags: + - 編寫 + - 術語表 +translation_of: Glossary/Compile +--- +

編譯是將給定編程語言中的計算機程式轉換成用另一種語言(通常是計算機可執行的二進制語言)編寫的相同程式的過程。

+ +

了解更多

+ +

基礎知識

+ + + +

學習資源

+ + diff --git a/files/zh-tw/glossary/compile_time/index.html b/files/zh-tw/glossary/compile_time/index.html new file mode 100644 index 0000000000..c462fbd76e --- /dev/null +++ b/files/zh-tw/glossary/compile_time/index.html @@ -0,0 +1,19 @@ +--- +title: 編譯時間 +slug: Glossary/Compile_time +tags: + - 編譯時間 + - 術語表 +translation_of: Glossary/Compile_time +--- +

編譯時間是指程式從第一次加載到解析({{Glossary("parse","parsed")}})程式的時間。

+ +

了解更多

+ +

基礎知識

+ + + +

 

diff --git a/files/zh-tw/glossary/computer_programming/index.html b/files/zh-tw/glossary/computer_programming/index.html new file mode 100644 index 0000000000..efb69cf121 --- /dev/null +++ b/files/zh-tw/glossary/computer_programming/index.html @@ -0,0 +1,20 @@ +--- +title: Computer Programming +slug: Glossary/Computer_Programming +tags: + - 術語表 + - 計算機編程 +translation_of: Glossary/Computer_Programming +--- +

電腦程式設計是編寫和組織一系列指令的過程。它會以電腦/軟體程式能理解的語言,告訴他們要做什麼事情。這些指令來自不同形式的語言,例如如:C++、Java、JavaScript、HTML、Python、Ruby、和Rust。

+ +

使用合適的語言,可以設計/創建所有類型的軟體。例如,幫助科學家進行複雜運算的程式、儲存大量資料的資料庫、讓用戶下載音樂的網站、或者讓用戶建立動畫電影的軟體。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/constructor/index.html b/files/zh-tw/glossary/constructor/index.html new file mode 100644 index 0000000000..a920ec31f0 --- /dev/null +++ b/files/zh-tw/glossary/constructor/index.html @@ -0,0 +1,41 @@ +--- +title: 建構子 +slug: Glossary/Constructor +translation_of: Glossary/Constructor +--- +

建構子(constructor)屬於實做(instantiated)的指定 class {{glossary("object")}}。建構子概念可應用到大多數的{{glossary("OOP","物件導向")}}程式語言。基本上,{{glossary("JavaScript")}} 建構子用於在 {{glossary("class")}} 的實做(instance)聲明。

+ +

語法

+ +
// 這是個通用的建構子 class Default
+function Default() {
+}
+
+// 這是擁有幾個參數的過載建構子 class Overloaded
+function Overloaded(arg1, arg2, ...,argN){
+}
+
+ +

要呼叫 JavaScript 內的建構子 class ,請用 new 操作符給 {{glossary("variable")}} 宣告新的 {{glossary("object reference")}}。

+ +
function Default() {
+}
+
+// 新的 Default 物件參照被分派給局部變數 defaultReference
+var defaultReference = new Default();
+
+ +

深入理解

+ +

基本知識

+ + + +

技術資訊

+ + diff --git a/files/zh-tw/glossary/continuous_media/index.html b/files/zh-tw/glossary/continuous_media/index.html new file mode 100644 index 0000000000..cd5b9e48b6 --- /dev/null +++ b/files/zh-tw/glossary/continuous_media/index.html @@ -0,0 +1,11 @@ +--- +title: Continuous Media +slug: Glossary/Continuous_Media +tags: + - CSS + - Media +translation_of: Glossary/Continuous_Media +--- +

CSS 可以用在許多不同的地方,印刷媒體便是一種。有些排版用的 CSS 會因為所處環境的不同而有不一樣的效果。

+ +

連續性媒體 (continuous media) 指的就是這樣一種環境,其中的內容不是以片段呈現,而是持續更迭。比方說顯示在螢幕上的網頁內容、語音內容都是連續性媒體。

diff --git a/files/zh-tw/glossary/cookie/index.html b/files/zh-tw/glossary/cookie/index.html new file mode 100644 index 0000000000..2751a58d60 --- /dev/null +++ b/files/zh-tw/glossary/cookie/index.html @@ -0,0 +1,21 @@ +--- +title: Cookie +slug: Glossary/Cookie +tags: + - cookie + - 術語表 +translation_of: Glossary/Cookie +--- +

Cookie 是一個網站通過瀏覽器訪問在訪客電腦裏留下的一小段信息。

+ +

Cookies 被網站用於個性化用戶個人的網頁體驗。 訪問該網站時它可能覆蓋了用戶的喜好或輸入。用戶可以自定義他們的瀏覽器是個接受或是刪除 cookies.

+ +

Cookies 可以設置和修改,在伺服器級別使用Set-Cookie HTTP header, 或在 JavaScript 使用 document.cookie.

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/cors/index.html b/files/zh-tw/glossary/cors/index.html new file mode 100644 index 0000000000..3aac367e9d --- /dev/null +++ b/files/zh-tw/glossary/cors/index.html @@ -0,0 +1,49 @@ +--- +title: CORS +slug: Glossary/CORS +tags: + - 安全 + - 術語表 +translation_of: Glossary/CORS +--- +

CORS(跨來源資源共享)是瀏覽器技術規範,用來傳輸 HTTP 標頭,判斷阻擋或允許不同來源網域的資源存取。

+ +

同源安全政策(same-origin security policy),預設會禁止跨網域的資源請求。CORS 賦予網站伺服器跨網域存取控制能力,使其能安全地跨網域傳輸資料。

+ +

了解更多

+ +

一般知識

+ + + +

CORS 標頭

+ +
+
{{HTTPHeader("Access-Control-Allow-Origin")}}
+
表示回傳資料能否共享(布林值)。
+
{{HTTPHeader("Access-Control-Allow-Credentials")}}
+
指定為 true 時,瀏覽器可以傳送或接收敏感資訊(HTTP Cookie)。
+
{{HTTPHeader("Access-Control-Allow-Headers")}}
+
指定可以出現在真實請求的 HTTP 標頭,用來回應預檢請求。
+
{{HTTPHeader("Access-Control-Allow-Methods")}}
+
指定存取資源所允許的 HTTP 方法,用來回應預檢請求。
+
{{HTTPHeader("Access-Control-Expose-Headers")}}
+
表示瀏覽器允許存取的標頭白名單,例如 X-My-Header, X-My-Custom-Header
+
{{HTTPHeader("Access-Control-Max-Age")}}
+
表示預檢請求的回傳結果可以被快取多久(秒)。
+
{{HTTPHeader("Access-Control-Request-Headers")}}
+
用於預檢請求,讓伺服器知道後續真實請求夾帶的 HTTP 標頭。
+
{{HTTPHeader("Access-Control-Request-Method")}}
+
用於預檢請求,讓伺服器端知道後續真實請求使用的 HTTP 方法
+
{{HTTPHeader("Origin")}}
+
告訴伺服器請求來源之網域。
+
+ +

技術參考

+ + diff --git a/files/zh-tw/glossary/crawler/index.html b/files/zh-tw/glossary/crawler/index.html new file mode 100644 index 0000000000..85774c9786 --- /dev/null +++ b/files/zh-tw/glossary/crawler/index.html @@ -0,0 +1,12 @@ +--- +title: Crawler +slug: Glossary/Crawler +translation_of: Glossary/Crawler +--- +

網路爬蟲(web crawler)是個程式,也被稱作機器人(bot、robot),會系統化瀏覽{{glossary("World Wide Web","網路")}}以蒐集網頁資料。通常,搜尋引擎會用爬蟲建立網頁索引。

+ +

深入理解

+ + diff --git a/files/zh-tw/glossary/crud/index.html b/files/zh-tw/glossary/crud/index.html new file mode 100644 index 0000000000..16eb27ad05 --- /dev/null +++ b/files/zh-tw/glossary/crud/index.html @@ -0,0 +1,14 @@ +--- +title: CRUD +slug: Glossary/CRUD +translation_of: Glossary/CRUD +--- +

CRUD (新增:Create ,  讀取:Read, 更新: Update, 刪除:Delete) 是指操作儲存資料方式的首字母縮寫。是指操作儲存資料方式的首字母縮寫。CRUD 通常指在資料庫或數據儲存的執行操作,但它也適用於應用程式的高層次功能,像是不直接刪除資料,僅透過狀態標記為刪除的軟刪除。

+ +

Learn more

+ +

General knowledge

+ + diff --git a/files/zh-tw/glossary/cryptography/index.html b/files/zh-tw/glossary/cryptography/index.html new file mode 100644 index 0000000000..eb8c5953fc --- /dev/null +++ b/files/zh-tw/glossary/cryptography/index.html @@ -0,0 +1,20 @@ +--- +title: 密碼學 +slug: Glossary/Cryptography +tags: + - 安全性 + - 密碼學 + - 術語表 +translation_of: Glossary/Cryptography +--- +

密碼學, 或者說隱語, 是研究如何安全地編碼和傳遞信息的科學。加密學設計和研究用於在不安全的環境中對消息進行編碼和解碼的算法和應用。密碼學不僅僅涉及數據保密性,它還包含了識別、認證無依賴性和數據完整性。因此它同樣研究密碼學方法在上下文、密碼系統的用法。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/csp/index.html b/files/zh-tw/glossary/csp/index.html new file mode 100644 index 0000000000..17341793c6 --- /dev/null +++ b/files/zh-tw/glossary/csp/index.html @@ -0,0 +1,25 @@ +--- +title: CSP +slug: Glossary/CSP +tags: + - HTTP + - 術語表 +translation_of: Glossary/CSP +--- +

CSP (内容安全策略)是被用於檢測和緩解某些網站相關的攻擊類型如{{Glossary("XSS")}} 和資料注入。

+ +

這個策略的履行是基於 {{Glossary("HTTP")}} 頭部的 Content-Security-Policy.

+ +

了解更多

+ +

基礎知識

+ + + +

技術資訊

+ + diff --git a/files/zh-tw/glossary/csrf/index.html b/files/zh-tw/glossary/csrf/index.html new file mode 100644 index 0000000000..cb8a6509ac --- /dev/null +++ b/files/zh-tw/glossary/csrf/index.html @@ -0,0 +1,23 @@ +--- +title: CSRF +slug: Glossary/CSRF +translation_of: Glossary/CSRF +--- +

跨站請求偽造(Cross-Site Request Forgery, CSRF)是一種冒充信任用戶,來傳送非預期指令的攻擊。比方說,可以在 {{glossary("URL")}} 連結背後添加惡意參數來攻擊:

+ +
<img src="https://www.example.com/index.php?action=delete&id=123">
+
+ +

對擁有 https://www.example.com 權限的用戶來說,<img> 元素會在用戶沒注意到的情況下執行 https://www.example.com 的操作。就算這個元素的域名不在 https://www.example.com 亦然。

+ +

有很多能預防 CSRF 的辦法,例如實作 {{glossary("REST", "RESTful API")}}、或添加 secure token 等等。

+ +

了解更多

+ +

一般知識

+ + diff --git a/files/zh-tw/glossary/css/index.html b/files/zh-tw/glossary/css/index.html new file mode 100644 index 0000000000..3afe82b10a --- /dev/null +++ b/files/zh-tw/glossary/css/index.html @@ -0,0 +1,49 @@ +--- +title: CSS +slug: Glossary/CSS +tags: + - CSS + - CodingScripting + - Web + - 'l10n:priority' + - 階層式樣式表 +translation_of: Glossary/CSS +--- +

階層式樣式表,或稱層疊樣式表(Cascading Style Sheets,CSS)是控制網頁的外觀,要在{{glossary("瀏覽器")}}裡面如何表現的陳述式語言。瀏覽器會套用 CSS 樣式宣告、以期被選中的元素能正確顯示之。樣式宣告包含了屬性(Property)與屬性值(Value)。它們會判斷網頁如何顯示。

+ +

CSS 與 {{Glossary("HTML")}} 及 {{Glossary("JavaScript")}} 並列為網路三大核心技術。CSS 通常用作{{Glossary("Element"," HTML 元素")}}的樣式化,但它也能給其他像 {{Glossary("SVG")}} 或 {{Glossary("XML")}} 之類的標示語言樣式化。

+ +

CSS 的規則,是一個{{Glossary("CSS Property","屬性")}}配上一個{{Glossary("selector","選擇器")}}。以下的例子能把所有 HTML 的段落元素,變成黑底黃字:

+ +
/* 選擇器「p」是指所有文件內的段落,都會受這個規則所影響。 */
+p {
+  /* "color" 屬性定義了文字的顏色,本例為黃色。 */
+  color: yellow;
+
+  /* "background-color" 屬性定義了背景的顏色,本例為黑色。 */
+  background-color: black
+}
+ +

階層式樣式表的「階層(Cascading)」一詞,就是在指:如何決定改變網頁外觀的選擇器,其優先次序為何的支配規則。這個功能非常重要,因為一個夠複雜的網頁,可以動用上千個 CSS 規則。

+ +

深入了解

+ +

基本知識

+ + + +

技術參考

+ + + +

深入了解 CSS

+ + diff --git a/files/zh-tw/glossary/css_pixel/index.html b/files/zh-tw/glossary/css_pixel/index.html new file mode 100644 index 0000000000..ef969d88a6 --- /dev/null +++ b/files/zh-tw/glossary/css_pixel/index.html @@ -0,0 +1,24 @@ +--- +title: CSS 像素 +slug: Glossary/CSS_pixel +translation_of: Glossary/CSS_pixel +--- +

CSS 像素—在 {{Glossary("CSS")}} 以 px 前輟表示—是大致對應單個點長高、肉眼也能輕易見到、否則就盡可能小的長度單位。按照定義,CSS 像素是在肉眼一臂之遙的距離下,像素密度(pixel density)為單個 96 DPI 像素的物理尺寸。

+ +

這定義當然因為如「輕易見到」或「一臂之遙」之類的不精確、因人而異的用詞,而有很多解釋的空間:像是用戶坐在桌上型電腦前,用戶與那台電腦的距離,其實比手機還遠。

+ +

因此,不管屏幕的實際像素密度多少,通常在談到 px 的時候,是為了想辦法讓 96px 與的長度等於1英寸(約 2.54 公分)。換句話說,如果某台手機的像素密度為 266 DPI,而某個元素的長度為 96px,該元素的實際長度為 266 {{Glossary("設備像素")}}。

+ +

深入理解

+ +

技術參考

+ + + +

學習它

+ + diff --git a/files/zh-tw/glossary/css_preprocessor/index.html b/files/zh-tw/glossary/css_preprocessor/index.html new file mode 100644 index 0000000000..b450a2dea9 --- /dev/null +++ b/files/zh-tw/glossary/css_preprocessor/index.html @@ -0,0 +1,26 @@ +--- +title: CSS 預處理器 +slug: Glossary/CSS_preprocessor +translation_of: Glossary/CSS_preprocessor +--- +

CSS 預處理器是個能透過該預處理器語法,產生純 {{Glossary("CSS")}} 的程式。CSS 預處理器有很多選擇,不過大多數的 CSS 預處理器都會添加純 CSS 所沒有的功能,例如:mixin、巢狀選擇器、繼承選擇器等。這些功能會令 CSS 結構的可讀性更高、也更容易維護。

+ +

要使用 CSS 預處理器,你需要在{{Glossary("伺服器")}}安裝 CSS 編譯器,或是在開發環境透過 CSS 預處理器編譯後,上傳編譯好的 CSS 到伺服器。

+ + diff --git a/files/zh-tw/glossary/css_selector/index.html b/files/zh-tw/glossary/css_selector/index.html new file mode 100644 index 0000000000..a22541284a --- /dev/null +++ b/files/zh-tw/glossary/css_selector/index.html @@ -0,0 +1,60 @@ +--- +title: CSS 選擇器 +slug: Glossary/CSS_Selector +tags: + - 樣式表 + - 超文本標記語言 + - 選擇器 +translation_of: Glossary/CSS_Selector +--- +

CSS 選擇器是 CSS 規則的一部分。它能讓你選定要調整哪個(或哪些)元素的樣式。例如:

+ +
***HTML***
+<div> I am inside of a div element. </div>
+<p> I am inside of a paragraph element. </p>
+
+
+***CSS***
+div {
+ color: green;
+}
+
+p {
+ color: red;
+}
+
+ +

在第一個 CSS 規則,我選取了 <div> 元素、並將該元素的文字變成了綠色。在第二個 CSS 規則,我選取了 <p> 元素、並將該元素的文字變成了紅色。結果應該長成這個樣子:

+ +

CSS 選擇器的結果

+ +

深入理解

+ +

基本知識

+ + + +

技術指南

+ +

{{SpecName("CSS3 Selectors")}}

diff --git a/files/zh-tw/glossary/cssom/index.html b/files/zh-tw/glossary/cssom/index.html new file mode 100644 index 0000000000..a55ce90074 --- /dev/null +++ b/files/zh-tw/glossary/cssom/index.html @@ -0,0 +1,18 @@ +--- +title: CSS 物件模型 (CSSOM) +slug: Glossary/CSSOM +translation_of: Glossary/CSSOM +--- +

CSS 物件模型 (CSS Object Model, CSSOM) 是一個存放所有 CSS 選擇器與相關特性的樹狀結構容器,擁有根節點、鄰居節點、後代節點、子代節點以及其他關係。CSSCOM 非常類似於 DOM 文件物件模型 。它們兩者都是關鍵渲染路徑的其中一部分,是網站渲染的必要步驟。

+ +

CSSOM 與 DOM 一起建構渲染樹,瀏覽器依序使用它來排版與繪製網頁。

+ +

CSSOM API

+ +

CSS Object Model 的系列 API 允許從 JavaScript 處理操作 CSS。它更像是 DOM,但是用於 CSS 而非 HTML。允許使用者動態讀取與修改 CSS 樣式。

+ +

也可以看看

+ + diff --git a/files/zh-tw/glossary/data_structure/index.html b/files/zh-tw/glossary/data_structure/index.html new file mode 100644 index 0000000000..ec4d0cd68f --- /dev/null +++ b/files/zh-tw/glossary/data_structure/index.html @@ -0,0 +1,14 @@ +--- +title: 資料結構 +slug: Glossary/Data_structure +tags: + - 資料結構 +translation_of: Glossary/Data_structure +--- +

資料結構 用一些特別的方式去組織與儲存資料使得資料能夠更有效率的被使用。

+ +

了解更多

+ + diff --git a/files/zh-tw/glossary/developer_tools/index.html b/files/zh-tw/glossary/developer_tools/index.html new file mode 100644 index 0000000000..e437649d62 --- /dev/null +++ b/files/zh-tw/glossary/developer_tools/index.html @@ -0,0 +1,29 @@ +--- +title: 開發者工具 +slug: Glossary/Developer_Tools +tags: + - 術語表 + - 開發者工具 +translation_of: Glossary/Developer_Tools +--- +

開發者工具 (或"開發工具"或簡稱 "DevTools")是程式准許開發者執行創建、測試和{{Glossary("debug")}}的軟體。

+ +

現在的瀏覽器都提供了完整的開發者工具,它被准許用來檢查網站。它們讓用戶檢查和debug 頁面上的 {{Glossary("HTML")}}, {{Glossary("CSS")}} 和 {{Glossary("JavaScript")}}准許檢查引起的網路流量,并使測量性能成爲更多,以及其他。

+ +

了解更多

+ +

基礎知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/dhtml/index.html b/files/zh-tw/glossary/dhtml/index.html new file mode 100644 index 0000000000..dfffad06bb --- /dev/null +++ b/files/zh-tw/glossary/dhtml/index.html @@ -0,0 +1,7 @@ +--- +title: DHTML +slug: Glossary/DHTML +translation_of: Glossary/DHTML +--- +

DHTML 是動態 (dynamic) HTML 的縮短形式,且通常用於指那些未使用 flash 或 java 等外掛的交互式網頁後面的程式碼。The term aggregates the combined functionality 允許網頁開法者使用 HTMLCSSDocument Object Model ,以及 JavaScript

+

DHTML 與 {{Glossary("Ajax")}} 的不同之處在於,在載入階段它仍然基於 HTML, CSS 和 JS 等程式碼來定義。相反的,基於 Ajax 的頁面則使用 {{domxref("XMLHttpRequest")}} 介面來動態載入更多的資料。

diff --git a/files/zh-tw/glossary/dns/index.html b/files/zh-tw/glossary/dns/index.html new file mode 100644 index 0000000000..b03da4794b --- /dev/null +++ b/files/zh-tw/glossary/dns/index.html @@ -0,0 +1,18 @@ +--- +title: DNS +slug: Glossary/DNS +tags: + - DNS + - 術語表 +translation_of: Glossary/DNS +--- +

DNS (域名系統)將便於記憶的需要查找 {{Glossary("Internet")}} 上特定的計算機服務或私人網路{{glossary("domain name","域名")}}轉換為數字{{Glossary("IP address","IP addresses")}}。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/doctype/index.html b/files/zh-tw/glossary/doctype/index.html new file mode 100644 index 0000000000..bf0f51c1d9 --- /dev/null +++ b/files/zh-tw/glossary/doctype/index.html @@ -0,0 +1,22 @@ +--- +title: Doctype +slug: Glossary/Doctype +translation_of: Glossary/Doctype +--- +

<!DOCTYPE>會告知你的{{Glossary("瀏覽器")}}這個文件是用哪個版本的 {{Glossary("HTML")}} (或 {{glossary("XML")}})撰寫。Doctype 是一種宣告,而非 {{Glossary("tag")}}。你也可以把它想作「document type declaration」(文件類型宣告),或是縮寫的 「DTD」。

+ +

了解詳情

+ +

基本知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/document_directive/index.html b/files/zh-tw/glossary/document_directive/index.html new file mode 100644 index 0000000000..3aa32cfdaa --- /dev/null +++ b/files/zh-tw/glossary/document_directive/index.html @@ -0,0 +1,35 @@ +--- +title: Document directive +slug: Glossary/Document_directive +tags: + - 指令 + - 術語表 +translation_of: Glossary/Document_directive +--- +

{{Glossary("CSP")}} 文件指令 被用在 {{HTTPHeader("Content-Security-Policy")}} 頭部和管理應用策略的文件或工作者環境的屬性。

+ +

文件指令不會回退到 {{CSP("default-src")}} 指令。

+ +

這些 CSP 指令是文件指令:

+ + + +

了解更多

+ +

技術資訊

+ + diff --git a/files/zh-tw/glossary/dom/index.html b/files/zh-tw/glossary/dom/index.html new file mode 100644 index 0000000000..17b1aa58f2 --- /dev/null +++ b/files/zh-tw/glossary/dom/index.html @@ -0,0 +1,29 @@ +--- +title: DOM +slug: Glossary/DOM +tags: + - DOM + - 文件物件模組 + - 術語表 +translation_of: Glossary/DOM +--- +

DOM(Document Object Model, DOM) 是用來表示和與任何{{glossary("HTML")}} 或 {{glossary("XML")}} 文件互動的 {{glossary("API")}}。DOM是一個載入於{{glossary("browser")}}中的文件模組,它的表示方式像樹的節點一樣, 每個節點代表著文件的一部分(如:{{Glossary("element")}}、 文字或留言)。

+ +

DOM是一個在{{glossary("World Wide Web","Web")}}中最常被使用的{{Glossary("API")}}s,因為它在瀏覽器中允許程式碼執行存取和互動任何在文件中的節點。 節點可以被創建、移動和變更。事件監聽器可以被新增至節點中,當發生特定事件時會被觸發。

+ +

DOM最初並沒有被定義—它是來自於當瀏覽器開始啟用{{Glossary("JavaScript")}}時出現。這個老舊的DOM有時候會稱DOM 0。此時此刻, WHATWG推動著DOM現存的標準.

+ +

了解更多

+ +

基本知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/domain/index.html b/files/zh-tw/glossary/domain/index.html new file mode 100644 index 0000000000..311c5d0589 --- /dev/null +++ b/files/zh-tw/glossary/domain/index.html @@ -0,0 +1,16 @@ +--- +title: 域 +slug: Glossary/Domain +tags: + - 域 + - 瀏覽器 + - 術語表 +translation_of: Glossary/Domain +--- +

域是實體控制數據處理資源的電腦網路的一部分,比如說網站。

+ +

了解更多

+ + diff --git a/files/zh-tw/glossary/domain_name/index.html b/files/zh-tw/glossary/domain_name/index.html new file mode 100644 index 0000000000..89565e0310 --- /dev/null +++ b/files/zh-tw/glossary/domain_name/index.html @@ -0,0 +1,18 @@ +--- +title: 域名 +slug: Glossary/Domain_name +tags: + - 域名 + - 術語表 +translation_of: Glossary/Domain_name +--- +

域名是指在網際網路({{Glossary("Internet")}})上的網站地址。它在網址({{Glossary("URL","URLs")}})裡被用來確定所屬伺服器的具體網頁。它由一組層次順序標籤 (labels)組成並以句點 (dots)分割和擴展名({{glossary("TLD","extension")}})結尾。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/dos_attack/index.html b/files/zh-tw/glossary/dos_attack/index.html new file mode 100644 index 0000000000..84c0b65a0f --- /dev/null +++ b/files/zh-tw/glossary/dos_attack/index.html @@ -0,0 +1,34 @@ +--- +title: DoS 攻擊 +slug: Glossary/DOS_attack +tags: + - DoS + - 安全性 + - 術語表 +translation_of: Glossary/DOS_attack +--- +

DoS (拒絕服務)是一種網路攻擊手段,它通過大量的伺服器請求來阻止合法使用伺服器({{glossary("server")}})資源。

+ +

計算機的資源有限,例如計算能力或内存。當這些資源過載,程式可能會凍結或崩潰,導致程式不可用。DoS 攻擊由耗盡資源、使伺服器或網路對合法用戶不可用、使服務器執行緩慢等多種技術組成。

+ +

DoS 攻擊的類型

+ +

DoS 攻擊更多的是一種類別而不是具體的某種方式的攻擊。如下是 DoS 攻擊類型的不完全列表: 

+ + + +

了解更多

+ + diff --git a/files/zh-tw/glossary/ecma/index.html b/files/zh-tw/glossary/ecma/index.html new file mode 100644 index 0000000000..441fc58302 --- /dev/null +++ b/files/zh-tw/glossary/ecma/index.html @@ -0,0 +1,20 @@ +--- +title: ECMA +slug: Glossary/ECMA +tags: + - Glossary + - Stub + - WebMechanics + - 'l10n:priority' +translation_of: Glossary/ECMA +--- +

Ecma International (全名 European Computer Manufacturers Association,歐洲電腦製造商協會)是一個制定電腦硬體、通訊、程式語言標準的非營利組織。

+ +

該組織維護 ECMA-262 規格(又稱 {{Glossary("ECMAScript")}}),也就是 {{Glossary("JavaScript")}} 語言的核心標準規格,而在網路上為人所知。

+ +

了解更多

+ + diff --git a/files/zh-tw/glossary/ecmascript/index.html b/files/zh-tw/glossary/ecmascript/index.html new file mode 100644 index 0000000000..d27e9454e1 --- /dev/null +++ b/files/zh-tw/glossary/ecmascript/index.html @@ -0,0 +1,22 @@ +--- +title: ECMAScript +slug: Glossary/ECMAScript +tags: + - 術語 +translation_of: Glossary/ECMAScript +--- +

ECMAScript 是一種腳本語言,且 {{glossary("JavaScript")}} 奠基於此之上。Ecma International 這個組織負責將 ECMAScript 標準化。

+ +

了解更多

+ +

基本知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/element/index.html b/files/zh-tw/glossary/element/index.html new file mode 100644 index 0000000000..0b455c993b --- /dev/null +++ b/files/zh-tw/glossary/element/index.html @@ -0,0 +1,20 @@ +--- +title: 元素 +slug: Glossary/Element +tags: + - HTML + - 術語 +translation_of: Glossary/Element +--- +

元素(element)是網頁結構的一部分。在 XML 與 HTML 中,元素可能包含資料清單、文字、圖片,或是也可能不包含東西。典型的元素會包含一個有些許屬性(attributes)的開始標籤(opening tag)、被包覆住的文字內容,以及一個結束標籤(closing tag)。
+ Example: in <p class="nice">Hello world!</p>, '<p class="nice">' is an opening tag, 'class="nice"' is an attribute and its value, 'Hello world!' is enclosed text content, and '</p>' is a closing tag.

+ +

元素與標籤是不同的概念。在原始碼中,標籤用來標注元素開始與結束,而元素其實是 {{Glossary("DOM")}} 的一部分。DOM,指文件物件模型(document object model),會由 {{glossary("browser")}} 將 DOM 呈現為網頁。

+ +

瞭解更多

+ + diff --git a/files/zh-tw/glossary/empty_element/index.html b/files/zh-tw/glossary/empty_element/index.html new file mode 100644 index 0000000000..14876af156 --- /dev/null +++ b/files/zh-tw/glossary/empty_element/index.html @@ -0,0 +1,33 @@ +--- +title: Empty element +slug: Glossary/Empty_element +tags: + - 置空元素 + - 術語表 +translation_of: Glossary/Empty_element +--- +

置空元素(empty element)是一種來自HTML、 SVG 或 MathML 不能有任何子節點 (如,嵌套元素或 文本節點)的元素({{Glossary("element")}})。

+ +

HTMLSVGMathML 規範非常精確地定義了每個元素可以包含什麼。很多組合沒有語義意義,例如 {{HTMLElement("audio")}} 元素嵌套{{HTMLElement("hr")}} 元素。

+ +

在 HTML,給置空元素使用閉合標籤是無效的。例如:<input type="text"></input> 就是無效的 HTML。

+ +

 HTML的置空元素列表如下:

+ + diff --git a/files/zh-tw/glossary/engine/index.html b/files/zh-tw/glossary/engine/index.html new file mode 100644 index 0000000000..b959e4de46 --- /dev/null +++ b/files/zh-tw/glossary/engine/index.html @@ -0,0 +1,17 @@ +--- +title: Engine +slug: Glossary/Engine +tags: + - 引擎 + - 術語表 +translation_of: Glossary/Engine +--- +

{{glossary("JavaScript")}} 引擎是解析和執行 JavaScript 程式的翻譯員。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/event/index.html b/files/zh-tw/glossary/event/index.html new file mode 100644 index 0000000000..fb95918359 --- /dev/null +++ b/files/zh-tw/glossary/event/index.html @@ -0,0 +1,24 @@ +--- +title: 事件 +slug: Glossary/event +tags: + - 事件 + - 術語表 +translation_of: Glossary/event +--- +

事件是 DOM 元素產生的事情,它可以通過 Javascript 代碼來操作.

+ +

了解更多

+ +

技術參考

+ + + +

基礎知識

+ + diff --git a/files/zh-tw/glossary/firefox_os/index.html b/files/zh-tw/glossary/firefox_os/index.html new file mode 100644 index 0000000000..050eec7eed --- /dev/null +++ b/files/zh-tw/glossary/firefox_os/index.html @@ -0,0 +1,23 @@ +--- +title: Firefox OS +slug: Glossary/Firefox_OS +tags: + - Firefox OS + - 術語表 +translation_of: Glossary/Firefox_OS +--- +

Firefox OS 是 Mozilla's 手機操作系統,基於 Linux 和 {{glossary("Mozilla Firefox","Firefox's")}} 强大的 {{glossary("Gecko")}} 渲染引擎。Firefox OS 主要由 {{glossary("Gaia")}}, {{glossary("Gecko")}}, 和 {{glossary("Gonk")}} 組成。

+ +

了解更多

+ +

基礎知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/firewall/index.html b/files/zh-tw/glossary/firewall/index.html new file mode 100644 index 0000000000..f2b6ce11e7 --- /dev/null +++ b/files/zh-tw/glossary/firewall/index.html @@ -0,0 +1,20 @@ +--- +title: 防火墻 +slug: Glossary/firewall +tags: + - 安全性 + - 術語表 + - 防火墻 +translation_of: Glossary/firewall +--- +

防火墻是一個過濾網路流量的系統。 它也可以根據一些特定的規則,讓它穿透或阻止它。例如,它可以阻止特定端口的傳入鏈接或者是傳出鏈接到特定的 IP 地址。 

+ +

防火墻可以像單一軟體的一樣簡單或者更複雜,就像專門的軟體,衹有防火墻一個功能。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/first-class_function/index.html b/files/zh-tw/glossary/first-class_function/index.html new file mode 100644 index 0000000000..f4f9e1d50b --- /dev/null +++ b/files/zh-tw/glossary/first-class_function/index.html @@ -0,0 +1,98 @@ +--- +title: 一級函式(First-class Function) +slug: Glossary/First-class_Function +translation_of: Glossary/First-class_Function +--- +

當函式在那個語言中可以被視為跟其他的變數一樣時,我們稱那樣的程式語言擁有一級函式。例如,函式可以作為參數傳遞到另一個函式,可以被另一個函式作為回傳值且可以被當作值一樣指派到另一個變數。

+ +

範例 | 指定函式到一個變數

+ +

JavaScript

+ +
const foo = function() {
+   console.log("foobar");
+}
+// Invoke it using the variable
+foo();
+
+ +

我們指派一個 匿名函式變數 中,然後在這個變數後面加上括弧 () 的方式來調用那個函式。

+ +
+

即使你已經為函式命名了,你仍然可以透過這個變數的名稱來調用它。有命名的函數在你除錯時是有幫助的。但是這並不會影響我們調用它的方式

+
+ +

範例 | 將函式作為參數來傳遞

+ +

JavaScript

+ +
function sayHello() {
+   return "Hello, ";
+}
+function greeting(helloMessage, name) {
+  console.log(helloMessage() + name);
+}
+// Pass `sayHello` as an argument to `greeting` function
+greeting(sayHello, "JavaScript!");
+
+ +

我們將 sayHello() 函式當成是變數傳遞到 greeting() 函式,這說明了我們將函式視為是一個   來使用它。

+ +
+

將函式作為參數傳遞到另一個函式時,被當作參數傳遞的那個函式我們稱之為回調函式 Callback function sayHello 就是一個回調函式。

+
+ +

範例 | 回傳一個函式

+ +

JavaScript

+ +
function sayHello() {
+   return function() {
+      console.log("Hello!");
+   }
+}
+
+ +

在這個例子中,我們需要從另一個函式中回傳函式回來 - 在 JavaScript 中,我們可以回傳函式是因為我們將函式當成是一個  。

+ +
+

當一個函式可以回傳一個函式時,稱之為高階函式 ( Higher-Order Function )。

+
+ +

回到剛才的例子,現在我們需要調用 sayHello 函式與它所回傳的匿名函式 (Anonymous Function)。 為了達成這個目標,我們有兩種方式:

+ +

1- 使用變數

+ +
const sayHello = function() {
+   return function() {
+      console.log("Hello!");
+   }
+}
+const myFunc = sayHello();
+myFunc();
+
+ +

這樣做的話,它會回傳 Hello! 這個訊息。

+ +
+

如果你直接調用 sayHello 的話,你必須再使用另一個變數來儲存之後再調用它,調用 sayHello 只會回傳函式回來而非調用它所回傳的函式

+
+ +

2- 使用雙括號

+ +
function sayHello() {
+   return function() {
+      console.log("Hello!");
+   }
+}
+sayHello()();
+ +

我們也可使用雙括號 ()() 來調用所回傳的函數。

+ +

Learn more

+ +

General knowledge

+ + diff --git a/files/zh-tw/glossary/first_contentful_paint/index.html b/files/zh-tw/glossary/first_contentful_paint/index.html new file mode 100644 index 0000000000..25ac67cbcb --- /dev/null +++ b/files/zh-tw/glossary/first_contentful_paint/index.html @@ -0,0 +1,15 @@ +--- +title: 首次內容繪製 +slug: Glossary/First_contentful_paint +translation_of: Glossary/First_contentful_paint +--- +

首次內容繪製 (First Contentful Paint, FCP) 是當瀏覽器從文件物件模型 (DOM) 渲染第一塊內容,第一次提供頁面正在載入的回饋給使用者。這個問題是「它發生了嗎?」當首次內容繪製完成時,答案為「是的」。

+ +

首次內容繪製時間戳記是當瀏覽器第一次渲染任何文字、圖片(包含背景圖片),以及非空白的 canvas 標籤或 SVG 向量圖片。排除任何 iframe 裡的內容,但包含等待中的網路字體 (webfonts)。意即使用者第一次開始使用頁面內容。

+ +

也可以看看:

+ + diff --git a/files/zh-tw/glossary/first_cpu_idle/index.html b/files/zh-tw/glossary/first_cpu_idle/index.html new file mode 100644 index 0000000000..c2ea874868 --- /dev/null +++ b/files/zh-tw/glossary/first_cpu_idle/index.html @@ -0,0 +1,6 @@ +--- +title: 首次 CPU 閒置 +slug: Glossary/First_CPU_idle +translation_of: Glossary/First_CPU_idle +--- +

首次 CPU 閒置 (First CPU Idle)  測量當頁面進行最小幅度的互動或適當視窗平靜到足夠處理使用者的輸入。它是一個非標準的 Google 網站效能指標。一般來說,它發生在大部分但是非必要的所有可見 UI 元素進行互動時,且使用者介面能做出回應,大多數平均的使用者輸入落在 50 毫秒。它也被稱為 First interactive 。

diff --git a/files/zh-tw/glossary/first_input_delay/index.html b/files/zh-tw/glossary/first_input_delay/index.html new file mode 100644 index 0000000000..0161930979 --- /dev/null +++ b/files/zh-tw/glossary/first_input_delay/index.html @@ -0,0 +1,15 @@ +--- +title: 首次輸入延遲 +slug: Glossary/First_input_delay +translation_of: Glossary/First_input_delay +--- +

首次輸入延遲 (First input delay, FID) 測量從使用者第一次與你的網站互動(例如當他們點選連結、按鈕或是使用自訂的 JavaScript 控制),瀏覽器實際上能夠回應此次互動的時間點。它是個在首次使用者於網頁互動以及瀏覽器回應此互動的時間長度 (以毫秒為單位)。捲動與縮放行為都不包含在這個指標。

+ +

這個時間介於內容已經在頁面繪製完成 (FCP) 以及所有功能都能夠回應使用者的互動時間。通常取決於 JavaScript 需要在主執行緒下載、剖析、以及執行,而且在缺乏裝置速度 (考慮低階行動裝置) 的情況。延遲時間越長,使用者體驗越差。縮短網站初始化時間以及預估 long tasks 有助於預估首次輸入延遲。 

+ +

也可以看看

+ + diff --git a/files/zh-tw/glossary/ftp/index.html b/files/zh-tw/glossary/ftp/index.html new file mode 100644 index 0000000000..ade332674a --- /dev/null +++ b/files/zh-tw/glossary/ftp/index.html @@ -0,0 +1,20 @@ +--- +title: FTP +slug: Glossary/FTP +tags: + - FTP + - 術語表 +translation_of: Glossary/FTP +--- +

FTP (文件傳輸協定)作爲從一個伺服器({{glossary("host")}}) 到另一個伺服器通過網路傳輸文件的標準協定({{glossary("protocol")}})很多年。不過逐漸現在很多團隊和托管賬戶不允許使用 FTP 并且使用依賴于版本控制系統如 Git 代替。你可能會發現在老的托管賬戶中仍有使用它,但確切的說, FTP不再是最佳實踐。 

+ +

了解更多

+ +

基礎知識

+ + + +

 

diff --git a/files/zh-tw/glossary/git/index.html b/files/zh-tw/glossary/git/index.html new file mode 100644 index 0000000000..06b4272e1b --- /dev/null +++ b/files/zh-tw/glossary/git/index.html @@ -0,0 +1,15 @@ +--- +title: Git +slug: Glossary/Git +translation_of: Glossary/Git +--- +

Git 是一套自由、開放原始碼,分散式原始碼管理({{Glossary("SCM", "SCM", 1)}})的工具軟體。它有助於分散式的開發團隊處理程式碼協同作業。有別於以前的原始碼管理系統,本地開發環境能處理常用的操作(分支、提交等),而無需更改主要的程式碼儲存倉庫,即使沒有寫入權限。

+ +

學習更多

+ +

一般知識

+ + diff --git a/files/zh-tw/glossary/grid/index.html b/files/zh-tw/glossary/grid/index.html new file mode 100644 index 0000000000..08c6263d8b --- /dev/null +++ b/files/zh-tw/glossary/grid/index.html @@ -0,0 +1,71 @@ +--- +title: Grid +slug: Glossary/Grid +translation_of: Glossary/Grid +--- +

CSS 格線(CSS grid) 使用 display: grid; 值,你可以透過 {{cssxref("grid-template-rows")}} 與 {{cssxref("grid-template-columns")}} 屬性定義格線的行(Row)與列(Column)。

+ +

使用這些屬性的格線會稱做明式格線(explicit grid)。

+ +

如果把內容放在明式格線外;或是依賴自動配置、而格線演算法要建立額外的{{glossary("grid tracks", "格線軌道")}}以支持{{glossary("grid item", "格線單元")}}的話,明式格線內就會建立額外的格線軌道。明式格線是指內容因為定義的軌道外增添,而自動建立內容的格線。

+ +

下例創建了三列兩行的明式格線。格線第三行是明式格線行軌道,它是為了讓超過六個單元的格線,能夠填滿明式格線。

+ +
+ + +
.wrapper {
+  display: grid;
+  grid-template-columns: 1fr 1fr 1fr;
+  grid-template-rows: 100px 100px;
+}
+
+ +
<div class="wrapper">
+   <div>One</div>
+   <div>Two</div>
+   <div>Three</div>
+   <div>Four</div>
+   <div>Five</div>
+   <div>Six</div>
+   <div>Seven</div>
+   <div>Eight</div>
+</div>
+
+ +

{{ EmbedLiveSample('example', '500', '330') }}

+ +

深入理解re

+ +

屬性參考

+ + + +

參閱

+ + +
diff --git a/files/zh-tw/glossary/hash/index.html b/files/zh-tw/glossary/hash/index.html new file mode 100644 index 0000000000..358c8c54ab --- /dev/null +++ b/files/zh-tw/glossary/hash/index.html @@ -0,0 +1,17 @@ +--- +title: 散列 +slug: Glossary/hash +tags: + - Hash + - 術語表 +translation_of: Glossary/hash +--- +

散列函式需要一個可變長度的消息輸入并產生一個固定長度的輸出。它通常是以128位的指紋或信息摘要的形式出現。散列對於密碼學({{glossary("cryptography")}})非常有用-它們確保了傳輸數據的完整性。這為提供消息認證的{{glossary("HMAC's")}}提供了基礎。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/head/index.html b/files/zh-tw/glossary/head/index.html new file mode 100644 index 0000000000..73baa9e8b8 --- /dev/null +++ b/files/zh-tw/glossary/head/index.html @@ -0,0 +1,19 @@ +--- +title: Head +slug: Glossary/Head +tags: + - HTML + - head + - 術語表 +translation_of: Glossary/Head +--- +

Head 是一個 {{glossary("HTML")}} 文檔的一部分,它包含了關於文檔的 {{glossary("metadata")}},如作者(author)、描述(description)、 和引入 {{glossary("CSS")}} 或 {{glossary("JavaScript")}} 文件 并將應用于HTML。

+ +

了解更多

+ +

HTML head

+ + diff --git a/files/zh-tw/glossary/hoisting/index.html b/files/zh-tw/glossary/hoisting/index.html new file mode 100644 index 0000000000..650e30013c --- /dev/null +++ b/files/zh-tw/glossary/hoisting/index.html @@ -0,0 +1,72 @@ +--- +title: 提升(Hoisting) +slug: Glossary/Hoisting +tags: + - JavaScript + - hoisting + - 提升 +translation_of: Glossary/Hoisting +--- +

提升(Hoisting)是在 ECMAScript® 2015 Language Specification 裡面找不到的專有名詞。它是一種釐清 JaveScript 在執行階段內文如何運行的思路(尤其是在創建和執行階段)。然而,提升一詞可能會引起誤解:例如,提升看起來是單純地將變數和函式宣告,移動到程式的區塊頂端,然而並非如此。變數和函數的宣告會在編譯階段就被放入記憶體,但實際位置和程式碼中完全一樣。

+ +

了解更多

+ +

技術範例

+ +

在執行任何程式碼前,JavaScript 會把函式宣告放進記憶體裡面,這樣做的優點是:可以在程式碼宣告該函式之前使用它。
例如:

+ +
function catName(name) {
+  console.log("My cat's name is " + name);
+}
+
+catName("Tigger");
+/*
+上面程式的結果是: "My cat's name is Tigger"
+*/
+
+ +

上面的程式碼片段,就是你希望程式碼運作的樣子。現在讓我們看看,如果在這一段函式宣告之前就執行它,到底會發生什麼事:

+ +
catName("Chloe");
+
+function catName(name) {
+  console.log("My cat's name is " + name);
+}
+/*
+上面程式的結果是: "My cat's name is Chloe"
+*/
+
+ +

即使我們函式的程式碼之前就先呼叫它,程式碼仍然可以運作。這是出於 JavaScript 內文執行的運作原理。

+ +

提升也適用於其他型別和變數。變數可以在宣告之前進行初始化和使用。但如果沒有初始化,就不能使用它們。

+ +

技術範例

+ +
num = 6;
+num + 7;
+var num;
+/* 只要 num 有被宣告,就不會有錯誤 */
+
+
+ +

JavaScript 僅提升宣告的部分,而不是初始化。如果在使用該變數後才宣告和初始化,那麼該值將是 undefined。以下兩個範例顯示了這個特性。

+ +
var x = 1; // 初始化 x
+console.log(x + " " + y);  // '1 undefined'
+var y = 2;
+//上下的程式結果都一樣
+
+var x = 1; // 初始化 x
+var y; // 宣告 y
+console.log(x + " " + y);  // '1 undefined'
+y = 2; // 初始化 y
+
+ +

技術參考

+ + diff --git a/files/zh-tw/glossary/host/index.html b/files/zh-tw/glossary/host/index.html new file mode 100644 index 0000000000..c48024c384 --- /dev/null +++ b/files/zh-tw/glossary/host/index.html @@ -0,0 +1,20 @@ +--- +title: 主機 +slug: Glossary/Host +tags: + - 主機 + - 網頁 + - 術語表 +translation_of: Glossary/Host +--- +

主機是一種連接網際網路({{glossary("Internet")}})或本地網路的設備。有些稱作伺服器({{glossary("server")}})的主機還會提供額外的服務:像是提供網頁服務、存放文件和郵件。

+ +

伺服器的主機服務可以是由硬體直接產生,也可以由軟體程式產生虛擬實體。後者被稱為虛擬主機(Virtual hosting)。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/html/index.html b/files/zh-tw/glossary/html/index.html new file mode 100644 index 0000000000..c2a0dd5ed0 --- /dev/null +++ b/files/zh-tw/glossary/html/index.html @@ -0,0 +1,51 @@ +--- +title: HTML +slug: Glossary/HTML +tags: + - CodingScripting + - Glossary + - HTML + - 'l10n:priority' +translation_of: Glossary/HTML +--- +
{{QuickLinksWithSubpages("/en-US/docs/Glossary")}}
+ +

超文件標示語言(HTML,HyperText Markup Language)是用於指定網頁結構的描述性語言。

+ +

簡歷

+ +

在 1990 年,作為 Tim Berners-Lee 對{{Glossary("World Wide Web","網路")}}所知的一部分,{{Glossary("hypertext","超文本")}}的概念被定義起來了。隔年,Berners-Lee 以 {{Glossary("SGML")}} 的標記為基礎定型起來。{{Glossary("IETF")}} 於 1993 年規範了 HTML、並在 1995 年發布 2.0(第二版)。1994 年 Berners-Lee 成立了 {{Glossary("W3C")}} 以便發展網路。1996 年,W3C 接手 HTML 的工作,並在隔年發布了 HTML 3.2 Recommendation(HTML 3.2 建議)。在 1999 年發布了 HTML 4.0 並在 2000 年成為 {{Glossary("ISO")}} 標準。

+ +

這段期間,偏好 {{Glossary("XHTML")}} 的 W3C 幾乎拋棄了 HTML,使得 2004 年一個稱作 {{Glossary("WHATWG")}} 的獨立團體成立起來。也因為 WHATWG 的努力,{{Glossary("HTML5")}} 的工作持續進行:兩個組織在 2008 年發布了第一份草稿、最終標準則在 2014 年實行。

+ +

概念及語法

+ +

HTML 是個以{{Glossary("element","元素")}}構成的純文字文件。元素通常被開啟與關閉的{{Glossary("tag","標籤")}}包覆起來。每個標籤都以角括號(<>)作為開始與結束。不過,也有些不包覆任何文件的空標籤(empty or void tag),例如 {{htmlelement("img")}}。

+ +

你可以透過{{Glossary("attribute","屬性")}}擴展 HTML 標籤,它能提供附加訊息,以改變瀏覽器的解釋方法:

+ +

HTML 元素的結構資訊

+ +

HTML 文件的副檔名通常存為 .htm 或是 .html。它們會放在{{Glossary("伺服器","網頁伺服器")}}上運作、並由{{Glossary("瀏覽器")}}渲染。

+ +

深入了解

+ +

基本知識

+ + + +

學習 HTML

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/html5/index.html b/files/zh-tw/glossary/html5/index.html new file mode 100644 index 0000000000..60f627a355 --- /dev/null +++ b/files/zh-tw/glossary/html5/index.html @@ -0,0 +1,16 @@ +--- +title: HTML5 +slug: Glossary/HTML5 +tags: + - HTML + - HTML5 + - 術語表 +translation_of: Glossary/HTML5 +--- +

{{Glossary("HTML")}} 最新的穩定版本, HTML5 將 HTML 從簡單的文檔結構標記帶領到全app 開發平臺。新增了更多其他的功能, HTML5 包含了新的元素和{{glossary("JavaScript")}} {{glossary("API","APIs")}},它們提高了存儲、多媒體和硬體訪問的效率。

+ +

了解更多

+ + diff --git a/files/zh-tw/glossary/http/index.html b/files/zh-tw/glossary/http/index.html new file mode 100644 index 0000000000..fadef9e26f --- /dev/null +++ b/files/zh-tw/glossary/http/index.html @@ -0,0 +1,13 @@ +--- +title: HTTP +slug: Glossary/HTTP +translation_of: Glossary/HTTP +--- +

超文字傳輸協定(HyperText Transfer Protocol、HTTP)是能在{{glossary("World Wide Web","全球資訊網")}}發起文件傳輸的基本{{glossary("protocol","協定")}}。HTTP 屬於文本性(所有交流都透過純文字完成)及無狀態(所有交流都不會記得上一次的交流)的。

+ +

深入了解

+ + diff --git a/files/zh-tw/glossary/identifier/index.html b/files/zh-tw/glossary/identifier/index.html new file mode 100644 index 0000000000..7cb9add9f3 --- /dev/null +++ b/files/zh-tw/glossary/identifier/index.html @@ -0,0 +1,19 @@ +--- +title: 識別字 +slug: Glossary/Identifier +tags: + - 術語表 + - 識別字 +translation_of: Glossary/Identifier +--- +

字符中的代碼序列定義了變數({{glossary("variable")}})、函式({{glossary("function")}}) 或屬性({{glossary("property")}})。

+ +

在 {{glossary("JavaScript")}} 中, 識別字衹能包含字母數字字符 (或 "$" 或 "_"),并不能以數字開頭。識別字不同於字符串,字符串是數據而識別字是代碼的一部分 。在 JavaScript 中,沒有辦法把識別字轉換為字符串,但有時候可能把字符串解析為識別碼。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/iife/index.html b/files/zh-tw/glossary/iife/index.html new file mode 100644 index 0000000000..10c20fbf91 --- /dev/null +++ b/files/zh-tw/glossary/iife/index.html @@ -0,0 +1,69 @@ +--- +title: IIFE +slug: Glossary/IIFE +translation_of: Glossary/IIFE +--- +

IIFE (Immediately Invoked Function Expression) 是一個定義完馬上就執行的 {{glossary("JavaScript")}} {{glossary("function")}}。

+ +

他又稱為 {{glossary("Self-Executing Anonymous Function")}},也是一種常見的設計模式,包含兩個主要部分:第一個部分是使用{{jsxref("Operators/Grouping", "Grouping Operator")}} () 包起來的 anonymous function。這樣的寫法可以避免裡面的變數污染到 global scope。

+ +

第二個部分是馬上執行 function 的 expression (),JavaScript 引擎看到它就會立刻轉譯該 function。

+ +

Examples

+ +

Function 轉換為 expression 形式,並且馬上執行,function scope 內的變數在外面是無法存取的。

+ +
(function () {
+    var aName = "Barry";
+})();
+// Variable name is not accessible from the outside scope
+aName // throws "Uncaught ReferenceError: aName is not defined"
+
+ +

把 IIFE 只配給變數會儲存它的結果,而非 function 本身

+ +
var result = (function () {
+    var name = "Barry";
+    return name;
+})();
+// Immediately creates the output:
+result; // "Barry"
+ +

其它形式

+ +

符合 JSLint 的版本,行為一樣,只有語意略有差異:

+ +
(function () {
+    var aName = "Barry";
+}());
+
+ +

Arrow function 版本,程式碼更為精簡,行為一致:

+ +
(() => {
+    var aName = "Barry";
+})();
+ +

Async function 版本,目前主要為了 top level await 而使用:

+ +
(async function () {
+    var aName = "Barry";
+})();
+
+(async () => {
+    var aName = "Barry";
+})();
+ +

更多資訊

+ +

學習它

+ + + +

基本知識

+ + diff --git a/files/zh-tw/glossary/immutable/index.html b/files/zh-tw/glossary/immutable/index.html new file mode 100644 index 0000000000..5bf9879041 --- /dev/null +++ b/files/zh-tw/glossary/immutable/index.html @@ -0,0 +1,22 @@ +--- +title: Immutable +slug: Glossary/Immutable +translation_of: Glossary/Immutable +--- +

我們在說一個不可變的{{glossary("物件")}},意思就是這樣的物件內容部會被改變。

+ +

在多數情況下會要使物件成為immutable,例如:

+ + + +

了解更多

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/index.html b/files/zh-tw/glossary/index.html new file mode 100644 index 0000000000..e09fd53b7c --- /dev/null +++ b/files/zh-tw/glossary/index.html @@ -0,0 +1,25 @@ +--- +title: 術語表 +slug: Glossary +tags: + - Beginner + - Glossary + - Index + - TopicStub +translation_of: Glossary +--- +
{{LearnBox({"title":"Learn a new term:"})}}
+ +

網路技術包含了一長串的術語以及縮寫,這些會被使用在文件跟程式碼中。此術語表提供你需要知道的辭彙與縮寫的定義,以便能成功理解和建構網路。

+ +

{{GlossaryList({"split":"h3", "css":"multiColumnList"})}}

+ +

為術語表作貢獻

+ +

這個術語表永遠不會寫完。你可以幫忙撰寫新術語或是改寫現有的術語。最簡單的開始方法,就是按下面的按鈕,或是點選其中一個術語。

+ +

撰寫新的術語

+ +

{{GlossaryList({"terms":["at-rule","Attack","Character set","cryptosystem","debug","digital signature","execution","flex-direction","fork","GLSL","Grid Container","Interface", "Intrinsic size","Library","Memory management","Public-key crytography","routers","RTP","RTSP","Self-Executing Anonymous Function","Stylesheet","Symmetric-key cryptography","Vector image"], "filter":"notdefined", "css":"multiColumnList"})}}

+ +

如果想知道如何建設術語表,請看看術語表文件的進度頁面

diff --git a/files/zh-tw/glossary/indexeddb/index.html b/files/zh-tw/glossary/indexeddb/index.html new file mode 100644 index 0000000000..3da56fa08c --- /dev/null +++ b/files/zh-tw/glossary/indexeddb/index.html @@ -0,0 +1,20 @@ +--- +title: IndexedDB +slug: Glossary/IndexedDB +tags: + - API + - Sql + - 'l10n:priority' + - 撰寫程式 + - 術語表 + - 資料庫 +translation_of: Glossary/IndexedDB +--- +

IndexedDB 是一個用來在瀏覽器內儲存大型數據結構,並對其建立索引以高效查詢的 Web {{glossary("API")}}。類似基於 {{glossary("SQL")}} 的 關連式資料庫管理系統(RDBMS), IndexedDB 是一套交易式資料庫系統。然而,它使用 {{glossary("JavaScript")}} 物件而非固定欄位的資料表來記錄資料。

+ +

了解更多

+ + diff --git a/files/zh-tw/glossary/ip_address/index.html b/files/zh-tw/glossary/ip_address/index.html new file mode 100644 index 0000000000..1bc874eb9a --- /dev/null +++ b/files/zh-tw/glossary/ip_address/index.html @@ -0,0 +1,21 @@ +--- +title: IP 位址 +slug: Glossary/IP_Address +tags: + - Beginner + - Glossary + - Infrastructure + - Web +translation_of: Glossary/IP_Address +--- +

IP 位址是一組分配給所有使用網際網路通訊協定的裝置的編號。

+ +

在 IPv6 被更廣泛採用前,「IP 位址」一般來說指的仍然是 32 位元長度的 IPv4 位址。

+ +

了解更多

+ +

一般知識

+ + diff --git a/files/zh-tw/glossary/jank/index.html b/files/zh-tw/glossary/jank/index.html new file mode 100644 index 0000000000..68af9b8f07 --- /dev/null +++ b/files/zh-tw/glossary/jank/index.html @@ -0,0 +1,6 @@ +--- +title: Jank +slug: Glossary/Jank +translation_of: Glossary/Jank +--- +

Jank 是在講用戶介面的執行緩慢,主因是主執行緒的執行過久、或是遭到封鎖的渲染、抑或在後台進程上,花費太多的處理器能力。

diff --git a/files/zh-tw/glossary/java/index.html b/files/zh-tw/glossary/java/index.html new file mode 100644 index 0000000000..0675ad405f --- /dev/null +++ b/files/zh-tw/glossary/java/index.html @@ -0,0 +1,23 @@ +--- +title: Java +slug: Glossary/Java +tags: + - Java + - 術語表 +translation_of: Glossary/Java +--- +

Java 是一個{{glossary("Compile", "編譯式")}}、{{glossary("OOP", "物件導向")}}、可攜性高的{{Glossary("computer programming", "程式設計")}}語言。

+ +

Java 屬於靜態型別,並具有類 C 的語法。它還有個稱作 Java 軟體開發套件(Java Software Development Kit, SDK)的函式庫,裡面有很多易於使用的功能包。

+ +

程式只提前{{glossary("Compile", "編譯")}}一次,編譯成專有的字節碼和包格式,接著在 Java 虛擬機(Java Virtual Machine, JVM)內部執行。JVM 支持跨平台,這使得 Java 程式幾乎可以在任何地方運行,而無需再次編譯或打包。這個特性使它成為很多大型企業的首選,但也可能會被認為過於「沉重」。

+ +

了解更多

+ +

基礎知識

+ + + +
{{QuickLinksWithSubpages("/zh-TW/docs/Glossary")}}
diff --git a/files/zh-tw/glossary/javascript/index.html b/files/zh-tw/glossary/javascript/index.html new file mode 100644 index 0000000000..0e0f970f4d --- /dev/null +++ b/files/zh-tw/glossary/javascript/index.html @@ -0,0 +1,41 @@ +--- +title: JavaScript +slug: Glossary/JavaScript +translation_of: Glossary/JavaScript +--- +

JavaScript(JS)是個程式語言。通常用於用戶端(client-side)的動態網頁腳本,不過也常藉由 Node.js 之類的軟體包,使用到{{Glossary("Server","伺服器")}}端(Server-side)。

+ +

不要把 JavaScript 與 {{interwiki("wikipedia", "Java")}} 這兩個程式語言混淆了。雖然「Java」與「JavaScript」都是甲骨文公司(Oracle)在美國和其他國家或地區註冊的商標,但這兩個程式語言在語法、語意、還有用處上,都有極大的不同。

+ +

前 Netscape 員工 Brendan Eich 原本想讓 JavaScript 成為伺服器端語言。但 JavaScript 卻在 1995 年九月於 Netscape Navigator 2.0 降生並得到隨之而來的成功。{{glossary("Microsoft Internet Explorer", "Internet Explorer 3.0")}} 也在 1996 年八月以 JScript 的名義支援 JavaScript。

+ +

1996 年十一月,Netscape 開始與 ECMA International 合作以期使 JavaScript 成為行業標準(industry standard)。從此以後,標準化的 JavaScript 就被稱為 ECMAScript 並規範在 ECMA-262 之下,其最新的第八版於 2017 年六月生效。

+ +

JavaScript 通常用於瀏覽器,使開發者能透過 {{Glossary("DOM")}} 操縱網頁內容、或透過 {{Glossary("AJAX")}} 與 {{Glossary("IndexedDB")}} 操縱資料;還可以用它在 {{Glossary("canvas")}} 上面繪圖、透過各種 {{Glossary("API","API")}} 與各種設備的瀏覽器交流……等等。由於近年各大瀏覽器的增長、以及 {{Glossary("API","APIs")}} 的效能改進,JavaScript 成了全世界最常用的程式語言之一。

+ +

最近,JavaScript 挾著非瀏覽器跨平台執行環境 Node.js 的巨大成功,重返了伺服器世界。電腦上的 Node.js 能讓 JavaScript 作為腳本語言使用以處理自動化。另外,還可以組建完整的 {{Glossary("HTTP")}} 與 {{Glossary("Web Sockets")}} 伺服器。

+ +

深入了解

+ +

基本知識

+ + + +

學習 JavaScript

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/jpeg/index.html b/files/zh-tw/glossary/jpeg/index.html new file mode 100644 index 0000000000..987a570df4 --- /dev/null +++ b/files/zh-tw/glossary/jpeg/index.html @@ -0,0 +1,14 @@ +--- +title: JPEG +slug: Glossary/jpeg +translation_of: Glossary/jpeg +--- +

JPEG(Joint Photographic Experts Group,聯合圖像專家小組)通常指是一種圖片的失真壓縮法。

+ +

深入理解

+ +

一般資訊

+ + diff --git a/files/zh-tw/glossary/jquery/index.html b/files/zh-tw/glossary/jquery/index.html new file mode 100644 index 0000000000..66c7f1035e --- /dev/null +++ b/files/zh-tw/glossary/jquery/index.html @@ -0,0 +1,42 @@ +--- +title: jQuery +slug: Glossary/jQuery +translation_of: Glossary/jQuery +--- +

jQuery 是專精於簡化 {{Glossary("DOM")}}、{{Glossary("AJAX")}}、與 {{Glossary("Event")}} 操作的 {{Glossary("JavaScript")}} {{Glossary("函式庫")}}。

+ +

jQuery 用 $(selector).action() 格式,指派元素到指定的事件。詳細來說, $(selector) 會呼叫 jQuery 選取 selector 元素,並指派它到稱作 .action() 事件的 {{Glossary("API")}}。

+ +
$(document).ready(function(){
+  alert("Hello World!");
+  $("#blackBox").hide();
+});
+ +

上面這段 jQuery 程式碼,會執行與這段原生 JavaScript 程式碼相同的事情:

+ +
window.onload = function() {
+  alert("Hello World!");
+  document.getElementById("blackBox").style.display = "none";
+};
+ +

或這段:

+ +
window.addEventListener("load", () => {
+  alert("Hello World!");
+  document.getElementById("blackBox").style.display = "none";
+});
+ +

深入理解

+ +

基本知識

+ + + +

技術資訊

+ + diff --git a/files/zh-tw/glossary/json/index.html b/files/zh-tw/glossary/json/index.html new file mode 100644 index 0000000000..776ffecdcb --- /dev/null +++ b/files/zh-tw/glossary/json/index.html @@ -0,0 +1,29 @@ +--- +title: JSON +slug: Glossary/JSON +tags: + - CodingScripting + - Glossary + - Intro + - JSON +translation_of: Glossary/JSON +--- +

JavaScript Object NotationJSON)是一種資料交換格式。JSON 的語法非常接近 {{Glossary("JavaScript")}},但嚴格上來說 JSON 並不是 JavaScript 的一個子集。許多程式語言都支援 JSON,不過 JSON 在基於 JavaScript 的應用程式(包含網站和瀏覽器擴充功能)中特別有用。

+ +

JSON 可以表示數字、布林值、字串、null、陣列(一些有順序的數值),以及由這些數值所組成的物件(字串和數值的對應表)。原生的 JSON 不能用來表示較複雜的資料,像是函式、正規表達式、日期等。(日期物件可以被序列化成為 ISO 格式的日期字串,不會完全遺失資料。)如果你需要 JSON 來表示這些額外的資料類型,請在他們序列或反序列化時轉換數值。

+ +

JSON 和 XML 很像,能夠儲存傳統 CSV 格式不能儲存的多層級資料。有許多工具可以互相轉換這些格式,例如 JSON to CSV Converter

+ +

了解更多

+ +

基礎知識

+ + + +

技術資料

+ + diff --git a/files/zh-tw/glossary/key/index.html b/files/zh-tw/glossary/key/index.html new file mode 100644 index 0000000000..70c8f5c612 --- /dev/null +++ b/files/zh-tw/glossary/key/index.html @@ -0,0 +1,20 @@ +--- +title: Key +slug: Glossary/Key +tags: + - Key + - 安全性 + - 術語表 +translation_of: Glossary/Key +--- +

密鑰是密碼({{Glossary("cipher")}})用於加密({{Glossary("encryption")}}) 和/或解密({{Glossary("decryption")}})的一條信息。 關於加密系統({{Glossary("cryptosystem")}})的所有加密信息都應該保持安全,除了密鑰,這是公共的認知。

+ +

在對稱密鑰密碼學({{Glossary("symmetric-key cryptography")}})中,同時使用相同的密鑰加解密。在公共密鑰密碼學({{Glossary("public-key cryptography")}})中,存在一對作為公鑰和私鑰的相關密鑰。公鑰是免費提供的,而私鑰則是保密的。公鑰可以對只有相應私鑰解密的信息加密,反之亦然。

+ +

了解更多

+ +

技術參考

+ + diff --git a/files/zh-tw/glossary/keyword/index.html b/files/zh-tw/glossary/keyword/index.html new file mode 100644 index 0000000000..53e51ca354 --- /dev/null +++ b/files/zh-tw/glossary/keyword/index.html @@ -0,0 +1,19 @@ +--- +title: 關鍵詞 +slug: Glossary/Keyword +tags: + - 術語表 + - 關鍵詞 +translation_of: Glossary/Keyword +--- +

關鍵詞是描述内容的字或短語。在綫關鍵詞被用於搜索引擎的查詢或用來識別站點上的内容.

+ +

當你使用搜索引擎,你會使用指定的關鍵詞來搜索你想查找的東西,搜索引擎根據關鍵詞來返回相關的結果頁。爲了搜索到更精準的結果,需要嘗試更多指定的關鍵詞,如使用 "Blue Mustang GTO" 代替簡單的 "Mustang"。網頁也可以用 meta 標簽(寫在 {{htmlelement("head")}}使用關鍵詞描述頁面的内容,它可以使搜索引擎更好的定義和組織網頁。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/ligature/index.html b/files/zh-tw/glossary/ligature/index.html new file mode 100644 index 0000000000..a3909276cc --- /dev/null +++ b/files/zh-tw/glossary/ligature/index.html @@ -0,0 +1,16 @@ +--- +title: Ligature +slug: Glossary/Ligature +translation_of: Glossary/Ligature +--- +

所謂「連字」(ligature),即是將兩個字母整合為單一字母。以法文的「œ」為例,即是「o」與「e」的連字。

+ +

你可使用 {{cssxref("font-variant-ligatures")}} 在自己的網頁上設計出連字。

+ +

Learn more

+ +

General knowledge

+ + diff --git a/files/zh-tw/glossary/localization/index.html b/files/zh-tw/glossary/localization/index.html new file mode 100644 index 0000000000..01a4dec5ac --- /dev/null +++ b/files/zh-tw/glossary/localization/index.html @@ -0,0 +1,63 @@ +--- +title: 在地化 +slug: Glossary/Localization +tags: + - 本地化 +translation_of: Glossary/Localization +--- +

 

+ +
+

在地化 (Localization)(有時稱本地化)是將程式介面由一種語言翻譯成另一種語言,並調整各部份為適合當地文化及習慣的過程。下面的資源可協助建立 Mozilla 相關程式或套件的在地化工作。

+
+ + + + + + + + +
+

精選文件

+ +
+
XUL 教學:在地化
+
XUL 教學 中提到如何在地化 XUL 程式的小節。
+
+ +
+
XUL 教學:Property 檔案
+
XUL 教學 中解釋如何使用 Property 檔案的小節。
+
+ +
+
撰寫可在地化的程式碼
+
本文提供程式設計師們關於在地化的練習和撰寫準則。
+
+ +
+
如何翻譯套件敘述
+
想要翻譯套件敘述(就是擴充套件視窗中套件名稱下面的說明),你需要用特殊的 prefreence key 才能蓋掉 install.rdf 檔中原來的英文敘述。本文會教你如何修改 preference key。
+
+ +

所有文件...

+
+

其他頁面

+ + + +

相關主題

+ +
+
擴充套件, XUL
+
+ +

 

+
+ +
 
diff --git a/files/zh-tw/glossary/mathml/index.html b/files/zh-tw/glossary/mathml/index.html new file mode 100644 index 0000000000..0005ad20de --- /dev/null +++ b/files/zh-tw/glossary/mathml/index.html @@ -0,0 +1,23 @@ +--- +title: MathML +slug: Glossary/MathML +tags: + - MathML + - 術語表 +translation_of: Glossary/MathML +--- +

MathML (一種 {{glossary("XML")}} 應用程式)是一種在網頁上表示數學表達式的開放標準。在 1998 年 W3C 第一次在瀏覽器({{glossary("browser")}})推薦了 MathML 表示數學表達式。 MathML還有其他應用程式,它包括了科學内容和聲音合成。 

+ +

了解更多 

+ +

基礎知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/mime_type/index.html b/files/zh-tw/glossary/mime_type/index.html new file mode 100644 index 0000000000..cb2af73d63 --- /dev/null +++ b/files/zh-tw/glossary/mime_type/index.html @@ -0,0 +1,32 @@ +--- +title: MIME type +slug: Glossary/MIME_type +tags: + - MIME Types + - 内容類型 + - 媒體類型 + - 術語表 +translation_of: Glossary/MIME_type +--- +

MIME 類型 (現在被更準確的稱作「媒體類型」(media type),但有時也被稱作「内容類型」(content type)) 是一種隨附文件發送的標識字符串。它主要用於標示文件類型、描述內容的類型:例如說,一個聲音文件就可能標為audio/ogg、或者圖像檔案就可能是 image/png

+ +

它的目的與 Microsoft Windows 的副檔名相似。裡面的名字,是源自最初用於 E-Mail 的 MIME 標準。

+ +

了解更多

+ +

基礎知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/mvc/index.html b/files/zh-tw/glossary/mvc/index.html new file mode 100644 index 0000000000..28dcae8a52 --- /dev/null +++ b/files/zh-tw/glossary/mvc/index.html @@ -0,0 +1,28 @@ +--- +title: MVC +slug: Glossary/MVC +translation_of: Glossary/MVC +--- +

模型─視圖─控制器(Model-View-Controller, MVC)是個軟體設計模式。它強調把軟體的行事邏輯與排版顯示分離(也就是關注點分離,Separation of concerns),如此一來開發者們就可以輕鬆分派工作、以及維護專案。有些設計模式也基於 MVC,像是 MVVM(Model-View-ViewModel)、MTP(Model-View-Presenter)、and MVW(Model-View-Whatever) 等等。

+ +

MVC 在定義方面有爭議,但通常會包含:

+ +
    +
  1. 模型(Model):包含資料、或是軟體的行事邏輯。行事邏輯可以有演算法、與資料庫的溝通等。
  2. +
  3. 視圖(View):包含軟體的排版與顯示。
  4. +
  5. 控制器(Controller):包含軟體的行事邏輯、或是連接模型與視圖。
  6. +
+ +

深入理解

+ +

基本知識

+ + + +

學習 MVC

+ + diff --git a/files/zh-tw/glossary/node.js/index.html b/files/zh-tw/glossary/node.js/index.html new file mode 100644 index 0000000000..0d9524750f --- /dev/null +++ b/files/zh-tw/glossary/node.js/index.html @@ -0,0 +1,22 @@ +--- +title: Node.js +slug: Glossary/Node.js +translation_of: Glossary/Node.js +--- +

Node.js 為 {{Glossary("JavaScript")}} 跨平台執行環境,可讓開發者建立伺服器端 JavaScript 網路程式。

+ +

了解詳情

+ +

基本知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/null/index.html b/files/zh-tw/glossary/null/index.html new file mode 100644 index 0000000000..721877299c --- /dev/null +++ b/files/zh-tw/glossary/null/index.html @@ -0,0 +1,26 @@ +--- +title: 'Null' +slug: Glossary/Null +tags: + - 'Null' + - 術語表 +translation_of: Glossary/Null +--- +

在計算機科學裏,一個 null 值代表了一個參考,通常是指一個不存在的或無效的物件({{glossary("object")}})或地址。在語言實現中空值引用的含義各不相同。

+ +

在 {{Glossary("JavaScript")}} 中, null 是一種原始值({{Glossary("Primitive", "primitive values")}})。

+ +

了解更多

+ +

基礎知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/number/index.html b/files/zh-tw/glossary/number/index.html new file mode 100644 index 0000000000..39c76cb579 --- /dev/null +++ b/files/zh-tw/glossary/number/index.html @@ -0,0 +1,27 @@ +--- +title: Number +slug: Glossary/Number +tags: + - JavaScript + - Number + - 術語表 +translation_of: Glossary/Number +--- +

在 {{Glossary("JavaScript")}}, Number 是雙精度64位浮點格式(IEEE 754)中的數字數據類型。在其他編程語言中可以存在不同的數字類型,如:整型(Integers)、浮點型(Floats)、雙精度型(Doubles)、 或 大數型(Bignums).

+ +

了解更多

+ +

基礎知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/object/index.html b/files/zh-tw/glossary/object/index.html new file mode 100644 index 0000000000..b6e4fdc39d --- /dev/null +++ b/files/zh-tw/glossary/object/index.html @@ -0,0 +1,18 @@ +--- +title: 物件 +slug: Glossary/Object +tags: + - Glossary +translation_of: Glossary/Object +--- +

物件(Object)是一個包含資料與處理資料指令的資料結構。物件有時是指真實世界的東西,像是賽車遊戲的車子 car 或地圖 map 物件。{{glossary("JavaScript")}}、Java、C++、Python、Ruby 都是 {{glossary("OOP","物件導向程式設計")}} 的語言例子。

+ +

了解更多

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/oop/index.html b/files/zh-tw/glossary/oop/index.html new file mode 100644 index 0000000000..d2fc69a0c0 --- /dev/null +++ b/files/zh-tw/glossary/oop/index.html @@ -0,0 +1,15 @@ +--- +title: 物件導向程式設計 +slug: Glossary/OOP +translation_of: Glossary/OOP +--- +

物件導向程式設計(Object-Oriented Programming、OOP)是一種程式設計方法。其將資料封裝(encapsulate)於物件({{glossary("object","objects")}})中,我們需透過物件間接操作這些被封裝的內部資料,而非直接操作資料本身。

+ +

{{glossary("JavaScript")}}為重度物件導向語言,其遵循 prototype-based model與 class-based 相對

+ +

相關文章

+ + diff --git a/files/zh-tw/glossary/opera_browser/index.html b/files/zh-tw/glossary/opera_browser/index.html new file mode 100644 index 0000000000..37bbc8e9eb --- /dev/null +++ b/files/zh-tw/glossary/opera_browser/index.html @@ -0,0 +1,21 @@ +--- +title: Opera 瀏覽器 +slug: Glossary/Opera_Browser +tags: + - Browser + - Glossary + - Navigation + - Opera + - Opera Browser +translation_of: Glossary/Opera_Browser +--- +

Opera 是最常使用的 {{glossary("browser")}} 第五名,1996 年正式推出,一開始僅能在 Windows 使用。Opera 自 2013 年起使用 {{glossary("Blink")}} 排版引擎,在那之前使用的是 {{glossary("Presto")}}。Opera 也有提供行動與平板電腦版本。

+ +

了解更多

+ +

一般知識

+ + diff --git a/files/zh-tw/glossary/parameter/index.html b/files/zh-tw/glossary/parameter/index.html new file mode 100644 index 0000000000..0cd6c5abfd --- /dev/null +++ b/files/zh-tw/glossary/parameter/index.html @@ -0,0 +1,38 @@ +--- +title: 參數 +slug: Glossary/Parameter +translation_of: Glossary/Parameter +--- +

參數 (parameter) 是個會傳進函式 ({{Glossary("function")}}) 的已命名變量,用來把引數 (({{Glossary("argument","arguments")}})) 導入到函式中。

+ +

要特別注意參數和引數的差異:

+ + + +

 一般而言,參數的形式有兩種表示方式:

+ +
+
輸入用的參數
+
像這樣藉由值呼叫的形式最常見。此外,還可以根據不同的程式語言,讓輸入用參數的使用模式多樣,例如:用值呼叫 (call-by-value)、用位置呼叫 (call-by-address) 和完成函式程序後把它的值設定成回傳值 (也就是 call-by-reference)。
+
輸出和回傳 (return) 用的函數
+
在函式的程序完成之後,會負責回傳多重的量值。不過,這方式可能會讓程式開發者誤解它的意思,所以不建議使用。
+
+ +

想了解更多嗎?

+ +

一般常識篇

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/php/index.html b/files/zh-tw/glossary/php/index.html new file mode 100644 index 0000000000..1b27ff0c82 --- /dev/null +++ b/files/zh-tw/glossary/php/index.html @@ -0,0 +1,55 @@ +--- +title: PHP +slug: Glossary/PHP +translation_of: Glossary/PHP +--- +

PHP(PHP: Hypertext Preprocessor 的遞歸縮寫,意為「PHP:超文字預處理器」)是一個開源的伺服器端腳本語言,可用於建制網頁應用和動態網站。

+ +

範例

+ +

基本語法

+ +
  // PHP 程式開始
+<?php
+     // PHP 程式在此執行
+ ?>
+// PHP 程式結束
+ +

在螢幕上印東西

+ +
<?php
+   echo "Hello World!";
+?>
+ +

PHP 變數

+ +
​​​​​​​​​​​​​​<?php
+ // 變數
+ $nome='Danilo';
+ $sobrenome='Santos';
+ $pais='Brasil';
+ $email='danilocarsan@gmailcom';
+​​​​​​​
+ // 印出變數
+ echo $nome;
+ echo $sobrenome;
+ echo $pais;
+ echo $email;
+?>
+ + diff --git a/files/zh-tw/glossary/png/index.html b/files/zh-tw/glossary/png/index.html new file mode 100644 index 0000000000..d5950fffcd --- /dev/null +++ b/files/zh-tw/glossary/png/index.html @@ -0,0 +1,17 @@ +--- +title: PNG +slug: Glossary/PNG +tags: + - PNG + - 術語表 +translation_of: Glossary/PNG +--- +

PNG (便攜式網路圖形) 是一種支持無損數據壓縮的圖片文件格式。

+ +

了解更多

+ +

基礎知識

+ + diff --git a/files/zh-tw/glossary/pop/index.html b/files/zh-tw/glossary/pop/index.html new file mode 100644 index 0000000000..3cb09f9be1 --- /dev/null +++ b/files/zh-tw/glossary/pop/index.html @@ -0,0 +1,22 @@ +--- +title: POP3 +slug: Glossary/POP +tags: + - POP3 + - 基礎 + - 術語表 +translation_of: Glossary/POP +--- +

POP3 (郵局協定)是一種常見協定({{glossary("protocol")}}) 用於從伺服器接收郵件通過 {{glossary("TCP")}} 鏈接.不同於{{Glossary("IMAP4")}}, 由於POP3 結構更爲複雜,更難以實施,POP3 不支持多資料夾。

+ +

客戶端通常會從伺服器取回所有的訊息然後刪除伺服器上的訊息,但是 POP3 允許伺服器保留副本。目前幾乎所有的郵件伺服器和客戶端都支持 POP3.

+ +

了解更多

+ + diff --git a/files/zh-tw/glossary/port/index.html b/files/zh-tw/glossary/port/index.html new file mode 100644 index 0000000000..17359cc5bb --- /dev/null +++ b/files/zh-tw/glossary/port/index.html @@ -0,0 +1,23 @@ +--- +title: 通訊埠 +slug: Glossary/Port +tags: + - Glossary + - Intro + - Security + - computer network + - 'l10n:priority' + - port +translation_of: Glossary/Port +--- +

對使用 {{Glossary("IP address")}} 連線到網路的電腦來說,通訊埠是傳輸時的端點。我們可用不同的數字(通訊埠號)來分辨不同的通訊埠,而小於 1024 號的每個埠通常都有自己預設使用的 {{Glossary("protocol")}}。

+ +

舉例來說,{{Glossary("HTTP")}} 通訊協定的預設埠號是 80,而 HTTPS 通訊協定預設的埠號是 443,這麼 {{Glossary("HTTP")}} 伺服器預設就會在這些通訊埠上等待請求。網際網路上的每個通訊協定都會有自己的預設通訊埠: {{Glossary("SMTP")}} (25)、{{Glossary("POP3")}} (110)、{{Glossary("IMAP")}} (143)、{{Glossary("IRC")}} (194) 等等。

+ +

了解更多

+ +

一般知識

+ + diff --git a/files/zh-tw/glossary/presto/index.html b/files/zh-tw/glossary/presto/index.html new file mode 100644 index 0000000000..d9b68c2b21 --- /dev/null +++ b/files/zh-tw/glossary/presto/index.html @@ -0,0 +1,18 @@ +--- +title: Presto +slug: Glossary/Presto +tags: + - Glossary + - Infrastructure + - Opera + - Presto + - 'l10n:priority' +translation_of: Glossary/Presto +--- +

Presto 是 {{Glossary("Opera browser")}} 原本使用的專屬排版引擎, Opera 瀏覽器 15 版起改用以 Chromium 為基礎的 {{Glossary('Blink')}} 排版引擎。

+ +

了解更多

+ + diff --git a/files/zh-tw/glossary/progressive_enhancement/index.html b/files/zh-tw/glossary/progressive_enhancement/index.html new file mode 100644 index 0000000000..95f72a2d1d --- /dev/null +++ b/files/zh-tw/glossary/progressive_enhancement/index.html @@ -0,0 +1,14 @@ +--- +title: 漸進增強 +slug: Glossary/Progressive_Enhancement +translation_of: Glossary/Progressive_Enhancement +--- +

漸進增強(Progressive enhancement)是強調要在受限情境下提供初等體驗、對所有人提供必要的內容與功能、以及需要時再加上其他可選功能的設計哲學。它更接近於強調無障礙、以及許多腳本技術的網站設計策劃。這個技術很有用,因為它讓網路開發者,在專注開發最強大的網站同時,和某些未知的用戶代理,在訪問網站時發生的問題間達到權衡。

+ +

了解詳情

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/property/index.html b/files/zh-tw/glossary/property/index.html new file mode 100644 index 0000000000..50ccfe72ce --- /dev/null +++ b/files/zh-tw/glossary/property/index.html @@ -0,0 +1,13 @@ +--- +title: 屬性 +slug: Glossary/property +tags: + - Disambiguation + - Glossary + - NeedsTranslation + - TopicStub +translation_of: Glossary/property +--- +

根據所屬情境的不同,「屬性(Property)」可代表不同的意思。可能是:

+ +

{{GlossaryDisambiguation}}

diff --git a/files/zh-tw/glossary/property/javascript/index.html b/files/zh-tw/glossary/property/javascript/index.html new file mode 100644 index 0000000000..8bd94bccf9 --- /dev/null +++ b/files/zh-tw/glossary/property/javascript/index.html @@ -0,0 +1,22 @@ +--- +title: Property (JavaScript) +slug: Glossary/property/JavaScript +translation_of: Glossary/property/JavaScript +--- +

property(屬性)是典型的物件特徵,經常與資料結構聯結。屬性分為兩種類型:

+ + + +

屬性擁有一個名字(為{{glossary("string", "字串")}})以及值(可以是{{glossary("primitive", "基本資料型別")}}、{{glossary("method", "方法")}}或是{{glossary("object reference", "物件參考")}})。請注意,當我們說「一個屬性保存著物件」,其實是指「一個屬性保存著物件的參考(reference)」。這其中的差別在於,當你改變屬性中的值的時候,所指向的物件實體之值也會改變。

+ +

了解詳情

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/protocol/index.html b/files/zh-tw/glossary/protocol/index.html new file mode 100644 index 0000000000..e4487bc543 --- /dev/null +++ b/files/zh-tw/glossary/protocol/index.html @@ -0,0 +1,21 @@ +--- +title: 通訊協定 +slug: Glossary/Protocol +tags: + - Glossary + - Infrastructure + - Protocols +translation_of: Glossary/Protocol +--- +

通訊協定是一套定義在電腦內部或兩台電腦間,如何交換資料的系統化規則。不同的裝置若需進行溝通,就需要先確認好要交換的資料格式與交換方法,而這些定義好的格式與方法就是通訊協定。

+ +

了解更多

+ +

一般知識

+ + + +

 

diff --git a/files/zh-tw/glossary/prototype/index.html b/files/zh-tw/glossary/prototype/index.html new file mode 100644 index 0000000000..94f5b421b8 --- /dev/null +++ b/files/zh-tw/glossary/prototype/index.html @@ -0,0 +1,16 @@ +--- +title: 原型 +slug: Glossary/Prototype +translation_of: Glossary/Prototype +--- +

原型(prototype)是在開發早期表現應用程式外觀或行為的模型。

+ +

請詳見繼承與原型鍊(Inheritance and the prototype chain)。

+ +

深入理解

+ +

一般知識

+ + diff --git a/files/zh-tw/glossary/pseudo-element/index.html b/files/zh-tw/glossary/pseudo-element/index.html new file mode 100644 index 0000000000..5272add4b8 --- /dev/null +++ b/files/zh-tw/glossary/pseudo-element/index.html @@ -0,0 +1,16 @@ +--- +title: 偽元素 +slug: Glossary/Pseudo-element +translation_of: Glossary/Pseudo-element +--- +

CSS中的偽元素選擇器可被應用在當HTML內沒有特定元素可以選擇,且文件內容需套用格式的時候。舉例來說,與其將每個段落的第一個字變成獨立元素,你也可選擇利用 p{{ Cssxref("::first-letter") }}的寫法選擇各段首字。

+ +

 

+ +

了解更多

+ +

技術參考

+ + diff --git a/files/zh-tw/glossary/python/index.html b/files/zh-tw/glossary/python/index.html new file mode 100644 index 0000000000..61d6a4b107 --- /dev/null +++ b/files/zh-tw/glossary/python/index.html @@ -0,0 +1,33 @@ +--- +title: Python +slug: Glossary/Python +translation_of: Glossary/Python +--- +

Python是高階通用(general-purpose)程式語言。他使用了多型編程範式(multi-paradigm approach),這意味著他支援了程序化、物件導向、還有一些函式語言程式設計結構體(functional programming constructs)。

+ +

它是由吉多·范羅蘇姆(Guido van Rossum)作為 1985 到 1990 之間盛行的 ABC 語言繼承者形象而誕生的。目前各大領域都有使用 Python:例如 Web 開發、桌面程式、資料科學、DevOps、自動化或生產力用途等。

+ +

Python 是在 OSI 認可的開源許可證規範下開發的,使其能自由使用與分發,即使是商用亦然。目前 Python 許可證是由 Python Software Foundation 管理的。

+ + diff --git a/files/zh-tw/glossary/recursion/index.html b/files/zh-tw/glossary/recursion/index.html new file mode 100644 index 0000000000..9712988a69 --- /dev/null +++ b/files/zh-tw/glossary/recursion/index.html @@ -0,0 +1,15 @@ +--- +title: 遞迴 +slug: Glossary/Recursion +translation_of: Glossary/Recursion +--- +

函式呼叫函式自己的行為,稱為遞迴、或是遞歸。它主要用於解決含有子問題的問題。遞迴函式會收到兩個輸入:結束遞迴的基本情況(base case)或是延續遞迴的遞迴情況(recursive case)。

+ +

深入了解

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/reflow/index.html b/files/zh-tw/glossary/reflow/index.html new file mode 100644 index 0000000000..1643bb0635 --- /dev/null +++ b/files/zh-tw/glossary/reflow/index.html @@ -0,0 +1,12 @@ +--- +title: Reflow +slug: Glossary/Reflow +translation_of: Glossary/Reflow +--- +

Reflow(回流)會發生於瀏覽器({{glossary("browser")}})必須再次處理和繪製部分或整個網頁時,如在互動式網站更新後。

+ +

深入了解

+ + diff --git a/files/zh-tw/glossary/regular_expression/index.html b/files/zh-tw/glossary/regular_expression/index.html new file mode 100644 index 0000000000..13bd28ef71 --- /dev/null +++ b/files/zh-tw/glossary/regular_expression/index.html @@ -0,0 +1,29 @@ +--- +title: 正規表示式 +slug: Glossary/Regular_expression +tags: + - CodingScripting + - Glossary + - Regular Expression + - 'l10n:priority' +translation_of: Glossary/Regular_expression +--- +

正規表示式Regular expressions,或是regex)是主宰著字符序列搜索的規則。

+ +

許多語言都實作了正規表示式,但最出名的實作,是引出一連串不同實作方式的 Perl 版本實作,稱為 PCRE (Perl Compatible Regular Expression)。在 Web 平台,{{glossary("JavaScript")}} 透過 {{jsxref("RegExp")}} 物件,提供另一種正規表示式的實作。

+ +

了解詳情

+ +

基本知識

+ + + +

技術參考

+ + diff --git a/files/zh-tw/glossary/responsive_web_design/index.html b/files/zh-tw/glossary/responsive_web_design/index.html new file mode 100644 index 0000000000..130bca44fc --- /dev/null +++ b/files/zh-tw/glossary/responsive_web_design/index.html @@ -0,0 +1,16 @@ +--- +title: 響應式網頁設計 +slug: Glossary/Responsive_web_design +translation_of: Glossary/Responsive_web_design +--- +

響應式網頁設計RWD)是一種強調製作能在所有上網設備上,提供最佳外觀和體驗的 Web 開發觀念。

+ +

深入理解

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/rest/index.html b/files/zh-tw/glossary/rest/index.html new file mode 100644 index 0000000000..f07cdfcf6d --- /dev/null +++ b/files/zh-tw/glossary/rest/index.html @@ -0,0 +1,26 @@ +--- +title: REST +slug: Glossary/REST +translation_of: Glossary/REST +--- +

具象狀態傳輸(REST,Representational State Transfer)是一組實現效率、可讀性、還有可擴展分散式系統(scalable distributed system)的軟體架構設計規範。如果一個系統能維持某些規範,他就是 RESTful。

+ +

REST 的基本概念是資源(resource):例如說,文件能透過明確且標準的操作與格式,轉換其狀態與超文本的關聯。通常在 {{Glossary("API")}} 或服務能直接更改文件類型,而非觸發其他行為時,就會稱做 RESTful。

+ +

由於網際網路({{glossary("World Wide Web")}})背後的 {{Glossary("HTTP")}} 協議也能傳送文件及超文本連結、又同時充當了標準,簡易的 HTTP API 雖然有時不一定遵守所有 REST 規範,他們還是會俗稱為 RESTful API、RESTful 服務、或直接叫 REST 服務。初學者可以先假設 REST API 是指能透過 web 相關的函式庫和工具來呼叫的 HTTP 服務。

+ +

深入理解

+ +

搞懂它

+ + + +

基礎知識

+ + diff --git a/files/zh-tw/glossary/routers/index.html b/files/zh-tw/glossary/routers/index.html new file mode 100644 index 0000000000..016a3c1c32 --- /dev/null +++ b/files/zh-tw/glossary/routers/index.html @@ -0,0 +1,29 @@ +--- +title: Routers +slug: Glossary/routers +translation_of: Glossary/routers +--- +

routers 是指路由器。在 Web 有兩種意思:

+ +
    +
  1. 針對網路層,路由器是一種決定{{Glossary('封包')}}去向的網路設備。路由器是由 retailer 分發,允許用戶與網際網路互動。
  2. +
  3. 針對應用層的 {{Glossary('SPA')}},路由器是一種透過給定的 {{Glossary('URL')}} 來決定頁面如何呈現的函式庫。這個中間件(middleware)會藉由給定 URL 給檔案生成需要的路徑、以渲染下一頁的所需內容。
  4. +
+ +

了解更多

+ +

一般知識

+ +

針對網路層:

+ + + +

針對應用層,訪間熱門的 SPA 框架都有自己的路由器函式庫:

+ + diff --git a/files/zh-tw/glossary/ruby/index.html b/files/zh-tw/glossary/ruby/index.html new file mode 100644 index 0000000000..1e1832c8a8 --- /dev/null +++ b/files/zh-tw/glossary/ruby/index.html @@ -0,0 +1,31 @@ +--- +title: Ruby +slug: Glossary/Ruby +translation_of: Glossary/Ruby +--- +

Ruby 是個開源的程式語言。在{{glossary("world wide web","網際網路")}}的脈落下,Ruby 常藉由伺服器端的 Ruby On Rails(ROR)框架構建網站或 app。

+ +

Ruby 也可以指 HTML 文件內,東亞文字的註釋方法。請參考 {{HTMLElement("ruby")}} 元素。

+ + diff --git a/files/zh-tw/glossary/seo/index.html b/files/zh-tw/glossary/seo/index.html new file mode 100644 index 0000000000..7d955eb1c2 --- /dev/null +++ b/files/zh-tw/glossary/seo/index.html @@ -0,0 +1,40 @@ +--- +title: SEO +slug: Glossary/SEO +tags: + - 搜尋引擎最佳化 +translation_of: Glossary/SEO +--- +

搜尋引擎最佳化(Search Engine Optimization、SEO)是提高網站於搜尋引擎的能見度之過程,又稱搜索排名改進。

+ +

搜尋引擎會{{Glossary("Crawler", "爬行")}}網路,從某個頁面連結到另一個頁面,並編篡找到的內容。當你搜尋的時候,搜尋引擎就會顯示已編好的內容。爬蟲遵循規則。如果你在給網站 SEO 時遵循這些規則,就能提高網站出現在搜尋結果首位的機會。它能增進流量,並透過電子商務與廣告,增加潛在收入。

+ +

搜尋引擎針對 SEO 給予一些建議,但大型搜尋引擎,把排名結果視為商業機密。SEO 結合了官方搜尋引擎的指引、經驗知識、以及源自論文或專利的理論知識。

+ +

SEO 方法分為三大類:

+ +
+
技術
+
使用語意化的 {{Glossary("HTML")}} 標示內容。當爬蟲在探索網站時,它只會找要索引的內容。
+
文案
+
使用閱覽者的詞彙來編寫內容。使用文字和圖像,讓爬蟲能夠理解主題。
+
聲望
+
當其他網站連結到你的網站時,你會得到最多流量。
+
+ +

深入理解

+ +

一般常識

+ + + +

理解 SEO

+ + diff --git a/files/zh-tw/glossary/server/index.html b/files/zh-tw/glossary/server/index.html new file mode 100644 index 0000000000..1d2333a873 --- /dev/null +++ b/files/zh-tw/glossary/server/index.html @@ -0,0 +1,19 @@ +--- +title: 伺服器 +slug: Glossary/Server +translation_of: Glossary/Server +--- +

硬體而言的伺服器(server)是個能在網路上,提供用戶端服務的共享性電腦(shared computer)。軟體而言的伺服器程式,則是指能給用戶端提供服務的程式。

+ +

服務(Services)通常會提供於內部網路、或是公開網路。用戶端程式與伺服器端程式通常利用 {{glossary("protocol")}} 來傳送編碼的數據、並依此連接之。

+ +

內部網路最常見的伺服器有檔案、域名、電郵、印表機、還有傳真伺服器。另一個常見的伺服器是連結到網際網路的 Web 伺服器。在資料中心(data center)的微電腦、大型電腦、還有超級電腦... 等,也都是伺服器。

+ +

了解更多

+ +

一般知識

+ + diff --git a/files/zh-tw/glossary/sgml/index.html b/files/zh-tw/glossary/sgml/index.html new file mode 100644 index 0000000000..36c3c4f537 --- /dev/null +++ b/files/zh-tw/glossary/sgml/index.html @@ -0,0 +1,21 @@ +--- +title: SGML +slug: Glossary/SGML +tags: + - CodingScripting + - Composing + - Glossary + - SGML + - 'l10n:priority' +translation_of: Glossary/SGML +--- +

標準通用標記式語言(Standard Generalized Markup Language 或簡稱 SGML)是一套 {{Glossary("ISO")}} 所定義,用來規範宣告式標記語言的標準。

+ +

在 Web 環境當中,{{Glossary("HTML")}} 4、{{Glossary("XHTML")}} 以及 {{Glossary("XML")}} 都是知名的以 SGML 為基礎的語言。然而值得一提的是,HTML 自第五版起擁有了自己的剖析規則,不再是以 SGML 為基礎的語言。

+ +

了解更多

+ + diff --git a/files/zh-tw/glossary/spa/index.html b/files/zh-tw/glossary/spa/index.html new file mode 100644 index 0000000000..7bf0e740dc --- /dev/null +++ b/files/zh-tw/glossary/spa/index.html @@ -0,0 +1,38 @@ +--- +title: SPA +slug: Glossary/SPA +translation_of: Glossary/SPA +--- +

單頁應用(SPA,Single-page application)是一種 Web app 開發實作。它能在使用網站時,只載入一個頁面;並在網頁更新時,透過 JavaScript API 如 {{domxref("XMLHttpRequest")}} 與 Fetch 同步更新部份網頁。

+ +

SPA 能讓用戶在使用網站時,不用從伺服器載入整個頁面,所以會提升性能與動態體驗。相對地,在 {{Glossary("SEO")}}、狀態與路由管理、還有性能監控方面,都會是需要考慮的劣勢。

+ +

參見

+ +

一般知識

+ +

以下為訪間最熱門的 SPA:

+ + + + diff --git a/files/zh-tw/glossary/sql/index.html b/files/zh-tw/glossary/sql/index.html new file mode 100644 index 0000000000..2c620ac65c --- /dev/null +++ b/files/zh-tw/glossary/sql/index.html @@ -0,0 +1,21 @@ +--- +title: SQL +slug: Glossary/SQL +translation_of: Glossary/SQL +--- +

SQL(Structured Query Language,結構化查詢語言)是專為表格形式資料庫的更新、檢索、計算,所設計的描述性電腦語言。

+ +

深入了解

+ +

基本知識

+ + + +

了解 SQL

+ + diff --git a/files/zh-tw/glossary/sql_injection/index.html b/files/zh-tw/glossary/sql_injection/index.html new file mode 100644 index 0000000000..2e44516cc2 --- /dev/null +++ b/files/zh-tw/glossary/sql_injection/index.html @@ -0,0 +1,63 @@ +--- +title: SQL 注入 +slug: Glossary/SQL_Injection +translation_of: Glossary/SQL_Injection +--- +

SQL 注入(SQL injection)利用了網路程式(Web apps)的錯誤輸入。駭客可以透過執行後端資料庫的網路程式,惡意繞過 SQL 指令。

+ +

SQL 注入能在未授權的情況下,直接從資料庫訪問資料庫與檢索信息。許多數據洩露肇因於 SQL 注入。

+ +

+ +

如何做動

+ +

+ +

在輸入 username (用戶名)與 password (密碼)後,GUI 背後的 SQL 查詢會這樣工作:

+ +
"SELECT Count(*) FROM Users WHERE Username=' " + txt.User.Text+" ' AND Password=' "+ txt.Password.Text+" ' ";
+ +

假設用戶在 username 欄位輸入了 admin 還在 password 欄位輸入了 passwd123,接著按了下面的 Log in(登入), SQL 查詢會這樣運作:

+ +
"SELECT Count(*) FROM Users WHERE Username=' admin ' AND Password=' passwd123 ' ";
+
+ +

如果驗證正確,用戶就可以登入,是個很簡單(所以很不安全)的機制。駭客利用者這種不安全,獲取未經授權的訪問。

+ +

駭客使用一種稱為 Magical String 的簡單字串,例如:

+ +

Username: admin

+ +

Password: anything 'or'1'='1

+ +

在按下 login 按鈕以後,SQL 查詢會這樣運作:

+ +
"SELECT Count(*) FROM Users WHERE Username=' admin ' AND Password=' anything 'or'1'='1 ' ";
+
+ +

仔細檢查一下查詢密碼的部分。

+ +
Password=' anything 'or'1'='1 '
+ +

密碼不是 anything,因此 password=anything 會回傳 FALSE(錯誤)。但 '1'='1' 是正確的宣告,所以會回傳 TRUE(正確)。最後,透過 OR (或)運算符,FALSE OR TRUE 的比較結果是 TRUE,認證因而成功通過。只要一點簡單的字串(Magical String)整個資料庫就會被洩漏。

+ +

如何避免

+ +

在執行用戶的憑證查詢前,先做如下的改變:

+ +
$id = $_GET['id'] 
+
+(1) $id = Stripslashes($id)
+
+(2) $id = mysql_real_escape_String($id)
+ +

藉由 (1) 所有輸入字串的單引號 ' 取代成雙引號 ",還有 (2) 在每個 ' 之前加上 /。 修正後的 Magical String 不能繞過驗證,並使你的資料庫保持安全。

+ +

了解詳情

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/svg/index.html b/files/zh-tw/glossary/svg/index.html new file mode 100644 index 0000000000..717b0b0337 --- /dev/null +++ b/files/zh-tw/glossary/svg/index.html @@ -0,0 +1,33 @@ +--- +title: SVG +slug: Glossary/SVG +translation_of: Glossary/SVG +--- +

可縮放向量圖形Scalable Vector Graphics, SVG)是基於 {{Glossary("XML")}} 語法的 2D 向量圖片格式。

+ +

{{Glossary("W3C")}} 在 1990 晚期啟動 SVG 開發,但它要在 {{Glossary("Microsoft Internet Explorer", "IE")}} 9 開始支援 SVG 後才開始發跡。目前所有主流{{Glossary("browser","瀏覽器")}}都支援 SVG。

+ +

由於 SVG 基於 {{Glossary("XML")}} 語法,所以它可以透過 {{Glossary("CSS")}} 樣式化、並透過 {{Glossary("JavaScript")}} 互動。HTML5 目前能在 {{Glossary("HTML")}} 檔案內直接嵌入 SVG {{Glossary("Tag","標籤")}}。

+ +

由於 SVG 是向量圖形,它因此可以無限縮放。也由於你可以建立介面元素(interface element)還有在任何螢幕尺寸縮放的圖形,它在{{Glossary("responsive design","響應式設計")}}上也相當重要。SVG 也提供一組有用的工具,例如剪輯、遮罩、濾器、動畫(clipping, masking, filters, animation)。

+ +

深入理解

+ +

基本知識

+ + + +

理解 SVG

+ + + +

技術資訊

+ + diff --git a/files/zh-tw/glossary/svn/index.html b/files/zh-tw/glossary/svn/index.html new file mode 100644 index 0000000000..1de335a064 --- /dev/null +++ b/files/zh-tw/glossary/svn/index.html @@ -0,0 +1,24 @@ +--- +title: SVN +slug: Glossary/SVN +tags: + - SVN + - 術語表 +translation_of: Glossary/SVN +--- +

Apache Subversion (SVN) 是免費的資源控制管理({{Glossary("SCM")}}) 系統。 它准許開發者保留文本和程式碼修改的歷史記錄。儘管 SVN 可以處理二進制文件,但我們不建議使用。

+ +

了解更多

+ +

基礎知識

+ + + +

學習使用

+ + diff --git a/files/zh-tw/glossary/synchronous/index.html b/files/zh-tw/glossary/synchronous/index.html new file mode 100644 index 0000000000..db33bd48e1 --- /dev/null +++ b/files/zh-tw/glossary/synchronous/index.html @@ -0,0 +1,19 @@ +--- +title: 同步 +slug: Glossary/Synchronous +translation_of: Glossary/Synchronous +--- +

同步(Synchronous)是指各方在接收(必要的話還會執行與回覆)訊息時,立刻(或盡可能接近立刻)執行的即時通訊。

+ +

以人類通訊來比喻就是電話:在電話通訊時,你通常會立刻回覆對方的訊息。

+ +

很多程式指令都是同步的:例如在計算時,環境會立刻回傳結果,除非你撰寫程式時不讓它這麼做。

+ +

深入理解

+ +

技術參考

+ + diff --git a/files/zh-tw/glossary/type/index.html b/files/zh-tw/glossary/type/index.html new file mode 100644 index 0000000000..8a2a1106fd --- /dev/null +++ b/files/zh-tw/glossary/type/index.html @@ -0,0 +1,17 @@ +--- +title: 型別 +slug: Glossary/Type +translation_of: Glossary/Type +--- +

型別(或資料型別)是能決定 {{glossary("value")}} 該存為何種類型的特性:例如 JavaScript 的 {{domxref("Boolean")}} 只能存為 true/false 兩者其一、而字串({{domxref("String")}})能存為文字字串、{{domxref("Number")}} 則能存城任何類型的數字……等等。

+ +

型別也能決定哪些操作是有效的:例如說整數(integer)可以與整數相乘,但不能與字串相乘。

+ +

深入了解

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/uri/index.html b/files/zh-tw/glossary/uri/index.html new file mode 100644 index 0000000000..8e0d68000c --- /dev/null +++ b/files/zh-tw/glossary/uri/index.html @@ -0,0 +1,15 @@ +--- +title: URI +slug: Glossary/URI +translation_of: Glossary/URI +--- +

統一資源識別碼 (Uniform Resource Identifier,一般縮寫成 URI) 是個會指向資訊來源的字串。 其中又以定位網址 {{Glossary("URL","URLs")}} 最為常見,會把該位址傳給網站,好讓網站辨認資訊來源。不過,統一資源名稱 {{Glossary("URN","URNs")}} 就不一樣了,是用命名空間允許的名稱指向資訊來源,例如國際標準書碼 (International Standard Book Number,一般以ISBN 縮寫)

+ +

想了解更多嗎?

+ +

一般常識篇

+ + diff --git a/files/zh-tw/glossary/url/index.html b/files/zh-tw/glossary/url/index.html new file mode 100644 index 0000000000..2aecd64d12 --- /dev/null +++ b/files/zh-tw/glossary/url/index.html @@ -0,0 +1,35 @@ +--- +title: URL +slug: Glossary/URL +tags: + - URL + - 'l10n:priority' + - 術語表 + - 鏈接 +translation_of: Glossary/URL +--- +

統一資源定位器 (URL) 是一個在互聯網上查找指定資源(例如網頁,圖片或視頻)位置的文本字符串。 

+ +

在{{Glossary("HTTP")}}的文本中, URLs 通常被稱作網頁地址或鏈接。瀏覽器把 URLs 顯示在地址欄,如: https://developer.mozilla.org Some browsers display only the part of a URL after the "//", that is, the {{Glossary("Domain name")}}.

+ +

URLs 同樣可以用於文件傳輸({{Glossary("FTP")}}) , 郵件 ({{Glossary("SMTP")}}), 以及其他應用程式.

+ +

了解更多

+ +

基礎知識

+ + + +

學習其他

+ + + +

Specification

+ + diff --git a/files/zh-tw/glossary/viewport/index.html b/files/zh-tw/glossary/viewport/index.html new file mode 100644 index 0000000000..654d8e81df --- /dev/null +++ b/files/zh-tw/glossary/viewport/index.html @@ -0,0 +1,25 @@ +--- +title: Viewport +slug: Glossary/Viewport +tags: + - CodingScripting + - Glossary +translation_of: Glossary/Viewport +--- +

一個 viewport(視圖、視區)在電腦圖像中表示一個正在被觀看的多邊型區域(通常是方形)。在瀏覽器的術語中,它指涉的是在視窗中(如果在全螢幕模式底下,那也可以是在螢幕中),正在瀏覽的文件中可被看見的一部分。在 viewport 外的內容在螢幕上是看不到的,直到內容被滾動到畫面中。

+ +

在視窗/螢幕上能被看見的 viewport 區域被稱為 visual viewport(可視視圖)。它有時會比 layout viewport 還來得小,例如在使用者縮放網頁的時候,layout viewport(布局視圖)會保持同樣的大小,而 visual viewport 則會變得較小。

+ + + +

瞭解更多

+ +

General Knowledge

+ + diff --git a/files/zh-tw/glossary/w3c/index.html b/files/zh-tw/glossary/w3c/index.html new file mode 100644 index 0000000000..94ce9c4039 --- /dev/null +++ b/files/zh-tw/glossary/w3c/index.html @@ -0,0 +1,19 @@ +--- +title: W3C +slug: Glossary/W3C +translation_of: Glossary/W3C +--- +

全球資訊網協會(World Wide Web Consortium,W3C)是維護{{Glossary("World Wide Web", "網路相關")}}規則與架構的國際機構。

+ +

它由 420 多個開發網路標準、經營宣傳計畫、還有維護網路相關的公開討論會……等成員組織構成。W3C 的業界協調公司確保它們實行相同的 W3C 標準。

+ +

每個標準都會有四個成熟過程:工作草案(Working Draft、WD)、候選推薦標準(Candidate Recommendation、CR)、提案推薦標準(Proposed Recommendation、PR)、以及 W3C 推薦標準(W3C Recommendation、REC)。

+ +

深入了解

+ +

基本知識

+ + diff --git a/files/zh-tw/glossary/webextensions/index.html b/files/zh-tw/glossary/webextensions/index.html new file mode 100644 index 0000000000..9983d915a6 --- /dev/null +++ b/files/zh-tw/glossary/webextensions/index.html @@ -0,0 +1,19 @@ +--- +title: WebExtensions +slug: Glossary/WebExtensions +tags: + - CodingScripting + - Glossary + - NeedsContent + - WebExtensions +translation_of: Glossary/WebExtensions +--- +

WebExtensions 是一種跨瀏覽器系統,用於開發 Firefox 的瀏覽器附加元件。這個系統提供許多 API 能夠在不同的瀏覽器中執行,例如 Mozilla Firefox、Google Chrome、Opera 瀏覽器和 Microsoft Edge。

+ +

深入了解

+ +

技術資訊

+ + diff --git a/files/zh-tw/glossary/websockets/index.html b/files/zh-tw/glossary/websockets/index.html new file mode 100644 index 0000000000..7aca64282e --- /dev/null +++ b/files/zh-tw/glossary/websockets/index.html @@ -0,0 +1,29 @@ +--- +title: WebSockets +slug: Glossary/WebSockets +translation_of: Glossary/WebSockets +--- +

WebSocket 是允許{{Glossary("Server", "伺服器")}}與用戶端之間發起持續性的 {{Glossary("TCP")}} 連接,以便隨時交換資料的{{Glossary("protocol", "協定")}}。

+ +

任何用戶端與伺服器端程式都能使用 WebSocket,不過一般來說,大都是在{{Glossary("Browser", "網路瀏覽器")}}與伺服器之間發起的。伺服器藉由 WebSocket 可以在用戶端沒有事先請求的情況下,將數據傳遞給用戶端,以便動態更新資料。

+ +

深入理解

+ +

一般常識

+ + + +

技術參考

+ + + +

學習之

+ + diff --git a/files/zh-tw/html5_cross_browser_polyfills/index.html b/files/zh-tw/html5_cross_browser_polyfills/index.html new file mode 100644 index 0000000000..d823a44760 --- /dev/null +++ b/files/zh-tw/html5_cross_browser_polyfills/index.html @@ -0,0 +1,34 @@ +--- +title: HTML5 跨瀏覽器兼容程式碼 +slug: HTML5_Cross_Browser_Polyfills +--- +

這是個蒐集中文世界開發(但不一定原創)的跨瀏覽器兼容代碼、連結的地方,作為 Paul Irish《HTML5 Cross Browser Polyfills》的仿效文件。蒐集不會完全,因此也強烈建議繼續追蹤上述文件的進展,或是使用搜尋引擎。

+

歡迎貢獻新的代碼、連結,不過請注意放在這個地方的代碼皆屬於公有領域

+

全頻(fullscreen)API

+

支援  Gecko:FullScreenAPI 草案的 {{ domxref("window.fullScreen") }} 與 {{ domxref("element.onfullscreenchange", "fullscreenchange") }} 事件 ,由贺师俊(hax)所提供

+
if (!('fullScreen' in window)) Object.defineProperty(window, 'fullScreen', {
+  get: function() {
+  return (screen.width == window.outerWidth && screen.height == window.outerHeight)
+  }
+})
+
+var _fullScreen = window.fullScreen
+if (!('onfullscreenchange' in window)) window.addEventListener('resize', function() {
+  var f = window.fullScreen
+  if (f != _fullScreen) {
+    _fullScreen = f
+    fireSimpleEvent('fullscreenchange', document, {bubbles:true})
+  }
+}, false)
+
+function fireSimpleEvent(type, target, option) {
+  if (!target) target = document
+  if (!option) option = {}
+  var evt = document.createEvent('Event')
+  evt.initEvent(type, !!option.bubbles, !!option.cancelable)
+  return target.dispatchEvent(evt)
+}
+
+

中文排版

+ diff --git a/files/zh-tw/introducing_the_audio_api_extension/index.html b/files/zh-tw/introducing_the_audio_api_extension/index.html new file mode 100644 index 0000000000..cc33296a5d --- /dev/null +++ b/files/zh-tw/introducing_the_audio_api_extension/index.html @@ -0,0 +1,181 @@ +--- +title: 介紹音效 API +slug: Introducing_the_Audio_API_Extension +translation_of: Archive/Mozilla/Introducing_the_Audio_API_Extension +--- +

音效 API 是 HTML5 規範中的媒體元素 {{ HTMLElement("audio") }} 與 {{ HTMLElement("video") }} 的補充功能,它讓開發者可以存取音效的後設資料跟音頻本身的生資料。開發者可以具象化這些音效資料,分析這些資料,甚至是創造出新的音效資料。

+

讀取音頻串流

+

loadedmetadata 事件

+

當一個媒體的後設資料傳至使用者電腦的時候,一個 loadedmetadata 事件會被觸發。這個事件有以下這些屬性:

+ +

這些資料在解碼音頻資料串流的的時候會用到。下面是一個從一個音頻元素取出這些資料的例子:

+
<!DOCTYPE html>
+<html>
+  <head>
+    <title>JavaScript 後設資料範例</title>
+  </head>
+  <body>
+    <audio id="audio-element"
+           src="song.ogg"
+           controls="true"
+           style="width: 512px;">
+    </audio>
+    <script>
+      function loadedMetadata() {
+        channels          = audio.mozChannels;
+        rate              = audio.mozSampleRate;
+        frameBufferLength = audio.mozFrameBufferLength;
+      }
+      var audio = document.getElementById('audio-element');
+      audio.addEventListener('loadedmetadata', loadedMetadata, false);
+    </script>
+  </body>
+</html>
+
+

MozAudioAvailable 事件

+

當播放一個音頻源的時候,樣本資料會被傳播至音頻處理層級而這些樣本也會被輸入進音頻緩衝(大小取決於mozFrameBufferLength)。當緩衝被填滿的時候,一個 MozAudioAvailable 事件會被觸發,而這個事件就含有一段時間內的樣本。這些樣本不一定在事件被觸發的時候已經被播放過,也不一定馬上反應媒體元素上的靜音設定或是音量調整。音頻的播放、暫停、跳躍都會影響生音頻資料串流。

+

MozAudioAvailable 事件有兩個屬性:

+ +

frame緩衝含有一個音頻樣本的陣列。請注意樣本不會照對應的頻道分隔,而是混在一起。舉例來說,一個二頻道訊號:頻道1-樣本1 頻道2-樣本1 頻道1-樣本2 頻道2-樣本2 頻道3-樣本1 頻道3-樣本2。

+

讓我們擴充之前的範例,在一個 {{ HTMLElement("div") }} 元素裡顯示時間戳記跟首兩個樣本:

+
<!DOCTYPE html>
+<html>
+  <head>
+    <title>JavaScript 具象化範例</title>
+    <body>
+    <audio id="audio-element"
+           src="revolve.ogg"
+           controls="true"
+           style="width: 512px;">
+    </audio>
+	<pre id="raw">hello</pre>
+    <script>
+      function loadedMetadata() {
+        channels          = audio.mozChannels;
+        rate              = audio.mozSampleRate;
+        frameBufferLength = audio.mozFrameBufferLength;
+      }
+
+      function audioAvailable(event) {
+        var frameBuffer = event.frameBuffer;
+        var t = event.time;
+
+        var text = "Samples at: " + t + "\n"
+        text += frameBuffer[0] + "  " + frameBuffer[1]
+        raw.innerHTML = text;
+      }
+
+      var raw = document.getElementById('raw')
+      var audio = document.getElementById('audio-element');
+      audio.addEventListener('MozAudioAvailable', audioAvailable, false);
+      audio.addEventListener('loadedmetadata', loadedMetadata, false);
+
+    </script>
+  </body>
+</html>
+
+

產生一個音頻串流

+

產生並裝置一個由腳本撰寫的 {{ HTMLElement("audio") }} 元素(也就是沒有 src 屬性)也是可以的。你可以用腳本設定音頻串流,然後寫入音頻樣本。網頁製作者必須產生一個音頻物件然後使用 mozSetup() 函式來設定頻道的數量跟頻率(赫茲)。舉例來說:

+
// 產生一個新的音頻元素
+var audioOutput = new Audio();
+// 設定此音頻元素的串流為「雙聲道,44.1千赫」
+audioOutput.mozSetup(2, 44100);
+
+

再來就需要做樣本。這些樣本和 mozAudioAvailable 事件的樣本用的格式是一樣的。這些樣本可以用 mozWriteAudio() 函式來寫入音頻串流。請注意並不是所有的樣本都會被寫入串流。函示會回傳被寫入串流的樣本數,這對於下一次要寫入資料的時候的很好用。請看下面的例子:

+
// 用JS陣列來寫樣本
+var samples = [0.242, 0.127, 0.0, -0.058, -0.242, ...];
+var numberSamplesWritten = audioOutput.mozWriteAudio(samples);
+
+// 用參數化陣列來寫樣本
+var samples = new Float32Array([0.242, 0.127, 0.0, -0.058, -0.242, ...]);
+var numberSamplesWritten = audioOutput.mozWriteAudio(samples);
+
+

我們在下一個範例做一個脈動:

+
<!doctype html>
+<html>
+  <head>
+     <title>及時產生音頻</title>
+   <script type="text/javascript">
+     function playTone() {
+       var output = new Audio();
+      output.mozSetup(1, 44100);
+       var samples = new Float32Array(22050);
+       var len = samples.length;
+
+       for (var i = 0; i < samples.length ; i++) {
+         samples[i] = Math.sin( i / 20 );
+       }
+              output.mozWriteAudio(samples);
+     }
+   </script>
+ </head>
+ <body>
+   <p>當你按下以下的按鈕之後,這個demo會撥一秒鐘的音調。</p>
+   <button onclick="playTone();">播放</button>
+ </body>
+ </html>
+

mozCurrentSampleOffset() 方法回傳音頻串流的「可聽位置」,也就是最後一次被播放的樣本的位置。

+
// 取得當時後端音頻串流的可聽位置(以樣本數計算)。
+var currentSampleOffset = audioOutput.mozCurrentSampleOffset();
+
+

對於正在被播放的樣本(正在被硬體播放的樣本位置可以由 mozCurrentSampleOffset() 取得),為了保持一點點的領先(「一點點」一般大約是500 ms),你應該定期地用 mozWriteAudio() 寫入固定額度的音頻資料。舉例來說,假如我們設此音頻為雙聲道與每秒44100個樣本、間隔時間為100 ms、pre-buffer為500 ms,則我們每次需要寫 (2 * 44100 / 10) = 8820 個樣本,總計的樣本數是 (currentSampleOffset + 2 * 44100 / 2)。(譯注:個人覺得這段寫得很怪,直接看例子可能會比較好懂。)

+

為了讓聲音的播放不間斷但是在寫入音頻資料資料與播放的時間差為最小,自動偵測最小的pre-buffer也是可能的。為了達到這個目的,你可以在一開始的時候寫入很小部份的資料,當看到 mozCurrentSampleOffset() 的回傳值大於 0 的時候測量其時間差。

+
var prebufferSize = sampleRate * 0.020; // 初使緩衝為 20 ms
+var autoLatency = true, started = new Date().valueOf();
+...
+// 延遲(Latency)的自動偵測
+if (autoLatency) {
+  prebufferSize = Math.floor(sampleRate * (new Date().valueOf() - started) / 1000);
+  if (audio.mozCurrentSampleOffset()) { // 開始播放了嗎?
+    autoLatency = false;
+}
+
+

處理音頻串流

+

由於 MozAudioAvailable 事件與 mozWriteAudio() 方法都是使用 Float32Array 為傳值,把一個音頻串流的輸出直接接上(或是處理過後接上)另一個是可以做到的。你應該將第一個音頻串流設為靜音使得只有第二音頻元素能被聽到。

+
<audio id="a1"
+       src="song.ogg"
+       controls>
+</audio>
+<script>
+var a1 = document.getElementById('a1'),
+    a2 = new Audio(),
+    buffers = [];
+
+function loadedMetadata() {
+  // 將音頻 a1 設為靜音
+  a1.volume = 0;
+  // 講 a2 的設定弄成與 a1 相等,然後由這個播放。
+  a2.mozSetup(a1.mozChannels, a1.mozSampleRate);
+}
+
+function audioAvailable(event) {
+  // 寫入當下的 framebuffer
+  var frameBuffer = event.frameBuffer;
+  writeAudio(frameBuffer);
+}
+
+a1.addEventListener('MozAudioAvailable', audioAvailable, false);
+a1.addEventListener('loadedmetadata', loadedMetadata, false);
+
+function writeAudio(audio) {
+  buffers.push(audio);
+
+  // 有在緩衝裡的資料的話,寫入該資料
+  while(buffers.length > 0) {
+    var buffer = buffers.shift();
+    var written = a2.mozWriteAudio(buffer);
+    // 如果非所有資料都被寫進去的話,將之留在緩衝裡:
+    if(written < buffer.length) {
+      buffers.unshift(buffer.slice(written));
+      return;
+    }
+  }
+}
+</script>
+
+

參見

+ +

{{ languages( { "en": "en/Introducing_the_Audio_API_Extension"} ) }}

diff --git a/files/zh-tw/learn/accessibility/index.html b/files/zh-tw/learn/accessibility/index.html new file mode 100644 index 0000000000..9ded955a1e --- /dev/null +++ b/files/zh-tw/learn/accessibility/index.html @@ -0,0 +1,75 @@ +--- +title: 無障礙網頁 +slug: Learn/Accessibility +tags: + - ARIA + - Accessibility + - Articles + - Beginner + - CSS + - CodingScripting + - HTML + - JavaScript + - Landing + - Learn + - Module + - NeedsTranslation + - TopicStub +translation_of: Learn/Accessibility +--- +
{{LearnSidebar}}
+ +

如果要當 web 開發者,學會 HTML、CSS、JavaScript 是很重要的。不過除此之外,你還要學得更多:你需要負責任地運用這些技術,才能讓所有讀者都能使用你的網頁。要達成這點,本模塊將展示一般最佳實做(在 HTMLCSSJavaScript 有示範)、跨瀏覽器測試、還有其他啟動的要點。

+ +

概觀

+ +

When someone describes a site as "accessible," they mean that any user can use all its features and content, regardless of how the user accesses the web — even and especially users with physical or mental impairments.

+ + + +

By default, HTML is accessible, if used correctly. Web accessibility involves ensuring that content remains accessible, regardless of who and how the web is accessed.

+ +

先決條件

+ +

要理解本模塊的概念,最少理解 HTMLCSSJavaScript 是個好主意。如果在學習相關技術時學習會更好。

+ +
+

:如果使用的設備無法讓你建立自己的文件,可以試著在 JSBinThimble 這種程式撰寫網站,執行大多數範例。

+
+ +

教學

+ +
+
何謂無障礙網頁?
+
這篇文章針對何謂無障礙網頁,起了一個好開頭。這模塊包含了要考慮哪些族群以及理由、不同族群會用什麼工具和 Web 互動、還有怎麼把無障礙網頁導入 Web 開發工作流程。
+
HTML:無障礙網頁的好開始
+
只要確保在任何時候,正確的 HTML 元素都用於正確的目的,就能消除各種網頁的障礙。這篇文章詳述 HTML 如何確保網頁無障礙。
+
充分實踐 CSS 與 JavaScript 的無障礙
+
如果 CSS 與 JavaScript 使用得當,將可以為無障礙網頁提供助力……反過來的話,就會嚴重影響無障礙體驗。這篇文章詳述如何在內容複雜的情況下,確保能充分實踐 CSS 與 JavaScript 的無障礙。
+
WAI-ARIA 基礎
+
從之前的文章來看,有時製作要涉及到非語意的 HTML 還有動態 JavaScript 更新技術……等,會令複雜的 UI 控制變得很困難。WAI-ARIA 正是為了解決此一問題而生。它對瀏覽器和輔助技術添加進一步的語意,讓用戶能知道發生了什麼事。我們將介紹如何在基本層面使用此技術,以提昇無障礙。
+
無障礙多媒體
+
會導致無障礙網頁出問題的另一個根源是多媒體:影片、聲音、圖片等內容,需要有合適的文字替代,以便輔助技術和它的用戶能夠理解。我們將在這篇文章中闡明作法。
+
行動無障礙網頁
+
隨著行動設備訪問漸受歡迎、還有像是 iOS 與 Android 這般熱門平台,已經具備完善的輔助工具,考慮到如何在這些平台上實踐無障礙網頁,就變得十分重要。這篇文章將討論行動裝置特有的無障礙網頁相關議題。
+
+ +

評估

+ +
+
無障礙網頁偵錯
+
要評估本模塊,我們會提出一些簡單的網站,你需要偵測有哪些無障礙的問題並修復之。
+
+ +

參見

+ + diff --git a/files/zh-tw/learn/accessibility/mobile/index.html b/files/zh-tw/learn/accessibility/mobile/index.html new file mode 100644 index 0000000000..eb04f93fd4 --- /dev/null +++ b/files/zh-tw/learn/accessibility/mobile/index.html @@ -0,0 +1,302 @@ +--- +title: Mobile accessibility +slug: Learn/Accessibility/Mobile +translation_of: Learn/Accessibility/Mobile +--- +
+
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Accessibility/Multimedia","Learn/Accessibility/Accessibility_troubleshooting", "Learn/Accessibility")}}
+ +

With web access on mobile devices being so popular, and popular platforms such as iOS and Android having fully fledged accessibility tools, it is important to consider the accessibility of your web content on these platforms. This article looks at mobile-specific accessibility considerations.

+ + + + + + + + + + + + +
Prerequisites:Basic computer literacy, a basic understanding of HTML, CSS, and JavaScript, and an understanding of the previous articles in the course.
Objective:To understand what problems exist with accessibility on mobile devices, and how to overcome them.
+ +

行動裝置上的無障礙

+ +

The state of accessibility — and support for web standards in general — is good in modern mobile devices. Long gone are the days when mobile devices ran completely different web technologies to desktop browsers, forcing developers to use browser sniffing and serve them completely separate sites (although quite a few companies still detect usage of mobile devices and serve them a separate mobile domain).

+ +

目前,行動裝置通常可以處理“全脂(full fat)”網站,主要平台甚至還內置了屏幕閱讀器,使視障人士能夠成功使用它們。 現代手機行動瀏覽器也傾向於對WAI-ARIA有很好的支持。

+ +

To make a website accessible and usable on mobile, you just need to follow general good web design and accessibility best practices.

+ +

There are some exceptions that need special consideration for mobile; the main ones are:

+ + + +

Summary of screenreader testing on Android and iOS

+ +

The most common mobile platforms have fully functional screenreaders. These function in much the same way as desktop screenreaders, except they are largely operated using touch gestures rather than key combinations.

+ +

Let's look at the main two: TalkBack on Android and VoiceOver on iOS.

+ +

Android TalkBack

+ +

The TalkBack screenreader is built into the Android operating system.

+ +

To turn it on, select Settings > Accessibility > TalkBack, and then press the slider switch to turn it on. Follow any additional on-screen prompts that you are presented with.

+ +

Note: Older versions of TalkBack are turned on in slightly different ways.

+ +

When TalkBack is turned on, your Android device's basic controls will be a bit different. For example:

+ +
    +
  1. Single-tapping an app will select it, and the device will read out what the app is.
  2. +
  3. Swiping left and right will move between apps, or buttons/controls if you are in a control bar. The device will read out each option.
  4. +
  5. Double-tapping anywhere will open the app/select the option.
  6. +
  7. You can also "explore by touch" — hold your finger down on the screen and drag it around, and your device will read out the different apps/items you move across.
  8. +
+ +

If you want to turn TalkBack off:

+ +
    +
  1. Navigate to your Settings app using the above gestures.
  2. +
  3. Navigate to Accessibility > TalkBack.
  4. +
  5. Navigate to the slider switch and activate it to turn it off.
  6. +
+ +

Note: You can get to your homescreen at any time by swiping up and left in a smooth motion. If you have more than one homescreen, you can move between them by swiping two fingers left and right.

+ +

For a more complete list of TalkBack gestures, see Use TalkBack gestures.

+ +

Unlocking the phone

+ +

When TalkBack is turned on, unlocking the phone is a bit different.

+ +

You can do a two-finger swipe up from the bottom of the lock screen. If you've set a passcode or pattern for unlocking your device, you will then be taken to the relevant entry screen to enter it.

+ +

You can also explore by touch to find the Unlock button at the bottom middle of the screen, and then double-tap.

+ +

Global and local menus

+ +

TalkBack allows you to access global and local context menus, wherever you have navigated to on the device. The former provides global options relating to the device as a whole, and the latter provides options relating just to the current app/screen you are in.

+ +

To get to these menus:

+ +
    +
  1. Access the global menu by quickly swiping down, and then right.
  2. +
  3. Access the local menu by quickly swiping up, and then right.
  4. +
  5. Swipe left and right to cycle between the different options.
  6. +
  7. Once you've selected the option you want, double-click to choose that option.
  8. +
+ +

For details on all the options available under the global and local context menus, see Use global and local context menus.

+ +

Browsing web pages

+ +

You can use the local context menu while in a web browser to find options to navigate web pages using just the headings, form controls, or links, or navigate line by line, etc.

+ +

For example, with TalkBack turned on:

+ +
    +
  1. Open your web browser.
  2. +
  3. Activate the URL bar.
  4. +
  5. Enter a web page that has a bunch of headings on it, such as the front page of bbc.co.uk. To enter the text of the URL: +
      +
    • Select the URL bar by swiping left/right till you get to it, and then double-tapping.
    • +
    • Hold your finger down on the virtual keyboard until you get the character you want, and then release your finger to type it. Repeat for each character.
    • +
    • Once you've finished, find the Enter key and press it.
    • +
    +
  6. +
  7. Swipe left and right to move between different items on the page.
  8. +
  9. Swipe up and right with a smooth motion to enter the local content menu.
  10. +
  11. Swipe right until you find the "Headings and Landmarks" option.
  12. +
  13. Double-tap to select it. Now you'll be able to swipe left and right to move between headings and ARIA landmarks.
  14. +
  15. To go back to the default mode, enter the local context menu again by swiping up and right, select "Default", and then double-tap to activate.
  16. +
+ +

Note: See Get started on Android with TalkBack for more complete documentation.

+ +

iOS VoiceOver

+ +

A mobile version of VoiceOver is built into the iOS operating system.

+ +

To turn it on, go to Your Settings app and select General > Accessibility > VoiceOver. Press the VoiceOver slider to enable it (you'll also see a number of other options related to VoiceOver on this page).

+ +

Once VoiceOver is enabled, the iOS's basic control gestures will be a bit different:

+ +
    +
  1. A single tap will cause the item you tap on to be selected; your device will speak the item you've tapped on.
  2. +
  3. You can also navigate the items on the screen by swiping left and right to move between them, or by sliding your finger around on the screen to move between different items (when you find the item you want, you can remove your finger to select it).
  4. +
  5. To activate the selected item (e.g., open a selected app), double-tap anywhere on the screen.
  6. +
  7. Swipe with three fingers to scroll through a page.
  8. +
  9. Tap with two fingers to perform a context-relevant action — for example, taking a photo while in the camera app.
  10. +
+ +

To turn it off again, navigate back to Settings > General > Accessibility > VoiceOver using the above gestures, and toggle the VoiceOver slider back to off.

+ +

Unlock phone

+ +

To unlock the phone, you need to press the home button (or swipe) as normal. If you have a passcode set, you can select each number by swiping/sliding (as explained above) and then double-tapping to enter each number when you've found the right one.

+ +

Using the Rotor

+ +

When VoiceOver is turned on, you have a navigation feature called the Rotor available to you, which allows you to quickly choose from a number of common useful options. To use it:

+ +
    +
  1. Twist two fingers around on the screen like you are turning a dial. Each option will be read aloud as you twist further around. You can go back and forth to cycle through the options.
  2. +
  3. Once you've found the option you want: +
      +
    • Release your fingers to select it.
    • +
    • If it is an option you can iterate the value of (such as Volume or Speaking Rate), you can do a swipe up or down to increase or decrease the value of the selected item.
    • +
    +
  4. +
+ +

The options available under the Rotor are context-sensitive — they will differ depending on what app or view you are in (see below for an example).

+ +

Browsing web pages

+ +

Let's have a go at web browsing with VoiceOver:

+ +
    +
  1. Open your web browser.
  2. +
  3. Activate the URL bar.
  4. +
  5. Enter a web page that has a bunch of headings on it, such as the front page of bbc.co.uk. To enter the text of the URL: +
      +
    • Select the URL bar by swiping left/right until you get to it, and then double-tapping.
    • +
    • For each character, hold your finger down on the virtual keyboard until you get the character you want, and then release your finger to select it. Double-tap to type it.
    • +
    • Once you've finished, find the Enter key and press it.
    • +
    +
  6. +
  7. Swipe left and right to move between items on the page. You can double-tap an item to select it (e.g., follow a link).
  8. +
  9. By default, the selected Rotor option will be Speaking Rate; you can currently swipe up and down to increase or decrease the speaking rate.
  10. +
  11. Now turn two fingers around the screen like a dial to show the rotor and move between its options. Here are a few examples of the options available: +
      +
    • Speaking Rate: Change the speaking rate.
    • +
    • Containers: Move between different semantic containers on the page.
    • +
    • Headings: Move between headings on the page.
    • +
    • Links: Move between links on the page.
    • +
    • Form Controls: Move between form controls on the page.
    • +
    • Language: Move between different translations, if they are available.
    • +
    +
  12. +
  13. Select Headings. Now you'll be able to swipe up and down to move between headings on the page.
  14. +
+ +

Note: For a more complete reference covering the VoiceOver gestures available and other hints on accessibility testing on iOS, see Test Accessibility on Your Device with VoiceOver.

+ +

Control mechanisms

+ +

In our CSS and JavaScript accessibility article, we looked at the idea of events that are specific to a certain type of control mechanism (see Mouse-specific events). To recap, these cause accessibility issues because other control mechanisms can't activate the associated functionality.

+ +

As an example, the click event is good in terms of accessibility — an associated event handler can be invoked by clicking the element the handler is set on, tabbing to it and pressing Enter/Return, or tapping it on a touchscreen device. Try our simple-button-example.html example (see it running live) to see what we mean.

+ +

Alternatively, mouse-specific events such as mousedown and mouseup create problems — their event handlers cannot be invoked using non-mouse controls.

+ +

If you try to control our simple-box-drag.html (see example live) example with keyboard or touch, you'll see the problem. This occurs because we are using code such as the following:

+ +
div.onmousedown = function() {
+  initialBoxX = div.offsetLeft;
+  initialBoxY = div.offsetTop;
+  movePanel();
+}
+
+document.onmouseup = stopMove;
+ +

To enable other forms of control, you need to use different, yet equivalent events — for example, touch events work on touchscreen devices:

+ +
div.ontouchstart = function(e) {
+  initialBoxX = div.offsetLeft;
+  initialBoxY = div.offsetTop;
+  positionHandler(e);
+  movePanel();
+}
+
+panel.ontouchend = stopMove;
+ +

We've provided a simple example that shows how to use the mouse and touch events together — see multi-control-box-drag.html (see the example live also).

+ +

Note: You can also see fully functional examples showing how to implement different control mechanisms at Implementing game control mechanisms.

+ +

響應式設計

+ +

Responsive design is the practice of making your layouts and other features of your apps dynamically change depending on factors such as screen size and resolution, so they are usable and accessible to users of different device types.

+ +

In particular, the most common problems that need to be addressed for mobile are:

+ + + +

Note: We won't provide a full discussion of responsive design techniques here, as they are covered in other places around MDN (see above links).

+ +

Specific mobile considerations

+ +

There are other important issues to consider when making sites more accessible on mobile. We have listed a couple here, but we will add more when we think of them.

+ +

Not disabling zoom

+ +

Using viewport, it is possible to disable zoom. Alwasy ensure resizing is enabled, and set the width to the device's width in the {{htmlelement("head")}}:

+ +
<meta name="viewport" content="width=device-width; user-scalable=yes">
+ +

You should never set user-scalable=no if at all possible — many people rely on zoom to be able to see the content of your website, so taking this functionality away is a really bad idea. There are certain situations where zooming might break the UI; in such cases, if you feel that you absolutely need to disable zoom, you should provide some other kind of equivalent, such as a control for increasing the text size in a way that doesn't break your UI.

+ +

Keeping menus accessible

+ +

Because the screen is so much narrower on mobile devices, it is very common to use media queries and other technologies to make the navigation menu shrink down to a tiny icon at the top of the display — which can be pressed to reveal the menu only if it's needed — when the site is viewed on mobile. This is commonly represented by a "three horizontal lines" icon, and the design pattern is consequently known as a "hamburger menu".

+ +

When implementing such a menu, you need to make sure that the control to reveal it is accessible by appropriate control mechanisms (normally touch for mobile), as discussed in {{anch("Control mechanisms")}} above, and that the rest of the page is moved out of the way or hidden in some way while the menu is being accessed, to avoid confusion with navigating it.

+ +

Click here for a good hamburger menu example.

+ +

User input

+ +

On mobile devices, inputting data tends to be more annoying for users than the equivalent experience on desktop computers. It is more convenient to type text into form inputs using a desktop or laptop keyboard than a touchscreen virtual keyboard or a tiny mobile physical keyboard.

+ +

For this reason, it is worth trying to minimize the amount of typing needed. As an example, instead of getting users to fill out their job title each time using a regular text input, you could instead offer a {{htmlelement("select")}} menu containing the most common options (which also helps with consistency in data entry), and offer an "Other" option that displays a text field to type any outliers into. You can see a simple example of this idea in action in common-job-types.html (see the common jobs example live).

+ +

It is also worth considering the use of HTML5 form input types such as date on mobile platforms as they handle them well — both Android and iOS, for example, display usable widgets that fit well with the device experience. See html5-form-examples.html for some examples (see the HTML5 form examples live) — try loading these and manipulating them on mobile devices. For example:

+ + + +

If you want to provide a different solution for desktops, you could always serve different markup to your mobile devices using feature detection. See input types for raw information on detecting different input types, and also check out our feature detection article for much more information.

+ +

總結

+ +

In this article we have provided you with some details about common mobile accessibility-specific issues and how to overcome them. We also took you through usage of the most common screenreaders to aid you in accessibility testing.

+ +

延伸閱讀

+ + + +
{{PreviousMenuNext("Learn/Accessibility/Multimedia","Learn/Accessibility/Accessibility_troubleshooting", "Learn/Accessibility")}}
+ +
+

In this module

+ + +
+
diff --git a/files/zh-tw/learn/accessibility/wai-aria_basics/index.html b/files/zh-tw/learn/accessibility/wai-aria_basics/index.html new file mode 100644 index 0000000000..926505aa85 --- /dev/null +++ b/files/zh-tw/learn/accessibility/wai-aria_basics/index.html @@ -0,0 +1,421 @@ +--- +title: WAI-ARIA基礎 +slug: Learn/Accessibility/WAI-ARIA_basics +translation_of: Learn/Accessibility/WAI-ARIA_basics +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Accessibility/CSS_and_JavaScript","Learn/Accessibility/Multimedia", "Learn/Accessibility")}}
+ +

接續之前的文章,有時在涉及非語意HTML與動態 JavaScript更新的內容製作複雜的UI控制措施將是個難題。WAI-ARIA即是一個能藉由添加進一步的語意幫助處理這種問題的技術 ,讓瀏覽器與輔助科技可以辨識及用以讓使用者知道發生甚麼事情。這裡我們將展示如何以基本水準的運用來增進無障礙使用。

+ + + + + + + + + + + + +
先決條件:基本電腦技能、基本瞭解HTML, CSS與JavaScript、瞭解本課程先前文章。
目標:能熟悉WAI-ARIA,以及在必要時如何用於提供有用的附加語意強化無障礙。
+ +

甚麼是WAI-ARIA?

+ +

開始瞭解甚麼是WAI-ARIA,以及它可為我們做些甚麼。

+ +

一個全新問題集

+ +

當網站應用程式開始更複雜與動態,新的無障礙特性與問題集就開始出現。

+ +

例如,HTML5 導入許多語意的元素來定義一般頁面的特性({{htmlelement("nav")}}, {{htmlelement("footer")}}等) 在沒有這些可用之前,開發者僅簡單使用{{htmlelement("div")}}搭配IDs或classes,如<div class="nav">,但這些是有問題的,因為沒有很簡單的方法可程式化地容易找到特定的頁面特性如主要導覽功能。

+ +

起初的解決方案是在頁面的頂端添加一個或更多隱藏的連結去連結到導覽功能(或其他任何的功能),例如:

+ +
<a href="#hidden" class="hidden">Skip to navigation</a>
+ +

但這仍然不是非常精確,並且僅能使用於螢幕報讀器從頁面頂端閱讀下來的時候。

+ +

如同另一個例子,應用程式開始具有複雜的控制措施如日期選取器提供選擇日期,內容滑塊提供選取內容值等。HTML5提供特定的輸入型態來呈現這些控制措施:

+ +
<input type="date">
+<input type="range">
+ +

這些在跨瀏覽器之間沒有全面性支援,而且也非常困難去為他們指定樣式,而使他們與網站設計整合時不是很好用。因此,開發者時常依賴JavaScript資源庫來產生這些一系列內嵌的控制措施 {{htmlelement("div")}}或具有classnames的表格元素,透過CSS指定樣式與使用JavaScript控制。

+ +

這個的問題是視覺上可以運作,但螢幕報讀器則一點也無法理解它們是甚麼,以及它們的使用者僅被告知他們可以看到一堆沒有語意的元素來描述它們的含意。

+ +

進入WAI-ARIA

+ +

WAI-ARIA 是一個由W3C編撰的規格,定義一套額外的HTML屬性能用於元素上提供額外的語意及改善可及性,當元素缺乏這些條件時可適用。本規格定義三個主要的特點:

+ + + +

有關WAI-ARIA屬性的重要觀點是他們不會影響網頁的任何內容,除了透過瀏覽器無障礙API揭露資訊之外(螢幕報讀器即從中獲得資訊)。儘管WAI-ARIA屬性對CSS選擇元素很有用,但不會影響網頁結構、DOM等。

+ +
+

注意:你可以在WAI-ARIA規格中找到所有ARIA的角色及其用法的很有用清單,請參見 Definition of Roles連結以獲得更進一步的資訊。

+ +

本規格也涵括所有屬性與狀態的清單,請參見 Definitions of States and Properties (all aria-* attributes)連結以獲得更進一步的資訊。

+
+ +

哪裡支援WAI-ARIA?

+ +

這不是一個容易回答的問題。要難找到一個決定性的資源來陳述何者是支援WAI-ARIA的特點以及在何處,因為:

+ +
    +
  1. 在WAI-ARIA規格中有很多特點。
  2. +
  3. 要考量作業系統、瀏覽器與螢幕報讀器的許多組合。
  4. +
+ +

最後一點是關鍵—首先要使用螢幕報讀器,你的作業系統必須執行具有必要的無障礙API的瀏覽器去揭露螢幕報讀器必須去完成工作的資訊。大部分主流的作業系統有1個或2個瀏覽器可供螢幕報讀器使用。Paciello Group一則最近的文章提供這些數據—請參見 Rough Guide: browsers, operating systems and screen reader support updated

+ +

接著,你必須擔心瀏覽器是否支援ARIA特徵並透過其API揭露,同時螢幕報讀器是否辨識該資訊並以可用的方式向使用者呈現的問題。

+ +
    +
  1. 瀏覽器支援一般相當好—在撰文當下, caniuse.com表示全球瀏覽器對WAI-ARIA的支援率大約為88%。
  2. +
  3. 螢幕報讀器對ARIA特徵的支援沒有相當於此水平,但大部分主流的螢幕報讀器是有達到此水平。你可查閱Powermapper的 WAI-ARIA Screen reader compatibility這篇文章了解支援的水平。
  4. +
+ +

在本文中,我們未試圖涵蓋每一個WAI-ARIA特徵及其確切的支援細節。相反地,我們將涵蓋最關鍵的WAI-ARIA特徵讓你知道;如果我們沒有提到任何支援細節,你可認定該特徵得到很好的支援。我們會明確地提到這個例外情況。

+ +
+

注意:某些JavaScript儲存庫支援WAI-ARIA,亦即當他們產生UI特徵如複雜的表單控制措施,他們添加ARIA屬性來增進這些特徵的無障礙。如果你在尋找第三方的JavaScript解決方案來快速的開發UI,你應該謹慎地考量其UI插件的無障礙作為你決定使用的重要因素。jQuery UI(參見About jQuery UI: Deep accessibility support)、 ExtJS與 Dojo/Dijit是良好範例。

+
+ +

何時應該使用WAI-ARIA?

+ +

我們討論了促使WAI-ARIA早期建立的一些問題,但基本上WAI-ARIA在4個主要領域很有用:

+ +
    +
  1. 路標/地標:ARIA的角色屬性值可作為地標,不是複製HTML5元素的語意(如{{htmlelement("nav")}}),就是超越HTML5語意而對不同的功能區域提供路標,如搜尋、頁籤群組、頁籤、清單框等。
  2. +
  3. 動態內容更新:螢幕報讀器往往難以報讀不斷改變的內容;當某個內容區域更新時,我們可以使用aria-live通知螢幕報讀器的使用者,例如透過 XMLHttpRequestDOM APIs
  4. +
  5. 增強鍵盤無障礙:內建的HTML元素具有原生的鍵盤無障礙;當其他元素伴隨使用JavaScript模擬相似的互動時,鍵盤無障礙操作與螢幕報讀器報讀會遭遇問題。如果這是不可避免的,WAI-ARIA提供讓其他元素獲得焦點的一種方法(使用 tabindex)。
  6. +
  7. 非語意控制措施的無障礙:當一系列巢狀的<div>搭配CSS/JavaScript用於創建一個複雜的UI特徵,或者一個透過JavaScript大幅增強/改變的原生控制措施,無障礙會遭遇到困難—如果沒有語意或其他線索,螢幕報讀器使用者將發覺難以理解該特徵的作用。在這種情況下,ARIA可以幫助提供缺失的部分使用如按鈕、清單框或頁籤群組等角色組合,以及aria-required 或aria-posinset等屬性對功能性提供進一步的線索。
  8. +
+ +

記住一件事 — 僅在必需時才使用WAI-ARIA! 理想情況下,你應該總是使用原生HTML特徵提供螢幕報讀器所需要的語意來告訴其使用者接下來將發生甚麼事情。有時候這是不可能的情形,不是因為你受限於控制該程式碼,就是因為你創建一些複雜而無法用簡易的HTML元素來開發。在這種情況下,WAI-ARIA可作為有價值的無障礙增強工作。

+ +

再說一次,只有需要的時候才使用它!

+ +
+

注意: 請確保有各類實際的使用者來測試你的網站 — 非身障者、使用螢幕報讀器者、使用鍵盤導覽者等。他們將比你更能了解它運作的效果。

+
+ +

實作WAI-ARIA開發

+ +

在下一個章節我們將更仔細地看看這4個領域,並附帶實際的範例。在繼續之前,你應該將備妥螢幕報讀器測試設置,以便在過程中你可以測試這些範例。

+ +

更多資訊請參見螢幕報讀器測試章節。

+ +

路標/地標

+ +

WAI-ARIA添加角色屬性給瀏覽器,讓你可以在必要時添加額外的語意值到你網站上的元素。這第一個主要的領域在為螢幕報讀器提供資訊方面非常有用,讓螢幕報讀器的使用者可以找到常見的頁面元素。我們來看個範例 — 網站-無-角色範例(看實際頁面)有以下的結構:

+ +
<header>
+  <h1>...</h1>
+  <nav>
+    <ul>...</ul>
+    <form>
+      <!-- search form  -->
+    </form>
+  </nav>
+</header>
+
+<main>
+  <article>...</article>
+  <aside>...</aside>
+</main>
+
+<footer>...</footer>
+ +

若你嘗試在現代瀏覽器中使用螢幕報讀器來測試此範例,你將可以獲得一些有用的資訊。例如,VoiceOver給你以下的資訊:

+ + + +

如果你到VoiceOver地標選單(使用VoiceOver主鍵+ U,然後使用游標鍵循環整個選單選項),你會看到大部分元素被列的很好,因此可以很快地訪問他們。

+ +

+ +

然而,這裡我們可以做得更好,搜尋表單是一個人們想要找到的很重要的地標,但是它並沒有列在地標選項之中或者被視為顯著的地標,除了在實際輸入而被召喚作為搜尋輸入之外(<input type="search">)。另外,有些舊的瀏覽器(大部分是指IE8)無法辨識HTML5元素的語意。

+ +

讓我們使用一些ARIA特徵來改善它。首先,我們將添加一些角色屬性到我們的HTML結構。你可以試著複製我們原始的檔案(參見index.htmlstyle.css),或者瀏覽我們的網站-aria-角色範例(看實際頁面),其結構如下:

+ +
<header>
+  <h1>...</h1>
+  <nav role="navigation">
+    <ul>...</ul>
+    <form role="search">
+      <!-- search form  -->
+    </form>
+  </nav>
+</header>
+
+<main>
+  <article role="article">...</article>
+  <aside role="complementary">...</aside>
+</main>
+
+<footer>...</footer>
+ +

在本範例中我們也將給你一個額外的特徵—{{htmlelement("input")}} 元素賦予 aria-label屬性,藉由給予描述性的標籤讓螢幕報讀器可以報讀出來,即使我們沒有包含{{htmlelement("label")}}元素。像這種情況就非常有用—搜尋表單是一個非常常見、容易辨識的特徵,而添加視覺的標籤可能破壞頁面的設計。

+ +
<input type="search" name="q" placeholder="Search query" aria-label="Search through site content">
+ +

現在如果我們使用VoiceOver來看這個範例,我們可以獲得一些改善:

+ + + +

除此之外,該網站對舊瀏覽器如IE8的使用者更可能無障礙;為了這個目的,包含ARIA角色是值得的。如果為了某些原因,你的網站僅使用 <div>建置,那麼肯定你應該包含ARIA角色來提供這些非常需要的語意!

+ +

當ARIA超越從HTML5所能獲得的語意時,搜尋表單的改進語意已經顯示實現的可能性。你將會在下面看到更多關於這些語意與ARIA屬性的能力,尤其在{{anch("Accessibility of non-semantic controls")}}章節。現在,我們先來看看ARIA如何幫助動態內容更新。

+ +

動態內容更新

+ +

從文本內容到附著於圖片的替代文字,其內容載入至DOM中可方便螢幕報讀器使用。因此,大部分使用文字內容的傳統靜態網站能輕易讓視覺障礙者無障礙使用。

+ +

問題在於現代網頁應用程式通常不只是靜態的文字—他們傾向有很多動態更新的內容,例如透過像XMLHttpRequest, Fetch, 或DOM APIs等機制更新的內容而不必重新載入全部的頁面。這些有時稱為即時區塊。

+ +

我們來看一個簡單的範例—請看 aria-no-live.html (看實際頁面)。本範例中我們有簡單的隨機引言框:

+ +
<section>
+  <h1>Random quote</h1>
+  <blockquote>
+    <p></p>
+  </blockquote>
+</section>
+ +

我們的JavaScript透過含有一系列的隨機引言與其作者的 XMLHttpRequest 載入一個JSON檔案。一旦這些完成,我們就開始 setInterval() 迴圈每10秒載入新的隨機引言到引言框之中。

+ +
var intervalID = window.setInterval(showQuote, 10000);
+ +

這個運作正常,但對無障礙不是很好—此內容更新無法被螢幕報讀器所偵測,所以他們的使用者不知道發生甚麼事情。這是一個相當平凡的例子,但只要想像一下如果你正在創建一個有著大量不斷更新內容的複雜UI,如聊天室、一個策略型的遊戲UI、或者一個即時更新的購物車顯示窗—則將不可能以任何有效的方式使用該應用程式而沒有某種提醒使用者該更新內容的方法。

+ +

很幸運地WAI-ARIA提供一項有用的機制來提供這些警告—即aria-live 屬性。將此屬性用在元素上可讓螢幕報讀器讀出更新的內容。報讀內容的緊急性決定於以下屬性值:

+ + + +

一般而言, assertive 設置足以讓你的更新內容在他們出現時依序地讀出,因此如果同時有多個事件改變,你將獲得所有的更新。只有對非常高優先順序的更新使用  rude 才能覆蓋其他所有的更新。

+ +

我們希望你複製 aria-no-live.html 與 quotes.json,並更新 <section> 標籤如下所示:

+ +
<section aria-live="assertive">
+ +

這將使螢幕報讀器在內容更新時讀出更新的內容。

+ +
+

注意: 如果你嘗試從 XMLHttpRequest 執行 file:// URL大部分的瀏覽器會拋出安全異常,例如你直接上傳該檔案到瀏覽器(透過雙擊滑鼠鍵等)。為了這項可以執行,你需要將檔案上傳到一個網站伺服器如 GitHub,或本機網站伺服器如 Python's SimpleHTTPServer

+
+ +

這裡有一項額外的考量—只有文字更新才讀出。如果我們也總是讀出標題,那將很好,以讓使用者記住讀出的內容。為做到這樣,我們可以添加 aria-atomic 屬性到這個部分,再次更新您的 <section> 標籤如下所示:

+ +
<section aria-live="assertive" aria-atomic="true">
+ +

aria-atomic="true"屬性告訴螢幕報讀器以一個原子單位方式讀出完整的元素內容,而不僅只讀出更新的部分。

+ +
+

注意:你可以查看完成的範例 aria-live.html (看實際頁面)。

+
+ +
+

注意: aria-relevant 屬性在即時區塊更新時對於控制讀出甚麼內容也相當有用,例如你可以僅獲得讀出新增或移除的內容。

+
+ +

增強鍵盤無障礙

+ +

如同在本模組其他章節所討論, HTML關於無障礙的關鍵優勢之一是內建鍵盤無障礙特徵如按鈕、表單控制措施及連結。一般而言,你可以使用tab鍵在控制措施之間移動,輸入(Enter)/返回(Return)鍵用來選擇或觸發控制措施,以及偶爾需要其他的控制措施(例如上下游標在 <select> 框中的選項間移動)。

+ +

然而,有時你最終必須撰寫不是使用非語意的元素如按鈕(或其他控制的型態),或者使用可獲焦點的控制措施用作非正確目的程式碼。你可能嘗試修正一些繼承來的不好的程式碼,或者你可能創建需要某些種類的複雜插件。

+ +

讓非焦點的程式碼可獲得焦點,WAI-ARIA使用一些新值擴展 tabindex 屬性:

+ + + +

我們更詳細討論這一點並在我們的HTML無障礙文章中展示典型的實作—請參見 Building keyboard accessibility back in.

+ +

非語意控制措施的無障礙

+ +

本部份接續前一章節—當一系列巢狀的 <div>搭配CSS/JavaScript用於創建一個複雜的UI特徵,或者一個透過JavaScript大幅增強/改變的原生控制措施,不僅鍵盤無障礙會遭遇到困難,而且如果沒有語意或其他線索,螢幕報讀器使用者也會發覺難以理解該特徵的作用。在這種情況下,ARIA可以幫助提供缺失的語意。

+ +

表單驗證與錯誤警告

+ +

首先,讓我們再看一次在我們的CSS與JavaScript無障礙文章中第一次看的表單範例(請閱讀 Keeping it unobtrusive完整回顧)。在本章節文末我們展示當你試著送出表單而驗證錯誤時,出現我們包含一些在錯誤訊息框的ARIA屬性。

+ +
<div class="errors" role="alert" aria-relevant="all">
+  <ul>
+  </ul>
+</div>
+ + + +

我們可進一步使用我們的ARIA,並提供更多的驗證協助。如何指出區塊是否需要在第一個位置,以及年齡的範圍應該多少?

+ +
    +
  1. 在此,複製我們的 form-validation.html 與 validation.js 檔案,並將他們儲存在本機目錄。
  2. +
  3. 在文字編輯器開啟他們並且看一下該程式碼如何運作。
  4. +
  5. 首先,在開始的 <form> 標籤之上增加一個段落,如下所示,並且用星號標記兩個表單的 <label>。這是一般我們對有視力的使用者標記必要區塊的方法。 +
    <p>Fields marked with an asterisk (*) are required.</p>
    +
  6. +
  7. 這讓視覺有意義,但這對螢幕報讀器使用者不能輕易理解。很幸運地,WAI-ARIA提供 aria-required 屬性以提示螢幕報讀器應告訴使用者需要填寫的表單輸入欄位。更新<input> 元素如下: +
    <input type="text" name="name" id="name" aria-required="true">
    +
    +<input type="number" name="age" id="age" aria-required="true">
    +
  8. +
  9. 如果你現在儲存本範例並使用螢幕報讀器測試,你應該聽到這個內容 "Enter your name star, required, edit text"。
  10. +
  11. 如果我們給予螢幕報讀器使用者與視覺的使用者有關年齡的值應該是甚麼的概念,這樣也將會很有用。這個或許常以提示或在表單輸入區內預設文本的方式呈現。WAI-ARIA用包含 aria-valuemin 與 aria-valuemax 屬性來指定最小與最大值,但這些目前未受到很好的支持;比較受支持的特徵是 HTML5 placeholder 屬性,它在沒有輸入值的時間將含有的訊息顯示在輸入框,並能由許多螢幕報讀器讀出。更新你的數值輸入如下所示: +
    <input type="number" name="age" id="age" placeholder="Enter 1 to 150" aria-required="true">
    +
  12. +
+ +
+

注意:你可以查看完成的範例 form-validation-updated.html

+
+ +

除了傳統的 {{htmlelement("label")}} 元素之外,WAI-ARIA也能賦予一些進階的表單標籤技術。我們已經談論過使用 aria-label 屬性在我們不希望標籤讓有視覺的使用者看見的地方來提供標籤(參見上述 {{anch("Signposts/Landmarks")}} 章節。如果你想要指定一個非<label> 元素當作標籤或具有相同標籤多重的表單輸入標籤,這裡有使用其他屬性如 aria-labelledby 的其他標籤技術,如果你想要其他的訊息與表單輸入關聯並且報讀出來,使用 aria-describedby。更多細節請參見 WebAIM's Advanced Form Labeling article

+ +

還有許多其他有用的屬性與狀態,用來指出表單元素的狀態。例如, aria-disabled="true" 可用於指出表單區域是處於停用的狀態。許多瀏覽器只會跳過停用的表單區塊,並且甚至不會被螢幕報讀器讀出,但在某些情況下,他們可被感知,所以最好包含此屬性讓螢幕報讀器知道停用的輸入事實上即是停用的狀態。

+ +

如果輸入的停用狀態可能產生改變,也最好在發生時指出,以及其結果為何。例如,在我們的 form-validation-checkbox-disabled.html 展示中,當核取框被核取時,可以讓另一個表單輸入允許輸入更進一步的資訊。我們已經設置一個隱藏的即時區塊:

+ +
<p class="hidden-alert" aria-live="assertive"></p>
+ +

這是使用絕對位置從視窗中隱藏。當核取/未核取時,我們更新在隱藏的即時區塊中的文字,告訴螢幕報讀器使用者選取這個核取框時結果會是甚麼,以及更新 aria-disabled 的狀態,連同一些視覺的指示:

+ +
function toggleMusician(bool) {
+  var instruItem = formItems[formItems.length-1];
+  if(bool) {
+    instruItem.input.disabled = false;
+    instruItem.label.style.color = '#000';
+    instruItem.input.setAttribute('aria-disabled', 'false');
+    hiddenAlert.textContent = 'Instruments played field now enabled; use it to tell us what you play.';
+  } else {
+    instruItem.input.disabled = true;
+    instruItem.label.style.color = '#999';
+    instruItem.input.setAttribute('aria-disabled', 'true');
+    instruItem.input.removeAttribute('aria-label');
+    hiddenAlert.textContent = 'Instruments played field now disabled.';
+  }
+}
+ +

描述非語意按鈕為按鈕

+ +

本課程我們已經談過幾次按鈕、連結或表單元素(參見HTML無障礙文章的 UI controls ,以及前述{{anch("Enhancing keyboard accessibility")}}的原生無障礙(以及在使用其他元素偽造背後的無障礙議題)。基本上,使用 tabindex 與一些 JavaScript,在很多情況下,你可以在沒有太多困難下增加鍵盤無障礙支援功能。

+ +

但螢幕報讀器的情況如何呢?他們仍然無法將這些元素視為按鈕。如果我們用螢幕報讀器測試我們的 fake-div-buttons.html 範例,我們偽造的按鈕將會用句子如 "Click me!, group"讀出,很顯然地令人困惑。

+ +

我們可以使用WAI-ARIA角色來修正它。請複製 fake-div-buttons.html在本機,並且對每個按鈕<div>增加  role="button" ,範例如下:

+ +
<div data-message="This is from the first button" tabindex="0" role="button">Click me!</div>
+ +

現在當你使用螢幕報讀器測試它時,按鈕將會用句子如"Click me!, button" 讀出—這樣好多了。

+ +
+

注意:記住最好盡可能使用正確的語意元素,如果你希望創建一個按鈕,並且可使用 {{htmlelement("button")}} 元素,就應該使用 {{htmlelement("button")}} 元素!

+
+ +

透過複雜的插件引導使用者

+ +

除了標準HTML可用外,還有一堆其他角色可以辨識非語意的元素結構作為一般的使用者介面特徵,例如 combobox, slider, tabpanel, tree。你可在 Deque university code library中找到很多有用的範例,可給你這些控制措施如何做到無障礙的想法。

+ +

我們來看看我們自己的範例,我們回到我們簡單的絕對位置頁籤的介面(參見在我們的CSS與JavaScript無障礙文章中的 Hiding things ),你可以找到 頁籤資訊框範例(看原始碼).

+ +

本範例以鍵盤無障礙而言運作正常—你可以開心地在不同的頁籤間跳位,並且選擇他們顯示該頁籤的內容,也相當地容易操作—你可以滾動內容並使用標題來導覽,即使你看不到螢幕上正發生的事情。然而內容是甚麼並非很明顯—螢幕報讀器目前以連結的清單報讀內容,以及有三個標題的內容。這樣無法給你了解內容之間的關係。最好給予使用者更多關於內容結構的線索。

+ +

為改善這些,我們創建新的範例版本為 aria-tabbed-info-box.html (看實際頁面),我們已經更新頁籤介面的結構如下:

+ +
<ul role="tablist">
+  <li class="active" role="tab" aria-selected="true" aria-setsize="3" aria-posinset="1" tabindex="0">Tab 1</li>
+  <li role="tab" aria-selected="false" aria-setsize="3" aria-posinset="2" tabindex="0">Tab 2</li>
+  <li role="tab" aria-selected="false" aria-setsize="3" aria-posinset="3" tabindex="0">Tab 3</li>
+</ul>
+<div class="panels">
+  <article class="active-panel" role="tabpanel" aria-hidden="false">
+    ...
+  </article>
+  <article role="tabpanel" aria-hidden="true">
+    ...
+  </article>
+  <article role="tabpanel" aria-hidden="true">
+    ...
+  </article>
+</div>
+ +
+

注意: 這裡最引人注目的是我們移除在原來範例中的連結,並且只使用清單項目作為頁籤—這樣做是因為對螢幕報讀器使用者比較少困擾(連結並非真正地帶妳到哪個地方;他們只是改變視窗),並且可讓組件大小/位置在組件特徵中有很好的運作—當這些是放在連結上的時候,瀏覽器將維持報讀"1 of 1",而非"1 of 3"、"2 of 3"等。

+
+ +

新的特徵如下:

+ + + +

在我們的測試中,這些新的結構確實提供整體的改善。頁籤現在被認定為頁籤(如螢幕報讀器讀出"索引標籤"),被選取的頁籤以”已選取”指出並讀出頁籤的名稱,螢幕報讀器也告訴你目前所在的頁籤數目。此外,因為設置 aria-hidden (只有非隱藏的頁籤才設定aria-hidden="false" ),非隱藏的頁籤是唯一你可以向下導覽的內容,意即所選取的內容很容易找到。

+ +
+

注意:如果有任何你很明確地不希望螢幕報讀器讀出的內容,你可賦予它們 aria-hidden="true" 屬性。

+
+ +

總結

+ +

本文並未涵蓋所有WAI-ARIA的內容,但應該給予你足夠的資訊來了解如何使用它,以及了解一些你會遇到而需要它的最常見型態。

+ +

相關參考資訊

+ + + +

{{PreviousMenuNext("Learn/Accessibility/CSS_and_JavaScript","Learn/Accessibility/Multimedia", "Learn/Accessibility")}}

+ +

 

+ +

本模組章節

+ + + +

 

diff --git a/files/zh-tw/learn/accessibility/what_is_accessibility/index.html b/files/zh-tw/learn/accessibility/what_is_accessibility/index.html new file mode 100644 index 0000000000..35e520c814 --- /dev/null +++ b/files/zh-tw/learn/accessibility/what_is_accessibility/index.html @@ -0,0 +1,201 @@ +--- +title: 何謂無障礙網頁? +slug: Learn/Accessibility/What_is_accessibility +translation_of: Learn/Accessibility/What_is_accessibility +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/Accessibility/HTML", "Learn/Accessibility")}}
+ +

這篇文章給「到底什麼是無障礙網頁」的模塊,開了個好起頭:以下將包括我們該考慮什麼樣的用戶以及理由、不同的人要在 web 用什麼工具互動、還有如何令無障礙網頁成為 web 開發的一部分。

+ + + + + + + + + + + + +
先決要求:基本資訊能力、還有對 HTML 與 CSS 有基本的理解。
目標:熟悉無障礙網頁,包含它是什麼、還有它如何影響作為 web 開發者的你。
+ +

到底什麼是無障礙網頁?

+ +

無障礙是盡可能令更多人,使用你網站的實做:一般來說,我們會認為這屬於身心障礙者的範疇,但它其實會涵蓋其他群體:像是使用行動設備、或者網速很慢的人。

+ +

也可以把無障礙想成:所有人,不論他們的能力或環境如何,都要同等看待、並給予同等機會。就如同我們不能把坐在輪椅的人,排除在某棟物理大樓之外:目前的公共建築,通常都會有電梯或輪椅坡道;我們也不能排除視障或手機用戶,使用我們的網站。儘管我們生而不同,但我們都是人,因此,我們都擁有相同的人權。

+ +

無障礙是好事,但也是某些國家法律的一部分,也能開啟一些關係到你的服務或產品的市場。

+ +

無障礙與其所需之最佳實做將使大家受益:

+ + + +

你在鎖定什麼樣的障礙者?

+ +

身心障礙者和非身心障礙者一樣多元,他們的障別也是如此。重點是,不要光用自己使用電腦和 web 的角度去思考這件事:你並不是無障礙網頁的用戶。下文將解釋應當考慮的障別,還有他們訪問 web 內容的特殊工具(通常稱作 assistive technologiesAT輔助工具輔具)。

+ +
+

:世界衛生組織的殘疾與健康指出「超過10億人,約佔世界人口的15%,患有某種形式的殘疾。」、且「1.1億至1.9億成年人有很嚴重的功能性障礙。」。

+
+ +

視覺障礙

+ +

視覺障礙包括盲人、低度視覺、色盲……等等。這類的用戶會使用擴視器(screen magnifier,可能是物理擴視機、或是軟體的縮放功能:當代多數瀏覽器和作業系統都有這種功能),也有些人會用螢幕閱讀器(screen reader,朗讀數位文字的軟體):

+ + + +

熟悉螢幕閱讀器是個好主意;你得設定好螢幕閱讀器、還要會使用它,以理解其工作原理。請參見cross browser testing screen readers guide以深入理解。以下影片提供了簡單的體驗。

+ +

{{EmbedYouTube("IK97XMibEws")}}

+ +

在統計方面,世界衛生組織表明:「全球視力受損人數約2.53億:3600萬人患有盲症,2.17億人有中度至重度視力損害。」(請參見視力損害和盲症)。如果網站編寫不正確,你的網站就會失去如此龐大的和重要的用戶群:這大約是全美國的總人口數。

+ +

聽覺障礙

+ +

聽覺障礙者、或聾人,是指聽力低落、或毫無聽力的群體。聽覺障礙者通常會用輔具(請參見Assistive Devices for People with Hearing, Voice, Speech, or Language Disorders),但沒有給電腦/web使用的專門輔具。

+ +

不過,請記得有專門技術,會針對有聲內容,提供閱讀的替代文字。有簡單的文本記錄(text transcript)、也有能在影片出現的追蹤文字(text track),例如字幕。接下來將有文章深入探討。

+ +

聽覺障礙者也是龐大的人口,世界衛生組織在耳聾和聽力損失指出:「全球有3.6億人患有殘疾性聽力損失」。

+ +

行動障礙

+ +

有運動障礙的人,可能是純粹身體問題(例如: 肢體殘缺或癱瘓)或是四肢無力、失去控制等神經或遺傳疾病。他們可能難以使用滑鼠做出精確的手部動作,甚至可能只能使用頭指針(head pointer)操作電腦。

+ +

這些殘疾也可能是老化的結果,而不是受到創傷或疾病,或可能是硬體的限制——有些使用者可能沒有滑鼠。

+ +

通常影響開發者開發網站的需求是要能使用鍵盤操作網頁——我們會在後續的文內討論使用鍵盤操作網頁。雖然這個需求有些麻煩,但這是一個很好的主意,請開發者嘗試看看。例如:你可以使用 Tab 鍵在表單中切換填寫項目嗎?你可以在我們的跨瀏覽器測試中找到更多關於使用鍵盤控制網頁的相關資訊

+ +

統計數據顯示,許多人有行動障礙。 美國疾病控制和預防中心的殘疾統計數據(涵蓋範圍為非法人的18歲以上成人)顯示,在美國,有身體機能障礙者佔成人人口的 15.1% 。

+ +

認知障礙

+ +

最後一類,可能是最廣泛出現的殘疾——認知障礙。認知障礙廣義可涵蓋從精神疾病到學習困難,包含ADHD(注意缺陷多動障礙)自閉症患者、思覺失調以及許多其他相關疾病。這些與記憶、解決問題能力、理解能力與注意力等問題相關的疾病,都大大影響病患的日常生活。

+ +

這些疾病會影響病患使用網站,而最常見的問題就是他們會在理解如何完成網頁操作、記憶以往完成網頁操作的過程、以及經歷各種不同的操作流程與不一致的佈局/導覽列/其他頁面功能時,增加許許多多的挫敗感。

+ +

與其他網路無障礙問題不同,我們無法快速解決認知障礙引起的網路操作問題;
+ 你唯一能做的就是設計網站時,盡可能符合邏輯性、一致性與可用性,例如:

+ + + +

上述這些並不是「無障礙技術」,但他們是很好的設計理念。他們會讓使用者受益良多,因此他們應該成為你開發網站的工作標準之一。

+ +

康乃爾大學 2014 年的殘疾報告顯示,2014 年美國 21 歲至 64 歲的人中,有 4.5% 的人有認知障礙。

+ +
+

注:WebAIM 的認知頁面提供了更多資訊,值得一讀

+
+ +

專案引入無障礙

+ +

有一個很常見的迷思,就是在專案管理方面,無障礙屬於昂貴的「外加」成本。如果有以下情形的話,這個迷思的確會發生:

+ + + +

如果在專案初期就考慮到無障礙網頁,大多數無障礙內容的成本可以最小化。

+ +

當在規劃專案時,將無障礙測試納入你的測試中,就像測試其他功能一樣(例如:移動裝置 UI 測試)。
+ 及早測試、經常測試,理想情況是運行自動化測試以檢測缺少的功能(例如:圖片缺少替代文字、不好的連結文字 - 請參見 Element relationships and context),並做一些測試,為了讓殘疾人士能夠操作更複雜的網站功能。例如:

+ + + +

你應該記錄自己網站中有問題的地方,並努力讓這些地方變成無障礙或考慮解決方案 / 替代方案,並持續進行測試。文字內容(你可以在下一章看到更多資訊)要做到無障礙很簡單,但是如你想要在網站中放上更多絢麗的 3D 圖形,那應該要怎麼做呢?
+ 你應該評估專案的預算,並考慮有什麼解決方案可以讓這些絢麗的 3D 圖形容易被存取。
+ 例如:你可以支付高額的費用,讓那些多媒體內容轉錄成無障礙設備可存取的資訊,雖然昂貴,卻是可行的方案。

+ +

雖然要實現 100% 無障礙網頁是一種難以達成的理想,世事難料,你總是會遇到一些不常見的問題,導致某個使用者難以使用網頁,但你還是應該盡可能做到無障礙網頁。如果你打算使用WebGL製作的炫麗的 3D 圓餅圖,可以撰寫替代的文字,來傳達圖表的資訊。或者你可以只使用表格來傳達資訊而不使用3D 圓餅圖,這樣每個人都可以一目了然表格傳達的資訊、網頁傳輸編碼更快、CPU使用率更低,並且更容易維護。

+ +

但是如果你是一個有趣的 3D 藝術畫廊網站開發者,那麼期待這些藝術品能夠傳達給視障人士,就不太合理,因為圖畫這類的藝術品本身就是透過視覺作為傳達訊息的媒介。

+ +

為了表明你對無障礙網頁的關心,請在你的網站上發佈無障礙網頁聲明,並詳細說明你為無障礙網頁做了哪些事情、採取了哪些步驟。如果有人抱怨你的網站存在無障礙問題,請他們回報給你們,並嘗試解決。

+ +
+

:我們的 Handling common accessibility problems article 包含了應該進行詳細測試的無障礙網頁規範。

+
+ +

總而言之:

+ + + +

無障礙網頁的指引與法律

+ +

有一些針對無障礙網頁的檢查清單和指引能夠用做測試,它們乍看之下可能令人眼花撩亂。我們建議你只要專注熟悉的基本領域、並理解指引裡面,與你最相關的高層次結構。

+ + + +

因此,儘管 WCAG 有所指引,你的國家可能還是有管理無障礙網頁、或最少針對公眾無障礙服務(可能包含了網站、電視、物理空間……等等)的法案。最好先看看所處地區的法律管轄權。如果不好好檢查內容是否無障礙,當身心障礙者投訴時,你可能會面臨法律問題。

+ +

聽起來很可怕,但只要在開發時,如上所述地把無障礙網頁議題當作高度優先就可以了。如果真的有疑問,請諮詢合格的專業律師。我們不是律師,所以不會提供更深入的意見。

+ +

無障礙網頁 API

+ +

瀏覽器使用特殊的accessibility API(由各自的作業系統底層提供)對輔助技術(AT)提供有用的信息:輔助技術傾向使用語義訊息,因此這種訊息不包含樣式化資訊、或是 JavaScript。這種資訊建構成一個稱為 accessibility tree 的訊息樹(tree of information)。

+ +

不同的作業系統有不同的 accessibility API:

+ + + +

如果由 web app 裡面,HTML 元素提供的原生語意訊息出問題了,你可以把它用做 WAI-ARIA 規範的補充:它會把語意訊息添加到 accessibility tree 以增進無障礙功能。你可以在 WAI-ARIA 基礎文章學習 WAI-ARIA。

+ +

結論

+ +

本文應當使你對無障礙網頁有著概括性的認知、明白其重要性、並在知道如何在工作流程中安排它。你也該對知道如何實做無障礙網頁的細節有興趣。我們將在下個章節開始闡明為什麼 HTML 是無障礙網頁的好基礎。

+ +

{{NextMenu("Learn/Accessibility/HTML", "Learn/Accessibility")}}

+ +

在本模塊

+ + diff --git a/files/zh-tw/learn/common_questions/index.html b/files/zh-tw/learn/common_questions/index.html new file mode 100644 index 0000000000..4aafae4a32 --- /dev/null +++ b/files/zh-tw/learn/common_questions/index.html @@ -0,0 +1,135 @@ +--- +title: Common questions +slug: Learn/Common_questions +tags: + - CodingScripting + - Infrastructure + - Learn + - NeedsTranslation + - TopicStub + - Web + - WebMechanics +translation_of: Learn/Common_questions +--- +
{{LearnSidebar}}
+ +

This section of the Learning Area is designed to provide answers to common questions that may come up, which are not necessarily part of the structured core learning pathways (e.g. the HTML or CSS learning articles.) These articles are designed to work on their own.

+ +

How the Web works

+ +

This section covers web mechanics —questions relating to general knowledge of the Web ecosystem and how it works.

+ +
+
+

How does the Internet work?

+
+
The Internet is the backbone of the Web, the technical infrastructure that makes the Web possible. At its most basic, the Internet is a large network of computers which communicate all together. This article discusses how it works, at a basic level.
+
+

What is the difference between webpage, website, web server, and search engine?

+
+
In this article we describe various web-related concepts: webpages, websites, web servers, and search engines. These terms are often confused by newcomers to the Web, or are incorrectly used. Let's learn what they each mean!
+
+

What is a URL?

+
+
With {{Glossary("Hypertext")}} and {{Glossary("HTTP")}}, URL is one of the key concepts of the Web. It is the mechanism used by {{Glossary("Browser","browsers")}} to retrieve any published resource on the web.
+
+

What is a domain name?

+
+
Domain names are a key part of the Internet infrastructure. They provide a human-readable address for any web server available on the Internet.
+
+

What is a web server?

+
+
The term "Web server" can refer to the hardware or software that serves web sites to clients across the Web — or both of them working together. In this article we go over how web servers work, and why they're important.
+
+ +
+
In this article, we'll go over what hyperlinks are and why they matter.
+
+ +

Tools and setup

+ +

Questions related to the tools/software you can use to build websites.

+ +
+
+

How much does it cost to do something on the Web?

+
+
When you're launching a website, you may spend nothing or your costs may go through the roof. In this article we discuss how much everything costs and what you get for what you pay (or don't pay).
+
+

What software do I need to build a website?

+
+
In this article we explain which software components you need when you're editing, uploading, or viewing a website.
+
+

What text editors are available?

+
+
In this article we highlight some things to think about when choosing and installing a text editor for web development.
+
+

What are browser developer tools?

+
+
Every browser features a set of devtools for debugging HTML, CSS, and other web code. This article explains how to use the basic functions of your browser's devtools.
+
+

How do you make sure your website works properly?

+
+
So you've published your website online — very good! But are you sure it works properly? This article provides some basic troubleshooting steps.
+
+

How do you set up a local testing server?

+
+
+
+

This article explains how to set up a simple local testing server on your machine, and the basics of how to use it.

+
+
+
+

How do you upload files to a web server?

+
+
This article shows how to publish your site online with FTP tools — one of the most common ways to get a website online so others can access it from their computers.
+
+

How do I use GitHub Pages?

+
+
This article provides a basic guide to publishing content using GitHub's gh-pages feature.
+
+

How do you host your website on Google App Engine?

+
+
Looking for a place to host your website? Here's a step-by-step guide to hosting your website on Google App Engine.
+
+

What tools are available to debug and improve website performance?

+
+
This set of articles shows you how to use the Developer Tools in Firefox to debug and improve performance of your website, using the tools to check the memory usage, the JavaScript call tree, the amount of DOM nodes being rendered, and more.
+
+ +

Design and accessibility

+ +

This section lists questions related to aesthetics, page structure, accessibility techniques, etc.

+ +
+
+

How do I start to design my website?

+
+
This article covers the all-important first step of every project: define what you want to accomplish with it.
+
+

What do common web layouts contain?

+
+
When designing pages for your website, it's good to have an idea of the most common layouts. This article runs thorugh some typical web layouts, looking at the parts that make up each one.
+
+

What is accessibility?

+
+
This article introduces the basic concepts behind web accessibility.
+
+

How can we design for all types of users?

+
+
This article provides basic techniques to help you design websites for any kind of user — quick accessibility wins, and other such things.
+
+

What HTML features promote accessibility?

+
+
This article describes specific features of HTML that can be used to make a web page more accessible to people with different disabilities.
+
+ +

HTML, CSS and JavaScript questions

+ +

For common solutions to HTML/CSS/JavaScript problems, try the following articles:

+ + diff --git a/files/zh-tw/learn/common_questions/what_is_a_web_server/index.html b/files/zh-tw/learn/common_questions/what_is_a_web_server/index.html new file mode 100644 index 0000000000..d8bb301ab1 --- /dev/null +++ b/files/zh-tw/learn/common_questions/what_is_a_web_server/index.html @@ -0,0 +1,116 @@ +--- +title: 何謂網路伺服器? +slug: Learn/Common_questions/What_is_a_web_server +translation_of: Learn/Common_questions/What_is_a_web_server +--- +
+

本文章將講解網路伺服器是什麼、如何運作、還有他們的重要性。

+
+ + + + + + + + + + + + +
要求:你要知道 Internet 是怎麼運作的、並知道網頁、網站、網路伺服器的不同
目標:你將知道網路伺服器是什麼、並大致了解它的運作原理。
+ +

概要

+ +

「網路伺服器」(web server)可以指軟體、也可以指硬體、還可以指它們共同運作的狀態。

+ +
    +
  1. 以硬體來說,web server 是存放網路伺服器軟體、還有網站檔案(如 HTML 文件、圖片、CSS 樣式表、JavaScript 檔案)的電腦。它會連上網際網路(Internet)並能和其他連上網的設備做物理數據交換。
  2. +
  3. 以軟體來說,web server 包含了一連串控制網路用戶如何訪問託管檔案──至少有 HTTP 伺服器──的檔案。HTTP 伺服器是其中一個部份,它理解 {{Glossary("URL","URLs")}}(網路地址)與 {{Glossary("HTTP")}}(瀏覽器用來觀察網頁的協議)。它能透過域名(domain name)訪問託管的網站(如 mozilla.org)、並將其內容遞送到終端用戶(end-user)的設備上。
  4. +
+ +

以最基本的層面來說,如果瀏覽器需要網路伺服器所託管的檔案,它就需要透過 HTTP 發送對該檔案的請求。如果請求已經傳送到正確的(硬體)網路伺服器,那 HTTP(軟體)伺服器就會接受請求、找出所請求的文件(假若不是接著回傳 404 頁面)、再透過 HTTP 回傳給瀏覽器。

+ +

Basic representation of a client/server connection through HTTP

+ +

要發布網站,你需要一個靜態或動態的網路伺服器。

+ +

靜態網路伺服器(static web server)、或是 stack,由(硬體的)電腦和(軟體的) HTTP 伺服器組成。之所以稱為「靜態」是因為伺服器只會給你的瀏覽器,傳送「事先寫好的」(as-is)檔案。

+ +

動態網路伺服器(dynamic web server)除了靜態網路伺服器以外、還附加了一些軟體:通常是應用伺服器(application server)與資料庫(database)之所以稱為「動態」是因為:應用伺服器會在託管檔案,透過 HTTP 伺服器傳送到瀏覽器之前更新之。

+ +

例如說,要生成瀏覽器看到的最終網頁,應用伺服器會使用從資料庫讀取資料的 HTML 模板(HTML template)填補之。像 MDN 或維基百科(Wikipedia)這樣的網站也有上千個網頁:但它們全都不是「真的」HTML 文件,而是少數的 HTML 模板、還有龐大的資料庫。如此一來,要維護並傳送資料、都會變得很容易。

+ +

主動學習

+ +

目前還沒有好用的內容。請考慮貢獻一下

+ +

深入一點……

+ +

如同我們講過的:要取得網頁,瀏覽器會向伺服器發送一個在伺服器內,尋找某個檔案的請求。如果伺服器找到了檔案,就會讀取它、按需求處理、並回傳檔案。讓我們逐步檢視它們。

+ +

託管檔案

+ +

首先,網路伺服器要儲存網站檔案,也就是所有 HTML 文件、和附屬的 asset:asset 包含了圖片、CSS 樣式表、JavaScript 檔案、字型檔、還有影片。

+ +

技術上來說,你可以把它們都放在自己的電腦裡面,但放在網路伺服器上面會方便許多,理由是伺服器:

+ + + +

因此,找到優秀的託管提供者,是建立網站的重點之一。好好探索各大公司提供的服務、並選擇一個符合需求、預算也能負擔的方案(服務的價格從免費到上千美元都有)。你可以在這篇文章找到更多資訊。

+ +

一旦找到適合的網絡託管解決方案,你只要把文件上傳到網路伺服器就行了。

+ +

透過 HTTP 溝通

+ +

接下來,網路伺服器會支援 {{Glossary("HTTP")}}(Hypertext Transfer Protocol,超文本傳輸協議)。顧名思義,HTTP 會指定兩台電腦之間,該如何傳送超文本(例如 linked web document)。

+ +

協議({{Glossary("Protocol")}})是一套兩台電腦間該如何溝通的規則。HTTP 是文本性、無狀態的協議。

+ +
+
文本性(Textual)
+
所有指令都是純文字、人類也容易理解。
+
無狀態(Stateless)
+
無論伺服器還是瀏覽器,都不會記得他們上一次的溝通。像是伺服器,如果只依賴 HTTP 的話,它就不會記得你輸入的帳號密碼、或是在交易中採取了哪些步驟。要完成這樣的任務,你需要應用伺服器(我們將在其他文章中介紹這種技術)。
+
+ +

HTTP 提供了用戶端與伺服器端,該如何溝通的明確規則。我們將在之後的技術文章內講解 HTTP 本身。目前,我們會先聚焦在:

+ + + +

MDN 404 錯誤頁面範例 在網路伺服器裡面,HTTP 伺服器負責處理和回答傳入的請求。

+ +
    +
  1. HTTP 伺服器接收請求後,會先檢查請求的 URL 是否匹配現有文件。
  2. +
  3. 如果匹配,網路伺服器會把檔案內容回傳給瀏覽器。不然,應用伺服器會建立需要的檔案。
  4. +
  5. 如果都沒有用的話,網路伺服器會回傳錯誤訊息給瀏覽器,最常見的就是「404 Not Found」。(這個錯誤很常見,所以許多網頁設計師花了相當多的心力設計 404 錯誤頁面。)
  6. +
+ +

靜態與動態內容

+ +

大略上來說,伺服器能儲存動態與靜態的內容。「靜態」是指「提供事先寫好的」。靜態網站設定上最簡單,所以我們建議選擇靜態內容,作為你的第一個網站。

+ +

「動態」指的是伺服器處理內容、甚至從資料庫即時產生。這個解決方案提供了更多靈活性,但技術會變得難以駕馭、令網站明顯複雜許多。

+ +

以你目前閱讀的頁面為例。在託管的伺服器裡面,有個應用伺服器會從資料庫取得內容、規範化、再把它塞進某些 HTML 模板裡面。這裡的應用伺服器,是以 Python 語言的 Django 框架為基礎,所組建的 Kuma。Mozilla 團隊基於 MDN 的特殊需求開發了 Kuma,不過也有很多相似、但使用其他技術的應用程式。

+ +

從海量的應用伺服器裡面選一個推薦,是個大難題。有些應用程式會迎合特定的類別,如部落格、百科、電子商務。其他還有更通用的 {{Glossary("CMS")}}(content management systems,內容管理系統)。如果要建立動態網站,花點時間找個符合需求的工具。除非想學習伺服器端程式設計(也是個扣人心弦的領域!),否則不用建立屬於自己的應用伺服器。那樣只是在{{Interwiki("wikipedia", "重造輪子")}}。

+ +

下一步

+ +

熟悉了伺服器以後可以:

+ + diff --git a/files/zh-tw/learn/css/css_layout/index.html b/files/zh-tw/learn/css/css_layout/index.html new file mode 100644 index 0000000000..385121536f --- /dev/null +++ b/files/zh-tw/learn/css/css_layout/index.html @@ -0,0 +1,71 @@ +--- +title: CSS 排版 +slug: Learn/CSS/CSS_layout +tags: + - CSS + - 佈局 + - 多欄 + - 彈性盒子 + - 排版 + - 新手 + - 浮動 + - 網格 +translation_of: Learn/CSS/CSS_layout +--- +
{{draft}}
+ +
{{LearnSidebar}}
+ +

基於我們已經看過了 CSS 基本原理:如何將文字賦予樣式、如何該便樣式或操作你的文字內容所處的 box 模型。現在是時候看看如何將你的 box 模型在視圖中放置於相對應的正確位置。我們已經涵蓋了必要的先備知識,接下來我們可以深入CSS 排版,看一些不同的顯示方式,如現代的排版方式——彈性盒子、CSS 網格及定位,當然還有一些舊式的技術你可能會想要理解。

+ +

先備知識

+ +

開始這個單元之前,需要做如下準備:

+ +
    +
  1. 對 HTML 有基本的認知,如  HTML 簡介 單元中所述。
  2. +
  3. 熟悉 CSS 基本原理,如 CSS 簡介中所述。
  4. +
  5. 了解如何 樣式框
  6. +
+ +
+

: 如果你正在使用的電腦/平板/其他設備讓你無法建立自己的文件,你可以透過線上工具如 JSBin 或 Thimble 編輯並嘗試(大部分的)範例程式碼。

+
+ +

指導

+ +

這些文章旨在提供關於 CSS 中可用的技術以及基本排版工具和技術的指導。在課程的結尾有一個評估測驗——配置一個網頁的版面,這可以幫助你了解你對 CSS 排版方式的理解程度。

+ +
+
CSS 排版介紹
+
這篇文章將回顧一些之前單元中提過的 CSS 排版特性,像是不同的{{cssxref("display")}} 參數,藉由這個單元我們將介紹一些基本概念。
+
常規流
+
在我們做任何事之前,網頁上的元素會根據常規流自行排列。這篇文章解釋常規流的基礎知識,用來學習如何改變它。
+
彈性盒子
+
彈性盒子是一維空間的排版方式,用來讓項目以行或列的方式排列。項目會延展或限縮來符合較大或較小的空間。這篇文章會解釋基礎原理。
+
網格
+
CSS 網格排版是一個二維空間的網頁排版系統。它讓你將內容排入行與列中,且它有許多功能讓你在建立複雜的排版時變得簡單明瞭。這篇文章會告訴你全部。
+
浮動
+
最初是為了在文字區塊中浮動排列圖片,而後為了在網頁中建造多攔排版{{cssxref("float")}} 屬性成為了最常用的工具之一。這篇文章會解釋如何使用。
+
定位
+
定位准許將元素從正常的文檔流中脫離出來,讓他們表現不同,例如設置在另一個模塊的上方,或使模塊在瀏覽器視窗內部始終停留在相同的地方。這篇文章將解釋不同的{{cssxref("position")}} 值和如何使用它們。
+
多欄排版
+
多欄排版規格提供你將內容排進欄位的排版方式,像你可能在報紙上看到的那樣。這篇文章會解釋如何使用這個功能。
+
舊式排版方式
+
網格系統是另一個在 CSS 排版中非常常用的特性,在網格排版出現之前,它通常使用浮動或其他佈局來實現。想像你的佈局為一組列數(如 4, 6, 或 12),然後將你的內容放置在這些虛構的列中。在這篇文章中我們將隨著創建網格系統、看看使用網格框架提供現成的網格框架和體驗 CSS 網格來結束-一個新興的瀏覽器特性使得在 Web 實現網格設計變得大為容易等來探索這些基本的想法。
+
支援舊版瀏覽器
+
+

在這個單元,我們建議你使用彈性盒子和網格作為主要的設計方式。但是有些造訪你網站的人會使用舊版瀏覽器,或者他使用的瀏覽器不支援你的設計方式。以下情形在網路上一定會發生——當新功能開發出來了,不同的瀏覽器會有不同的支援優先級。這篇文章會解釋如何使用現代網頁技術且不遺漏舊技術的使用者。

+
+
基礎排版理解測驗
+
配置網頁版面,這是一個測試你對於不同排版方式理解程度的測驗。
+
+ +

參見 

+ +
+
實際的定位排版範例
+
這篇文章會告訴你如何建立一些真實的範例來說明什麼樣的情況你可以使用定位排版。
+
+ +

 

diff --git a/files/zh-tw/learn/css/first_steps/getting_started/index.html b/files/zh-tw/learn/css/first_steps/getting_started/index.html new file mode 100644 index 0000000000..aed101592c --- /dev/null +++ b/files/zh-tw/learn/css/first_steps/getting_started/index.html @@ -0,0 +1,265 @@ +--- +title: CSS 入門 +slug: Learn/CSS/First_steps/Getting_started +tags: + - CSS + - 元素 + - 初學者 + - 學習 + - 狀態 + - 範例 + - 語法 + - 課程 + - 選擇器 +translation_of: Learn/CSS/First_steps/Getting_started +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/CSS/First_steps/What_is_CSS", "Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps")}}
+ +

在這個主題中,我們將 CSS 套用到一個簡單的 HTML 文件上,在過程中學習這個語言一些實際的東西。

+ + + + + + + + + + + + +
先備知識:基本的電腦概念、能夠安裝基本軟體,基本與各種檔案打交道的能力,以及 HTML 的基礎(由HTML 入門學到)。
學習目標:了解將 CSS 文件與 HTML 檔案連接的基本知識,並且能夠使用 CSS 對文字作簡單的格式變化。
+ +

由某個 HTML 開始

+ +

我們的起點是一個 HTML 文件。如果您想要在自己的電腦上操作,可以把下面的程式碼複製下來。在您電腦上的目錄中,用 index.html 為檔名儲存

+ +

+ +
<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>Getting started with CSS</title>
+</head>
+
+<body>
+
+    <h1>I am a level one heading</h1>
+
+    <p>This is a paragraph of text. In the text is a <span>span element</span>
+and also a <a href="http://example.com">link</a>.</p>
+
+    <p>This is the second paragraph. It contains an <em>emphasized</em> element.</p>
+
+    <ul>
+        <li>Item one</li>
+        <li>Item two</li>
+        <li>Item <em>three</em></li>
+    </ul>
+
+</body>
+
+</html>
+ +
+

注意:如果您用來閱讀這篇文章的環境沒辦法簡單地建立檔案,也別擔心。底下會提供線上程式編輯器讓你就在這個頁面中撰寫範例程式。

+
+ +

為我們的文件加入CSS

+ +

首先,告訴HTML文件我們有些CSS規則要加入是第一個步驟。你可能會碰到三種不同的方式可以將CSS檔案應用進HTML文件之中,不過我們現在先將焦點放在最常見且最實用的方式:將CSS從文件的前頭連接進去。

+ +

先建立一個檔案,將它存在與你HTML文件同一個目錄之中並命名為styles.css 。.css 外掛會辨識它為一個CSS檔案。

+ +

To link styles.css to index.html add the following line somewhere inside the {{htmlelement("head")}} of the HTML document:

+ +
<link rel="stylesheet" href="styles.css">
+ +

This {{htmlelement("link")}} element tells the browser that we have a stylesheet, using the rel attribute, and the location of that stylesheet as the value of the href attribute. You can test that the CSS works by adding a rule to styles.css. Using your code editor add the following to your CSS file:

+ +
h1 {
+  color: red;
+}
+ +

Save your HTML and CSS files and reload the page in a web browser. The level one heading at the top of the document should now be red. If that happens, congratulations — you have successfully applied some CSS to an HTML document. If that doesn't happen, carefully check that you've typed everything correctly.

+ +

You can continue to work in styles.css locally, or you can use our interactive editor below to continue with this tutorial. The interactive editor acts as if the CSS in the first panel is linked to the HTML document, just as we have with our document above.

+ +

Styling HTML elements

+ +

By making our heading red we have already demonstrated that we can target and style an HTML element. We do this by targeting an element selector — this is a selector that directly matches an HTML element name. To target all paragraphs in the document you would use the selector p. To turn all paragraphs green you would use:

+ +
p {
+  color: green;
+}
+ +

You can target multiple selectors at once, by separating the selectors with a comma. If I want all paragraphs and all list items to be green my rule looks like this:

+ +
p, li {
+    color: green;
+}
+ +

Try this out in the interactive editor below (edit the code boxes), or in your local CSS document.

+ +

{{EmbedGHLiveSample("css-examples/learn/getting-started/started1.html", '100%', 900)}} 

+ +

Changing the default behavior of elements

+ +

When we look at a well-marked up HTML document, even something as simple as our example, we can see how the browser is making the HTML readable by adding some default styling. Headings are large and bold and our list has bullets. This happens because browsers have internal stylesheets containing default styles, which they apply to all pages by default; without them all of the text would run together in a clump and we would have to style everything from scratch. All modern browsers display HTML content by default in pretty much the same way.

+ +

However, you will often want something other than the choice the browser has made. This can be done by simply choosing the HTML element that you want to change, and using a CSS rule to change the way it looks.  A good example is our <ul>, an unordered list. It has list bullets, and if I decide I don't want those bullets I can remove them like so:

+ +
li {
+  list-style-type: none;
+}
+ +

Try adding this to your CSS now.

+ +

The list-style-type property is a good property to look at on MDN to see which values are supported. Take a look at the page for list-style-type and you will find an interactive example at the top of the page to try some different values in, then all allowable values are detailed further down the page.

+ +

Looking at that page you will discover that in addition to removing the list bullets you can change them — try changing them to square bullets by using a value of square.

+ +

Adding a class

+ +

So far we have styled elements based on their HTML element names. This works as long as you want all of the elements of that type in your document to look the same. Most of the time that isn't the case and so you will need to find a way to select a subset of the elements without changing the others. The most common way to do this is to add a class to your HTML element and target that class.

+ +

In your HTML document, add a class attribute to the second list item. Your list will now look like this:

+ +
<ul>
+  <li>Item one</li>
+  <li class="special">Item two</li>
+  <li>Item <em>three</em></li>
+</ul>
+ +

In your CSS you can target the class of special by creating a selector that starts with a full stop character. Add the following to your CSS file:

+ +
.special {
+  color: orange;
+  font-weight: bold;
+}
+ +

Save and refresh to see what the result is.

+ +

You can apply the class of special to any element on your page that you want to have the same look as this list item. For example, you might want the <span> in the paragraph to also be orange and bold. Try adding a class of special to it, then reload your page and see what happens.

+ +

Sometimes you will see rules with a selector that lists the HTML element selector along with the class:

+ +
li.special {
+  color: orange;
+  font-weight: bold;
+}
+ +

This syntax means "target any li element that has a class of special". If you were to do this then you would no longer be able to apply the class to a <span> or another element by simply adding the class to it; you would have to add that element to the list of selectors:

+ +
li.special,
+span.special {
+  color: orange;
+  font-weight: bold;
+}
+ +

As you can imagine, some classes might be applied to many elements and you don't want to have to keep editing your CSS every time something new needs to take on that style. Therefore it is sometimes best to bypass the element and simply refer to the class, unless you know that you want to create some special rules for one element alone, and perhaps want to make sure they are not applied to other things.

+ +

Styling things based on their location in a document

+ +

There are times when you will want something to look different based on where it is in the document. There are a number of selectors that can help you here, but for now we will look at just a couple. In our document are two <em> elements — one inside a paragraph and the other inside a list item. To select only an <em> that is nested inside an <li> element I can use a selector called the descendant combinator, which simply takes the form of a space between two other selectors.

+ +

Add the following rule to your stylesheet.

+ +
li em {
+  color: rebeccapurple;
+}
+ +

This selector will select any <em> element that is inside (a descendant of) an <li>. So in your example document, you should find that the <em> in the third list item is now purple, but the one inside the paragraph is unchanged.

+ +

Something else you might like to try is styling a paragraph when it comes directly after a heading at the same hierarchy level in the HTML. To do so place a +  (an adjacent sibling combinator) between the selectors.

+ +

Try adding this rule to your stylesheet as well:

+ +
h1 + p {
+  font-size: 200%;
+}
+ +

The live example below includes the two rules above. Try adding a rule to make a span red, if it is inside a paragraph. You will know if you have it right as the span in the first paragraph will be red, but the one in the first list item will not change color.

+ +

{{EmbedGHLiveSample("css-examples/learn/getting-started/started2.html", '100%', 1100)}}

+ +
+

Note: As you can see, CSS gives us several ways to target elements, and we've only scratched the surface so far! We will be taking a proper look at all of these selectors and many more in our Selectors articles later on in the course.

+
+ +

Styling things based on state

+ +

The final type of styling we shall take a look at in this tutorial is the ability to style things based on their state. A straightforward example of this is when styling links. When we style a link we need to target the <a> (anchor) element. This has different states depending on whether it is unvisited, visited, being hovered over, focused via the keyboard, or in the process of being clicked (activated). You can use CSS to target these different states — the CSS below styles unvisited links pink and visited links green.

+ +
a:link {
+  color: pink;
+}
+
+a:visited {
+  color: green;
+}
+ +

You can change the way the link looks when the user hovers over it, for example removing the underline, which is achieved by in the next rule:

+ +
a:hover {
+  text-decoration: none;
+}
+ +

In the live example below, you can play with different values for the various states of a link. I have added the rules above to it, and now realise that the pink color is quite light and hard to read — why not change that to a better color? Can you make the links bold?

+ +

{{EmbedGHLiveSample("css-examples/learn/getting-started/started3.html", '100%', 900)}} 

+ +

We have removed the underline on our link on hover. You could remove the underline from all states of a link. It is worth remembering however that in a real site, you want to ensure that visitors know that a link is a link. Leaving the underline in place, can be an important clue for people to realize that some text inside a paragraph can be clicked on — this is the behavior they are used to. As with everything in CSS, there is the potential to make the document less accessible with your changes — we will aim to highlight potential pitfalls in appropriate places.

+ +
+

Note: you will often see mention of accessibility in these lessons and across MDN. When we talk about accessibility we are referring to the requirement for our webpages to be understandable and usable by everyone.

+ +

Your visitor may well be on a computer with a mouse or trackpad, or a phone with a touchscreen. Or they might be using a screenreader, which reads out the content of the document, or they may need to use much larger text, or be navigating the site using the keyboard only.

+ +

A plain HTML document is generally accessible to everyone — as you start to style that document it is important that you don't make it less accessible.

+
+ +

Combining selectors and combinators

+ +

It is worth noting that you can combine multiple selectors and combinators together. For example:

+ +
/* selects any <span> that is inside a <p>, which is inside an <article>  */
+article p span { ... }
+
+/* selects any <p> that comes directly after a <ul>, which comes directly after an <h1>  */
+h1 + ul + p { ... }
+ +

You can combine multiple types together, too. Try adding the following into your code:

+ +
body h1 + p .special {
+  color: yellow;
+  background-color: black;
+  padding: 5px;
+}
+ +

This will style any element with a class of special, which is inside a <p>, which comes just after an <h1>, which is inside a <body>. Phew!

+ +

In the original HTML we provided, the only element styled is <span class="special">.

+ +

Don't worry if this seems complicated at the moment — you'll soon start to get the hang of it as you write more CSS.

+ +

Wrapping up

+ +

In this tutorial, we have taken a look at a number of ways in which you can style a document using CSS. We will be developing this knowledge as we move through the rest of the lessons. However you now already know enough to style text, apply CSS based on different ways of targeting elements in the document, and look up properties and values in the MDN documentation.

+ +

In the next lesson we will be taking a look at how CSS is structured.

+ +

{{PreviousMenuNext("Learn/CSS/First_steps/What_is_CSS", "Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps")}}

+ +

In this module

+ +
    +
  1. What is CSS?
  2. +
  3. Getting started with CSS
  4. +
  5. How CSS is structured
  6. +
  7. How CSS works
  8. +
  9. Using your new knowledge
  10. +
diff --git a/files/zh-tw/learn/css/first_steps/how_css_works/index.html b/files/zh-tw/learn/css/first_steps/how_css_works/index.html new file mode 100644 index 0000000000..eebac03f5c --- /dev/null +++ b/files/zh-tw/learn/css/first_steps/how_css_works/index.html @@ -0,0 +1,156 @@ +--- +title: How CSS works +slug: Learn/CSS/First_steps/How_CSS_works +translation_of: Learn/CSS/First_steps/How_CSS_works +--- +

{{LearnSidebar}}
+ {{PreviousMenuNext("Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps/Using_your_new_knowledge", "Learn/CSS/First_steps")}}

+ +

我們已經學會基本 CSS 的用途與用法了,這堂課我們就來看看瀏覽器是如何將 CSS 和 HTML 變化成網頁的吧。

+ + + + + + + + + + + + +
需求:基本電腦操作、已安裝基本的軟體檔案處理的基本知識、HTML 基礎 (請參閱 HTML 入門)。
目標:了解瀏覽器如何解析 CSS 和 HTML ,以及當瀏覽器遇到不認識的 CSS 時會發生什麼事。
+ +

CSS 實際上是怎麼運作的?

+ +

每當瀏覽器要顯示一份文件時,它得先為文件內容穿上樣式,這會歷經許多程序,我們已經列在下方了。記得喔,這只是非常簡化的版本,不同的瀏覽器會有自己的做法,不過原則上就是這樣。

+ +
    +
  1. 瀏覽器載入 HTML (比如從網路上接收(receive))。
  2. +
  3. 它將 {{Glossary("HTML")}} 轉換成 {{Glossary("DOM")}} (Document Object Model,文件物件模型),這東西是文件在電腦記憶體中的表示形式,詳情我們下個小節再說。
  4. +
  5. 瀏覽器蒐集所有 HTML 文件連到的資源,像是嵌入網頁的圖片和影片等等,當然,裡面也包含 CSS!JavaScript 也是其中的一種資源,在此步驟的稍後就會處理,但我們先不要把事情弄得這麼複雜,這邊暫且不講。
  6. +
  7. 瀏覽器解析 (parse) CSS,先按照選擇器的類型(如元素、類別、ID 等等),將規則放入相對應的「桶子(buckets)」裡。接著再依找到的選擇器,推算哪些規則應該要套用在哪些 DOM 節點上,並將樣式附著上去,最後產生的東西叫做轉譯樹(render tree)。
  8. +
  9. 當規則都套用完畢後,開始按照網頁結構布局(layout)轉譯樹。
  10. +
  11. 網頁被呈現在螢幕上,這個步驟稱為繪製(painting)。
  12. +
+ +

下面是此流程的示意圖。

+ +

+ +

關於 DOM

+ +

DOM 有著一個樹狀結構,每個標記語言中的元素、屬性,以及文字片段都會是這個樹狀結構裡的{{Glossary("Node/DOM","節點")}}。每個節點與其他節點間的關係都有定義:若節點有子節點(child),則自己是他們的父節點(parent);若子節點為複數,則這些子節點稱彼此為兄弟/姊妹節點(sibling)。

+ +

了解 DOM 對於設計、除錯以及維護 CSS 有相當大的助益,因為 DOM 正是 CSS 與文件內容的交會之處。當你要利用瀏覽器的開發者工具(DevTools)來查看元素套用的規則時,你就會見到它們。

+ +

一個活生生的 DOM 例子

+ +

我們就別絮絮叨叨了,直接看個簡單的例子,來瞭解 HTML 片段是如何轉換成 DOM 的吧。

+ +

以下列 HTML 原始碼為例:

+ +
<p>
+  Let's use:
+  <span>Cascading</span>
+  <span>Style</span>
+  <span>Sheets</span>
+</p>
+
+ +

在 DOM 中,<p> 元素對應到的節點是一個父節點,它的子節點有一個純文字節點以及三個 <span> 元素節點,而 SPAN 節點也是有著純文字子節點的父節點:

+ +
P
+├─ "Let's use:"
+├─ SPAN
+|  └─ "Cascading"
+├─ SPAN
+|  └─ "Style"
+└─ SPAN
+   └─ "Sheets"
+
+ +

這就是瀏覽器如何解析上段的 HTML 片段的 — 它轉譯了以上的 DOM 樹,並產生了以下的輸出:

+ +

{{EmbedLiveSample('一個活生生的_DOM_例子', '100%', 55)}}

+ + + +

將 CSS 套用至 DOM

+ +

讓我們在上例中加入一些 CSS 來增添樣式。同樣地,HTML 如下:

+ +
<p>
+  Let's use:
+  <span>Cascading</span>
+  <span>Style</span>
+  <span>Sheets</span>
+</p>
+ +

假設我們把以下 CSS 套用上去:

+ +
span {
+  border: 1px solid black;
+  background-color: lime;
+}
+ +

瀏覽器會先解析 HTML 並產生 DOM 樹,然後再解析 CSS。因為這個 CSS 中只有使用 span 選擇器,所以瀏覽器可以很快地完成分類!接著它會將這個規則套用到每一個 <span> 上,並在螢幕上繪製出最終的畫面。

+ +

現在輸出變成這樣:

+ +

{{EmbedLiveSample('將_CSS_套用至_DOM', '100%', 55)}}

+ +

在下個主題裡的為 CSS 除錯中我們將會使用瀏覽器的 DevTools 來為 CSS 除錯,屆時我們將會學到更多瀏覽器解析 CSS 的方法。

+ +

瀏覽器遇到不認識的 CSS 時會發生什麼事?

+ +

在先前的課程中,我們曾提過瀏覽器並不會一次實作全部的新 CSS。此外,很多人都不是使用最新版的瀏覽器。要知道 CSS 是與時俱進的,會超出瀏覽器可辨認的範圍是很正常的事,所以啦,你可能會很好奇,當瀏覽器遇到它看不懂的 CSS 選擇器或宣告時會發生什麼事呢?

+ +

答案就是裝作沒看到,繼續往下解析其它的CSS!

+ +

如果瀏覽器在解析規則時,遇到它不認識的屬性或值,它會忽略它,並繼續解析下一個宣告。因此當它這麼做的時候,如果不是你拼錯字了,那就是那個屬性或值太新奇了,所以你的瀏覽器還沒有支援它。

+ +

同樣地,如果瀏覽器遇到一個它不認識的選擇器時,它會忽略整條規則,並繼續解析其他規則。

+ +

下面的例子使用英式英語來拼寫 color (也就是 colour),進而導致該屬性失效,因為現在瀏覽器看不懂它了。也因此下面的段落無法以藍字顯示,不過其他的 CSS 還是成功地套用上去了,只有無效的會被忽略掉。

+ +
+
<p> I want this text to be large, bold and blue.</p>
+ +
p {
+  font-weight: bold;
+  colour: blue; /* incorrect spelling of the color property */
+  font-size: 200%;
+}
+
+ +

{{EmbedLiveSample('Skipping_example', '100%', 200)}}

+ +

這樣做有個很大的好處,就是你可以放心地利用新 CSS 做出很炫炮的效果,而不用擔心瀏覽器不支援時會出錯 — 反正差別只在於那個新特性有或沒有而已。再加上 CSS 層疊 (cascade) 的天性,只要你提供兩條具有相同具體程度(specificity)的規則,就能讓不支援的瀏覽器套用另一條規則。

+ +

這在想要使用某個剛推出的值,但它還未普及時非常有用。舉個例子,一些老舊的瀏覽器不支援以 calc() 來當作值,所以當我想要用它來決定寬的時候,可能會先寫一個備用的寬(以像素為單位的值),然後再寫一個值為 calc(100% - 50px) 的寬。這樣一來,老舊的瀏覽器會使用像素版本 ,並忽略 calc() 版本,因為它們看不懂這個;而新的瀏覽器則會先解析像素版本,然後再將 calc() 版本覆寫上去,因為它比較晚出現。

+ +
.box {
+  width: 500px;
+  width: calc(100% - 50px);
+}
+ +

我們在之後的課程中還會學到更多支援不同瀏覽器的方法。

+ +

最後

+ +

你已經快完成這個主題了,但是還差臨門一腳,在下篇文章裡,你將會利用你學到的新知識來重新美化一個範例,並在過程中重溫你所學到的 CSS 技巧。

+ +

{{PreviousMenuNext("Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps/Using_your_new_knowledge", "Learn/CSS/First_steps")}}

+ +

在這個主題中

+ +
    +
  1. CSS 是什麼?
  2. +
  3. CSS 入門
  4. +
  5. CSS 是如何組織的
  6. +
  7. CSS 是如何運作的
  8. +
  9. 利用你學到的新知識
  10. +
diff --git a/files/zh-tw/learn/css/first_steps/index.html b/files/zh-tw/learn/css/first_steps/index.html new file mode 100644 index 0000000000..ee9dc82a1d --- /dev/null +++ b/files/zh-tw/learn/css/first_steps/index.html @@ -0,0 +1,59 @@ +--- +title: 初探 CSS +slug: Learn/CSS/First_steps +tags: + - CSS + - 入門 + - 單元 + - 學習 + - 新手 + - 新手教學 +translation_of: Learn/CSS/First_steps +--- +
{{LearnSidebar}}
+ +

CSS(階層式樣式表)被用來設定網頁的樣式及佈局。舉例來說,改變字體、顏色、尺寸以及擺放您的內容、拆分為多欄,或是添加動畫效果和其它裝飾的特性。這個單元提供一個平緩的學習路徑,透過介紹 CSS 的工作原理、語法的樣式,以及如何在 HTML 中添加樣式設定。

+ +

想要成為網頁前端開發員?

+ +

我們整理了一門課程,包含了您實現目標所需要的所有基本知識。

+ +

開始

+ +

先備知識

+ +

開始這個單元之前,您應該具備:

+ +
    +
  1. 基本熟悉電腦的操作,以及網路的使用(即:在網路查資料,看看內容)。
  2. +
  3. 設定好一個基本的工作環境(參考安裝基本軟體單元),並知道如何建立以及管檔案(參考檔案的管理單元)。
  4. +
  5. 對 HTML 有基本的認識,像是 HTML 介紹單元裡所提到的。 
  6. +
+ +
+

注意:如果您使用的電腦/平板/或其它裝置上,無法建立您所需要的檔案。您可以在像是 JSBin 或 Glitch 的線上程式編輯平台上嘗試(絕大部分的)範例程式。

+
+ +

導覽

+ +

這個單元包含以下的主題,會帶你瀏覽所有 CSS 的基本理論,並提供您一些測試技巧的機會:

+ +
+
CSS 是什麼?
+
{{Glossary("CSS")}} (階層式樣式表)讓您能夠建立好看的網頁,但是它骨子是是怎麼運作的?這個主題用一個簡單的語法範例來解釋 CSS 是什麼,並涵蓋有關這個語言的一些關鍵術語。
+
CSS 入門
+
這個主題中,我們將把 CSS 套用到一個簡單的 HTML 文件上,逐步學習有關這個語言的一些實用知識。
+
CSS 的結構
+
現在您對 CSS 是什麼以及基本使用方法有了一些概念,是時候去更深入看看這個語言的結構了。我們在這裡討論了許多的觀念;如果之後您對任何概念感到模糊,可以到這裡來回顧。
+
CSS 的運作方式
+
我們已經學到了什麼是 CSS 以及如何寫一個簡單樣式表的基礎概念。我們會在這堂課裡看看瀏覽器是如何依據 CSS 和 HTML 的內容轉化為網頁的呈現。
+
使用您的新知識
+
透過你在前面堂課所學到的東西,你應該會發現您可以對簡單的文字內套用 CSS 設定,加入您想要的樣式。這個主題給您一個機會來做這件事。
+
+ +

參見

+ +
+
Intermediate Web Literacy 1: Intro to CSS
+
一個很好的 Mozilla 基礎課程,探討及測試許多 CSS 技巧。了解關於在網頁上設定 HTML 元素樣式、 CSS 選擇器、屬性、數值。
+
diff --git a/files/zh-tw/learn/css/first_steps/what_is_css/index.html b/files/zh-tw/learn/css/first_steps/what_is_css/index.html new file mode 100644 index 0000000000..3eb04bcbe1 --- /dev/null +++ b/files/zh-tw/learn/css/first_steps/what_is_css/index.html @@ -0,0 +1,131 @@ +--- +title: CSS 是什麼? +slug: Learn/CSS/First_steps/What_is_CSS +tags: + - CSS + - CSS 入門 + - 初學者 + - 單元 + - 學習 + - 技術指引 + - 語法 +translation_of: Learn/CSS/First_steps/What_is_CSS +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First_steps")}}
+ +

{{Glossary("CSS")}} (階層式樣式表)可以讓您建立出好看的網頁,但是它背後是怎麼運作的?在這個主題裡,藉由簡單的語法範例來說明 CSS 是什麼,以及含蓋這個語言的一些關鍵項目。

+ + + + + + + + + + + + +
先備知識:基本的電腦概念、能夠安裝基本軟體,基本與各種檔案打交道的能力,以及 HTML 的基礎(由HTML 入門學到)。
學習目標:學到 CSS 是什麼。
+ +

HTML 入門單元中,我們含蓋了什麼是 HTML 以及它是如何被用來標記文件。這些文件能夠被瀏覽器讀取,標題的文字會看起來比一般段落更大,段落之間會換行並帶有間隔。連結會帶有顏色及底線,讓它與其它一般的文字有區別。您所看到的這些是瀏覽器的預設樣式,用來確保當作者沒有指定任何樣式的狀況下,仍有一些非常基本的樣式被套用上,好讓內容基本上能夠被閱讀(如下圖所示)。

+ +

The default styles used by a browser

+ +

然而,如果所有的網站都長這個樣子,網路世界將是個很無趣的地方。您能使用 CSS 對 HTML 元件的樣子作更多控制,將這些標記以任何您喜歡的設計作調整。

+ +

看看下面的影片,了解更多關於瀏覽器預設樣式(可開 CC 字幕並自動翻譯為中文)。

+ +

{{EmbedYouTube("spK_S0HfzFw")}}

+ +

CSS 是作什麼用的?

+ +

如同我們前面所提到的, CSS 是一種用來指定文件該用什麼方式呈現的語言,可以定義它們的樣式、布局…等。

+ +

文件通常指的是使用標記語言的文字檔案,{{Glossary("HTML")}} 是其中最常見的,但是您也可能遇到其它例如 {{Glossary("SVG")}} 或 {{Glossary("XML")}} 的標記語言。

+ +

所謂的呈現文件,指的是將文件轉換為你的讀者可用的形式。像是 {{Glossary("Mozilla Firefox","Firefox")}} 、 {{Glossary("Google Chrome","Chrome")}} 或 {{Glossary("Microsoft Edge","Edge")}} 這類的{{Glossary("browser","瀏灠器")}},是設計來將文件視覺化,再呈現電腦螢幕、投影機上或是由列表機列印出來。

+ +
+

注意:瀏覽器有時候被稱為 {{Glossary("User agent","user agent")}}(用戶終端),它基本上泛指電腦裡安裝的應用軟體。雖然並不是唯一,當我們在討論 CSS 的時候,用戶終端主要指的是瀏覽器。至於其它的用戶終端,有些能夠將 HTML 和 CSS 轉換為 PDF 再列印出來。

+
+ +

CSS 可以用在很基本文字樣式上頭,像是改變標題和連結的顏色尺寸。它可以用在建立布局,像是將原本單欄的文字內容加入布局,劃分出主要的內容以及包含相關資訊的側邊欄。它甚至可以用在建立動畫效果。點進上面的連結,看看相關的例子。

+ +

CSS 語法

+ +

CSS 是一種基於規則的語言,您對網頁裡特定或一群元素指定一系列的規則。舉例來說:「我要讓頁面裡的主標題,以紅色且大號的字體呈現」。

+ +

下面這段語法是為了實現上面的需求,用簡單 CSS 規則示範:

+ +
h1 {
+    color: red;
+    font-size: 5em;
+}
+ +

樣式規則以一個{{Glossary("CSS Selector", "選擇器")}}開始。它選擇了您預計改變樣式的 HTML 元素。在這個例子中,我們要調整的是第一級的標題元素({{htmlelement("h1")}})。

+ +

接著我們跟著一組花括號 { },裡面是一到多個聲明,它的形式是一對一對屬性名稱屬性內容的組合。每一對聲明會將我們選中元素的屬性,付予我們所想要設定的內容(或數值)。

+ +

在冒號(:)前面的是屬性的名稱,後面的是屬性內容(值)。CSS 的{{Glossary("property/CSS","屬性")}}依照其類型可以使用的值而有所不同。在我們的例子中,有個 color 屬性,它可以設定各種顏色值。而 font-size 屬性則可以採用不同尺寸單位的值。

+ +

一個 CSS 樣式表包含了許多這樣子的規則,一個接著一個。

+ +
h1 {
+    color: red;
+    font-size: 5em;
+}
+
+p {
+    color: black;
+}
+ +

你將會發些有些值很容易學會,而另一些則需要查資料確認。MDN 上有各個屬性的獨立頁面讓您能查到屬性及其可使用的值,在你忘記了或是想知道其它可能用法的時候提供一個快速的路徑。

+ +
+

注意: 您可以在 MDN 的 CSS 參考資源找到所有的 CSS 屬性(以及其它 CSS 特性)頁面的連結。 另外,當您需要得到某個 CSS 特性的更多資訊,應該去習慣使用「mdn 特性名稱」的方式在您喜歡搜尋引擊上搜尋。舉例來說,嘗試以「mdn color」和「mdn font-size」作關鍵字搜尋!

+
+ +

CSS 的各個主題(單元)

+ +

由於 CSS 有太多的項目可以進行設定,因此將這個語言依不同主題切分出單元。您將會在探索 MDN 的時候看到這些單元,並發現許多文章是圍繞著特定單元所組織的。舉例來說,您可以在 MDN 關於背景與邊框的單元裡,看到它的目的,以及其包含了哪些不同的屬性及特性。 您也將在文末發現到相關 CSS 規範的連結。

+ +

在這裡不用太煩惱 CSS 的架構,可以讓尋找資訊變得簡單一些。例如說,當你知道某個屬性可能用在其它類似的東西上,因此它們可能被放在同一個規範(單元)裡。

+ +

舉個特別的例子,讓我們回到背景與邊框的單元中,您可能會認為在邏輯上 background-colorborder-color 會在同一個單元裡被定義。所以您猜對了。

+ +

CSS 規範

+ +

所有網路標準技術(HTML、CSS、JavaScript…等)都被定義在稱為定義(specifications 或簡稱 specs)巨型文件中,由像是 {{glossary("W3C")}}、{{glossary("WHATWG")}}、{{glossary("ECMA")}} 或 {{glossary("Khronos")}} 之類的標準組織所發布,並且很精確地定義這些技術的行為方式。

+ +

CSS 並沒有什麼不同,它由 W3C 一個被稱為 CSS 工作組的團體所發展。這個團體是由對 CSS 感興趣的瀏覽器供應商和其它公司的代表所組成。還有其它被稱為邀請專家的人,與其它的成員組織無關,可以獨立的發聲。

+ +

新的 CSS 特性被 CSS 工作組所發展、定義。有時候是因為特定瀏覽器對某個功能有興趣,而有時候是因為網站設計師與開發人員的要求,還有一些時候是工作組本身定義的需求。CSS 正不斷發展,新的可用特性正在出現。然而,每個人很努力達到的 CSS 重要方針,是不要往會破壞舊網站的方向進行改變。一個在 2000 年建立的網站,使用了當時能用的 CSS 特性,應該到今天仍能夠在瀏覽器上使用。

+ +

作為一個 CSS 新手,你會發現 CSS 的規範不勝枚舉,它們是用來給開發用戶端程式的開發者實作功能所使用,而不是讓網站開發人員閱讀來了解 CSS。許多經驗的豐富的開發者,寧願看 MDN 上的文件或其它指引。然而,知道規範的存在還是有價值的,可以了解它們與您正使用的 CSS 之間的關係,瀏覽器支援(如下)以及相關定義。

+ +

瀏覽器支援

+ +

被定義好的 CSS 特性,只有被一個或更多瀏覽器實作出來之後,才會在我們開發網頁上面有所幫助。這意味著已經編寫了程式,可以將 CSS 檔案裡的設定轉換為輸出在畫面上的結果。我們將在 CSS 工作原理中詳細介紹這個過程。一個(新)特性被所有瀏覽器同時實作出來是不常見的,通常會缺了幾個,CSS 某些部分您可以在某些瀏覽器上使用,然而在其它瀏覽器人則沒有作用。基於這個原因,確認特性被實作的狀況是有用的。在每個 MDN 的資源頁面上,您可以看到感興趣的屬性現在的狀態,因此您可以確定能不能把它使用在網站上。

+ +

以下是 CSS font-family 屬性的支援狀態表。

+ +

{{Compat("css.properties.font-family")}}

+ +

下一步…

+ +

現在您已經知卜 CSS 是什麼,接著移動到 CSS 入門單元,您可以在這裡開始寫一些 CSS。

+ +

{{NextMenu("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First_steps")}}

+ +

在這個單元中

+ +
    +
  1. CSS 是什麼?
  2. +
  3. CSS 入門
  4. +
  5. CSS 的結構
  6. +
  7. CSS 工作原理
  8. +
  9. 使用您的新知識
  10. +
diff --git a/files/zh-tw/learn/css/index.html b/files/zh-tw/learn/css/index.html new file mode 100644 index 0000000000..eedd54f655 --- /dev/null +++ b/files/zh-tw/learn/css/index.html @@ -0,0 +1,72 @@ +--- +title: CSS(樣式表) +slug: Learn/CSS +tags: + - CSS + - 入門 + - 初學者 + - 撰寫程式 + - 樣式 + - 風格 +translation_of: Learn/CSS +--- +
{{LearnSidebar}}
+ +

階層式樣式表({{glossary("CSS")}})是學習完 {{glossary("HTML")}} 之後,您應該學習的第一項技術。HTML 用於定義內容的架構與語意,CSS 則是用來設定樣式與佈局方式。舉例來說,您可以使用 CSS 來改變內容的字體、顏色、字型大小、間距、拆分成多欄,或是加入動畫和其他裝飾性質的特性。

+ +

想要成為 Web 前端開發人員?

+ +

我們整理了一門課程,包含了你實現目標需要的所有基礎知識。

+ +

開始

+ +

先備知識

+ +

在嘗試 CSS 之前,您應該先了解基本的 HTML 知識。我們建議先閱讀 HTML 介紹單元。在這個單元你會學習到關於:

+ + + +

在您了解最基礎的 HTML 運作思維後,我們推薦您同時學習 HTML 與 CSS,使兩者之間互相搭配。因為 HTML 搭配上 CSS 會變得無比有趣,兩者是密不可分的,您無法在不理解 HTML 的情況下獨立學習 CSS。

+ +

在開始這個主題之前,您應該要有電腦的基礎使用概念以及使用網頁的經驗(單純地瀏覽、查看內容)。您應該要有一個已經設定的好的基本工作環境,如同安裝基本軟體所敘述的,知道怎麼建立與管理檔案,如同處理檔案提到的內容。這兩者都是 Web 入門裡初學者單元中一部分。

+ +

建議您在開始課程前先閱讀 Web 入門,不過並非絕對必要,儘量那裡有許多詳細的介紹,大部分 CSS 概念在我們的 CSS 入門單元中也會含蓋到。

+ +

單元

+ +

這個主題按建議的學習順序包含以下的單元。強烈建議您從第一項開始。

+ +
+
CSS 入門
+
CSS(階層式樣式表)用來設定網頁的樣式及佈局,例如:改變文字的字體、顏色、大小及間距以及拆分為多欄,或是增加動畫或裝飾性的效果。這個單元提供一個溫和的路徑,讓您逐漸熟悉 CSS 的基礎概念,包含它的運作方式,語法是什麼樣子,以及如何開始在 HTML 裡添加樣式。
+
CSS 的組成
+
這個單元接續在 CSS 入門之後,現在已經熟悉了這門語言的語法,並有了一些基本的使用經驗,是時候再深入一些。這個單元關注於疊加(cascade)和繼承(inheritance)規則、所有可用的選擇器類型、單位、尺寸、背景與邊框的樣式、除錯,以及其它更多的。
+
這裡的目的是在進入更進階的主題,像是文字樣式CSS 佈局之前,給您一個足以寫出合格 CSS 的工具包並幫助您了解所有的基礎理論。
+
裝飾文字
+
在含蓋了 CSS 語言基本的部分之後,下一個帶給您的 CSS 主題會專注於文字樣式的裝飾上,您將最常用 CSS 作的事情之一。在這裡,我們文字樣式的基礎,包括設定字體、粗細、斜體、行距與字距、陰影與其它的文字效果。整個單元圍繞於在您的頁面上套用選擇的字體,以及對清單和連結進行樣式調整。
+
CSS 的布局
+
到了這邊,我們已經看過了 CSS 的基礎知識,如何裝飾文字,如何裝飾並控制您內容所在的區。現在是時候來看看如合將您的這些區塊擺放到正確的位置,並能依不同的可視空間進行調整。我們已經含蓋了必須的先備知識,所以我們現在可以深入到 CSS 的布局,看看不同的顯示設定,像是新的佈局工具 flexbox 、 CSS grid 和定位(position)以及一些您可能仍想要了解的早期技術。
+
+ +

解決常見的 CSS 問題

+ +

使用 CSS 解決常見的問題裡提供了許多單元的連結,其內容說明如何使用 CSS 解決在建立網頁時常見的問題。

+ +

在一開始,您主要將顏色套用到 HTML 元素或是背景;改變元素的大小、形狀和位置,然後添加、定義元素的邊框。當您對 CSS 的基礎知識有深刻的理解,就沒有太多作不到的事情。學習 CSS 其中一項最棒的事情,是當你了解了基本原理,通常您就能很好的抓到「什麼能作」、「什麼作不到」的感覺,既使是在您還不確切的知道要怎麼實現它的狀況下。

+ +

怪異的 CSS

+ +

CSS 與您將遇到程式語言或設計工具在運作上有點不太一樣。為什麼要用這種方式運作?在下面影片中, Miriam Suzanne 解釋為什麼 CSS 是這樣運作,以及為什麼會這樣子發展。(可以利用字幕翻譯功能,將 CC 字幕轉為中文)

+ +

{{EmbedYouTube("aHUtMbJw8iA")}}

+ +

相關資源

+ +
+
MDN 中的 CSS 資源
+
在 MDN 網站裡,CSS 文件的主要入口,您將可以在這裡找到所有 CSS 語言的所有特性,以及它們詳細的參考資訊。想要知道一個屬性可以套用的所有設定嗎?這是一個不錯的地方。
+
diff --git a/files/zh-tw/learn/css/styling_text/index.html b/files/zh-tw/learn/css/styling_text/index.html new file mode 100644 index 0000000000..2d5368fdfe --- /dev/null +++ b/files/zh-tw/learn/css/styling_text/index.html @@ -0,0 +1,40 @@ +--- +title: 文字樣式 +slug: Learn/CSS/Styling_text +translation_of: Learn/CSS/Styling_text +--- +
{{LearnSidebar}}
+ +

託了 CSS 語言基礎的福,下一個讓你專攻的 CSS 主題是文字樣式——最常會在 CSS 使用的部分。讓我們來看看文字樣式的基礎知識,包含設定字形、粗細、斜體、行距與字距、陰影以及更多文字功能。我們會套用客製化字形、設定清單樣式和連結樣式到你的網頁來完成這個單元。

+ +

先備知識

+ +

在開始這個單元之前,你應該先熟悉基礎的 HTML,如 HTML 介紹 這個單元所討論的,並且要對 CSS 的基礎感到輕鬆,如 CSS 介紹 討論的。

+ +
+

Note: If you are working on a computer/tablet/other device where you don't have the ability to create your own files, you could try out (most of) the code examples in an online coding program such as JSBin, CodePen or Thimble.

+
+ +

指南

+ +

這個單元包含以下的文章會教導你?設定 HTML 文字內容樣式的全部要領。

+ +
+
基本的字形及文字樣式
+
In this article we go through all the basics of text/font styling in detail, including setting font weight, family and style, font shorthand, text alignment and other effects, and line and letter spacing.
+
清單樣式
+
Lists behave like any other text for the most part, but there are some CSS properties specific to lists that you need to know about, and some best practices to consider. This article explains all.
+
連結樣式
+
When styling links, it is important to understand how to make use of pseudo-classes to style link states effectively, and how to style links for use in common varied interface features such as navigation menus and tabs. We'll look at all these topics in this article.
+
網頁字形
+
Here we will explore web fonts in detail — these allow you to download custom fonts along with your web page, to allow for more varied, custom text styling.
+
+ +

Assessments

+ +

The following assessments will test your understanding of the text styling techniques covered in the guides above.

+ +
+
Typesetting a community school homepage
+
In this assessment we'll test your understanding of styling text by getting you to style the text for a community school's homepage.
+
diff --git a/files/zh-tw/learn/getting_started_with_the_web/css_basics/index.html b/files/zh-tw/learn/getting_started_with_the_web/css_basics/index.html new file mode 100644 index 0000000000..f51f584cf8 --- /dev/null +++ b/files/zh-tw/learn/getting_started_with_the_web/css_basics/index.html @@ -0,0 +1,273 @@ +--- +title: CSS 基本 +slug: Learn/Getting_started_with_the_web/CSS_basics +translation_of: Learn/Getting_started_with_the_web/CSS_basics +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web")}}
+ +
+

階層樣式表 (Cascading Stylesheets;CSS) 可用以塑造網站的特殊風格。例如這段文字要用一般的黑色,或是改用紅色標明重點?某段重要內容應該置於畫面的何處?想用什麼背景圖片及顏色裝飾你的網站?〈CSS 基本概念〉帶你入門。

+
+ +

CSS到底是什麼?

+ +

跟 HTML 一樣,CSS 既非標準程式語言,也不是標記語言, 而是一種風格頁面語言(style sheet language):它能讓你在 HTML 文件中的元素(element)上套用不同的頁面樣式(style)。例如, 當想要將 HTML 頁面上所有段落元素(paragraph elements)裡的文字全部轉換成紅色,你會在CSS裡寫:

+ +
p {
+  color: red;
+}
+ +

試看看在你的編輯器上建立新的檔案 style.css 並貼上這三行 CSS 程式碼,並存到你的styles 目錄。

+ +

但我們還需要把 CSS 套用在 HTML 文件上。否則 CSS 的樣式效果,不會在瀏覽器的 HTML 檔案顯示。(如果你還未跟上我們的專案,請閱讀 Dealing with filesHTML basics 以找出你需要什麼)

+ +
    +
  1. 打開 index.html 文件,然後將下面一行貼到 head,也就是 <head></head> 標籤之間。 + +
    <link href="styles/style.css" rel="stylesheet" type="text/css">
    +
  2. +
  3. 存檔 index.html 並且在瀏覽器載入。你應該可以看到下面的頁面。
  4. +
+ +

A mozilla logo and some paragraphs. The paragraph text has been styled red by our css.如果你的段落文字現在變成紅色, 恭喜, 你已經成功撰寫你的第一份 CSS!

+ +

解析 CSS ruleset

+ +

讓我們深入解析下列的 CSS:

+ +

+ +

整個架構我們稱為規則集 (rule set),或是簡稱為規則 (rule) 也可以。(也注意名字裡面的單獨部分)

+ +
+
選擇器(Selector)
+
在這個規則的最前頭為 HTML 的元素名。它將決定你 HTML 裡什麼元素將被你接下來的設定影響(在這個範例中,就是 段落元素 p)。若要改變欲影響的元素,只要更改選擇器就行了。
+
宣告(Declaration)
+
單一個規則,例如 color: red; 指定了這個元素的呈現樣貌。
+
屬性 (Properties)
+
修改屬性是改變你HTML元素的一種方法 . (在這範例中, color 是段落(p)元素的一種屬性.) 在CSS中, 你可以選擇哪些屬性用來影響 rule.
+
屬性值 (Property value)
+
屬性值 就是位於屬性右邊,在冒號(:)之後,從眾多的可能樣式選出一個給予屬性(範例中就是從眾多的 color 樣式中選出 red
+
+ +

注意語法其他重要的部分:

+ + + +

下面是一個簡單的CSS規則範例。注意每個宣告都是以冒號(:)來指定屬性值,並且宣告之間都是以分號做區分 (;) 。

+ +
p {
+  color: red;
+  width: 500px;
+  border: 1px solid black;
+}
+ +

選擇多個元素

+ +

你可以選擇數種元素(elements)並同時用在同一個 rule set 上。可以用逗號(,)包含數個選擇器,如:

+ +
p,li,h1 {
+  color: red;
+}
+ +

選擇器的不同類型

+ +

選擇器有很多種類。到目前為止,我們只看到了元素選擇器(element selector),它選取了指定 HTML 檔案下的所有選定元素。不過,我們還有更多選擇器。以下有一些常見類型:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
選擇器名選取/控制什麼範例
元素選擇器,有時也稱作標籤或類型選擇器(Element selector、tag or type selector)指定所有 HTML 元素中的特定元素p
+ 選取 <p>
ID 選擇器(ID selector)指定頁面上的特定 ID 元素(單一 HTML 頁面中,每個 ID 只能綁定一個元素)#my-id
+ 控制 <p id="my-id"><a id="my-id">
Class 選擇器(Class selector)指定頁面上的特定 class 元素(單一 HTML 頁面中,class 屬性可以被多個元素使用).my-class
+ 控制 <p class="my-class"><a class="my-class">
屬性選擇器(Attribute selector)指定頁面上的特定屬性元素img[src]
+ 控制 <img src="myimage.png"> 但不控制 <img>
虛擬 class 選擇器(Pseudo-class selector)在特定的情況下,指定頁面的元素,例如懸停時。 +

a:hover
+ 控制 <a>, 但只有在滑鼠游標停留在連結上時.

+
+ +

還有很多值得探索的選擇器,你可以在我們的選擇器導引章節 Selectors guide 看到更多介紹。

+ +

文字與字體

+ +

現在我們已經瀏覽過一些CCS的基礎,接下來我們開始增加更多的規則和資訊到我們的style.css檔案,讓我們範例中的字型和文字看起來更好.

+ +
    +
  1. 第一步, 我們回到 output from Google Fonts 找到你存的字體。 加上 <link ... > 這個元素在你的 index.html文件裡的head中(在 <head> 跟 </head> 任何位置中)。
    + 這一段code將頁面連結到樣式表,將Open Sans字體系列與網頁一起下載,並讓你在HTML元素上使用自己的樣式表進行設置。 它看起來會像: +
    <link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
    +
  2. +
  3. 下一步, 刪除style.css文件中其他現有的字體。這是個很好的嘗試, 但紅色字體看起來真的有點醜。
  4. +
  5. 把下面這行加在這個地方, 取代 placeholder line with the actual font-family line you got from Google 字體. (font-family 是指你想在文件中使用的字體.)
    + 這規則
    + 此規則首先為頁面設置整體的基本字體和字型(因 <html> 是整個頁面的父元素, 頁面中所有的元素會繼承同樣的字體和字型): +
    html {
    +  font-size: 10px; /* px means 'pixels': the base font size is now 10 pixels high  */
    +  font-family: placeholder: this should be the rest of the output you got from Google fonts
    +}
    + +
    +

    Note: 我已增加了對於 "px" 的說明在上面. 任何在 CSS document 中 /*  */ 內的文字是 CSS 說明, 瀏覽器在編譯時會忽略掉. 這是一個可以用來說明你做了什麼的幫助訊息.

    +
    +
  6. +
  7. 現在我們將會在HTML body中為包含文字的元素設置字體大小,<h1>,<li>,<p>。我們也設置標題居中,並在正文內容上設置一些行高和間距,使其更具可讀性
  8. +
  9. +
    h1 {
    +  font-size: 60px;
    +  text-align: center;
    +}
    +
    +p, li {
    +  font-size: 16px;
    +  line-height: 2;
    +  letter-spacing: 1px;
    +}
    +
  10. +
+ +

你可以依自己喜好修改 px 的值。你目前的工作成果可能如下圖所示:

+ +

a mozilla logo and some paragraphs. a sans-serif font has been set, the font sizes, line height and letter spacing are adjusted, and the main page heading has been centered

+ +

CSS:和塊(box)密不可分

+ +

當你在編寫 CSS,設定尺寸、顏色及位置時,你會發現它有著如同箱子(塊,box)的概念。多數在網頁上的 HTML 元素就像是箱子一般相互堆疊而成。

+ +

a big stack of boxes or crates sat on top of one another

+ +

CSS佈局主要基於「box 模型」。在頁面空間的每個 box 都有下列屬性:

+ + + +

three boxes sat inside one another. From outside to in they are labelled margin, border and padding

+ +

在本節中,我們還使用:

+ + + +

所以,讓我們開始對我們的頁面添加更多 CSS!繼續將這些新規則添加到style.css頁面底部,不需要害怕多方嘗試去改值設定來了解結果。

+ +

改變頁面顏色

+ +
html {
+  background-color: #00539F;
+}
+ +

這條規則將會套用到整個頁面的背景顏色。根據你在規劃網站時選擇的顏色修改其中的顏色代碼。

+ +

設定 body 的風格(styling)

+ +
body {
+  width: 600px;
+  margin: 0 auto;
+  background-color: #FF9500;
+  padding: 0 20px 20px 20px;
+  border: 5px solid black;
+}
+ +

接下來修改 body 元素。以下依序介紹一些常見的宣告:

+ + + +

設定我們主要頁面標題的位置(Positioning)和風格(styling)

+ +
h1 {
+  margin: 0;
+  padding: 20px 0;
+  color: #00539F;
+  text-shadow: 3px 3px 1px black;
+}
+ +

You may have noticed there's a horrible gap at the top of the body. That happens because browsers apply some default styling to the {{htmlelement("h1")}} element (among others), even when you haven't applied any CSS at all! That might sound like a bad idea, but we want even an unstyled webpage to have basic readability. To get rid of the gap we overrode the default styling by setting margin: 0;.

+ +

Next up, we've set the heading's top and bottom padding to 20 pixels, and made the heading text the same color as the html background color.

+ +

One rather interesting property we've used here is text-shadow, which applies a text shadow to the text content of the element. Its four values are as follows:

+ + + +

Again, try experimenting with different values to see what you can come up with.

+ +

把圖像置中

+ +
img {
+  display: block;
+  margin: 0 auto;
+}
+ +

Finally, we'll center the image to make it look better. We could use the margin: 0 auto trick again as we did earlier for the body, but we also need to do something else. The body element is block level, meaning it takes up space on the page and can have margin and other spacing values applied to it. Images, on the other hand, are inline elements, meaning they can't. So to apply margins to the image, we have to give the image block-level behavior using display: block;.

+ +
+

Note: Don't worry if you don't yet understand display: block; and the block-level/inline distinction. You will as you study CSS in more depth. You can find out more about the different available display values at our display reference page.

+
+ +

結論

+ +

看完了以上的介紹並依照各個步驟實做,你應該能自己寫出這樣的網頁(如下, view it here):

+ +

a mozilla logo, centered, and a header and paragraphs. It now looks nicely styled, with a blue background for the whole page and orange background for the centered main content strip.

+ +

如果哪裡卡關了,你可以隨時造訪 Github 上的 finished example code ,看看裡面的 code 和你寫的哪裡不同。

+ +

這篇文章觸及的是非常基本的 CSS 介紹,若你有興趣想進一步了解,歡迎參考 CSS Learning topic

+ +

{{PreviousMenuNext("Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web")}}

diff --git a/files/zh-tw/learn/getting_started_with_the_web/dealing_with_files/index.html b/files/zh-tw/learn/getting_started_with_the_web/dealing_with_files/index.html new file mode 100644 index 0000000000..8411bdbe86 --- /dev/null +++ b/files/zh-tw/learn/getting_started_with_the_web/dealing_with_files/index.html @@ -0,0 +1,117 @@ +--- +title: 與各式各樣檔案打交道 +slug: Learn/Getting_started_with_the_web/Dealing_with_files +tags: + - HTML + - 初學者 + - 指南 + - 網站 +translation_of: Learn/Getting_started_with_the_web/Dealing_with_files +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web")}}
+ +
+

一個網站會包含許多檔案: 文字內容、程式碼、樣式表、影音內容......等。每當你建立一個網站時,你需要將這些檔案在你的電腦上合理架構好。以確保它們能夠互相溝通,並讓內容正常顯示。然後你接著才能將你的網站發佈上線。本篇文章將探討你應該注意的一些議題,以便讓你能夠為你的網站設定好合理的檔案架構。

+
+ +

你的網站在哪裡?

+ +

當你正在你自己的電腦上編輯你的網站時,你應該將所有相關的檔案放在同一個資料夾中,這反映到未來在伺服器上的檔案架構。這個資料夾可以放在任何地方,但你應該會放在一個容易找到的地方,對吧!像是你的桌面,你的家目錄,或是你硬碟的根目錄。

+ +
    +
  1. 找到一個地方來存放你的網站專案。首先,建立一個新資料夾並命名為 web-projects (或類似名稱)。 這裡將存放你的各種網站專案.
  2. +
  3. 在上述資料夾底下,建立另一個資料夾來存放你的第一個網站,請將這個資料夾命名為 test-site (或其他有創意的名稱).
  4. +
+ +

留意大小寫與空格

+ +

你將注意到在本篇文章中,我們會要求你在命名檔案或是資料夾時,只使用小寫並且避免使用空格。這是因為:

+ +
    +
  1. 許多的電腦尤其是網路伺服器,是大小寫區分的(case-sensitive)。所以假設你放了圖片在你的網站上而路徑是 test-site/MyImage.jpg,然後另一個檔案你想放在 test-site/myimage.jpg,這可能是無法運作的。
  2. +
  3. 瀏覽器、伺服器、以及各種程式語言對於空格的處理並不是一致的。舉例來說,如果你在檔名中使用了空格,有些系統會將其視為兩個檔名,有些伺服器會將空格替換成 "%20" (這是空格在 URIs 中的表示法),並破壞了你的連結。我們建議使用底線(underscores)與破折號(dashes)來隔開單字。例如:my-file.html 或是 my_file.html.
  4. +
+ +

也因為這些原因,你應該盡量在命名資料夾與檔案時使用小寫並避免使用空格,這樣一來將能夠減少一些不必要的錯誤。

+ +

你的網站架構應該如何?

+ +

下一步,我們要看看我們的測試網站應該具有什麼樣的架構。我們的網站專案最常見的東西就是一個HTML檔案與專門放圖片、樣式檔案、腳本檔案的資料夾們。讓我們來看看下面:

+ +
    +
  1. index.html: 這個檔案會包含你的首頁內容,也就是別人一進到你的網站時所看到的文字與圖片。使用你的文字編輯器,建立一個新檔案命名為 index.html ,並將它存到 test-site 這個資料夾下。
  2. +
  3. images folder: 這個資料夾包含了所有網站會用到的圖片,建立一個新資料夾命名為 images ,並將它存到 test-site 這個資料夾下。
  4. +
  5. styles folder: 這個資料夾包含了能夠設計你的網站的CSS碼(例如:設定文字與背景顏色),建立一個資料夾命名為 styles,並將它存到 test-site 這個資料夾下。
  6. +
  7. scripts folder: 這個資料將包含能夠使網站具有互動性的JavaScript程式碼。(例如:按下按鈕後會載入資料)。建立一個資料夾命名 scripts ,並將它存到 test-site 這個資料夾下。
  8. +
+ +
+

Note: 在Windows的電腦上,你可能在設定副檔名上會遇到一些困難。因為Windows預設會將已知的檔案類型名稱隱藏。一般來說你可以將這項設定關掉,只需要去檔案總管,選擇「資料夾選項」並取消選取「隱藏已知檔案類型的副檔名」,並點選 OK 。有關不同版本的Windows的設定方法,請利用搜尋引擎搜尋。

+
+ +

檔案路徑

+ +

要讓一個檔案能夠與另一個檔案"溝通",你需要提供一個他們之間的相對檔案路徑以讓檔案能夠找到另一個檔案在哪裡。為了要展示,我們將插入一小段的HTML到我們的 index.html 檔案中,並且讓它顯示你在 "What will your website look like?" 這篇文章中所選的圖片。

+ +
    +
  1. 複製你選的圖片並放到 images 資料夾中。
  2. +
  3. 打開你的 index.html,並複製貼上下面這段code。先別擔心這些code代表什麼意思,我們會在後面的時候講解它們代表的意義。 +
    <!DOCTYPE html>
    +<html>
    +  <head>
    +    <meta charset="utf-8">
    +    <title>My test page</title>
    +  </head>
    +  <body>
    +    <img src="" alt="My test image">
    +  </body>
    +</html> 
    +
  4. +
  5. <img src="" alt="My test image"> 這行是一段將圖片插入到頁面中的 HTML code,我們必須告訴HTML圖片在哪。我們知道圖片在  images 資料夾中,而  images 資料夾就跟 index.html 在同一目錄下。為了要在檔案系統結構中從 index.html 走到我們的圖片,我們需要將檔案路徑設為images/your-image-filename. 舉例來說,我們的圖片命名為 firefox-icon.png,所以這裡的檔案路徑即為 images/firefox-icon.png.
  6. +
  7. 將檔案路徑貼到你的 HTML code 中的 src="" 的雙引號之間。
  8. +
  9. 將你的 HTML 檔案存檔,並且滑鼠雙擊HTML檔案來打開它,你應該會看到一個新的網頁並展示著你的圖片!
  10. +
+ +

A screenshot of our basic website showing just the firefox logo - a flaming fox wrapping the world

+ +

一些有關路徑的規則:

+ + + +

至此,你已經知道目前需要知道的了。

+ +
+

Note: Windows的檔案系統會傾向使用反斜線(\),而非斜線(/)。例如 C:\windows. 這並沒有關係,即使你是在Windows上開發網站,你仍然應該在程式碼中使用斜線(/)。

+
+ +

還有什麼需要被完成的?

+ +

目前先這樣吧。你的資料夾裡面現在應該長得像這樣:

+ +

A file structure in mac os x finder, showing an images folder with an image in, empty scripts and styles folders, and an index.html file

+ +

{{PreviousMenuNext("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web")}}

+ +

 

+ +

In this module

+ + + +

 

diff --git a/files/zh-tw/learn/getting_started_with_the_web/how_the_web_works/index.html b/files/zh-tw/learn/getting_started_with_the_web/how_the_web_works/index.html new file mode 100644 index 0000000000..05ac9e4d7b --- /dev/null +++ b/files/zh-tw/learn/getting_started_with_the_web/how_the_web_works/index.html @@ -0,0 +1,101 @@ +--- +title: 網路如何運作 +slug: Learn/Getting_started_with_the_web/How_the_Web_works +translation_of: Learn/Getting_started_with_the_web/How_the_Web_works +--- +
{{LearnSidebar}}
+ +
{{PreviousMenu("Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}
+ +
+

〈網路如何運作〉將簡單介紹,當你透過電腦或手機瀏覽器瀏覽網頁時,究竟發生什麼事。

+
+ +

短期來看,在撰寫網站程式碼時,這些理論並不是非懂不可,但在之後,了解這些背後原理,對你會很有幫助。

+ +

用戶與伺服器

+ +

連接到網路的電腦稱為用戶端(client)與伺服器端(server)。彼此的連結原理如圖所示:

+ +

+ + + +

百寶箱的其他魔法

+ +

剛剛描述的用戶/伺服器端還不是一切,我們還要講述其他部份,才能說完整個故事。

+ +

現在把網路想像成一條大道。大道的一端是用戶端,就像你家一樣;另一端則是伺服器,就像是你要去血拼的商店。

+ +

+ +

除了用戶與伺服器之外,我們還需要和這些朋友們打招呼:

+ + + +

所以我說到底發生了啥?

+ +

當你在瀏覽器輸入網址時(你可以想像說自己要走去商店時):

+ +
    +
  1. 瀏覽器會先去 DNS 伺服器尋找託管網站的伺服器,其真實位置所在(如同你去尋找商店的地址)
  2. +
  3. 瀏覽器向伺服器傳送 HTTP 訊息,請求伺服器向用戶端傳送網站的複本(如同去商店下訂單)。在用戶端及伺服器的之間,請求訊息與其他資訊,會使用 TCP/IP 在網路連線之間傳送。
  4. +
  5. 伺服器如果允許用戶端請求,伺服器就會傳送「200 OK」訊息,意味著「好,你可以閱覽這個網站,那我給你網站資料囉~」並開始對瀏覽器以一小串稱作「資料封包」的組合形式,傳送網站的檔案。這就像是商店給你商品,你接著把它們都帶回家一樣
  6. +
  7. 瀏覽器把一小塊一小塊的東西,組合成完整的網站,並把它呈現起來--商品送到家門口後,閃亮亮的新貨在你眼前,超棒的啦!
  8. +
+ +

講講 DNS

+ +

真正的網址,並不是在瀏覽器的網址列上,輸入好記好讀的字串,就能找到你最愛的網站。它們其實是一串特殊的數字,看起來就像是這樣:63.245.215.20

+ +

這叫做 {{Glossary("IP Address", "IP 地址")}},網路上它擁有獨一無二的位置。不過,記數字果然不簡單吧?這就是要發明域名伺服器的原因。他們會把你在瀏覽器輸入的網址(例如 mozilla.org)和網站的真實位置(IP)相匹配

+ +

網站能直接透過其 IP 位置訪問之:在瀏覽器的網址列輸入 63.245.215.20 的話,可以走到 Mozilla 的網站。

+ +

A domain name is just another form of an IP address

+ +

再講講封包

+ +

稍早我們用了「封包」來描述從伺服器傳到用戶端的資料格式。這裡的「封包」是什麼意思呢?通常資料在網路傳送時,會傳送上千個小資料,這樣在同一時間和同一網站,才能有很多用戶下載內容。如果網站只傳送一個大傢伙過去,那在同一時間就只能有一個用戶能下載,網路會變得很慢、很無聊...

+ +

參見

+ + + +

製作群

+ +

街頭的照片:Street composing、作者是Kevin D

+ +

{{PreviousMenu("Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}

+ +

在模塊裡面

+ + diff --git a/files/zh-tw/learn/getting_started_with_the_web/html_basics/index.html b/files/zh-tw/learn/getting_started_with_the_web/html_basics/index.html new file mode 100644 index 0000000000..f59eb8eab7 --- /dev/null +++ b/files/zh-tw/learn/getting_started_with_the_web/html_basics/index.html @@ -0,0 +1,232 @@ +--- +title: HTML 基礎 +slug: Learn/Getting_started_with_the_web/HTML_basics +tags: + - HTML + - Web + - 學習 + - 寫程式 + - 新手 +translation_of: Learn/Getting_started_with_the_web/HTML_basics +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web")}}
+ +
+

HTML(Hypertext Markup Language),中文全名為「超文字標示語言」,是一種用來組織架構並呈現網頁內容的程式語言。網頁內容的組成,可能包含了段落、清單、圖片或表格...等。透過這篇文章,希望能幫助大家對 HTML 及其功能有基本的認識。

+
+ +

HTML 到底是什麼?

+ +

HTML 是一種標記語言(markup language),而非一般熟知的程式設計語言;它會告訴瀏覽器該如何呈現你的網頁──單純簡易或是極其複雜的頁面都沒問題。HTML 包含了一系列的元素({{Glossary("element", "elements")}}),而元素包含了標籤({{Glossary("tag", "tags")}})內容(content),我們用標籤來控制內容的呈現樣貌,例如字體大小、斜體粗體、在文字或圖片設置超連結等。舉例來說,請看看以下這個句子:

+ +
My cat is very grumpy
+ +

如果我們想讓這個句子自成一個段落,那麼可以在它前後分別加上段落標籤 ({{htmlelement("p")}}),它就變成一個段落元素了:

+ +
<p>My cat is very grumpy</p>
+ +

HTML 元素的組成

+ +

讓我們來仔細的觀察一下,內容、標籤和元素的關係:

+ +

+ +

我們可以看到基本的架構:

+ +
    +
  1. 起始標籤 (The opening tag):先打角括弧,也就是大於、小於的符號「< >」,裡面再放入元素名稱,如上面的例子「<p>」。起始標籤代表這個元素從這裡開始。
  2. +
  3. 結束標籤 (The closing tag): 與起始標籤一樣,只是在元素名稱前面多了個前置斜線「/」。很容易理解地,內容的最後加上結束標籤,代表這個元素的尾端。在寫HTML時,很容易忘了最後的結束標籤,提醒大家要多注意唷!
  4. +
  5. 內容(The content): 這個元素的內容,以上面的例子來說,內容就是這句文字。
  6. +
  7. 元素(The element): 由起始標籤、結束標籤、內容所組成。
  8. +
+ +

元素還可以有「屬性(Attribute)」,請大家看看下面的例子:

+ +

+ +

屬性能提供更多的資訊(當然,這個資訊是幫助我們更有效及方便編輯,不會呈現在網頁上),屬性包含了屬性名稱與值,你可以利用屬性設定這個元素的色彩、對齊方式、圖表的格線等等。

+ +

屬性的組成包含:

+ +
    +
  1. 在元素名稱和屬性之間有一個空格(如果有多個屬性,屬性之間也需要有空格)
  2. +
  3. 屬性名稱後面接著等於符號「=」
  4. +
  5. 屬性包在起始標籤裡面,如範例所示
  6. +
+ +

巢狀元素

+ +

元素裡面可以在放進元素,我們稱之為「巢狀元素(nesting element)」。例如這個句子:「我的貓有夠無敵臭臉」,若你想強調「有夠無敵」,我們就可以把「有夠無敵」這四個字自成一個顯示為粗體的元素 {{htmlelement("strong")}} :

+ +
<p>My cat is <strong>very</strong> grumpy.</p>
+ +

要注意的是,每個元素都有自己的起始和結束標籤,一層一層的包覆。所以最外層是<p>  ,接著<strong> ;先結束strong元素,所以先寫</strong>,最外面才是 </p>。

+ +
<p>My cat is <strong>very grumpy.</p></strong>
+ +

如果元素的起始和結束標籤錯置(如上方),那麼瀏覽器只能自行判斷你想呈現的樣子,可能會完全不如預期!所以在做巢狀元素時要多注意唷!

+ +

空元素

+ +

有些元素沒有內容,我們稱為「空元素(empty elements)」。 以這個圖片元素 {{htmlelement("img")}} 為例:

+ +
<img src="images/firefox-icon.png" alt="My test image">
+ +

它有兩個屬性,但是沒有結束標籤,也沒有裡面的內容。因為圖片元素是直接把圖檔嵌在 HTML 網頁上。

+ +

HTML 文件的架構

+ +

讓我們來看看一個完整的HTML頁面它所包含的要素(以下範例的程式碼出自這篇文章:Dealing with files):

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>My test page</title>
+  </head>
+  <body>
+    <img src="images/firefox-icon.png" alt="My test image">
+  </body>
+</html>
+ +

我們可以看到:

+ + + +

圖片

+ +

再讓我們複習一下圖片元素:

+ +
<img src="images/firefox-icon.png" alt="My test image">
+ +

如同我們前面提到,圖片元素是直接把圖檔嵌在HTML網頁上,它是透過圖片來源(src ,source)這個屬性,提供了連到圖片檔案的路徑。

+ +

我們也可以加上alt (alternative) 這個屬性。在網頁瀏覽者無法正確看到圖片時,你希望對他們呈現什麼樣的說明文字。這種狀況會發生通常是因為:

+ +
    +
  1. 許多視能障礙的網頁瀏覽者,會使用「Screen Readers」這樣的工具,利用說明文字(alt text)來了解網頁要呈現的圖片內容。
  2. +
  3. 就是有些東西出錯了。例如,你誤植了圖片來源的路徑,你可能就會看到類似以下的文字:
  4. +
+ +

+ +

說明文字應該要好好呈現這個圖片的內容,上面這個例子就很差。好的例子像是:「Firefox  Logo:有一隻狐狸繞著地球」

+ +
+

注意:你可以在 MDN's Accessibility landing page 查看無障礙頁面的資訊。

+
+ +

標記文字

+ +

這個段落將為大家介紹如何標記文字(讓這些文字如何呈現)。

+ +

文件標題 (heading)

+ +

讓你呈現這些內容的主題,就像一本書有書名、章節名稱和副標題,一份HTML文件也有類似的概念。HTML最多可以有六層的heading, {{htmlelement("h1")}}–{{htmlelement("h6")}} ,雖然通常我們只使用3至4層:

+ +
<h1>My main title</h1>
+<h2>My top level heading</h2>
+<h3>My subheading</h3>
+<h4>My sub-subheading</h4>
+ +

請試試在 {{htmlelement("img")}} 上方,加上合適的heading。

+ +

段落 (paragraph)

+ +

如上面介紹過的,{{htmlelement("p")}} elements 包含文字段落,在呈現一般文字時,這是我們最常用到的。

+ +
<p>This is a single paragraph</p>
+ +

請試試在這裡 What should your website look like? 的圖片(<img> element)下方,加上幾段文字。

+ +

清單 (list)

+ +

清單至少會包含兩個元素,以下是最常見的清單類,無順序性與有順序性的:

+ +
    +
  1. 無順序性清單(Unordered lists) 代表這些項目的順序改變,不影響任何是,例如購物清單。項目會包含在  {{htmlelement("ul")}} 裡面。
  2. +
  3. 有順序性清單(Ordered lists)代表這些項目的順序是有意義的,例如食譜裡的製作步驟。項目會包含在 {{htmlelement("ol")}} 裡面。
  4. +
+ +

每個項目則分別放在{{htmlelement("li")}} (list item) element裡面。

+ +

例如,我們想把以下這段文字變成清單:

+ +
<p>At Mozilla, we’re a global community of technologists, thinkers, and builders working together ... </p>
+ +

寫法如下:

+ +
<p>At Mozilla, we’re a global community of</p>
+
+<ul>
+  <li>technologists</li>
+  <li>thinkers</li>
+  <li>builders</li>
+</ul>
+
+<p>working together ... </p>
+ +

請試試在練習網頁,加上一個清單。

+ + + +

連結對於網頁來說是非常重要的。要加上連結,我們需要用到這個元素 — {{htmlelement("a")}} —  a 代表了「anchor」。要讓文字變成連結的步驟如下:

+ +
    +
  1. 選擇一些文字,例如「Mozilla Manifesto」。
  2. +
  3. 把他們包在這個<a> 元素裡: +
    <a>Mozilla Manifesto</a>
    +
  4. +
  5. 在<a> element 中加上href attribute這個屬性: +
    <a href="">Mozilla Manifesto</a>
    +
  6. +
  7. 屬性質就是你要連結網址: +
    <a href="https://www.mozilla.org/zh-TW/about/manifesto/">Mozilla Manifesto</a>
    +
  8. +
+ +

網址的開頭使用https://http:// (網路文字傳送標準的不同)可能會給你不一樣的結果。因此,在寫連結時,請自己先點擊過,確認無誤。

+ +

請試試在練習網頁加上一個超連結。

+ +
+

href 這個屬性名稱比較不直觀,不太好記,但它代表的是:hypertext reference的縮寫。

+
+ +

+ +

結論

+ +

看完了以上的介紹並依照各個步驟實做,你應該能自己寫出這樣的網頁(如下, view it here):
+
+ A web page screenshot showing a firefox logo, a heading saying mozilla is cool, and two paragraphs of filler text

+ +

如果哪裡卡關了,你可以隨時造訪Github上的 finished example code ,看看裡面的code和你寫的哪裡不同。

+ +

這篇文章觸及的是非常基本的HTML介紹,若你有興趣想進一步了解,歡迎參考 HTML Learning page

+ +

{{PreviousMenuNext("Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web")}}

+ + + +

In this module

+ + diff --git a/files/zh-tw/learn/getting_started_with_the_web/index.html b/files/zh-tw/learn/getting_started_with_the_web/index.html new file mode 100644 index 0000000000..f2629247fc --- /dev/null +++ b/files/zh-tw/learn/getting_started_with_the_web/index.html @@ -0,0 +1,59 @@ +--- +title: Web 入門 +slug: Learn/Getting_started_with_the_web +tags: + - Beginner + - CSS + - Design + - Guide + - HTML + - Index + - NeedsTranslation + - TopicStub + - publishing + - theory +translation_of: Learn/Getting_started_with_the_web +--- +
{{LearnSidebar}}
+ +
+

〈Web 入門〉是一系列簡潔的文章,介紹網頁開發的實用範例。你將運用相關工具建構簡易網頁並發布自己的程式碼。

+
+ +

替你的第一個網站說故事

+ +

建立個人網站需要很多功夫。如果你才剛開始接觸網頁設計,我們建議大家可以先從小地方著手。不是要你立刻就寫出跟「Facebook」一樣規模的網站,但自己架一個上線的網站一點都不難,現在就開始吧!

+ +

只要依序看過以下的系列文章,你將初學者蛻變成會架設自己的第一個上線網頁,Let's go!

+ +

安裝基本軟體

+ +

現有許多工具可建構網站。如果你剛起步,你可能不知從何選擇程式碼編輯器、框架、測試工具等等。我們將透過〈安裝基本軟體〉逐步引領你安裝基本的網頁開發軟體。

+ +

你的網站看起來會是什麼樣子?

+ +

在開始為自己的網站寫程式碼之前,你應該先規劃要呈現哪些資訊?要採用哪種字體與顏色?你可依照〈你的網站看起來會是什麼樣子?〉所提供的簡易方法,照著來規劃網站的內容與設計。

+ +

與各式各樣檔案打交道

+ +

一個網站包含許多檔案:文字內容、程式碼、樣式表、多媒體內容等等。當建立網站時,你需要將這些檔案組合成清晰的架構,並確保它們能彼此互動溝通。〈與各式各樣檔案打交道〉將引領你安排合理的檔案架構,以及你應該注意的問題。

+ +

HTML 基本概念

+ +

超文字標籤語言 (Hypertext Markup Language;HTML) 可用以建構網頁內容,並賦予其含意和用途。例如某段內容要分為多個段落,或是用項目符號列成幾個重點?要在網頁插入圖片?這裡需要以資料表格整理嗎?如果這些沒有嚇到你,〈HTML 基本概念〉將提供足夠的資訊。

+ +

CSS 基本概念

+ +

串接樣式表 (Cascading Stylesheets;CSS) 可用以塑造網站的特殊風格。例如這段文字要用一般的黑色,或是改用紅色標明重點?某段重要內容應該置於畫面的何處?想用什麼背景圖片及顏色裝飾你的網站?〈CSS 基本概念〉帶你入門。

+ +

JavaScript 基本概念

+ +

程式設計語言 JavaScript 可為你的網站增加互動功能,例如動畫、遊戲、按下按鈕的後續動作、將資料輸入表單、動態套用樣式的效果等等。〈JavaScript 基本概念〉將帶你瞭解此一有趣的程式語言及其能耐,並讓你快速入門。

+ +

將你的網站發佈上線

+ +

在寫完程式碼並整理好檔案之後,接著就是將網站發佈上線,讓其他人可以瀏覽、欣賞內容。〈將你的網站發佈上線〉將帶領你以最輕鬆的方法發佈你的範例程式碼。

+ +

網站的運作方式

+ +

在瀏覽喜愛的網站時,你可能未意識到瀏覽器正於背景中運作著許多複雜事情。〈網站的運作方式〉將簡略說明網頁瀏覽時所發生的大小事。

diff --git a/files/zh-tw/learn/getting_started_with_the_web/installing_basic_software/index.html b/files/zh-tw/learn/getting_started_with_the_web/installing_basic_software/index.html new file mode 100644 index 0000000000..c9874db847 --- /dev/null +++ b/files/zh-tw/learn/getting_started_with_the_web/installing_basic_software/index.html @@ -0,0 +1,73 @@ +--- +title: 安裝基本軟體 +slug: Learn/Getting_started_with_the_web/Installing_basic_software +translation_of: Learn/Getting_started_with_the_web/Installing_basic_software +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web")}}
+ +
+

在本文中,你會知道有哪些 Web 開發的簡易工具,以及正確的安裝方式。

+
+ +

專家都用哪些工具?

+ + + +

我實際需要、立刻需要哪些工具?

+ +

上面一長串看起來好像很嚇人,但其實剛接觸 Web 開發時,不需了解所有的東西。我們先幫你設定最低限度的必要工具:文字編輯器和幾款主流瀏覽器。

+ +

安裝文字編輯器

+ +

你的電腦裡很可能已經提供基本的文字編輯器了。Windows 本身就有 記事本;OS X 已提供 文字編輯;Linux 各版本不太一樣:例如 Ubuntu 就有 gedit

+ +

而針對 Web 開發,其實有著比 Notepad 或 TextEdit 好很多的工具。我們推薦使用 Visual Studio Code,因為這個自由編輯器有提供即時預覽、以及程式碼提示。

+ +

安裝常用瀏覽器

+ +

目前我們會安裝數款 Web 瀏覽器的桌面版,以利測試我們所寫的程式碼。先在下方找到自己所用的作業系統,再點擊你愛用的瀏覽器連結:

+ + + +

在著手開發之前,應先安裝至少兩款瀏覽器以利後續測試。

+ +
+

Internet Explorer 與當今的 web 不相容,可能會讓專案跑不動。

+
+ +

安裝伺服器軟體

+ +

有些例子需要使用伺服器軟體。你可以在 How do you set up a local testing server? 找到作法。

+ +

{{NextMenu("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web")}}

+ +

於本模塊

+ + diff --git a/files/zh-tw/learn/getting_started_with_the_web/javascript_basics/index.html b/files/zh-tw/learn/getting_started_with_the_web/javascript_basics/index.html new file mode 100644 index 0000000000..e4c01763c9 --- /dev/null +++ b/files/zh-tw/learn/getting_started_with_the_web/javascript_basics/index.html @@ -0,0 +1,440 @@ +--- +title: JavaScript 基礎 +slug: Learn/Getting_started_with_the_web/JavaScript_basics +tags: + - JavaScript + - 初學 + - 學習 + - 寫程式 + - 新手 + - 網頁 +translation_of: Learn/Getting_started_with_the_web/JavaScript_basics +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}
+ +
+

JavaScript 是一個可以幫您在網站裡加入互動功能的程式語言(舉例來說,一個遊戲可能會在按鈕按下或資料被輸入表單內時回應、動態更改樣式、以及展示動畫等)。這篇文章會幫助您踏上學習這個令人興奮的語言的旅程,並展示她可以實現的所有可能。

+
+ +

所以 JavaScript 到底是什麼?

+ +

{{Glossary("JavaScript")}} 是一個成熟的動態程式語言,應用於 {{Glossary("HTML")}} 文件(document)上時,就可以為網頁提供動態的互動功能。JavaScript 是由 Mozilla project、Mozilla Foundation 和 Mozilla Corporation 的創辦人 Brendan Eich 所發明的。

+ +

你可以用 JavaScript 實現許多事情。你可以先從簡單的特性開始,如跑馬燈、相簿、動態版型、回應按鈕點擊等。在你熟悉的這個程式語言以後,甚至可以製作遊戲、2D平面以及立體的圖像、資料庫系統等等的應用!

+ +

JavaScript 本身非常的簡潔,卻也充滿彈性,開發者們已經以 JavaScript 核心為基礎為她撰寫了相當多的工具,讓各位可以感到事半功倍。這些工具包括:

+ + + +

「Hello world」範例程式

+ +

前面所述的功能聽起來令人興奮,而她也的確符合這樣的期待— JavaScript 是眾多令人感到興奮的網路科技之一,您會因為選擇利用她來製作網頁而進入一個嶄新且充滿創意及力量的次元。

+ +

但無論如何,要讓 JavaScript 跟 HTML 和 CSS 合作無間的話,可能還要費一些功夫。現在您將會從一些細小的地方開始著手,接著一步步地往前進。首先,我們將會向您展示如何將一些基本的 JavaScript 給加入您的頁面中,並且打造一個「hello world!」的範例(這同時也是許多程式語言的標準範例程式)。

+ +
+

注意:如果您還沒有學習過先前的課程,請您下載這個範例程式碼,並以此開始練習。

+
+ +
    +
  1. 首先,進入您測試網頁的資料夾中,並建立一個名為 main.js 的檔案,再將她存放於 scripts 資料夾內。
  2. +
  3. 接著,開啟 index.html 檔案,並在 </body> 這個結束標籤之前的位置,使用一行新的空間來輸入以下的元素: +
    <script src="scripts/main.js"></script>
    +
  4. +
  5. 我們做的事情,基本上跟新增一個 CSS 的 {{htmlelement("link")}} 元素是相同的概念 — 我們將 JavaScript 給導入這個頁面中,讓她來影響 HTML(以及 CSS、還有任何頁面上的東西)。
  6. +
  7. 再來我們把以下的程式碼新增到 main.js 檔案內: +
    var myHeading = document.querySelector('h1');
    +myHeading.textContent = 'Hello world!';
    +
  8. +
  9. 現在請您將修改過的 HTML 和 JavaScript 給存檔,再用瀏覽器讀取 index.html。您應該會看到以下的內容:
  10. +
+ +
+

備註:我們選擇將 {{htmlelement("script")}} 元素放在接近 HTML 檔案底部的原因,是因為瀏覽器是依照程式碼存在檔案中的順序來讀取 HTML 檔案的。如果 JavaScript 先被瀏覽器讀取了,那她應該要去影響她之後的 HTML 程式碼,但有時候卻行不通,因為她比應該產生改變的 HTML 還要早被讀取到。因此,把她放在接近檔案底部的位置,通常都會是一個不錯的策略。

+
+ +

發生什麼事了?

+ +

所以您的標題文字已經被 JavaScript 修改成「Hello world!」了。我們先使用了一個叫做 {{domxref("Document.querySelector", "querySelector()")}} 的函式來取得了我們標題參考(Reference),並且將她存在一個叫做 myHeading 的變數裡面。這跟我們在操作 CSS 時使用的選擇器是相似的。當您想要更動某個元素時,首先您要將她選取起來。

+ +

之後,我們將變數 myHeading 中 {{domxref("Element.innerHTML", "innerHTML")}} 特性的值設為「Hello world!」。

+ +
+

備註:Both of the features you used above are parts of the Document Object Model (DOM) API, which allows you to manipulate documents.

+
+ +

語言基礎速成

+ +

接著我們來解釋一下 JavaScript 基本特性,以讓您更加地了解她是如何運作的。更好的事情是,這些特性基本上也存在於所有程式語言中。所以如果您可以充分理解這些基礎知識,您就可以撰寫程式來創造無限可能!

+ +
+

注意:在這篇文章中,請您試著將範例程式碼輸入到 JavaScript 主控台中,並觀察發生了什麼事。如果您想要了解更多 JavaScript 主控台的細節,請參閱 Discover browser developer tools

+
+ +

變數(Variables)

+ +

變數({{Glossary("Variable", "Variables")}})是可以用來儲存數值的容器。要宣告一個變數,首先要用關鍵字 var 來開頭,並在後面輸入您想要用來呼叫她的名字:

+ +
let myVariable;
+ +
+

備註:在 JavaScript 檔案內的每行內容都需要在結尾加上分號,以標示出這行結束的位置。只有在需要於單行中隔開敘述句時,分號才是絕對需要的。然而,有些人相信在每一個敘述句結尾加上分號才是最佳實踐。這裡有其他何時要加或不加分號的規則——請參考 Your Guide to Semicolons in JavaScript 以瞭解更多資訊。

+
+ +
+

備註:基本上您可以幫變數取任何名字,不過還是有一些限制的(請參閱這篇文章以了解變數的命名規則)。假如不太確定,可以檢查變數名稱來看看是否合法。

+
+ +
+

備註:JavaScript 是會區分大小寫字母的——myVariable 就跟 myvariable 不相同。如果您的程式碼出現了一些問題,可以試著檢查一下字母的大小寫!

+
+ +

宣告了一個變數之後,您可以為她指定一個數值:

+ +
myVariable = 'Bob';
+ +

您可以呼叫這個變數的名字來取得這個值:

+ +
myVariable;
+ +

如果您有需要,您也可以在一行之內同時做完這兩件事情:

+ +
let myVariable = 'Bob';
+ +

當您把一個數值指定給一個變數之後,您也可以再次改變它:

+ +
let myVariable = 'Bob';
+myVariable = 'Steve';
+ +

請記得這些變數有著不同的資料型態

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
變數說明範例
{{Glossary("String")}}字串,一段文字。如果要將字串指定給一個變數,您應該將內容用引號給框起來。let myVariable = 'Bob';
{{Glossary("Number")}}數值,一個數字。數字不被引號框起來。let myVariable = 10;
{{Glossary("Boolean")}}布林值,一個  True(真)/False(假)數值。true/false 是 JavaScript 內的特殊關鍵字,不需要用引號將她框住。let myVariable = true;
{{Glossary("Array")}}陣列,一個可以儲存多個數值在單一參考中的結構。 +

let myVariable = [1,'Bob','Steve',10];
+ 可以用這個方式來呼叫陣列的每一個成員:myVariable[0]、myVariable[1] 等等。

+
{{Glossary("Object")}}物件。基本上,JavaScript 內的所有東西都可以視為一個物件,而且可以被存放在變數裡。請將這個概念記下來。let myVariable = document.querySelector('h1');
+ 這個項目之前的所有例子也都是物件。
+ +

所以為什麼我們需要變數?這個嘛,我們寫程式時可以做的任何有趣的事情,都需要有變數的參與。如果數值不會更動,那您也無法做任何動態的事情,像是客製化一個歡迎訊息、或是變更相簿裡的圖片。

+ +

註解(Comments)

+ +

您可以在您的 JavaScript 程式碼中加入註解,就像您在撰寫 CSS 時做的事情一樣:

+ +
/*
+Everything in between is a comment.
+*/
+ +

如果您的註解只有一行,我們通常會簡單將註解放在兩個斜線的後方,像以下的範例:

+ +
// This is a comment
+
+ +

運算子(Operators)

+ +

運算子( {{Glossary("operator")}})是一個數學符號,可以讓兩個數值(或是變數)交互作用以後產生結果。您可以從以下的表格中看到一些最簡單的運算子,並將範例輸入 JavaScript 主控台來測試看看。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
運算子說明符號範例
相加/連接用於將兩個數字相加,或是將兩個字串連接在一起。+6 + 9;
+ 'Hello ' + 'world!';
+

減、乘、除

+
這些運算子就跟基礎數學計算中在做的事情相同。-, *, /9 - 3;
+ 8 * 2; // 在 JavaScript 中,相乘運算子是個星號
+ 9 / 3;
指定運算子您已經見過她了:這可以將一個數值指定給一個變數。=var myVariable = 'Bob';
等價運算子測試兩個數值是否相等,並且回傳一個 true/false 的結果。===var myVariable = 3;
+ myVariable === 4;
否定、不相等通常會跟相等運算子搭配使用,否定運算子在 JavaScript 中代表邏輯非(NOT)—她可以將 true 轉換為 false ……等。!, !== +

第一個敘述句回傳的是 true,但我們使否定運算子,使得對照組的敘述句回傳了 false

+ +

var myVariable = 3;
+ !(myVariable === 3);

+ +

在這裏,我們測試了「myVariable 是否不等於 3」的一個敘述。這個敘述回傳的是 false,因為她確實等於 3。

+ +

var myVariable = 3;
+ myVariable !== 3;

+
+ +

其實還有更多的運算子等的您去探索,但我們將在這裡先打住。您可以參照這篇運算式與運算子以取得完整的列表。

+ +
+

備註:混合使用多種資料型態的話,可能會在計算時產生一些奇怪的結果,所以您要謹慎地為變數選用正確的資料類型。舉個例子:在主控台中輸入  "35" + "25"。為什麼您沒有得到您所想要的結果?因為使用引號框住數字會將她轉換成字串,所以您其實是將兩個字串給連接起來,而不是將她們給相加。如果您輸入的是 35 + 25,您將會得到正確的結果。

+
+ +

條件(Conditionals)

+ +

條件是種程式碼結構,可以讓您測試某個陳述式會不會回傳真值,並根據不同的結果執行不同程式碼。最常見的形式是 if ... else 。以下是一個範例:

+ +
let iceCream = 'chocolate';
+if (iceCream === 'chocolate') {
+  alert('Yay, I love chocolate ice cream!');
+} else {
+  alert('Awwww, but chocolate is my favorite...');
+}
+ +

if ( ... ) 裡面的陳述式就是一個測試—這將會使用到等價運算子(如先前所描述的)來比較變數 iceCream 和字串 chocolate 兩者是否相等,如果在比較之後回傳了 true,接著就執行第一個區塊內的程式碼。如果不是,就略過第一個區塊的程式碼並轉而執行寫在執行在 else 之後、第二個區塊內的程式碼。

+ +

函式(Functions)

+ +

函式({{Glossary("Function", "Functions")}})是一種將需要重複使用的功能打包裝起來的方法,所以當要再次執行這些功能的時候,就可以呼叫這個函式來達成,而不是一再的重新撰寫程式碼。您在先前的篇幅中其實已經看過一些函式了,例如:

+ +
    +
  1. +
    let myVariable = document.querySelector('h1');
    +
  2. +
  3. +
    alert('hello!');
    +
  4. +
+ +

這些函式是瀏覽器為您內建的,您可以自由地使用。

+ +

如果您看到某些很像是變數名稱的東西,但是後面帶有括號 — () — 的話,表示這可能是一個函式。函式通常會接收參數({{Glossary("Argument", "arguments")}})—這是一些可以讓她完成工作的必要資料。這些參數會被寫在括號裡面,如果有不只一個參數的話,彼此間要用逗號隔開。

+ +

舉例來說,alert() 這個函式會在瀏覽器內視窗內產生一個彈出視窗,但是我們必須要傳給她一個字串當作參數,告訴這個函式,該把什麼東西放到這個彈出視窗裡。

+ +

好消息是:您可以定義您自己的函式 — 底下的這個範例中,我們將會為您帶來一個簡單的函式,她會接收兩個數字當作參數,並將其相乘:

+ +
function multiply(num1,num2) {
+  let result = num1 * num2;
+  return result;
+}
+ +

您可以試著在主控台中執行上述的函式,然後再用不同的參數來測試這個函式幾次,例如:

+ +
multiply(4,7);
+multiply(20,20);
+multiply(0.5,3);
+ +
+

備註return 陳述式會要求瀏覽器將 result 變數回傳,以利後續使用。這是必要的,不然在函式內定義的變數就只能在函式內使用。這個現象叫作變數的有效使用範圍({{Glossary("Scope", "scoping")}})(請參閱這篇文章以了解變數的有效使用範圍

+
+ +

事件(Events)

+ +

如果要在網頁上創造真正的互動功能,您將會需要事件(Events) — 這是一種可以監聽瀏覽器發生了什麼事情的程式碼結構,接著她會允許您執行其他程式碼以回應這些事件。最明顯的事件就是 click event 了,當瀏覽器裡的某個東西被滑鼠點選時,這個事件就會被觸發。如果要測試一下這個事件,請您把底下的程式碼輸入到主控台內,接著用滑鼠點選目前的網頁:

+ +
document.querySelector('html').onclick = function() {
+    alert('Ouch! Stop poking me!');
+}
+ +

有許多的方法可以把事件跟網頁元素結合在一起。在底下的程式碼中,我們先選擇了 HTML 元素,並把這個元素的 onclick 處理器設定為一個匿名函式,裡面裝著在滑鼠點選事件發生時,要執行的程式碼:

+ +

請特別注意到以下這段程式碼:

+ +
document.querySelector('html').onclick = function() {};
+ +

產生的結果將會與下面這段程式碼相同

+ +
var myHTML = document.querySelector('html');
+myHTML.onclick = function() {};
+ +

只是上面那段寫起來比較簡短罷了。

+ +

徹底加強我們的範例網頁

+ +

到目前為止,我們已經學會一些 JavaScript 的基礎知識了,接下來讓我們幫這個網頁新增一些很酷的特色,並給您一些靈感。

+ +

加入一個圖片變換器

+ +

在這個小節中,我們將在這個網頁裡添加一個圖片,以及一些簡單的 JavaScript,當這個圖片被滑鼠點選的時候,就會在兩個圖片之間互相切換。

+ +
    +
  1. 首先,先去找張您可以為您的網頁增添光彩的圖片。請盡量找一張尺寸跟第一張圖相同的圖片、或至少是張相似尺寸的圖片。
  2. +
  3. 將圖片存放到 images 資料夾內。
  4. +
  5. 編輯您的 main.js 檔案,並且將以下的 JavaScript 輸入到檔案內(如果您還有看見那段 hello world 的 JavaScript,請把她們給刪除): +
    var myImage = document.querySelector('img');
    +
    +myImage.onclick = function() {
    +    let mySrc = myImage.getAttribute('src');
    +    if(mySrc === 'images/firefox-icon.png') {
    +      myImage.setAttribute ('src','images/firefox2.png');
    +    } else {
    +      myImage.setAttribute ('src','images/firefox-icon.png');
    +    }
    +}
    +
  6. +
  7. 請將全部檔案儲存,並用瀏覽器開啟 index.html。現在請您點選圖片,她應該會切換成另外一張!
  8. +
+ +

在這裡,我們把一個圖片元素的參考存進了 myImage 變數裡。接著,我們把這個變數的 onclick 事件處理器設定為一個匿名函式。現在,每當這個圖片被點選一次:

+ +
    +
  1. 我們會去取得圖片中 src 屬性的數值
  2. +
  3. 我們用一個條件判斷式,來檢查 src 的數值是否跟原始圖片的位址相同: +
      +
    1. 如果兩者相同,那我們就把 src 的數值更改為第二個圖片的位址,也就是在  {{htmlelement("image")}} 元素裡強迫讀取另外一張圖片。
    2. +
    3. 如果兩者不同(也就是圖片已經被切換過了),我們就把 src 的數值更改為原始圖片的位址,圖片就會被切換回原來那張。
    4. +
    +
  4. +
+ +

添加個客製化的歡迎訊息

+ +

接著我們再來添加一些程式碼,在使用者瀏覽這個網頁的時候,將網頁標題改為客製化的歡迎訊息。這個歡迎訊息會一直保留著,直到使用者離開這個網頁為止。我們也會添加個切換使用者的選項,並且一併更改歡迎訊息。

+ +
    +
  1. 編輯 index.html 檔案,並將下列程式碼置於 {{htmlelement("script")}} 元素之前: + +
    <button>Change user</button>
    +
  2. +
  3. 編輯 main.js 檔案,並將下列程式碼一字不漏地置於檔案的最末端 — 這些程式碼將會取得新按鈕、標題的參考,並把它們存在變數裡: +
    var myButton = document.querySelector('button');
    +var myHeading = document.querySelector('h1');
    +
  4. +
  5. 現在,將以下的函式加進去以設定客製化的歡迎訊息 — 這些函式目前還不會產生作用,但我們等一下會用到她們: +
    function setUserName() {
    +  let myName = prompt('Please enter your name.');
    +  localStorage.setItem('name', myName);
    +  myHeading.innerHTML = 'Mozilla is cool, ' + myName;
    +}
    + 這個函式包含了一個會產生一個對話視窗的 prompt() 函式,有點像 alert(),只是 prompt() 會要求使用者輸入一些資料,並在使用者點選確認之後,將內容儲存在一個變數裡面。接著,我們呼叫一個名稱為 localStorage 的 API,這個 API 可以讓使用者先將一些資料儲存在瀏覽器裡面,之後有需要的話再取出來使用。我們使用 localStorage 的 setItem() 函式來建立並且把資料儲存到一個名稱為 'name' 的變數裡,再把包含者用者名字的 myName 的值指定給她。最後,我們將一個字串跟使用者的名字指定給標題的 innerHTML 特性:
  6. +
  7. 接著,加入這個 if ... else 區塊 — 因為她會在程式一開始被讀取的時候就被啟用,我們稱她為初始化程式碼: +
    if(!localStorage.getItem('name')) {
    +  setUserName();
    +} else {
    +  let storedName = localStorage.getItem('name');
    +  myHeading.innerHTML = 'Mozilla is cool, ' + storedName;
    +}
    + 這個區塊一開始使用了邏輯負運算子(邏輯非)來檢查 name 這個物件是否存在。如果沒有,那就執行 setUserName() 這個函式並且創造她。如果有了(例如:使用者已經在上一次造訪網頁時就設定過了),我們就使用 getItem() 函式來取得儲存的名字,並且將標題的 innerHTML 特性設定為一個字串加上使用者的名字,也就是我們在 setUserName() 函式裡做的事情。
  8. +
  9. 最後,把以下的 onclick 事件處理器跟按鈕綁定,如此一來,每次點選按鈕時就會執行 setUserName()。這將允許使用者透過點選那個按鈕來重新設定一個新的名字: +
    myButton.onclick = function() {
    +  setUserName();
    +}
    +
    +
  10. +
+ +

現在當您造訪這個網頁時,她會詢問您的名字,並且給您一個客製化過的歡迎訊息。在這之後,您也可以隨時透過點選那個按鈕來更改名字。順帶一提,因為這組客製化過的訊息是存在 localStorage 裡的,所以即使您將網頁關起來,她還是會保留著,所以當您下次開啟這個網頁時,這段客製化的訊息依然會出現!

+ +

用戶名稱是否為null

+ +

當您運行範例並出現提示您輸入用戶名稱的對話框時,請嘗試按下取消 鈕。您會看到一個標題顯示著"Mozilla is cool, null"。這是因為當您取消提示時,該值將會被設為null。null在Javascript中的一個特殊值,基本上用來表示沒有任何值。

+ +

再試試按下OK,但不輸入任何名字。您將會看到"Mozilla is cool,",該結果的原因非常簡單的可以理解。

+ +

如果你想避免產生這些問題,您應該檢查使用者是否輸入了null或是空白的名字。試著透過修改setUserName()來應對這些問題,結果如下:

+ +
function setUserName() {
+  let myName = prompt('Please enter your name.');
+  if(!myName || myName === null) {
+    setUserName();
+  } else {
+    localStorage.setItem('name', myName);
+    myHeading.innerHTML = 'Mozilla is cool, ' + myName;
+  }
+}
+ +

用人類的語言來理解,如果myName沒有值或是它的值是null,再次從頭執行setUserName()。如果myName有值(如果上述條件是不為真).將值存入localStorage並將值設定給標頭檔的文件。

+ +

結語

+ +

如果您已經照著這篇文章的所有步驟做完了,您應該會看到以下的畫面(或者您也可以瀏覽我們製作的版本):

+ +

+ +

如果在過程中遇到了任何問題,您也可以隨時把您的成品與我們 放在 Github 上的範例 相互對照。

+ +

在此,我們只稍稍體驗了 JavaScript 的一些皮毛。如果您非常享受這段學習的過程,並想要繼續深究,請您繼續瀏覽我們製作的 JavaScript 指南

+ +

See also

+ +
+
JavaScript — Dynamic client-side scripting
+
Our JavaScript learning topic — dive into JavaScript in much more detail.
+
Learn JavaScript
+
An excellent resource for aspiring web developers — Learn JavaScript in an interactive environment, with short lessons and interactive tests, guided by automated assessment. The first 40 lessons are free, and the complete course is available for a small one-time payment.
+
+ +

{{PreviousMenuNext("Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/getting_started_with_the_web/publishing_your_website/index.html b/files/zh-tw/learn/getting_started_with_the_web/publishing_your_website/index.html new file mode 100644 index 0000000000..355291387a --- /dev/null +++ b/files/zh-tw/learn/getting_started_with_the_web/publishing_your_website/index.html @@ -0,0 +1,116 @@ +--- +title: 將你的網站發佈上線 +slug: Learn/Getting_started_with_the_web/Publishing_your_website +translation_of: Learn/Getting_started_with_the_web/Publishing_your_website +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web/How_the_Web_works", "Learn/Getting_started_with_the_web")}}
+ +
+

當你完成你的網頁程式碼後,你需要把它放到網路上,這樣人們才可以搜尋得到。這個章節將介紹如何快速的把你的程式碼放到網路上。

+
+ +

有哪些選項?

+ +

發佈網站並不是一個幾句話就能說得完的課題,主要是因為有太多方法能夠發佈網站。在這個章節中,我們不會介紹所有可能的方法,但是我們會簡單講解三個概念,並從初學者的角度分別說明它們的優缺點,然後一步一步帶你用一個你現階段有辦法完成的方法發佈網站。

+ +

取得主機(hosting)和網域名稱(domain name)

+ +

如果想要完全掌控你發佈的網站,那你可能需要花錢買:

+ + + +

許多專業的網站是用這個方法發佈的。

+ +

除此之外,你還會需要一個 {{Glossary("FTP", "File Transfer Protocol (FTP)")}} 程式(點選How much does it cost: software 來取得更多資訊),這樣才能真正的把你建置的網頁檔案傳達給伺服器。FTP 程式很廣泛,但一般來說,你可以用你公司提供的資訊,像是使用者名稱、密碼以及host name來登入你的網頁伺服器,它就會以兩個視窗的形式分別顯示你電腦裡的檔案和你網頁伺服器上的檔案,然後你就可以移動你的檔案。

+ +

+ +

租借主機和網域的方法

+ + + +

使用線上工具,像是 GitHub 或 Google App Engine

+ +

使用工具來發佈網站:

+ + + +

這類工具和託管不同,通常他們都是免費的,不過功能當然也會受限。

+ +

透過如 Thimble 這樣的網路 IDE

+ +

有些 web app 會模擬網站的開發環境,讓你能執行 HTML, CSS, JavaScript,顯示程式碼執行結果、並渲染至網站上--一切都在瀏覽器的一個頁籤內完成。通常這些工具用起來都簡單、學起來簡單、基本功能還是免費的。他們用獨一無二的網址,替你保管渲染好的頁面。不過,基本功能基本上很受限,而且 app 通常都不提供如圖像這種 asset 的託管。

+ +

試試以下網站,看看你能想到什麼點子:

+ + + +

+ +

透過 GitHub 發布

+ +

來看看把網站用 Github Pages 發佈多簡單。

+ +
    +
  1. 首先註冊 GitHub 並驗證電子郵件。
  2. +
  3. 接著針對要上傳的檔案建立一個 repository
  4. +
  5. 在頁面的 Repository name 標籤輸入 username.github.io,username 是指你的用戶名。例如我們的好朋友 bobsmith 就會輸入 bobsmith.github.io.
    + 另外,請勾選 Initialize this repository with a README 後點選 Create repository
  6. +
  7. 之後,把網站內容拖曳到 repository 目錄,並勾選 Commit changes。 +
    +

    :請確定目錄內有 index.html 檔案。

    +
    +
  8. +
  9. +

    現在讓瀏覽器連到 username.github.io 來看看你的網站。例如你的用戶名字是 chrisdavidmills,就連到 chrisdavidmills.github.io

    + +
    +

    :讓網站上線需要一點時間。如果網站沒有馬上運行,稍等一段時間後再試一次。

    +
    +
  10. +
+ +

想多理解的話,請參考 GitHub Pages Help.

+ +

參閱

+ + + +

{{PreviousMenuNext("Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web/How_the_Web_works", "Learn/Getting_started_with_the_web")}}

+ +

在本模組內

+ + diff --git a/files/zh-tw/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html b/files/zh-tw/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html new file mode 100644 index 0000000000..cb753a09d2 --- /dev/null +++ b/files/zh-tw/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html @@ -0,0 +1,108 @@ +--- +title: 你的網站看起來會是什麼樣子? +slug: Learn/Getting_started_with_the_web/What_will_your_website_look_like +translation_of: Learn/Getting_started_with_the_web/What_will_your_website_look_like +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Getting_started_with_the_web/Installing_basic_software", "Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web")}}
+ +
+

你的網站看起來會是什麼樣子?會說明你該為網站做的規劃與設計,決定自己的「網站該提供哪些資訊?」、「該使用哪些字型與色彩?」,以及「網站又該達到哪些目的?」

+
+ +

首要:規劃

+ +

做任何事之前都需要一些想法。你的網站要達到哪種目的?任何 1 個網站均具備基本作用,但首先你應該保持簡單。我們要先寫出包含了標題、圖像,以及數段文字的簡單網頁。

+ +

開始之前,請你先回答下列問題:

+ +
    +
  1. 你網站的主題為何?你喜歡貓貓狗狗?想寫城市遊記?或你愛打電動呢?
  2. +
  3. 你對某個主題所提供的資訊到哪種程度?寫個標題加上幾段文字,或是在網頁上加個圖片。
  4. +
  5. 簡單的問:你網站的外觀為何?背景顏色?哪種字型比較合適?一般字型?卡通化的字型?又粗又大的字體?還是要纖細淡化的文字呢?
  6. +
+ +
+

注意:複雜專案就需要更詳細的建構指南,包含所用的顏色、字型、物件之間的留白空間、適合的書寫風格,等等。這些要素有時會統整為設計指南或品牌手冊,你可參閱〈Firefox OS Guidelines〉進一步了解。

+
+ +

從頭設計

+ +

接著就是拿紙筆,概略畫出你理想的網站外觀。對自己的第一個簡易網頁,不需考量太多要素或畫得太仔細,應該先養成這個勾勒草圖的習慣。不是要你變成梵谷或畢卡索,但對你以後絕對有幫助!

+ +

+ +
+

注意:即便是實際的複雜網站,設計團隊也都會先在紙上勾勒草圖,再接著透過圖檔編輯器或 Web 技術弄出數位版的草稿。

+ +

Web 團隊往往編制了圖像設計師與{{Glossary("UX", "使用者經驗")}} (User Experience;UX) 設計師各 1 名。圖像設計師當然是負責整合網站的視覺效果;較屬抽象角色的 UX 設計師則要確定使用者與網站的互動方式。

+
+ +

選擇網頁風格

+ +

現在開始組合你想在網頁上呈現的內容。

+ +

文字

+ +

你應該已經準備好了一些文章並分好段落。

+ +

主題色彩

+ +

可透過選色工具找到你喜歡的顏色。當你點擊其中一種顏色,就會看到如下圖「#660066」的 6 位數字,此即代表該顏色的十六進位 (Hexadecimal) 色碼。請另外找個地方記錄此色碼。

+ +

+ +

圖片

+ +

可透過 Google 的圖片搜尋找到適合的圖片。

+ +
    +
  1. 找到你想要的圖片時,點選該圖片。
  2. +
  3. 按下「查看圖片」按鈕。
  4. +
  5. 接著在圖片上點擊滑鼠右鍵 (Mac 則是 Ctrl + click),選擇「將圖片另存新檔...」,將圖片儲存到你熟悉的位置。或是可複製瀏覽器網址列中的網址,以待往後使用。
  6. +
+ +

+ +

+ +
+

注意:在網路上可找到的大多數圖片,包含 Google 圖片服務在內,都已註冊了著作權。為了避免自己可能違反著作權法,你可以透過 Google 的授權篩選功能。只要點擊「搜尋工具」再找到「使用權限」即可:

+ +

+
+ +

字型

+ +

選用自己喜歡的字型:

+ +
    +
  1. Google Fonts 上捲動清單,直找到你喜歡的字型。你也可以使用左邊的控制功能先行篩選。
  2. +
  3. 點擊你想要的字型旁邊「Add to collection」按鈕。
  4. +
  5. 點擊頁面底端的「使用 (Use)」按鈕。
  6. +
  7. 進入下一頁,捲動到區塊 3 與區塊 4,將 Google 顯示的程式碼複製到你的文字編輯器中,儲存以待稍後利用。
  8. +
+ +

+ +

 

+ +

+ +

{{PreviousMenuNext("Learn/Getting_started_with_the_web/Installing_basic_software", "Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web")}}

+ +

In this module

+ + + +

 

diff --git a/files/zh-tw/learn/how_to_contribute/index.html b/files/zh-tw/learn/how_to_contribute/index.html new file mode 100644 index 0000000000..f8a864b98d --- /dev/null +++ b/files/zh-tw/learn/how_to_contribute/index.html @@ -0,0 +1,81 @@ +--- +title: 如何建設 MDN 學習專區 +slug: Learn/How_to_contribute +tags: + - Documentation + - 初學者 + - 貢獻 +translation_of: Learn/How_to_contribute +--- +
{{LearnSidebar}}
+ +

無論你是初來乍到、抑或尋至深處無怨尤、都應該是對貢獻 MDN 學習專區起了興趣吧。那很棒!

+ +

在這裡,你會看到該如何改進 MDN 學習專區的內容。視你的時間多寡、以及你是初學者網路開發者教師而定,有一些你可以完成的事情。

+ +
+

注意:你可以在如何撰寫幫助別人理解 Web 的文章裡面找到指引如何撰寫學習專區的新文章。

+
+ +

找到特定的任務

+ +

貢獻者們使用 Trello board 來組織工作事務。你可以透過這個方法,找出某個專案的工作。要加入的話,只要 建立一個 Trello 的帳號、然後去 ping Chris Mills 叫他給你撰寫 board 的權限。

+ +

Contributing is a great way to have some fun while learning new stuff. If you ever feel lost or have questions, don't hesitate to reach us on our mailing list or IRC channel (see at the bottom of this page for details). Chris Mills is the topic driver for the Learning Area — you could also try pinging him directly.

+ +

接下來的章節,會提供一些在你所能下的常見點子。

+ +

我是初學者

+ +

真棒!初學者在學習專區的創建與給予回饋,不但重要還很寶貴。身為目標閱聽者的你能在文章方面,提供令你成為團內重要成員的獨特觀點。如果你透過這些文章學習卻碰上問題、或是在某些地方稿不清楚,你可以自己去改它、或告訴我們以便我們修正之。

+ +

我們建議你可以透過以下方法貢獻:

+ +
+
給我們的文章添加標籤(約五分鐘)
+
給 MDN 的文章添加標籤,是向 MDN 貢獻的最簡單方法。我們有很多功能會透過標籤助以呈現內文資訊,所以幫忙標籤的建設相當寶貴。從沒有任何標籤的術語表以及學習專區開始吧。
+
閱讀並評價術語表(約五分鐘)
+
我們需要身為初學者的眼光,來檢視我們的內容。如果你發現某個術語難以理解,就表示該術語需要改進。你可以作任何認為有需要的更動。如果你不認為自己有修改該術語的技能,至少請透過我們的郵件清單告訴我們。
+
撰寫新的術語(約二十分鐘)
+
這是最有效的新技能學習法。選一個你想理解的概念去研究。接著,撰寫這個術語。和別人解釋,是「固著」你腦內知識的好方法。既幫自己理解所知、也幫了其他人。利人利己,大家都贏!
+
閱讀並評價術語表學習專區的文章(約兩小時)
+
和閱讀術語表差不多,但因為文章會更長了些,所以要花更多時間。
+
+ +

我是網路開發者

+ +

好極了!我們需要你的技能,來確保我們教給初學者的內容正確無誤。因為這裡的宗旨是理解網路,請確保解釋儘可能簡單,但不致毫無用處。比起過度精確,可以理解才是最重要的。

+ +
+
閱讀並評價術語表(約五分鐘)
+
我們需要你確認文章的內容是正確又不過於艱澀難懂的。請你變更任何你認為有必要改善的地方。如果你想要在做變更之前討論一下內容,歡迎透過 our mailing list 或 IRC channel通知我們。
+
撰寫新的術語(約二十分鐘)
+
闡明術語是一個簡單又精確的學習方式,初學者還會感激你。我們有很多尚未定義的用詞需要你的協助,挑一個你擅長的吧。
+
閱讀並評價術語表學習專區的文章(約兩小時)
+
這跟評價數語表一樣(如上述),只是這些文章的篇幅更常,需要花更多的時間。
+
撰寫新的學習專區文章 (約四小時或更多)
+
MDN缺少簡單易懂的網頁技術相關文章(例如HTML, CSS, JavaScript)。我們也有較舊的文章需要重新審視並修正,請你將技能發揮到極致,讓初學者也能使用網頁技術。
+
提供練習題、範例或是互動式的教學工具。(? 小時)
+
我們所有的文章都需要 "active learning" 的素材在內,因為讓人們學習的最好途徑就是讓他們自己實作。這些素材會是練習題或互動式的內容,能協助使用者將文章內詳述的概念實際運用。有很多方式能夠製作 "active learning" 的內容,像是使用 JSFiddle 或相似的工具提供範例程式碼,或使用Thimble提供互動式的內容。 好好發揮你得創造力吧!
+
+ +

我是教師

+ +

MDN 有著精良的技術史,但我們對教導新人觀念的最佳方法,缺乏深入了解。針對這方面,我們需要借重做為教師或導師身份的你。你能幫我們確保給讀者們的內容,有著良好而實用的教育路徑(educational track)。

+ +
+
閱讀並評價術語表(約十五分鐘)
+
Check out a glossary entry and feel free to make any changes you think are necessary. If you want to discuss the content before editing, ping us on our mailing list or IRC channel.
+
撰寫新的術語(約一小時)
+
Clear, simple definitions of terms and basic overviews of concepts in the glossary are critical in meeting beginners' needs. Your experience as an educator can help create excellent glossary entries; we have many undefined terms which need your attention. Pick one and go for it.
+
添加實例或圖表至文章 (約一小時)
+
As you might know, illustrations are an invaluable part of any learning content. This is something we often lack on MDN and your skills can make a difference in that area. Check out the articles that lack illustrative content and pick one you'd like to create graphics for.
+
閱讀並審核教學文章 (約兩小時)
+
This is similar to reviewing glossary entries (see above), but it requires more time since the articles are typically quite a bit longer.
+
撰寫新的教學文章 (約四小時)
+
We need simple, straightforward articles about the Web ecosystem and other functional topics around it. Since these learning articles need to be educational rather than trying to literally cover everything there is to know, your experience in knowing what to cover and how will be a great asset.
+
建立練習題,測驗或是互動式的學習工具(? 小時)
+
All our learning articles require "active learning" materials. Such materials are exercises or interactive content which help a user learn to use and expand upon the concepts detailed in an article.  There are lots of things you can do here, from creating quizzes to building fully hackable interactive content with Thimble. Unleash your creativity!
+
建立學習途徑 (? 小時)
+
In order to provide progressive and comprehensible tutorials, we need to shape our content into pathways. It's a way to gather existing content and figure out what is missing to create a learning article to write.
+
diff --git a/files/zh-tw/learn/html/forms/how_to_structure_an_html_form/index.html b/files/zh-tw/learn/html/forms/how_to_structure_an_html_form/index.html new file mode 100644 index 0000000000..b403666795 --- /dev/null +++ b/files/zh-tw/learn/html/forms/how_to_structure_an_html_form/index.html @@ -0,0 +1,315 @@ +--- +title: 如何建構 HTML 表單 +slug: Learn/HTML/Forms/How_to_structure_an_HTML_form +translation_of: Learn/Forms/How_to_structure_a_web_form +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Forms/Your_first_form", "Learn/Forms/Basic_native_form_controls", "Learn/Forms")}}
+ +

有了基礎後,我們就能探討表單元素,所提供的結構與文意之詳細資訊;還有各表單部份的相異之處。

+ + + + + + + + + + + + +
先決條件:對電腦還有 HTML 有基本理解。
目標:理解如何構建 HTML 表單並給予無障礙的語意化。
+ +

表單表單的彈性化令其成為 HTML 最複雜的結構之一。你能使用專用的表單元素和屬性,來構建任何類型的基本表單。使用正確的 HTML 表單結構能讓確保表單可用、且無障礙

+ +

<form> 元素

+ +

{{HTMLElement("form")}} 元素會形式上的定義表單和決定行為屬性。每次建立 HTML 表單時,都必須使用 form 元素;並將所有內容嵌進去。大多數的輔助技術與瀏覽器套件,都能抓到 {{HTMLElement("form")}} 元素,並實做特殊的 hook,使其更易於使用。

+ +

我們之前就講過這件事了。

+ +
注意:絕對不能在表單裡面再嵌入表單。這會讓表單行為變得難以理解,所以是一個壞主意。
+ +

你可以從表單外面控制 {{HTMLElement("form")}} 。這麼做的話,除非使用 form 將其與表單關聯,否則該操作預設上和任何表單無關。引入此功能是為了可以在即使該操作未嵌在表單中,其依舊能顯式地將操作與表單綁定。

+ +

接下來就開始探討表單裡面可能會嵌入什麼吧。

+ +

<fieldset> and <legend> 元素

+ +

{{HTMLElement("fieldset")}} 元素能方便地建立用途相近、樣式及語意化都很方便的小部件組(groups of widgets)。你可以透過添加 {{HTMLElement("legend")}} 來給 {{HTMLElement("fieldset")}} 的內部開頭添加標籤。{{HTMLElement("legend")}} 的文字內容能描述 {{HTMLElement("legend")}} 目的。

+ +

多數輔助科技會在 {{HTMLElement("legend")}} 元素被 {{HTMLElement("fieldset")}} 包住時偵測並使用它。比如說 JawsNVDA 之類的螢幕報讀器就會在讀到每個控件的標籤前,讀出 legend 的內容。

+ +

下面就有一個示例:

+ +
<form>
+  <fieldset>
+    <legend>Fruit juice size</legend>
+    <p>
+      <input type="radio" name="size" id="size_1" value="small">
+      <label for="size_1">Small</label>
+    </p>
+    <p>
+      <input type="radio" name="size" id="size_2" value="medium">
+      <label for="size_2">Medium</label>
+    </p>
+    <p>
+      <input type="radio" name="size" id="size_3" value="large">
+      <label for="size_3">Large</label>
+    </p>
+  </fieldset>
+</form>
+ +
+

:你可以在fieldset-legend.html 觀察範例(或著觀察這個動態互動)。

+
+ +

在閱讀表單時,螢幕報讀器會針對第一個小部件組,說出「Fruit juice size small」、接著針對第二個小部件組,說出「Fruit juice size medium」、第三個則是「Fruit juice size large」。

+ +

這個示例的是最重要的用法之一:每次有一組 radio 按鈕時,就該在裡面放一個 {{HTMLElement("fieldset")}} 元素。{{HTMLElement("fieldset")}} 也能用在表單的其他地方。理想上,要是表單一長,就要把他放到其他頁面。但如果做不到這點,那將不同的相關部分,放在不同的 fieldsets 之中,也可以提高可用性。

+ +

由於 {{HTMLElement("fieldset")}} 對輔助技術的影響,這個元素是建立無障礙表單的基石,但請注意不要濫用這個元素。可以的話,聽聽螢幕報讀是怎麼講的。如果踢起來怪怪的,那就試著改進表單。

+ +

<label> 元素

+ +

正如上篇文章中所見,{{HTMLElement("label")}} 元素是定義 HTML 表單控件的正式方法。如果要構建無障礙的表單,這是最重要的元素:正確實做後,螢幕閱讀器會說出表單元素標籤、以及相關說明,同時也對有視力的用戶很有用。以這個例子為例,我們在上一篇文章中看過:

+ +
<label for="name">Name:</label> <input type="text" id="name" name="user_name">
+ +

<label> 元素透過 for 屬性與 <input> 元素的 id 屬性正確連結後,螢幕閱讀器就會讀出「Name, edit text」這樣的文字。

+ +

還有另一種控制標籤與表單控件關聯的方法:那就是把表單控件嵌在 <label> 元素裡面,以便隱式關聯。

+ +
<label for="name">
+  Name: <input type="text" id="name" name="user_name">
+</label>
+ +

但即使在這種情況下,最好還是設置 for 屬性,以確保所有輔具都能理解標籤和控件之間的關係。

+ +

如果沒有標籤、或著說表單控件沒有被顯式或隱式關聯,螢幕閱讀器會讀出沒啥幫助的「Edit text blank」。

+ +

標籤也能點喔!

+ +

使用標籤的另一個好處,就是能在點選該標籤後,啟動相對應的小部件。這種功能在控制文字輸入的時候會很好用:用戶點選標籤時就可以 focus 到 input 那邊。這對 button 與 checkbox 尤其有用:因為點選的區域可能很小,因此使它盡可能簡單地啟用,會是很有用的。

+ +

例如在下面的示例中,點選「I like cherry」標籤文字後會切換 taste_cherry checkbox 的點選狀態:

+ +
<form>
+  <p>
+    <input type="checkbox" id="taste_1" name="taste_cherry" value="cherry">
+    <label for="taste_1">I like cherry</label>
+  </p>
+  <p>
+    <input type="checkbox" id="taste_2" name="taste_banana" value="banana">
+    <label for="taste_2">I like banana</label>
+  </p>
+</form>
+ +
+

:你可以在 checkbox-label.html 觀察示例(這裡有展示版本!

+
+ +

多個標籤

+ +

嚴格來說,一個小部件組能放很多個標籤,但由於部分輔助科技處理上會有問題,所以這也不是個好點子。如果有多個標籤,請試著把巢狀各個小部件,並在裡面只安插一個 {{htmlelement("label")}} 元素。

+ +

來看看這個例子:

+ +
<p>Required fields are followed by <abbr title="required">*</abbr>.</p>
+
+<!-- So this: -->
+<div>
+  <label for="username">Name:</label>
+  <input id="username" type="text" name="username">
+  <label for="username"><abbr title="required" aria-label="required">*</abbr></label>
+</div>
+
+<!-- would be better done like this: -->
+<div>
+  <label for="username">
+    <span>Name:</span>
+    <input id="username" type="text" name="username">
+    <abbr title="required" aria-label="required">*</abbr>
+  </label>
+</div>
+
+<!-- But this is probably best: -->
+<div>
+  <label for="username">Name: <abbr title="required" aria-label="required">*</abbr></label>
+  <input id="username" type="text" name="username">
+</div>
+ +

{{EmbedLiveSample("Multiple_labels", 120, 120)}}

+ +

The paragraph at the top states a rule for required elements. The rule must be included before it is used so that sighted users and users of assistive technologies such as screen readers can learn what it means before they encounter a required element. While this helps inform users what an asterisk means, it can not be relied upon. A screen reader will speak an asterisk as "star" when encountered. When hovered by a sighted mouse user, "required" should appear, which is achieved by use of the title attribute. Titles being read aloud depend on the screen reader's settings, so it is more reliable to also include the aria-label attribute, which is always read by screen readers.

+ +

The above variants increase in effectiveness as you go through them:

+ + + +
+

Note: You might get slightly different results, depending on your screenreader. This was tested in VoiceOver (and NVDA behaves similarly). We'd love to hear about your experiences too.

+
+ +
+

Note: You can find this example on GitHub as required-labels.html (see it live also). don't test the example with 2 or 3 of the versions uncommented — screenreaders will definitely get confused if you have multiple labels AND multiple inputs with the same ID!

+
+ +

建立表單所常用的 HTML 結構

+ +

Beyond the structures specific to web forms, it's good to remember that form markup is just HTML. This means that you can use all the power of HTML to structure a web form.

+ +

As you can see in the examples, it's common practice to wrap a label and its widget with a {{HTMLElement("li")}} element within a {{HTMLElement("ul")}} or {{HTMLElement("ol")}} list. {{HTMLElement("p")}} and {{HTMLElement("div")}} elements are also commonly used. Lists are recommended for structuring multiple checkboxes or radio buttons.

+ +

In addition to the {{HTMLElement("fieldset")}} element, it's also common practice to use HTML titles (e.g. {{htmlelement("h1")}}, {{htmlelement("h2")}}) and sectioning (e.g. {{htmlelement("section")}}) to structure complex forms.

+ +

Above all, it is up to you to find a comfortable coding style that results in accessible, usable forms. Each separate section of functionality should be contained in a separate {{htmlelement("section")}} element, with {{htmlelement("fieldset")}} elements to contain radio buttons.

+ +

主動學習:建立表單結構

+ +

Let's put these ideas into practice and build a slightly more involved form — a payment form. This form will contain a number of control types that you may not yet understand. Don't worry about this for now; you'll find out how they work in the next article (Basic native form controls). For now, read the descriptions carefully as you follow the below instructions, and start to form an appreciation of which wrapper elements we are using to structure the form, and why.

+ +
    +
  1. To start with, make a local copy of our blank template file and the CSS for our payment form in a new directory on your computer.
  2. +
  3. Apply the CSS to the HTML by adding the following line inside the HTML {{htmlelement("head")}}: +
    <link href="payment-form.css" rel="stylesheet">
    +
  4. +
  5. Next, create your form by adding the outer {{htmlelement("form")}} element: +
    <form>
    +
    +</form>
    +
  6. +
  7. Inside the <form> tags, add a heading and paragraph to inform users how required fields are marked: +
    <h1>Payment form</h1>
    +<p>Required fields are followed by <strong><abbr title="required">*</abbr></strong>.</p>
    +
  8. +
  9. Next we'll add a larger section of code into the form, below our previous entry. Here you'll see that we are wrapping the contact information fields inside a distinct {{htmlelement("section")}} element. Moreover, we have a set of two radio buttons, each of which we are putting inside its own list ({{htmlelement("li")}}) element. We also have two standard text {{htmlelement("input")}}s and their associated {{htmlelement("label")}} elements, each contained inside a {{htmlelement("p")}}, and a password input for entering a password. Add this code to your form: +
    <section>
    +    <h2>Contact information</h2>
    +    <fieldset>
    +      <legend>Title</legend>
    +      <ul>
    +          <li>
    +            <label for="title_1">
    +              <input type="radio" id="title_1" name="title" value="K" >
    +              King
    +            </label>
    +          </li>
    +          <li>
    +            <label for="title_2">
    +              <input type="radio" id="title_2" name="title" value="Q">
    +              Queen
    +            </label>
    +          </li>
    +          <li>
    +            <label for="title_3">
    +              <input type="radio" id="title_3" name="title" value="J">
    +              Joker
    +            </label>
    +          </li>
    +      </ul>
    +    </fieldset>
    +    <p>
    +      <label for="name">
    +        <span>Name: </span>
    +        <strong><abbr title="required">*</abbr></strong>
    +      </label>
    +      <input type="text" id="name" name="username">
    +    </p>
    +    <p>
    +      <label for="mail">
    +        <span>E-mail: </span>
    +        <strong><abbr title="required">*</abbr></strong>
    +      </label>
    +      <input type="email" id="mail" name="usermail">
    +    </p>
    +    <p>
    +      <label for="pwd">
    +        <span>Password: </span>
    +        <strong><abbr title="required">*</abbr></strong>
    +      </label>
    +      <input type="password" id="pwd" name="password">
    +    </p>
    +</section>
    +
  10. +
  11. The second <section> of our form is the payment information. We have three distinct controls along with their labels, each contained inside a <p>. The first is a drop-down menu ({{htmlelement("select")}}) for selecting credit card type. The second is an <input> element of type tel, for entering a credit card number; while we could have used the number type, we don't want the number's spinner UI. The last one is an <input> element of type date, for entering the expiration date of the card; this one will come up with a date picker widget in supporting browsers, and fall back to a normal text input in non-supporting browsers. These newer input types are reintroduced in The HTML5 input types.
    +
    + Enter the following below the previous section: +
    <section>
    +    <h2>Payment information</h2>
    +    <p>
    +      <label for="card">
    +        <span>Card type:</span>
    +      </label>
    +      <select id="card" name="usercard">
    +        <option value="visa">Visa</option>
    +        <option value="mc">Mastercard</option>
    +        <option value="amex">American Express</option>
    +      </select>
    +    </p>
    +    <p>
    +      <label for="number">
    +        <span>Card number:</span>
    +        <strong><abbr title="required">*</abbr></strong>
    +      </label>
    +      <input type="tel" id="number" name="cardnumber">
    +    </p>
    +    <p>
    +      <label for="date">
    +        <span>Expiration date:</span>
    +        <strong><abbr title="required">*</abbr></strong>
    +        <em>formatted as mm/dd/yyyy</em>
    +      </label>
    +      <input type="date" id="date" name="expiration">
    +    </p>
    +</section>
    +
  12. +
  13. The last section we'll add is a lot simpler, containing only a {{htmlelement("button")}} of type submit, for submitting the form data. Add this to the bottom of your form now: +
    <p> <button type="submit">Validate the payment</button> </p>
    +
  14. +
+ +

You can see the finished form in action below (also find it on GitHub — see our payment-form.html source and running live):

+ +

{{EmbedLiveSample("A_payment_form","100%",620, "", "Learn/Forms/How_to_structure_a_web_form/Example")}}

+ +

結論

+ +

你現在擁有了正確建構 HTML 表單的所有知識。接下來將介紹本章介紹的許多功能。在下一篇文章中,將詳細探討如何使用各種不同類型的表單小部件,來收集用戶的訊息。

+ +

參見

+ + + +

{{PreviousMenuNext("Learn/Forms/Your_first_form", "Learn/Forms/Basic_native_form_controls", "Learn/Forms")}}

+ +

在本模塊

+ + + +

Advanced Topics

+ + diff --git a/files/zh-tw/learn/html/forms/index.html b/files/zh-tw/learn/html/forms/index.html new file mode 100644 index 0000000000..589880794f --- /dev/null +++ b/files/zh-tw/learn/html/forms/index.html @@ -0,0 +1,359 @@ +--- +title: 網站表單-與數據合作 +slug: Learn/HTML/Forms +tags: + - Featured + - Forms + - Guide + - HTML + - NeedsTranslation + - TopicStub + - Web + - 待翻譯 +translation_of: Learn/Forms +--- +

這篇指南提供了一系列的文章,幫你掌握HTML表單的基本知識。對於與使用者互動,網站表單是一項十分有力的工具,最常使用於用戶數據蒐集,或控制使用者介面。但由於一些歷史與技術上的因素,並沒有顯著的方法發揮表單的潛力。在下面的指引中,我們將介紹網站表單所有基本面向,包括標記他們的HTML結構、設定控制器樣式、驗證數據及將數距提送至伺服器

+ +

參考文章列表

+ +
    +
  1. 我的第一個HTML表單
  2. +
  3. 如何構建 HTML 表單
  4. +
  5. 本機表單控件
  6. +
  7. CSS和HTML表單 +
      +
    1. 造型HTML表單
    2. +
    3. HTML表單高級造型
    4. +
    5. 表單控件屬性兼容表
    6. +
    +
  8. +
  9. 發送和檢索表單數據
  10. +
  11. 數據表單驗證
  12. +
  13. 如何創建自定義表單控件
  14. +
  15. 通過JavaScript發送形式 +
      +
    1. 使用FORMDATA 對象
    2. +
    +
  16. +
  17. 在傳統的瀏覽器的HTML表單
  18. +
+ +

HTML 文件

+ +

HTML 元素

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HTML 元素元素的 DOM interface說明
{{HTMLElement("button")}}{{domxref("HTMLButtonElement")}}按鈕元素表示一個可點擊的按鈕。
{{HTMLElement("datalist")}}{{domxref("HTMLDataListElement")}}數據列表元素包含了一組  {{ HTMLElement("option") }}  表示對其他表單元素的值可能的選擇要素。
{{HTMLElement("fieldset")}}{{domxref("HTMLFieldSetElement")}}字段集是用來在表單中的組數表單元素。
{{HTMLElement("form")}}{{domxref("HTMLFormElement")}}形式元素表示的文件的一部分,它包含使用戶能夠提交信息給web服務器的交互元件。
{{HTMLElement("input")}}{{domxref("HTMLInputElement")}}該  輸入元素用於創建表格的交互式控制。
{{HTMLElement("keygen")}}{{domxref("HTMLKeygenElement")}}所述凱基元素存在,以促進生成的密鑰材料,並提交了公開密鑰的作為HTML形式的一部分
{{HTMLElement("label")}}{{domxref("HTMLLabelElement")}}標籤元素代表一個項目在用戶界面的標題
{{HTMLElement("legend")}}{{domxref("HTMLLegendElement")}}傳說元素代表一個標題為其父 {{ HTMLElement("fieldset") }} 的內容。
{{HTMLElement("meter")}}{{domxref("HTMLMeterElement")}}所述元素表示一個已知的範圍內的任一標量值或分數值。
{{HTMLElement("optgroup")}}{{domxref("HTMLOptGroupElement")}}OPTGROUP元素創建一個 {{ HTMLElement("select") }}  元素中的一組選項。
{{HTMLElement("option")}}{{domxref("HTMLOptionElement")}}在HTML 選項元素用於創建表示  {{ HTMLElement("select") }} ,一個 {{ HTMLElement("optgroup") }}  {{ HTMLElement("datalist") }} 元素中的項目的控制。
{{HTMLElement("output")}}{{domxref("HTMLOutputElement")}}輸出元素表示一個計算的結果。
{{HTMLElement("progress")}}{{domxref("HTMLProgressElement")}}進展元素用於查看任務的完成進度。
{{HTMLElement("select")}}{{domxref("HTMLSelectElement")}}選擇元素代表呈現一個選項菜單的控制。
{{HTMLElement("textarea")}}{{domxref("HTMLTextAreaElement")}}textarea的元素代表多行純文本編輯控制。
+ +
+

注:所有的表單元素,因為所有的HTML元素,支持 {{domxref("HTMLElement")}} DOM接口。

+
+ +

HTML 屬性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
屬性能使用該屬性的 HTML 元素說明
accept{{ HTMLElement("form") }}, {{ HTMLElement("input") }}的類型列表服務器接受,通常是文件類型。
accept-charset{{ HTMLElement("form") }}支持的字符集列表。
action{{ HTMLElement("form") }}一個程序處理通過表單提交的信息的URI。
autocomplete{{ HTMLElement("form") }}, {{ HTMLElement("input") }}指示是否在這個表單控件可以在默認情況下有其值由瀏覽器自動完成。
autofocus{{ HTMLElement("button") }}、 {{ HTMLElement("input") }}、 {{ HTMLElement("keygen") }}、 {{ HTMLElement("select") }}、 {{ HTMLElement("textarea") }}該元素應該在頁面加載後自動聚焦。
challenge{{ HTMLElement("keygen") }}即隨著公共密鑰提交的挑戰字符串。
checked{{ HTMLElement("input") }}指示是否應將元素在頁面加載檢查。
cols{{ HTMLElement("textarea") }}限定在一個textarea的列數。
data{{ HTMLElement("object") }}指定的資源的URL。
dirname{{ HTMLElement("input") }}, {{ HTMLElement("textarea") }}
disabled{{ HTMLElement("button") }} 、{{ HTMLElement("fieldset") }} 、 {{ HTMLElement("input") }} 、 {{ HTMLElement("keygen") }} 、 {{ HTMLElement("optgroup") }} 、 {{ HTMLElement("option") }} 、 {{ HTMLElement("select") }} 、 {{ HTMLElement("textarea")}}表明用戶是否可以與元件進行交互。
enctype{{ HTMLElement("form") }}定義當表單數據的內容類型的方法是POST。
for{{ HTMLElement("label") }}、 {{ HTMLElement("output") }}描述了屬於這一種元素。
form{{ HTMLElement("button") }} 、 {{ HTMLElement("fieldset") }} 、 {{ HTMLElement("input") }} 、 {{ HTMLElement("keygen") }} 、 {{ HTMLElement("label") }} 、 {{ HTMLElement("meter") }} 、 {{ HTMLElement("object") }} 、 {{ HTMLElement("output") }} 、 {{ HTMLElement("progress") }} 、 {{ HTMLElement("select") }} 、 {{ HTMLElement("textarea")}}表明是元件的所有者的形式。
high{{ HTMLElement("meter") }}表示下界的上限範圍。
keytype{{ HTMLElement("keygen") }}指定鍵所產生的類型。
list{{ HTMLElement("input") }}標識的預定義的選項的列表,以向用戶建議。
low{{ HTMLElement("meter") }}指示上限較低的範圍內。
max{{ HTMLElement("input") }} 、 {{ HTMLElement("meter") }} 、 {{ HTMLElement("progress") }}指示所允許的最大值。
maxlength{{ HTMLElement("input") }} 、 {{ HTMLElement("textarea") }}定義了在元件允許的字符的最大數目。
method{{HTMLElement("form")}}定義提交表單時使用的HTTP方法。可GET(默認)或POST。
min{{ HTMLElement("input") }} 、 {{ HTMLElement("meter") }}指示所允許的最小值。
multiple{{ HTMLElement("input") }}、 {{ HTMLElement("select") }}表示是否多個值所用的類型的輸入可以輸入電子郵件文件
name{{ HTMLElement("button") }} 、 {{ HTMLElement("form") }} 、 {{ HTMLElement("fieldset") }} 、 {{ HTMLElement("input") }} 、 {{ HTMLElement("keygen") }} 、 {{ HTMLElement("output") }} 、 {{ HTMLElement("select") }} 、 {{ HTMLElement("textarea") }}該元素的名稱。例如所使用的服務器,以確定在表單提交的字段。
novalidate{{ HTMLElement("form") }}此屬性表明,當提交表單應該無法通過驗證。
optimum{{ HTMLElement("meter") }}表示最佳數值。
pattern{{ HTMLElement("input") }}定義一個正則表達式元素的值將針對驗證。
placeholder{{ HTMLElement("input") }}、 {{ HTMLElement("textarea") }}提供一個提示什麼可以在字段中輸入的用戶。
readonly{{ HTMLElement("input") }} 、 {{ HTMLElement("textarea") }}指示該元素是否可以編輯或沒有。
required{{ HTMLElement("input") }} 、 {{ HTMLElement("select") }}、 {{ HTMLElement("textarea") }}指示此元素是否必填。
rows{{ HTMLElement("textarea") }}限定在一個textarea的行數。
selected{{ HTMLElement("option") }}定義了將在頁面加載所選的值。
size{{ HTMLElement("input") }}、 {{ HTMLElement("select") }}限定了元件的寬度(以像素為單位)。如果該元素的類型的屬性是文本密碼那麼它的字符數。
src{{ HTMLElement("img") }}可嵌入內容的URL。
step{{ HTMLElement("input") }}
target{{ HTMLElement("form") }}
type{{ HTMLElement("button") }} 、 {{ HTMLElement("input") }}限定了元件的類型。
usemap{{ HTMLElement("img") }}
value{{ HTMLElement("button") }}、 {{ HTMLElement("option") }}、 {{ HTMLElement("input") }}、 {{ HTMLElement("meter") }}、 {{ HTMLElement("progress") }}定義了將被顯示在頁面上的負載元件的默認值。
wrap{{ HTMLElement("textarea") }}指示文本是否應被包裹或沒有。
+ +

規範性引用文件

+ + + +
+
+
diff --git a/files/zh-tw/learn/html/howto/index.html b/files/zh-tw/learn/html/howto/index.html new file mode 100644 index 0000000000..9a14c26039 --- /dev/null +++ b/files/zh-tw/learn/html/howto/index.html @@ -0,0 +1,150 @@ +--- +title: 使用HTML解決日常問題 +slug: Learn/HTML/Howto +translation_of: Learn/HTML/Howto +--- +
{{LearnSidebar}}
+ +

以下連結會給出 HTML 常見待解問題的方法

+ +
+
+

基本結構

+ +

HTML 文件的最基本結構應用。如果你是 HTML 新手,就先從這裡開始看。

+ + + +

基本文字語法

+ +

HTML 專攻於為文件提供語義資訊,因此 HTML 可以提供使用者更精準的文件資訊傳達方式。

+ + +
+ +
+

超連結

+ +

{{Glossary("hyperlink", "超連結")}}把 HTML 導覽變得相當容易,它可以這麼用:

+ + + +

圖片與多媒體

+ + + +

腳本與樣式

+ +

HTML 只建立文件的基礎架構,可以透過 {{glossary("CSS")}} 或腳本使內容呈現更具互動性。

+ + + +

嵌入內容

+ + +
+
+ +

不常見或進階的問題

+ +

除了上述的基本功能外,HTML 還提供許多進階功能讓使用者解決較複雜的問題。這些文章可以幫助你處理一些較不常見的情況:

+ +
+
+

表單

+ +

Forms are a complex HTML structure made to send data from a webpage to a web server. We encourage you to go over our full dedicated guide. Here is where you should start:

+ + + +

表格訊息

+ +

Some information, called tabular data, needs to be organized into tables with columns and rows. It's one of the most complex HTML structures, and mastering it is not easy:

+ + + +

資料表示方式

+ + + +

互動性

+ + +
+ + +
+ +

     

diff --git a/files/zh-tw/learn/html/index.html b/files/zh-tw/learn/html/index.html new file mode 100644 index 0000000000..897bbcdd5e --- /dev/null +++ b/files/zh-tw/learn/html/index.html @@ -0,0 +1,61 @@ +--- +title: 學習 HTML :指南與教學 +slug: Learn/HTML +tags: + - Beginner + - Guide + - HTML + - Intro + - Learn + - NeedsTranslation + - Topic + - TopicStub + - 初心者 + - 指南 + - 超文本標記語言 +translation_of: Learn/HTML +--- +
{{LearnSidebar}}
+ +

為了建立網頁,你應該要先知道 {{Glossary('「HTML」')}} — 用來建造網站架構的科技。 HTML 是用來辨認網頁中的內容該如何被解讀,例如說被解讀為:一個段落(paragraph)、清單(list)、文件標題(heading)、連結(link)、圖片(images)、多媒體撥放器(multimedia player)、表單(form)或是任何一個可使用的「元素(elements)」,甚至是你自己定義的新元素。

+ +

學習途徑

+ +

理想上,你應該從學習 HTML 開始你的學習旅程。可以先從閱讀 HTML介紹(Introduction to HTML) 開始。接下來你可以開始閱讀以下的進階主題:

+ + + +

當你開始閱讀這主題時,你至少必須對使用電腦有基礎了解,以及會基本的上網 (諸如網頁瀏覽、了解網頁內容)。而你需要建立一個已安裝基本軟體 (詳細軟體請參閱Installing basic software)的基礎工作環境,並且了解如何建立與管理檔案(詳細請參閱Dealing with files) — 這些都包含在新手 Web 入門的章節裡。

+ +

建議你在開始學習 HTML 這個項目之前,可以先 從網際網路開始 瞭解是如何運作的。儘管知道網路的運作不是必要的;大部分的項目都在 HTML basics 的文章中 Introduction to HTML 這個章節更詳盡地介紹 模組 (module), albeit。

+ +

模組

+ +

這主題包含了以下幾個單元, 你可以根據以下順序來閱讀他們。強烈推薦從第一個單元開始讀起。

+ +
+
HTML介紹
+
這個單元為你提供一個平台,讓你熟悉重要的概念和語法、思考如何將HTML應用於文本、如何創建超鏈接以及使用HTML來構建網頁。
+
嵌入多媒體
+
本單元探索如何在你的網頁中使用HTML置入多媒體,包括置入圖像的各種方法,以及如何嵌入影片,聲音檔或甚至其他網頁。
+
表格
+
以一種易於理解、無障礙的方式在網頁上顯示表格數據可能是一個挑戰。此單元涵蓋基本的表格標記以及更複雜的功能,例如實行標題和摘要。
+
+ +

解決常見的 HTML 問題

+ +

利用HTML解決常見問題 提供部分連結,這些內容解釋了在創建網頁時如何使用HTML解決常見的問題:標題,添加圖像或視頻,強調內容,創建基本表單等等。

+ +

或許你還想看......

+ +
+
+
網站表單
+
這篇指南提供了一系列的文章,幫你掌握HTML表單的基本知識。對於與使用者互動,網站表單是一項十分有力的工具,最常使用於用戶數據蒐集,或控制使用者介面。但由於一些歷史與技術上的因素,並沒有顯著的方法發揮表單的潛力。在下面的指引中,我們將介紹網站表單所有基本面向,包括標記他們的HTML結構、設定控制器樣式、驗證數據及將數距提送至伺服器。
+
HTML
+
MDN的HTML參考文件的主要入口,包括詳細的元素和屬性參考-例如,如果您想知道元素具有哪些屬性或屬性具有什麼值,那麼這是一個很好的起點。
+
+
diff --git a/files/zh-tw/learn/html/introduction_to_html/advanced_text_formatting/index.html b/files/zh-tw/learn/html/introduction_to_html/advanced_text_formatting/index.html new file mode 100644 index 0000000000..3b5786613b --- /dev/null +++ b/files/zh-tw/learn/html/introduction_to_html/advanced_text_formatting/index.html @@ -0,0 +1,456 @@ +--- +title: Advanced text formatting +slug: Learn/HTML/Introduction_to_HTML/Advanced_text_formatting +tags: + - HTML +translation_of: Learn/HTML/Introduction_to_HTML/Advanced_text_formatting +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML")}}
+ +

There are many other elements in HTML for formatting text, which we didn't get to in the HTML text fundamentals article. The elements described in this article are less well-known, but still useful to know about (and this is still not a complete list by any means.) In here you'll learn about marking up quotations, description lists, computer code and other related text, subscript and superscript, contact information, and more.

+ + + + + + + + + + + + +
Prerequisites:Basic HTML familiarity, as covered in Getting started with HTML. HTML text formatting, as covered in HTML text fundamentals.
Objective:To learn how to use lesser-known HTML elements to mark up advanced semantic features.
+ +

說明列表

+ +

In HTML text fundamentals, we walked through how to mark up basic lists in HTML, but we didn't mention the third type of list you'll occasionally come across — description lists. The purpose of these lists is to mark up a set of items and their associated descriptions, such as terms and definitions, or questions and answers. Let's look at an example of a set of terms and definitions:

+ +
soliloquy
+In drama, where a character speaks to themselves, representing their inner thoughts or feelings and in the process relaying them to the audience (but not to other characters.)
+monologue
+In drama, where a character speaks their thoughts out loud to share them with the audience and any other characters present.
+aside
+In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of additional background information
+ +

Description lists use a different wrapper than the other list types — {{htmlelement("dl")}}; in addition each term is wrapped in a {{htmlelement("dt")}} (description term) element, and each description is wrapped in a {{htmlelement("dd")}} (description description) element. Let's finish marking up our example:

+ +
<dl>
+  <dt>soliloquy</dt>
+  <dd>In drama, where a character speaks to themselves, representing their inner thoughts or feelings and in the process relaying them to the audience (but not to other characters.)</dd>
+  <dt>monologue</dt>
+  <dd>In drama, where a character speaks their thoughts out loud to share them with the audience and any other characters present.</dd>
+  <dt>aside</dt>
+  <dd>In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of additional background information.</dd>
+</dl>
+ +

The browser default styles will display description lists with the descriptions indented somewhat from the terms. MDN's styles follow this convention fairly closely, but also embolden the terms for extra definition.

+ +
+
soliloquy
+
In drama, where a character speaks to themselves, representing their inner thoughts or feelings and in the process relaying them to the audience (but not to other characters.)
+
monologue
+
In drama, where a character speaks their thoughts out loud to share them with the audience and any other characters present.
+
aside
+
In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of addtional background information.
+
+ +

Note that it is permitted to have a single term with multiple descriptions, for example:

+ +
+
aside
+
In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of additional background information.
+
In writing, a section of content that is related to the current topic, but doesn't fit directly into the main flow of content so is presented nearby (often in a box off to the side.)
+
+ +

Active learning: Marking up a set of definitions

+ +

It's time to try your hand at description lists; add elements to the raw text in the Input field so that it appears as a description list in the Output field. You could try using your own terms and descriptions if you like.

+ +

If you make a mistake, you can always reset it using the Reset button. If you get really stuck, press the Show solution button to see the answer.

+ + + +

{{ EmbedLiveSample('Playable_code', 700, 500) }}

+ +

Quotations

+ +

HTML also has features available for marking up quotations; which element you use depends on whether you are marking up a block or inline quotation.

+ +

Blockquotes

+ +

If a section of block level content (be it a paragraph, multiple paragraphs, a list, etc.) is quoted from somewhere else, you should wrap it inside a {{htmlelement("blockquote")}} element to signify this, and include a URL pointing to the source of the quote inside a {{htmlattrxref("cite","blockquote")}} attribute. For example, the following markup is taken from the MDN <blockquote> element page:

+ +
<p>The <strong>HTML <code>&lt;blockquote&gt;</code> Element</strong> (or <em>HTML Block
+Quotation Element</em>) indicates that the enclosed text is an extended quotation.</p>
+ +

To turn this into a block quote, we would just do this:

+ +
<blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote">
+  <p>The <strong>HTML <code>&lt;blockquote&gt;</code> Element</strong> (or <em>HTML Block
+  Quotation Element</em>) indicates that the enclosed text is an extended quotation.</p>
+</blockquote>
+ +

Browser default styling will render this as an indented paragraph, as an indicator that it is a quote; MDN does this, but also adds some extra styling:

+ +
+

The HTML <blockquote> Element (or HTML Block Quotation Element) indicates that the enclosed text is an extended quotation.

+
+ +

Inline quotations

+ +

Inline quotations work in exactly the same way, except that they use the {{htmlelement("q")}} element. For example, the below bit of markup contains a quotation from the MDN <q> page:

+ +
<p>The quote element — <code>&lt;q&gt;</code> — is <q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q">intended
+for short quotations that don't require paragraph breaks.</q></p>
+ +

Browser default styling will render this as normal text put in quotes to indicate a quotation, like so:

+ +

The quote element — <q> — is intended for short quotations that don't require paragraph breaks.

+ +

Citations

+ +

The content of the {{htmlattrxref("cite","blockquote")}} attribute sounds useful, but unfortunately browsers, screenreaders, etc. don't really do much with it. There is no way to get the browser to display the contents of cite, without writing your own solution using JavaScript or CSS. If you want to make the source of the quotation available on the page, a better way to mark it up is put the {{htmlelement("cite")}} element next to the quote element. This is really meant to contain the name of the quote source — i.e. the name of the book, or name of the person that said the quote — but there is no reason why you couldn't link the text inside <cite> to the quote source in some way:

+ +
<p>According to the <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote">
+<cite>MDN blockquote page</cite></a>:
+</p>
+
+<blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote">
+  <p>The <strong>HTML <code>&lt;blockquote&gt;</code> Element</strong> (or <em>HTML Block
+  Quotation Element</em>) indicates that the enclosed text is an extended quotation.</p>
+</blockquote>
+
+<p>The quote element — <code>&lt;q&gt;</code> — is <q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q">intended
+for short quotations that don't require paragraph breaks.</q> -- <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q">
+<cite>MDN q page</cite></a>.</p>
+ +

Citations are styled in italic font by default. You can see this code at work in our quotations.html example.

+ +

Active learning: Who said that?

+ +

Time for another active learning example! In this example we'd like you to:

+ +
    +
  1. Turn the middle paragraph into a blockquote, which includes a cite attribute.
  2. +
  3. Turn part of the third paragraph into an inline quote, which includes a cite attribute.
  4. +
  5. Include a <cite> element for each quote
  6. +
+ +

Search online to find appropriate quote sources.

+ +

If you make a mistake, you can always reset it using the Reset button. If you get really stuck, press the Show solution button to see the answer.

+ + + +

{{ EmbedLiveSample('Playable_code_2', 700, 500) }}

+ +

Abbreviations

+ +

Another fairly common element you'll meet when looking around the Web is {{htmlelement("abbr")}} — this is used to wrap around an abbreviation or acronym, and provide a full expansion of the term (included inside a {{htmlattrxref("title")}} attribute.) Let's look at a couple of examples:

+ +
<p>We use <abbr title="Hypertext Markup Language">HTML</abbr> to structure our web documents.</p>
+
+<p>I think <abbr title="Reverend">Rev.</abbr> Green did it in the kitchen with the chainsaw.</p>
+ +

These will come out looking something like this (the expansion will appear in a tooltip when the term is hovered over):

+ +

We use HTML to structure our web documents.

+ +

I think Rev. Green did it in the kitchen with the chainsaw.

+ +
+

Note: There is another element, {{htmlelement("acronym")}}, which basically does the same thing as <abbr>, and was intended specifically for acronyms rather than abbreviations. This however has fallen into disuse — it wasn't supported as well in browsers as well as <abbr>, and has such as similar function that it was felt pointless to have both. Just use <abbr> instead.

+
+ +

Active learning: marking up an abbreviation

+ +

For this simple active learning assignment, we'd like you to simply mark up an abbreviation. You can use our sample below, or replace it with one of your own. 

+ + + +

{{ EmbedLiveSample('Playable_code_3', 700, 350) }}

+ +

Marking up contact details

+ +

HTML has an element for marking up contact details — {{htmlelement("address")}}. This simply wraps around your contact details, for example:

+ +
<address>
+  <p>Chris Mills, Manchester, The Grim North, UK</p>
+</address>
+ +

One thing to remember however is that the <address> element is meant for marking up the contact details of the person who wrote the HTML document, not any address. So the above would only be ok if Chris had written the document the markup appears on. Note that something like this would also be ok:

+ +
<address>
+  <p>Page written by <a href="../authors/chris-mills/">Chris Mills</a>.</p>
+</address>
+ +

Superscript and subscript

+ +

You will occasionally need to use superscript and subscript when marking up items like dates, chemical formulae, and mathematical equations so they have the correct meaning. The {{htmlelement("sup")}} and {{htmlelement("sub")}} elements handle this job. For example:

+ +
<p>My birthday is on the 25<sup>th</sup> of May 2001.</p>
+<p>Caffeine's chemical formula is C<sub>8</sub>H<sub>10</sub>N<sub>4</sub>O<sub>2</sub>.</p>
+<p>If x<sup>2</sup> is 9, x must equal 3 or -3.</p>
+ +

The output of this code looks like so:

+ +

My birthday is on the 25th of May 2001.

+ +

Caffeine's chemical formula is C8H10N4O2.

+ +

If x2 is 9, x must equal 3 or -3.

+ +

Representing computer code

+ +

There are a number of elements available for marking up computer code:

+ + + +

Let's look at a few examples. You should try having a play with these (try grabbing a copy of our other-semantics.html sample file):

+ +
<pre><code>var para = document.querySelector('p');
+
+para.onclick = function() {
+  alert('Owww, stop poking me!');
+}</code></pre>
+
+<p>You shouldn't use presentational elements like <code>&lt;font&gt;</code> and <code>&lt;center&gt;</code>.</p>
+
+<p>In the above JavaScript example, <var>para</var> represents a paragraph element.</p>
+
+
+<p>Select all the text with <kbd>Ctrl</kbd>/<kbd>Cmd</kbd> + <kbd>A</kbd>.</p>
+
+<pre>$ <kbd>ping mozilla.org</kbd>
+<samp>PING mozilla.org (63.245.215.20): 56 data bytes
+64 bytes from 63.245.215.20: icmp_seq=0 ttl=40 time=158.233 ms</samp></pre>
+ +

The above code will look like so:

+ +

{{ EmbedLiveSample('Representing_computer_code','100%',300) }}

+ +

Marking up times and dates

+ +

HTML also provides the {{htmlelement("time")}} element for marking up times and dates in a machine-readable format. For example:

+ +
<time datetime="2016-01-20">20 January 2016</time>
+ +

Why is this useful? Well, there are many different ways that humans write down dates. The above date could be written as:

+ + + +

But these different forms cannot be easily recognised by the computers — what if you wanted to automatically grab the dates of all events in a page and insert them into a calendar? The {{htmlelement("time")}} element allows you to attach a unambiguous, machine-readable time/date for this purpose.

+ +

The basic example above just provides a simple machine readable date, but there are many other options that are possible, for example:

+ +
<!-- Standard simple date -->
+<time datetime="2016-01-20">20 January 2016</time>
+<!-- Just year and month -->
+<time datetime="2016-01">January 2016</time>
+<!-- Just month and day -->
+<time datetime="01-20">20 January</time>
+<!-- Just time, hours and minutes -->
+<time datetime="19:30">19:30</time>
+<!-- You can do seconds and milliseconds too! -->
+<time datetime="19:30:01.856">19:30:01.856</time>
+<!-- Date and time -->
+<time datetime="2016-01-20T19:30">7.30pm, 20 January 2016</time>
+<!-- Date and time with timezone offset-->
+<time datetime="2016-01-20T19:30+01:00">7.30pm, 20 January 2016 is 8.30pm in France</time>
+<!-- Calling out a specific week number-->
+<time datetime="2016-W04">The fourth week of 2016</time>
+ +

Summary

+ +

That marks the end of our study of HTML text semantics. Bear in mind that what you have seen during this course is not an exhaustive list of HTML text elements — we wanted to try to cover the essentials, and some of the more common ones you will see in the wild, or at least might find interesting. To find way more HTML elements, you can take a look at our HTML element reference (the Inline text semantics section would be a great place to start.) In the next article we will look at the HTML elements you'd use to structure the different parts of an HTML document.

+ +

{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML")}}

diff --git a/files/zh-tw/learn/html/introduction_to_html/creating_hyperlinks/index.html b/files/zh-tw/learn/html/introduction_to_html/creating_hyperlinks/index.html new file mode 100644 index 0000000000..059cfa427c --- /dev/null +++ b/files/zh-tw/learn/html/introduction_to_html/creating_hyperlinks/index.html @@ -0,0 +1,326 @@ +--- +title: Creating hyperlinks +slug: Learn/HTML/Introduction_to_HTML/Creating_hyperlinks +translation_of: Learn/HTML/Introduction_to_HTML/Creating_hyperlinks +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML")}}
+ +

超連結(Hyperlinks)真的超級重要 — 它造就了我們現今所熟知的網路。這篇文章將會介紹超連結的使用語法,並且探討建立它們的最佳實踐方法。

+ + + + + + + + + + + + +
需求:我們在 HTML 入門 中介紹過的 HTML 基礎,以及在 HTML 的文字基礎知識 中介紹過的文字格式化技巧。
目標:學習如何有效地使用超連結,並利用它們來連結多個檔案。
+ +

什麼是超連結?

+ +

超連結可說是網路中最令人振奮的革新技術。當然啦,早在網路技術萌芽之初,它們就已經在那了,它們正是網路之所以被稱為「網路」的最大原因 — 它讓我們的文件能任意地與其他文件(或者資源)相互連結(或是連結文件中的特定部份),讓我們能透過一個簡單的網路位址來經營我們的網路應用(相較之下,本機應用(native apps)就必須要安裝在主機上才能使用)。幾乎所有的網路內容都能被轉換成一個連結,讓網路瀏覽器在這些連結被點擊或觸發之後,跳轉到該網路位址({{glossary("URL")}})上。

+ +
+

Note: URL 能夠指向 HTML 檔案、純文字檔案、圖片、文字文件、影音檔案等等可存在網路上的東西。如果網路瀏覽器不知道如何顯示或者處理該檔案的話,它會問你想要開啟這個檔案(將檔案交由本機應用來處理)還是要下載該檔案(意即你可以待會兒再處理)。

+
+ +

以 BBC 的主頁為例,裡面就包含了非常多的連結,各自連到不同新聞、網站的其它地方(導覽功能),或者登入/註冊頁面等等。

+ +

frontpage of bbc.co.uk, showing many news items, and navigation menu functionality

+ +

解析連結

+ +

一個基本的連結由 {{htmlelement("a")}} 元素包裹一段文字而成(當然也不一定要是文字,見下方的{{anch("區塊級連結")}}),同時,你需要將網路位址填入 {{htmlattrxref("href", "a")}} 屬性中,這個屬性有時也被叫做超文字參考(Hypertext Reference)目標(target)

+ +
<p>I'm creating a link to
+<a href="https://www.mozilla.org/en-US/">the Mozilla homepage</a>.
+</p>
+ +

這會產生以下結果:

+ +

I'm creating a link to the Mozilla homepage.

+ +

利用 title 屬性來添加額外資訊

+ +

另外一個你可能會想在連結中附加的屬性是 title,它的目的是攜帶一個補充訊息到連結上,好比說目標網頁有什麼樣的資訊,或者是一些警告訊息,範例如下:

+ +
<p>I'm creating a link to
+<a href="https://www.mozilla.org/en-US/"
+   title="The best place to find more information about Mozilla's
+          mission and how to contribute">the Mozilla homepage</a>.
+</p>
+ +

這將會產生以下結果(當游標移到連結上方時,標題會以提示的形式出現):

+ +

I'm creating a link to the Mozilla homepage.

+ +
+

Note: 連結標題只有在游標停在連結上方時才會出現,也就是說那些只依賴鍵盤來瀏覽網頁的人將會很難看到這個訊息,因此,如果說標題資訊對網頁易用性(usability)有著重大影響的話,你應該把它放在大家都看得到的地方,比方說放在一般的文字元素裡。

+
+ +

不要只用看的:建立你自己的範例連結

+ +

主動學習時間!我們想要你用自己的文字編輯器來撰寫一個 HTML 文件(你可以修改我們的入門範本,那應該就很夠用了)。

+ + + + + +

就像先前所提到的,你可以將任何內容轉換成連結,就算是區塊級元素也沒問題!如果你有一張圖片要轉換成連結,你可以把圖片元素放在 <a> 標籤裡,像這樣:

+ +
<a href="https://www.mozilla.org/en-US/">
+  <img src="mozilla-image.png" alt="mozilla logo that links to the mozilla homepage">
+</a>
+ +
+

Note: 在往後的教學中,你還會學到更多的圖片使用技法。

+
+ +

快速理解 URL 和路徑

+ +

在完全搞懂連結標的(link target)之前,你必須要先瞭解什麼是 URL 和檔案路徑,而這個小節就是要帶你來看這些東西。

+ +

URL 全名為 Uniform Resource Locator (一致資源定位器,俗稱網址),是一條用來指出某樣東西在網路上的位址的字串。比如說 Mozilla 的英文主頁就是位在 https://www.mozilla.org/en-US/

+ +

URL 利用路徑來找到檔案,而路徑會指出你所感興趣的檔案位於檔案系統上的什麼地方。現在讓我們來看個簡單的目錄結構範例(請見我們的建立超連結目錄)。

+ +

A simple directory structure. The parent directory is called creating-hyperlinks and contains two files called index.html and contacts.html, and two directories called projects and pdfs, which contain an index.html and a project-brief.pdf file, respectively

+ +

creating-hyperlinks 是這個目錄結構的根目錄(root),當你在本地端撰寫網站時,你會將整個網站都放在這樣的資料夾中。在我們的根目錄裡有 index.htmlcontacts.html 兩個檔案,在現實的情況中,index.html 會是我們的首頁或者登陸頁面(landing page,網站或它的某部份的進入點)。

+ +

我們的根目錄中有兩個子目錄 — pdfsprojects,它們各自都有一個檔案在裡頭,分別是 project-brief.pdfindex.html。請記得,你可以很愉快地在一個專案中擁有兩個 index.html,只要它們處在檔案系統上的不同位址。很多網站都會這麼做,第二個 index.html 可能會拿來當作是與專案有關資訊的主登陸頁面。

+ + + +
+

Note: 你可以將多個這種語法組成一個較為複雜的 URL,例如:../../../complex/path/to/my/file.html

+
+ +

文件片段 (Document fragments)

+ +

並不是每次都只能連到文件的頂端,你也可以連到 HTML 文件中的某個部分,而這個部分叫做文件片段(document fragment)。要做到這件事,你得先為你要連的元素設定 {{htmlattrxref("id")}} 屬性,通常你可以把連結設在標題(heading)上,像是下面這樣:

+ +
<h2 id="Mailing_address">Mailing address</h2>
+ +

要連到特定的 id,你得在你的 URL 的後面加上一個 # 號,像這樣:

+ +
<p>Want to write us a letter? Use our <a href="contacts.html#Mailing_address">mailing address</a>.</p>
+ +

你甚至可以利用文件片段來連到同個文件的其他部分

+ +
<p>The <a href="#Mailing_address">company mailing address</a> can be found at the bottom of this page.</p>
+ +

絕對 URL vs. 相對 URL

+ +

你會在網路上看到兩個名詞,絕對 URL(absolute URL)相對 URL(relative URL):

+ +

絕對 URL:指向網路上的絕對位址,裡頭包含協定({{glossary("protocol")}})和網域名稱({{glossary("domain name")}})。舉個例子,假設一個 web server 的根目錄有一個 projects 目錄,裡面放著一個 index.html,該網站的網域為 http://www.example.com,則網頁可以透過網址 http://www.example.com/projects/index.html 來取得 (或寫成 http://www.example.com/projects/ 也行,因為大多的 web server 都能在 URL 沒有明確指出時,自動找尋如 index.html 之類的登陸頁面)。

+ +

絕對 URL 無論在什麼地方使用,它都會代表同一個位址。

+ +

相對 URL:指向一個檔案的相對位址,這跟我們在先前看到的非常類似。舉例來說,如果我們想要從 http://www.example.com/projects/index.html 連到同一目錄下的 PDF 檔,URL 就只要檔名就好 — 像是 project-brief.pdf — 不需要其它的資訊。如果那個 PDF 放在 projects 中叫做 pdfs 的子目錄裡,其相對連結就是 pdfs/project-brief.pdf (等效的絕對 URL 為 http://www.example.com/projects/pdfs/project-brief.pdf)。

+ +

相對 URL 指向的位址會受到檔案所在的真正位址影響 — 舉例來說,如果我們將 index.html 移出 projects,並放在網站的根目錄中 (也就是在最上層中),裡頭指向 pdfs/project-brief.pdf 的相對 URL 連結會指到 http://www.example.com/pdfs/project-brief.pdf,而非 http://www.example.com/projects/pdfs/project-brief.pdf

+ +

當然,project-brief.pdfpdfs 的位置不會因為你移動 index.html 就改變 — 這會使得你的連結指到錯誤的地方,你一定得非常小心!

+ +

連結的最佳實踐

+ +

撰寫連結時有幾個最佳實踐方法,現在讓我們來看看吧。

+ + + +

使用明確的字詞

+ +

要在你的網頁上加入連結非常簡單,但這還不夠,我們必須確保連結能夠被所有讀者取用到,無論他們的背景或者使用的工具為何。比如說:

+ + + +

我們來看幾個例子:

+ +

好的連結文字:下載 Firefox

+ +
<p><a href="https://firefox.com/">
+  下載 Firefox
+</a></p>
+ +

不好的連結文字:點這裡來下載 Firefox

+ +
<p><a href="https://firefox.com/">
+  點這裡
+</a>
+來下載 Firefox</p>
+
+ +

其它小訣竅:

+ + + +

盡可能使用相對連結

+ +

經過之前的說明,你可能會覺得無論如何都應該採用絕對連結,畢竟它們不會像相對連結一樣,因為頁面被搬移而失效。然而,對於相同網站內的連結,你應該盡量使用相對連結 (連到別的網站的連結必須使用絕對連結),原因如下:

+ + + +

要連到非 HTML 的資源時請先聲明

+ +

當連結連至一個需要下載的資源 (像是 PDF 或 Word 文件) 或是串流 (如影音串流) 或是其他有潛在未知影響的東西 (開啟彈出式視窗或者載入 Flash movie) 時,你應該要加上一些文字來預示,以下就是幾個非常惱人的情境:

+ + + +

讓我們來看一些可以改善這些情況的方法:

+ +
<p><a href="http://www.example.com/large-report.pdf">
+  下載銷售報告(PDF, 10MB)
+</a></p>
+
+<p><a href="http://www.example.com/video-stream/" target="_blank">
+  觀看影片(將在新分頁開啟串流,HD 畫質)
+</a></p>
+
+<p><a href="http://www.example.com/car-game">
+  遊玩賽車遊戲(需要 Flash)
+</a></p>
+ +

當連結會觸發下載時,使用下載屬性

+ +

當你連結一個需要下載的資源時,你可以使用 download 屬性來提供一個預設的儲存檔名。以下範例是最新版的 Windows 版 Firefox 的下載連結:

+ +
<a href="https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US"
+   download="firefox-latest-64bit-installer.exe">
+  下載Windows上的最新版Firefox (64-bit) (English, US)
+</a>
+ +

不要只用看的:建立一個導覽選單

+ +

在這次練習中,我們想要你利用導覽列來將許多網頁連結在一起,創造出一個具有多個頁面的網站。這是一個很常見的網站建造方式 — 每一個網頁都使用同樣的網頁結構,其中包含相同的導覽選單,這樣子一來,當連結被點擊時,會讓人以為還留在原地,但內容卻倏忽更迭。

+ +

你需要先在一個目錄中建立下面這四個網頁的複本 (你可以在 navigation-menu-start 目錄下找到完整的清單):

+ + + +

接著,你可以這麼做:

+ +
    +
  1. 在指定的地方添加一個無序列表,裡面放著可以連到的網頁名稱。因為導覽選單其實就是一個連結的列表,所以這麼做在語義上沒什麼問題。
  2. +
  3. 把每一個網頁名稱變成超連結。
  4. +
  5. 把導覽選單複製到每一個頁面上。
  6. +
  7. 把每個網頁中,連到自己的連結移除,因為這種連結毫無意義且令人困惑,此外,無連結的文字可以用來提示使用者的所在位置。
  8. +
+ +

完成後的範例應該會長這樣:

+ +

An example of a simple HTML navigation menu, with home, pictures, projects, and social menu items

+ +
+

Note: 如果你卡住了,或者不確定有沒有做對,你可以到 navigation-menu-marked-up 目錄來偷瞄答案。

+
+ +

E-mail 連結

+ +

你可以建立一個連結或按鈕,使得它被點擊之後,開啟一個正在撰寫中的電子郵件訊息。這可以透過 {{HTMLElement("a")}} 元素和 mailto: URL scheme 來達成。

+ +

多數情況 mailto: 會填入收信人的電子郵件地址。例如:

+ +
<a href="mailto:nowhere@mozilla.org">Send email to nowhere</a>
+
+ +

它的結果會像是這樣:Send email to nowhere

+ +

事實上,電子郵件地址是選填的。如果你將它留空 (也就是說,你的 {{htmlattrxref("href", "a")}} 只寫了 "mailto:"),使用者的 mail client 會開啟一個寄信視窗,其中並沒有指定收信人,這在使用「分享」連結時非常有用,使用者可以自行決定要寄給誰。

+ +

指定細節

+ +

除了電子郵件地址之外,你還可以提供其他資訊,事實上,任何標準的郵件標頭欄位都能被加到  mailto URL 中,常見的有主旨(subject)、副本(cc)以及主體(body) (這個雖然不是真的標頭欄位,但能讓你放一條簡短的訊息在新郵件的主體中)。每個欄位與它的值被定義成一組查詢項(query term)。

+ +

下面是一個包含 cc、bcc(密件副本)、subject 和 body 的範例:

+ +
<a href="mailto:nowhere@mozilla.org?cc=name2@rapidtables.com&bcc=name3@rapidtables.com&subject=The%20subject%20of%20the%20email&body=The%20body%20of%20the%20email">
+  Send mail with cc, bcc, subject and body
+</a>
+ +
+

Note: 每一個欄位的值必須以 URL 編碼,也就是將空白及不可印字元(不可見的字元如縮排(tabs)、回車(carriage return)、換頁(page breaks)等等)轉換成百分號編碼。也請注意這裡使用問號(?)來分隔主要 URL 和其他欄位;以 & 來分隔 mailto: URL 中的不同的欄位,這是標準的 URL 查詢記號(query notation)。你可以閱讀 GET 方法來得知有那些常用的查詢記號。

+
+ +

以下是 mailto URL 的其他例子:

+ + + +

小試身手!

+ +

你已經讀完這個章節囉,但你有掌握箇中的重點嗎?你可以在繼續閱讀後面的章節之前,先進行一些測驗 — 請前往小試身手:超連結。

+ +

總結

+ +

總而言之,以上就是超連結的介紹了! 稍後你在後續的課程中學到如何位連結增添樣式時,還會再碰到它們。HTML 的下一章,我們將繼續討論文字語義(text semantics),並看一些進階/不常見的特性,相信你會獲益良多的 — 下一站是:進階文字格式化技巧!

+ +

{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML")}}

+ +

在本主題中的內容

+ + diff --git a/files/zh-tw/learn/html/introduction_to_html/document_and_website_structure/index.html b/files/zh-tw/learn/html/introduction_to_html/document_and_website_structure/index.html new file mode 100644 index 0000000000..2a4a379123 --- /dev/null +++ b/files/zh-tw/learn/html/introduction_to_html/document_and_website_structure/index.html @@ -0,0 +1,283 @@ +--- +title: Document and website structure +slug: Learn/HTML/Introduction_to_HTML/Document_and_website_structure +translation_of: Learn/HTML/Introduction_to_HTML/Document_and_website_structure +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML")}}
+ +

{{glossary("HTML")}} 不僅能夠定義網頁的單獨部分(例如“段落”或“圖片”),還可以使用區塊級元素(例如“標題欄”、“導覽選單”、“主內容列”)來定義網站中的複合區域。本文將探討如何規劃基本的網站結構,並根據規劃的結構來編寫 HTML。

+ + + + + + + + + + + + +
預備知識:Basic HTML familiarity, as covered in Getting started with HTML. HTML text formatting, as covered in HTML text fundamentals. How hyperlinks work, as covered in Creating hyperlinks.
學習目標:學習使用語義標籤來建立文本,建置簡單的網站結構。
+ +

文本的基本組成

+ +

網頁有各式各樣的外觀,但是除了全螢幕影片、遊戲或藝術作品頁面外,都傾向於使用類似的標準元件:

+ +
+
頁首:
+
通常橫跨於整個頁面頂部有一個大標題。這是網站的主要資訊,通常存在於所有網頁。
+
導覽列:
+
指向網站各個主要區段的超連結。通常用選單按鈕、連結或頁簽來表示。類似於頁首,導航列通常應在所有網頁之間保持一致,否則會讓用戶感到疑惑,甚至無所適從。許多web 設計人員認為導航列是頁首的一部分,而不是獨立的元件,但這並非絕對;還有人認為,兩者獨立可以提供更好的無障礙訪問特性,因為螢幕可以更清晰地分辨二者。
+
主要內容:
+
中心的大部分區域是當前網頁大多數的獨有內容,例如影片、文章、地圖、新聞等。這些內容是網站的一部分,且會因頁面而異。
+
側邊攔:
+
一些外圍資訊、連結、引用、廣告等。通常與主內容相關(例如一個新聞頁面上,側邊欄可能包含作者資訊或相關文章連結)。
+
頁尾:
+
橫跨頁面底部的狹長區域。和頁首一樣,頁尾是放置共用資訊(比如版權聲明或聯繫方式)的,一般使用較小字體,且通常為次要內容。還可以通過提供快速訪問連結來進行{{Glossary("SEO")}} 。
+
+ +

一個“典型的網站”可能會這樣佈局:

+ +

a simple website structure example featuring a main heading, navigation menu, main content, side bar, and footer.

+ +

用於構造內容的HTML

+ +

上面顯示的簡單範例並不美觀,但對於說明典型的網站佈局範例來說是非常好的。 有些網站上有更多欄,有些則複雜得多,但是您知道了。 使用正確的CSS,您幾乎可以使用任何元素來包裹不同的部分,並使其看起來像您想要的樣子,但是如前所述,我們需要遵守語義並將正確的元素用於正確的運行。

+ +

這是因為視覺效果並不能說明整個故事。 We use color and font size to draw sighted users' attention to the most useful parts of the content, like the navigation menu and related links, but what about visually impaired people for example, who might not find concepts like "pink" and "large font" very useful?

+ +
+

Note: Colorblind people represent around 4% of the world population or, to put it another way, approximately 1 in every 12 men and 1 in every 200 women are colorblind. Blind and visually impaired people represent roughly 4-5% of the world population (in 2012 there were 285 million such people in the world, while the total population was around 7 billion).

+
+ +

In your HTML code, you can mark up sections of content based on their functionality — you can use elements that represent the sections of content described above unambiguously, and assistive technologies like screenreaders can recognise those elements and help with tasks like "find the main navigation", or "find the main content." As we mentioned earlier in the course, there are a number of consequences of not using the right element structure and semantics for the right job.

+ +

To implement such semantic mark up, HTML provides dedicated tags that you can use to represent such sections, for example:

+ + + +

Active learning: exploring the code for our example

+ +

Our example seen above is represented by the following code (you can also find the example in our GitHub repository). We'd like you to look at the example above, and then look over the listing below to see what parts make up what section of the visual.

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+
+    <title>My page title</title>
+    <link href="https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300|Sonsie+One" rel="stylesheet" type="text/css">
+    <link rel="stylesheet" href="style.css">
+
+    <!-- the below three lines are a fix to get HTML5 semantic elements working in old versions of Internet Explorer-->
+    <!--[if lt IE 9]>
+      <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"></script>
+    <![endif]-->
+  </head>
+
+  <body>
+    <!-- Here is our main header that is used across all the pages of our website -->
+
+    <header>
+      <h1>Header</h1>
+    </header>
+
+    <nav>
+      <ul>
+        <li><a href="#">Home</a></li>
+        <li><a href="#">Our team</a></li>
+        <li><a href="#">Projects</a></li>
+        <li><a href="#">Contact</a></li>
+      </ul>
+
+       <!-- A Search form is another commmon non-linear way to navigate through a website. -->
+
+       <form>
+         <input type="search" name="q" placeholder="Search query">
+         <input type="submit" value="Go!">
+       </form>
+     </nav>
+
+    <!-- Here is our page's main content -->
+    <main>
+
+      <!-- It contains an article -->
+      <article>
+        <h2>Article heading</h2>
+
+        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Donec a diam lectus. Set sit amet ipsum mauris. Maecenas congue ligula as quam viverra nec consectetur ant hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur.</p>
+
+        <h3>Subsection</h3>
+
+        <p>Donec ut librero sed accu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor.</p>
+
+        <p>Pelientesque auctor nisi id magna consequat sagittis. Curabitur dapibus, enim sit amet elit pharetra tincidunt feugiat nist imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros.</p>
+
+        <h3>Another subsection</h3>
+
+        <p>Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum soclis natoque penatibus et manis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p>
+
+        <p>Vivamus fermentum semper porta. Nunc diam velit, adipscing ut tristique vitae sagittis vel odio. Maecenas convallis ullamcorper ultricied. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, is fringille sem nunc vet mi.</p>
+      </article>
+
+      <!-- the aside content can also be nested within the main content -->
+      <aside>
+        <h2>Related</h2>
+
+        <ul>
+          <li><a href="#">Oh I do like to be beside the seaside</a></li>
+          <li><a href="#">Oh I do like to be beside the sea</a></li>
+          <li><a href="#">Although in the North of England</a></li>
+          <li><a href="#">It never stops raining</a></li>
+          <li><a href="#">Oh well...</a></li>
+        </ul>
+      </aside>
+
+    </main>
+
+    <!-- And here is our main footer that is used across all the pages of our website -->
+
+    <footer>
+      <p>©Copyright 2050 by nobody. All rights reversed.</p>
+    </footer>
+
+  </body>
+</html>
+ +

Take some time to look over the code and understand it — the comments inside the code should also help you to understand it. We aren't asking you to do much else in this article, because the key to understanding document layout is writing a sound HTML structure, and then laying it out with CSS. We'll wait for this until you start to study CSS layout as part of the CSS topic.

+ +

HTML layout elements in more detail

+ +

It's good to understand the overall meaning of all the HTML sectioning elements in detail — this is something you'll work on gradually as you start to get more experience with web development. You can find a lot of detail by reading our HTML element reference. For now, these are the main definitions that you should try to understand:

+ + + +

Non-semantic wrappers

+ +

Sometimes you'll come across a situation where you can't find an ideal semantic element to group some items together or wrap some content. Sometimes you might want to just group a set of elements together to affect them all as a single entity with some {{glossary("CSS")}} or {{glossary("JavaScript")}}. For cases like these, HTML provides the {{HTMLElement("div")}} and {{HTMLElement("span")}} elements. You should use these preferably with a suitable {{htmlattrxref('class')}} attribute, to provide some kind of label for them so they can be easily targeted.

+ +

{{HTMLElement("span")}} is an inline non-semantic element, which you should only use if you can't think of a better semantic text element to wrap your content, or don't want to add any specific meaning. For example:

+ +
<p>The King walked drunkenly back to his room at 01:00, the beer doing nothing to aid
+him as he staggered through the door <span class="editor-note">[Editor's note: At this point in the
+play, the lights should be down low]</span>.</p>
+ +

In this case, the editor's note is supposed to merely provide extra direction for the director of the play; it is not supposed to have extra semantic meaning. For sighted users, CSS would perhaps be used to distance the note slightly from the main text.

+ +

{{HTMLElement("div")}} is a block level non-semantic element, which you should only use if you can't think of a better semantic block element to use, or don't want to add any specific meaning. For example, imagine a shopping cart widget that you could choose to pull up at any point during your time on an e-commerce site:

+ +
<div class="shopping-cart">
+  <h2>Shopping cart</h2>
+  <ul>
+    <li>
+      <p><a href=""><strong>Silver earrings</strong></a>: $99.95.</p>
+      <img src="../products/3333-0985/thumb.png" alt="Silver earrings">
+    </li>
+    <li>
+      ...
+    </li>
+  </ul>
+  <p>Total cost: $237.89</p>
+</div>
+ +

This isn't really an <aside>, as it doesn't necessarily relate to the main content of the page (you want it viewable from anywhere). It doesn't even particularly warrant using a  <section>, as it isn't part of the main content of the page. So a <div> is fine in this case. We've included a heading as a signpost to aid screenreader users in finding it.

+ +
+

Warning: Divs are so convenient to use that it's easy to use them too much. As they carry no semantic value, they just clutter your HTML code. Take care to use them only when there is no better semantic solution and try to reduce their usage to the minimum otherwise you'll have a hard time updating and maintaining your documents.

+
+ +

Line breaks and horizontal rules

+ +

Two elements that you'll use occasionally and will want to know about are {{htmlelement("br")}} and {{htmlelement("hr")}}:

+ +

<br> creates a line break in a paragraph; it is the only way to force a rigid structure in a situation where you want a series of fixed short lines, such as in a postal address or a poem. For example:

+ +
+
<p>There once was a man named O'Dell<br>
+Who loved to write HTML<br>
+But his structure was bad, his semantics were sad<br>
+and his markup didn't read very well.</p>
+
+ +

Without the <br> elements, the paragraph would just be rendered in one long line (as we said earlier in the course, HTML ignores most whitespace); with <br> elements in the code, the markup renders like this:

+ +

{{EmbedLiveSample('line-break-live-sample', '100%', '125px', '', '', 'hide-codepen-jsfiddle')}}

+ +

<hr> elements create a horizontal rule in the document that denotes a thematic change in the text (such as a change in topic or scene). Visually it just looks like a horizontal line. As an example:

+ +
+
<p>Ron was backed into a corner by the marauding netherbeasts. Scared, but determined to protect his friends, he raised his wand and prepared to do battle, hoping that his distress call had made it through.</p>
+<hr>
+<p>Meanwhile, Harry was sitting at home, staring at his royalty statement and pondering when the next spin off series would come out, when an enchanted distress letter flew through his window and landed in his lap. He read it hazily and sighed; "better get back to work then", he mused.</p>
+
+ +

Would render like this:

+ +

{{EmbedLiveSample('horizantal-rule-live-sample', '100%', '185px', '', '', 'hide-codepen-jsfiddle')}}

+ +

Planning a simple website

+ +

Once you've planned out the structure of a simple webpage, the next logical step is to try to work out what content you want to put on a whole website, what pages you need, and how they should be arranged and link to one another for the best possible user experience. This is called {{glossary("Information architecture")}}. In a large, complex website, a lot of planning can go into this process, but for a simple website of a few pages, this can be fairly simple, and fun!

+ +
    +
  1. Bear in mind that you'll have a few elements common to most (if not all) pages — such as the navigation menu, and the footer content. If your site is for a business, for example, it's a good idea to have your contact information available in the footer on each page. Note down what you want to have common to every page.the common features of the travel site to go on every page: title and logo, contact, copyright, terms and conditions, language chooser, accessibility policy
  2. +
  3. Next, draw a rough sketch of what you might want the structure of each page to look like (it might look like our simple website above). Note what each block is going to be.A simple diagram of a sample site structure, with a header, main content area, two optional sidebars, and footer
  4. +
  5. Now, brainstorm all the other (not common to every page) content you want to have on your website — write a big list down.A long list of all the features that we could put on our travel site, from searching, to special offers and country-specific info
  6. +
  7. Next, try to sort all these content items into groups, to give you an idea of what parts might live together on different pages. This is very similar to a technique called {{glossary("Card sorting")}}.The items that should appear on a holiday site sorted into 5 categories: Search, Specials, Country-specific info, Search results, and Buy things
  8. +
  9. Now try to sketch a rough sitemap — have a bubble for each page on your site, and draw lines to show the typical workflow between pages. The homepage will probably be in the center, and link to most if not all of the others; most of the pages in a small site should be available from the main navigation, although there are exceptions. You might also want to include notes about how things might be presented.A map of the site showing the homepage, country page, search results, specials page, checkout, and buy page
  10. +
+ +

Active learning: create your own sitemap

+ +

Try carrying out the above exercise for a website of your own creation. What would you like to make a site about?

+ +
+

Note: Save your work somewhere; you might need it later on.

+
+ +

Test your skills!

+ +

You've reached the end of this article, but can you remember the most important information? You can find a detailed assessment that tests these skills at the end of the module; see Structuring a page of content. We'd advise going through the next article in the series first and not just skipping to it though!

+ +

Summary

+ +

At this point you should have a better idea about how to structure a web page/site. In the last article of this module, we'll study how to debug HTML.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/html/introduction_to_html/getting_started/index.html b/files/zh-tw/learn/html/introduction_to_html/getting_started/index.html new file mode 100644 index 0000000000..b68ccd2b73 --- /dev/null +++ b/files/zh-tw/learn/html/introduction_to_html/getting_started/index.html @@ -0,0 +1,626 @@ +--- +title: Getting started with HTML +slug: Learn/HTML/Introduction_to_HTML/Getting_started +translation_of: Learn/HTML/Introduction_to_HTML/Getting_started +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML")}}
+ +

本文將探討 HTML 最基本的部分。首先,我們將會定義元素(elements)、屬性(attributes)以及其它你可能聽過的重要名詞,然後講解該如何使用它們。我們也會告訴你典型的 HTML 頁面以及其中的元素是如何構成的,以及解釋其他重要的基礎語言特性。在此過程中,我們會撰寫一些 HTML 來引發你的興趣!

+ + + + + + + + + + + + +
需求:基礎電腦能力、已安裝需要的基本軟體、並知道如何操作檔案
目標:對 HTML 產生初步認識、並練習如何撰寫 HTML 元素。
+ +

什麼是 HTML?

+ +

{{glossary("HTML")}} (Hypertext Markup Language) 並不是一種程式語言,而是用來告訴瀏覽器該如何呈現網頁的標記式語言(markup language)。它可以很複雜也可以很陽春,端看網頁開發者如何構思。HTML 由一系列的元素({{glossary("Element", "elements")}})組成,你將利用它們來圍住、包裹,或者說標記(mark up)網頁中的每個部分,使它們在外表或行為上呈現某種特定風貌。被標籤({{glossary("Tag", "tags")}})包住的內容會變成超連結,或者斜體字,以及諸如此類的功能,舉例來說,請看下列內容:  

+ +
My cat is very grumpy
+ +

如果我們想要讓這行字獨立出來,不讓它跟其他東西排在一起,我們可以用段落標籤( paragraph tag {{htmlelement("p")}})讓它自成段落:

+ +
<p>My cat is very grumpy</p>
+
+ +
+

注意:
+ HTML 中的元素是不區分大小寫的
+ 例如 : 一個 {{htmlelement("title")}} 標籤可以寫成<title><TITLE><Title><TiTlE>,之類的形式,都沒有問題
+ 通常來說,為了保持一致性(consistency)、可讀性(readability),以及其他可能的原因,最好還是以小寫來撰寫標籤

+
+ +

分析 HTML 元素

+ +

讓我們更深入地探索段落中的元素:

+ +

+ +

元素中主要的內容有: 

+ +
    +
  1. 起始標籤(opening tag):它包含了元素的名字(在這裡是 p),夾在一對 <、> (angle brackets)之間。它指明元素從何開始生效 — 在上例中則代表段落的開始。
  2. +
  3. 結束標籤(closing tag):結束標籤和起始標籤長得差不多,只不過它在名字前面還多加了一條斜線 (forward slash) 。它表示元素結束的地方 — 在上例中表示該段落的結束。忘記加上結束標籤是初學者常犯的錯誤,這將導致奇怪的結果。
  4. +
  5. 內容(content): 元素的內容。在上例中就是一段文字。
  6. +
  7. 元素(element): 以上三者加起來就是元素。
  8. +
+ +

不要光是看: 創造你的第一個 HTML 元素

+ +

編輯下面輸入區域中的文字,嘗試用 <em> 和 </em> 標籤包裹住文字(把 <em> 放在文字前面來起始元素,把 </em> 放在後面來結束元素) ,這會使得文字變成斜體字。你可以在下面的輸出區域看到更新後的變化。

+ +

如果你不小心打錯了,你可以按下 Reset 鍵來重置。如果你卡關了,你可以點擊 Show solution 鍵來偷看答案。

+ + + +

{{ EmbedLiveSample('Playable_code', 700, 400, "", "", "hide-codepen-jsfiddle") }}

+ +

巢狀元素(Nesting elements)

+ +

你可以把元素放進另一個元素裡面 — 這叫做巢套(nesting)。比如說,我們想要強調我們的貓咪非常兇,我們可以用{{htmlelement("strong")}}元素來包住 "very" 這個字,這樣就可以標註我們想要強調的字:

+ +
<p>My cat is <strong>very</strong> grumpy.</p>
+ +

你必須確保你的元素正確地巢套:在上述範例中,我們先用了 p 元素,然後才用 strong 元素,因此我們必須先關閉 strong 元素,再關閉 p 元素。下面是錯誤示範:

+ +
<p>My cat is <strong>very grumpy.</p></strong>
+ +

這些元素必須要正確地開啟與關閉,它們與其他元素的內外關係要相當明確。如果它們像上例這樣交互重疊,你的網頁瀏覽器將無法解讀,只能盡可能地猜測你的意思,因此你很有可能會得到一個不如預期的結果。所以,別這樣做!!

+ +

區塊級元素 vs. 行內元素(Block versus inline elements)

+ +

在 HTML 中有兩種你應該要知道的重要元素類別 — 區塊級元素(block-level elements)和行內元素(inline elements)。

+ + + +

以下面這個例子來說:

+ +
<em>first</em><em>second</em><em>third</em>
+
+<p>fourth</p><p>fifth</p><p>sixth</p>
+
+ +

{{htmlelement("em")}} 是一個行內元素,所以你可以看到下面的例子中,前三個元素互相緊鄰在同一行,兩兩中間並無任何空白。另一方面,{{htmlelement("p")}} 是一個區塊級元素,所以每個元素都自成一行,並且上下都有一些空間。(這些空間是由於瀏覽器套用預設的CSS styling到這些段落上的緣故)。

+ +

{{ EmbedLiveSample('區塊級元素_vs._行內元素Block_versus_inline_elements', 700, 200, "", "") }}

+ +
+

Note: HTML5 重新定義了元素類別:請見 Element content categories。新的定義比先前所定義的更為準確且少歧義性,因此它們也同時比 block 和 inline 還來得複雜,所以我們選擇在這裡繼續使用這個觀念。

+
+ +
+

Note: 在本主題所使用的 block 與 inline 這兩個名詞,不應與 CSS 的 boxes 種類混淆。它們在預設時是很像的,但改變 CSS 的顯示型態(display type)並不會改變元素的類別,也不會影響該元素能包含或被包含的元素類別。HTML5 之所以會重新定義元素類別,部分也是基於此一原因。

+
+ +
+

Note: 你可以查看 block element 與 inline element 分別有哪些元素 — 請見 Block-level elementsInline elements

+
+ +

空元素(Empty elements)

+ +

不是所有元素都符合起始標籤、內容、結束標籤的格式。有些元素只有一個標籤,這些標籤通常用來在文件中插入/嵌入物件。例如 {{htmlelement("img")}} 元素便是用來在當前位置嵌入圖片檔:

+ +
<img src="https://raw.githubusercontent.com/mdn/beginner-html-site/gh-pages/images/firefox-icon.png">
+ +

這將會產生下面的結果:

+ +

{{ EmbedLiveSample('空元素Empty_elements', 700, 300, "", "", "hide-codepen-jsfiddle") }}

+ +
+

Note: 空元素有時也被稱作 void elements。

+
+ +

屬性(Attributes)

+ +

你也可以在元素中加入屬性,像是:

+ +

&lt;p class="editor-note">My cat is very grumpy&lt;/p>

+ +

屬性有著關於元素的額外資訊,但你並不會想要顯示它們。在這個例子中 class 屬性讓你能夠賦予一個元素辨別名稱,稍後就能用這個名稱來指定元素的樣式及其他的東西。

+ +

一個屬性應該要有:

+ +
    +
  1. 一個空白,用來隔開屬性和元素名稱(或者前一個屬性,如果該元素已經有一個以上的屬性的話)。
  2. +
  3. 屬性名稱以及一個接在其後的等號。
  4. +
  5. 屬性值以及一對包著它的引號。
  6. +
+ +

主動學習: 在元素中加入屬性

+ +

我們再舉另外一個元素的例子 {{htmlelement("a")}} 代表 anchor (錨),而這個元素會讓被它包裹住的內容變成一個超連結。它可以和很多種屬性搭配,以下僅列出幾種:

+ + + +

請編輯下面輸入區的文字,使它變成一個通往你最喜歡的網站的連結。

+ +
    +
  1. 首先,加入<a> 元素。
  2. +
  3. 再來,加入 href 屬性以及 title 屬性。
  4. +
  5. 最後,將 target 屬性設定為在新分頁中開啟。
  6. +
+ +

你將會在底下的輸出區域裡面即時地看到你改動產生的變化。當你完成後,你應該會看到一個連結;當你滑過時,連結將顯示 title 屬性的內容;當你點擊連結時,將會導向到 href 元素中的網址。切記,你需要以空白隔開元素名字以及每一個屬性。 

+ +

如果你不小心打錯了,你可以按下 Reset 鍵重置。如果你卡關了,可以點擊 Show solution 鍵來偷看答案。

+ + + +

{{ EmbedLiveSample('Playable_code2', 700, 300) }}

+ +

布林屬性(Boolean attributes)

+ +

你有時會看到一些沒有值的屬性,這完全是可行的。它們叫做布林屬性,他們只能附帶一個值,而這個值一般來說會和屬性的名字一樣。以 {{htmlattrxref("disabled", "input")}} 屬性來說,你可以把它指派為 input 元素的屬性,使得輸入文字的框框變得不能輸入文字。

+ +
<input type="text" disabled="disabled">
+ +

你可以把它寫得更簡短(在下面的例子中,我們也寫出了沒有 disabled 屬性的 input 元素供你參考,讓你更了解兩者的差別):

+ +
<input type="text" disabled>
+
+<input type="text">
+
+ +

結果 :

+ +

{{ EmbedLiveSample('布林屬性Boolean_attributes' , 700, 100, "", "", "hide-codepen-jsfiddle") }}

+ +

忘記加屬性值的引號

+ +

當你看遍全世界的網頁,你就會發現各種千奇百怪的標記風格(markup style),包括沒加引號的屬性值。這在某些情況是被允許的,但在其他情況下則會使屬性結果不如預期。沿用我們之前的例子,我們先只用 href 屬性,如下:

+ +
<a href=https://www.mozilla.org/>favourite website</a>
+ +

看起來沒甚麼問題,但是,一旦我們加上 title 屬性時,就會造成錯誤的結果: 

+ +
<a href=https://www.mozilla.org/ title=The Mozilla homepage>favourite website</a>
+ +

此時瀏覽器會誤解你的標記,認為 title 屬性其實是三個屬性:一個值為 "The" 的標題屬性,以及兩個布林屬性 Mozilla 和 homepage。這絕對不是你想要的結果,而且會導致錯誤或者意想不到的行為。你可以看看下面的示範,把你的游標移到連結上,看看會出現什麼提示!

+ +

{{ EmbedLiveSample('忘記加屬性值的引號', 700, 100) }}

+ +

我們建議不管怎樣都要加屬性引號,避免這些錯誤,同時增加原始碼的可讀性。

+ +

要用單引號還是雙引號? (Single or double quotes?)

+ +

在這個章節中,你會發現所有的屬性都是使用雙引號,而你可能會發現其他人的 HTML 中使用的是單引號。這純粹是個人風格,你可以依照你個人的喜好去使用它們。下面兩行的意思是相同的:

+ +
<a href="http://www.example.com">A link to my example.</a>
+
+<a href='http://www.example.com'>A link to my example.</a>
+ +

但是,你應該確認你沒有混著使用它們。下面這行則會造成錯誤!

+ +
<a href="http://www.example.com'>A link to my example.</a>
+ +

如果你在你的 HTML 中使用其中一種引號,你就可以包裹另外一種引號:

+ +
<a href="http://www.example.com" title="Isn't this fun?">A link to my example.</a>
+ +

不過,如果你想要包裹相同種類的引號,你就必須要用到 HTML entities。例如,以下範例是錯的:

+ +
 <a href='http://www.example.com' title='Isn't this fun?'>A link to my example.</a> 
+ +

你應該要這樣寫:

+ +
<a href='http://www.example.com' title='Isn&#39;t this fun?'>A link to my example.</a> 
+ +

解析 HTML 文檔

+ +

以上講述了 HTML 中個別元素的基礎知識,但是單獨使用它們,並沒有多大用處。所以現在就讓我們來看看如何將這些元素組成一個 HTML 網頁吧:

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>My test page</title>
+  </head>
+  <body>
+    <p>This is my page</p>
+  </body>
+</html>
+ +

這裡有:

+ +
    +
  1. <!DOCTYPE html>: 文件類型(doctype)。 在很久很久以前,當 HTML 還年輕的時候(約莫在西元 1991 年左右),文件類型是要作為一系列規範的連結,HTML 網頁必須要遵守這些規範才會被當作是好的 HTML,比如說具備自動錯誤檢查和其他有用的東西等。在那個時候,它們看起來像這樣: + +
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    + 不過,現在已經沒有人在乎它們了,它們只是個歷史痕跡,需要形式上地被引入,以確保一切正常。<!DOCTYPE html> 是字數最短的有效 doctype。你只需要知道這些就夠了。
  2. +
  3. <html></html>: {{htmlelement("html")}} 元素。該元素包裹住頁面的所有內容,有時也被稱作根元素(root element)。
  4. +
  5. <head></head>: {{htmlelement("head")}} 元素。這個元素放著你想含括的所有重要資訊,這些資訊不會呈現在網頁瀏覽者眼前。這些東西包括,顯示於搜尋結果的關鍵字、頁面說明、CSS 等等。你將會在這個系列的下個章節中學到更多有關這部分的知識。
  6. +
  7. <meta charset="utf-8">: 這個元素指定你的文件使用 UTF-8 為字元編碼,這種編碼含有這世上大部分語言的字元,理論上可以處理所有你想放文字內容,因此建議大家都要使用這種編碼,它能幫你免去許多煩惱。
  8. +
  9. <title></title>: {{htmlelement("title")}} 元素。這是用來設定網頁名稱的,它會顯示在分頁標籤上,當你將該網頁加入書籤或加入最愛時,則是用來形容這個網站。
  10. +
  11. <body></body>: {{htmlelement("body")}} 元素含括了所有你想要給網頁瀏覽者看到的內容,不管是文字、圖片、遊戲、可以播放的音樂或其他東西。
  12. +
+ +

主動學習: 在HTML文檔中加入一些特徵

+ +

如果你想試試看在你的電腦上寫一些 HTML,你可以: 

+ +
    +
  1. 複製上面的 HTML 範例。
  2. +
  3. 在你的文字編輯器中建立一個新檔案。
  4. +
  5. 將剛複製的 HTML 範例貼到新開的檔案裡。
  6. +
  7. 將檔案儲存為 index.html
  8. +
+ +
+

Note: 你也可以在這找到基本的 HTML 範本: MDN Learning Area Github repo

+
+ +

接著你就可以用網頁瀏覽器開啟你的檔案,看看這些原始碼會被渲染(rendered)成什麼樣子,然後編輯原始碼並重新整理瀏覽器,再看看會變成怎樣。目前你的網頁會長這樣:

+ +

A simple HTML page that says This is my page在這個練習中,你可以在自己的電腦中撰寫原始碼,就像上面寫的一樣,或者你可以在底下的範例視窗中進行編輯(該視窗僅表示 {{htmlelement("body")}} 元素的內容) 我們希望你依照以下的步驟逐步前行:

+ + + +

如果你不小心打錯了,你可以用 Reset 鍵重置。如果你卡關了,可以點擊 Show solution 鍵來偷看答案。

+ + + +

{{ EmbedLiveSample('Playable_code3', 700, 600) }}

+ +

HTML中的空格(Whitespace)

+ +

在上面的範例中,你可能會發現原始碼中有許多空格,其實這是完全不需要的,下面兩段原始碼會有相同的結果: 

+ +
<p>Dogs are silly.</p>
+
+<p>Dogs        are
+         silly.</p>
+ +

不管你用多少空格(whitespace,包括空白字元與換行字元),HTML 的語法分析器都只會留下一個空格。所以說,為什麼要用這麼多空格呢?答案是為了增加可讀性 — 適當的排版會讓人更明白你的原始碼,所以千萬不要把你的原始碼擠成一團,讓它們變得雜亂無章。在我們的 HTML 中,我們將每個巢狀的元素都以兩個空格縮排。原始碼的排版風格(如要用多少空格進行縮排),可依照個人喜好使用,但你的排版方式應該要一致。

+ +

實體參照(Entity references): 引用 HTML 中的特殊字元

+ +

在 HTML 中, < 、 > 、 " 、 ' 和 & 是特殊字元,它們是 HTML 語法的一部份。那麼,要如何使用這些特殊字元呢?比方說,你如果想要用 & (ampersand)或小於符號  < (less than sign) 時,要如何避免它們被瀏覽器當成原始碼呢?

+ +

這時候我們就需要用到字元參照(character references),它們是用來表示特殊字元的編碼,專門用在這種情形上。每個字元參照都是以 & (ampersand) 起頭,以分號 ; (semi-colon) 做結。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
字元相應的字元引用
<&lt;
>&gt;
"&quot;
'&apos;
&&amp;
+ +

如果你英文不錯的話,應該不難發現字元參照其實就是這些字元的英文縮寫,也就是說,"&lt;" 為 less than (小於);"&gt;" 為 great than (大於);"&quot;" 為 quotation (引號);"&apos;" 為 apostrophe (單引號);"&amp;" 為 ampersand (和號)。你可以透過下面的維基連結來查看 HTML 的字元實體參照。在下面的範例中,你可以看到兩段敘述網頁技術的段落:

+ +
<p>In HTML, you define a paragraph using the <p> element.</p>
+
+<p>In HTML, you define a paragraph using the &lt;p&gt; element.</p>
+ +

看到下面的輸出結果,你會發現第一個段落是錯誤的,因為瀏覽器認為第二個 <p> 是要開啟新段落。而第二個段落就沒問題,因為我們將 < 及 > 換成了字元參照。

+ +

{{ EmbedLiveSample('實體參照Entity_references_引用_HTML_中的特殊字元', 700, 200, "", "", "hide-codepen-jsfiddle") }}

+ +
+

Note: 你可以在維基百科中找到完整的 HTML 字元實體參照的對照表: List of XML and HTML character entity references。請記得只要你的 HTML 的字元編碼設定為 UTF-8,你就不需要使用其他字元的實體參照,因為現今的瀏覽器都能應付。

+
+ +

HTML 註解

+ +

HTML 就像大部分的程式語言,提供了一種能讓我們可以在原始碼中加入註解的方式 — 註解是會被瀏覽器忽略,並且不會被使用者看到的,它們存在的目的是要讓你得以在原始碼中說明你的原始碼是如何運作的、每段原始碼的作用等等。當你已經六個月沒有察看某個網頁的原始碼,而你完全想不起來你做了什麼的時候、或是當你把你的原始碼交給別人一同協作時,註解將會是你的好朋友!

+ +

試著將你 HTML 檔案中的一部份內容變成註解,你需要將內容包裹在特殊的符號 <!-- 和 -->之中,例如:

+ +
<p>I'm not inside a comment</p>
+
+<!-- <p>I am!</p> -->
+ +

如你所見,在下方的範例中,第一個段落出現在輸出結果中,但第二個段落並沒有出現。

+ +

{{ EmbedLiveSample('HTML_註解', 700, 100) }}

+ +

總結

+ +

恭喜你看完了這個章節,我們你能享受這個學習基礎 HTML 的旅程!目前,你應該已經了解 HTML 長什麼樣子、它最基本的運作方式,並且能夠寫出一些元素和屬性。基礎 HTML 大致上就到這裡結束,在單元接下來的章節中,我們將會更深入探討本章節學到的內容並介紹更多 HTML 的觀念。千萬別轉台!

+ +
+

Note: 目前,在你要開始學更多有關 HTML 的知識時,你可能也想要探索基礎的 CSS(Cascading Style Sheets)。CSS 是一種用來為你的網頁增添花樣的語言,例如改變字型、顏色,或改變頁面的布局。你很快就會發現,同時使用 HTML 和 CSS 會帶來很棒的效果。

+
+ +

 另見

+ + + +
{{NextMenu("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML")}}
+ +

在本主題中的內容

+ + diff --git a/files/zh-tw/learn/html/introduction_to_html/html_text_fundamentals/index.html b/files/zh-tw/learn/html/introduction_to_html/html_text_fundamentals/index.html new file mode 100644 index 0000000000..fc0e2eff89 --- /dev/null +++ b/files/zh-tw/learn/html/introduction_to_html/html_text_fundamentals/index.html @@ -0,0 +1,953 @@ +--- +title: 基本 HTML 文字 +slug: Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals +translation_of: Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML")}}
+ +

HTML 的其中一件核心工作,就是給出文件的結構和含義(又稱{{glossary("semantics")}}),以便瀏覽器正確顯示。本文章旨在說明 {{glossary("HTML")}} 可透過增加標題、章節、強調、建立清單等,建立結構化的頁面。

+ + + + + + + + + + + + +
需求:熟悉基本 HTML、在 Getting started with HTML 有講解。
目標:學習如何標記一個具有文字的基礎頁面賦予它結構及含義— 包含段落, 標題, 列表, 強調文字, 以及引用句
+ +

基本:標題與段落

+ +

多數結構化的文字由標題及段落構成,不論你是在閱讀故事,翻閱報紙,讀教科書,翻閱雜誌,等等。

+ +

An example of a newspaper front cover, showing use of a top level heading, subheadings and paragraphs.

+ +

充滿結構性的文字內容讓閱讀經驗變得輕鬆且更加愉悅。

+ +

在HTML裡,每個段落都被包在 {{htmlelement("p")}} 元素中,就像:

+ +
<p>I am a paragraph, oh yes I am.</p>
+ +

而每個標題需要被包在標題元素中:

+ +
<h1>I am the title of the story.</h1>
+ +

在HTML裡有六種標題元素:{{htmlelement("h1")}}, {{htmlelement("h2")}}, {{htmlelement("h3")}}, {{htmlelement("h4")}}, {{htmlelement("h5")}},跟 {{htmlelement("h6")}}. 每個元素分別代表著在文件中的不同層級; <h1> 代表主標題, <h2> 代表副標題, <h3> 代表更次級的副標題, 依此類推。

+ +

實作架構化階層

+ +

舉例來說,在一個故事裡,<h1> 將用來代表整個故事的標題,<h2> 則代表每個章節的標題,而<h3> 代表每個章節中的副標題,依此類推下去。

+ +
<h1>The Crushing Bore</h1>
+
+<p>By Chris Mills</p>
+
+<h2>Chapter 1: The dark night</h2>
+
+<p>It was a dark night. Somewhere, an owl hooted. The rain lashed down on the ...</p>
+
+<h2>Chapter 2: The eternal silence</h2>
+
+<p>Our protagonist could not so much as a whisper out of the shadowy figure ...</p>
+
+<h3>The specter speaks</h3>
+
+<p>Several more hours had passed, when all of a sudden the specter sat bolt upright and exclaimed, "Please have mercy on my soul!"</p>
+ +

只要層次結構有意義,要一個元件顯示什麼取決於你。當你在建立類似的文字結構時,只要記得以下幾點:

+ + + +

為何我們需要架構?

+ +

為了回答這個問題。我們先看看 text-start.html 這個文章(鷹嘴豆泥食譜)的最前端。請先下載這個文件的副本到你的電腦,等一下練習時會用到。這個文件目前包含很多不同的內容,並沒有被標記出架構,唯一的排版只有換行而已。

+ +

所以當你在瀏覽器中打開這份文件時,你將會看到這些文字看起來擠成一團!

+ +

A webpage that shows a wall of unformatted text, because there are no elements on the page to structure it.

+ +

這是因為文件內沒有元素去標示出文件的架構,所以瀏覽器不知道怎麼排版。此外:

+ + + +

以上原因說明為何我們要為內容標示出架構。

+ +

Active learning: Giving our content structure

+ +

Let's jump straight in with a live example. In the example below, add elements to the raw text in the Input field so that it appears as a heading and two paragraphs in the Output field.

+ +

If you make a mistake, you can always reset it using the Reset button. 如果你中途卡關,點擊按鈕來查看答案

+ + + +

{{ EmbedLiveSample('Playable_code', 700, 400, "", "", "hide-codepen-jsfiddle") }}

+ +

Why do we need semantics?

+ +

Semantics are relied on everywhere around us — we rely on previous experience to tell us what the function of an everyday object is; when we see something, we know what its function will be. So, for example, we expect a red traffic light to mean "stop", and a green traffic light to mean "go". Things can get tricky very quickly if the wrong semantics are applied (Do any countries use red to mean "go"? I hope not.)

+ +

In a similar vein, we need to make sure we are using the correct elements, giving our content the correct meaning, function, or appearance. In this context the {{htmlelement("h1")}} element is also a semantic element, which gives the text it wraps around the role (or meaning) of "a top level heading on your page."

+ +
<h1>This is a top level heading</h1>
+ +

By default, the browser will give it a large font size to make it look like a heading (although you could style it to look like anything you wanted using CSS). More importantly, its semantic value will be used in multiple ways, for example by search engines and screen readers (as mentioned above).

+ +

On the other hand, you could make any element look like a top level heading. Consider the following:

+ +
<span style="font-size: 32px; margin: 21px 0; display: block;">Is this a top level heading?</span>
+ +

This is a {{htmlelement("span")}} element. It has no semantics. You use it to wrap content when you want to apply CSS to it (or do something to it with JavaScript) without giving it any extra meaning (you'll find out more about these later on in the course). We've applied some CSS to it to make it look like a top level heading, but since it has no semantic value, it will not get any of the extra benefits described above. It is a good idea to use the relevant HTML element for the job.

+ +

Lists

+ +

Now let's turn our attention to lists. Lists are everywhere in life — from your shopping list to the list of directions you subconsciously follow to get to your house every day, to the lists of instructions you are following in these tutorials! Lists are everywhere on the Web too, and we've got three different types to worry about.

+ +

Unordered

+ +

Unordered lists are used to mark up lists of items for which the order of the items doesn't matter — let's take a shopping list as an example.

+ +
milk
+eggs
+bread
+hummus
+ +

Every unordered list starts off with a {{htmlelement("ul")}} element — this wraps around all the list items:

+ +
<ul>
+milk
+eggs
+bread
+hummus
+</ul>
+ +

The last step is to wrap each list item in a {{htmlelement("li")}} (list item) element:

+ +
<ul>
+  <li>milk</li>
+  <li>eggs</li>
+  <li>bread</li>
+  <li>hummus</li>
+</ul>
+ +

Active learning: Marking up an unordered list

+ +

Try editing the live sample below to create your very own HTML unordered list.

+ + + +

{{ EmbedLiveSample('Playable_code_2', 700, 400, "", "", "hide-codepen-jsfiddle") }}

+ +

Ordered

+ +

Ordered lists are lists in which the order of the items does matter — let's take a set of directions as an example:

+ +
Drive to the end of the road
+Turn right
+Go straight across the first two roundabouts
+Turn left at the third roundabout
+The school is on your right, 300 meters up the road
+ +

The markup structure is the same as for unordered lists, except that you have to wrap the list items in an {{htmlelement("ol")}} element, rather than <ul>:

+ +
<ol>
+  <li>Drive to the end of the road</li>
+  <li>Turn right</li>
+  <li>Go straight across the first two roundabouts</li>
+  <li>Turn left at the third roundabout</li>
+  <li>The school is on your right, 300 meters up the road</li>
+</ol>
+ +

Active learning: Marking up an ordered list

+ +

Try editing the live sample below to create your very own HTML ordered list.

+ + + +

{{ EmbedLiveSample('Playable_code_3', 700, 500, "", "", "hide-codepen-jsfiddle") }}

+ +

Active learning: Marking up our recipe page

+ +

So at this point in the article, you have all the information you need to mark up our recipe page example. You can choose to either save a local copy of our text-start.html starting file and do the work there, or do it in the editable example below. Doing it locally will probably be better, as then you'll get to save the work you are doing, whereas if you fill it in to the editable example, it will be lost the next time you open the page. Both have pros and cons.

+ + + +

{{ EmbedLiveSample('Playable_code_4', 900, 500, "", "", "hide-codepen-jsfiddle") }}

+ +

If you get stuck, you can always press the Show solution button, or check out our text-complete.html example on our github repo.

+ +

Nesting lists

+ +

It is perfectly ok to nest one list inside another one. You might want to have some sub-bullets sitting below a top level bullet. Let's take the second list from our recipe example:

+ +
<ol>
+  <li>Remove the skin from the garlic, and chop coarsely.</li>
+  <li>Remove all the seeds and stalk from the pepper, and chop coarsely.</li>
+  <li>Add all the ingredients into a food processor.</li>
+  <li>Process all the ingredients into a paste.</li>
+  <li>If you want a coarse "chunky" hummus, process it for a short time.</li>
+  <li>If you want a smooth hummus, process it for a longer time.</li>
+</ol>
+ +

Since the last two bullets are very closely related to the one before them (they read like sub-instructions or choices that fit below that bullet), it might make sense to nest them inside their own unordered list, and put that list inside the current fourth bullet. This would look like so:

+ +
<ol>
+  <li>Remove the skin from the garlic, and chop coarsely.</li>
+  <li>Remove all the seeds and stalk from the pepper, and chop coarsely.</li>
+  <li>Add all the ingredients into a food processor.</li>
+  <li>Process all the ingredients into a paste.
+    <ul>
+      <li>If you want a coarse "chunky" hummus, process it for a short time.</li>
+      <li>If you want a smooth hummus, process it for a longer time.</li>
+    </ul>
+  </li>
+</ol>
+ +

Try going back to the previous active learning example and updating the second list like this.

+ +

Emphasis and importance

+ +

In human language, we often emphasise certain words to alter the meaning of a sentence, and we often want to mark certain words as important or different in some way. HTML provides various semantic elements to allow us to mark up textual content with such effects, and in this section, we'll look at a few of the most common ones.

+ +

Emphasis

+ +

When we want to add emphasis in spoken language, we stress certain words, subtly altering the meaning of what we are saying. Similarly, in written language we tend to stress words by putting them in italics. For example, the following two sentences have different meanings.

+ +

I am glad you weren't late.

+ +

I am glad you weren't late.

+ +

The first sentence sounds genuinely relieved that the person wasn't late. In contrast, the second one sounds sarcastic or passive-aggressive, expressing annoyance that the person arrived a bit late.

+ +

In HTML we use the {{htmlelement("em")}} (emphasis) element to mark up such instances. As well as making the document more interesting to read, these are recognised by screen readers and spoken out in a different tone of voice. Browsers style this as italic by default, but you shouldn't use this tag purely to get italic styling. To do that, you'd use a {{htmlelement("span")}} element and some CSS, or perhaps an {{htmlelement("i")}} element (see below).

+ +
<p>I am <em>glad</em> you weren't <em>late</em>.</p>
+ +

Strong importance

+ +

To emphasize important words, we tend to stress them in spoken language and bold them in written language. For example:

+ +

這液體具有相當強的毒性

+ +

我相信你。千萬別遲到了!

+ +

In HTML we use the {{htmlelement("strong")}} (strong importance) element to mark up such instances. As well as making the document more useful, again these are recognized by screen readers and spoken in a different tone of voice. Browsers style this as bold text by default, but you shouldn't use this tag purely to get bold styling. To do that, you'd use a {{htmlelement("span")}} element and some CSS, or perhaps a {{htmlelement("b")}} element (see below).

+ +
<p>This liquid is <strong>highly toxic</strong>.</p>
+
+<p>I am counting on you. <strong>Do not</strong> be late!</p>
+ +

You can nest strong and emphasis inside one another if desired:

+ +
<p>This liquid is <strong>highly toxic</strong> —
+if you drink it, <strong>you may <em>die</em></strong>.</p>
+ +

Active learning: Let's be important!

+ +

In this active learning section, we have provided an editable example. Inside it, we'd like you to try adding emphasis and strong importance to the words you think need them, just to have some practice.

+ + + +

{{ EmbedLiveSample('Playable_code_5', 700, 500, "", "", "hide-codepen-jsfiddle") }}

+ +

Italic, bold, underline...

+ +

The elements we've discussed so far have clearcut associated semantics. The situation with {{htmlelement("b")}}, {{htmlelement("i")}}, and {{htmlelement("u")}} is somewhat more complicated. They came about so people could write bold, italics, or underlined text in an era when CSS was still supported poorly or not at all. Elements like this, which only affect presentation and not semantics, are known as presentational elements and should no longer be used, because as we've seen before, semantics is so important to accessibility, SEO, etc.

+ +

HTML5 redefined <b>, <i> and <u> with new, somewhat confusing, semantic roles.

+ +

Here's the best rule of thumb: it's likely appropriate to use <b>, <i>, or <u> to convey a meaning traditionally conveyed with bold, italics, or underline, provided there is no more suitable element. However, it always remains critical to keep an accessibility mindset. The concept of italics isn't very helpful to people using screen readers, or to people using a writing system other than the Latin alphabet.

+ + + +
+

A kind warning about underline: People strongly associate underlining with hyperlinks. Therefore, on the Web, it's best to underline only links. Use the <u> element when it's semantically appropriate, but consider using CSS to change the default underline to something more appropriate on the Web. The example below illustrates how it can be done.

+
+ +
<!-- scientific names -->
+<p>
+  The Ruby-throated Hummingbird (<i>Archilochus colubris</i>)
+  is the most common hummingbird in Eastern North America.
+</p>
+
+<!-- foreign words -->
+<p>
+  The menu was a sea of exotic words like <i lang="uk-latn">vatrushka</i>,
+  <i lang="id">nasi goreng</i> and <i lang="fr">soupe à l'oignon</i>.
+</p>
+
+<!-- a known misspelling -->
+<p>
+  Someday I'll learn how to <u style="text-decoration-line: underline; text-decoration-style: wavy;">spel</u> better.
+</p>
+
+<!-- Highlight keywords in a set of instructions -->
+<ol>
+  <li>
+    <b>Slice</b> two pieces of bread off the loaf.
+  </li>
+  <li>
+    <b>Insert</b> a tomato slice and a leaf of
+    lettuce between the slices of bread.
+  </li>
+</ol>
+ +

總結

+ +

That's it for now! This article should have given you a good idea of how to start marking up text in HTML, and introduced you to some of the most important elements in this area. There are a lot more semantic elements to cover in this area, and we'll look at a lot more in our 'More Semantic Elements' article, later on in the course. In the next article, we'll be looking in detail at how to create hyperlinks, possibly the most important element on the Web.

+ +

{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/html/introduction_to_html/index.html b/files/zh-tw/learn/html/introduction_to_html/index.html new file mode 100644 index 0000000000..47c9f80769 --- /dev/null +++ b/files/zh-tw/learn/html/introduction_to_html/index.html @@ -0,0 +1,61 @@ +--- +title: HTML介紹 +slug: Learn/HTML/Introduction_to_HTML +translation_of: Learn/HTML/Introduction_to_HTML +--- +
{{LearnSidebar}}
+ +

本質上,{{glossary("HTML")}} 是一種非常簡單的語言,由元素所組成。元素可以賦予文字片段不同的意義 (比方說,將它們描述成段落、項目清單,或是表格的一部分)、將文件組織成不同的邏輯區段 (如標頭(header)、三行的內文,或是導覽目錄),以及在網頁中嵌入圖片或影片等內容。在這個主題中我們將介紹前面兩項,並介紹基本概念以及語法以讓你了解 HTML。

+ +

預備知識

+ +

在開始閱讀之前,你並不需要具備任何 HTML 知識,你只要能夠操作電腦、瀏覽網頁並消化其中的內容即可。你需要建立一個基礎工作環境,並且了解如何建立與管理檔案──這些都屬於我們 Web 入門 的一部分。

+ +
+

提示: 如果您是在某些無法建立個人檔案的電腦/平板/其他裝置上進行,您可以在一些線上 coding program (如 JSBinThimble) 上測試程式碼範例。

+
+ +

導覽

+ +

這個主題包含以下子題,將帶你了解所有 HTML 的基礎理論,並且提供充足的機會讓你測試所習得的技能。

+ +
+
HTML 入門
+
包含 HTML 最基礎的部分──我們將定義元素(elements)、屬性(attributes)以及其他重要術語,並且介紹它們的使用方法。除此之外,我們也將說明典型的 HTML 網頁及其中的元素是如何構成的,並解釋其他重要的基本語言特性。還有,我們也會玩一些 HTML,好引發你的興趣!
+
在 head 中有什麼? HTML 中的後設資料(Metadata)
+
HTML 文件的 head 是在網頁加載完畢之後,不會顯示在瀏覽器上的部分。其中包含一些資訊,如頁面的標題({{htmlelement("title")}})、{{glossary("CSS")}} 的連結 (當你想利用 CSS 來妝點你的頁面 HTML 時,你會用到它們)、網頁圖示(favicon)的連結,以及 metadata (裡頭承載了有關於該 HTML 的資料,如作者、描述該文件的關鍵詞等。)
+
HTML 文字的基礎知識
+
一個 HTML 的主要作用是賦予純文字意義(又稱為語義化),好讓瀏覽器知道如何正確地顯示它。這篇文章將探討如何使用 HTML 來將文字區塊拆解為標題(heading)和段落(paragraph)、強調字詞、建立列表等等。
+
建立超連結
+
超連結真的非常重要 — 它造就了我們現今所知的網路。這篇文章介紹超連結的使用語法,並且探討建立連結的最佳實踐方法。
+
進階文字格式
+
在 HTML 中還有許多可以用來格式化文字的元素,但我們沒有在 HTML 文字的基礎知識中提及這些內容。雖然這些元素比較鮮為人知,不過還是相當值得一談。在這篇文章中,你將會學到如何表示引言、描述列表、程式碼、上下標,及聯繫訊息等等。 
+
文件與網站架構
+
除了分別定義網頁的各個成分(例如:段落或是圖片),HTML 還能定義網頁上的區塊(例如:標頭、導航列或是主要內容)。這篇文章將介紹如何規劃一個基本的網頁架構,以及如何透過編寫 HTML 來表示網頁架構。
+
HTML 除錯
+
如果 HTML 出錯了,卻找不到哪裡有錯誤該怎麼辦?這篇文章將會介紹一些能幫得上忙的實用工具。
+
+ +

評量

+ +

下面的評量將測試您對於以上的 HTML 基礎是否已經了解。

+ +
+
標記信件內容
+
我們都學過怎麼寫信,而信件也是用來測試我們格式化文字技巧的好例子。在這份測驗中,你將需要以 HTML 將一封信標記成題目要求的樣子。
+
組織網頁內容
+
這份測驗將要測試你利用 HTML 來組織網頁的能力,該網頁將包含頁眉(header)、頁腳(footer)、導覽列(navigation)、內文(main content)和側邊攔(sidebar)。
+
+ +

另見

+ +
+
Web literacy basics 1
+
Mozilla 基金會所提供的一個優質課程。該課程探索並測驗了很多在本主題中所提及的技術。透過裡頭的六大學習主題,學習者能夠熟悉閱讀、撰寫以及參與網路,並經由實作與合作了解網路基礎。
+
+ +
+

回饋

+ +

請填寫問卷以協助改善我們的導覽與教學。

+
diff --git a/files/zh-tw/learn/html/introduction_to_html/the_head_metadata_in_html/index.html b/files/zh-tw/learn/html/introduction_to_html/the_head_metadata_in_html/index.html new file mode 100644 index 0000000000..db41ab4ec4 --- /dev/null +++ b/files/zh-tw/learn/html/introduction_to_html/the_head_metadata_in_html/index.html @@ -0,0 +1,261 @@ +--- +title: What’s in the head? Metadata in HTML +slug: Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML +tags: + - 初學者 +translation_of: Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Getting_started", "Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML")}}
+ +

HTML 文件的 {{glossary("Head", "head")}} 是網頁在加載完畢之後,不會顯示在瀏覽器上的部分。其中包含一些資訊,如頁面的標題({{htmlelement("title")}})、{{glossary("CSS")}} 的連結 (當你想利用 CSS 來妝點你的頁面 HTML 時,你會用到它們)、網頁圖示(favicon)的連結,以及 metadata (裡頭承載了有關於該 HTML 的資料,如作者、描述該文件的關鍵詞等)。在這一章節裡,我們會討論以上的內容,甚至更多,藉此替你打下標記網頁的根基。

+ + + + + + + + + + + + +
需求:對 HTML 的基礎認識,內容我們已在 HTML 入門中提及。
目標:學習 HTML 的 head,了解它的目的、它能包含什麼重要東西,以及它對 HTML 文件產生的影響。
+ +

什麼是 HTML head?

+ +

讓我們再看一次之前所看過的 HTML 文件

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>My test page</title>
+  </head>
+  <body>
+    <p>This is my page</p>
+  </body>
+</html>
+ +

HTML 的 head 就是 {{htmlelement("head")}} 元素裡面的內容 — 跟 {{htmlelement("body")}} 元素中的內容不同(當網頁被載入瀏覽器中時,會呈現在頁面上),head 裡的內容不會顯示在頁面上,它的任務是要容納文件的 {{glossary("Metadata", "metadata")}}。在上例中,head 只有這樣:

+ +
<head>
+  <meta charset="utf-8">
+  <title>My test page</title>
+</head>
+ +

假如換作是較大型的網頁,head 裡面可能就會有非常多東西了。現在你可以先到幾個你常去的網站,並利用開發者工具來檢視它們的 head。我們在這裡並不打算要向你展示所有能放在 head 中的東西,而是教你使用一些常用的元素,讓你熟悉熟悉它們。總而言之,讓我們開始吧!

+ +

加入標題(title)

+ +

我們已經看到活生生的 {{htmlelement("title")}} 元素了 — 這東西就是用來為文件加上標題的。你可能會把它跟 {{htmlelement("h1")}} 搞混,{{htmlelement("h1")}} 是用來為網頁主體加上標題的元素,有時也被叫做頁面標題 (page title),雖然聽起來功能很像,但他們是不同的東西!

+ + + +

不要光是看:檢視一個簡單的範例

+ +
    +
  1. 在開始這次主動學習之前,請你先到我們的 GitHub repo 中下載一份 title-example.html page。要做到這件事情,你可以: + +
      +
    1. 用你的文字編輯器開一個新檔案,並將原始碼複製到裡面,然後再儲存在一個合適的地方。
    2. +
    3. 按下網頁上的 Raw 按鈕,它就會將原始碼以純文字的形式顯示在你瀏覽器的新分頁上。接著點按右鍵,將檔案儲存在你喜歡的地方。
    4. +
    +
  2. +
  3. 現在在你的瀏覽器中開啟檔案,你看到的東西應該會長這樣: +

    A simple web page with the title set to <title> element, and the <h1> set to <h1> element.這樣子你應該可以很清楚地看到哪裡是 <h1>,而哪裡是 <title> 了!

    +
  4. +
  5. 試著開啟文字編輯器,修改兩元素的內容,儲存後再重整網頁,看看有什麼不同。
  6. +
+ +

<title> 元素中的內容也被用在其他地方。舉個例子,如果你想要收藏這個網頁,(在 Firefox 上是 書籤 > 將本頁加入書籤 或按下 URL 列的星星符號),你就會看到 <title> 的內容被設為建議的書籤名稱。

+ +

A webpage being bookmarked in firefox; the bookmark name has been automatically filled in with the contents of the <title> element

+ +

接下來你就會看到,<title> 的內容也會被用在搜尋當中。

+ +

Metadata: <meta> 元素

+ +

Metadata is data that describes data, and HTML has an "official" way of adding metadata to a document — the {{htmlelement("meta")}} element. Of course, the other stuff we are talking about in this article could also be thought of as metadata too. There are a lot of different types of <meta> element that can be included in your page's <head>, but we won't try to explain them all at this stage, as it would just get too confusing. Instead, we'll explain a few things that you might commonly see, just to give you an idea.

+ +

指定文件字元編碼

+ +

In the example we saw above, this line was included:

+ +
<meta charset="utf-8">
+ +

This element simply specifies the document's character encoding — the character set that the document is permitted to use. utf-8 is a universal character set that includes pretty much any character from any human language. This means that your web page will be able to handle displaying any language; it's therefore a good idea to set this on every web page you create! For example, your page could handle English and Japanese just fine:

+ +

a web page containing English and Japanese characters, with the character encoding set to universal, or utf-8. Both languages display fine,If you set your character encoding to ISO-8859-1, for example (the character set for the Latin alphabet), your page rendering would be all messed up:

+ +

a web page containing English and Japanese characters, with the character encoding set to latin. The Japanese characters don't display correctly

+ +

Active learning: Experiment with character encoding

+ +

To try this out, revisit the simple HTML template you obtained in the previous section on <title> (the title-example.html page), try changing the meta charset value to ISO-8859-1, and add the Japanese to your page. This is the code we used:

+ +
<p>Japanese example: ご飯が熱い。</p>
+ +

加入作者(author)和描述(description)

+ +

Many <meta> elements include name and content attributes:

+ + + +

Two such meta elements that are useful to include on your page define the author of the page, and provide a concise description of the page. Let's look at an example:

+ +
<meta name="author" content="Chris Mills">
+<meta name="description" content="The MDN Learning Area aims to provide
+complete beginners to the Web with all they need to know to get
+started with developing web sites and applications.">
+ +

Specifying an author is useful in a few ways: it is useful to be able to work out who wrote the page, if you want to contact them with questions about the content. Some content management systems have facilities to automatically extract page author information and make it available for such purposes.

+ +

Specifying a description that includes keywords relating to the content of your page is useful as it has the potential to make your page appear higher in relevant searches performed in search engines (such activities are termed Search Engine Optimization, or {{glossary("SEO")}}.)

+ +

Active learning: The description's use in search engines

+ +

The description is also used on search engine result pages. Let's go through an exercise to explore this

+ +
    +
  1. Go to the front page of The Mozilla Developer Network.
  2. +
  3. View the page's source (Right/Ctrl + click on the page, choose View Page Source from the context menu.)
  4. +
  5. Find the description meta tag. It will look like this: +
    <meta name="description" content="The Mozilla Developer Network (MDN) provides
    +information about Open Web technologies including HTML, CSS, and APIs for both
    +Web sites and HTML5 Apps. It also documents Mozilla products, like Firefox OS.">
    +
  6. +
  7. Now search for "Mozilla Developer Network" in your favorite search engine (We used Yahoo.) You'll notice the description <meta> and <title> element content used in the search result — definitely worth having! +

    A Yahoo search result for "Mozilla Developer Network"

    +
  8. +
+ +
+

Note: In Google, you will see some relevant subpages of MDN listed below the main MDN homepage link — these are called sitelinks, and are configurable in Google's webmaster tools — a way to make your site's search results better in the Google search engine.

+
+ +
+

Note: Many <meta> features just aren't used any more. For example, the keyword <meta> element (<meta name="keywords" content="fill, in, your, keywords, here">) — which is supposed to provide keywords for search engines to determine relevance of that page for different search terms — is ignored by search engines, because spammers were just filling the keyword list with hundreds of keywords, biasing results.

+
+ +

其他種類的metadata

+ +

As you travel around the web, you'll find other types of metadata, too. A lot of the features you'll see on websites are proprietary creations, designed to provide certain sites (such as social networking sites) with specific pieces of information they can use.

+ +

For example, Open Graph Data is a metadata protocol that Facebook invented to provide richer metadata for websites. In the MDN sourcecode, you'll find this:

+ +
<meta property="og:image" content="https://developer.cdn.mozilla.net/static/img/opengraph-logo.dc4e08e2f6af.png">
+<meta property="og:description" content="The Mozilla Developer Network (MDN) provides
+information about Open Web technologies including HTML, CSS, and APIs for both Web sites
+and HTML5 Apps. It also documents Mozilla products, like Firefox OS.">
+<meta property="og:title" content="Mozilla Developer Network">
+ +

One effect of this is that when you link to MDN on facebook, the link appears along with an image and description: a richer experience for users.

+ +

Open graph protocol data from the MDN homepage as displayed on facebook, showing an image, title, and description.Twitter also has its own similar proprietary metadata, which has a similar effect when the site's URL is displayed on twitter.com. For example:

+ +
<meta name="twitter:title" content="Mozilla Developer Network">
+ +

加入屬於自己的網頁icon

+ +

To further enrich your site design, you can add references to custom icons in your metadata, and these will be displayed in certain contexts.

+ +

The humble favicon, which has been around for many years, was the first icon of this type, a 16 x 16 pixel icon used in multiple places. You'll see favicons displayed in the browser tab containing each open page, and next to bookmarked pages in the bookmarks panel.

+ +

A favicon can be added to your page by:

+ +
    +
  1. Saving it in the same directory as the site's index page, saved in .ico format (most browsers will support favicons in more common formats like .gif or .png, but using the ICO format will ensure it works as far back as Internet Explorer 6.)
  2. +
  3. Adding the following line into your HTML <head> to reference it: +
    <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
    +
  4. +
+ +

Here is an example of a favicon in a bookmarks panel:

+ +

The Firefox bookmarks panel, showing a bookmarked example with a favicon displayed next to it.

+ +

There are lots of other icon types to consider these days as well. For example, you'll find this in the source code of the MDN homepage:

+ +
<!-- third-generation iPad with high-resolution Retina display: -->
+<link rel="apple-touch-icon-precomposed" sizes="144x144" href="https://developer.cdn.mozilla.net/static/img/favicon144.a6e4162070f4.png">
+<!-- iPhone with high-resolution Retina display: -->
+<link rel="apple-touch-icon-precomposed" sizes="114x114" href="https://developer.cdn.mozilla.net/static/img/favicon114.0e9fabd44f85.png">
+<!-- first- and second-generation iPad: -->
+<link rel="apple-touch-icon-precomposed" sizes="72x72" href="https://developer.cdn.mozilla.net/static/img/favicon72.8ff9d87c82a0.png">
+<!-- non-Retina iPhone, iPod Touch, and Android 2.1+ devices: -->
+<link rel="apple-touch-icon-precomposed" href="https://developer.cdn.mozilla.net/static/img/favicon57.a2490b9a2d76.png">
+<!-- basic favicon -->
+<link rel="shortcut icon" href="https://developer.cdn.mozilla.net/static/img/favicon32.e02854fdcf73.png">
+ +

The comments explain what each icon is used for — these elements cover things like providing a nice high resolution icon to use when the website is saved to an iPad's home screen.

+ +

Don't worry too much about implementing all these types of icon right now — this is a fairly advanced feature, and you won't be expected to have knowledge of this to progress through the course. The main purpose here is to let you know what such things are, in case you come across them while browsing other websites' source code.

+ +

在HTML中加入CSS和JavaScript

+ +

Just about all websites you'll use in the modern day will employ {{glossary("CSS")}} to make them look cool, and {{glossary("JavaScript")}} to power interactive functionality, such as video players, maps, games, and more. These are most commonly applied to a web page using the {{htmlelement("link")}} element and the {{htmlelement("script")}} element, respectively.

+ + + +

Active learning: applying CSS and JavaScript to a page

+ +
    +
  1. To start this active learning, grab a copy of our meta-example.html, script.js and style.css files, and save them on your local computer in the same directory. Make sure they are saved with the correct names and file extensions.
  2. +
  3. Open the HTML file in both your browser, and your text editor.
  4. +
  5. By following the information given above, add {{htmlelement("link")}} and {{htmlelement("script")}} elements to your HTML, so that your CSS and JavaScript are applied to your HTML.
  6. +
+ +

If done correctly, when you save your HTML and refresh your browser you'll see that things have changed:

+ +

Example showing a page with CSS and JavaScript applied to it. The CSS has made the page go green, whereas the JavaScript has added a dynamic list to the page.

+ + + +
+

Note: If you get stuck in this exercise and can't get the CSS/JS to apply, try checking out our css-and-js.html example page.

+
+ +

預設文件語言

+ +

Finally, it's worth mentioning that you can (and really should) set the language of your page. This can be done by adding the lang attribute to the opening HTML tag (as seen in the meta-example.html and shown below.)

+ +
<html lang="en-US">
+ +

This is useful in many ways. Your HTML document will be indexed more effectively by search engines if its language is set (allowing it to appear correctly in language-specific results, for example), and it is useful to people with visual impairments using screen readers (for example, the word "six" exists in both French and English, but is pronounced differently.)

+ +

You can also set subsections of your document to be recognised as different languages. For example, we could set our Japanese language section to be recognised as Japanese, like so:

+ +
<p>Japanese example: <span lang="jp">ご飯が熱い。</span>.</p>
+ +

These codes are defined by the ISO 639-1 standard. You can find more about them in Language tags in HTML and XML.

+ +

總結

+ +

That marks the end of our quickfire tour of the HTML head — there's a lot more you can do in here, but an exhaustive tour would be boring and confusing at this stage, and we just wanted to give you an idea of the most common things you'll find in there for now! In the next article we'll be looking at HTML text fundamentals.

+ +

{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Getting_started", "Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML")}}

diff --git "a/files/zh-tw/learn/html/multimedia_and_embedding/html\344\270\255\347\232\204\345\234\226\347\211\207/index.html" "b/files/zh-tw/learn/html/multimedia_and_embedding/html\344\270\255\347\232\204\345\234\226\347\211\207/index.html" new file mode 100644 index 0000000000..5a2dfd7eff --- /dev/null +++ "b/files/zh-tw/learn/html/multimedia_and_embedding/html\344\270\255\347\232\204\345\234\226\347\211\207/index.html" @@ -0,0 +1,502 @@ +--- +title: HTML中的圖片 +slug: Learn/HTML/Multimedia_and_embedding/HTML中的圖片 +translation_of: Learn/HTML/Multimedia_and_embedding/Images_in_HTML +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding")}}
+ +

最初的網頁最初的發展階段,只是文字。而只有文字想當然爾令網頁讀起來十分的枯燥乏味。然而幸運的是沒有多久,將圖片(以及其他更有趣的內容類型)嵌入網頁的功能就誕生了。 在多媒體嵌入網頁的學習中,從<img>元素開始是相對適當,因為該元素用於在網頁中嵌入簡單的圖像。 在本文中,我們將研究如何深入使用它,包括在網頁中嵌入簡單圖像的基礎知識,使用<figure>增加標題說明以做註釋,以及詳細說明它與CSS背景圖片的關係。

+ + + + + + + + + + + + +
課成需求:基本的電腦操作, 安裝軟體的能力, 處理檔案的基本能力, 熟悉最基本的HTML的 (如HTML入門中所述
學習目標:了解如何在HTML中嵌入簡單的圖片,為它們加上標題註釋,以及HTML圖片與CSS背景圖片之間的關係。
+ +

如何將圖片放入網頁中?

+ +

為了在網頁上放置一個簡單的圖像,我們使用<img>元素。 這是一個空元素(意味著它沒有文本內容或結束標記),並需要至少一個屬性(src)(有時稱為其完整標題,source)才有用。 src屬性包含指向要嵌入頁面的圖像的路徑,該路徑可以是相對路徑或絕對路徑URL,與<a>元素中的href屬性相同。

+ +
+

提醒: 在繼續之前,您應該閱讀有關URL和路徑的快速入門,以複習相對路徑和絕對路徑URL

+
+ +

舉例來說, 如果您的圖片名為 dinosaur.jpg 且與HTML檔案位於同一資料夾中,可以這樣嵌入圖片:

+ +
<img src="dinosaur.jpg">
+ +

如果圖片位於名為images的資料夾中,且該目錄與HTML頁面位於同一資料夾(Google建議這樣的編排,以利於SEO /索引目的),則應將其嵌入如下:

+ +
<img src="images/dinosaur.jpg">
+ +

像這樣.

+ +
+

提醒: 搜索引擎還會讀取圖片名稱,並將其納入SEO中。 因此您應該為圖片提供一個描述性的檔名。 例如 dinosaur.jpg 的命名方式會比 img835.png 更好。

+
+ +

你也可以用絕對路徑URL來嵌入圖片,例如

+ +
<img src="https://www.example.com/images/dinosaur.jpg">
+ +

但這麼做是沒有意義的,因為它只會使瀏覽器執行更多工作,瀏覽器需重複執行從DNS服務器中搜尋IP地址等等工作。您應將網站上的圖片與HTML存放在同一個伺服器上。

+ +
+

注意: 大多數圖像均受版權保護。 請勿在你的網站上隨意顯示圖片,除非:

+ + + +

侵犯版權是違法及不道德的。 此外,切勿將src屬性指向您未被授權的他人網站上的圖便。 這稱為“熱連結”。再次重申,竊取某人的頻寬是違法的,且這會減慢您網站的速度。此外當別人變更、移除或換上令人尷尬的內容時你將無法做出改變。

+
+ +

我們上面的程式碼將有以下結果:

+ +

A basic image of a dinosaur, embedded in a browser, with "Images in HTML" written above it

+ +
+

提醒: <img>和<video>之類的元素有時也稱為替換元素。 這是因為元素的內容和圖片大小是由外部(例如圖片或影音檔)所定義的,而不是由元素的內容定義。

+
+ +
+

提醒: 您可以從在Github上找到本節完成的示例(參見開源碼。)

+
+ +

替代性文字

+ +

我們下一個要看的屬性是alt。 它的功能算是圖片的文字描述,應用於因網路連接速度慢而無法看到/顯示圖片或需要長時間來跑圖等等情況。 例如,上面的程式碼我們可以像這樣修改:

+ +
<img src="images/dinosaur.jpg"
+     alt="The head and torso of a dinosaur skeleton;
+          it has a large head with long sharp teeth">
+ +

測試替代文字最簡單方法是故意拼錯檔名。 例如,如果我們的圖片名稱為dinosooooor.jpg,則瀏覽器將不會顯示該圖片,而是顯示alt文本:The Images in HTML title, but this time the dinosaur image is not displayed, and alt text is in its place.

+ +

那麼,為什麼您會看到或需要替代文字? 它可以派上用場的原因有很多:

+ + + +

您應該在alt屬性中確切寫些什麼? 這取決於圖片為何而出現;也就是說,如果圖片不顯示,您將損失什麼:

+ + + +

本質上,關鍵是即使在看不見圖片的情況下也能提供相同的體驗。這樣可以確保所有使用者都不會丟失任何內容。嘗試在瀏覽器中關閉圖像,然後查看外觀。您很快就會意識到,如果看不到圖片,替代文字會很有幫助。

+ +
+

Note: For more information, see our guide to Text Alternatives.

+
+ +

寬與高

+ +

You can use the width and height attributes to specify the width and height of your image. You can find your image's width and height in a number of ways. For example on the Mac you can use Cmd + I to get the info display up for the image file. Returning to our example, we could do this:

+ +
<img src="images/dinosaur.jpg"
+     alt="The head and torso of a dinosaur skeleton;
+          it has a large head with long sharp teeth"
+     width="400"
+     height="341">
+ +

This doesn't result in much difference to the display, under normal circumstances. But if the image isn't being displayed, for example, the user has just navigated to the page, and the image hasn't yet loaded, you'll notice the browser is leaving a space for the image to appear in:

+ +

The Images in HTML title, with dinosaur alt text, displayed inside a large box that results from width and height settings

+ +

This is a good thing to do, resulting in the page loading quicker and more smoothly.

+ +

However, you shouldn't alter the size of your images using HTML attributes. If you set the image size too big, you'll end up with images that look grainy, fuzzy, or too small, and wasting bandwidth downloading an image that is not fitting the user's needs. The image may also end up looking distorted, if you don't maintain the correct aspect ratio. You should use an image editor to put your image at the correct size before putting it on your webpage.

+ +
+

Note: If you do need to alter an image's size, you should use CSS instead.

+
+ +

圖片標題

+ +

As with links, you can also add title attributes to images, to provide further supporting information if needed. In our example, we could do this:

+ +
<img src="images/dinosaur.jpg"
+     alt="The head and torso of a dinosaur skeleton;
+          it has a large head with long sharp teeth"
+     width="400"
+     height="341"
+     title="A T-Rex on display in the Manchester University Museum">
+ +

This gives us a tooltip on mouse hover, just like link titles:

+ +

The dinosaur image, with a tooltip title on top of it that reads A T-Rex on display at the Manchester University Museum

+ +

However, this does not come recommended — title has a number of accessibility problems, mainly based around the fact that screen reader support is very unpredictable and most browsers won't show it unless you are hovering with a mouse (so e.g. no access to keyboard users). If you are interested in more information about this, read The Trials and Tribulations of the Title Attribute by Scott O'Hara.

+ +

It is better to include such supporting information in the main article text, rather than attached to the image.

+ +

實戰練習:嵌入圖片

+ +

It is now your turn to play! This active learning section will have you up and running with a simple embedding exercise. You are provided with a basic {{htmlelement("img")}} tag; we'd like you to embed the image located at the following URL:

+ +

https://raw.githubusercontent.com/mdn/learning-area/master/html/multimedia-and-embedding/images-in-html/dinosaur_small.jpg

+ +

Earlier we said to never hotlink to images on other servers, but this is just for learning purposes, so we'll let you off this one time.

+ +

We would also like you to:

+ + + +

If you make a mistake, you can always reset it using the Reset button. If you get really stuck, press the Show solution button to see an answer:

+ + + +

{{ EmbedLiveSample('Playable_code', 700, 350, "", "", "hide-codepen-jsfiddle") }}

+ +

用圖文和圖文標註說明圖像

+ +

Speaking of captions, there are a number of ways that you could add a caption to go with your image. For example, there would be nothing to stop you from doing this:

+ +
<div class="figure">
+  <img src="images/dinosaur.jpg"
+       alt="The head and torso of a dinosaur skeleton;
+            it has a large head with long sharp teeth"
+       width="400"
+       height="341">
+
+  <p>A T-Rex on display in the Manchester University Museum.</p>
+</div>
+ +

This is ok. It contains the content you need, and is nicely stylable using CSS. But there is a problem here: there is nothing that semantically links the image to its caption, which can cause problems for screen readers. For example, when you have 50 images and captions, which caption goes with which image?

+ +

A better solution, is to use the HTML5 {{htmlelement("figure")}} and {{htmlelement("figcaption")}} elements. These are created for exactly this purpose: to provide a semantic container for figures, and to clearly link the figure to the caption. Our above example could be rewritten like this:

+ +
<figure>
+  <img src="images/dinosaur.jpg"
+       alt="The head and torso of a dinosaur skeleton;
+            it has a large head with long sharp teeth"
+       width="400"
+       height="341">
+
+  <figcaption>A T-Rex on display in the Manchester University Museum.</figcaption>
+</figure>
+ +

The {{htmlelement("figcaption")}} element tells browsers, and assistive technology that the caption describes the other content of the {{htmlelement("figure")}} element.

+ +
+

Note: From an accessibility viewpoint, captions and {{htmlattrxref('alt','img')}} text have distinct roles. Captions benefit even people who can see the image, whereas {{htmlattrxref('alt','img')}} text provides the same functionality as an absent image. Therefore, captions and alt text shouldn't just say the same thing, because they both appear when the image is gone. Try turning images off in your browser and see how it looks.

+
+ +

A figure doesn't have to be an image. It is an independent unit of content that:

+ + + +

A figure could be several images, a code snippet, audio, video, equations, a table, or something else.

+ +

實戰練習:建立圖文標註

+ +

In this active learning section, we'd like you to take the finished code from the previous active learning section, and turn it into a figure:

+ +
    +
  1. Wrap it in a {{htmlelement("figure")}} element.
  2. +
  3. Copy the text out of the title attribute, remove the title attribute, and put the text inside a {{htmlelement("figcaption")}} element below the image.
  4. +
+ +

If you make a mistake, you can always reset it using the Reset button. If you get really stuck, press the Show solution button to see an answer:

+ + + +

{{ EmbedLiveSample('Playable_code_2', 700, 350, "", "", "hide-codepen-jsfiddle") }}

+ +

CSS 背景圖片

+ +

您還可以使用CSS將圖像嵌入網頁(JavaScript也可以,但這完全是另一回事了)。 CSSbackground-image屬性和其他background- *屬性用於控制背景圖片的放置。 例如要將背景圖片放置在頁面的每個段落上,可以執行以下操作:

+ +
p {
+  background-image: url("images/dinosaur.jpg");
+}
+ +

這種嵌入圖片的方式比HTML圖像更容易定位和控制。 那麼,為什麼還要用HTML嵌入圖片呢? 如上所述,CSS背景圖像僅用於裝飾。 如果您只是想在頁面上添加一些漂亮的東西以增強視覺效果,那很好。 但是,此類圖像根本沒有語義。 它們與文字不同,對於螢幕閱讀器是不可見的,依此類推。 這裡需要的是HTML圖片!

+ +

總結來說,如果圖片在內容上具有含義,則應使用HTML圖像。 如果圖像純粹是裝飾性的,則應使用CSS背景圖片。

+ +
+

提醒: 在我們的CSS主題中,您將學到更多關於CSS背景圖片的知識。

+
+ +

試試看!

+ +

您已經來到了本文的末端,但是您還記得最重要的內容嗎? 在繼續往下之前,這裡有些測驗讓您驗證看看您是否都學會了 — 測驗:HTML圖像

+ +

總結

+ +

目前就是這樣啦。 我們已經詳細介紹了圖片和標題說明。 在下一篇文章中我們將進一步介紹,如何使用HTML將視頻和音頻嵌入在網頁中。

+ +

{{NextMenu("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding")}}

+ +

在這個主題中

+ + diff --git a/files/zh-tw/learn/html/multimedia_and_embedding/index.html b/files/zh-tw/learn/html/multimedia_and_embedding/index.html new file mode 100644 index 0000000000..05d98a462b --- /dev/null +++ b/files/zh-tw/learn/html/multimedia_and_embedding/index.html @@ -0,0 +1,53 @@ +--- +title: Multimedia and Embedding +slug: Learn/HTML/Multimedia_and_embedding +translation_of: Learn/HTML/Multimedia_and_embedding +--- +

{{LearnSidebar}}

+ +

到目前為止,我們已經看到了很多文字,但是只使用文字讓人感到無聊。讓我們開始研究如何透過更有趣的內容讓網絡變得活躍起來!本單元探討如何使用HTML在您的網頁中包增加媒體,包括可以嵌入圖像的不同方式,以及如何嵌入影片,音訊甚至整個網頁。

+ +

預備知識

+ +

在此單元開始之前,我們假設你對HTML基礎知識 (如HTML介紹) 已經有一定的了解,如果還沒有,建議您先預習該部分再回來。

+ +
+

Note: 如果你所操作的電腦、平板或裝置環境不允許你建立自己的檔案,你可以在諸如 JSBin 或Thimble 這樣的網站上嘗試(多數的)範例程式碼。

+
+ +

導覽

+ +

本單元包含以下章節,它們將帶您了解在網頁上嵌入多媒體的所有基礎知識。

+ +
+
HTML中的圖片
+
可以考慮到的多媒體種類很多,但是從用以將簡單圖像嵌入網頁中不起眼的{{htmlelement(" img")}}元素開始是很合乎邏輯的。在本文中,我們將研究如何更深入地使用它,包括基礎知識,使用{{htmlelement("figure")}}加上標題的註釋以及它與CSS背景圖像的關係。
+
視訊與音訊內容
+
接著,我們將研究如何使用HTML5 {{htmlelement("video")}}和{{htmlelement("audio")}} 元素在頁面上嵌入視訊和音訊,包括基本知識,以提供對不同頁面的訪問文件格式添加到不同的瀏覽器,添加標題和字幕,以及如何為舊版瀏覽器添加後備廣告。
+
從物件到 iframe — 其他嵌入技巧
+
在這裡,我們想橫跨一步,著眼於幾個元素,這些元素可以使您將各種內容類型嵌入到網頁中:{{htmlelement("iframe")}},{{htmlelement("embed")}}和 {{htmlelement("object")}}元素。 <iframe>用於嵌入其他網頁,另外兩個允許您嵌入PDF,SVG甚至Flash(一種即將消逝的技術,但您可能仍會定期看到它)。
+
為 Web 新增向量圖
+
向量圖形在某些情況下可能非常有用。 與PNG / JPG等常見格式不同,它們在放大時不會失真/像素化-在縮放時可以保持平滑。 本文向您介紹什麼是向量圖,以及如何在網頁中加入流行的{{glossary("SVG")}}格式。
+
適應性圖片
+
在本文中,我們將學習適應性圖片 (又稱響應式圖片)的概念。適應性圖片在不同螢幕尺寸,解析度和其他類似功能差異很大的設備上都能很好地運作。我們還會研究HTML提供了哪些工具來幫助實現它們。 這有助於提高不同設備之間的性能。 響應式圖片只是響應式設計的一部分,在將來您學習CSS的單元中還會有響應式圖片的單元。
+
+ +

評量

+ +

以下評量中將測試您對以上指南中介紹的HTML基礎的理解:

+ +
+
Mozilla 啟動頁面
+
在此測驗中,我們將測試您對本區塊文章中討論的一些技術的了解,使您能夠向時髦的啟動頁面添加有關Mozilla的一些圖片和視訊!
+
+ +

另見

+ +
+
增加點擊映射到圖片上層
+
圖像映射提供了一種機制,可以使圖像的不同部分鏈接到不同的位置。(請試想在地圖上點擊每個不同國家/地區以取得更多資訊)此技術有時很有用。
+
網頁知識基礎2
+
+

一個出色的Mozilla基礎課程,探索和測試此多媒體和嵌入單元中討論的一些技能。 深入研究網頁組成,可訪問性設計,共享資源,使用線上媒體和開放性工作的基礎知識(這意味著您的內容可以免費獲得併可以由他人共享)。

+
+
diff --git a/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/index.html b/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/index.html new file mode 100644 index 0000000000..aa4de14fe3 --- /dev/null +++ b/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/index.html @@ -0,0 +1,339 @@ +--- +title: Video and audio content +slug: Learn/HTML/Multimedia_and_embedding/Video_and_audio_content +tags: + - Article + - Audio + - Beginner + - Guide + - HTML + - NeedsTranslation + - TopicStub + - Video + - captions + - subtitles + - track +translation_of: Learn/HTML/Multimedia_and_embedding/Video_and_audio_content +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Images_in_HTML", "Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies", "Learn/HTML/Multimedia_and_embedding")}}
+ +

Now that we are comfortable with adding simple images to a webpage, the next step is to start adding video and audio players to your HTML documents! In this article we'll look at doing just that with the {{htmlelement("video")}} and {{htmlelement("audio")}} elements; we'll then finish off by looking at how to add captions/subtitles to your videos.

+ + + + + + + + + + + + +
Prerequisites:Basic computer literacy, basic software installed, basic knowledge of working with files, familiarity with HTML fundamentals (as covered in Getting started with HTML) and Images in HTML.
Objective:To learn how to embed video and audio content into a webpage, and add captions/subtitles to video.
+ +

Video and audio on the web

+ +

Web developers have wanted to use video and audio on the Web for a long time, ever since the early 2000s when we started to have bandwidth fast enough to support any kind of video (video files are much larger than text or even images.) In the early days, native web technologies such as HTML didn't have the ability to embed video and audio on the Web, so proprietary (or plugin-based) technologies like Flash (and later, Silverlight) became popular for handling such content. This kind of technology worked ok, but it had a number of problems, including not working well with HTML/CSS features, security issues, and accessibility issues.

+ +

A native solution would solve much of this if implemented correctly. Fortunately, a few years later the {{glossary("HTML5")}} specification had such features added, with the {{htmlelement("video")}} and {{htmlelement("audio")}} elements, and some shiny new {{Glossary("JavaScript")}} {{Glossary("API","APIs")}} for controlling them. We'll not be looking at JavaScript here — just the basic foundations that can be achieved with HTML.

+ +

We won't be teaching you how to produce audio and video files — that requires a completely different skillset. We have provided you with sample audio and video files and example code for your own experimentation, in case you are unable to get hold of your own.

+ +
+

Note: Before you begin here, you should also know that there are quite a few OVPs (online video providers) like YouTube, Dailymotion, and Vimeo, and online audio providers like Soundcloud. Such companies offer a convenient, easy way to host and consume videos, so you don't have to worry about the enormous bandwidth consumption. OVPs even usually offer ready-made code for embedding video/audio in your webpages; if you use that route, you can avoid some of the difficulties we discuss in this article. We'll be discussing this kind of service a bit more in the next article.

+
+ +

The <video> element

+ +

The {{htmlelement("video")}} element allows you to embed a video very easily. A really simple example looks like this:

+ +
<video src="rabbit320.webm" controls>
+  <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.webm">link to the video</a> instead.</p>
+</video>
+ +

The features of note are:

+ +
+
{{htmlattrxref("src","video")}}
+
In the same way as for the {{htmlelement("img")}} element, the src (source) attribute contains a path to the video you want to embed. It works in exactly the same way.
+
{{htmlattrxref("controls","video")}}
+
Users must be able to control video and audio playback (it's especially critical for people who have epilepsy.) You must either use the controls attribute to include the browser's own control interface, or build your interface using the appropriate JavaScript API. At a minimum, the interface must include a way to start and stop the media, and to adjust the volume.
+
The paragraph inside the <video> tags
+
This is called fallback content — this will be displayed if the browser accessing the page doesn't support the <video> element, allowing us to provide a fallback for older browsers. This can be anything you like; in this case, we've provided a direct link to the video file, so the user can at least access it some way regardless of what browser they are using.
+
+ +

The embedded video will look something like this:

+ +

A simple video player showing a video of a small white rabbit

+ +

You can try the example live here (see also the source code.)

+ +

Using multiple source formats to improve compatibility

+ +

There's a problem with the above example, which you may have noticed already if you've tried to access the live link above with an older browser like Internet Explorer or even an older version of Safari. The video won't play, because different browsers support different video (and audio) formats. Fortunately, there are things you can do to help prevent this from being a problem.

+ +

Contents of a media file

+ +

First, let's go through the terminology quickly. Formats like MP3, MP4 and WebM are called container formats. They define a structure in which the audio and/or video tracks that make up the media are stored, along with metadata describing the media, what codecs are used to encode its channels, and so forth.

+ +

A WebM file containing a movie which has a main video track and one alternate angle track, plus audio for both English and Spanish, in addition to audio for an English commentary track can be conceptualized as shown in the diagram below. Also included are text tracks containing closed captions for the feature film, Spanish subtitles for the film, and English captions for the commentary.

+ +

Diagram conceptualizing the contents of a media file at the track level.

+ +

The audio and video tracks within the container hold data in the appropriate format for the codec used to encode that media. Different formats are used for audio tracks versus video tracks. Each audio track is encoded using an audio codec, while video tracks are encoded using (as you probably have guessed) a video codec. As we talked about before, different browsers support different video and audio formats, and different container formats (like MP3, MP4, and WebM, which in turn can contain different types of video and audio).

+ +

For example:

+ + + +

There are some special cases. For example, for some types of audio, a codec's data is often stored without a container, or with a simplified container. One such instance is the FLAC codec, which is stored most commonly in FLAC files, which are just raw FLAC tracks.

+ +

Another such situation is the always-popular MP3 file. An "MP3 file" is actually an MPEG-1 Audio Layer III (MP3) audio track stored within an MPEG or MPEG-2 container. This is especially interesting since while most browsers don't support using MPEG media in the {{HTMLElement("video")}} and {{HTMLElement("audio")}} elements, they may still support MP3 due to its popularity.

+ +

An audio player will tend to play an audio track directly, e.g. an MP3 or Ogg file. These don't need containers.

+ +

Media file support in browsers

+ +
+

Why do we have this problem? It turns out that several popular formats, such as MP3 and MP4/H.264, are excellent but are encumbered by patents; that is, there are patents covering some or all of the technology that they're based upon. In the United States, patents covered MP3 until 2017, and H.264 is encumbered by patents through at least 2027.

+ +

Because of those patents, browsers that wish to implement support for those codecs must pay typically enormous license fees. In addition, some people simply prefer to avoid restricted software and prefer to use only open formats. Due to these legal and preferential reasons, web developers find themselves having to support multiple formats to capture their entire audience.

+
+ +

The codecs described in the previous section exist to compress video and audio into manageable files, since raw audio and video are both exceedingly large. Each web browser supports an assortment of {{Glossary("Codec","codecs")}}, like Vorbis or H.264, which are used to convert the compressed audio and video into binary data and back. Each codec offers its own advantages and drawbacks, and each container may also offer its own positive and negative features affecting your decisions about which to use.

+ +

Things become slightly more complicated because not only does each browser support a different set of container file formats, they also each support a different selection of codecs. In order to maximize the likelihood that your web site or app will work on a user's browser, you may need to provide each media file you use in multiple formats. If your site and the user's browser don't share a media format in common, your media simply won't play.

+ +

Due to the intricacies of ensuring your app's media is viewable across every combination of browsers, platforms, and devices you wish to reach, choosing the best combination of codecs and container can be a complicated task. See {{SectionOnPage("/en-US/docs/Web/Media/Formats/Containers", "Choosing the right container")}} for help selecting the container file format best suited for your needs; similarly, see {{SectionOnPage("/en-US/docs/Web/Media/Formats/Video_codecs", "Choosing a video codec")}} and {{SectionOnPage("/en-US/docs/Web/Media/Formats/Audio_codecs", "Choosing an audio codec")}} for help selecting the first media codecs to use for your content and your target audience.

+ +

One additional thing to keep in mind: mobile browsers may support additional formats not supported by their desktop equivalents, just like they may not support all the same formats the desktop version does. On top of that, both desktop and mobile browsers may be designed to offload handling of media playback (either for all media or only for specific types it can't handle internally). This means media support is partly dependent on what software the user has installed.

+ +

So how do we do this? Take a look at the following updated example (try it live here, also):

+ +
<video controls>
+  <source src="rabbit320.mp4" type="video/mp4">
+  <source src="rabbit320.webm" type="video/webm">
+  <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p>
+</video>
+ +

Here we've taken the src attribute out of the actual {{HTMLElement("video")}} tag, and instead included separate {{htmlelement("source")}} elements that point to their own sources. In this case the browser will go through the {{HTMLElement("source")}} elements and play the first one that it has the codec to support. Including WebM and MP4 sources should be enough to play your video on most platforms and browsers these days.

+ +

Each <source> element also has a {{htmlattrxref("type", "source")}} attribute. This is optional, but it is advised that you include it. The type attribute contains the {{glossary("MIME type")}} of the file specified by the <source>, and browsers can use the type to immediately skip videos they don't understand. Iftype isn't included, browsers will load and try to play each file until they find one that works, which obviously takes time and is an unnecessary use of resources.

+ +

Refer to our guide to media types and formats for help selecting the best containers and codecs for your needs, as well as to look up the right MIME types to specify for each.

+ +

Other <video> features

+ +

There are a number of other features you can include when displaying an HTML video. Take a look at our next example:

+ +
<video controls width="400" height="400"
+       autoplay loop muted preload="auto"
+       poster="poster.png">
+  <source src="rabbit320.mp4" type="video/mp4">
+  <source src="rabbit320.webm" type="video/webm">
+  <p>Your browser doesn't support HTML video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p>
+</video>
+
+ +

The resulting UI looks something like this:

+ +

A video player showing a poster image before it plays. The poster image says HTML5 video example, OMG hell yeah!

+ +

The new features are:

+ +
+
{{htmlattrxref("width","video")}} and {{htmlattrxref("height","video")}}
+
You can control the video size either with these attributes or with {{Glossary("CSS")}}. In both cases, videos maintain their native width-height ratio — known as the aspect ratio. If the aspect ratio is not maintained by the sizes you set, the video will grow to fill the space horizontally, and the unfilled space will just be given a solid background color by default.
+
{{htmlattrxref("autoplay","video")}}
+
Makes the audio or video start playing right away, while the rest of the page is loading. You are advised not to use autoplaying video (or audio) on your sites, because users can find it really annoying.
+
{{htmlattrxref("loop","video")}}
+
Makes the video (or audio) start playing again whenever it finishes. This can also be annoying, so only use if really necessary.
+
{{htmlattrxref("muted","video")}}
+
Causes the media to play with the sound turned off by default.
+
{{htmlattrxref("poster","video")}}
+
The URL of an image which will be displayed before the video is played. It is intended to be used for a splash screen or advertising screen.
+
{{htmlattrxref("preload","video")}}
+
+

Used for buffering large files; it can take one of three values:

+ +
    +
  • "none" does not buffer the file
  • +
  • "auto" buffers the media file
  • +
  • "metadata" buffers only the metadata for the file
  • +
+
+
+ +

You can find the above example available to play live on Github (also see the source code.) Note that we haven't included the autoplay attribute in the live version — if the video starts to play as soon as the page loads, you don't get to see the poster!

+ +

The <audio> element

+ +

The {{htmlelement("audio")}} element works just like the {{htmlelement("video")}} element, with a few small differences as outlined below. A typical example might look like so:

+ +
<audio controls>
+  <source src="viper.mp3" type="audio/mp3">
+  <source src="viper.ogg" type="audio/ogg">
+  <p>Your browser doesn't support HTML5 audio. Here is a <a href="viper.mp3">link to the audio</a> instead.</p>
+</audio>
+ +

This produces something like the following in a browser:

+ +

A simple audio player with a play button, timer, volume control, and progress bar

+ +
+

Note: You can run the audio demo live on Github (also see the audio player source code.)

+
+ +

This takes up less space than a video player, as there is no visual component — you just need to display controls to play the audio. Other differences from HTML video are as follows:

+ + + +

Other than this, <audio> supports all the same features as <video> — review the above sections for more information about them.

+ +

Restarting media playback (requires JavaScript)

+ +

At any time, you can reset the media to the beginning—including the process of selecting the best media source, if more than one is specified using {{HTMLElement("source")}} elements—by calling the element's {{domxref("HTMLMediaElement.load", "load()")}} method:

+ +
const mediaElem = document.getElementById("my-media-element");
+mediaElem.load();
+ +

Detecting track addition and removal (requires JavaScript)

+ +

You can monitor the track lists within a media element to detect when tracks are added to or removed from the element's media. For example, you can watch for the {{event("addtrack")}} event being fired on the associated {{domxref("AudioTrackList")}} object (retrieved via {{domxref("HTMLMediaElement.audioTracks")}}) to be informed when audio tracks are added to the media:

+ +
const mediaElem = document.querySelector("video");
+mediaElem.audioTracks.onaddtrack = function(event) {
+  audioTrackAdded(event.track);
+}
+
+ +

You'll find more information about this in our {{domxref("TrackEvent")}} documentation.

+ +

Displaying video text tracks

+ +

Now we'll discuss a slightly more advanced concept that is really useful to know about. Many people can't or don't want to hear the audio/video content they find on the Web, at least at certain times. For example:

+ + + +

Wouldn't it be nice to be able to provide these people with a transcript of the words being spoken in the audio/video? Well, thanks to HTML video, you can. To do so we use the WebVTT file format and the {{htmlelement("track")}} element.

+ +
+

Note: "Transcribe" means "to write down spoken words as text." The resulting text is a "transcript."

+
+ +

WebVTT is a format for writing text files containing multiple strings of text along with metadata such as the time in the video at which each text string should be displayed, and even limited styling/positioning information. These text strings are called cues, and there are several kinds of cues which are used for different purposes. The most common cues are:

+ +
+
subtitles
+
Translations of foreign material, for people who don't understand the words spoken in the audio.
+
captions
+
Synchronized transcriptions of dialog or descriptions of significant sounds, to let people who can't hear the audio understand what is going on.
+
timed descriptions
+
Text which should be spoken by the media player in order to describe important visuals to blind or otherwise visually impaired users.
+
+ +

A typical WebVTT file will look something like this:

+ +
WEBVTT
+
+1
+00:00:22.230 --> 00:00:24.606
+This is the first subtitle.
+
+2
+00:00:30.739 --> 00:00:34.074
+This is the second.
+
+  ...
+
+ +

To get this displayed along with the HTML media playback, you need to:

+ +
    +
  1. Save it as a .vtt file in a sensible place.
  2. +
  3. Link to the .vtt file with the {{htmlelement("track")}} element. <track> should be placed within <audio> or <video>, but after all <source> elements. Use the {{htmlattrxref("kind","track")}} attribute to specify whether the cues are subtitles, captions, or descriptions. Further, use {{htmlattrxref("srclang","track")}} to tell the browser what language you have written the subtitles in.
  4. +
+ +

Here's an example:

+ +
<video controls>
+    <source src="example.mp4" type="video/mp4">
+    <source src="example.webm" type="video/webm">
+    <track kind="subtitles" src="subtitles_es.vtt" srclang="es">
+</video>
+ +

This will result in a video that has subtitles displayed, kind of like this:

+ +

Video player with stand controls such as play, stop, volume, and captions on and off. The video playing shows a scene of a man holding a spear-like weapon, and a caption reads "Esta hoja tiene pasado oscuro."

+ +

For more details, please read Adding captions and subtitles to HTML5 video. You can find the example that goes along with this article on Github, written by Ian Devlin (see the source code too.) This example uses some JavaScript to allow users to choose between different subtitles. Note that to turn the subtitles on, you need to press the "CC" button and select an option — English, Deutsch, or Español.

+ +
+

Note: Text tracks also help you with {{glossary("SEO")}}, since search engines especially thrive on text. Text tracks even allow search engines to link directly to a spot partway through the video.

+
+ +

Active learning: Embedding your own audio and video

+ +

For this active learning, we'd (ideally) like you to go out into the world and record some of your own video and audio — most phones these days allow you to record audio and video very easily and, provided you can transfer it on to your computer, you can use it. You may have to do some conversion to end up with a WebM and MP4 in the case of video, and an MP3 and Ogg in the case of audio, but there are enough programs out there to allow you to do this without too much trouble, such as Miro Video Converter and Audacity. We'd like you to have a go!

+ +

If you are unable to source any video or audio, then you can feel free to use our sample audio and video files to carry out this exercise. You can also use our sample code for reference.

+ +

We would like you to:

+ +
    +
  1. Save your audio and video files in a new directory on your computer.
  2. +
  3. Create a new HTML file in the same directory, called index.html.
  4. +
  5. Add {{HTMLElement("audio")}} and {{HTMLElement("video")}} elements to the page; make them display the default browser controls.
  6. +
  7. Give both of them {{HTMLElement("source")}} elements so that browsers will find the audio format they support best and load it. These should include {{htmlattrxref("type", "source")}} attributes.
  8. +
  9. Give the <video> element a poster that will be displayed before the video starts to be played. Have fun creating your own poster graphic.
  10. +
+ +

For an added bonus, you could try researching text tracks, and work out how to add some captions to your video.

+ +

Test your skills!

+ +

You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see Test your skills: Multimedia and embedding. Note that the third assessment question in this test assumes knowledge of some of the techniques covered in the next article, so you may want to read that before attempting it.

+ +

Summary

+ +

And that's a wrap; we hope you had fun playing with video and audio in web pages! In the next article, we'll look at other ways of embedding content on the Web, using technologies like {{htmlelement("iframe")}} and {{htmlelement("object")}}.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Images_in_HTML", "Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies", "Learn/HTML/Multimedia_and_embedding")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/test_your_skills_colon__multimedia_and_embedding/index.html b/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/test_your_skills_colon__multimedia_and_embedding/index.html new file mode 100644 index 0000000000..951de62ef5 --- /dev/null +++ b/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/test_your_skills_colon__multimedia_and_embedding/index.html @@ -0,0 +1,104 @@ +--- +title: 測試你的技能:多媒體和嵌入 +slug: >- + Learn/HTML/Multimedia_and_embedding/Video_and_audio_content/Test_your_skills:_Multimedia_and_embedding +tags: + - HTML + - 初學者 + - 多媒體 + - 學習 + - 嵌入 + - 測驗 +translation_of: >- + Learn/HTML/Multimedia_and_embedding/Video_and_audio_content/Test_your_skills:_Multimedia_and_embedding +--- +
{{learnsidebar}}
+ +
這項技能測試的目的是評估您是否了解我們的視訊和音訊內容以及從物件到iframe的其他嵌入技術文章。
+ +
+ +
+

Note: 您可以在下面的交互式編輯器中嘗試解決方案,但是下載代碼並使用在線工具如 CodePen, jsFiddle, or Glitch 去完成測試。
+
+ 如果您遇到困難,請向我們尋求幫助-請參閱 {{anch("Assessment or further help")}} 此頁面底部的部分。

+
+ +

多媒體和嵌入1

+ +

在此測試中,我們希望您將一個簡單的音檔嵌入到頁面上。你需要:

+ + + +

嘗試更新下面的程式碼以完成測驗:

+ +

{{EmbedGHLiveSample("learning-area/html/multimedia-and-embedding/tasks/media-embed/mediaembed1.html", '100%', 700)}}

+ +
+

下載此測驗的程式碼在你自己的編輯器或線上編輯器中運行。

+
+ +

多媒體和嵌入2

+ +

在此測驗中,我們希望你標記一個稍微複雜一些的影片播放器,此外還具有多個來源、字幕和其他功能。你需要:

+ + + +

嘗試更新下面的程式碼以完成測驗:

+ +

{{EmbedGHLiveSample("learning-area/html/multimedia-and-embedding/tasks/media-embed/mediaembed2.html", '100%', 700)}}

+ +
+

下載此測驗的程式碼在你自己的編輯器或線上編輯器中運行。

+
+ +

多媒體和嵌入3

+ +

對於此最終測驗,你需要執行兩個測驗:

+ + + +

T嘗試更新下面的程式碼以完成測驗:

+ +

{{EmbedGHLiveSample("learning-area/html/multimedia-and-embedding/tasks/media-embed/mediaembed3.html", '100%', 700)}}

+ +
+

下載此測驗的程式碼在你自己的編輯器或線上編輯器中運行。

+
+ +

評估或進一步幫助

+ +

您可以在上面的Interactive Editors中練習這些示例。

+ +

如果您希望對自己的工作進行評估,或者遇到困難希望尋求幫助:

+ +
    +
  1. 將您的工作放入在線共享編輯器中,例如 CodePen, jsFiddle, 或 Glitch. 您可以自己編寫程式碼,也可以使用以上各節中連接到的初始文件。
  2. +
  3. 撰寫帖子,要求評估和/或幫助 MDN Discourse forum Learning category. 你的貼文應包括: +
      +
    • 描述性標題,例如“ HTML圖像基礎知識1技能測試所需的評估”。
    • +
    • 您已經嘗試過的內容以及您希望我們做什麼的詳細信息,例如如果您陷入困境並需要幫助,或者需要評估。
    • +
    • 聯機共享編輯器中您要評估或需要幫助的示例的鏈接(如上面的步驟1中所述)。這是進入的好習慣-如果看不到他們的代碼,很難幫助有編碼問題的人。
    • +
    • 指向實際任務或評估頁面的鏈接,因此我們可以找到您需要幫助的問題。
    • +
    +
  4. +
+ +
+
+
diff --git "a/files/zh-tw/learn/html/multimedia_and_embedding/\345\205\266\344\273\226_\345\265\214\345\205\245_\346\212\200\350\241\223/index.html" "b/files/zh-tw/learn/html/multimedia_and_embedding/\345\205\266\344\273\226_\345\265\214\345\205\245_\346\212\200\350\241\223/index.html" new file mode 100644 index 0000000000..a1996f2537 --- /dev/null +++ "b/files/zh-tw/learn/html/multimedia_and_embedding/\345\205\266\344\273\226_\345\265\214\345\205\245_\346\212\200\350\241\223/index.html" @@ -0,0 +1,386 @@ +--- +title: 從物件到iframe - 其他嵌入技術 +slug: Learn/HTML/Multimedia_and_embedding/其他_嵌入_技術 +translation_of: Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web", "Learn/HTML/Multimedia_and_embedding")}}
+ +

到現在為止,您應該真正掌握了將內容嵌入網頁的方法,包括圖片,影片和聲音。在這一點上,我們想採取一些橫向的措施,尋找一些元素,使您可以將各種內容類型嵌入到網頁中: {{htmlelement("iframe")}}, {{htmlelement("embed")}} 和 {{htmlelement("object")}} 元素。<iframe>用於嵌入其他網頁,另外兩個用於嵌入PDF,SVG甚至是Flash(這項技術正在淘汰,但您仍會半定期看到)。

+ + + + + + + + + + + + +
Prerequisites:Basic computer literacy, basic software installed, basic knowledge of working with files, familiarity with HTML fundamentals (as covered in Getting started with HTML) and the previous articles in this module.
Objective:To learn how to embed items into web pages using {{htmlelement("object")}}, {{htmlelement("embed")}}, and {{htmlelement("iframe")}}, like Flash movies and other webpages.
+ +

A short history of embedding

+ +

A long time ago on the Web, it was popular to use frames to create websites — small parts of a website stored in individual HTML pages. These were embedded in a master document called a frameset, which allowed you to specify the area on the screen that each frame filled, rather like sizing the columns and rows of a table. These were considered the height of coolness in the mid to late 90s, and there was evidence that having a webpage split up into smaller chunks like this was better for download speeds — especially noticeable with network connections being so slow back then. They did however have many problems, which far outweighed any positives as network speeds got faster, so you don't see them being used anymore.

+ +

A little while later (late 90s, early 2000s), plugin technologies became very popular, such as Java Applets and Flash — these allowed web developers to embed rich content into webpages such as videos and animations, which just weren't available through HTML alone. Embedding these technologies was achieved through elements like {{htmlelement("object")}}, and the lesser-used {{htmlelement("embed")}}, and they were very useful at the time. They have since fallen out of fashion due to many problems, including accessibility, security, file size, and more; these days most mobile devices don't support such plugins anymore, and desktop support is on the way out.

+ +

Finally, the {{htmlelement("iframe")}} element appeared (along with other ways of embedding content, such as {{htmlelement("canvas")}}, {{htmlelement("video")}}, etc.) This provides a way to embed an entire web document inside another one, as if it were an {{htmlelement("img")}} or other such element, and is used regularly today.

+ +

With the history lesson out of the way, let's move on and see how to use some of these.

+ +

Active learning: classic embedding uses

+ +

In this article we are going to jump straight into an active learning section, to immediately give you a real idea of just what embedding technologies are useful for. The online world is very familiar with Youtube, but many people don't know about some of the sharing facilities it has available. Let's look at how Youtube allows us to embed a video in any page we like using an {{htmlelement("iframe")}}.

+ +
    +
  1. First, go to Youtube and find a video you like.
  2. +
  3. Below the video, you'll find a Share button — select this to display the sharing options.
  4. +
  5. Select the Embed button and you'll be given some <iframe> code — copy this.
  6. +
  7. Insert it into the Input box below, and see what the result is in the Output.
  8. +
+ +

For bonus points, you could also try embedding a Google Map in the example:

+ +
    +
  1. Go to Google Maps and find a map you like.
  2. +
  3. Click on the "Hamburger Menu" (three horizontal lines) in the top left of the UI.
  4. +
  5. Select the Share or embed map option.
  6. +
  7. Select the Embed map option, which will give you some <iframe> code — copy this.
  8. +
  9. Insert it into the Input box below, and see what the result is in the Output.
  10. +
+ +

If you make a mistake, you can always reset it using the Reset button. If you get really stuck, press the Show solution button to see an answer.

+ + + +

{{ EmbedLiveSample('Playable_code', 700, 600, "", "", "hide-codepen-jsfiddle") }}

+ +

Iframes in detail

+ +

So, that was easy and fun, right? {{htmlelement("iframe")}} elements are designed to allow you to embed other web documents into the current document. This is great for incorporating third-party content into your website that you might not have direct control over and don't want to have to implement your own version of — such as video from online video providers, commenting systems like Disqus, maps from online map providers, advertising banners, etc. The live editable examples you've been using through this course are implemented using <iframe>s.

+ +

There are some serious {{anch("Security concerns")}} to consider with <iframe>s, as we'll discuss below, but this doesn't mean that you shouldn't use them in your websites — it just requires some knowledge and careful thinking. Let's explore the code in a bit more detail. Say you wanted to include the MDN glossary on one of your web pages — you could try something like this:

+ +
<iframe src="https://developer.mozilla.org/en-US/docs/Glossary"
+        width="100%" height="500" frameborder="0"
+        allowfullscreen sandbox>
+  <p>
+    <a href="https://developer.mozilla.org/en-US/docs/Glossary">
+       Fallback link for browsers that don't support iframes
+    </a>
+  </p>
+</iframe>
+ +

This example includes the basic essentials needed to use an <iframe>:

+ +
+
{{htmlattrxref('allowfullscreen','iframe')}}
+
If set, the <iframe> is able to be placed in fullscreen mode using the Full Screen API (somewhat beyond scope for this article.)
+
{{htmlattrxref('frameborder','iframe')}}
+
If set to 1, this tells the browser to draw a border between this frame and other frames, which is the default behaviour. 0 removes the border. Using this isn't really recommended any more, as the same effect can be better achieved using {{cssxref('border')}}: none; in your {{Glossary('CSS')}}.
+
{{htmlattrxref('src','iframe')}}
+
This attribute, as with {{htmlelement("video")}}/{{htmlelement("img")}}, contains a path pointing to the URL of the document to be embedded.
+
{{htmlattrxref('width','iframe')}} and {{htmlattrxref('height','iframe')}}
+
These attributes specify the width and height you want the iframe to be.
+
Fallback content
+
In the same way as other similar elements like {{htmlelement("video")}}, you can include fallback content between the opening and closing <iframe></iframe> tags that will appear if the browser doesn't support the <iframe>. In this case, we have included a link to the page instead. It is unlikely that you'll come across any browser that doesn't support <iframe>s these days.
+
{{htmlattrxref('sandbox','iframe')}}
+
This attribute, which works in slightly more modern browsers than the rest of the <iframe> features (e.g. IE 10 and above) requests heightened security settings; we'll say more about this in the next section.
+
+ +
+

Note: In order to improve speed, it's a good idea to set the iframe's src attribute with JavaScript after the main content is done with loading. This makes your page usable sooner and decreases your official page load time (an important {{glossary("SEO")}} metric.)

+
+ +

Security concerns

+ +

Above we mentioned security concerns — let's go into this in a bit more detail now. We are not expecting you to understand all of this content perfectly the first time; we just want to make you aware of this concern, and provide a reference to come back to as you get more experienced and start considering using <iframe>s in your experiments and work. Also, there is no need to be scared and not use <iframe>s — you just need to be careful. Read on...

+ +

Browser makers and Web developers have learned the hard way that iframes are a common target (official term: attack vector) for bad people on the Web (often termed hackers, or more accurately, crackers) to attack if they are trying to maliciously modify your webpage, or trick people into doing something they don't want to do, such as reveal sensitive information like usernames and passwords. Because of this, spec engineers and browser developers have developed various security mechanisms for making <iframe>s more secure, and there are also best practices to consider — we'll cover some of these below.

+ +
+

{{interwiki('wikipedia','Clickjacking')}} is one kind of common iframe attack where hackers embed an invisible iframe into your document (or embed your document into their own malicious website) and use it to capture users' interactions. This is a common way to mislead users or steal sensitive data.

+
+ +

A quick example first though — try loading the previous example we showed above into your browser — you can find it live on Github (see the source code too.) You won't actually see anything displayed on the page, and if you look at the Console in the browser developer tools, you'll see a message telling you why. In Firefox, you'll get told Load denied by X-Frame-Options: https://developer.mozilla.org/en-US/docs/Glossary does not permit framing. This is because the developers that built MDN have included a setting on the server that serves the website pages to disallow them from being embedded inside <iframe>s (see {{anch("Configure CSP directives")}}, below.) This makes sense — an entire MDN page doesn't really make sense to be embedded in other pages unless you want to do something like embed them on your site and claim them as your own — or attempt to steal data via clickjacking, which are both really bad things to do. Plus if everybody started to do this, all the additional bandwidth would start to cost Mozilla a lot of money.

+ +

Only embed when necessary

+ +

Sometimes it makes sense to embed third-party content — like youtube videos and maps — but you can save yourself a lot of headaches if you only embed third-party content when completely necessary. A good rule of thumb for web security is "You can never be too cautious. If you made it, double-check it anyway. If someone else made it, assume it's dangerous until proven otherwise."

+ +
+

Besides security, you should also be aware of intellectual property issues. Most content is copyrighted, offline and online, even content you might not expect (for example, most images on Wikimedia Commons). Never display content on your webpage unless you own it or the owners have given you written, unequivocal permission. Penalties for copyright infringement are severe. Again, you can never be too cautious.

+ +

If the content is licensed, you must obey the license terms. For example, the content on MDN is licensed under CC-BY-SA. That means, you must credit us properly when you quote our content, even if you make substantial changes.

+
+ +

Use HTTPS

+ +

{{Glossary("HTTPS")}} is the encrypted version of {{Glossary("HTTP")}}. You should serve your websites using HTTPS whenever possible:

+ +
    +
  1. HTTPS reduces the chance that remote content has been tampered with in transit,
  2. +
  3. HTTPS prevents embedded content from accessing content in your parent document, and vice versa.
  4. +
+ +

Using HTTPS requires a security certificate, which can be expensive (although Let's Encrypt makes things easier) — if you can't get one, you may serve your parent document with HTTP. However, because of the second benefit of HTTPS above, no matter what the cost, you must never embed third-party content with HTTP. (In the best case scenario, your user's Web browser will give them a scary warning.) All reputable companies that make content available for embedding via an <iframe> will make it available via HTTPS — look at the URLs inside the <iframe> src attribute when you are embedding content from Google Maps or Youtube, for example.

+ +
+

Note: Github pages allow content to be served via HTTPS by default, so is useful for hosting content. If you are using different hosting and are not sure, ask your hosting provider about it.

+
+ +

Always use the sandbox attribute

+ +

You want to give attackers as little power as you can to do bad things on your website, therefore you should give embedded content only the permissions needed for doing its job. Of course, this applies to your own content, too. A container for code where it can be used appropriately — or for testing — but can't cause any harm to the rest of the codebase (either accidental or malicious) is called a sandbox.

+ +

Unsandboxed content can do way too much (executing JavaScript, submitting forms, popup windows, etc.) By default, you should impose all available restrictions by using the sandbox attribute with no parameters, as shown in our previous example.

+ +

If absolutely required, you can add permissions back one by one (inside the sandbox="" attribute value) — see the {{htmlattrxref('sandbox','iframe')}} reference entry for all the available options. One important note is that you should never add both allow-scripts and allow-same-origin to your sandbox attribute — in that case, the embedded content could bypass the Same-origin policy that stops sites from executing scripts, and use JavaScript to turn off sandboxing altogether.

+ +
+

Note: Sandboxing provides no protection if attackers can fool people into visiting malicious content directly (outside an iframe). If there's any chance that certain content may be malicious (e.g., user-generated content), please serve it from a different {{glossary("domain")}} to your main site.

+
+ +

Configure CSP directives

+ +

{{Glossary("CSP")}} stands for content security policy and provides a set of HTTP Headers (metadata sent along with your web pages when they are served from a web server) designed to improve the security of your HTML document. When it comes to securing <iframe>s, you can configure your server to send an appropriate X-Frame-Options  header. This can prevent other websites from embedding your content in their web pages (which would enable {{interwiki('wikipedia','clickjacking')}} and a host of other attacks), which is exactly what the MDN developers have done, as we saw earlier on.

+ +
+

Note: You can read Frederik Braun's post On the X-Frame-Options Security Header for more background information on this topic. Obviously, it's rather out of scope for a full explanation in this article.

+
+ +

The <embed> and <object> elements

+ +

The {{htmlelement("embed")}} and {{htmlelement("object")}} elements serve a different function to {{htmlelement("iframe")}} — these elements are general purpose embedding tools for embedding multiple types of external content, which include plugin technologies like Java Applets and Flash, PDF (which can be shown in a browser with a PDF plugin), and even content like videos, SVG and images!

+ +
+

Note: A plugin, in this context, refers to software that provides access to content the browser cannot read natively.

+
+ +

However, you are unlikely to use these elements very much — Applets haven't been used for years, Flash is no longer very popular, due to a number of reasons (see {{anch("The case against plugins")}}, below), PDFs tend to be better linked to than embedded, and other content such as images and video have much better, easier elements to handle those. Plugins and these embedding methods are really a legacy technology, and we are mainly mentioning them in case you come across them in certain circumstances like intranets, or enterprise projects.

+ +

If you find yourself needing to embed plugin content, this is the kind of information you'll need, at a minimum:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{htmlelement("embed")}}{{htmlelement("object")}}
{{glossary("URL")}} of the embedded content{{htmlattrxref('src','embed')}}{{htmlattrxref('data','object')}}
accurate {{glossary("MIME type", 'media type')}} of the embedded content{{htmlattrxref('type','embed')}}{{htmlattrxref('type','object')}}
height and width (in CSS pixels) of the box controlled by the plugin{{htmlattrxref('height','embed')}}
+ {{htmlattrxref('width','embed')}}
{{htmlattrxref('height','object')}}
+ {{htmlattrxref('width','object')}}
names and values, to feed the plugin as parametersad hoc attributes with those names and valuessingle-tag {{htmlelement("param")}} elements, contained within <object>
independent HTML content as fallback for an unavailable resourcenot supported (<noembed> is obsolete)contained within <object>, after <param> elements
+ +
+

Note: <object> requires a data attribute, a type attribute, or both. If you use both, you may also use the {{htmlattrxref('typemustmatch','object')}} attribute (only implemented in Firefox and Chrome, as of this writing). typemustmatch keeps the embedded file from running unless the type attribute provides the correct media type. typemustmatch can therefore confer significant security benefits when you're embedding content from a different {{glossary("origin")}} (it can keep attackers from running arbitrary scripts through the plugin).

+
+ +

Here's an example that uses the {{htmlelement("embed")}} element to embed a Flash movie (see this live on Github, and check the source code too):

+ +
<embed src="whoosh.swf" quality="medium"
+       bgcolor="#ffffff" width="550" height="400"
+       name="whoosh" align="middle" allowScriptAccess="sameDomain"
+       allowFullScreen="false" type="application/x-shockwave-flash"
+       pluginspage="http://www.macromedia.com/go/getflashplayer">
+ +

Pretty horrible, isn't it? The HTML generated by the Adobe Flash tool tended to be even worse, using an <object> element with an <embed> element embedded in it, to cover all bases (check out an example.) Flash was even used successfully as fallback content for HTML5 video, for a time, but this is increasingly being seen as not necessary.

+ +

Now let's look at an <object> example that embeds a PDF into a page (see the live example and the source code):

+ +
<object data="mypdf.pdf" type="application/pdf"
+        width="800" height="1200" typemustmatch>
+  <p>You don't have a PDF plugin, but you can
+    <a href="mypdf.pdf">download the PDF file.
+    </a>
+  </p>
+</object>
+ +

PDFs were a necessary stepping stone between paper and digital, but they pose many accessibility challenges and can be hard to read on small screens. They do still tend to be popular in some circles, but it is much better to link to them so they can be downloaded or read on a separate page, rather than embedding them in a webpage.

+ +

The case against plugins

+ +

Once upon a time, plugins were indispensable on the Web. Remember the days when you had to install Adobe Flash Player just to watch a movie online? And then you constantly got annoying alerts about updating Flash Player and your Java Runtime Environment. Web technologies have since grown much more robust, and those days are over. For virtually all applications, it's time to stop delivering content that depends on plugins and start taking advantage of Web technologies instead.

+ + + +
+

Note: Due to its inherent issues and the lack of support for Flash, Adobe announced that they would stop supporting it at the end of 2020.  As of January 2020, most browsers block Flash content by default, and by December 31st of 2020, all browsers will have completly removed all Flash functionality. Any existing Flash content will be inaccessable after that date.

+
+ +

So what should you do? If you need interactivity, HTML and {{glossary("JavaScript")}} can readily get the job done for you with no need for Java applets or outdated ActiveX/BHO technology. Instead of relying on Adobe Flash, you should use HTML5 video for your media needs, SVG for vector graphics, and Canvas for complex images and animations. Peter Elst was already writing some years ago that Adobe Flash is rarely the right tool for the job. As for ActiveX, even Microsoft's {{glossary("Microsoft Edge","Edge")}} browser no longer supports it.

+ +

Test your skills!

+ +

You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see Test your skills: Multimedia and embedding.

+ +

Summary

+ +

The topic of embedding other content in web documents can quickly become very complex, so in this article, we've tried to introduce it in a simple, familiar way that will immediately seem relevant, while still hinting at some of the more advanced features of the involved technologies. To start with, you are unlikely to use embedding for much beyond including third-party content like maps and videos on your pages. As you become more experienced, however, you are likely to start finding more uses for them.

+ +

There are many other technologies that involve embedding external content besides the ones we discussed here. We saw some in earlier articles, such as {{htmlelement("video")}}, {{htmlelement("audio")}}, and {{htmlelement("img")}}, but there are others to discover, such as {{htmlelement("canvas")}} for JavaScript-generated 2D and 3D graphics, and {{SVGElement("svg")}} for embedding vector graphics. We'll look at SVG in the next article of the module.

+ +

{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web", "Learn/HTML/Multimedia_and_embedding")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/html/tables/index.html b/files/zh-tw/learn/html/tables/index.html new file mode 100644 index 0000000000..0e282b2a68 --- /dev/null +++ b/files/zh-tw/learn/html/tables/index.html @@ -0,0 +1,34 @@ +--- +title: HTML 表格 +slug: Learn/HTML/Tables +translation_of: Learn/HTML/Tables +--- +
{{LearnSidebar}}
+ +

HTML 的常見任務就是建構表格資料,某些元素與屬性正是為此目的而生。HTML 以及用於樣式化的 CSS 能方便顯示諸如讀書計劃、附近游泳池的開放時間、分析最喜歡的恐龍或足球隊……之類的表格資訊。本模塊將帶你認識建構 HTML 表格資料所需的一切。

+ +

先決條件

+ +

開始本模塊之前,你要理解基本的 HTML:請參見 HTML 介紹

+ +
+

注意:如果你用的電腦或平板之類的設備,無法允許建立自己的檔案,你可以把大部分的例子放在線上程式網站,例如 JSBinThimble

+
+ +

教學

+ +

本模塊包含以下文章:

+ +
+
HTML 表格基礎
+
這篇文章將介紹 HTML 表格,包含像是行列、標題、製作單元格、跨多行與列等基礎知識,還有如何把他們組合在一起,以方便樣式化。
+
HTML 表格進階與無障礙
+
本模塊的第二篇文章將介紹一些 HTML 表格的進階功能:例如說明、摘要、將行分成標頭、身體、還有註腳三大部分。另外,我們也會探討針對視障人士的表格無障礙。
+
+ +

評估

+ +
+
建構行星數據
+
在我們的表格評估中,我們將提供太陽系中行星的一些數據,並讓你把他們構建到 HTML 表格中。
+
diff --git "a/files/zh-tw/learn/html/tables/\345\237\272\347\244\216/index.html" "b/files/zh-tw/learn/html/tables/\345\237\272\347\244\216/index.html" new file mode 100644 index 0000000000..03325afbce --- /dev/null +++ "b/files/zh-tw/learn/html/tables/\345\237\272\347\244\216/index.html" @@ -0,0 +1,568 @@ +--- +title: HTML表格的基礎 +slug: Learn/HTML/Tables/基礎 +translation_of: Learn/HTML/Tables/Basics +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/HTML/Tables/Advanced", "Learn/HTML/Tables")}}
+ +

這篇文章將帶你從列、格、標頭,以及將各格以數欄、數列的方式合併等基礎開始探索HTML表格。

+ + + + + + + + + + + + +
先備知識: +

HTML的基礎(見介紹HTML)

+
目標:對HTML表格有基本的認識
+ +

什麼是表格?

+ +

表格是一個由列和欄組成的結構化資料(tabular data)。表格能幫助你快速查看不同資料類型間的關聯值。例如人和年紀、一周當中的某天或是地方游泳池的時間表。

+ +

A sample table showing names and ages of some people - Chris 38, Dennis 45, Sarah 29, Karen 47.

+ +

A swimming timetable showing a sample data table

+ +

表格在人類社會當中被廣泛使用且已經有很久的歷史,如下是美國1800年的人口普查紀錄表格。

+ +

A very old parchment document; the data is not easily readable, but it clearly shows a data table being used.

+ +

這也難怪HTML的開創者要提供一個在網路建立和呈現表格化資料的方法。

+ +

表格是怎麼運作的呢?

+ +

表格是精確的,資訊可以透過列和欄位名稱之間的視覺關聯輕鬆呈現。觀察以下表格,利用列和欄目名稱找出有62個衛星的類木行星。

+ +

有關太陽系星球的資訊 (真實資料取自 Nasa's Planetary Fact Sheet - Metric. )

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
名稱質量(1024kg)直徑 (km)密度(kg/m3)重力(m/s2)一天的長度(小時)和太陽的距離(106km)平均溫度 (°C)衛星的數目備註
陸地行星水星0.3304,87954273.74222.657.91670最接近太陽
金星4.8712,10452438.92802.0108.24640
地球5.9712,75655149.824.0149.6151我們的世界
火星0.6426,79239333.724.7227.9-652紅色星球
類木行星氣態巨行星木星1898142,984132623.19.9778.6-11067最大的星球
土星568120,5366879.010.71433.5-14062
冰質巨行星天王星86.851,11812718.717.22872.5-19527
海王星10249,528163811.016.14495.1-20014
矮行星冥王星0.01462,37020950.7153.35906.4-2255在2006年被從行星類別中除名,但這還些爭議
+ +

在正確執行之下,就連視障者都可以把表格資料詮釋為HTML格式的表格。一份成功的HTML表格就應該如此提升視障者的使用經驗。

+ +

表格樣式

+ +

你也可以在 GitHub 上看看實際範例 ! 而你也許會注意到那裡的表格似乎更容易閱讀。那是因為這裡的表格只有加上很少樣式,而GitHub上的版本卻應用上了更多明顯的CSS 。

+ +

需要弄清楚的一點是 : 要讓表格在網頁上有效呈現需要提供紮實的HTML架構和CSS樣式資訊,但將在這個模組中聚焦在HTML的部分。若想瞭解CSS的部分,可以在完成這部分閱讀之後造訪表格樣式設計的文章。

+ +

在這個單元裡我們將不會聚焦在CSS上,但是我們提供基本的CSS樣式表讓你做使用,這將會使你製作的表格比起毫無修飾的預設樣式更方便閱讀。你能在這找到樣式表,並且你也能找到一個適用於樣式表的HTML模版 — 他們能一起讓你有個好起點來實驗HTML表格。

+ +

當何時你不應該使用HTML表格?

+ +

HTML表格應該被使用在結構化資料(tabular data)上 — 這就是它們被設計的目的。
+ 不幸地是,許多人習慣使用HTML表格去排版他們的網頁,例如: 使用一列去當header,一列當做內容欄位,一列當作footer...等等,你能在我們的輔助學習單元裡的頁面輸出發現更多細節以及一個範例。它曾經被這麼使用是因為CSS過去在不同瀏覽器之間的支援程度十分可怕; 如今,已非常少在用表格做排版,但你仍然可能在網路的一些邊邊角角見到。

+ +

簡單來說,使用表格排版而非使用CSS排版技術是一件很糟的事情。
+ 下列是主要原因:

+ +
    +
  1. 表格排版會減少對視障使用者的輔助 : 視障者使用的螢幕閱讀器會翻譯存在於HTML網頁的標籤並對使用者念出內容。由於表格並不是正確的排版工具,並且標示方式遠複雜於CSS排版技術,所以螢幕閱讀器輸出的內容會使他們的使用者感到困惑。
  2. +
  3. 表格會產生標籤雜燴(tag soup): 就像上面提到的,表格排版通常會比一般適當的輸出技術包含更複雜的標籤結構。這會導致程式碼本身更難撰寫、維護及debug。
  4. +
  5. 表格不會自適應(automatically responsive): 當你使用合適的排版容器(像是{htmlelement("header")}, {{htmlelement("section")}}) 或是 {{htmlelement("div")}}),它們的寬度相對於父層預設為100%,而表格的預設大小是依據它們的內容物,所以當表格樣式要有效的在不同的裝置之間運行時,會需要做額外的測量調整。
  6. +
+ +

主動學習:建造你第一個表格

+ +

關於表格的理論我們已經談論夠了,所以,來深入實際的例子並建立一個簡單的表格吧!

+ +
    +
  1. 第一件事,在自己的電腦複製一份新的空白模板.html 以及 簡易表格.css 
  2. +
  3. 每一個表格裡的內容都是由這兩個標籤所組成:<table></table> 將這些放入你的HTML中的body。
  4. +
  5. 表格裡最小的容器是表格儲存格,由<td>元素所組成('td' 代表 'table data')。將下列的程式碼加入你的表格標籤之中: +
    <td>Hi, I'm your first cell.</td>
    +
  6. +
  7. 如果我們想要一個四格儲存格寬的列(row), 我們需要複製這些標籤三次。
    + 將你的表格內容更新成這樣: +
    <td>Hi, I'm your first cell.</td>
    +<td>I'm your second cell.</td>
    +<td>I'm your third cell.</td>
    +<td>I'm your fourth cell.</td>
    +
  8. +
+ +

就像你看到的,儲存格不會在各自的下方,它們彼此自動排列在同一列上。每個 <td> 元素會創造單個儲存格並且使它們據在同一行,我們新增的每一個儲存格都會使列更長。

+ +

要讓這個列停止增加並開始在下一列增加連續的儲存格的話,我們需要用 <tr> 元素 ('tr' 代表 'table row'),現在來探討一下:

+ +
    +
  1. 放置四個你已新增在 <tr> 標籤裡的儲存格, 像這樣: + +
    <tr>
    +  <td>Hi, I'm your first cell.</td>
    +  <td>I'm your second cell.</td>
    +  <td>I'm your third cell.</td>
    +  <td>I'm your fourth cell.</td>
    +</tr>
    +
  2. +
  3. 現在你已經製作了一列了,可以再繼續做一、二列 — 每個列都需要被額外的 <tr> 元素包裹住, 並且每個儲存格都須包含在一個 <td>  內
  4. +
+ +

表格應該會看起來像下面這樣:

+ + + + + + + + + + + + + + + + +
Hi, I'm your first cell.I'm your second cell.I'm your third cell.I'm your fourth cell.
Second row, first cell.Cell 2.Cell 3.Cell 4.
+ +
+

Note: 你也可以在GitHub 上看到 simple-table.html (see it live also).

+
+ +

用 <th> 加上標頭元素

+ +

現在,讓我們把注意力轉移到表格的標頭(table header) — 存在於一列或一欄開頭的特別儲存格並且定義了欄或列中內容的資料型態 (舉個例子, 看看這篇文章中第一個範例裡 的"Person" 和 "Age" 儲存格 )。
+ 為了說明為什麼它們很有用,請看下面的表格例子, 首先是程式碼:

+ +
<table>
+  <tr>
+    <td>&nbsp;</td>
+    <td>Knocky</td>
+    <td>Flor</td>
+    <td>Ella</td>
+    <td>Juan</td>
+  </tr>
+  <tr>
+    <td>Breed</td>
+    <td>Jack Russell</td>
+    <td>Poodle</td>
+    <td>Streetdog</td>
+    <td>Cocker Spaniel</td>
+  </tr>
+  <tr>
+    <td>Age</td>
+    <td>16</td>
+    <td>9</td>
+    <td>10</td>
+    <td>5</td>
+  </tr>
+  <tr>
+    <td>Owner</td>
+    <td>Mother-in-law</td>
+    <td>Me</td>
+    <td>Me</td>
+    <td>Sister-in-law</td>
+  </tr>
+  <tr>
+    <td>Eating Habits</td>
+    <td>Eats everyone's leftovers</td>
+    <td>Nibbles at food</td>
+    <td>Hearty eater</td>
+    <td>Will eat till he explodes</td>
+  </tr>
+</table>
+ +

這是實際渲染出的表格:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KnockyFlorEllaJuan
BreedJack RussellPoodleStreetdogCocker Spaniel
Age169105
OwnerMother-in-lawMeMeSister-in-law
Eating HabitsEats everyone's leftoversNibbles at foodHearty eaterWill eat till he explodes
+ +

這裡的問題在於,當你找到想知道的資料時,並不容易去找到資料之間對應的位置。如果欄跟列能有個明顯的標示,會比較好理解。

+ +

主動學習 : 表格標頭

+ +

讓我們來繼續改善這個表格吧!

+ +
    +
  1. 首先, 複製 dogs-table.html and minimal-table.css 檔案到你的電腦。
    + 這份HTML裡包含跟底下你看到的一樣的狗狗範例。
  2. +
  3. 為了在語意上和視覺上辨識表格的標頭,你可以使用 <th> 元素 ('th' 代表 'table header')。它的運作方式跟 <td> 完全相同,除了它表示的是標頭而非一般儲存格外。
    + 繼續修改你的HTML將所有外圍的 <td> 元素變成 <th> 元素。
  4. +
  5. 儲存你的HTML並在瀏覽器上執行,現在你應該可以看到標頭應有的樣子。
  6. +
+ +
+

Note: 你可以在GitHub上的dogs-table-fixed.html找到我們寫好的完整的範例(直接看看長怎樣).

+
+ +

標頭為什麼實用?

+ +

我們已經部分解答了這個問題 — 當有標頭清楚標示時,它能更簡單的使你找到資料並讓整體設計看起來更完整。

+ +
+

Note: 表格標頭有具備預設樣式 — 粗體並置中,即使你不加上你自己的表格樣式,他們仍然能被凸顯。

+
+ +

表格標頭還有一個額外的好處 — 伴隨著 作用域(scope) 屬性 (我們將會在下一個章節中學到),當要連結每個標頭而所有資料都在同一列或欄時,這能允許表格使用起來更無障礙。並且,螢幕閱讀器能一次性讀出完整一列或一欄的資料,這是非常實用的。

+ +

允許列或欄的儲存格合併

+ +

有時我們想要儲存格涵蓋複數的列或欄,來看看下列顯示常見動物名稱的簡單例子。在某些案例,我們想要將名字代表雄性或雌性顯示在動物名字旁邊,但有些不需要,這種情況下我們只想將動物名字橫跨整個表格。

+ +

初始架構會看起來像這樣:

+ +
<table>
+  <tr>
+    <th>Animals</th>
+  </tr>
+  <tr>
+    <th>Hippopotamus</th>
+  </tr>
+  <tr>
+    <th>Horse</th>
+    <td>Mare</td>
+  </tr>
+  <tr>
+    <td>Stallion</td>
+  </tr>
+  <tr>
+    <th>Crocodile</th>
+  </tr>
+  <tr>
+    <th>Chicken</th>
+    <td>Hen</td>
+  </tr>
+  <tr>
+    <td>Rooster</td>
+  </tr>
+</table>
+ +

但輸出的不如我們想要的樣子:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Animals
Hippopotamus
HorseMare
Stallion
Crocodile
ChickenHen
Rooster
+ +

我們需要一種方式讓"Animals", "Hippopotamus", 和 "Crocodile" 橫跨兩個欄位, 然後讓 "Horse" and "Chicken" 向下合併兩列儲存格。幸運地是,表格標頭和儲存格有 colspan 和 rowspan 屬性,可以讓我們這樣做。 兩者都接受無單位的數值等同於你想合併的列或欄的數量。舉例來說,colspan="2" 會讓這個儲存格合併兩欄。

+ +

來使用 colspan 和 rowspan 來改善這麼表格吧!

+ +
    +
  1. 首先,複製一份我們的 animals-table.html 和 minimal-table.css 檔案在你的電腦上。這個HTML包含跟上面同樣的動物範例。
  2. +
  3. 接著,使用 colspan 來讓 "Animals", "Hippopotamus", 和 "Crocodile" 合併橫跨兩個欄位。
  4. +
  5. 最後, 使用 rowspan 來讓 "Horse" and "Chicken" 合併橫跨兩列。
  6. +
  7. 儲存並在瀏覽器上檢視你改善後的程式碼。
  8. +
+ +
+

Note: 你可以在GitHub上的 animals-table-fixed.html 找到我們寫好的完整的範例 (see it live also).

+
+ + +
+ +

Providing common styling to columns

+ +

在我們繼續下去前,我們將要告訴你這節文章最後一個重點。HTML有一個一次定義一整欄樣式資訊的方法 —  <col>  <colgroup> 元素。These exist because it can be a bit annoying and inefficient having to specify styling on columns — you generally have to specify your styling information on every <td> or <th> in the column, or use a complex selector such as {{cssxref(":nth-child()")}}.

+ +
+

Note: Styling columns like this is limited to a few properties: border, background, width, and visibility. To set other properties you'll have to either style every <td> or <th> in the column, or use a complex selector such as {{cssxref(":nth-child()")}}.

+
+ +

Take the following simple example:

+ +
<table>
+  <tr>
+    <th>Data 1</th>
+    <th style="background-color: yellow">Data 2</th>
+  </tr>
+  <tr>
+    <td>Calcutta</td>
+    <td style="background-color: yellow">Orange</td>
+  </tr>
+  <tr>
+    <td>Robots</td>
+    <td style="background-color: yellow">Jazz</td>
+  </tr>
+</table>
+ +

Which gives us the following result:

+ + + + + + + + + + + + + + + + +
Data 1Data 2
CalcuttaOrange
RobotsJazz
+ +

This isn't ideal, as we have to repeat the styling information across all three cells in the column (we'd probably have a class set on all three in a real project and specify the styling in a separate stylesheet). Instead of doing this, we can specify the information once, on a <col> element. <col> elements are  specified inside a <colgroup> container just below the opening <table> tag. We could create the same effect as we see above by specifying our table as follows:

+ +
<table>
+  <colgroup>
+    <col>
+    <col style="background-color: yellow">
+  </colgroup>
+  <tr>
+    <th>Data 1</th>
+    <th>Data 2</th>
+  </tr>
+  <tr>
+    <td>Calcutta</td>
+    <td>Orange</td>
+  </tr>
+  <tr>
+    <td>Robots</td>
+    <td>Jazz</td>
+  </tr>
+</table>
+ +

Effectively we are defining two "style columns", one specifying styling information for each column. We are not styling the first column, but we still have to include a blank <col> element — if we didn't, the styling would just be applied to the first column.

+ +

If we wanted to apply the styling information to both columns, we could just include one <col> element with a span attribute on it, like this:

+ +
<colgroup>
+  <col style="background-color: yellow" span="2">
+</colgroup>
+ +

Just like colspan and rowspan, span takes a unitless number value that specifies the number of columns you want the styling to apply to.

+ +

Active learning: colgroup and col

+ +

Now it's time to have a go yourself.

+ +

Below you can see the timetable of a languages teacher. On Friday she has a new class teaching Dutch all day, but she also teaches German for a few periods on Tuesday and Thursdays. She wants to highlight the columns containing the days she is teaching.

+ +

{{EmbedGHLiveSample("learning-area/html/tables/basic/timetable-fixed.html", '100%', 320)}}

+ +

Recreate the table by following the steps below.

+ +
    +
  1. First, make a local copy of our timetable.html file in a new directory on your local machine. The HTML contains the same table you saw above, minus the column styling information.
  2. +
  3. Add a <colgroup> element at the top of the table, just underneath the <table> tag, in which you can add your <col> elements (see the remaining steps below).
  4. +
  5. The first two columns need to be left unstyled.
  6. +
  7. Add a background color to the third column. The value for your style attribute is background-color:#97DB9A;
  8. +
  9. Set a separate width on the fourth column. The value for your style attribute is width: 42px;
  10. +
  11. Add a background color to the fifth column. The value for your style attribute is background-color: #97DB9A;
  12. +
  13. Add a different background color plus a border to the sixth column, to signify that this is a special day and she's teaching a new class. The values for your style attribute are background-color:#DCC48E; border:4px solid #C1437A;
  14. +
  15. The last two days are free days, so just set them to no background color but a set width; the value for the style attribute is width: 42px;
  16. +
+ +

See how you get on with the example. If you get stuck, or want to check your work, you can find our version on GitHub as timetable-fixed.html (see it live also).

+ +

Summary

+ +

That just about wraps up the basics of HTML Tables. In the next article we will look at some slightly more advanced table features, and start to think how accessible they are for visually impaired people.

+ +
{{NextMenu("Learn/HTML/Tables/Advanced", "Learn/HTML/Tables")}}
+ +
+

In this module

+ + +
diff --git a/files/zh-tw/learn/index.html b/files/zh-tw/learn/index.html new file mode 100644 index 0000000000..729b0d7999 --- /dev/null +++ b/files/zh-tw/learn/index.html @@ -0,0 +1,238 @@ +--- +title: 學習該如何開發 Web +slug: Learn +tags: + - Beginner + - Index + - Landing + - Learn + - NeedsTranslation + - TopicStub + - Web +translation_of: Learn +--- +
+
+

+ +

{{LearnSidebar}}

+ +

+ +

歡迎來到 MDN 的「學習專區(Learning Area)」。本系列文章將提供撰寫程式碼的必要網站,讓剛接觸的新手也能開發 Web。

+
+ +

MDN 學習專區不是要讓「初學者」變成「專家」;而是想讓「初學者」能夠更怡然自得。你在這裡可完全安排自己的進度,逐步探索 MDN 的其他部分,再接觸進階資源來堆砌之前所習得的知識。

+ +

如果你是完全的新手,那 Web 開發過程可能頗有難度。我們希望能帶領你輕鬆學習,另提供相關細節以培養你的正確觀念。不論你是要學習 Web 開發(自學或參與課程)的學生、尋找教材的老師、純粹興趣使然的業餘工程師,甚至只是想進一步了解 Web 技術的人,都希望你在這裡就像在家裡一樣自在。

+ +
+

重要:此學習專區將定期新增更多資訊。如果你希望能納入其他自己感興趣的主題,或覺得某個地方尚有缺漏,請到下方的{{anch("聯絡我們")}}尋找相關資訊並取得聯繫。

+
+ +

入門

+ + + +
+

注意:我們的字彙庫另提供專有名詞的定義。

+
+ +

{{LearnBox({"title":"Random glossary entry"})}}

+ +

涵蓋主題

+ +

以下是 MDN 學習專區內涵蓋的主題清單。

+ +
+
Web 入門
+
針對完全新手提供實際介紹。
+
HTML:構建 Web
+
HTML 是構建不同區域的內容、還有定義這些區域意義和用途的語言。這個主題詳述了 HTML。
+
CSS:裝飾 Web
+
CSS 是用來妝點和編排 web 內容、添加動畫行為之類的語言。這個主題總括 CSS 的一切。
+
JavaScript:動態用戶端腳本
+
JavaScript 是給網頁添加動態功能的語言。這個主題會教你要自在理解並撰寫 JavaScript 所需的一切。
+
無障礙網頁:讓大家都能用上 Web
+
無障礙網頁是給盡可能給任何人提供 Web 內容的做法,無論那個人是否受障礙、設備、地點、或其他原因影響。這個主題提供你需要知道的一切。
+
工具與測試
+
這個主題介紹開發者用來改善工作的工具,如跨瀏覽器測試工具。
+
伺服端網站程式設計
+
就算對用戶端 Web 開發熟悉了,理解伺服器和伺服器端程式如何做動是很有用的。這個主題提供了伺服器端做動原理的總體介紹,並藉著兩大熱門框架──Django(Python)與 Express(node.js)──詳細說明如何建立伺服器端 app。
+
+ +

取得我們的範例程式碼

+ +

在學習專區看到的所有程式碼都放在 GitHub 上了。如果想把它們複製到自己的電腦,最簡單的方法是:

+ +
    +
  1. 在電腦上安裝 Git。這個版本控制系統,是 GitHub 運作的基礎。
  2. +
  3. 在 GitHub 註冊一個帳號。很簡單的。
  4. +
  5. 註冊好後用自己的帳密登入 github.com
  6. +
  7. 開啟你的命令提示字元(Windows)(譯註:如果使用 Windows 7 以後,建議使用 Powershell)或是終端機(LinuxMacOSX
  8. +
  9. 要把學習專區的 repo 透過命令提示字元/終端機複製到目錄裡面,稱作 learning-area 的資料夾,只要鍵入以下指令: +
    git clone https://github.com/mdn/learning-area
    +
  10. +
  11. 現在你能透過檔案管理員或 cd 指令進入目錄,找到想要的檔案了。
  12. +
+ +

你可以在 GitHub 的 learning-area repository 做任何更新,只要這麼做:

+ +
    +
  1. 在命令提示字元/終端機裡面,用 cd 進到 learning-area 目錄,例如說你要是在上一層目錄的話: + +
    cd learning-area
    +
  2. +
  3. 用這個指令更新 repository: +
    git pull
    +
  4. +
+ +

{{LearnBox({"title":"隨機了解常見的相關術語"})}}

+ +

聯絡我們

+ +

如果你想向我們詢問任何事情,最快的方式就是透過學習專區討論串IRC 頻道留下訊息。不論你覺得網站有哪個地方做錯或缺漏,想看到新的學習主題、對自己不了解的地方尋求協助,或其他疑難雜症,都歡迎你提供意見給我們。

+ +

如果你想幫我們添增\改善內容,則請先了解該如何協助並聯絡我們!不論你是學生、教師、Web 開發老手,或是想幫我們改善學習經驗,都歡迎和我們聯絡。

+ +

另可參閱

+ +
+
Mozilla Developer Newsletter
+
我們針對網頁開發者發行的電子報,對於所有程度的開發者都是很好的學習資源。
+
EXLskills 
+
免費和開放的課程,學習技術技能,指導和基於項目的學習
+
Codecademy
+
絕妙的互動式網站,可從頭開始學習程式設計語言。
+
Code.org
+
基本的編碼理論與實作,主要為孩童與初學者所設計。
+
freeCodeCamp.com
+
富含教學與專案實做的互動式網路開發學習網站。
+
+ +
+
Web Literacy Map
+
Web 素養與 21 世紀常見技術的入門,亦已分門別類提供教學活動。
+
Teaching activities
+
由 Mozilla 基金會所設計的一系列教學 (與學習) 活動,涵蓋 JavaScript 的基本 Web 素養與隱私概念,並可嘗試開發 Minecraft。
+
+ + + +
    +
  1. Web 入門 + +
      +
    1. 安裝基本軟體
    2. +
    3. 你的網站看起來會是什麼樣子?
    4. +
    5. 與各式各樣檔案打交道
    6. +
    7. HTML 基本概念
    8. +
    9. CSS 基本概念
    10. +
    11. JavaScript 基本概念
    12. +
    13. 將你的網站發佈上線
    14. +
    15. 網站的運作方式
    16. +
    +
  2. +
  3. HTML — 建構 Web +
      +
    1. HTML 概述
    2. +
    3. HTML 介紹 +
        +
      1. HTML 基本介紹
      2. +
      3. HTML 入門
      4. +
      5. 先入為主?HTML 的 Metadata
      6. +
      7. HTML 文字基本概念
      8. +
      9. 建立超連結
      10. +
      11. 進階文字格式
      12. +
      13. 文件與網站架構
      14. +
      15. HTML 除錯
      16. +
      17. 評量習題:對字母標記
      18. +
      19. 評量習題:建構內容網頁
      20. +
      +
    4. +
    5. 多媒體與嵌入 +
        +
      1. 多媒體與嵌入概述
      2. +
      3. HTML 圖像
      4. +
      5. 視訊與音訊內容
      6. +
      7. 從物件到 iframe — 其他嵌入技術
      8. +
      9. 為 Web 新增向量圖像
      10. +
      11. 有所回應互動的圖像
      12. +
      13. 評量習題:Mozilla splash 頁面
      14. +
      +
    6. +
    +
  4. +
  5. CSS — 讓 Web 別有風格 +
      +
    1. CSS 概述
    2. +
    3. CSS 介紹 +
        +
      1. CSS 基本介紹
      2. +
      3. CSS 運作方式
      4. +
      5. CSS 語法
      6. +
      7. 選擇器(Selectors)
      8. +
      9. CSS 數值與單位
      10. +
      11. 串接 (Cascade) 與繼承 (Inheritance)
      12. +
      13. 區塊模型 (Box model)
      14. +
      15. CSS 除錯
      16. +
      17. 評量習題:基礎的 CSS 綜合運算 (Comprehension)
      18. +
      +
    4. +
    5. 文字樣式 +
        +
      1. 文字樣式概述
      2. +
      3. 文字與字體樣式基本原則
      4. +
      5. 清單樣式
      6. +
      7. 連結樣式
      8. +
      9. Web 字型
      10. +
      11. 評量習題:Typesetting a community school homepage
      12. +
      +
    6. +
    7. 框盒 (boxes) 樣式 +
        +
      1. 框盒樣式概述
      2. +
      3. 框盒模型 (Box model) 回顧
      4. +
      5. 背景
      6. +
      7. 邊框
      8. +
      9. 表格樣式
      10. +
      11. 進階框盒效果
      12. +
      13. 評量習題:Creating fancy letterheader paper
      14. +
      15. 評量習題:A cool looking box
      16. +
      +
    8. +
    9. CSS 配置 +
        +
      1. CSS 配置概述
      2. +
      3. 浮動布局(Floats)
      4. +
      5. Positioning
      6. +
      7. Practical positioning examples
      8. +
      9. 彈性盒子(Flexbox)
      10. +
      +
    10. +
    +
  6. +
  7. 進階學習教材 +
      +
    1. JavaScript — 動態指令
    2. +
    3. WebGL — 圖像處理
    4. +
    +
  8. +
  9. 常見問題 +
      +
    1. HTML 問題
    2. +
    3. CSS 問題
    4. +
    5. Web 運作方式
    6. +
    7. 工具與設定
    8. +
    9. 設計與親和度
    10. +
    +
  10. +
  11. 該如何貢獻
  12. +
+
diff --git a/files/zh-tw/learn/javascript/building_blocks/build_your_own_function/index.html b/files/zh-tw/learn/javascript/building_blocks/build_your_own_function/index.html new file mode 100644 index 0000000000..80b134992a --- /dev/null +++ b/files/zh-tw/learn/javascript/building_blocks/build_your_own_function/index.html @@ -0,0 +1,246 @@ +--- +title: 建立自己的功能函數 +slug: Learn/JavaScript/Building_blocks/Build_your_own_function +translation_of: Learn/JavaScript/Building_blocks/Build_your_own_function +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}
+ +

通過前一篇文章中討論的大部分基本理論,本文提供了實踐經驗。 在這裡,您將學習構建自己的自定義功能函數。 在此過程中,我們還將解釋處理函數的一些有用細節。

+ + + + + + + + + + + + +
Prerequisites:Basic computer literacy, a basic understanding of HTML and CSS, JavaScript first steps, Functions — reusable blocks of code.
Objective:To provide some practice in building a custom function, and explain a few more useful associated details.
+ +

Active learning: Let's build a function

+ +

The custom function we are going to build will be called displayMessage(). It will display a custom message box on a web page and will act as a customized replacement for a browser's built-in alert() function. We've seen this before, but let's just refresh our memories. Type the following in your browser's JavaScript console, on any page you like:

+ +
alert('This is a message');
+ +

The alert function takes a single argument — the string that is displayed in the alert box. Try varying the string to change the message.

+ +

The alert function is limited: you can alter the message, but you can't easily vary anything else, such as the color, icon, or anything else. We'll build one that will prove to be more fun.

+ +
+

Note: This example should work in all modern browsers fine, but the styling might look a bit funny in slightly older browsers. We'd recommend you doing this exercise in a modern browser like Firefox, Opera, or Chrome.

+
+ +

The basic function

+ +

To begin with, let's put together a basic function.

+ +
+

Note: For function naming conventions, you should follow the same rules as variable naming conventions. This is fine, as you can tell them apart — function names appear with parentheses after them, and variables don't.

+
+ +
    +
  1. Start by accessing the function-start.html file and making a local copy. You'll see that the HTML is simple — the body contains just a single button. We've also provided some basic CSS to style the custom message box, and an empty {{htmlelement("script")}} element to put our JavaScript in.
  2. +
  3. Next, add the following inside the <script> element: +
    function displayMessage() {
    +
    +}
    + We start off with the keyword function, which means we are defining a function. This is followed by the name we want to give to our function, a set of parentheses, and a set of curly braces. Any parameters we want to give to our function go inside the parentheses, and the code that runs when we call the function goes inside the curly braces.
  4. +
  5. Finally, add the following code inside the curly braces: +
    var html = document.querySelector('html');
    +
    +var panel = document.createElement('div');
    +panel.setAttribute('class', 'msgBox');
    +html.appendChild(panel);
    +
    +var msg = document.createElement('p');
    +msg.textContent = 'This is a message box';
    +panel.appendChild(msg);
    +
    +var closeBtn = document.createElement('button');
    +closeBtn.textContent = 'x';
    +panel.appendChild(closeBtn);
    +
    +closeBtn.onclick = function() {
    +  panel.parentNode.removeChild(panel);
    +}
    +
  6. +
+ +

This is quite a lot of code to go through, so we'll walk you through it bit by bit.

+ +

The first line uses a DOM API function called {{domxref("document.querySelector()")}} to select the {{htmlelement("html")}} element and store a reference to it in a variable called html, so we can do things to it later on:

+ +
var html = document.querySelector('html');
+ +

The next section uses another DOM API function called {{domxref("Document.createElement()")}} to create a {{htmlelement("div")}} element and store a reference to it in a variable called panel. This element will be the outer container of our message box.

+ +

We then use yet another DOM API function called {{domxref("Element.setAttribute()")}} to set a class attribute on our panel with a value of msgBox. This is to make it easier to style the element — if you look at the CSS on the page, you'll see that we are using a .msgBox class selector to style the message box and its contents.

+ +

Finally, we call a DOM function called {{domxref("Node.appendChild()")}} on the html variable we stored earlier, which nests one element inside the other as a child of it. We specify the panel <div> as the child we want to append inside the <html> element. We need to do this as the element we created won't just appear on the page on its own — we need to specify where to put it.

+ +
var panel = document.createElement('div');
+panel.setAttribute('class', 'msgBox');
+html.appendChild(panel);
+ +

The next two sections make use of the same createElement() and appendChild() functions we've already seen to create two new elements — a {{htmlelement("p")}} and a {{htmlelement("button")}} — and insert them in the page as children of the panel <div>. We use their {{domxref("Node.textContent")}} property — which represents the text content of an element — to insert a message inside the paragraph, and an 'x' inside the button. This button will be what needs to be clicked/activated when the user wants to close the message box.

+ +
var msg = document.createElement('p');
+msg.textContent = 'This is a message box';
+panel.appendChild(msg);
+
+var closeBtn = document.createElement('button');
+closeBtn.textContent = 'x';
+panel.appendChild(closeBtn);
+ +

Finally, we use an {{domxref("GlobalEventHandlers.onclick")}} event handler to make it so that when the button is clicked, some code is run to delete the whole panel from the page — to close the message box.

+ +

Briefly, the onclick handler is a property available on the button (or in fact, any element on the page) that can be set to a function to specify what code to run when the button is clicked. You'll learn a lot more about these in our later events article. We are making the onclick handler equal to an anonymous function, which contains the code to run when the button is clicked. The line inside the function uses the {{domxref("Node.removeChild()")}} DOM API function to specify that we want to remove a specific child element of the HTML element — in this case the panel <div>.

+ +
closeBtn.onclick = function() {
+  panel.parentNode.removeChild(panel);
+}
+ +

Basically, this whole block of code is generating a block of HTML that looks like so, and inserting it into the page:

+ +
<div class="msgBox">
+  <p>This is a message box</p>
+  <button>x</button>
+</div>
+ +

That was a lot of code to work through — don't worry too much if you don't remember exactly how every bit of it works right now! The main part we want to focus on here is the function's structure and usage, but we wanted to show something interesting for this example.

+ +

Calling the function

+ +

You've now got your function definition written into your <script> element just fine, but it will do nothing as it stands.

+ +
    +
  1. Try including the following line below your function to call it: +
    displayMessage();
    + This line invokes the function, making it run immediately. When you save your code and reload it in the browser, you'll see the little message box appear immediately, only once. We are only calling it once, after all.
  2. +
  3. +

    Now open your browser developer tools on the example page, go to the JavaScript console and type the line again there, you'll see it appear again! So this is fun — we now have a reusable function that we can call any time we like.

    + +

    But we probably want it to appear in response to user and system actions. In a real application, such a message box would probably be called in response to new data being available, or an error having occurred, or the user trying to delete their profile ("are you sure about this?"), or the user adding a new contact and the operation completing successfully ... etc.

    + +

    In this demo, we'll get the message box to appear when the user clicks the button.

    +
  4. +
  5. Delete the previous line you added.
  6. +
  7. Next, we'll select the button and store a reference to it in a variable. Add the following line to your code, above the function definition: +
    var btn = document.querySelector('button');
    +
  8. +
  9. Finally, add the following line below the previous one: +
    btn.onclick = displayMessage;
    + In a similar way to our closeBtn.onclick... line inside the function, here we are calling some code in response to a button being clicked. But in this case, instead of calling an anonymous function containing some code, we are calling our function name directly.
  10. +
  11. Try saving and refreshing the page — now you should see the message box appear when you click the button.
  12. +
+ +

You might be wondering why we haven't included the parentheses after the function name. This is because we don't want to call the function immediately — only after the button has been clicked. If you try changing the line to

+ +
btn.onclick = displayMessage();
+ +

and saving and reloading, you'll see that the message box appears without the button being clicked! The parentheses in this context are sometimes called the "function invocation operator". You only use them when you want to run the function immediately in the current scope. In the same respect, the code inside the anonymous function is not run immediately, as it is inside the function scope.

+ +

If you tried the last experiment, make sure to undo the last change before carrying on.

+ +

Improving the function with parameters

+ +

As it stands, the function is still not very useful — we don't want to just show the same default message every time. Let's improve our function by adding some parameters, allowing us to call it with some different options.

+ +
    +
  1. First of all, update the first line of the function: +
    function displayMessage() {
    + to this: + +
    function displayMessage(msgText, msgType) {
    + Now when we call the function, we can provide two variable values inside the parentheses to specify the message to display in the message box, and the type of message it is.
  2. +
  3. To make use of the first parameter, update the following line inside your function: +
    msg.textContent = 'This is a message box';
    + to + +
    msg.textContent = msgText;
    +
  4. +
  5. Last but not least, you now need to update your function call to include some updated message text. Change the following line: +
    btn.onclick = displayMessage;
    + to this block: + +
    btn.onclick = function() {
    +  displayMessage('Woo, this is a different message!');
    +};
    + If we want to specify parameters inside parentheses for the function we are calling, then we can't call it directly — we need to put it inside an anonymous function so that it isn't in the immediate scope and therefore isn't called immediately. Now it will not be called until the button is clicked.
  6. +
  7. Reload and try the code again and you'll see that it still works just fine, except that now you can also vary the message inside the parameter to get different messages displayed in the box!
  8. +
+ +

A more complex parameter

+ +

On to the next parameter. This one is going to involve slightly more work — we are going to set it so that depending on what the msgType parameter is set to, the function will display a different icon and a different background color.

+ +
    +
  1. First of all, download the icons needed for this exercise (warning and chat) from GitHub. Save them in a new folder called icons in the same location as your HTML file. + +
    Note: warning and chat icons found on iconfinder.com, and designed by Nazarrudin Ansyari. Thanks!
    +
  2. +
  3. Next, find the CSS inside your HTML file. We'll make a few changes to make way for the icons. First, update the .msgBox width from: +
    width: 200px;
    + to + +
    width: 242px;
    +
  4. +
  5. Next, add the following lines inside the .msgBox p { ... } rule: +
    padding-left: 82px;
    +background-position: 25px center;
    +background-repeat: no-repeat;
    +
  6. +
  7. Now we need to add code to our displayMessage() function to handle displaying the icons. Add the following block just above the closing curly brace (}) of your function: +
    if (msgType === 'warning') {
    +  msg.style.backgroundImage = 'url(icons/warning.png)';
    +  panel.style.backgroundColor = 'red';
    +} else if (msgType === 'chat') {
    +  msg.style.backgroundImage = 'url(icons/chat.png)';
    +  panel.style.backgroundColor = 'aqua';
    +} else {
    +  msg.style.paddingLeft = '20px';
    +}
    + Here, if the msgType parameter is set as 'warning', the warning icon is displayed and the panel's background color is set to red. If it is set to 'chat', the chat icon is displayed and the panel's background color is set to aqua blue. If the msgType parameter is not set at all (or to something different), then the else { ... } part of the code comes into play, and the paragraph is simply given default padding and no icon, with no background panel color set either. This provides a default state if no msgType parameter is provided, meaning that it is an optional parameter!
  8. +
  9. Let's test out our updated function, try updating the displayMessage() call from this: +
    displayMessage('Woo, this is a different message!');
    + to one of these: + +
    displayMessage('Your inbox is almost full — delete some mails', 'warning');
    +displayMessage('Brian: Hi there, how are you today?','chat');
    + You can see how useful our (now not so) little function is becoming.
  10. +
+ +
+

Note: If you have trouble getting the example to work, feel free to check your code against the finished version on GitHub (see it running live also), or ask us for help.

+
+ +

Conclusion

+ +

Congratulations on reaching the end! This article took you through the entire process of building up a practical custom function, which with a bit more work could be transplanted into a real project. In the next article we'll wrap up functions by explaining another essential related concept — return values.

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}

+ +

 

+ +

In this module

+ + + +

 

diff --git a/files/zh-tw/learn/javascript/building_blocks/conditionals/index.html b/files/zh-tw/learn/javascript/building_blocks/conditionals/index.html new file mode 100644 index 0000000000..8b63b1034d --- /dev/null +++ b/files/zh-tw/learn/javascript/building_blocks/conditionals/index.html @@ -0,0 +1,789 @@ +--- +title: 在代碼中做出決定 - 條件 +slug: Learn/JavaScript/Building_blocks/conditionals +translation_of: Learn/JavaScript/Building_blocks/conditionals +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}
+ +

在任何編程語言中,代碼都需要根據不同的輸入做出決策並相應地執行操作。 例如,在遊戲中,如果玩家的生命數量為0,則遊戲結束。 在天氣應用程序中,如果在早上查看,則顯示日出圖形; 如果是夜晚,則顯示星星和月亮。 在本文中,我們將探討條件結構如何在JavaScript中工作。

+ + + + + + + + + + + + +
Prerequisites:Basic computer literacy, a basic understanding of HTML and CSS, JavaScript first steps.
Objective:To understand how to use conditional structures in JavaScript.
+ +

你可以擁有一個條件..!

+ +

從小到大,人們(和其它動物)作出決定的時間會影響到他們的生活 ("我應該吃一個或兩個餅乾?")  ("我應該留在我的家鄉並在我父親的農場工作還是應該要到美國研讀天體物理學?")

+ +

條件敘述句(Conditional statements)讓我們能將這些決定的過程在Javascript表示出來,從一定得做出的選擇(例如:「吃一個或兩個餅乾」),到這些選擇的結果(或許「吃一個餅乾」會出現「還是會餓」這種結果,而「吃兩個餅乾」的結果會是「吃飽了,但因為吃了全部餅乾而被媽媽罵」)。

+ +

+ +

if ... else 敘述句

+ +

讓我們來看Javascript中最常見的條件敘述句 if ... else statement.

+ +

基本的 if ... else 語法

+ +

最基本的 if...else 語法看起來像以下 {{glossary("虛擬碼")}}:

+ +
if (condition) {
+  code to run if condition is true
+} else {
+  run some other code instead
+}
+ +

這邊我們可以得知基礎的架構:

+ +
    +
  1. 關鍵字 if 和後頭的括號。
  2. +
  3. 想測試的條件放在括號中(通常像是「這個值是否大於其他值」或是「這個值是否存在」等等)。這裡的條件會使用先前提過的 比較運算子comparison operators),並且最後會回傳 true 或是 false
  4. +
  5. 第一組大括號,在大括號裡面有一些程式碼 — 內容可以是任何我們所需要執行的程式碼,並且只有在條件句回傳 true 才會執行。
  6. +
  7. 關鍵字 else
  8. +
  9. 另一組大括號,在大括號中我們一樣是放置所需的程式碼,並只有在條件句回傳 false 才會執行。
  10. +
+ +

這個程式碼的架構很容易理解  — 「如果條件回傳 true ,則執行程式A,否則執行程式B」。

+ +

值得注意的是,else 和第二組大括號並不是必要的。如以下範例也能夠執行:

+ +
if (condition) {
+  code to run if condition is true
+}
+
+run some other code
+ +

然而,在這邊有一點要注意:在這個例子中的第二個區塊並沒有被條件式控制,也就是說無論條件式回傳的是 true 或是 false,它都會執行。這並不一定是件壞事,但它可能不會是你要的,通常你可能是想要執行程式碼的一個區塊或是另一塊,而不是兩個都執行。

+ +

最後一點,你可能有時候會看到 if...else 敘述是不加大括弧的:

+ +
if (condition) code to run if condition is true
+else run some other code instead
+ +

這當然也是有效的程式碼,但不太建議這樣用。使用大括弧能夠很清楚地看到程式區塊、縮排,也能夠擁有多行程式碼,對於程式的可讀性會提高許多。

+ +

A real example

+ +

To understand this syntax better, let's consider a real example. Imagine a child being asked for help with a chore by their mother or father. The parent might say "Hey sweetheart, if you help me by going and doing the shopping, I'll give you some extra allowance so you can afford that toy you wanted." In JavaScript, we could represent this like so:

+ +
var shoppingDone = false;
+
+if (shoppingDone === true) {
+  var childsAllowance = 10;
+} else {
+  var childsAllowance = 5;
+}
+ +

This code as shown will always result in the shoppingDone variable returning false, meaning disappointment for our poor child. It'd be up to us to provide a mechanism for the parent to set the shoppingDone variable to true if the child did the shopping.

+ +
+

Note: You can see a more complete version of this example on GitHub (also see it running live.)

+
+ +

else if

+ +

The last example provided us with two choices, or outcomes — but what if we want more than two?

+ +

There is a way to chain on extra choices/outcomes to your if...else — using else if. Each extra choice requires an additional block to put in between if() { ... } and else { ... } — check out the following more involved example, which could be part of a simple weather forecast application:

+ +
<label for="weather">Select the weather type today: </label>
+<select id="weather">
+  <option value="">--Make a choice--</option>
+  <option value="sunny">Sunny</option>
+  <option value="rainy">Rainy</option>
+  <option value="snowing">Snowing</option>
+  <option value="overcast">Overcast</option>
+</select>
+
+<p></p>
+ +
var select = document.querySelector('select');
+var para = document.querySelector('p');
+
+select.addEventListener('change', setWeather);
+
+function setWeather() {
+  var choice = select.value;
+
+  if (choice === 'sunny') {
+    para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.';
+  } else if (choice === 'rainy') {
+    para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.';
+  } else if (choice === 'snowing') {
+    para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.';
+  } else if (choice === 'overcast') {
+    para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.';
+  } else {
+    para.textContent = '';
+  }
+}
+
+
+ +

{{ EmbedLiveSample('else_if', '100%', 100, "", "", "hide-codepen-jsfiddle") }}

+ +
    +
  1. Here we've got an HTML {{htmlelement("select")}} element allowing us to make different weather choices, and a simple paragraph.
  2. +
  3. In the JavaScript, we are storing a reference to both the {{htmlelement("select")}} and {{htmlelement("p")}} elements, and adding an event listener to the <select> element so that when its value is changed, the setWeather() function is run.
  4. +
  5. When this function is run, we first set a variable called choice to the current value selected in the <select> element. We then use a conditional statement to show different text inside the paragraph depending on what the value of choice is. Notice how all the conditions are tested in else if() {...} blocks, except for the first one, which is tested in an if() {...} block.
  6. +
  7. The very last choice, inside the else {...} block, is basically a "last resort" option — the code inside it will be run if none of the conditions are true. In this case, it serves to empty the text out of the paragraph if nothing is selected, for example if a user decides to re-select the "--Make a choice--" placeholder option shown at the beginning.
  8. +
+ +
+

Note: You can also find this example on GitHub (see it running live on there also.)

+
+ +

A note on comparison operators

+ +

Comparison operators are used to test the conditions inside our conditional statements. We first looked at comparison operators back in our Basic math in JavaScript — numbers and operators article. Our choices are:

+ + + +
+

Note: Review the material at the previous link if you want to refresh your memories on these.

+
+ +

We wanted to make a special mention of testing boolean (true/false) values, and a common pattern you'll come across again and again. Any value that is not false, undefined, null, 0, NaN, or an empty string ('') actually returns true when tested as a conditional statement, therefore you can simply use a variable name on its own to test whether it is true, or even that it exists (i.e. it is not undefined.) So for example:

+ +
var cheese = 'Cheddar';
+
+if (cheese) {
+  console.log('Yay! Cheese available for making cheese on toast.');
+} else {
+  console.log('No cheese on toast for you today.');
+}
+ +

And, returning to our previous example about the child doing a chore for their parent, you could write it like this:

+ +
var shoppingDone = false;
+
+if (shoppingDone) { // don't need to explicitly specify '=== true'
+  var childsAllowance = 10;
+} else {
+  var childsAllowance = 5;
+}
+ +

Nesting if ... else

+ +

It is perfectly OK to put one if...else statement inside another one — to nest them. For example, we could update our weather forecast application to show a further set of choices depending on what the temperature is:

+ +
if (choice === 'sunny') {
+  if (temperature < 86) {
+    para.textContent = 'It is ' + temperature + ' degrees outside — nice and sunny. Let\'s go out to the beach, or the park, and get an ice cream.';
+  } else if (temperature >= 86) {
+    para.textContent = 'It is ' + temperature + ' degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.';
+  }
+}
+ +

Even though the code all works together, each if...else statement works completely independently of the other one.

+ +

Logical operators: AND, OR and NOT

+ +

If you want to test multiple conditions without writing nested if...else statements, logical operators can help you. When used in conditions, the first two do the following:

+ + + +

To give you an AND example, the previous example snippet can be rewritten to this:

+ +
if (choice === 'sunny' && temperature < 86) {
+  para.textContent = 'It is ' + temperature + ' degrees outside — nice and sunny. Let\'s go out to the beach, or the park, and get an ice cream.';
+} else if (choice === 'sunny' && temperature >= 86) {
+  para.textContent = 'It is ' + temperature + ' degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.';
+}
+ +

So for example, the first code block will only be run if choice === 'sunny' and temperature < 86 return true.

+ +

Let's look at a quick OR example:

+ +
if (iceCreamVanOutside || houseStatus === 'on fire') {
+  console.log('You should leave the house quickly.');
+} else {
+  console.log('Probably should just stay in then.');
+}
+ +

The last type of logical operator, NOT, expressed by the ! operator, can be used to negate an expression. Let's combine it with OR in the above example:

+ +
if (!(iceCreamVanOutside || houseStatus === 'on fire')) {
+  console.log('Probably should just stay in then.');
+} else {
+  console.log('You should leave the house quickly.');
+}
+ +

In this snippet, if the OR statement returns true, the NOT operator will negate it so that the overall expression returns false.

+ +

You can combine as many logical statements together as you want, in whatever structure. The following example executes the code inside only if both OR statements return true, meaning that the overall AND statement will return true:

+ +
if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === 'Steve')) {
+  // run the code
+}
+ +

A common mistake when using the logical OR operator in conditional statements is to try to state the variable whose value you are checking once, and then give a list of values it could be to return true, separated by || (OR) operators. For example:

+ +
if (x === 5 || 7 || 10 || 20) {
+  // run my code
+}
+ +

In this case the condition inside if(...)  will always evaluate to true since 7 (or any other non-zero value) always evaluates to true. This condition is actually saying "if x equals 5, or 7 is true — which it always is". This is logically not what we want! To make this work you've got to specify a complete test either side of each OR operator:

+ +
if (x === 5 || x === 7 || x === 10 ||x === 20) {
+  // run my code
+}
+ +

switch statements

+ +

if...else statements do the job of enabling conditional code well, but they are not without their downsides. They are mainly good for cases where you've got a couple of choices, and each one requires a reasonable amount of code to be run, and/or the conditions are complex (e.g. multiple logical operators). For cases where you just want to set a variable to a certain choice of value or print out a particular statement depending on a condition, the syntax can be a bit cumbersome, especially if you've got a large number of choices.

+ +

switch statements are your friend here — they take a single expression/value as an input, and then look through a number of choices until they find one that matches that value, executing the corresponding code that goes along with it. Here's some more pseudocode, to give you an idea:

+ +
switch (expression) {
+  case choice1:
+    run this code
+    break;
+
+  case choice2:
+    run this code instead
+    break;
+
+  // include as many cases as you like
+
+  default:
+    actually, just run this code
+}
+ +

Here we've got:

+ +
    +
  1. The keyword switch, followed by a set of parentheses.
  2. +
  3. An expression or value inside the parentheses.
  4. +
  5. The keyword case, followed by a choice that the expression/value could be, followed by a colon.
  6. +
  7. Some code to run if the choice matches the expression.
  8. +
  9. A break statement, followed by a semi-colon. If the previous choice matches the expression/value, the browser stops executing the code block here, and moves on to any code that appears below the switch statement.
  10. +
  11. As many other cases (bullets 3–5) as you like.
  12. +
  13. The keyword default, followed by exactly the same code pattern as one of the cases (bullets 3–5), except that default does not have a choice after it, and you don't need to break statement as there is nothing to run after this in the block anyway. This is the default option that runs if none of the choices match.
  14. +
+ +
+

Note: You don't have to include the default section — you can safely omit it if there is no chance that the expression could end up equaling an unknown value. If there is a chance of this however, you need to include it to handle unknown cases.

+
+ +

A switch example

+ +

Let's have a look at a real example — we'll rewrite our weather forecast application to use a switch statement instead:

+ +
<label for="weather">Select the weather type today: </label>
+<select id="weather">
+  <option value="">--Make a choice--</option>
+  <option value="sunny">Sunny</option>
+  <option value="rainy">Rainy</option>
+  <option value="snowing">Snowing</option>
+  <option value="overcast">Overcast</option>
+</select>
+
+<p></p>
+ +
var select = document.querySelector('select');
+var para = document.querySelector('p');
+
+select.addEventListener('change', setWeather);
+
+
+function setWeather() {
+  var choice = select.value;
+
+  switch (choice) {
+    case 'sunny':
+      para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.';
+      break;
+    case 'rainy':
+      para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.';
+      break;
+    case 'snowing':
+      para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.';
+      break;
+    case 'overcast':
+      para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.';
+      break;
+    default:
+      para.textContent = '';
+  }
+}
+ +

{{ EmbedLiveSample('A_switch_example', '100%', 100, "", "", "hide-codepen-jsfiddle") }}

+ +
+

Note: You can also find this example on GitHub (see it running live on there also.)

+
+ +

三元運算符

+ +

There is one final bit of syntax we want to introduce you to, before we get you to play with some examples. The ternary or conditional operator is a small bit of syntax that tests a condition and returns one value/expression if it is true, and another if it is false — this can be useful in some situations, and can take up a lot less code than an if...else block if you simply have two choices that are chosen between via a true/false condition. The pseudocode looks like this:

+ +
( condition ) ? run this code : run this code instead
+ +

So let's look at a simple example:

+ +
var greeting = ( isBirthday ) ? 'Happy birthday Mrs. Smith — we hope you have a great day!' : 'Good morning Mrs. Smith.';
+ +

Here we have a variable called isBirthday — if this is true, we give our guest a happy birthday message; if not, we give her the standard daily greeting.

+ +

Ternary operator example

+ +

You don't just have to set variable values with the ternary operator; you can also run functions, or lines of code — anything you like. The following live example shows a simple theme chooser where the styling for the site is applied using a ternary operator.

+ +
<label for="theme">Select theme: </label>
+<select id="theme">
+  <option value="white">White</option>
+  <option value="black">Black</option>
+</select>
+
+<h1>This is my website</h1>
+ +
var select = document.querySelector('select');
+var html = document.querySelector('html');
+document.body.style.padding = '10px';
+
+function update(bgColor, textColor) {
+  html.style.backgroundColor = bgColor;
+  html.style.color = textColor;
+}
+
+select.onchange = function() {
+  ( select.value === 'black' ) ? update('black','white') : update('white','black');
+}
+
+ +

{{ EmbedLiveSample('Ternary_operator_example', '100%', 300, "", "", "hide-codepen-jsfiddle") }}

+ +

Here we've got a {{htmlelement('select')}} element to choose a theme (black or white), plus a simple {{htmlelement('h1')}} to display a website title. We also have a function called update(), which takes two colors as parameters (inputs). The website's background color is set to the first provided color, and its text color is set to the second provided color.

+ +

Finally, we've also got an onchange event listener that serves to run a function containing a ternary operator. It starts with a test condition — select.value === 'black'. If this returns true, we run the update() function with parameters of black and white, meaning that we end up with background color of black and text color of white. If it returns false, we run the update() function with parameters of white and black, meaning that the site color are inverted.

+ +
+

Note: You can also find this example on GitHub (see it running live on there also.)

+
+ +

Active learning: A simple calendar

+ +

In this example you are going to help us finish a simple calendar application. In the code you've got:

+ + + +

We need you to write a conditional statement inside the onchange handler function, just below the // ADD CONDITIONAL HERE comment. It should:

+ +
    +
  1. Look at the selected month (stored in the choice variable. This will be the <select> element value after the value changes, so "January" for example.)
  2. +
  3. Set a variable called days to be equal to the number of days in the selected month. To do this you'll have to look up the number of days in each month of the year. You can ignore leap years for the purposes of this example.
  4. +
+ +

Hints:

+ + + +

If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution.

+ + + +

{{ EmbedLiveSample('Playable_code', '100%', 1110, "", "", "hide-codepen-jsfiddle") }}

+ +

Active learning: More color choices!

+ +

In this example you are going to take the ternary operator example we saw earlier and convert the ternary operator into a switch statement that will allow us to apply more choices to the simple website. Look at the {{htmlelement("select")}} — this time you'll see that it has not two theme options, but five. You need to add a switch statement just underneath the // ADD SWITCH STATEMENT comment:

+ + + +

If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution.

+ + + +

{{ EmbedLiveSample('Playable_code_2', '100%', 950, "", "", "hide-codepen-jsfiddle") }}

+ +

Conclusion

+ +

And that's all you really need to know about conditional structures in JavaScript right now! I'm sure you'll have understood these concepts and worked through the examples with ease; if there is anything you didn't understand, feel free to read through the article again, or contact us to ask for help.

+ +

See also

+ + + +

{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/javascript/building_blocks/functions/index.html b/files/zh-tw/learn/javascript/building_blocks/functions/index.html new file mode 100644 index 0000000000..719180656f --- /dev/null +++ b/files/zh-tw/learn/javascript/building_blocks/functions/index.html @@ -0,0 +1,396 @@ +--- +title: 函數 - 可重複使用的代碼塊 +slug: Learn/JavaScript/Building_blocks/Functions +translation_of: Learn/JavaScript/Building_blocks/Functions +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}
+ +

編碼中的另一個基本概念是函數,它允許您存儲一段代碼,該代碼在定義的塊內執行單個任務,然後在需要時使用一個簡短命令調用該代碼 - 而不必輸入相同的代碼 代碼多次。 在本文中,我們將探索函數背後的基本概念,例如基本語法,如何調用和定義它們,範圍和參數。

+ + + + + + + + + + + + +
Prerequisites:Basic computer literacy, a basic understanding of HTML and CSS, JavaScript first steps.
Objective:To understand the fundamental concepts behind JavaScript functions.
+ +

Where do I find functions?

+ +

In JavaScript, you'll find functions everywhere. In fact, we've been using functions all the way through the course so far; we've just not been talking about them very much. Now is the time, however, for us to start talking about functions explicitly, and really exploring their syntax.

+ +

Pretty much anytime you make use of a JavaScript structure that features a pair of parentheses — () — and you're not using a common built-in language structure like a for loop, while or do...while loop, or if...else statement, you are making use of a function.

+ +

Built-in browser functions

+ +

We've made use of functions built in to the browser a lot in this course. Every time we manipulated a text string, for example:

+ +
var myText = 'I am a string';
+var newString = myText.replace('string', 'sausage');
+console.log(newString);
+// the replace() string function takes a string,
+// replaces one substring with another, and returns
+// a new string with the replacement made
+ +

Or every time we manipulated an array:

+ +
var myArray = ['I', 'love', 'chocolate', 'frogs'];
+var madeAString = myArray.join(' ');
+console.log(madeAString);
+// the join() function takes an array, joins
+// all the array items together into a single
+// string, and returns this new string
+ +

Or every time we generated a random number:

+ +
var myNumber = Math.random();
+// the random() function generates a random
+// number between 0 and 1, and returns that
+// number
+ +

...we were using a function!

+ +
+

Note: Feel free to enter these lines into your browser's JavaScript console to re-familiarize yourself with their functionality, if needed.

+
+ +

The JavaScript language has many built-in functions to allow you to do useful things without having to write all that code yourself. In fact, some of the code you are calling when you invoke (a fancy word for run, or execute) a built in browser function couldn't be written in JavaScript — many of these functions are calling parts of the background browser code, which is written largely in low-level system languages like C++, not web languages like JavaScript.

+ +

Bear in mind that some built-in browser functions are not part of the core JavaScript language — some are defined as part of browser APIs, which build on top of the default language to provide even more functionality (refer to this early section of our course for more descriptions). We'll look at using browser APIs in more detail in a later module.

+ +

Functions versus methods

+ +

One thing we need to clear up before we move on — technically speaking, built in browser functions are not functions — they are methods. This sounds a bit scary and confusing, but don't worry — the words function and method are largely interchangeable, at least for our purposes, at this stage in your learning.

+ +

The distinction is that methods are functions defined inside objects. Built-in browser functions (methods) and variables (which are called properties) are stored inside structured objects, to make the code more efficient and easier to handle.

+ +

You don't need to learn about the inner workings of structured JavaScript objects yet — you can wait until our later module that will teach you all about the inner workings of objects, and how to create your own. For now, we just wanted to clear up any possible confusion of method versus function — you are likely to meet both terms as you look at the available related resources across the Web.

+ +

Custom functions

+ +

You've also seen a lot of custom functions in the course so far — functions defined in your code, not inside the browser. Anytime you saw a custom name with parentheses straight after it, you were using a custom function. In our random-canvas-circles.html example (see also the full source code) from our loops article, we included a custom draw() function that looked like this:

+ +
function draw() {
+  ctx.clearRect(0,0,WIDTH,HEIGHT);
+  for (var i = 0; i < 100; i++) {
+    ctx.beginPath();
+    ctx.fillStyle = 'rgba(255,0,0,0.5)';
+    ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+    ctx.fill();
+  }
+}
+ +

This function draws 100 random circles inside an {{htmlelement("canvas")}} element. Every time we want to do that, we can just invoke the function with this

+ +
draw();
+ +

rather than having to write all that code out again every time we want to repeat it. And functions can contain whatever code you like — you can even call other functions from inside functions. The above function for example calls the random() function three times, which is defined by the following code:

+ +
function random(number) {
+  return Math.floor(Math.random()*number);
+}
+ +

We needed this function because the browser's built-in Math.random() function only generates a random decimal number between 0 and 1. We wanted a random whole number between 0 and a specified number.

+ +

Invoking functions

+ +

You are probably clear on this by now, but just in case ... to actually use a function after it has been defined, you've got to run — or invoke — it. This is done by including the name of the function in the code somewhere, followed by parentheses.

+ +
function myFunction() {
+  alert('hello');
+}
+
+myFunction()
+// calls the function once
+ +

Anonymous functions

+ +

You may see functions defined and invoked in slightly different ways. So far we have just created a function like so:

+ +
function myFunction() {
+  alert('hello');
+}
+ +

But you can also create a function that doesn't have a name:

+ +
function() {
+  alert('hello');
+}
+ +

This is called an anonymous function — it has no name! It also won't do anything on its own. You generally use an anonymous function along with an event handler, for example the following would run the code inside the function whenever the associated button is clicked:

+ +
var myButton = document.querySelector('button');
+
+myButton.onclick = function() {
+  alert('hello');
+}
+ +

The above example would require there to be a {{htmlelement("button")}} element available on the page to select and click. You've already seen this structure a few times throughout the course, and you'll learn more about and see it in use in the next article.

+ +

You can also assign an anonymous function to be the value of a variable, for example:

+ +
var myGreeting = function() {
+  alert('hello');
+}
+ +

This function could now be invoked using:

+ +
myGreeting();
+ +

This effectively gives the function a name; you can also assign the function to be the value of multiple variables, for example:

+ +
var anotherGreeting = function() {
+  alert('hello');
+}
+ +

This function could now be invoked using either of

+ +
myGreeting();
+anotherGreeting();
+ +

But this would just be confusing, so don't do it! When creating functions, it is better to just stick to this form:

+ +
function myGreeting() {
+  alert('hello');
+}
+ +

You will mainly use anonymous functions to just run a load of code in response to an event firing — like a button being clicked — using an event handler. Again, this looks something like this:

+ +
myButton.onclick = function() {
+  alert('hello');
+  // I can put as much code
+  // inside here as I want
+}
+ +

Function parameters

+ +

Some functions require parameters to be specified when you are invoking them — these are values that need to be included inside the function parentheses, which it needs to do its job properly.

+ +
+

Note: Parameters are sometimes called arguments, properties, or even attributes.

+
+ +

As an example, the browser's built-in Math.random() function doesn't require any parameters. When called, it always returns a random number between 0 and 1:

+ +
var myNumber = Math.random();
+ +

The browser's built-in string replace() function however needs two parameters — the substring to find in the main string, and the substring to replace that string with:

+ +
var myText = 'I am a string';
+var newString = myText.replace('string', 'sausage');
+ +
+

Note: When you need to specify multiple parameters, they are separated by commas.

+
+ +

It should also be noted that sometimes parameters are optional — you don't have to specify them. If you don't, the function will generally adopt some kind of default behavior. As an example, the array join() function's parameter is optional:

+ +
var myArray = ['I', 'love', 'chocolate', 'frogs'];
+var madeAString = myArray.join(' ');
+// returns 'I love chocolate frogs'
+var madeAString = myArray.join();
+// returns 'I,love,chocolate,frogs'
+ +

If no parameter is included to specify a joining/delimiting character, a comma is used by default.

+ +

Function scope and conflicts

+ +

Let's talk a bit about {{glossary("scope")}} — a very important concept when dealing with functions. When you create a function, the variables and other things defined inside the function are inside their own separate scope, meaning that they are locked away in their own separate compartments, unreachable from inside other functions or from code outside the functions.

+ +

The top level outside all your functions is called the global scope. Values defined in the global scope are accessible from everywhere in the code.

+ +

JavaScript is set up like this for various reasons — but mainly because of security and organization. Sometimes you don't want variables to be accessible from everywhere in the code — external scripts that you call in from elsewhere could start to mess with your code and cause problems because they happen to be using the same variable names as other parts of the code, causing conflicts. This might be done maliciously, or just by accident.

+ +

For example, say you have an HTML file that is calling in two external JavaScript files, and both of them have a variable and a function defined that use the same name:

+ +
<!-- Excerpt from my HTML -->
+<script src="first.js"></script>
+<script src="second.js"></script>
+<script>
+  greeting();
+</script>
+ +
// first.js
+var name = 'Chris';
+function greeting() {
+  alert('Hello ' + name + ': welcome to our company.');
+}
+ +
// second.js
+var name = 'Zaptec';
+function greeting() {
+  alert('Our company is called ' + name + '.');
+}
+ +

Both functions you want to call are called greeting(), but you can only ever access the second.js file's greeting() function — it is applied to the HTML later on in the source code, so its variable and function overwrite the ones in first.js.

+ +
+

Note: You can see this example running live on GitHub (see also the source code).

+
+ +

Keeping parts of your code locked away in functions avoids such problems, and is considered best practice.

+ +

It is a bit like a zoo. The lions, zebras, tigers, and penguins are kept in their own enclosures, and only have access to the things inside their enclosures — in the same manner as the function scopes. If they were able to get into other enclosures, problems would occur. At best, different animals would feel really uncomfortable inside unfamiliar habitats — a lion or tiger would feel terrible inside the penguins' watery, icy domain. At worst, the lions and tigers might try to eat the penguins!

+ +

+ +

The zoo keeper is like the global scope — he or she has the keys to access every enclosure, to restock food, tend to sick animals, etc.

+ +

Active learning: Playing with scope

+ +

Let's look at a real example to demonstrate scoping.

+ +
    +
  1. First, make a local copy of our function-scope.html example. This contains two functions called a() and b(), and three variables — x, y, and z — two of which are defined inside the functions, and one in the global scope. It also contains a third function called output(), which takes a single parameter and outputs it in a paragraph on the page.
  2. +
  3. Open the example up in a browser and in your text editor.
  4. +
  5. Open the JavaScript console in your browser developer tools. In the JavaScript console, enter the following command: +
    output(x);
    + You should see the value of variable x output to the screen.
  6. +
  7. Now try entering the following in your console +
    output(y);
    +output(z);
    + Both of these should return an error along the lines of "ReferenceError: y is not defined". Why is that? Because of function scope — y and z are locked inside the a() and b() functions, so output() can't access them when called from the global scope.
  8. +
  9. However, what about when it's called from inside another function? Try editing a() and b() so they look like this: +
    function a() {
    +  var y = 2;
    +  output(y);
    +}
    +
    +function b() {
    +  var z = 3;
    +  output(z);
    +}
    + Save the code and reload it in your browser, then try calling the a() and b() functions from the JavaScript console: + +
    a();
    +b();
    + You should see the y and z values output in the page. This works fine, as the output() function is being called inside the other functions — in the same scope as the variables it is printing are defined in, in each case. output() itself is available from anywhere, as it is defined in the global scope.
  10. +
  11. Now try updating your code like this: +
    function a() {
    +  var y = 2;
    +  output(x);
    +}
    +
    +function b() {
    +  var z = 3;
    +  output(x);
    +}
    + Save and reload again, and try this again in your JavaScript console: + +
    a();
    +b();
    + Both the a() and b() call should output the value of x — 1. These work fine because even though the output() calls are not in the same scope as x is defined in, x is a global variable so is available inside all code, everywhere.
  12. +
  13. Finally, try updating your code like this: +
    function a() {
    +  var y = 2;
    +  output(z);
    +}
    +
    +function b() {
    +  var z = 3;
    +  output(y);
    +}
    + Save and reload again, and try this again in your JavaScript console: + +
    a();
    +b();
    + This time the a() and b() calls will both return that annoying "ReferenceError: z is not defined" error — this is because the output() calls and the variables they are trying to print are not defined inside the same function scopes — the variables are effectively invisible to those function calls.
  14. +
+ +
+

Note: The same scoping rules do not apply to loop (e.g. for() { ... }) and conditional blocks (e.g. if() { ... }) — they look very similar, but they are not the same thing! Take care not to get these confused.

+
+ +
+

Note: The ReferenceError: "x" is not defined error is one of the most common you'll encounter. If you get this error and you are sure that you have defined the variable in question, check what scope it is in.

+
+ + + +

Functions inside functions

+ +

Keep in mind that you can call a function from anywhere, even inside another function.  This is often used as a way to keep code tidy — if you have a big complex function, it is easier to understand if you break it down into several sub-functions:

+ +
function myBigFunction() {
+  var myValue;
+
+  subFunction1();
+  subFunction2();
+  subFunction3();
+}
+
+function subFunction1() {
+  console.log(myValue);
+}
+
+function subFunction2() {
+  console.log(myValue);
+}
+
+function subFunction3() {
+  console.log(myValue);
+}
+
+ +

Just make sure that the values being used inside the function are properly in scope. The example above would throw an error ReferenceError: myValue is not defined, because although the myValue variable is defined in the same scope as the function calls, it is not defined inside the function definitions — the actual code that is run when the functions are called. To make this work, you'd have to pass the value into the function as a parameter, like this:

+ +
function myBigFunction() {
+  var myValue = 1;
+
+  subFunction1(myValue);
+  subFunction2(myValue);
+  subFunction3(myValue);
+}
+
+function subFunction1(value) {
+  console.log(value);
+}
+
+function subFunction2(value) {
+  console.log(value);
+}
+
+function subFunction3(value) {
+  console.log(value);
+}
+ +

Conclusion

+ +

This article has explored the fundamental concepts behind functions, paving the way for the next one in which we get practical and take you through the steps to building up your own custom function.

+ +

See also

+ + + + + +

{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}

+ +

 

+ +

In this module

+ + + +

 

diff --git a/files/zh-tw/learn/javascript/building_blocks/image_gallery/index.html b/files/zh-tw/learn/javascript/building_blocks/image_gallery/index.html new file mode 100644 index 0000000000..32c5a1867a --- /dev/null +++ b/files/zh-tw/learn/javascript/building_blocks/image_gallery/index.html @@ -0,0 +1,135 @@ +--- +title: 影像圖庫 +slug: Learn/JavaScript/Building_blocks/Image_gallery +tags: + - JavaScript + - 事件 + - 事件處理器 + - 優先國際化 + - 初學者 + - 學習 + - 條件式 + - 編碼腳本 + - 評量 + - 迴圈 +translation_of: Learn/JavaScript/Building_blocks/Image_gallery +--- +
{{LearnSidebar}}
+ +
{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}
+ +

現在我們已經看過了基本的JavaScript組建,我們將讓你做一個測試,從建立一個在很多網站上常見的事物 — JavaScript基礎的影像圖庫,來測試你對迴圈、函數、條件式及事件的知識。

+ + + + + + + + + + + + +
先修課程:在進行這個評量前,你應已閱讀、練習了本模組中所有的文章。
目的:測試對JavaScript中迴圈、函數、條件式及事件的瞭解程度。
+ +

從這裡開始

+ +

要進行這個評量,你要先下載 grab the ZIP 檔案,解壓縮在你電腦中的某個檔案夾作為範例。

+ +
+

提醒:你也可以在某些網站進行評鑑,如 JSBin 或Thimble。你可以把這些HTML、CSS和JavaScript貼到這些線上編輯器中。如果你用了一個沒法把JavaScript/CSS分別放在不同面板的線上編輯器,你可以放心的把這些<script>/<style>元件改成inline貼進HTML網頁裡。

+
+ +

專案簡報

+ +

你手上已有我們提供的一些 HTML、CSS 和圖片資料,以及幾行 JavaScript 程式碼;你要寫一些必要的 JavaScript 讓它變成可運作的程式。這些 HTML 的 body 看起來如下:

+ +
<h1>Image gallery example</h1>
+
+<div class="full-img">
+  <img class="displayed-img" src="images/pic1.jpg">
+  <div class="overlay"></div>
+  <button class="dark">Darken</button>
+</div>
+
+<div class="thumb-bar">
+
+</div>
+ +

完成後看起來像下圖:

+ +

+ + + +

範例 CSS 檔案中最有趣的部分是:

+ + + +

在你的 JavaScript 裡需要:

+ + + +

為了讓你更清楚,你可以看看這個 完成的範例 (但別偷看原始碼!)

+ +

一步步完成

+ +

接下來幾節描述你該怎麼做。

+ +

讓所有圖片迴圈

+ +

我們已提供了幾行程式碼:將thumb-bar和 <div>儲存在 thumbBar這個變數裡、建立一個新的 <img> 元件、將它的 src 屬性設定在一個值為 xxx 的佔位符中,以及在 thumbBar 裡增加新 <img>

+ +

你要做的是:

+ +
    +
  1. Put the section of code below the "Looping through images" comment inside a loop that loops through all 5 images — you just need to loop through five numbers, one representing each image.
  2. +
  3. In each loop iteration, replace the xxx placeholder value with a string that will equal the path to the image in each case. We are setting the value of the src attribute to this value in each case. Bear in mind that in each case, the image is inside the images directory and its name is pic1.jpg, pic2.jpg, etc.
  4. +
+ +

在每個縮圖上添加onclick事件處理器

+ +

In each loop iteration, you need to add an onclick handler to the current newImage — this should:

+ +
    +
  1. 在每個 <img> 中把"src"作為運行getAttribute() 函數的參數,取得現在這張圖片的 src 屬性的值。但是要怎麼抓到現在這張圖片?如果用newImage 是做不到的,當在添加事件處理器前,迴圈已經先完成了;所以你每次都獲得前一個 <img>的回傳的 src 值。解法是,記住,在每個事件中,事件處理器的目標是 <img> ,如何獲得事件物件的資訊呢?
  2. +
  3. Run a function, passing it the returned src value as a parameter. You can call this function whatever you like.
  4. +
  5. This event handler function should set the src attribute value of the displayed-img <img> to the src value passed in as a parameter. We've already provided you with a line that stores a reference to the relevant <img> in a variable called displayedImg. Note that we want a defined named function here.
  6. +
+ +

寫一個讓暗化/亮化按鈕可以運作的處理器

+ +

That just leaves our darken/lighten <button> — we've already provided a line that stores a reference to the <button> in a variable called btn. You need to add an onclick handler that:

+ +
    +
  1. Checks the current class name set on the <button> — you can again achieve this by using getAttribute().
  2. +
  3. If the class name is "dark", changes the <button> class to "light" (using setAttribute()), its text content to "Lighten", and the {{cssxref("background-color")}} of the overlay <div> to "rgba(0,0,0,0.5)".
  4. +
  5. If the class name not "dark", changes the <button> class to "dark", its text content back to "Darken", and the {{cssxref("background-color")}} of the overlay <div> to "rgba(0,0,0,0)".
  6. +
+ +

The following lines provide a basis for achieving the changes stipulated in points 2 and 3 above.

+ +
btn.setAttribute('class', xxx);
+btn.textContent = xxx;
+overlay.style.backgroundColor = xxx;
+ +

提醒與提示

+ + + +

評量

+ +

If you are following this assessment as part of an organized course, you should be able to give your work to your teacher/mentor for marking. If you are self-learning, then you can get the marking guide fairly easily by asking on the Learning Area Discourse thread, or in the #mdn IRC channel on Mozilla IRC. Try the exercise first — there is nothing to be gained by cheating!

+ +

{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}

diff --git a/files/zh-tw/learn/javascript/building_blocks/index.html b/files/zh-tw/learn/javascript/building_blocks/index.html new file mode 100644 index 0000000000..500b7d28ed --- /dev/null +++ b/files/zh-tw/learn/javascript/building_blocks/index.html @@ -0,0 +1,52 @@ +--- +title: JavaScript building blocks +slug: Learn/JavaScript/Building_blocks +tags: + - JavaScript + - TopicStub + - 事件 + - 入門者 + - 函式 + - 指南 + - 模組 + - 評量 + - 迴圈 +translation_of: Learn/JavaScript/Building_blocks +--- +
{{LearnSidebar}}
+ +

在本單元中,我們繼續介紹所有JavaScript的關鍵基本功能,將注意力轉向常見的代碼塊類型,如條件語句,循環,函數和事件。 你已經在課程中看到了這些東西,但只是順便說一下 - 在這裡我們將明確地討論它。

+ +

先決條件

+ +

開始這個模組之前,你應該已經熟悉 HTMLCSS 的基礎知識了,你也應該閱讀完前一個模組 - JavaScript 入門 - 的內容了。

+ +
+

注意: 假如你正使用平板、電腦或任何無法讓你可以建立檔案的裝置時,你可以試著透過線上程式碼工具 (像是 JSBinThimble) 測試文章的測試碼。

+
+ +

指南

+ +
+
在代碼中做出決定 - 條件
+
在任何編程語言中,代碼都需要根據不同的輸入做出決策並相應地執行操作。 例如,在遊戲中,如果玩家的生命數量為0,則遊戲結束。 在天氣應用程序中,如果在早上查看,則顯示日出圖形; 如果是夜晚,則顯示星星和月亮。 在本文中,我們將探討條件結構如何在JavaScript中工作。
+
程式碼迴圈
+
有時候你需要超過一行的程式碼完成一項任務,舉例來說:尋找一個擁有許多名字的清單。透過編輯程式,迴圈可以幫助你完美的完成這項工作,在本文中,我們將探討迴圈的結構如何在 JavaScript 中運作。
+
函式 — 可重複使用的程式碼區塊
+
撰寫程式的另一個基本概念是函式 (function),它允許你在一個定義好的區塊內,存放一些程式碼。定義好的函式後,無論你需要在一個單一簡短的指令列用到它,或者是重複使用相同的片段程式碼,你都可以不段重複地呼叫這些函式執行對應的內容。在本文中,我們將探索函式的基本概念,像是基本語法、如何定義函式內容、以及函式將會使用的參數。
+
建立自己的函式
+
前面許多文章已經提到大部分的基本理論基礎了,在本文中,我們將分享一個實際的經驗,你將學習到關於打造自定義函式的實務範例。透過這樣的學習方式,我們也進一步解釋一些函式相關的細節知識。
+
函式回傳值
+
這堂課程中最後一個想要說明的基本概念就是函式的回傳值,一些函式執行完畢後,不會回傳一個數值;但有些函式則會。理解這些函式的回傳值是重要的概念,本文中,你將學會如何在自定義的函式中,回傳有用的數值提供給其他函式使用。
+
事件介紹
+
事件代表你所撰寫的程式在一套系統內所產生的動作或發生的事情,舉例來說:假如一位使用者在網頁點擊一個按鈕時,你可能想要讓使用者點擊該按鈕後,在畫面呈現一個訊息方塊。在本課程最後一篇文章內,我們將討論一些與事件相關的重要概念、以及這些事件在瀏覽器中,如何呈現給使用者。
+
+ +

評量

+ +

下方的試題將會測驗你對於上述幾項概念的 JavaScript 基本知識。

+ +
+
圖庫
+
我們已經看過許多 JavaScript 的基礎程式碼,我們將測驗你關於迴圈、函式、條件式迴圈與事件等相關的知識,測驗的方式是透過建立一個由 JavaScript 打造而成的圖庫應用程式。
+
diff --git a/files/zh-tw/learn/javascript/building_blocks/looping_code/index.html b/files/zh-tw/learn/javascript/building_blocks/looping_code/index.html new file mode 100644 index 0000000000..0e1e400b4d --- /dev/null +++ b/files/zh-tw/learn/javascript/building_blocks/looping_code/index.html @@ -0,0 +1,928 @@ +--- +title: 循環代碼 +slug: Learn/JavaScript/Building_blocks/Looping_code +translation_of: Learn/JavaScript/Building_blocks/Looping_code +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}
+ +

編程語言對於快速完成重複性任務非常有用,從多個基本計算到幾乎任何其他需要完成大量類似工作的情況。 在這裡,我們將看看JavaScript中可用於處理此類需求的循環結構。

+ + + + + + + + + + + + +
Prerequisites:Basic computer literacy, a basic understanding of HTML and CSS, JavaScript first steps.
Objective:To understand how to use loops in JavaScript.
+ +

保持循環

+ +

循環,循環,循環。 除了與受歡迎的早餐穀物,過山車和音樂作品有關聯,它們還是編程中的關鍵概念。 編程循環都是一遍又一遍地做同一件事-在編程方面被稱為迭代。

+ +

讓我們考慮一個農民的例子,他要確保他有足夠的食物來養家糊口。 他可能使用以下循環來實現此目的:

+ +


+

+ +

循環通常具有以下一項或多項功能:

+ + + +

In {{glossary("pseudocode")}}, this would look something like the following:

+ +
loop(food = 0; foodNeeded = 10) {
+  if (food = foodNeeded) {
+    exit loop;
+    // We have enough food; let's go home
+  } else {
+    food += 2; // Spend an hour collecting 2 more food
+    // loop will then run again
+  }
+}
+ +

因此,所需的食物數量設置為10,而農民當前擁有的食物數量設置為0。在循環的每次迭代中,我們檢查農民擁有的食物數量是否等於他所需的數量。 如果是這樣,我們可以退出循環。 如果不是這樣,農民將花一個小時收集兩份食物,然後循環再次運行。

+ +

不用麻煩

+ +

在這一點上,您可能了解了循環背後的高級概念,但您可能在想:“好,很好,但這如何幫助我編寫更好的JavaScript代碼?” 如前所述,循環與一次又一次地執行同一操作有關,這對於快速完成重複性任務非常有用。

+ +

通常,代碼在每次循環的每次迭代中都會略有不同,這意味著您可以完成全部相似但略有不同的任務,一般情況,如果您要執行許多不同的計算,則需要不斷地執行不同的式子,而不能一遍又一遍重複!

+ +

讓我們看一個示例,以完美地說明為什麼循環是如此便利。 Let's say we wanted to draw 100 random circles on a {{htmlelement("canvas")}} element (press the Update button to run the example again and again to see different random sets):

+ + + +

{{ EmbedLiveSample('Hidden_code', '100%', 400, "", "", "hide-codepen-jsfiddle") }}

+ +

您現在不必了解所有代碼,但讓我們看一下實際繪製100個圓圈的代碼部分:

+ +
for (var i = 0; i < 100; i++) {
+  ctx.beginPath();
+  ctx.fillStyle = 'rgba(255,0,0,0.5)';
+  ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+  ctx.fill();
+}
+ + + +

您應該了解基本概念-我們正在使用一個循環來運行此代碼的100次迭代,每個迭代在頁面上的隨機位置繪製一個圓圈。 無論我們繪製100個圓,1000個還是10,000個,所需的代碼量都是相同的。 只需更改一個數字。

+ +

如果我們不在此處使用循環,則必須為每個要繪製的圓重複以下代碼:

+ +
ctx.beginPath();
+ctx.fillStyle = 'rgba(255,0,0,0.5)';
+ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+ctx.fill();
+ +

這將變得很無聊,並且很難很快維護。 循環確實是最好的。

+ +

循環的規範

+ +

讓我們開始探索一些特定的循環結構。 第一個是for循環,您將在大多數時候使用它,它具有以下語法:

+ +
for (initializer; exit-condition; final-expression) {
+  // code to run
+}
+ +

這裡我們有:

+ +
    +
  1. 關鍵字“ for”,即跟隨其後的一些括號。
  2. +
  3. 在括號內,我們有三個項目,以 ; 分隔: +
      +
    1. 初始化程序-通常是一個設置為數字的變量,該變量將遞增以計算循環運行的次數。 有時也稱為計數器變量。
    2. +
    3. 退出條件-如前所述,它定義了循環何時應停止循環。 通常,這是一個具有比較運算符的表達式,該測試用於檢驗是否滿足退出條件。
    4. +
    5. 最終表達式—每當循環經過完整的迭代時,總是對它進行評估(或運行)。 它通常用於遞增(或在某些情況下遞減)計數器變量,以使其更接近退出條件值。
    6. +
    +
  4. +
  5. 一些花括號包含一個代碼塊-每次循環迭代時都將運行此代碼。
  6. +
+ +

讓我們看一個真實的例子,以便我們可以更清楚地看到它們的作用。

+ +
var cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin'];
+var info = 'My cats are called ';
+var para = document.querySelector('p');
+
+for (var i = 0; i < cats.length; i++) {
+  info += cats[i] + ', ';
+}
+
+para.textContent = info;
+ +

這為我們提供了以下輸出:

+ + + +

{{ EmbedLiveSample('Hidden_code_2', '100%', 60, "", "", "hide-codepen-jsfiddle") }}

+ +
+

Note: You can find this example code on GitHub too (also see it running live).

+
+ +

這顯示了一個循環,該循環用於遍歷數組中的項目並對其進行處理-這是JavaScript中非常常見的模式。 這裡:

+ +
    +
  1. 迭代器i從0開始(變量i = 0)。
  2. +
  3. 它被告知運行,直到它不再小於cats數組的長度為止。 這很重要,退出條件顯示了循環仍將運行的條件。 因此,在這種情況下,儘管i <cats.length仍然為true,循環仍將運行。
  4. +
  5. 在循環內部,我們將當前循環項(cats [i]是cats [無論 i 當時是什麼])與一個逗號和一個空格連接到info變量的末尾。 所以: +
      +
    1. 在第一次運行中,i = 0,因此cats [0] +','將連接到info(“ Bill,”)上。
    2. +
    3. 在第二次運行中,i = 1,因此cats [1] +','將連接到info(“ Jeff,”)上
    4. +
    5. 等等。 每次循環運行後,將1加到i(i ++),然後該過程將再次開始。
    6. +
    +
  6. +
  7. 當 i 等於cats.length時,循環將停止,瀏覽器將繼續循環下方的下一段代碼。
  8. +
+ +
+

Note: We have made the exit condition i < cats.length, not i <= cats.length, because computers count from 0, not 1 — we are starting i at 0, and going up to i = 4 (the index of the last array item). cats.length returns 5, as there are 5 items in the array, but we don't want to get up to i = 5, as that would return undefined for the last item (there is no array item with an index of 5). So therefore we want to go up to 1 less than cats.length (i <), not the same as cats.length (i <=).

+
+ +
+

Note: A common mistake with exit conditions is making them use "equal to" (===) rather than say "less than or equal to" (<=). If we wanted to run our loop up to i = 5, the exit condition would need to be i <= cats.length. If we set it to i === cats.length, the loop would not run at all because i is not equal to 5 on the first loop iteration, so it would stop immediately.

+
+ +

我們剩下的一個小問題是最終輸出語句的格式不太正確:

+ +
+

My cats are called Bill, Jeff, Pete, Biggles, Jasmin,

+
+ +

理想情況下,我們希望在最終循環迭代中更改串聯,以使句子的末尾沒有逗號。 好吧,沒問題-我們可以很高興地在for循環中插入一個條件來處理這種特殊情況:

+ +
for (var i = 0; i < cats.length; i++) {
+  if (i === cats.length - 1) {
+    info += 'and ' + cats[i] + '.';
+  } else {
+    info += cats[i] + ', ';
+  }
+}
+ +
+

Note: You can find this example code on GitHub too (also see it running live).

+
+ +
+

Important: With for — as with all loops — you must make sure that the initializer is iterated so that it eventually reaches the exit condition. If not, the loop will go on forever, and either the browser will force it to stop, or it will crash. This is called an infinite loop.

+
+ +

中斷退出循環

+ +

如果要在所有迭代完成之前退出循環,可以使用break語句。 在查看switch語句時,我們已經在上一篇文章中遇到了這一問題—當在switch語句中遇到與輸入表達式匹配的case時,break語句立即退出switch語句並移至其後的代碼上。

+ +

循環也是如此,-break語句將立即退出循環,並使瀏覽器繼續執行緊隨其後的任何代碼。

+ +

假設我們要搜索一系列聯繫人和電話號碼,然後僅返回我們要查找的號碼? 首先,提供一些簡單的HTML-文本 {{htmlelement(“ input”)}} 允許我們輸入要搜索的名稱,{{htmlelement(“ button”)}} 元素以提交搜索,以及 {{htmlelement (“ p”)}} 元素以在以下位置顯示結果:

+ +
<label for="search">Search by contact name: </label>
+<input id="search" type="text">
+<button>Search</button>
+
+<p></p>
+ +

Now on to the JavaScript:

+ +
var contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975'];
+var para = document.querySelector('p');
+var input = document.querySelector('input');
+var btn = document.querySelector('button');
+
+btn.addEventListener('click', function() {
+  var searchName = input.value;
+  input.value = '';
+  input.focus();
+  for (var i = 0; i < contacts.length; i++) {
+    var splitContact = contacts[i].split(':');
+    if (splitContact[0] === searchName) {
+      para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.';
+      break;
+    } else {
+      para.textContent = 'Contact not found.';
+    }
+  }
+});
+ + + +

{{ EmbedLiveSample('Hidden_code_3', '100%', 100, "", "", "hide-codepen-jsfiddle") }}

+ +
    +
  1. 首先,我們有一些變量定義-我們有一個聯繫信息陣列,每個項目都是一個字符串,其中包含用冒號分隔的姓名和電話號碼。
  2. +
  3. 接下來,我們將事件監聽器附加到按鈕(btn),以便在按下按鈕時,將運行一些代碼來執行搜索並返回結果。
  4. +
  5. 我們將輸入到文本輸入中的值存儲在一個名為searchName的變量中,然後清空文本輸入並再次對其進行聚焦,以準備進行下一次搜索。
  6. +
  7. 現在到有趣的部分,for循環: +
      +
    1. 我們從0開始啟動計數器,運行循環直到計數器不再小於contact.length,然後在每次循環之後將i遞增1。
    2. +
    3. 在循環內部,我們首先將當前觸點(contacts [i])分割為冒號字符,並將得到的兩個值存儲在名為 splitContact 的數組中。
    4. +
    5. 然後,我們使用條件語句來測試splitContact [0](聯繫人的姓名)是否等於輸入的searchName。 如果是這樣,我們在段落中輸入一個字符串以報告聯繫人的電話號碼,然後使用break結束循環。
    6. +
    +
  8. +
  9. +

    在(contacts.length-1)迭代之後,如果聯繫人姓名與輸入的搜索不匹配,則將段落文本設置為“找不到聯繫人。”,然後循環繼續進行迭代。

    +
  10. +
+ +
+

Note: You can view the full source code on GitHub too (also see it running live).

+
+ +

Skipping iterations with continue

+ +

The continue statement works in a similar manner to break, but instead of breaking out of the loop entirely, it skips to the next iteration of the loop. Let's look at another example that takes a number as an input, and returns only the numbers that are squares of integers (whole numbers).

+ +

The HTML is basically the same as the last example — a simple text input, and a paragraph for output. The JavaScript is mostly the same too, although the loop itself is a bit different:

+ +
var num = input.value;
+
+for (var i = 1; i <= num; i++) {
+  var sqRoot = Math.sqrt(i);
+  if (Math.floor(sqRoot) !== sqRoot) {
+    continue;
+  }
+
+  para.textContent += i + ' ';
+}
+ +

Here's the output:

+ + + +

{{ EmbedLiveSample('Hidden_code_4', '100%', 100, "", "", "hide-codepen-jsfiddle") }}

+ +
    +
  1. In this case, the input should be a number (num). The for loop is given a counter starting at 1 (as we are not interested in 0 in this case), an exit condition that says the loop will stop when the counter becomes bigger than the input num, and an iterator that adds 1 to the counter each time.
  2. +
  3. Inside the loop, we find the square root of each number using Math.sqrt(i), then check whether the square root is an integer by testing whether it is the same as itself when it has been rounded down to the nearest integer (this is what Math.floor() does to the number it is passed).
  4. +
  5. If the square root and the rounded down square root do not equal one another (!==), it means that the square root is not an integer, so we are not interested in it. In such a case, we use the continue statement to skip on to the next loop iteration without recording the number anywhere.
  6. +
  7. If the square root IS an integer, we skip past the if block entirely so the continue statement is not executed; instead, we concatenate the current i value plus a space on to the end of the paragraph content.
  8. +
+ +
+

Note: You can view the full source code on GitHub too (also see it running live).

+
+ +

while and do ... while

+ +

for is not the only type of loop available in JavaScript. There are actually many others and, while you don't need to understand all of these now, it is worth having a look at the structure of a couple of others so that you can recognize the same features at work in a slightly different way.

+ +

First, let's have a look at the while loop. This loop's syntax looks like so:

+ +
initializer
+while (exit-condition) {
+  // code to run
+
+  final-expression
+}
+ +

This works in a very similar way to the for loop, except that the initializer variable is set before the loop, and the final-expression is included inside the loop after the code to run — rather than these two items being included inside the parentheses. The exit-condition is included inside the parentheses, which are preceded by the while keyword rather than for.

+ +

The same three items are still present, and they are still defined in the same order as they are in the for loop — this makes sense, as you still have to have an initializer defined before you can check whether it has reached the exit-condition; the final-condition is then run after the code inside the loop has run (an iteration has been completed), which will only happen if the exit-condition has still not been reached.

+ +

Let's have a look again at our cats list example, but rewritten to use a while loop:

+ +
var i = 0;
+
+while (i < cats.length) {
+  if (i === cats.length - 1) {
+    info += 'and ' + cats[i] + '.';
+  } else {
+    info += cats[i] + ', ';
+  }
+
+  i++;
+}
+ +
+

Note: This still works just the same as expected — have a look at it running live on GitHub (also view the full source code).

+
+ +

The do...while loop is very similar, but provides a variation on the while structure:

+ +
initializer
+do {
+  // code to run
+
+  final-expression
+} while (exit-condition)
+ +

In this case, the initializer again comes first, before the loop starts. The do keyword directly precedes the curly braces containing the code to run and the final-expression.

+ +

The differentiator here is that the exit-condition comes after everything else, wrapped in parentheses and preceded by a while keyword. In a do...while loop, the code inside the curly braces is always run once before the check is made to see if it should be executed again (in while and for, the check comes first, so the code might never be executed).

+ +

Let's rewrite our cat listing example again to use a do...while loop:

+ +
var i = 0;
+
+do {
+  if (i === cats.length - 1) {
+    info += 'and ' + cats[i] + '.';
+  } else {
+    info += cats[i] + ', ';
+  }
+
+  i++;
+} while (i < cats.length);
+ +
+

Note: Again, this works just the same as expected — have a look at it running live on GitHub (also view the full source code).

+
+ +
+

Important: With while and do...while — as with all loops — you must make sure that the initializer is iterated so that it eventually reaches the exit condition. If not, the loop will go on forever, and either the browser will force it to stop, or it will crash. This is called an infinite loop.

+
+ +

Active learning: Launch countdown!

+ +

In this exercise, we want you to print out a simple launch countdown to the output box, from 10 down to Blast off. Specifically, we want you to:

+ + + +

If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution.

+ + + +

{{ EmbedLiveSample('Active_learning', '100%', 880, "", "", "hide-codepen-jsfiddle") }}

+ +

Active learning: Filling in a guest list

+ +

In this exercise, we want you to take a list of names stored in an array, and put them into a guest list. But it's not quite that easy — we don't want to let Phil and Lola in because they are greedy and rude, and always eat all the food! We have two lists, one for guests to admit, and one for guests to refuse.

+ +

Specifically, we want you to:

+ + + +

We've already provided you with:

+ + + +

Extra bonus question — after completing the above tasks successfully, you will be left with two lists of names, separated by commas, but they will be untidy — there will be a comma at the end of each one. Can you work out how to write lines that slice the last comma off in each case, and add a full stop to the end? Have a look at the Useful string methods article for help.

+ +

If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution.

+ + + +

{{ EmbedLiveSample('Active_learning_2', '100%', 680, "", "", "hide-codepen-jsfiddle") }}

+ +

Which loop type should you use?

+ +

For basic uses, for, while, and do...while loops are largely interchangeable. They can all be used to solve the same problems, and which one you use will largely depend on your personal preference — which one you find easiest to remember or most intuitive. Let's have a look at them again.

+ +

First for:

+ +
for (initializer; exit-condition; final-expression) {
+  // code to run
+}
+ +

while:

+ +
initializer
+while (exit-condition) {
+  // code to run
+
+  final-expression
+}
+ +

and finally do...while:

+ +
initializer
+do {
+  // code to run
+
+  final-expression
+} while (exit-condition)
+ +

We would recommend for, at least to begin with, as it is probably the easiest for remembering everything — the initializer, exit-condition, and final-expression all have to go neatly into the parentheses, so it is easy to see where they are and check that you aren't missing them.

+ +
+

Note: There are other loop types/features too, which are useful in advanced/specialized situations and beyond the scope of this article. If you want to go further with your loop learning, read our advanced Loops and iteration guide.

+
+ +

Conclusion

+ +

This article has revealed to you the basic concepts behind, and different options available when, looping code in JavaScript. You should now be clear on why loops are a good mechanism for dealing with repetitive code, and be raring to use them in your own examples!

+ +

If there is anything you didn't understand, feel free to read through the article again, or contact us to ask for help.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/javascript/building_blocks/return_values/index.html b/files/zh-tw/learn/javascript/building_blocks/return_values/index.html new file mode 100644 index 0000000000..f77f37d46c --- /dev/null +++ b/files/zh-tw/learn/javascript/building_blocks/return_values/index.html @@ -0,0 +1,172 @@ +--- +title: 函數回傳值 +slug: Learn/JavaScript/Building_blocks/Return_values +translation_of: Learn/JavaScript/Building_blocks/Return_values +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}
+ +

我們將在本課程中討論最後一個基本概念,即關閉函數 - 回傳值。 有些函數在完成後沒有回傳重要值,但其他函數會,並且了解它們的值是什麼,如何在代碼中使用它們以及如何使自己的自定義函數返回有用值非常重要。 我們將在下面介紹所有這些內容。

+ + + + + + + + + + + + +
Prerequisites: +

Basic computer literacy, a basic understanding of HTML and CSS, JavaScript first steps, Functions — reusable blocks of code.

+
Objective:To understand function return values, and how to make use of them.
+ +

What are return values?

+ +

Return values are just what they sound like — values returned by the function when it completes. You've already met return values a number of times, although you may not have thought about them explicitly. Let's return to some familiar code:

+ +
var myText = 'I am a string';
+var newString = myText.replace('string', 'sausage');
+console.log(newString);
+// the replace() string function takes a string,
+// replaces one substring with another, and returns
+// a new string with the replacement made
+ +

We saw exactly this block of code in our first function article. We are invoking the replace() function on the myText string, and passing it two parameters — the substring to find, and the substring to replace it with. When this function completes (finishes running), it returns a value, which is a new string with the replacement made. In the code above, we are saving this return value as the value of the newString variable.

+ +

If you look at the replace function MDN reference page, you'll see a section called Return value. It is very useful to know and understand what values are returned by functions, so we try to include this information wherever possible.

+ +

Some functions don't return a return value as such (in our reference pages, the return value is listed as void or undefined in such cases). For example, in the displayMessage() function we built in the previous article, no specific value is returned as a result of the function being invoked. It just makes a box appear somewhere on the screen — that's it!

+ +

Generally, a return value is used where the function is an intermediate step in a calculation of some kind. You want to get to a final result, which involves some values. Those values need to be calculated by a function, which then returns the results so they can be used in the next stage of the calculation.

+ +

Using return values in your own functions

+ +

To return a value from a custom function, you need to use ... wait for it ... the return keyword. We saw this in action recently in our random-canvas-circles.html example. Our draw() function draws 100 random circles somewhere on an HTML {{htmlelement("canvas")}}:

+ +
function draw() {
+  ctx.clearRect(0,0,WIDTH,HEIGHT);
+  for (var i = 0; i < 100; i++) {
+    ctx.beginPath();
+    ctx.fillStyle = 'rgba(255,0,0,0.5)';
+    ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+    ctx.fill();
+  }
+}
+ +

Inside each loop iteration, three calls are made to the random() function, to generate a random value for the current circle's x coordinate, y coordinate, and radius, respectively. The random() function takes one parameter — a whole number — and it returns a whole random number between 0 and that number. It looks like this:

+ +
function randomNumber(number) {
+  return Math.floor(Math.random()*number);
+}
+ +

This could be written as follows:

+ +
function randomNumber(number) {
+  var result = Math.floor(Math.random()*number);
+  return result;
+}
+ +

But the first version is quicker to write, and more compact.

+ +

We are returning the result of the calculation Math.floor(Math.random()*number) each time the function is called. This return value appears at the point the function was called, and the code continues. So for example, if we ran the following line:

+ +
ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+ +

and the three random() calls returned the values 500, 200, and 35, respectively, the line would actually be run as if it were this:

+ +
ctx.arc(500, 200, 35, 0, 2 * Math.PI);
+ +

The function calls on the line are run first and their return values substituted for the function calls, before the line itself is then executed.

+ +

Active learning: our own return value function

+ +

Let's have a go at writing our own functions featuring return values.

+ +
    +
  1. First of all, make a local copy of the function-library.html file from GitHub. This is a simple HTML page containing a text {{htmlelement("input")}} field and a paragraph. There's also a {{htmlelement("script")}} element in which we have stored a reference to both HTML elements in two variables. This little page will allow you to enter a number into the text box, and display different numbers related to it in the paragraph below.
  2. +
  3. Let's add some useful functions to this <script> element. Below the existing two lines of JavaScript, add the following function definitions: +
    function squared(num) {
    +  return num * num;
    +}
    +
    +function cubed(num) {
    +  return num * num * num;
    +}
    +
    +function factorial(num) {
    +  var x = num;
    +  while (x > 1) {
    +    num *= x-1;
    +    x--;
    +  }
    +  return num;
    +}
    + The squared() and cubed() functions are fairly obvious — they return the square or cube of the number given as a parameter. The factorial() function returns the factorial of the given number.
  4. +
  5. Next, we're going to include a way to print out information about the number entered into the text input. Enter the following event handler below the existing functions: +
    input.onchange = function() {
    +  var num = input.value;
    +  if (isNaN(num)) {
    +    para.textContent = 'You need to enter a number!';
    +  } else {
    +    para.textContent = num + ' squared is ' + squared(num) + '. ' +
    +                       num + ' cubed is ' + cubed(num) + '. ' +
    +                       num + ' factorial is ' + factorial(num) + '.';
    +  }
    +}
    + +

    Here we are creating an onchange event handler that runs whenever the change event fires on the text input — that is, when a new value is entered into the text input, and submitted (enter a value then press tab for example). When this anonymous function runs, the existing value entered into the input is stored in the num variable.

    + +

    Next, we do a conditional test — if the entered value is not a number, we print an error message into the paragraph. The test looks at whether the expression isNaN(num) returns true. We use the isNaN() function to test whether the num value is not a number — if so, it returns true, and if not, false.

    + +

    If the test returns false, the num value is a number, so we print out a sentence inside the paragraph element stating what the square, cube, and factorial of the number are. The sentence calls the squared(), cubed(), and factorial() functions to get the required values.

    +
  6. +
  7. Save your code, load it in a browser, and try it out.
  8. +
+ +
+

Note: If you have trouble getting the example to work, feel free to check your code against the finished version on GitHub (see it running live also), or ask us for help.

+
+ +

At this point, we'd like you to have a go at writing out a couple of functions of your own and adding them to the library. How about the square or cube root of the number, or the circumference of a circle with a radius of length num?

+ +

This exercise has brought up a couple of important points besides being a study on how to use the return statement. In addition, we have:

+ + + +

Conclusion

+ +

So there we have it — functions are fun, very useful and, although there's a lot to talk about in regards to their syntax and functionality, fairly understandable given the right articles to study.

+ +

If there is anything you didn't understand, feel free to read through the article again, or contact us to ask for help.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}

+ +

 

+ +

In this module

+ + + +

 

diff --git a/files/zh-tw/learn/javascript/client-side_web_apis/index.html b/files/zh-tw/learn/javascript/client-side_web_apis/index.html new file mode 100644 index 0000000000..c678aae7ae --- /dev/null +++ b/files/zh-tw/learn/javascript/client-side_web_apis/index.html @@ -0,0 +1,39 @@ +--- +title: 客戶端 web APIs +slug: Learn/JavaScript/Client-side_web_APIs +translation_of: Learn/JavaScript/Client-side_web_APIs +--- +
{{LearnSidebar}}
+ +

在為網站或應用程序編寫客戶端JavaScript時,您將很快遇到應用程式介面(API)。 API是應用程式介面,用於操作運行站點的瀏覽器和操作系統的不同方面,或操縱來自其他網站或服務的資料。 在本單元中,我們將探討API是什麼,以及如何使用您在開發工作中經常遇到的一些最常見的API。

+ +

必備知識

+ +

To get the most out of this module, you should have worked your way through the previous JavaScript modules in the series (First steps, Building blocks, and JavaScript objects). Those modules typically involve simple API usage, as it is often difficult to write client-side JavaScript examples without them. For this tutorial, we will assume that you are knowledgable about the core JavaScript language, and we will explore common Web APIs in a bit more detail.

+ + + +

了解 HTMLCSS 的基礎知識也會有所幫助。

+ +
+

Note: 假如你正在使用 電腦/平板/其他裝置,你不需要建立自己的檔案,你可以嘗試線上程式撰寫系統來撰寫範例程式,像是JSBin or Thimble.

+
+ +

概觀

+ +
+
Web API簡介
+
First up, we'll start by looking at APIs from a high level — what are they, how do they work, how do you use them in your code, and how are they structured? We'll also take a look at what the different main classes of APIs are, and what kind of uses they have.
+
文檔操作
+
When writing web pages and apps, one of the most common things you'll want to do is manipulate web documents in some way. This is usually done by using the Document Object Model (DOM), a set of APIs for controlling HTML and styling information that makes heavy use of the {{domxref("Document")}} object. In this article, we'll look at how to use the DOM in detail, along with some other interesting APIs that can alter your environment in interesting ways.
+
從服務器獲取數據
+
Another very common task in modern websites and applications is retrieving individual data items from the server to update sections of a webpage without having to load an entirely new page. This seemingly small detail has had a huge impact on the performance and behavior of sites.  In this article, we'll explain the concept, and look at technologies that make it possible, such as {{domxref("XMLHttpRequest")}} and the Fetch API.
+
第三方API
+
The APIs we've covered so far are built into the browser, but not all APIs are. Many large websites and services such as Google Maps, Twitter, Facebook, PayPal, etc. provide APIs allowing developers to make use of their data (e.g. displaying your twitter stream on your blog) or services (e.g. displaying custom Google Maps on your site, or using Facebook login to log in your users). This article looks at the difference between browser APIs and 3rd party APIs and shows some typical uses of the latter.
+
繪製圖形
+
The browser contains some very powerful graphics programming tools, from the Scalable Vector Graphics (SVG) language, to APIs for drawing on HTML {{htmlelement("canvas")}} elements, (see The Canvas API and WebGL). This article provides an introduction to the Canvas API, and further resources to allow you to learn more.
+
視頻和音頻API
+
HTML5 comes with elements for embedding rich media in documents — {{htmlelement("video")}} and {{htmlelement("audio")}} — which in turn come with their own APIs for controlling playback, seeking, etc. This article shows you how to do common tasks such as creating custom playback controls.
+
客戶端存儲
+
Modern web browsers feature a number of different technologies that allow you to store data related to web sites and retrieve it when necessary allowing you to persist data long term, save sites offline, and more. This article explains the very basics of how these work.
+
diff --git a/files/zh-tw/learn/javascript/client-side_web_apis/manipulating_documents/index.html b/files/zh-tw/learn/javascript/client-side_web_apis/manipulating_documents/index.html new file mode 100644 index 0000000000..5b04033cb1 --- /dev/null +++ b/files/zh-tw/learn/javascript/client-side_web_apis/manipulating_documents/index.html @@ -0,0 +1,314 @@ +--- +title: 文檔操作(文件操作) +slug: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents +translation_of: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Introduction", "Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs")}}
+ +

當你在撰寫網頁(web pages)或網路應用程式(web apps),其中一個最常見的事,你會希望能夠操作(網頁)文件結構。最常看見的方式是基於文件物件模型 ( Document Object Model, DOM ) 概念上,透過使用 API (Web APIs) 來控制 HTML 及 樣式;而這種方式也被大量使用在操作 Document 物件上。接下來的文章中,我們將會詳細的介紹如何操作 DOM,藉著使用有趣的 API 能帶來些新奇的體驗。

+ + + + + + + + + + + + +
你事先需要了解:基礎電腦知識, 了解基礎 HTML、CSS、JavaScript 概念 — 包含 JavaScript 物件概念.
你將學會:更加熟悉 DOM 核心 API, 和常用來操作 DOM 的 API
+ +

The important parts of a web browser

+ +

Web browsers are very complicated pieces of software with a lot of moving parts, many of which can't be controlled or manipulated by a web developer using JavaScript. You might think that such limitations are a bad thing, but browsers are locked down for good reasons, mostly centering around security. Imagine if a web site could get access to your stored passwords or other sensitive information, and log into websites as if it were you?

+ +

Despite the limitations, Web APIs still give us access to a lot of functionality that enable us to do a great many things with web pages. There are a few really obvious bits you'll reference regularly in your code — consider the following diagram, which represents the main parts of a browser directly involved in viewing web pages:

+ +

+ + + +

In this article we'll focus mostly on manipulating the document, but we'll show a few other useful bits besides.

+ +

The document object model

+ +

The document currently loaded in each one of your browser tabs is represented by a document object model. This is a "tree structure" representation created by the browser that enables the HTML structure to be easily accessed by programming languages — for example the browser itself uses it to apply styling and other information to the correct elements as it renders a page, and developers like you can manipulate the DOM with JavaScript after the page has been rendered.

+ +

We have created a simple example page at dom-example.html (see it live also). Try opening this up in your browser — it is a very simple page containing a {{htmlelement("section")}} element inside which you can find an image, and a paragraph with a link inside. The HTML source code looks like this:

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Simple DOM example</title>
+  </head>
+  <body>
+      <section>
+        <img src="dinosaur.png" alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth.">
+        <p>Here we will add a link to the <a href="https://www.mozilla.org/">Mozilla homepage</a></p>
+      </section>
+  </body>
+</html>
+ +

The DOM on the other hand looks like this:

+ +

+ +
+

Note: This DOM tree diagram was created using Ian Hickson's Live DOM viewer.

+
+ +

You can see here that each element and bit of text in the document has its own entry in the tree — each one is called a node. You will also encounter various terms used to describe the type of node, and their position in the tree in relation to one another:

+ + + +

It is useful to familiarize yourself with this terminology before working with the DOM, as a number of the code terms you'll come across make use of them. You may have also come across them if you have studied CSS (e.g. descendant selector, child selector).

+ +

Active learning: Basic DOM manipulation

+ +

To start learning about DOM manipulation, let's begin with a practical example.

+ +
    +
  1. Take a local copy of the dom-example.html page and the image that goes along with it.
  2. +
  3. Add a <script></script> element just above the closing </body> tag.
  4. +
  5. To manipulate an element inside the DOM, you first need to select it and store a reference to it inside a variable. Inside your script element, add the following line: +
    var link = document.querySelector('a');
    +
  6. +
  7. Now we have the element reference stored in a variable, we can start to manipulate it using properties and methods available to it (these are defined on interfaces like {{domxref("HTMLAnchorElement")}} in the case of {{htmlelement("a")}} element, its more general parent interface {{domxref("HTMLElement")}}, and {{domxref("Node")}} — which represents all nodes in a DOM). First of all, let's change the text inside the link by updating the value of the {{domxref("Node.textContent")}} property. Add the following line below the previous one: +
    link.textContent = 'Mozilla Developer Network';
    +
  8. +
  9. We should also change the URL the link is pointing to, so that it doesn't go to the wrong place when it is clicked on. Add the following line, again at the bottom: +
    link.href = 'https://developer.mozilla.org';
    +
  10. +
+ +
+

Note that, as with many things in JavaScript, there are many ways to select an element and store a reference to it in a variable. {{domxref("Document.querySelector()")}} is the recommended modern approach, which is convenient because it allows you to select elements using CSS selectors. The above querySelector() call will match the first {{htmlelement("a")}} element that appears in the document. If you wanted to match and do things to multiple elements, you could use {{domxref("Document.querySelectorAll()")}}, which matches every element in the document that matches the selector, and stores references to them in an array-like object called a NodeList.

+ +

There are older methods available for grabbing element references, such as:

+ + + +

These two work in older browsers than the modern methods like querySelector(), but are not as convenient. Have a look and see what others you can find!

+
+ +

Creating and placing new nodes

+ +

The above has given you a little taste of what you can do, but let's go further and look at how we can create new elements.

+ +
    +
  1. Going back to the current example, let's start by grabbing a reference to the our {{htmlelement("section")}} element — add the following code at the bottom of your existing script (do the same with the other lines too): +
    var sect = document.querySelector('section');
    +
  2. +
  3. Now let's create a new paragraph using {{domxref("Document.createElement()")}} and give it some text content in the same way as before: +
    var para = document.createElement('p');
    +para.textContent = 'We hope you enjoyed the ride.';
    +
  4. +
  5. You can now append the new paragraph at the end of the section using {{domxref("Node.appendChild()")}}: +
    sect.appendChild(para);
    +
  6. +
  7. Finally for this part, let's add a text node to the paragraph the link sits inside, to round off the sentence nicely. First we will create the text node using {{domxref("Document.createTextNode()")}}: +
    var text = document.createTextNode(' — the premier source for web development knowledge.');
    +
  8. +
  9. Now we'll grab a reference to the paragraph the link is inside, and append the text node to it: +
    var linkPara = document.querySelector('p');
    +linkPara.appendChild(text);
    +
  10. +
+ +

That's most of what you need for adding nodes to the DOM — you'll make a lot of use of these methods when building dynamic interfaces (we'll look at some examples later).

+ +

Moving and removing elements

+ +

There may be times when you want to move nodes, or delete them from the DOM altogether. This is perfectly possible.

+ +

If we wanted to move the paragraph with the link inside it to the bottom of the section, we could simply do this:

+ +
sect.appendChild(linkPara);
+ +

This moves the paragraph down to the bottom of the section. You might have thought it would make a second copy of it, but this is not the case — linkPara is a reference to the one and only copy of that paragraph. If you wanted to make a copy and add that as well, you'd need to use {{domxref("Node.cloneNode()")}} instead.

+ +

Removing a node is pretty simple as well, at least when you have a reference to the node to be removed and its parent. In our current case, we just use {{domxref("Node.removeChild()")}}, like this:

+ +
sect.removeChild(linkPara);
+ +

It gets slightly more complex when you want to remove a node based only on a reference to itself, which is fairly common. There is no method to tell a node to remove itself, so you'd have to do the following.

+ +
linkPara.parentNode.removeChild(linkPara);
+ +

Have a go at adding the above lines to your code.

+ +

Manipulating styles

+ +

It is possible to manipulate CSS styles via JavaScript in a variety of ways.

+ +

To start with, you can get a list of all the stylesheets attached to a document using {{domxref("Document.stylesheets")}}, which returns an array of {{domxref("CSSStyleSheet")}} objects. You can then add/remove styles as wished. However, we're not going to expand on those features because they are a somewhat archaic and difficult way to manipulate style. There are much easier ways.

+ +

The first way is to add inline styles directly onto elements you want to dynamically style. This is done with the {{domxref("HTMLElement.style")}} property, which contains inline styling information for each element in the document. You can set properties of this object to directly update element styles.

+ +
    +
  1. As an example, try adding these lines to our ongoing example: +
    para.style.color = 'white';
    +para.style.backgroundColor = 'black';
    +para.style.padding = '10px';
    +para.style.width = '250px';
    +para.style.textAlign = 'center';
    +
  2. +
  3. Reload the page and you'll see that the styles have been applied to the paragraph. If you look at that paragraph in your browser's Page Inspector/DOM inspector, you'll see that these lines are indeed adding inline styles to the document: +
    <p style="color: white; background-color: black; padding: 10px; width: 250px; text-align: center;">We hope you enjoyed the ride.</p>
    +
  4. +
+ +
+

Note: Notice how the JavaScript property versions of the CSS styles are written in lower camel case whereas the CSS versions are hyphenated (e.g. backgroundColor versus background-color). Make sure you don't get these mixed up, otherwise it won't work.

+
+ +

There is another common way to dynamically manipulate styles on your document, which we'll look at now.

+ +
    +
  1. Delete the previous five lines you added to the JavaScript.
  2. +
  3. Add the following inside your HTML {{htmlelement("head")}}: +
    <style>
    +.highlight {
    +  color: white;
    +  background-color: black;
    +  padding: 10px;
    +  width: 250px;
    +  text-align: center;
    +}
    +</style>
    +
  4. +
  5. Now we'll turn to a very useful method for general HTML manipulation — {{domxref("Element.setAttribute()")}} — this takes two arguments, the attribute you want to set on the element, and the value you want to set it to. In this case we will set a class name of highlight on our paragraph: +
    para.setAttribute('class', 'highlight');
    +
  6. +
  7. Refresh your page, and you'll see no change — the CSS is still applied to the paragraph, but this time by giving it a class that is selected by our CSS rule, not as inline CSS styles.
  8. +
+ +

Which method you choose is up to you; both have their advantages and disadvantages. The first method takes less setup and is good for simple uses, whereas the second method is more purist (no mixing CSS and JavaScript, no inline styles, which are seen as a bad practice). As you start building larger and more involved apps, you will probably start using the second method more, but it is really up to you.

+ +

At this point, we haven't really done anything useful! There is no point using JavaScript to create static content — you might as well just write it into your HTML and not use JavaScript. It is more complex than HTML, and creating your content with JavaScript also has other issues attached to it (such as not being readable by search engines).

+ +

In the next couple of sections we will look at a couple of more practical uses of DOM APIs.

+ +
+

Note: You can find our finished version of the dom-example.html demo on GitHub (see it live also).

+
+ +

Active learning: Getting useful information from the Window object

+ +

So far we've only really looked at using {{domxref("Node")}} and {{domxref("Document")}} features to manipulate documents, but there is no reason why you can't get data from other sources and use it in your UI. Think back to our simple maps-example.html demo from the last article — there we retrieved some location data and used it to display a map of your area. You just have to make sure your data is in the right format; JavaScript makes it easier than many other languages, being weakly typed — for example numbers will convert to strings automatically when you want to print them to the screen.

+ +

In this example we will solve a common problem — making sure your application is as big as the window it is viewed in, whatever size it is. This is often useful in situations like games, where you want to use as much of the screen area as possible to play the game in.

+ +

To start with, make a local copy of our window-resize-example.html and bgtile.png demo files. Open it and have a look — you'll see that we've got a {{htmlelement("div")}} element covering a small part of the screen, which has got a background tile applied to it. We'll use that to represent our app UI area.

+ +
    +
  1. First of all, let's grab a reference to the div, and then grab the width and height of the viewport (the inner window, where your document is displayed) and store them in variables — these two values are handily contained in the {{domxref("Window.innerWidth")}} and {{domxref("Window.innerHeight")}} properties. Add the following lines inside the existing {{htmlelement("script")}} element: +
    var div = document.querySelector('div');
    +var WIDTH = window.innerWidth;
    +var HEIGHT = window.innerHeight;
    +
  2. +
  3. Next, we'll dynamically alter the width and height of the div to equal that of the viewport. Add the following two lines below your first ones: +
    div.style.width = WIDTH + 'px';
    +div.style.height = HEIGHT + 'px';
    +
  4. +
  5. Save and try refreshing your browser — you should now see the div become as big as your viewport, whatever size of screen your are using. If you now try resizing your window to make it bigger, you'll see that the div stays the same size — we are only setting it once.
  6. +
  7. How about we use an event so that the div resizes as we resize the window? The {{domxref("Window")}} object has an event available on it called resize, which is fired every time the window is resized — let's access that via the {{domxref("Window.onresize")}} event handler and rerun our sizing code each time it changes. Add the following to the bottom of your code: +
    window.onresize = function() {
    +  WIDTH = window.innerWidth;
    +  HEIGHT = window.innerHeight;
    +  div.style.width = WIDTH + 'px';
    +  div.style.height = HEIGHT + 'px';
    +}
    +
  8. +
+ +
+

Note: If you get stuck, have a look at our finished window resize example (see it live also).

+
+ +

Active learning: A dynamic shopping list

+ +

To round off the article, we'd like to set you a little challenge — we want to make a simple shopping list example that allows you to dynamically add items to the list using a form input and button. When you add an item to the input and press the button:

+ + + +

The finished demo will look something like this:

+ +

+ +

To complete the exercise, follow the steps below, and make sure that the list behaves as described above.

+ +
    +
  1. To start with, download a copy of our shopping-list.html starting file and make a copy of it somewhere. You'll see that it has some minimal CSS, a list with a label, input, and button, and an empty list and {{htmlelement("script")}} element. You'll be making all your additions inside the script.
  2. +
  3. Create three variables that hold references to the list ({{htmlelement("ul")}}), {{htmlelement("input")}}, and {{htmlelement("button")}} elements.
  4. +
  5. Create a function that will run in response to the button being clicked.
  6. +
  7. Inside the function body, start off by storing the current value of the input element in a variable.
  8. +
  9. Next, empty the input element by setting its value to an empty string — ''.
  10. +
  11. Create three new elements — a list item ({{htmlelement('li')}}), {{htmlelement('span')}}, and {{htmlelement('button')}}, and store them in variables.
  12. +
  13. Append the span and the button as children of the list item.
  14. +
  15. Set the text content of the span to the input element value you saved earlier, and the text content of the button to 'Delete'.
  16. +
  17. Append the list item as a child of the list.
  18. +
  19. Attach an event handler to the delete button, so that when clicked it will delete the entire list item it is inside.
  20. +
  21. Finally, use the focus() method to focus the input element ready for entering the next shopping list item.
  22. +
+ +
+

Note: If you get really stuck, have a look at our finished shopping list (see it running live also.)

+
+ +

Summary

+ +

We have reached the end of our study of document and DOM manipulation. At this point you should understand what the important parts of a web browser are with respect to controlling documents and other aspects of the user's web experience. Most importantly, you should understand what the Document Object Model is, and how to manipulate it to create useful functionality.

+ +

See also

+ +

There are lots more features you can use to manipulate your documents. Check out some of our references and see what you can discover:

+ + + +

(See our Web API index for the full list of Web APIs documented on MDN!)

+ +
{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Introduction", "Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs")}}
+ +
+

In this module

+ + +
diff --git a/files/zh-tw/learn/javascript/first_steps/a_first_splash/index.html b/files/zh-tw/learn/javascript/first_steps/a_first_splash/index.html new file mode 100644 index 0000000000..38c7e4a4c4 --- /dev/null +++ b/files/zh-tw/learn/javascript/first_steps/a_first_splash/index.html @@ -0,0 +1,706 @@ +--- +title: 初次接觸Javascript +slug: Learn/JavaScript/First_steps/A_first_splash +translation_of: Learn/JavaScript/First_steps/A_first_splash +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/First_steps/What_is_JavaScript", "Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps")}}
+ +

目前你已經學會了一些JavaScript的理論,以及你能用它做些什麼。我們現在要透過一個完整的實際範例給你一個JavaScript基本功能的速成班。你將能一步一步地做出一個簡單的"猜數字"遊戲

+ + + + + + + + + + + + +
先備知識:基礎的電腦知識 , 有基礎的 HTML 跟 CSS 知識 ,
+ 還有知道 JavaScript 是甚麼 .
目標:獲得第一次寫 JavaScript 的經驗 ,
+ 還有知道最基礎的 JavaScript 程式該怎麼寫 .
+ +

並不會要求你馬上就能仔細地了解所有程式碼 — 目前我們只是想介紹一些概觀,並向你介紹一些關於JavaScript(以及其他程式語言)如何運作的知識。在接下來的章節你將會更仔細地瞭解這些功能!

+ +
+

Note: 你會在 JavaScript 看到許多跟其他程式語言一樣的特徵 — functions , loops 之類的 ,雖然程式語法看起來有差 ,但概念大部分都差不多 .

+
+ +

像程式工程師一樣思考

+ +

寫程式中最困難的事情之一,不是您需要學習的語法,而是如何應用它來解決現實世界中的問題。 您需要開始像個程式設計師一樣思考 — 這通常與檢視程式目標的說明有關,並確定實現這些功能所需的程式碼,以及如何使它們協同工作。

+ +

這需要辛勤工作,程式語法經驗和練習 — 以及一點創造力。 你寫了越多程式碼,你就會越熟練。 我們不能保證你會在5分鐘內開發出“程式設計師的大腦”,但我們會給你很多機會在整個課程中練習"像程式設計師一樣思考"。

+ +

考慮到這一點,讓我們看一下我們將在本文中構建的範例,並審視將其分解為具體任務的大致流程。

+ +

範例 — 猜數字遊戲

+ +

在本文中,我們將向您展示如何構建您可以在下面看到的簡單遊戲:

+ + + +

{{ EmbedLiveSample('Top_hidden_code', '100%', 320, "", "", "hide-codepen-jsfiddle") }}

+ +

好好玩一下遊戲再繼續吧 —— 在繼續前先與這個遊戲熟悉起來。

+ +

讓我們假設你的老闆給了你以下關於創建這個遊戲的簡介:

+ +
+

我要你幫我做一個很簡單的猜數字遊戲 .
+ 玩家要在 10 回合內猜中一個1到100之間的隨機數字 ,
+ 每回合結束時都要告訴玩家他們猜對還是猜錯 ,
+ 然後要是他們猜錯 , 要告訴他們數字猜的太小還是太大 ,
+ 這個遊戲會在玩家猜對 , 或是猜超過 10 次時結束 ,
+ 且遊戲結束時 , 要提供一個選項讓玩家可以再玩一次 .

+
+ +

當看到上面的介紹後,我們可以做的第一件事就是開始拆解,盡可能的像個程式設計師,將它拆解為簡單可執行的任務:

+ +
    +
  1. 產生一個1到100間的隨機數字。
  2. +
  3. 從一開始,紀錄玩家目前回合數。
  4. +
  5. 提供玩家猜數字的方向(太大還是太小)。
  6. +
  7. 當玩家送出第一個猜測後,將猜測記錄下來,讓玩家可以看到他們之前的猜測。
  8. +
  9. 接著檢查數字是否猜中。
  10. +
  11. 如果數字猜對: +
      +
    1. 顯示恭喜訊息。
    2. +
    3. 使玩家不能再輸入更多猜測(避免把遊戲玩壞)。
    4. +
    5. 顯示控制鈕讓玩家可以重新開始遊戲。
    6. +
    +
  12. +
  13. 如果數字猜錯而且玩家有剩餘回合數: +
      +
    1. 告訴玩家他猜錯了。
    2. +
    3. 讓玩家輸入其他的猜測
    4. +
    5. 回合數增加1。
    6. +
    +
  14. +
  15. 如果數字猜錯而且玩家沒有剩餘回合數: +
      +
    1. 告訴玩家遊戲結束。
    2. +
    3. 使玩家不能再輸入更多猜測(避免把遊戲玩壞)。
    4. +
    5. 顯示控制鈕讓玩家可以重新開始遊戲。
    6. +
    +
  16. +
  17. 當遊戲重新開始,確保遊戲邏輯和畫面(UI,使用這介面)全面重設,然後回到第一步。
  18. +
+ +

現在,讓我們繼續向前,一路上我們檢視如何將這些步驟轉化為程式碼、建構出上面的範例與探索JavaScript的功能。

+ +

初步設定

+ +

在課程開始前,我們希望你可以複製一份number-guessing-game-start.html到自己的電腦中(see it live here)。用瀏覽器與文字編輯器將檔案打開時,你會看到簡單的標題、說明段落還有輸入猜測的表單,然而表單目前還不會做任何事情。

+ +

所有的程式碼都會放入置於HTML底部的{{htmlelement("script")}}元素裡:

+ +
<script>
+
+  // Your JavaScript goes here
+
+</script>
+
+ +

加入變數儲存我們的資料

+ +

我們一起開始吧。首先,在你的{{htmlelement("script")}} 元素裡加入以下幾行:

+ +
let randomNumber = Math.floor(Math.random() * 100) + 1;
+
+const guesses = document.querySelector('.guesses');
+const lastResult = document.querySelector('.lastResult');
+const lowOrHi = document.querySelector('.lowOrHi');
+
+const guessSubmit = document.querySelector('.guessSubmit');
+const guessField = document.querySelector('.guessField');
+
+let guessCount = 1;
+let resetButton;
+ +

這一區塊的程式碼設定我們的程式中用來儲存資料的變數。簡單的來說,「變數」是「值」的容器(值可以是數字、一串文字或是其他東西)。你可以用「關鍵字」(keyword) let(或是var)後面加上變數的名字來建立變數(在之後的文章你會看到兩者的差別)。利用關鍵字 const 建立常數,常數(Constant)是用來儲存你不會更改的值。我們用常數儲存使用者介面的參照,使用者介面中的文字可能會改變,但是參照所指的HTML元素的不會改變。

+ +

藉由等於符號(=)後面加上一個值,你可以指定變數或是常數的值。

+ +

在我們的範例中:

+ + + +
+

Note: 從下一篇文章開始,你會學到更多有關變數的事。

+
+ +

函式

+ +

下一步,將下面這段添加到之前寫的那段程式碼:

+ +
function checkGuess() {
+  alert('I am a placeholder');
+}
+ +

函式是一段可重複利用的程式碼塊。建立一個函式便可以反複運行並避免撰寫重複的程式碼。定義函式有很多方法,在此我們先專注在一種簡單的方式。這裡我們以關鍵字 function 、自訂的函式名、一對括號以及一對花括號({ })建立函式。花括號中的程式碼便是我們調用函式時所要實際執行的程式碼。

+ +

輸入函式名稱與括號便可以執行函式。

+ +

讓我們來試試吧。儲存你的程式碼並重新整理瀏覽器畫面。進入 開發者工具 JavaScript console, 並輸入下面這行:

+ +
checkGuess();
+ +

 當按下 Return/Enter 時,你會看到一個警告跳窗顯示「I am a placeholder」。我們已經在程式中定義好一個函式,只要我們調用這個函式,函式便會彈出一個警告視窗。

+ +
+

Note: 你會在後續的課程中學習到更多關於函式的事。

+
+ +

運算子

+ +

JavaScript 運算子可以讓我們執行比較、數學運算、連接字符串等。

+ +

儲存我們的程式碼並重整頁面,開啟 開發者工具 JavaScript console 。接下來你可以試著輸入以下的範例 —— 輸入跟每個「範例」欄位中一樣的內容,每輸入一個就按下Return / Enter, 接著看看回傳的結果。

+ +

如果你不能快速打開瀏覽器開發工具, 你可以使用内嵌的應用程式中輸入以下範例:

+ + + +

{{ EmbedLiveSample('Hidden_code', '100%', 300, "", "", "hide-codepen-jsfiddle") }}

+ +

首先讓我們看看以下的算數運算子:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
運算子名稱範例
+加法6 + 9
-減法20 - 15
*乘法3 * 7
/除法10 / 5
+ +

你也可以使用 + 來連接字串 (在程式設計中,這稱爲連接)。試著輸入以下幾行程式,每次一行:

+ +
var name = 'Bingo';
+name;
+var hello = ' says hello!';
+hello;
+var greeting = name + hello;
+greeting;
+ +

你也可以使用一些捷徑,這些被稱爲增量賦值運算子。如果你只是簡單想將兩個字串加在一起,你可以這樣做:

+ +
name += ' says hello!';
+ +

相當於

+ +
name = name + ' says hello!';
+ +

當我們進行真假值測試時 (例如{{anch("條件", "下面")}}),我們可以使用比較運算子,如:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
運算子名稱範例
===嚴格等於 (是否完全一樣?)5 === 2 + 4
!==不等於 (是否不一樣?)'Chris' !== 'Ch' + 'ris'
<小於10 < 6
>大於10 > 20
+ +

條件

+ +

回到 checkGuess() 函式,我們希望的結果當然不只是彈出簡單訊息而已。我們更想要知道這個函式將如何檢查玩家的猜測是否準確,並回傳正確的結果。

+ +

所以現在將 checkGuess() 函式替換成下面這個版本:

+ +
function checkGuess() {
+  var userGuess = Number(guessField.value);
+  if (guessCount === 1) {
+    guesses.textContent = 'Previous guesses: ';
+  }
+  guesses.textContent += userGuess + ' ';
+
+  if (userGuess === randomNumber) {
+    lastResult.textContent = 'Congratulations! You got it right!';
+    lastResult.style.backgroundColor = 'green';
+    lowOrHi.textContent = '';
+    setGameOver();
+  } else if (guessCount === 10) {
+    lastResult.textContent = '!!!GAME OVER!!!';
+    setGameOver();
+  } else {
+    lastResult.textContent = 'Wrong!';
+    lastResult.style.backgroundColor = 'red';
+    if(userGuess < randomNumber) {
+      lowOrHi.textContent = 'Last guess was too low!';
+    } else if(userGuess > randomNumber) {
+      lowOrHi.textContent = 'Last guess was too high!';
+    }
+  }
+
+  guessCount++;
+  guessField.value = '';
+  guessField.focus();
+}
+ +

哇,突然出現了很多程式碼!我們來完整地看一遍這些程式並介紹它們是如何運行的。

+ + + +

事件

+ +

現在我們有了一個很好的 checkGuess() 函式,但它並不會做任何事情,因為我們還沒有呼叫它。我們想在按下 “Submit guess” 按鈕時呼叫它,為此,我們需要使用事件。事件是在瀏覽器中發生的操作,例如單擊按鈕,加載頁面或播放影片,以讓我們可以在這些操作發生時執行程式碼。偵聽事件發生的構造稱為事件偵聽器,偵聽事件而觸發執行的程式碼稱為事件處理器

+ +

在 checkGuess() 函式下面添加下行(不是指函式內部的後面,而是函式外):

+ +
guessSubmit.addEventListener('click', checkGuess);
+ +

這裡我們為 guessSubmit 按鈕添加一個事件偵聽器。這是一個函式,它接受兩個輸入值(稱為參數) - 我們正在監聽的事件類型字串(本例中的 click),以及我們想要在事件發生時運行的程式碼(在這種情況下是checkGuess()函式) — 請注意,在編寫 addEventListener() 內部時我們不需要為函式加上括號。

+ +

現在保存並重整頁面,現在你的範例應該可以正常執行了。現在唯一的問題是,如果你猜對了正確的答案或用完了猜測機會,那麼遊戲就會出錯,因為我們還沒有定義 setGameOver() — 遊戲結束後應該執行的函式。現在讓我們加上缺少的程式碼並完成範例功能。

+ +

完成遊戲功能

+ +

讓我們加入 setGameOver() 這個函式到我們程式碼的底部並演練它。 現在,在你的 JavaScript 尾端加上這些:

+ +
function setGameOver() {
+  guessField.disabled = true;
+  guessSubmit.disabled = true;
+  resetButton = document.createElement('button');
+  resetButton.textContent = 'Start new game';
+  document.body.appendChild(resetButton);
+  resetButton.addEventListener('click', resetGame);
+}
+ + + +

現在讓我們來定義 resetGame()!再次將下面這些程式碼加進你的 JavaScript 的最下方。

+ +
function resetGame() {
+  guessCount = 1;
+
+  var resetParas = document.querySelectorAll('.resultParas p');
+  for (var i = 0 ; i < resetParas.length ; i++) {
+    resetParas[i].textContent = '';
+  }
+
+  resetButton.parentNode.removeChild(resetButton);
+
+  guessField.disabled = false;
+  guessSubmit.disabled = false;
+  guessField.value = '';
+  guessField.focus();
+
+  lastResult.style.backgroundColor = 'white';
+
+  randomNumber = Math.floor(Math.random() * 100) + 1;
+}
+ +

這段相對較常的程式碼會完全將所有東西重置到遊戲的初始狀態,讓玩家可以再玩一次。這段程式碼做了下面這些事:

+ + + +

現在,你應該有了一個完整且能正常執行的簡單遊戲了 — 恭喜你啦!

+ +

接下來這篇文章的工作只剩下來談談其他幾個很重要的程式功能,你應該已經看過了,只是還沒察覺罷了。

+ +

迴圈

+ +

上面的程式碼中,一個我們需要仔細看看的部份是 for 迴圈。迴圈在程式設計中是一個非常重要的內容,可以讓你在滿足條件前反覆執行同一段程式碼。

+ +

開始吧,打開你的 開發者工具 JavaScript console,然後輸入下面這行:

+ +
for (var i = 1 ; i < 21 ; i++) { console.log(i) }
+ +

看見了嗎?在你的主控台內印出了數字 1到 20。這就是迴圈的效果。一個 for 迴圈需要三個參數:

+ +
    +
  1. 起始動作:這個例子中我們從 1 開始累加,這個起始數值可以是任何你想要的值。你也可以不要使用 i 這個變數名稱,但習慣上我們會使用 i ,因為它簡單好記。 
  2. +
  3. 離開條件:這裡我們指定了 i < 21 — 這個迴圈會一直執行直到 i 不再小於 21。當 i 達到 21,這個迴圈就會停止執行。
  4. +
  5. 增加動作:我們指定了 i++,「將 i 的值加 1」。這個迴圈會對每個 i 的值執行一次,直到 i 達到 21(如上一條所述)。這個例子中,我們簡單的透過 {{domxref("Console.log", "console.log()")}} 將每次迴圈中 i 的值輸出到主控台中。
  6. +
+ +

現在我們來看看在猜謎遊戲中的迴圈 — 這可以在 resetGame() 函式中找到:

+ +
var resetParas = document.querySelectorAll('.resultParas p');
+for (var i = 0 ; i < resetParas.length ; i++) {
+  resetParas[i].textContent = '';
+}
+ +

這段程式碼透過呼叫 {{domxref("Document.querySelectorAll", "querySelectorAll()")}} 創建一個變數並存著一個在 <div class="resultParas"> 中的所有段落清單,然後使用迴圈來遍歷每個段落元素,並移除其內容。

+ +

稍微討論一下物件

+ +

在開始討論這個段落的話題前,先來做點小小修改。在你的 JavaScript 接近頂部的 var resetButton 下一行加上:

+ +
guessField.focus();
+ +

,然後存檔。

+ +

這一行呼叫了 {{domxref("HTMLElement.focus", "focus()")}} 方法來在頁面讀取時,將輸入游標自動放進 {{htmlelement("input")}} 文字欄裡面,這意味著使用者在開啟頁面後就可以直接使用鍵盤來在文字欄內輸入文字,而不用先點選文字欄。這只是個小修改,可是大大的提升了使用體驗,也給了使用者清楚的提示 — 提示他們要做些什麼來遊玩這個遊戲。

+ +

讓我們來分析一下究竟發生了什麼事。在JavaScript中,所有東西都是一個物件。物件是一個集合,由許多相關的功能打包成一體。你可以創建一個你自己的物件,不過這比較進階,我們現在並不會涵蓋這個內容,這些會在課程的後期提到。現在,我們只會簡要的提到一些你的瀏覽器內建的物件,他們能夠讓你做到許多有用的事。

+ +

在這個例子中,我們首先創建了一個 guessField 變數,儲存著一個指向HTML表單中文字輸入欄的參照 — 這可以在我們定義變數的區塊中找到:

+ +
var guessField = document.querySelector('.guessField');
+ +

我們使用了 {{domxref("document.querySelector", "querySelector()")}} 來取得這個參照,前者是 {{domxref("document")}} 物件的方法。querySelector() 接受一個參數 — 一個 CSS 選擇器, 會回傳你想要的元素參照。

+ +

因為現在 guessField 中存著一個指向 {{htmlelement("input")}} 元素的參照,它現在可以存取這個元素的屬性(基本上就是存在物件中的變數,其中有一些可能會是常數)和方法(基本上就是存在物件中的函式)了。文字輸入欄的其中一個方法便是 focus(),我們便可以透過呼叫這個方法來給予其焦點:

+ +
guessField.focus();
+ +

沒有存著表單元素參照的變數就不會有 focus() 方法能使用。
+ 例如存著一個 {{htmlelement("p")}} 元素的 guesses 和存著一個數值的 guessCount

+ +

來玩玩瀏覽器物件

+ +

讓我們來稍微玩一點瀏覽器內建的物件吧。

+ +
    +
  1. 首先在瀏覽器中開啟你的程式。
  2. +
  3. 接下來,打開你的開發者工具 JavaScript console
  4. +
  5. 輸入 guessField,可以看到主控台顯示這個變數儲存著一個 {{htmlelement("input")}} 元素。你還可以發現主控台會自動幫你完成已存在的物件名稱!
  6. +
  7. 接下來輸入: +
    guessField.value = 'Hello';
    + value 屬性儲存著現在文字輸入欄內的內容參照。現在按下 Enter,看看文字欄內的內容是不是變了?
  8. +
  9. 試著輸入 guesses 然後按下 Enter,主控台會顯示這個變數儲存著一個 {{htmlelement("p")}} 元素。
  10. +
  11. 現在輸入: +
    guesses.value
    + 瀏覽器會回傳 undefined,因為 value 不存在在段落元素裡面。
  12. +
  13. 要更改段落元素中的文字,你需要的是 {{domxref("Node.textContent", "textContent")}} 屬性。試試這個: +
    guesses.textContent = 'Where is my paragraph?';
    +
  14. +
  15. 現在來做些好玩的事。一行一行輸入並 Enter: +
    guesses.style.backgroundColor = 'yellow';
    +guesses.style.fontSize = '200%';
    +guesses.style.padding = '10px';
    +guesses.style.boxShadow = '3px 3px 6px black';
    + 每個在頁面上的元素都有一個 style 屬性,其本身又是另一個物件,包含著許多該元素的行內 CSS 屬性。這讓我們能透過 JavaScript 來動態的為元素設置 CSS 屬性。
  16. +
+ +

差不多就到這了

+ +

這就是我們的範例 — 你順利地來到結尾了,做得不錯!試試你的最終成品,或試試我們的版本。如果你仍然有困難沒有解決,再看看我們的原始碼

+ +

{{PreviousMenuNext("Learn/JavaScript/First_steps/What_is_JavaScript", "Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps")}}

+ +

在這個學習模組中

+ + diff --git a/files/zh-tw/learn/javascript/first_steps/arrays/index.html b/files/zh-tw/learn/javascript/first_steps/arrays/index.html new file mode 100644 index 0000000000..895183b811 --- /dev/null +++ b/files/zh-tw/learn/javascript/first_steps/arrays/index.html @@ -0,0 +1,571 @@ +--- +title: Arrays +slug: Learn/JavaScript/First_steps/Arrays +translation_of: Learn/JavaScript/First_steps/Arrays +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}
+ +

在本單元的最後一篇文章中,我們將介紹陣列——一種在單個變數名下儲存資料項列表的簡潔方法。在這裡,我們看看為什麼這很有用,然後探討如何建立陣列,檢索、增加和刪除儲存在陣列中的項目等等。

+ + + + + + + + + + + + +
先備知識:基本計算機知識、基本理解 HTML 與 CSS、知道 JavaScript 是什麼。
目標:理解何謂陣列並在 JavaScript 操作之。
+ +

什麼是陣列?

+ +

陣列通常描述為「像列表的物件」:也就是一個列表物件,裡面含有幾個數值。陣列物件能放在變數裡面,處理方式也與資料型別大致相同。不過主要差異為,陣列可以獨立存取、並高效處理裡面的數值:像是利用迴圈,對每個數值作相同處理。例如我們的陣列是一組有項目和價格的產品、我們可以用迴圈把單價印在發票上、最後在發票底下印出合計。

+ +

不用陣列的話,就會需要註冊、並單獨呼叫很多獨立變數。這樣會花更多時間寫程式、效率更低、還更容易寫錯。只有十個的話還好解決,但如果有一百個,甚至一千個呢?我們會在接下來闡述之。

+ +

與前幾篇文章一樣,讓我們在 JavaScript 控制台中輸入一些示例,來了解陣列的基礎知識吧。

+ +

建立陣列

+ +

陣列用方括弧包起來,每個單位會用逗號分隔起來。

+ +
    +
  1. 來作一個購物清單的陣列吧:我們會做類似下面的事情。在主控台中輸入以下程式: +
    var shopping = ['bread', 'milk', 'cheese', 'hummus', 'noodles'];
    +shopping;
    +
  2. +
  3. 在此,陣列的每個單位都是字串。但請記住,陣列可以儲存任何單位:字串、數字、物件、另一個變數、甚至是另一個陣列。也可以混合單位的型別:它們不一定都要是數字或字串。來試試這個: +
    var sequence = [1, 1, 2, 3, 5, 8, 13];
    +var random = ['tree', 795, [0, 1, 2]];
    +
  4. +
  5. 看下去之前,試著自己作幾個陣列。
  6. +
+ +

存取並修改陣列的單位

+ +

你可以使用括號標記法存取個別單位,同時也可以存取字串中的字母

+ +
    +
  1. 在主控台輸入以下程式: +
    shopping[0];
    +// returns "bread"
    +
  2. +
  3. 也可以透過賦予陣列新數值修改該單位。試試這個: +
    shopping[0] = 'tahini';
    +shopping;
    +// shopping 回傳 [ "tahini", "milk", "cheese", "hummus", "noodles" ]
    + +
    注:前面有說過,但還是提醒下:電腦從 0 開始數!
    +
  4. +
  5. 請注意,陣列裡面的陣列稱為多維陣列(multidimensional array)。你可以撰寫兩組方括弧,來存取陣列裡面的陣列單位。例如說,存取前述 random 變數內的陣列單位就可以這麼寫: +
    random[2][2];
    +
  6. +
  7. 看下去之前,試著進一步使用並修改陣列。
  8. +
+ +

找出陣列長度

+ +

找出陣列長度(意即有幾個單位在陣列內)的方法,跟找出字串長度(含有幾個字元)的方式一樣——都是使用 {{jsxref("Array.prototype.length","length")}} 屬性。試試下方程式行:

+ +
shopping.length;
+// should return 5
+ +

這還有其他用途,但最常見的用法是讓迴圈一直循環直到所有的單元都走過一次。 舉個例子:

+ +
var sequence = [1, 1, 2, 3, 5, 8, 13];
+for (var i = 0; i < sequence.length; i++) {
+  console.log(sequence[i]);
+}
+ +

在後續的章節,你會學到更多關於迴圈的部分;簡而言之,上述程式碼的意思是:

+ +
    +
  1. 從陣列中索引為 0 的單元開始循環。
  2. +
  3. 當索引值等於陣列的長度時,停止循環。這個方法對任何長度的陣列都可行,但在這個例子中,迴圈會當索引等於 7 時停止循環(這樣很好,因為最後一個單元——我們希望有包含到的——是6)。
  4. +
  5. 我們在瀏覽器 console 中用 console.log() 將每個單元列印出來。
  6. +
+ +

好用的陣列方法

+ +

在這個小節中,我們會介紹一些相當有用、有關陣列的方法。例如將字串拆分為陣列,反之亦然,以及增加新的單位到陣列中。

+ +

在字串與陣列之間轉換

+ +

通常你會看到一組含有原始資料的長字串,而你可能會希望將有用的單元拆分、組成更好用的形式,對他進行操作。為了達成這個目的,我們可以使用 {{jsxref("String.prototype.split()","split()")}} 方法。它最簡單的形式是只使用一個參數,你想分離的字串位置的字元(分隔符),而後它會返回陣列中在分隔符之間的子字串。

+ +
+

Note: 好的,在技術上它屬於字串的方法,而非陣列的方法。但因為它可以很順利地對陣列進行操作,因此我們把它列在這邊。

+
+ +
    +
  1. 來試試這個,看它如何運作。首先,建立一個字串在你的 console: +
    var myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';
    +
  2. +
  3. 現在我們用逗點來分隔字串: +
    var myArray = myData.split(',');
    +myArray;
    +
  4. +
  5. 最後,試著找出你新的陣列的長度,並且從中取出一些單元: +
    myArray.length;
    +myArray[0]; // the first item in the array
    +myArray[1]; // the second item in the array
    +myArray[myArray.length-1]; // the last item in the array
    +
  6. +
  7. 相對地,你也可以用 {{jsxref("Array.prototype.join()","join()")}} 方法。試試下面這段: +
    var myNewString = myArray.join(',');
    +myNewString;
    +
  8. +
  9. 另一個將陣列轉換為字串的方法是用 {{jsxref("Array.prototype.toString()","toString()")}} 。toString() 因為不需要參數而比 join() 更簡潔,但因此也更多限制。使用 join() 你可以使用特定的分隔符(試著使用其他不同的字元來執行步驟 4)。 +
    var dogNames = ['Rocket','Flash','Bella','Slugger'];
    +dogNames.toString(); //Rocket,Flash,Bella,Slugger
    +
  10. +
+ +

新增與移除陣列單位

+ +

我們還沒談到增加與移除陣列的單位,現在來看看吧!我們使用上一個小節中的 myArray 陣列。如果你沒跟隨到上一個小節,那就先在你的 console 建立下面這個陣列:

+ +
var myArray = ['Manchester', 'London', 'Liverpool', 'Birmingham', 'Leeds', 'Carlisle'];
+ +

首先,我們可以分別使用 {{jsxref("Array.prototype.push()","push()")}} 和 {{jsxref("Array.prototype.pop()","pop()")}} 來增加或移除一個在陣列最末端的單元 。

+ +
    +
  1. Let's use push() first — note that you need to include one or more items that you want to add to the end of your array. Try this: + +
    myArray.push('Cardiff');
    +myArray;
    +myArray.push('Bradford', 'Brighton');
    +myArray;
    +
    +
  2. +
  3. The new length of the array is returned when the method call completes. If you wanted to store the new array length in a variable, you could do something like this: +
    var newLength = myArray.push('Bristol');
    +myArray;
    +newLength;
    +
  4. +
  5. Removing the last item from the array is as simple as running pop() on it. Try this: +
    myArray.pop();
    +
  6. +
  7. The item that was removed is returned when the method call completes. To save that item in a new variable, you could do this: +
    var removedItem = myArray.pop();
    +myArray;
    +removedItem;
    +
  8. +
+ +

{{jsxref("Array.prototype.unshift()","unshift()")}} and {{jsxref("Array.prototype.shift()","shift()")}} work in exactly the same way as push() and pop(), respectively, except that they work on the beginning of the array, not the end.

+ +
    +
  1. First unshift() — try the following commands: + +
    myArray.unshift('Edinburgh');
    +myArray;
    +
  2. +
  3. Now shift(); try these! +
    var removedItem = myArray.shift();
    +myArray;
    +removedItem;
    +
  4. +
+ +

Active learning: Printing those products!

+ +

Let's return to the example we described earlier — printing out product names and prices on an invoice, then totaling the prices and printing them at the bottom. In the editable example below there are comments containing numbers — each of these marks a place where you have to add something to the code. They are as follows:

+ +
    +
  1. Below the // number 1 comment are a number of strings, each one containing a product name and price separated by a colon. We'd like you to turn this into an array and store it in an array called products.
  2. +
  3. On the same line as the // number 2 comment is the beginning of a for loop. In this line we currently have i <= 0, which is a conditional test that causes the for loop to stop immediately, because it is saying "stop when i is no longer less than or equal to 0", and i starts at 0. We'd like you to replace this with a conditional test that stops the loop when i is no longer less than the products array's length.
  4. +
  5. Just below the // number 3 comment we want you to write a line of code that splits the current array item (name:price) into two separate items, one containing just the name and one containing just the price. If you are not sure how to do this, consult the Useful string methods article for some help, or even better, look at the {{anch("Converting between strings and arrays")}} section of this article.
  6. +
  7. As part of the above line of code, you'll also want to convert the price from a string to a number. If you can't remember how to do this, check out the first strings article.
  8. +
  9. There is a variable called total that is created and given a value of 0 at the top of the code. Inside the loop (below // number 4) we want you to add a line that adds the current item price to that total in each iteration of the loop, so that at the end of the code the correct total is printed onto the invoice. You might need an assignment operator to do this.
  10. +
  11. We want you to change the line just below // number 5 so that the itemText variable is made equal to "current item name — $current item price", for example "Shoes — $23.99" in each case, so the correct information for each item is printed on the invoice. This is just simple string concatenation, which should be familiar to you.
  12. +
+ + + +

{{ EmbedLiveSample('Playable_code', '100%', 730, "", "", "hide-codepen-jsfiddle") }}

+ +

Active learning: Top 5 searches

+ +

A good use for array methods like {{jsxref("Array.prototype.push()","push()")}} and {{jsxref("Array.prototype.pop()","pop()")}} is when you are maintaining a record of currently active items in a web app. In an animated scene for example, you might have an array of objects representing the background graphics currently displayed, and you might only want 50 displayed at once, for performance or clutter reasons. As new objects are created and added to the array, older ones can be deleted from the array to maintain the desired number.

+ +

In this example we're going to show a much simpler use — here we're giving you a fake search site, with a search box. The idea is that when terms are entered in the search box, the top 5 previous search terms are displayed in the list. When the number of terms goes over 5, the last term starts being deleted each time a new term is added to the top, so the 5 previous terms are always displayed.

+ +
+

Note: In a real search app, you'd probably be able to click the previous search terms to return to previous searches, and it would display actual search results! We are just keeping it simple for now.

+
+ +

To complete the app, we need you to:

+ +
    +
  1. Add a line below the // number 1 comment that adds the current value entered into the search input to the start of the array. This can be retrieved using searchInput.value.
  2. +
  3. Add a line below the // number 2 comment that removes the value currently at the end of the array.
  4. +
+ + + +

{{ EmbedLiveSample('Playable_code_2', '100%', 700, "", "", "hide-codepen-jsfiddle") }}

+ +

Conclusion

+ +

After reading through this article, we are sure you will agree that arrays seem pretty darn useful; you'll see them crop up everywhere in JavaScript, often in association with loops in order to do the same thing to every item in an array. We'll be teaching you all the useful basics there are to know about loops in the next module, but for now you should give yourself a clap and take a well-deserved break; you've worked through all the articles in this module!

+ +

The only thing left to do is work through this module's assessment, which will test your understanding of the articles that came before it.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}

+ + + +

In this module

+ + diff --git a/files/zh-tw/learn/javascript/first_steps/index.html b/files/zh-tw/learn/javascript/first_steps/index.html new file mode 100644 index 0000000000..418325ca8f --- /dev/null +++ b/files/zh-tw/learn/javascript/first_steps/index.html @@ -0,0 +1,71 @@ +--- +title: JavaScript 初探 +slug: Learn/JavaScript/First_steps +tags: + - JavaScript + - 初學者 + - 字串 + - 指引 + - 撰寫程式 + - 數值 + - 數學 + - 文章 + - 變數 + - 運算子 + - 陣列 +translation_of: Learn/JavaScript/First_steps +--- +
{{LearnSidebar}}
+ +

帶領各位開始體驗撰寫 JavaScript 前,在第一個 JavaScript 單元中,我們首先來回答一些基本的問題,像是「什麼是 JavaScript 啊?」、「它長什麼樣子?」以及「它能拿來做什麼?」。之後我們會詳細討論幾個關鍵元素,諸如變量(variables)、字串(strings)、數字(numbers)和陣列(arrays)。

+ +

事前準備

+ +

在開始這個教學之前,你不需要具備任何的 JavaScript 相關知識,但是你應該對 HTML 及 CSS 有一點熟悉。建議你在開始學習 JavaScript 前,先看過下列內容 :

+ + + +
+

注意: 假如你正在使用 電腦/平板/其他裝置,你還不需要知道如何建立自己的檔案,你可以在線上程式撰寫系統來嘗試範例程式,像是 JSBin 或 Thimble.

+
+ +

概觀

+ +
+
什麼是 JavaScript?
+
歡迎來到 MDN JavaScript 新手村教學!在第一個章節中我們將一個較高的層次看 JavaScript,回答像是「它是什麼?」、「有什麼用?」之類的問題,並且確保你能了解 JavaScript 的目的。
+
和 JavaScript 的第一次接觸
+
現在你已經學到一些關於 JavaScript 的原理,以及可以用它來作什麼,我們將經由完整的引導,給你一個關於 JavaScript 基礎功能的速成課。這裡你將會一步一步地建立一個簡單的「猜數字」遊戲。
+
什麼出錯了? JavaScript 的疑難排解(除錯)
+
當你在前一章節建立的「猜數字」遊戲過程中,你可能會發現它不能運作。不要慌,這個章節的目的是提供一些提示,用來找出及修正在 JavaScript 程式裡的錯誤,讓你不會因為這些問題而煩惱。
+
儲存你需要的資訊 — 變數
+
在讀過前面幾個章節後,你現在應該能由較高的層次了解 JavaScript 是什麼,它能為你做些什麼,如何與其他的網站技術一起使用,以及它的主要的特性。在本章節中,我們將深入探討真正的基礎知識,看看 JavaScript 最基本的組成 — 變數(Variables)是如何運作 。
+
JavaScript 的基本運算— 數字 與 運算子
+
本章的重點,我們討論 JavaScript 的數值計算 — 我們如何依我們的要求組合運算子與其它元素來操控數值。
+
處理文字 — JavaScript 的字串
+
接下來我們將焦點轉到字串(strings) — 這是程式裡對一段文字的稱呼。這個章節我們將會檢視學習 JavaScript 中,所有你通常想要知道於字串事情,例如創建字串、字串跳脫(escaping)操作,以及把它們組合起來。
+
有用的字串方法
+
我們已經看過了字串的基礎知識,現在讓我們加快腳步,看看可以使用內建的方法對字串進行哪些有用的操作 ,例如:取得字串的長度、串接或分割字串、替換字串中的某個字……等等。
+
陣列
+
在這個單元的最後一個章節,我們來看看陣列 (Array) — 把一連串資料整齊地儲存在一個變數中。我們會看到為什麼它有用,然後探索如何創建一個陣列,對陣列內的項目進行檢索、新增、刪除……等操作。
+
+ +

測試一下

+ +

下面的任務會測試你對於前面提到的 JavaScript 基本概念是否了解。

+ +
+
傻故事產生器
+
本次測試中,你的任務是使用在這個單元所學到的知識,建立一個能隨機產生笑話的有趣程式。祝你愉快!
+
+ +

參考資源

+ +
+
Learn JavaScript
+
對於想成為網站開發者一個很好的資源,以互動的方式學習 JavaScript ,包含短課程、互動測驗,自動評估狀況給予指引。前 40 堂課是免費,完整的課程可以在一次付費買下。
+
diff --git a/files/zh-tw/learn/javascript/first_steps/math/index.html b/files/zh-tw/learn/javascript/first_steps/math/index.html new file mode 100644 index 0000000000..4c7f1d4cba --- /dev/null +++ b/files/zh-tw/learn/javascript/first_steps/math/index.html @@ -0,0 +1,426 @@ +--- +title: JavaScript中的基本數學 - 數字和運算符 +slug: Learn/JavaScript/First_steps/Math +translation_of: Learn/JavaScript/First_steps/Math +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps")}}
+ +

在本課程的這一點上,我們將討論JavaScript中的數學 - 我們如何使用{{Glossary("Operator","operators")}} 和其他功能來成功操縱數字來進行我們的出價。

+ + + + + + + + + + + + +
先備知識:電腦基礎知識,了解基本的 HTML 和 CSS ,了解 JavaScript 是什麼。
目標:熟悉JavaScript中的基礎數學。
+ +

每個人都喜歡數學

+ +

好吧,也許不是。 我們中的一些人喜歡數學,我們有些人討厭數學,因為我們必須在學校學習乘法和除法,而我們中的一些人兩者皆要。 但我們都不能否認數學是生活中的一個基本組成部分,我們離不開它們。 當我們學習JavaScript(或任何其他語言)的程式時,尤其如此 - 我們所做的很多事情都依賴於處理數值數據,計算新值等等,你不會驚訝學習JavaScript 有一套功能齊全的數學函數。

+ +

本文僅討論你現在需了解的基本部分。

+ +

數字的種類

+ +

在程式裡,即使眾所周知的十進位數字系統也比您想像的要複雜。我們使用不同的術語來描述不同類型的十進位數字,例如:

+ + + +

我們甚至有不同類型的號碼系統!十進位以10為單位(表示每列使用0–9),但是也有像這些:

+ + + +

在開始擔心大腦融化之前,先等等!首先,我們將在整個課程中完全使用十進位數;您很少會想到其他類型的需求,如果有的話。 

+ +

第二個好消息是JavaScript只有一種數字資料類型 ,猜對了!就是{{jsxref("Number")}}。這代表無論你在JavaScript需要處理哪種數字,處理方法都是一樣的。

+ +
+

Note: 事實上, JavaScript 有第二種數字型態, {{Glossary("BigInt")}}, 用於非常、非常、非常大的整數。但這節課我只需要擔心 Number 的值。

+
+ +

我怎麼看都是些數字!

+ +

讓我們來快速操作一些數字來重新認識一下我們會需要用到的基本語法。將下面的需求表輸入進你的開發者工具js控制台(developer tools JavaScript console),或是簡單建立在任何你偏好的控制台。

+ +
    +
  1. 首先,先來宣告兩個變數,並分別賦予他們初始值為整數與浮點數,然後接著打上變數名稱來確認萬事預備: +
    var myInt = 5;
    +var myFloat = 6.667;
    +myInt;
    +myFloat;
    +
  2. +
  3. 數字的值不需要引號框起來 — 試著宣告和賦予更多初始值為數字的變數,在繼續下去之前。
  4. +
  5. 現在,來確認Now let's check that both our original variables are of the same datatype. There is an operator called {{jsxref("Operators/typeof", "typeof")}} in JavaScript that does this. Enter the below two lines as shown: +
    typeof myInt;
    +typeof myFloat;
    + You should get "number" returned in both cases — this makes things a lot easier for us than if different numbers had different data types, and we had to deal with them in different ways. Phew!
  6. +
+ +

算術運算符

+ +

Arithmetic operators are the basic operators that we use to do sums:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperatorNamePurposeExample
+加法Adds two numbers together.6 + 9
-減法Subtracts the right number from the left.20 - 15
*乘法Multiplies two numbers together.3 * 7
/除法Divides the left number by the right.10 / 5
%餘數 (sometimes called modulo) +

Returns the remainder left over after you've divided the left number into a number of integer portions equal to the right number.

+
8 % 3 (returns 2, as three goes into 8 twice, leaving 2 left over.)
**指數Raises a base number to the exponent power, that is, the base number multiplied by itself, exponent times. It was first Introduced in EcmaScript 2016.5 ** 2 (5的2次方得 25,跟 5 * 5結果相同)
+ +
+

Note: You'll sometimes see numbers involved in sums referred to as {{Glossary("Operand", "operands")}}.

+
+ +

Note: You may sometimes see exponents expressed using the older {{jsxref("Math.pow()")}} method, which works in a very similar way. For example, in Math.pow(7, 3)7 is the base and 3 is the exponent, so the result of the expression is 343Math.pow(7, 3) is equivalent to 7**3.

+ +

We probably don't need to teach you how to do basic math, but we would like to test your understanding of the syntax involved. Try entering the examples below into your developer tools JavaScript console, or use the simple built in console seen earlier if you'd prefer, to familiarize yourself with the syntax.

+ +
    +
  1. First try entering some simple examples of your own, such as +
    10 + 7
    +9 * 8
    +60 % 3
    +
  2. +
  3. You can also try declaring and initializing some numbers inside variables, and try using those in the sums — the variables will behave exactly like the values they hold for the purposes of the sum. For example: +
    var num1 = 10;
    +var num2 = 50;
    +9 * num1;
    +num2 / num1;
    +
  4. +
  5. Last for this section, try entering some more complex expressions, such as: +
    5 + 10 * 3;
    +num2 % 9 * num1;
    +num2 + num1 / 8 + 2;
    +
  6. +
+ +

Some of this last set of sums might not give you quite the result you were expecting; the below section might well give the answer as to why.

+ +

Operator precedence

+ +

Let's look at the last example from above, assuming that num2 holds the value 50 and num1 holds the value 10 (as originally stated above):

+ +
num2 + num1 / 8 + 2;
+ +

As a human being, you may read this as "50 plus 10 equals 60", then "8 plus 2 equals 10", and finally "60 divided by 10 equals 6".

+ +

But the browser does "10 divided by 8 equals 1.25", then "50 plus 1.25 plus 2 equals 53.25".

+ +

This is because of operator precedence — some operators will be applied before others when calculating the result of a sum (referred to as an expression, in programming).  Operator precedence in JavaScript is the same as is taught in math classes in school — Multiply and divide are always done first, then add and subtract (the sum is always evaluated from left to right).

+ +

If you want to override operator precedence, you can put parentheses round the parts that you want to be explicitly dealt with first. So to get a result of 6, we could do this:

+ +
(num2 + num1) / (8 + 2);
+ +

Try it and see.

+ +
+

Note: A full list of all JavaScript operators and their precedence can be found in Expressions and operators.

+
+ +

遞增和遞減運算符

+ +

Sometimes you'll want to repeatedly add or subtract one to/from a numeric variable value. This can be conveniently done using the increment (++) and decrement(--) operators. We used ++ in our  "Guess the number" game back in our first splash into JavaScript article, when we added 1 to our guessCount variable to keep track of how many guesses the user has left after each turn.

+ +
guessCount++;
+ +
+

Note: They are most commonly used in loops, which you'll learn about later on in the course. For example, say you wanted to loop through a list of prices, and add sales tax to each one. You'd use a loop to go through each value in turn and do the necessary calculation for adding the sales tax in each case. The incrementor is used to move to the next value when needed. We've actually provided a simple example showing how this is done — check it out live, and look at the source code to see if you can spot the incrementors! We'll look at loops in detail later on in the course.

+
+ +

Let's try playing with these in your console. For a start, note that you can't apply these directly to a number, which might seem strange, but we are assigning a variable a new updated value, not operating on the value itself. The following will return an error:

+ +
3++;
+ +

So, you can only increment an existing variable. Try this:

+ +
var num1 = 4;
+num1++;
+ +

Okay, strangeness number 2! When you do this, you'll see a value of 4 returned — this is because the browser returns the current value, then increments the variable. You can see that it's been incremented if you return the variable value again:

+ +
num1;
+ +

The same is true of -- : try the following

+ +
var num2 = 6;
+num2--;
+num2;
+ +
+

Note: You can make the browser do it the other way round — increment/decrement the variable then return the value — by putting the operator at the start of the variable instead of the end. Try the above examples again, but this time use ++num1 and --num2.

+
+ +

賦值運算符

+ +

Assignment operators are operators that assign a value to a variable. We have already used the most basic one, =, loads of times — it simply assigns the variable on the left the value stated on the right:

+ +
var x = 3; // x contains the value 3
+var y = 4; // y contains the value 4
+x = y; // x now contains the same value y contains, 4
+ +

But there are some more complex types, which provide useful shortcuts to keep your code neater and more efficient. The most common are listed below:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperatorNamePurposeExampleShortcut for
+=Addition assignmentAdds the value on the right to the variable value on the left, then returns the new variable valuex = 3;
+ x += 4;
x = 3;
+ x = x + 4;
-=Subtraction assignmentSubtracts the value on the right from the variable value on the left, and returns the new variable valuex = 6;
+ x -= 3;
x = 6;
+ x = x - 3;
*=Multiplication assignmentMultiples the variable value on the left by the value on the right, and returns the new variable valuex = 2;
+ x *= 3;
x = 2;
+ x = x * 3;
/=Division assignmentDivides the variable value on the left by the value on the right, and returns the new variable valuex = 10;
+ x /= 5;
x = 10;
+ x = x / 5;
+ +

Try typing some of the above examples into your console, to get an idea of how they work. In each case, see if you can guess what the value is before you type in the second line.

+ +

Note that you can quite happily use other variables on the right hand side of each expression, for example:

+ +
var x = 3; // x contains the value 3
+var y = 4; // y contains the value 4
+x *= y; // x now contains the value 12
+ +
+

Note: There are lots of other assignment operators available, but these are the basic ones you should learn now.

+
+ +

Active learning: sizing a canvas box

+ +

In this exercise, you will manipulate some numbers and operators to change the size of a box. The box is drawn using a browser API called the {{domxref("Canvas API", "", "", "true")}}. There is no need to worry about how this works — just concentrate on the math for now. The width and height of the box (in pixels) are defined by the variables x and y, which are initially both given a value of 50.

+ +

{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/maths/editable_canvas.html", '100%', 620)}}

+ +

Open in new window

+ +

In the editable code box above, there are two lines marked with a comment that we'd like you to update to make the box grow/shrink to certain sizes, using certain operators and/or values in each case. Let's try the following:

+ + + +

Don't worry if you totally mess the code up. You can always press the Reset button to get things working again. After you've answered all the above questions correctly, feel free to play with the code some more or create your own challenges.

+ +

比較運算符

+ +

Sometimes we will want to run true/false tests, then act accordingly depending on the result of that test — to do this we use comparison operators.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperatorNamePurposeExample
===Strict equalityTests whether the left and right values are identical to one another5 === 2 + 4
!==Strict-non-equalityTests whether the left and right values not identical to one another5 !== 2 + 3
<Less thanTests whether the left value is smaller than the right one.10 < 6
>Greater thanTests whether the left value is greater than the right one.10 > 20
<=Less than or equal toTests whether the left value is smaller than or equal to the right one.3 <= 2
>=Greater than or equal toTests whether the left value is greater than or equal to the right one.5 >= 4
+ +
+

Note: You may see some people using == and != in their tests for equality and non-equality. These are valid operators in JavaScript, but they differ from ===/!==. The former versions test whether the values are the same but not whether the values' datatypes are the same. The latter, strict versions test the equality of both the values and their datatypes. The strict versions tend to result in fewer errors, so we recommend you use them.

+
+ +

If you try entering some of these values in a console, you'll see that they all return true/false values — those booleans we mentioned in the last article. These are very useful, as they allow us to make decisions in our code, and they are used every time we want to make a choice of some kind. For example, booleans can be used to:

+ + + +

We'll look at how to code such logic when we look at conditional statements in a future article. For now, let's look at a quick example:

+ +
<button>Start machine</button>
+<p>The machine is stopped.</p>
+
+ +
var btn = document.querySelector('button');
+var txt = document.querySelector('p');
+
+btn.addEventListener('click', updateBtn);
+
+function updateBtn() {
+  if (btn.textContent === 'Start machine') {
+    btn.textContent = 'Stop machine';
+    txt.textContent = 'The machine has started!';
+  } else {
+    btn.textContent = 'Start machine';
+    txt.textContent = 'The machine is stopped.';
+  }
+}
+ +

{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/maths/conditional.html", '100%', 100)}}

+ +

Open in new window

+ +

You can see the equality operator being used just inside the updateBtn() function. In this case, we are not testing if two mathemetical expressions have the same value — we are testing whether the text content of a button contains a certain string — but it is still the same principle at work. If the button is currently saying "Start machine" when it is pressed, we change its label to  "Stop machine", and update the label as appropriate. If the button is currently saying "Stop machine" when it is pressed, we swap the display back again.

+ +
+

Note: Such a control that swaps between two states is generally referred to as a toggle. It toggles between one state and another — light on, light off, etc.

+
+ +

Summary

+ +

In this article we have covered the fundamental information you need to know about numbers in JavaScript, for now. You'll see numbers used again and again, all the way through your JavaScript learning, so it's a good idea to get this out of the way now. If you are one of those people that doesn't enjoy math, you can take comfort in the fact that this chapter was pretty short.

+ +

In the next article, we'll explore text and how JavaScript allows us to manipulate it.

+ +
+

Note: If you do enjoy math and want to read more about how it is implemented in JavaScript, you can find a lot more detail in MDN's main JavaScript section. Great places to start are our Numbers and dates and Expressions and operators articles.

+
+ +

{{PreviousMenuNext("Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps")}}

+ +

在這個學習模組中

+ + diff --git a/files/zh-tw/learn/javascript/first_steps/silly_story_generator/index.html b/files/zh-tw/learn/javascript/first_steps/silly_story_generator/index.html new file mode 100644 index 0000000000..2659623210 --- /dev/null +++ b/files/zh-tw/learn/javascript/first_steps/silly_story_generator/index.html @@ -0,0 +1,149 @@ +--- +title: 傻故事產生器 +slug: Learn/JavaScript/First_steps/Silly_story_generator +tags: + - JavaScript + - 初學者 + - 字串 + - 測試 + - 變數 + - 運算子 + - 陣列 +translation_of: Learn/JavaScript/First_steps/Silly_story_generator +--- +
{{LearnSidebar}}
+ +
{{PreviousMenu("Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}
+ +

在本次評估中,您被賦予的任務內容將與本單元學習到的知識息息相關,並將其應用於創建一個能隨機生成傻故事的有趣應用程式。 祝玩的開心!

+ + + + + + + + + + + + +
事先具備:進行此測驗之前你應先完成此區塊的所有內容
目標:測試對於JavaScript基礎的理解程度, 例如 變數, 數字, 運算子, 字串 以及陣列.
+ +

前置作業

+ +

在開始本測驗前,你應該:

+ + + +
+

備註: 除了將檔案下載到自己的電腦中,您也能使用線上編輯程式的網頁,像是: JSBin 或者Thimble 來完成評估測驗。您可以將 HTML, CSS 以及 JavaScript 貼到前述的線上編輯器中。如果您使用的線上編輯器沒有獨立給 JavaScript 的編輯區,您也能透過<script>直接將JS語法放到 HTML檔案中。

+
+ +

任務簡介

+ +

透過前述網頁您已經得到初版HTML/CSS 與一些JavaScript 字串、函數;您需要再寫一些必要的JavaScript語法來將這些檔案轉變為可運作的程式,任務如下: 

+ + + +

以下截圖為完成品的範例:

+ +

+ +

點擊右方連結可以參考與測試完成品: have a look at the finished example (請不要偷看原始碼喔!)

+ +

任務開始

+ +

以下清楚地描述了完成任務需要哪些動作。

+ +

基本設定:

+ +
    +
  1. 在有index.html的資料夾中建立一個新檔案稱之為 main.js
  2. +
  3. 請在index.html中引用第一點建立的外部JavaScript 檔案,引用方法是在</body> tag 前插入一組 {{htmlelement("script")}}元素 ,並在opening tag上加入src=" main.js"​​​​​​
  4. +
+ +

初始化變數與函數:

+ +
    +
  1. 在原始文件檔中(raw text file),請複製標題1. COMPLETE VARIABLE AND FUNCTION DEFINITIONS" 以下到第2點前的所有程式碼,並貼到main.js中。這給你三個變數來標記:文字輸入框 "Enter custom name" (輸入自定義名字) ,變數為 (customName) 與按鈕 "Generate random story"(產生隨機故事) ,變數為 (randomize), 以及HTML中接近body底部的 {{htmlelement("p")}} 元素,故事將會被複製進第三個變數(story)中。此外您還會得到一個函數稱為: randomValueFromArray() ,從命名中可以得知這是一個陣列,它會隨機提供一則儲存其中的故事。
  2. +
  3. 接著讓我們查看原始文件檔中(raw text file)的第2點: "2. RAW TEXT STRINGS"。 其包含的這些字串在程式運行時會被放進來,請幫忙在main.js中將這些字串分別存進對應的變數裡: +
      +
    1. 將第一行超級長的字串存進變數 storyText中。
    2. +
    3. 將第一組三個字串存進一陣列,並命名為insertX
    4. +
    5. 將第二組三個字串存進一陣列,並命名為insertY.
    6. +
    7. 將第三組三個字串存進一陣列,並命名為insertZ.
    8. +
    +
  4. +
+ +

放置事件監聽器與未完善的函數:

+ +
    +
  1. 再度回到原始文件檔中(raw text file)
  2. +
  3. 複製第3標題,"3. EVENT LISTENER AND PARTIAL FUNCTION DEFINITION" 以下的內容,並貼到 main.js 檔案中的最下方,這包含: +
      +
    • 給變數randomize增加一個點擊事件監聽器(clickevent listener) ,所以當產生故事的按鈕被點擊,result()函數會運行 。
    • +
    • 增加一個部分完成的函數 result() ,完成測驗您需要完善這個函數。
    • +
    +
  4. +
+ +

完善 result() 函數:

+ +
    +
  1. 創造一個新變數稱為:newStory,讓這個變數的值等於storyText;我們需要這個變數以便每次產生故事按鈕被點擊時,函數都能再次運作並產生新故事,如果我們只在storyText之上做改變,我們只能產生一次新故事。
  2. +
  3. 額外增加三個變數:xItemyItem 與 zItem,並使這三個變數等於函數randomValueFromArray()中三個陣列的結果(每次會從各陣列中隨機挑出一項)。舉例,你能透過寫randomValueFromArray(insertX)來從insertX得到任一隨機字串。
  4. +
  5. 接著我們需要將newStory中三個placeholders字串 :insertx::inserty:跟 :insertz:換成xItemyItem、 zItem。有些字串方法在這裡特別有用,請讓字串方法的返回值等於 newStory ,所以之後每次 newStory 被呼叫時,is made equal to itself, but with substitutions made. So each time the button is pressed, these placeholders are each replaced with a random silly string. As a further hint, the method in question only replaces the first instance of the substring it finds, so you might need to make one of the calls twice.
  6. +
  7. Inside the first if block, add another string replacement method call to replace the name 'Bob' found in the newStory string with the name variable. In this block we are saying "If a value has been entered into the customName text input, replace Bob in the story with that custom name."
  8. +
  9. Inside the second if block, we are checking to see if the uk radio button has been selected. If so, we want to convert the weight and temperature values in the story from pounds and Fahrenheit into stones and centigrade. What you need to do is as follows: +
      +
    1. Look up the formulae for converting pounds to stone, and Fahrenheit to centigrade.
    2. +
    3. Inside the line that defines the weight variable, replace 300 with a calculation that converts 300 pounds into stones. Concatenate ' stone' onto the end of the result of the overall Math.round() call.
    4. +
    5. Inside the line that defines the temperature variable, replace 94 with a calculation that converts 94 Fahrenheit into centigrade. Concatenate ' centigrade' onto the end of the result of the overall Math.round() call.
    6. +
    7. Just under the two variable definitions, add two more string replacement lines that replace '94 farenheit' with the contents of the temperature variable, and '300 pounds' with the contents of the weight variable.
    8. +
    +
  10. +
  11. Finally, in the second-to-last line of the function, make the textContent property of the story variable (which references the paragraph) equal to newStory.
  12. +
+ +

Hints and tips

+ + + +

測驗一下

+ +

如果您將這個測驗視為正規課程的一部分,建議將成果提供您的老師或指導者以利幫助您達到最好的學習效益。如果您是自學者,您可以輕鬆的透過右方網頁 discussion thread for this exercise 得到建議,或者在Mozilla IRC上的 #mdn IRC 頻道。提醒您:第一次嘗試這個測驗時,作弊可不會得到任何收穫喔!

+ +

{{PreviousMenu("Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}

+ + + +

相關學習模組

+ + diff --git a/files/zh-tw/learn/javascript/first_steps/strings/index.html b/files/zh-tw/learn/javascript/first_steps/strings/index.html new file mode 100644 index 0000000000..8e4a3b1f6a --- /dev/null +++ b/files/zh-tw/learn/javascript/first_steps/strings/index.html @@ -0,0 +1,352 @@ +--- +title: 處理文字 - JavaScript中的字串 +slug: Learn/JavaScript/First_steps/Strings +tags: + - JavaScript + - 初學者 + - 字串 + - 引號 + - 文章 + - 連接字串 +translation_of: Learn/JavaScript/First_steps/Strings +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps")}}
+ +

接下來我們將把注意力轉向字串——這就是程式設計中調用的文字片段。在本文中,我們將介紹在學習JavaScript時您應該了解所有有關字串的常見事項,例如建立字串,跳脫字串中的引號以及將字串連接在一起。

+ + + + + + + + + + + + +
先備知識:基本的電腦素養、對 HTML 與 CSS 有基本的認識、對 JavaScript 有認識。
目標:熟悉 JavaScript 字串的基礎。
+ +

文字的力量

+ +

文字對人類而言非常重要——它關乎我們如何交流、溝通。Web 以文字為基底的媒介,它的設計讓人類可以進行交流並分享資訊,因此掌握文字如何在 Web 上呈現是很有用的。{{glossary("HTML")}} 提供文字的結構以及定義;{{glossary("CSS")}} 讓我們更精確地設定樣式;而 JavaScript 則包含許多操作字串的特性,例如:製作客製化的歡迎訊息、正確地顯示所需的文字標籤、排列所需的詞語順序等。

+ +

到目前為止,所有我們課程上的編碼幾乎都包含一些字串的操作。

+ +

字串 — 基礎

+ +

剛開始你會覺得字串與數字的處理方式很類似,但當你越深入就會了解到一些明顯的差異。讓我們從在 console 裡輸入一些基本的程式行來熟悉它吧!在下方,我們提供一個 Console (你也可以另開一個頁籤或視窗使用他 ,或者使用瀏覽器的開發者工具)。

+ + + +

{{ EmbedLiveSample('Hidden_code', '100%', 300, "", "", "hide-codepen-jsfiddle") }}

+ +

建立字串

+ +
    +
  1. 首先,先輸入下面幾行程式碼: +
    let string = 'The revolution will not be televised.';
    +string;
    + 就像我們對數字的操作,我們聲明一個變數,並用一個值(字串)來初始化它,而後傳回這個值。唯一的差異在於,你需要用引號包住你的值。
  2. +
  3. 如果你沒有使用引號包住值,或缺少單一邊的引號,都會導致錯誤產生。試著輸入下面幾行程式碼: +
    let badString = This is a test;
    +let badString = 'This is a test;
    +let badString = This is a test';
    + 上述的程式無法運作,因為未使用引號包圍的文字都將被視為變數名稱、屬性名稱和保留字等。如果瀏覽器無法辨識它,便會產生錯誤(例如:「missing ; before statement」)。如果瀏覽器可以識別字段從哪裡開始,但無法找到字段的終點,意即缺少第二個引號,則會產生「unterminated string literal」的錯誤。如果你的程式出現了這樣的錯誤,檢查並確認自己的字串是否遺漏了任何引號。
  4. +
  5. 如果你先定義了變數 string ,則以下程式碼可以正常運作。馬上來試試看: +
    let badString = string;
    +badString;
    + badString 會被設定跟 string 具有一樣的值。
  6. +
+ +

單引號與雙引號

+ +
    +
  1. 在 JavaScript 中,你可以選擇用單引號或雙引號來包住字串。兩種方式都可行: +
    let sgl = 'Single quotes.';
    +let dbl = "Double quotes";
    +sgl;
    +dbl;
    +
  2. +
  3. 兩種之間的差異非常小,取決於你個人的習慣與喜好。你可以選擇一種,並且固定使用它。交互使用兩種方式,容易造成混亂。特別是當你使用兩種不同的引號包住一個字串!這會導致錯誤回傳: +
    let badQuotes = 'What on earth?";
    +
  4. +
  5. 瀏覽器會認為字串並沒有結束,沒有作為包住字串的引號,是可以出現在字串裡面的。看看下面的例子,兩種都是可行的: +
    let sglDbl = 'Would you eat a "fish supper"?';
    +let dblSgl = "I'm feeling blue.";
    +sglDbl;
    +dblSgl;
    +
  6. +
  7. 但是,字串中不可以再使用那個作為包住字串的引號。以下的程式行會出錯,因為瀏覽器無法判斷字串的結尾: +
    let bigmouth = 'I've got no right to take my place...';
    + This leads us very nicely into our next subject.
  8. +
+ +

字串中的跳脫字元(Escaping characters)

+ +

要修復先前出錯的那一行程式碼,我們需要解決引號的問題。跳脫字元(Escaping characters)的意思是我們需要確保它們被辨識為文字,而非程式碼本身。在 JavaScript 中,我們在字元的前面放一個反斜線解決這個問題。試試看這個:

+ +
let bigmouth = 'I\'ve got no right to take my place...';
+bigmouth;
+ +

這是可行的!你可以用一樣的方法跳脫其他字元,例如 \"。除此之外,還有一些特殊方法。更詳細的部分,請參閱跳脫符號 。

+ +

連接字串(Concatenating strings)

+ +
    +
  1. 連接(Concatenate)是一個新潮的程式用語。在 JavaScript 中,使用加號(+)將字串連接;這也是我們做數字相加的方式。但在這個狀況下,它有不同的作用。讓我們在 console 中示範:
  2. +
  3. +
    let one = 'Hello, ';
    +let two = 'how are you?';
    +let joined = one + two;
    +joined;
    + 這邊的結果是 joined  這個變數中,有了 「Hello, how are you?」這個值。
  4. +
  5. 在上一個範例中,我們只連接了兩個字串。但只要你在兩個字串之間加上 + ,那你要連接幾個都可以。試試看這個: +
    let multiple = one + one + one + one + two;
    +multiple;
    +
  6. +
  7. 你也可以結合變數和字串。試試看這個: +
    let response = one + 'I am fine — ' + two;
    +response;
    +
  8. +
+ +
+

Note: 當你輸入一個字串在你的程式碼中,並用單引號或雙引號將它括起來,它稱為字串文字string literal)。

+
+ +

Concatenation in context

+ +

讓我們看看實際運用連接字串的例子——以下是這堂課中稍早的範例:

+ +
<button>Press me</button>
+ +
const button = document.querySelector('button');
+
+button.onclick = function() {
+  let name = prompt('What is your name?');
+  alert('Hello ' + name + ', nice to see you!');
+}
+ +

{{ EmbedLiveSample('Concatenation_in_context', '100%', 50, "", "", "hide-codepen-jsfiddle") }}

+ +

在程式第四行我們用了 {{domxref("window.prompt()", "window.prompt()")}} 這個函式,可以要求使用者透過彈出的對話框去回答問題,並將使用者輸入的文字儲存在給訂的變數內(在這個例子中就是 name)。接著我們在第五行用了 {{domxref("window.alert()", "window.alert()")}} 函式,顯示另一個彈出視窗,以連接的方式將兩段字串文字以及 name 這個變數結合成一個字串。

+ +

數字 vs. 字串

+ +
    +
  1. 那麼我們將字串和數字連接會發生什麼事呢?讓我們在console中試試看: +
    'Front ' + 242;
    +
    + 或許你預期會跑出錯誤訊息,但看來依然正常運作。若將字串表示成數字似乎不太合理,但將數字表示成字串看來是可行的,所以瀏覽器便會巧妙地將數字轉換成字串,並將這兩個字串連接在一起。
  2. +
  3. 你也可以用兩個數字做這個例子 — 將這兩個數字包在引號中強制將它們轉換成字串。試試看(並使用typeof這個運算子去檢查變數是數字或字串): +
    let myDate = '19' + '67';
    +typeof myDate;
    +
  4. +
  5. 如果你想轉換數字變數成字串,但不要更動到原本的變數;或是想轉換字串變數成數字,也不要更動到原本的變數,你可以使用以下兩種方式: +
      +
    • 物件 {{jsxref("Number")}} 會將欲處理的變數轉換成數字(如果可行的話)。試試以下例子: +
      let myString = '123';
      +let myNum = Number(myString);
      +typeof myNum;
      +
    • +
    • 另一方面,也有 toString() 方法能夠讓數字轉換為相等的字串。試試看: +
      let myNum = 123;
      +let myString = myNum.toString();
      +typeof myString;
      +
    • +
    + 這些結構在某些情況相當好用。舉例來說:如果使用者在文字表單中輸入了一個數字,這個數字將會是字串格式。而若想要把這個數字加上另一個數字,那你會希望它是數字格式(才能做數字相加),所以可以使用 Number() 來處理這個情況。可以看看實際案例:猜數字遊戲, 第61行
  6. +
+ +

模版字符串(Template literals)

+ +

另一種你會遇上的字串語法是模版字符串(template literals) (也稱做模版字串 template strings)。這是一種更新的語法提供更彈性、簡單的方式去理解字串。

+ +
+

Note: 嘗試在你的瀏覽器上測試下面的範例,來看看會得到什麼結果。

+
+ +

將標準字串轉變為模版字符串,你需要將引號 (' ', or " ") 換為重音符 (backtick characters (` `) ),接著來看一個簡單的例子:

+ +
let song = 'Fight the Youth';
+ +

轉換成模版字符串會像這樣子:

+ +
song = `Fight the Youth`;
+ +

如果我們想要連接字串,或是將算式的結果包含在裡面,用傳統的字串去寫會很瑣碎且麻煩:

+ +
let score = 9;
+let highestScore = 10;
+let output = 'I like the song "' + song + '". I gave it a score of ' + (score/highestScore * 100) + '%.';
+ +

模版字符串能大量簡化這串程式碼:

+ +
output = `I like the song "${ song }". I gave it a score of ${ score/highestScore * 100 }%.`;
+ +

全部一串都只需要包含在一對重音符號裡,不再需要切開、合起一堆字串碎片。
+ 當你想要包含變數或者算式在字串裡時,你只需要將它放在 佔位符 ${ } 裡。

+ +

你能將複雜的算式包含在模版字符串裡,舉個例子:

+ +
let examScore = 45;
+let examHighestScore = 70;
+examReport = `You scored ${ examScore }/${ examHighestScore } (${ Math.round((examScore/examHighestScore*100)) }%). ${ examScore >= 49 ? 'Well done, you passed!' : 'Bad luck, you didn\'t pass this time.' }`;
+
+ + + +

另一個可以注意的點是,如果你想要將傳統字串拆分成多行,你需要加上一個斷行字母, \n

+ +
output = 'I like the song "' + song + '".\nI gave it a score of ' + (score/highestScore * 100) + '%.';
+ +

模版字符串保留了程式碼中的斷行方式,所以不再需要使用斷行字母。
+ 這樣也能達到相同的結果:

+ +
output = `I like the song "${ song }".
+I gave it a score of ${ score/highestScore * 100 }%.`;
+ +

我們建議你盡可能習慣使用模版字符串。現今流行的瀏覽器都能完好的支援它,只有一個地方你能發現它並不支援外: Internet Explorer。
+ 我們有許多的例子仍然使用目前標準的字串語法,但我們未來將會加入更多模版字符串的應用。

+ +

來我們的Template literals 相關頁面看看更多的範例與進階的特色細節。

+ +

測試您的技能!

+ +

你已到達文章的結尾了,但你能記得最重要的資訊嗎?
+ 在繼續學習之前,你可以找些難一點的測驗,來檢測你有記得這些知識 —  Test your skills: Strings. 記住,接下來的文章也需要這些知識,所以你可能想先看看。

+ +

結語

+ +

以上是JavaScript中基礎的字串觀念。下個文章中,我們會依循這些概念並試試一些適用於字串的內建方法,進而運用這些方法讓字串能照我們想要的方式呈現。

+ +

{{PreviousMenuNext("Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps")}}

+ +

在這個學習模組中

+ + diff --git a/files/zh-tw/learn/javascript/first_steps/useful_string_methods/index.html b/files/zh-tw/learn/javascript/first_steps/useful_string_methods/index.html new file mode 100644 index 0000000000..e5efb51e1b --- /dev/null +++ b/files/zh-tw/learn/javascript/first_steps/useful_string_methods/index.html @@ -0,0 +1,714 @@ +--- +title: 有用的字符串方法 +slug: Learn/JavaScript/First_steps/Useful_string_methods +translation_of: Learn/JavaScript/First_steps/Useful_string_methods +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}
+ +

現在我們已經了解了字符串的基礎知識,讓我們開始思考我們可以使用內置方法對字符串執行哪些有用的操作,例如查找文本字符串的長度,連接和拆分字符串 ,將字符串中的一個字符替換為另一個字符,等等。

+ + + + + + + + + + + + +
先備知識:基礎的電腦素養、基本的HTML和CSS、以及清楚什麼是JavaScript。
目標:了解字串是物件,學習使用一些能夠應用這些字串的基礎方法。
+ +

把字串當作物件

+ +

我們曾經說過,現在我們重申一遍—在javascript中,一切東西都可以被當作物件。例如我們創建一個字串。

+ +
var string = 'This is my string';
+ +

你的變數成為一個字串的實體物件,因此它將有許多性質(properties)與功能(methods)可以使用。

+ +

你的變數成為一個字串的實體物件,因此它將有許多性質(properties)與功能(methods)可以使用。你可以到 {{jsxref("String")}} 物件頁面的左方列表查看這些性質與功能!

+ +

好的,在你腦袋燒壞之前先別擔心!在這趟學習旅程中,關於這些大部分對於現在的你其實還不需要知道。不過有一些你可能會經常使用,我們將在這裡介紹。

+ +

Let's enter some examples into a fresh console. We've provided one below (you can also open this console in a separate tab or window, or use the browser developer console if you'd prefer).

+ + + +

{{ EmbedLiveSample('Hidden_code', '100%', 300, "", "", "hide-codepen-jsfiddle") }}

+ +

找出字串的長度(length)

+ +

這很簡單,你可以用 {{jsxref("String.prototype.length", "length")}} 屬性。試著輸入下面幾行:

+ +
var browserType = 'mozilla';
+browserType.length;
+ +

結果應該會回傳數字7,因為 "mozilla" 字元長度是7。 這在很多狀況下很好用,舉例來說:你會想知道序列的長度,這樣才能將這些序列按照長度排序,或是讓使用者知道他們輸入的名稱是否太長。

+ +

取得字串中的特定字元(string character)

+ +

On a related note, you can return any character inside a string by using square bracket notation — this means you include square brackets ([]) on the end of your variable name. Inside the square brackets you include the number of the character you want to return, so for example to retrieve the first letter you'd do this:

+ +
browserType[0];
+ +

記得電腦計數從0開始,不是1! 如果要在任何一個字串中取得最後一個字元,我們可以使用以下程式碼,結合了取得字元的技巧和上面學過的長度屬性:

+ +
browserType[browserType.length-1];
+ +

"mozilla" 這個詞的長度是7,但因為電腦是從0開始計數,所以最後一個位置是6,因此我們會將 length-1 。你也可以試試用這個方法找各序列的第一個字母,並將這些序列按字母順序排好 。

+ +

尋找字串中的子字串(substring)並提出子字串

+ +
    +
  1. Sometim有時候你會想搜尋是否有一個較小的字串存在於比較大的字串中(我們通常會說是否有個子字串存在於字串中)。這可以用 {{jsxref("String.prototype.indexOf()", "indexOf()")}} 方法,當中需要一個參數( {{glossary("parameter")}} ),也就是你想搜尋的子字串:
  2. +
  3. +
    browserType.indexOf('zilla');
    + 結果會傳回2,因為子字串 "zilla" 在 "mozilla" 中是從位置2開始的。(依然要記得電腦計數是從0開始)。這個方法可以用篩選字串,舉例來說:我們有一串網址的清單,而我們只想印出那些包含 "mozilla" 的網址。
  4. +
+ +
    +
  1. This can be done in another way, which is possibly even more effective. Try the following: +
    browserType.indexOf('vanilla');
    + This should give you a result of -1 — this is returned when the substring, in this case 'vanilla', is not found in the main string.
    +
    + You could use this to find all instances of strings that don't contain the substring 'mozilla', or do, if you use the negation operator, as shown below. You could do something like this: + +
    if(browserType.indexOf('mozilla') !== -1) {
    +  // do stuff with the string
    +}
    +
  2. +
  3. When you know where a substring starts inside a string, and you know at which character you want it to end, {{jsxref("String.prototype.slice()", "slice()")}} can be used to extract it. Try the following: +
    browserType.slice(0,3);
    + This returns "moz" — the first parameter is the character position to start extracting at, and the second parameter is the character position after the last one to be extracted. So the slice happens from the first position, up to, but not including, the last position. In this example, since the starting index is 0, the second parameter is equal to the length of the string being returned.
    +  
  4. +
  5. Also, if you know that you want to extract all of the remaining characters in a string after a certain character, you don't have to include the second parameter! Instead, you only need to include the character position from where you want to extract the remaining characters in a string. Try the following: +
    browserType.slice(2);
    + This returns "zilla" — this is because the character position of 2 is the letter z, and because you didn't include a second parameter, the substring that was returned was all of the remaining characters in the string. 
  6. +
+ +
+

Note: The second parameter of slice() is optional: if you don't include it, the slice ends at the end of the original string. There are other options too; study the {{jsxref("String.prototype.slice()", "slice()")}} page to see what else you can find out.

+
+ +

改變大小寫

+ +

The string methods {{jsxref("String.prototype.toLowerCase()", "toLowerCase()")}} and {{jsxref("String.prototype.toUpperCase()", "toUpperCase()")}} take a string and convert all the characters to lower- or uppercase, respectively. This can be useful for example if you want to normalize all user-entered data before storing it in a database.

+ +

Let's try entering the following lines to see what happens:

+ +
var radData = 'My NaMe Is MuD';
+radData.toLowerCase();
+radData.toUpperCase();
+ +

更動部分字串

+ +

You can replace one substring inside a string with another substring using the {{jsxref("String.prototype.replace()", "replace()")}} method. This works very simply at a basic level, although there are some advanced things you can do with it that we won't go into yet.

+ +

It takes two parameters — the string you want to replace, and the string you want to replace it with. Try this example:

+ +
browserType.replace('moz','van');
+ +

Note that to actually get the updated value reflected in the browserType variable in a real program, you'd have to set the variable value to be the result of the operation; it doesn't just update the substring value automatically. So you'd have to actually write this: browserType = browserType.replace('moz','van');

+ +

Active learning examples

+ +

In this section we'll get you to try your hand at writing some string manipulation code. In each exercise below, we have an array of strings, and a loop that processes each value in the array and displays it in a bulleted list. You don't need to understand arrays or loops right now — these will be explained in future articles. All you need to do in each case is write the code that will output the strings in the format that we want them in.

+ +

Each example comes with a "Reset" button, which you can use to reset the code if you make a mistake and can't get it working again, and a "Show solution" button you can press to see a potential answer if you get really stuck.

+ +

Filtering greeting messages

+ +

In the first exercise we'll start you off simple — we have an array of greeting card messages, but we want to sort them to list just the Christmas messages. We want you to fill in a conditional test inside the if( ... ) structure, to test each string and only print it in the list if it is a Christmas message.

+ +
    +
  1. First think about how you could test whether the message in each case is a Christmas message. What string is present in all of those messages, and what method could you use to test whether it is present?
  2. +
  3. You'll then need to write a conditional test of the form operand1 operator operand2. Is the thing on the left equal to the thing on the right? Or in this case, does the method call on the left return the result on the right?
  4. +
  5. Hint: In this case it is probably more useful to test whether the method call isn't equal to a certain result.
  6. +
+ + + +

{{ EmbedLiveSample('Playable_code', '100%', 590, "", "", "hide-codepen-jsfiddle") }}

+ +

Fixing capitalization

+ +

In this exercise we have the names of cities in the United Kingdom, but the capitalization is all messed up. We want you to change them so that they are all lower case, except for a capital first letter. A good way to do this is to:

+ +
    +
  1. Convert the whole of the string contained in the input variable to lower case and store it in a new variable.
  2. +
  3. Grab the first letter of the string in this new variable and store it in another variable.
  4. +
  5. Using this latest variable as a substring, replace the first letter of the lowercase string with the first letter of the lowercase string changed to upper case. Store the result of this replace procedure in another new variable.
  6. +
  7. Change the value of the result variable to equal to the final result, not the input.
  8. +
+ +
+

Note: A hint — the parameters of the string methods don't have to be string literals; they can also be variables, or even variables with a method being invoked on them.

+
+ + + +

{{ EmbedLiveSample('Playable_code_2', '100%', 550, "", "", "hide-codepen-jsfiddle") }}

+ +

Making new strings from old parts

+ +

In this last exercise, the array contains a bunch of strings containing information about train stations in the North of England. The strings are data items that contain the three-letter station code, followed by some machine-readable data, followed by a semicolon, followed by the human-readable station name. For example:

+ +
MAN675847583748sjt567654;Manchester Piccadilly
+ +

We want to extract the station code and name, and put them together in a string with the following structure:

+ +
MAN: Manchester Piccadilly
+ +

We'd recommend doing it like this:

+ +
    +
  1. Extract the three-letter station code and store it in a new variable.
  2. +
  3. Find the character index number of the semicolon.
  4. +
  5. Extract the human-readable station name using the semicolon character index number as a reference point, and store it in a new variable.
  6. +
  7. Concatenate the two new variables and a string literal to make the final string.
  8. +
  9. Change the value of the result variable to equal to the final string, not the input.
  10. +
+ + + +

{{ EmbedLiveSample('Playable_code_3', '100%', 585, "", "", "hide-codepen-jsfiddle") }}

+ +

結語

+ +

不可否認當網站在跟人們互相溝通時,處理文字和句子在程式設計中是相當重要的,尤其是在 JavaScript 中。這篇文章已經傳授你如何去處理字串的方法,應該對以後深入了解其他更複雜主題的你會很有幫助。接下來,我們將會看看最後一個近期內我們需要關注的主要的資料型態 — 陣列。

+ +

{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}

+ +

在這個學習模組中

+ + diff --git a/files/zh-tw/learn/javascript/first_steps/variables/index.html b/files/zh-tw/learn/javascript/first_steps/variables/index.html new file mode 100644 index 0000000000..1fce3a98fe --- /dev/null +++ b/files/zh-tw/learn/javascript/first_steps/variables/index.html @@ -0,0 +1,344 @@ +--- +title: 存儲您需要的資訊 - 變數 +slug: Learn/JavaScript/First_steps/Variables +tags: + - JavaScript + - 變數 + - 陣列 +translation_of: Learn/JavaScript/First_steps/Variables +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps")}}
+ +

閱讀完最後幾篇文章之後,您現在應該知道 JavaScript 是什麼,它可以為您做什麼,如何將它與其他 Web 技術一起使用,以及它的主要功能從高層看起來如何。 在本文中,我們將深入了解真正的基礎知識,了解如何使用 JavaScript 的大多數基本構建塊 - 變數。

+ + + + + + + + + + + + +
必備知識:電腦基礎知識,了解基本的 HTML 和 CSS ,了解 JavaScript 是什麼。
目標:熟悉 JavaScript 變數的基本知識。
+ +

您需要的工具

+ +

在此篇文章中,您將被要求輸入程式碼行來測試您對內容的理解。如果您使用的是網頁瀏覽器,最適合輸入代碼的地方便是 JavaScript 主控台, (請參閱什麼是瀏覽器開發工具這篇文章以取得更多關於此工具的資訊).

+ +

什麼是變量/變數 (variable) ?

+ +

變量是值的容器,就像我們可能在總和中使用的數字,或者我們可能用作句子一部分的字符串。 但關於變量的一個特殊之處在於它們包含的值可以改變。 我們來看一個簡單的例子:

+ +
<button>請按我</button>
+
+ +
const button = document.querySelector('button');
+
+button.onclick = function() {
+  let name = prompt('你叫什麼名字?');
+  alert('你好 ' + name + ', 很高興認識你!');
+}
+
+ +

{{ EmbedLiveSample('什麼是變量/變數_variable_?','100%', 50, "", "", "hide-codepen-jsfiddle") }}

+ +

在此示例中,按下按鈕會運行幾行代碼。 第一行在屏幕上彈出一個框,要求讀者輸入其名稱,然後將值存儲在變量中。 第二行顯示歡迎消息,其中包含從變量值中獲取的名稱。

+ +

要理解為什麼這麼有用,讓我們考慮如何在不使用變量的情況下編寫此示例。 它最終會看起來像這樣:

+ +
let name = prompt('What is your name?');
+
+if (name === 'Adam') {
+  alert('Hello Adam, nice to see you!');
+} else if (name === 'Alan') {
+  alert('Hello Alan, nice to see you!');
+} else if (name === 'Bella') {
+  alert('Hello Bella, nice to see you!');
+} else if (name === 'Bianca') {
+  alert('Hello Bianca, nice to see you!');
+} else if (name === 'Chris') {
+  alert('Hello Chris, nice to see you!');
+}
+
+// ... 等等 ...
+
+ +

你可能暫時還沒有完全理解這些代碼和語法,但是你應該能夠理解到如果我們沒有變量,我們就不得不寫大量的代碼去檢查輸入的名字,然後顯示相應名稱的消息 。這樣做顯然是低效率(雖然例子中只有5種選擇,但代碼卻相對地長)和不可行的你沒有辦法列舉出所有可能的名字。

+ +

使用變量才是明智的。隨著您對 JavaScript 越來越了解,您會開始習慣使用變量。

+ +

變量的另一個特性就是它們能夠存儲任何的東西不只是字符串和數字。變量可以存儲更複雜的數據,甚至是函數。你將在後續的內容中體驗到這些用法。

+ +
+

提示:變量是用來儲存數值的,而變量和數值是兩個不同的概念。變量不是數值本身,它們僅僅是一個用於儲存數值的容器。你可以把變量想像成一個個用來裝東西的紙皮箱。

+
+ +

+ +

定義變量 (Declaring a variable)

+ +

要想使用變量,你需要做的第一步就是創建它更準確的說,是定義一個變量。定義一個變量的語法是在關鍵字 var 或 let 之後加上變量的名字:

+ +
let myName;
+let myAge;
+
+ +

在這裡我們定義了兩個變量  myName 和 myAge。那麼現在嘗試輸入這些代碼到你的瀏覽器終端。之後,嘗試使用您自己選擇的名稱來創建一兩個變量。

+ +
+

提示在 JavaScript 中,所有代碼指令都會以分號結尾( ;)- 如果忘記加分號,你的單行代碼可能正常執行,但是在執行多行代碼的時候就可能出錯。所以,最好是養成主動以分號作為代碼結尾的習慣。

+
+ +

你可以輸入變量的名稱,來驗證這個變量的數值是否在執行環境(execution environment)中已經存在。例如,

+ +
myName;
+myAge;
+
+ +

以上這兩個變量並沒有數值,他們是空的容器。當你輸入變量名並按輸入鍵後,你會得到一個 undefined (沒有定義的值)的返回值。如果變量並不存在的話,你就會得到一個錯誤信息。請嘗試輸入:

+ +
scoobyDoo;
+ +
+

提示:千萬不要把兩個概念弄混淆了,「一個變量存在,但是沒有數值」和「一個變量並不存在」— 他們完全是兩回事。在前面你看到的盒子的類比中,不存在意味著沒有可以存放變量的「盒子」。沒有定義的值意味著一個「盒子」,但是它裡面沒有任何數值。

+
+ +

初始化變量 (Initializing a variable)

+ +

一旦你定義了一個變量,你就能夠初始化它來儲存數值。方法如下:在變量名之後跟上一個等號 (=),然後是數值。例如:

+ +
myName = 'Chris';
+myAge = 37;
+ +

Try going back to the console now and typing in these lines. You should see the value you've assigned to the variable returned in the console to confirm it, in each case. Again, you can return your variable values by simply typing their name into the console — try these again:

+ +
myName;
+myAge;
+ +

你可以同時定義並初始化變量,像是:

+ +
let myDog = 'Rover';
+ +

This is probably what you'll do most of the time, as it is quicker than doing the two actions on two separate lines.

+ +

比較var和let的不同 (The difference between var and let)

+ +

此刻你或許會思考「為什麼我們需要兩種方法來定義變數??「為甚麼要有varlet??

+ +

原因有些歷史淵源。在Javascript剛被創造的時候,只有var可以使用。在大部分的情況下都很正常,但是var的運作方式有些問題 — 它的設計有時會令人困惑甚至惹惱人。所以let在現代版本中的Javascript被創造出來,一個與var工作原理有些不同的創建變數的關鍵字,修復了var的種種問題。

+ +

以下將介紹幾個簡單的分別。我們現在不會一一講解全部的不同,但是當你慢慢深入Javascript,你將會開始發現它們的(如果你真的很想現在知道,歡迎看看我們的let 介紹頁)。

+ +

如下,假設你需要宣告、初始化一個變數myName,即使你是初始化之後才宣告也是可行的:

+ +
myName = 'Chris';
+
+function logName() {
+  console.log(myName);
+}
+
+logName();
+
+var myName;
+ +
+

Note: This won't work when typing individual lines into a JavaScript console, just when running multiple lines of JavaScript in a web document.

+
+ +

This works because of hoisting — read var hoisting for more detail on the subject.

+ +

Hoisting no longer works with let. If we changed var to let in the above example, it would fail with an error. This is a good thing — declaring a variable after you initialize it makes for confusing, harder to understand code.

+ +

Secondly, when you use var, you can declare the same variable as many times as you like, but with let you can't. The following would work:

+ +
var myName = 'Chris';
+var myName = 'Bob';
+ +

But the following would throw an error on the second line:

+ +
let myName = 'Chris';
+let myName = 'Bob';
+ +

You'd have to do this instead:

+ +
let myName = 'Chris';
+myName = 'Bob';
+ +

Again, this is a sensible language decision. There is no reason to redeclare variables — it just makes things more confusing.

+ +

For these reasons and more, we recommend that you use let as much as possible in your code, rather than var. There is no reason to use var, unless you need to support old versions of Internet Explorer with your code (it doesn't support let until version 11; the modern Windows Edge browser supports let just fine).

+ +
+

Note: We are currently in the process of updating the course to use let rather than var. Bear with us!

+
+ +

Updating a variable

+ +

Once a variable has been initialized with a value, you can change (or update) that value by simply giving it a different value. Try entering the following lines into your console:

+ +
myName = 'Bob';
+myAge = 40;
+ +

變數命名規則悄悄話

+ +

You can call a variable pretty much anything you like, but there are limitations. Generally, you should stick to just using Latin characters (0-9, a-z, A-Z) and the underscore character.

+ + + +
+

Note: You can find a fairly complete list of reserved keywords to avoid at Lexical grammar — keywords.

+
+ +

良好的命名範例:

+ +
age
+myAge
+init
+initialColor
+finalOutputValue
+audio1
+audio2
+ +

不好的命名範例:

+ +
1
+a
+_12
+myage
+MYAGE
+var
+Document
+skjfndskjfnbdskjfb
+thisisareallylongstupidvariablenameman
+ +

Error-prone name examples:

+ +
var
+Document
+
+ +

Try creating a few more variables now, with the above guidance in mind.

+ +

變數資料類型

+ +

There are a few different types of data we can store in variables. In this section we'll describe these in brief, then in future articles, you'll learn about them in more detail.

+ +

So far we've looked at the first two, but there are others.

+ +

Numbers 數字

+ +

You can store numbers in variables, either whole numbers like 30 (also called integers) or decimal numbers like 2.456 (also called floats or floating point numbers). You don't need to declare variable types in JavaScript, unlike some other programming languages. When you give a variable a number value, you don't include quotes:

+ +
let myAge = 17;
+ +

Strings 字串

+ +

Strings are pieces of text. When you give a variable a string value, you need to wrap it in single or double quote marks, otherwise, JavaScript will try to interpret it as another variable name.

+ +
let dolphinGoodbye = 'So long and thanks for all the fish';
+ +

Booleans 布林值

+ +

Booleans are true/false values — they can have two values, true or false. These are generally used to test a condition, after which code is run as appropriate. So for example, a simple case would be:

+ +
let iAmAlive = true;
+ +

Whereas in reality it would be used more like this:

+ +
let test = 6 < 3;
+ +

This is using the "less than" operator (<) to test whether 6 is less than 3. As you might expect, it will return false, because 6 is not less than 3! You will learn a lot more about such operators later on in the course.

+ +

Arrays 陣列

+ +

An array is a single object that 它包含多個用方括號括起來並用逗號分隔的值。Try entering the following lines into your console:

+ +
let myNameArray = ['Chris', 'Bob', 'Jim'];
+let myNumberArray = [10, 15, 40];
+ +

Once these arrays are defined, you can access each value by their location within the array. Try these lines:

+ +
myNameArray[0]; // should return 'Chris'
+myNumberArray[2]; // should return 40
+ +

The square brackets specify an index value corresponding to the position of the value you want returned. You might have noticed that arrays in JavaScript are zero-indexed: the first element is at index 0.

+ +

You'll learn a lot more about arrays in a future article.

+ +

Objects 物件

+ +

在編程中,物件是對真實生活物件進行建模的代碼結構。 您可以擁有一個代表停車場的簡單物件,其中包含有關其寬度和長度的信息,或者您可以擁有一個代表一個人的物件,並用物件紀錄其姓名、身高、體重、慣用語言,如何跟他打招呼等的資訊。

+ +

請試著在你的console中輸入以下指令:

+ +
let dog = { name : 'Spot', breed : 'Dalmatian' };
+ +

取得物件中儲存的資料可以使用以下語法:

+ +
dog.name
+ +

We won't be looking at objects any more for now — you can learn more about those in a future module.

+ +

動態型別

+ +

JavaScript 是一個"動態型別語言",意思是不像其他強型別程式語言,在JavaScript 宣告變數時你不用指定指定資料類型(數字、字串或陣列等等)。

+ +

For example, if you declare a variable and give it a value enclosed in quotes, the browser will treat the variable as a string:

+ +
let myString = 'Hello';
+ +

It will still be a string, even if it contains numbers, so be careful:

+ +
let myNumber = '500'; // oops, this is still a string
+typeof myNumber;
+myNumber = 500; // much better — now this is a number
+typeof myNumber;
+ +

Try entering the four lines above into your console one by one, and see what the results are. You'll notice that we are using a special operator called typeof — this returns the data type of the variable you pass into it. The first time it is called, it should return string, as at that point the myNumber variable contains a string, '500'. Have a look and see what it returns the second time you call it.

+ +

JavaScript中的常數

+ +

許多程式語言都有常數的概念:一經宣告就不改變的值。設定常數有許多原因,例如若引入第三方腳本而改動變數值,將會造成許多問題而且很難除錯。

+ +

一開始JavaScript是沒有常數的,直到今日我們才有了關鍵字 const,讓我們儲存不能改變的值:

+ +
const daysInWeek = 7;
+const hoursInDay = 24;
+ +

const works in exactly the same way as let, except that you can't give a const a new value. In the following example, the second line would throw an error:

+ +
const daysInWeek = 7;
+daysInWeek = 8;
+ +

Summary

+ +

By now you should know a reasonable amount about JavaScript variables and how to create them. In the next article, we'll focus on numbers in more detail, looking at how to do basic math in JavaScript.

+ +

{{PreviousMenuNext("Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps/Maths", "Learn/JavaScript/First_steps")}}

+ +

在這個學習模組中

+ + diff --git a/files/zh-tw/learn/javascript/first_steps/what_is_javascript/index.html b/files/zh-tw/learn/javascript/first_steps/what_is_javascript/index.html new file mode 100644 index 0000000000..c610e17dd8 --- /dev/null +++ b/files/zh-tw/learn/javascript/first_steps/what_is_javascript/index.html @@ -0,0 +1,425 @@ +--- +title: JavaScript 是什麼? +slug: Learn/JavaScript/First_steps/What_is_JavaScript +tags: + - API + - JavaScript + - 學習 + - 撰寫程式 + - 新手 + - 核心觀念 + - 瀏覽器 + - 註解 +translation_of: Learn/JavaScript/First_steps/What_is_JavaScript +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps")}}
+ +

歡迎來到 MDN 的 JavaScript 初學者課程!我們將在這個章節綜觀 JavaScript ,回答一些像是「它什麼?」和「可以使用它作什麼?」之的問題,並確保你了解 JavaScript 的特性。

+ + + + + + + + + + + + +
先備條件:基本的電腦知識,基本了解 HTML 和 CSS 技術。
學習目標:了解 JavaScript 的本質、功能、以及它如何構成網站的一部分
+ +

高層次的定義

+ +

JavaScript 是一種腳本,也能稱它為程式語言,可以讓你在網頁中實現出複雜的功能。當網頁不只呈現靜態的內容,另外提供了像是:內容即時更新、地圖交動、繪製 2D/3D 圖形,影片播放控制……等,你就可以大膽地認為 JavaScript 已經參與其中。它是標準網頁技術蛋糕的第三層,而其他兩層(HTML 和 CSS)我們在其他學習單元中有更多詳細的介紹。

+ +

+ + + +

這三層很好的構建在一起。讓我們以一個簡單的文字為例。我們可以使用 HTML 標記來表示它的結構和意圖:

+ +
<p>Player 1: Chris</p>
+ +

+ +

然後我們可以加一些 CSS ,讓它看起來更好:

+ +
p {
+  font-family: 'helvetica neue', helvetica, sans-serif;
+  letter-spacing: 1px;
+  text-transform: uppercase;
+  text-align: center;
+  border: 2px solid rgba(0,0,200,0.6);
+  background: rgba(0,0,200,0.3);
+  color: rgba(0,0,200,0.6);
+  box-shadow: 1px 1px 2px rgba(0,0,200,0.4);
+  border-radius: 10px;
+  padding: 3px 10px;
+  display: inline-block;
+  cursor:pointer;
+}
+ +

+ +

最後,我們可以加一些  JavaScript 來作出互動的行為:

+ +
const para = document.querySelector('p');
+
+para.addEventListener('click', updateName);
+
+function updateName() {
+  let name = prompt('輸入新的名字');
+  para.textContent = 'Player 1: ' + name;
+}
+
+ +

{{ EmbedLiveSample('高層次的定義', '100%', 80, "", "", "hide-codepen-jsfiddle") }}

+ +

試試點擊這最後版本的文字,看看會發生什麼事情(你同樣也可以在 GitHub 找到這個範例,來查看原始碼在線上執行)!

+ +

JavaScript 能做到更多,讓我們更深入地探索。

+ +

它究竟可以做什麼呢?

+ +

JavaScript 語言的核心包含了很多常用的程式功能供你使用,如:

+ + + +

然而,更令人興奮的是那些基於用戶端的 JavaScript 語言構建的功能。也就是所謂的 應用程式介面API),提供 JavaScript 程式額外的超能力。

+ +

API 是預先製作完成的程式模組,支援開發者實現困難或無法實現的功能。在程式設計中就如同在建築房子的時候使用系統傢俱,拿預先裁好的板子用螺絲鎖上來組合成書架,相比從頭自己設計,找合適木材,切成正確的形狀和尺寸,再找到合適的螺絲最後組裝書架而言更簡單。

+ +

他們通常分為兩類。

+ +

+ +

瀏覽器 API(Browser APIs)內建在你的瀏覽器中,能夠依本地的電腦環境輸出資料或實現複雜的功能。舉例而言:

+ + + +
+

注意:上面的許多範例無法在舊版的瀏覽器上運作。使用現代的瀏覽器像是 Firefox、Chrome、Edge 或 Opera 來嘗試執行你的程式總是比較好的。當你接近要交付作為產品的程式(也就是實際的用戶將要使用的時候),就需要思考關於跨瀏覽器測試的事情。

+
+ +

第三方 API 預設不內建在瀏覽器裡,你通常由網路上取得他們的程式碼與資訊。例如:

+ + + +
+

注意: 我們不會在此涵蓋這些進階的APIs。你可以在我們的 客戶端網頁 API 單元找到更多資訊。

+
+ +

那裡也有很多的東西。然而不要一頭熱陷進去。你不會在學習 JavaScript 24 小時後,就能開發出下一個 Facebook、Google 地圖或 Instagram 之類的產品出來。有許多的基礎的東西得先了解,這也是你在這裡的原因,讓我們繼續吧!

+ +

JavaScript 在你的頁面做了些什麼?

+ +

這裡我們開始看一些程式碼,探索當 JavaScript 在你的頁面上執行時,發生了哪些事情。

+ +

簡單回顧一下當瀏覽器載入一個網站時會發生的事情(第一次是在我們的CSS 如何工作章節中提到)。當瀏覽器載入一個網頁,就是在執行環境(瀏覽器分頁)中執行程式碼(HTML,CSS 和 JavaScript)。就像是工廠收集原料(程式碼)並且產出商品(網頁呈現的結果)。

+ +

+ +

透過 DOM API (上面提到的)動態調整 HTML 與 CSS 進行改變網頁呈現,在 JavaScript 是很常見的使用方式。要注意的是,檔案中的程式碼通常會以出現在頁面上的順序來執行。如果 JavaScript 比準備操作的 HTML 、 CSS 更早被載入,就可能會發生錯誤。你將會在這個章節的後段學到一些解決問題的方法,它在腳本載入策略的部分。

+ +

瀏覽器安全性

+ +

瀏覽器的每個分頁有獨立的空間來執行程式碼(技術上稱「執行環境excution environments」),這表示在絕大部分的情形之下,每個分頁的程式碼是獨立運行的,不能直接影響其它分頁(或網站)裡的程式。這是一個好的安全措施,少了它,有心人會開始寫程式來偷取網站的資料,或是作其它不好的事情。

+ +
+

注意:是有一些安全的方式能在不同的網頁、分頁之間傳遞程式和資料,不過這些進階的技術不會在涵蓋在這個單元中。

+
+ +

JavaScript 的執行順序

+ +

當瀏覽器遇到一段 JavaScript 程式碼,通常會由上到下執行。這意味著你需要注意東西擺放的順序。為了說明,讓我們回到我們曾看過的第一個範例:

+ +
const para = document.querySelector('p');
+
+para.addEventListener('click', updateName);
+
+function updateName() {
+  let name = prompt('輸入新的名字');
+  para.textContent = 'Player 1: ' + name;
+}
+ +

這裡我們選擇了一個文字段落(第 1 行),然後加上事件偵聽器,所以當段落被點擊的時候,updateName() 程式區塊(5 到 8 行 )會被執行。updateName() 程式區塊(這種可以重複使用的程式區塊被稱為「函數 function」)會向使用者要一個新的名字,然後將插到段落中,更新顯示的內容。

+ +

如果你交換前兩行的程式碼,它將不再正常運作。取而代之的,瀏覽器開發主控台會回報一個錯誤訊息:「TypeError: para is undefined」,意思是 para 物件尚不存在,所以我們在它上頭增加事件偵聽器。

+ +
+

注意: 這是一個很常見的錯誤,在你嘗試對物件進行操作之前,你需要注意它們已經存在。

+
+ +

直譯式與編譯式程式語言

+ +

你可能在程式相關的文章中看過直譯式 (interpreted )與編譯式 (compiled)這兩個詞。在直譯式程式語言中,程式碼由上到下執行,而且執行的結果是立即回應得到的。在瀏覽器執行前,你不需要將程式轉換為其它的形式。程式碼的內容是以對程式人員友善的形式並直接能夠運作。

+ +

另一方面,編譯式程式語言需要在電腦執行之前轉換(編譯)成另一種形式。例如: C/C++ 在被電腦執行之前要編譯為組合語言。被執行的程式是一種二進位的格式,由程式原始碼產生出來。

+ +

JavaScript 是一個輕量的直接程式語言。網頁瀏覽器收到文字格式的 JavaScript 程式碼,並直接執行。以技術的角度來看,大多數現代的 JavaScript 直譯器實際上會使用一種稱為即時編譯(just-in-time compiling)的技術來提升執行表現。 JavaScript 被使用時,原始程式會被編譯成更快的二進位格式,讓它們能更有效率的運行。然而, JavaScript 仍然被認為是一種直譯式的程式語言,因為編譯動作是在程式運作時,而不是事先完成。

+ +

兩種語言都有各自的優點,但是我們不在此時討論這個議題。

+ +

伺服器端與用戶端程式

+ +

你也有可能聽過伺服器端客戶端程式,尤其在網站開發的領域。客戶端程式在使用者的電腦中運作,當瀏覽網頁的時候,頁面中的客戶端程式被下載,接著被瀏覽器執行與顯示結果。在這個單元中,我們只談論客戶端 JavaScript

+ +

另一方面,伺服器端的程式在伺服器上執行,接著產出的結果被瀏覽器下載後顯示。受歡迎的伺服器端網頁語言,包括 PHP、Python、Ruby 和 ASP.NET 以及… JavaScript!JavaScript 也能夠作為伺服器端程式語言,流行的 Node.js 環境就是一例。你可以在我們的動態網站—伺服器端網站程式設計主題中找到更多資訊。

+ +

動態與靜態程式

+ +

動態一詞被用於描述用戶端 JavaScript 和伺服器端程的式語言,用來描述具有在不同的狀況下更新網頁/網頁應用程式來顯示不同東西,依需要來產生新內容的能力。是根據要求生成新內容的能力。伺服器端程式在伺服器上動態產生的新內容,可能是來自資料庫中取出的數據,而用戶端 JavaScript 在收到由伺服器端要回來的資料,在瀏覽器內動態產生新的內容(如 HTML 表格)後加入頁面中呈現出來。在兩個情境中詞義稍微不同,但是相關的,兩種方法(伺服器端和用戶端)通常可以協同工作。

+ +

一個沒有動態更新內容能力的網頁被稱為靜態,它在任何時候都只顯示一樣的內容。

+ +

如何在網頁中增加 JavaScript ?

+ +

在 HTML 頁面中使用 JavaScript 與 CSS 的方法類似。在 HTML 中 CSS 藉著{{htmlelement("link")}} 元素引入外部樣式(stylesheets)以及 {{htmlelement("style")}} 元素定義內部樣式。JavaScript 在 HTML中只需要一個朋友 — {{htmlelement("script")}} 元素。讓我們了解它是如何運作。

+ +

內部的 JavaScript

+ +
    +
  1. 首先,下載一份 apply-javascript.html 範例儲存在自己的電腦上合適的目錄裡。
  2. +
  3. 用瀏覽器與文字編輯器打開範例。你會看到 HTML 建立了一個簡單的網頁,包含一個可點擊的按鈕。
  4. +
  5. 接著,切換到文字編輯器,在標頭區加入下面的文字,就放在 </head> 結尾標籤前: +
    <script>
    +
    +  // JavaScript 將放在這裡
    +
    +</script>
    +
  6. +
  7. 現在,我們將在我們的 {{htmlelement("script")}} 元素中加入一些 JavaScript 程式,讓網頁能做些有趣的事,接者在「// JavaScript 將放在這裡」那行後面: +
    document.addEventListener("DOMContentLoaded", function() {
    +  function createParagraph() {
    +    let para = document.createElement('p');
    +    para.textContent = 'You clicked the button!';
    +    document.body.appendChild(para);
    +  }
    +
    +  const buttons = document.querySelectorAll('button');
    +
    +  for(let i = 0; i < buttons.length ; i++) {
    +    buttons[i].addEventListener('click', createParagraph);
    +  }
    +});
    +
  8. +
  9. 儲存你的檔案並且重新整理網頁,現在你會發現每次點擊按鈕,都會在下方產生一個新的文字段落。
  10. +
+ +
+

注意: 如果你的版本不能正常運作,重新按照步驟再操作一次,檢查每一步都正確。你下載的範例是 .html 結尾的檔名?你加入的 {{htmlelement("script")}} 元素在 </head> 標籤的前面?你輸入的 JavaScript 與上面提供的一模一樣? JavaScript 程式大小寫,而且很挑剔,所以你輸入的語法要一模一樣,不然可能會無法運作。

+
+ +
+

注意: GitHub上有完整版本的範例在 apply-javascript-internal.html看線上版本)。

+
+ +

外部的 JavaScript

+ +

內部 JavaScript 目前運作得很好,但如果我們想把 JavaScript 放在外部檔案,應該怎麼做?讓我們現在來探索。

+ +
    +
  1. 首先,建立一個新的檔案,和 HTML 檔案放在相同的目錄下,命名為 script.js ,確定這個檔案是以 .js 為副檔名, 因為這就是它被識別為 JavaScript 的原因。
  2. +
  3. 將 {{htmlelement("script")}} 元素(包含裡面的程式)換成下面的樣子: +
    <script src="script.js" async></script>
    +
  4. +
  5. script.js 中,加入下面的程式碼: +
    function createParagraph() {
    +  let para = document.createElement('p');
    +  para.textContent = 'You clicked the button!';
    +  document.body.appendChild(para);
    +}
    +
    +const buttons = document.querySelectorAll('button');
    +
    +for(let i = 0; i < buttons.length ; i++) {
    +  buttons[i].addEventListener('click', createParagraph);
    +}
    +
  6. +
  7. 儲存檔案並在你的瀏覽器執行重新整理,你應該會看到一樣的結果!雖然是一樣的結果,但現在我們是由外部的檔案來引入 JavaScript 程式。就組織程式碼,讓程式可以在多個 HTML 間重複被使用而言,這通常是好的作法。另外,因為少了一大堆程式碼在裡頭,也能夠讓 HTML 檔案更容易被閱讀。
  8. +
+ +
+

注意: 你可以在 GitHub 上找到這個版本的 apply-javascript-external.htmlscript.js看線上版本)。

+
+ +

行內的 JavaScript

+ +

注意,有時候你會遇到一些 JavaScript 程式混在HTML語法之中。它可能會看起來像這樣:

+ +
function createParagraph() {
+  var para = document.createElement('p');
+  para.textContent = 'You clicked the button!';
+  document.body.appendChild(para);
+}
+ +
<button onclick="createParagraph()">Click me!</button>
+ +

你可以在底下試試這個段程式的作用。

+ +

{{ EmbedLiveSample('行內的_JavaScript', '100%', 150, "", "", "hide-codepen-jsfiddle") }}

+ +

這個範例與前面兩個有完全相同的功能,除了 {{htmlelement("button")}} 元素中包含了一個行內 onclick 處理程序,當按鈕按下時執行。

+ +

然而,請不要這樣做。用 JavaScript 汙染你的 HTML 是一種不好的作法,而且沒有效率,因為你必須在每個你希望 JavaScript 作用的地方加入 onclick="createParagraph()" 屬性。

+ +

使用單純 JavaScript 的結構,讓你可以用一個指令選擇所有的按鈕。在我們前面的範例中,使用下面的程式碼達到這個目的:

+ +
var buttons = document.querySelectorAll('button');
+
+for (var i = 0; i < buttons.length ; i++) {
+  buttons[i].addEventListener('click', createParagraph);
+}
+ +

這或許看起來比 onclick 屬性還長一點,但是能套用在全部的按鈕上,無論頁面上有多少按鈕,也不管未來新增或移除多少個(按鈕)。這段 JavaScript 程式都不需要改變。

+ +
+

注意: 試著編輯你自己版本的 apply-javascript.html ,在裡面多添加一點按鈕。當你重新載入網頁,你應該會發現所有按鈕,按下去的時候都會建立一的段落。很簡潔吧!

+
+ +

腳本載入策略(Script loading strategies)

+ +

在正確的時機載入腳本涉及一些要注意的東西。並不如它看起來的簡單!其中一個常見的問題是,所有的 HTML 是根據出現順序載入。假如你使用 JavaScript 操作頁面中的元素(精確地來說是 DOM 元素),如果 JavaScript 在這些 HTML 操作對象前被讀取及解析,你的程式將無法運作。

+ +

上面的範例中,內部和外部 JavaScript 範例裡的程式碼都放在 HTML 的 head 區域,在 body 區被載入前就先被解析。這樣會造成一些問題,所以我們載入與執行在文件(HTML檔)的開頭,是HTML body 還沒解析之前。這可能會產生錯誤,所以我們使用一些模式來處理它。

+ +

在內部程式的範例中,你可以看到以下這樣結構的程式碼:

+ +
document.addEventListener("DOMContentLoaded", function() {
+  ...
+});
+ +

這是一個事件偵聽器,它偵聽瀏覽器的「DOMContentLoaded」事件,它是在 HTML body 部分已經完全載入與解析發出。區塊內(... 的部分)的 JavaScript 直到事件被發出後才會執行,這樣子問題就被避開了。(你將會在這個課程中學習到什麼是事件

+ +

在外部程式的範例中,我們使用比較現代的 JavaScript 特性來解決這個問題,defer 屬性,它告訴瀏覽器碰到這種 <script> 標籤時,繼續下載後面其他的 HTML 內容。

+ +
<script src="script.js" defer></script>
+ +

在這個例子中,腳本(JavaScript 程式)與 HTML 會同時載入,所以程式將正確地執行。

+ +
+

注意: 在外部程式的範例裡,我們不需要使用 DOMContentLoaded 事件因為 defer 為我們解決問題了。而在內部程式的範例裡我們沒用 defer 屬性,是因為 defer 屬性只能用於外部的腳本。

+
+ +

這個問題有另一個舊式的解決方法,就是將 script 元素放在 body 元素的底部(剛好在 </body> 的前面),如此它就會在所有 HTML 被解析完之後才被載入。這個方法的問題在於腳本的載入與解析工作會被完成擋住,一直到所有 HTML 載入完成。在擁有許多 JavaScript 的大型網站中,這樣會導致嚴重的效能問題,拖慢你的網站。

+ +

async 和 defer

+ +

實際上,有兩個方法可以閃過上述腳本被擋到的問題:asyncdefer(前面看到的)。來看看兩者的區別。

+ +

使用 async 屬性(如下所示)所載入的腳本,在下載的同時不會讓網頁的渲染被阻塞(停住),並且在下載完成後馬上執行。它並不保證腳本會按照任何特定的順序執行,只保證不去妨礙網頁中其他部分顯示工作。async 的最佳使用情境,是當網頁中的腳本間彼此獨立,因而不依賴彼此運行的狀況下。

+ +

例如你有以下的 script 元素

+ +
<script async src="js/vendor/jquery.js"></script>
+
+<script async src="js/script2.js"></script>
+
+<script async src="js/script3.js"></script>
+ +

你不能將元素的順序視為腳本載入順序。 jquery.js 可能會在 script2.jsscript3.js 的之前或之後載入,在這個情況下,在腳本中依賴 jquery 的函數將會發生錯誤,因為被執行到的時候 jquery 還沒被定義(載入且解析完畢)。

+ +

當有許多非立即要使用的腳本,而你只希望它們能盡快被載入完畢,就應該使用 async 。例如:你有一些遊戲內容的檔案需要載入,它將在遊戲開始後被用到。但是現在你只是需要顯示遊戲介紹、一些選單以及遊戲大廳,不希望等到所有內容都下載完成之後才顯示。

+ +

使用 defer 屬性(如下所示)所載入的腳本,會在腳本與內容都下載完成後,依照出現順序被執行。

+ +
<script defer src="js/vendor/jquery.js"></script>
+
+<script defer src="js/script2.js"></script>
+
+<script defer src="js/script3.js"></script>
+ +

全部具有 defer 屬性的腳本會依據出現的順序載入。因此在第二個範例中,我們可以肯定 jquery.js 會在 script2.jsscript3.js 之前被載入, script2.js 會在 script3.js 之前載入。在網頁的所有內容被載入完成之前,它是不會被執行的。當你的程式依賴著某些元素存在時(如:要調整頁面上一到多個元素),這個屬性很有用。

+ +

總結一下:

+ + + +

註解

+ +

如同 HTML 和 CSS,在 JavaScript 的程式碼中也可以撰寫註解,它會被瀏覽器忽略,僅用來提供你的開發伙伴,說明程式是如何運作(或是自己,當六個月後回來看程式碼,忘記曾經做過了什麼)。註解非常有用,你應該常常使用它,尤其是在大型應用程式裡。註解有兩種形式:

+ + + +

舉例來說,我們可以在前面範例的 JavaScript 裡加入註解,像是:

+ +
// 函數:建立一個段落元素並加到 HTML body 的尾端
+
+function createParagraph() {
+  var para = document.createElement('p');
+  para.textContent = 'You clicked the button!';
+  document.body.appendChild(para);
+}
+
+/*
+  1. 找出頁面上所有按鈕,並把它們放到陣列中
+  2. 使用迴圈,對每個按鈕偵聽 click 事件
+
+  當任何按鈕被按下,執行 createParagraph() 函數
+*/
+
+var buttons = document.querySelectorAll('button');
+
+for (var i = 0; i < buttons.length ; i++) {
+  buttons[i].addEventListener('click', createParagraph);
+}
+ +
+

注意:一般而言,多寫註解比少寫來得好。但是要注意,如果你發現加了許多註解在說明變數的用途(那麼你的變數命名可能需要更直觀,更帶有意義),或是解釋非常簡單的操作(也許你的程式碼太過於複雜)。

+
+ +

總結

+ +

所以你已經踏出在 JavaScript 世界中的第一步。我們從理論開始,逐漸熟悉使用 JavaScript 的原因,以及你可以用它做些什麼。過程中你看到了一些程式碼範例,學到如何將 JavaScript 與你網站的其它東西放在一起。

+ +

JavaScript 目前可能看起來有一點嚇人,然而不用擔心,在本課程我們會透過簡單的步驟,帶著你建立觀念並繼續向前。 在下一章節,我們將會投入更實用的知識,帶你直接入門並建立你自己的 JavaScript 作品。

+ +

在這個學習模組中

+ + + +

{{NextMenu("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps")}}

diff --git a/files/zh-tw/learn/javascript/first_steps/what_went_wrong/index.html b/files/zh-tw/learn/javascript/first_steps/what_went_wrong/index.html new file mode 100644 index 0000000000..5eec96717b --- /dev/null +++ b/files/zh-tw/learn/javascript/first_steps/what_went_wrong/index.html @@ -0,0 +1,253 @@ +--- +title: 出了什麼問題?JavaScript 疑難排解 +slug: Learn/JavaScript/First_steps/What_went_wrong +translation_of: Learn/JavaScript/First_steps/What_went_wrong +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps")}}
+ +

當你在練習撰寫上一節的"猜數字"遊戲時,你可能會發現它無法運作。不用擔心,本文將會把你從快被拔光的頭髮中拯救出來,並且給你一些小提示,讓你知道怎麼找出及修正 Javascript 的程式運行錯誤。

+ + + + + + + + + + + + +
先備:基本電腦能力,基本html及css理解以及了解JavaScript是什麼
目標:獲得開始解決簡單編碼問題的能力及信心
+ +

錯誤類型

+ +

一般來說,當你的編碼有錯誤時,主要有兩種類型

+ + + +

好的,但事情並沒有那麼單純——當你越深入,就會發現更多不同的因素。但上述的分類已經足夠應付初期的工程師職涯了。接著,我們將更深入來討論這兩個類型。

+ +

一個錯誤範例

+ +

讓我們從剛剛的猜數字遊戲開始 — 在這個版本中,我們將故意引入一些錯誤以便從中學習。前往 Github 下載一份 number-game-errors.html (或運行線上版 running live here).

+ +
    +
  1. 首先,在編輯器與瀏覽器分別開啟你剛下載檔案。
  2. +
  3. 試著玩遊戲——你會注意到當你按下按鈕「Submit guess」時,它沒有任何反應!
  4. +
+ +
+

Note: 你也許是想修復你自己寫的遊戲中的錯誤!這是件好事,但我們還是建議你在學習這篇文章時先使用我們的版本,這樣你才可以學到我們接下來要教的技巧。在這之後再回去修正你自己的遊戲也不遲!

+
+ +

現在,先讓我們來看看開發者主控台有沒有提示我們任何錯誤,然後試著修正他們。你會在接下來的段落中學到如何修正這些錯誤。

+ +

修復語法錯誤

+ +

在前篇文章中我們讓你在 開發者工具 JavaScript console 中輸入了一些JavaScript 指令(如果你不記得怎麼打開這個東西,點選前面的連結複習一下)。更重要的是,主控台在瀏覽器的 JavaScript引擎讀取到有語法錯誤的 JavaScript 時會提示一些錯誤訊息。現在讓我們來看看:

+ +
    +
  1. 切換到你開啟了 number-game-errors.html 的分頁,然後打開你的 JavaScript 主控台。你應該會看到如下的幾行錯誤訊息:
  2. +
  3. 這是一個非常容易追尋的錯誤,而且瀏覽器還給你了不少有用的資訊來幫助你(這張截圖是 Firefox 的,但其他瀏覽器也會提示相似的錯誤訊息)。從左到右,我們可以看到: +
      +
    • 一個紅色的 "X" 代表這是一個錯誤訊息。
    • +
    • 一條錯誤訊息提示你什麼東西出錯了:"TypeError: guessSubmit.addeventListener is not a function(TypeError: guessSubmit.addeventListener 並不是一個函式)"
    • +
    • 一個 "Learn More" 連結連向一個解釋這個錯誤並包含大量詳細資訊的 MDN 頁面。
    • +
    • 出錯的 JavaScript 檔案名稱,連結連向開發者工具的除錯器。點下這個連結,你就能看到出錯的那行程式被高亮顯示出來。
    • +
    • 在該 JavaScript 檔案中錯誤的行號,還有錯誤發生在該行第幾個字元。在這個例子中,是第 86 行的第 3 個字元。
    • +
    +
  4. +
  5. 如果我們在編輯器中檢視第 86 行,我們會看到: +
    guessSubmit.addeventListener('click', checkGuess);
    +
  6. +
  7. 主控台提示的錯誤訊息寫著 "guessSubmit.addeventListener is not a function(guessSubmit.addeventListener 並不是一個函式)",所以我們大概是哪裡拼錯字了。如果你並不確定一個函式的正確名稱如何拼寫,打開 MDN 確認看看是個不錯的選擇。最佳做法是在你喜歡的搜尋引擎搜尋 "mdn 關鍵字"。為了節省時間,這裡提供你一個捷徑:addEventListener()
  8. +
  9. 回來看看這個頁面,我們明顯是把函式名稱給拼錯了!記住,JavaScript 是會區分大小寫的,所以任何些微的拼寫錯誤甚至是大小寫錯誤都會造成錯誤發生。把addeventListener 改成addEventListener 問題就解決了。現在將你的程式碼修正吧。
  10. +
+ +
+

Note: 看看這個 TypeError: "x" is not a function 連結來了解更多有關這類錯誤的資訊。

+
+ +

語法錯誤:第二回合

+ +
    +
  1. 將你的頁面存檔並重整,你現在應該會看到剛剛的錯誤消失了。
  2. +
  3. 現在試著輸入一個猜測並按下 Submit guess 按鈕,你會發現... 另一個錯誤!
  4. +
  5. 這次的錯誤是 "TypeError: lowOrHi is null(TypeError: lowOrHi 為 null)",在第 78 行的位置。 +
    Note: Null 是一個特別的值,代表著「空」、「什麼都沒有」。lowOrHi 被宣告為一個變數,但並沒有被賦予任何有意義的值 — 他既沒有變數型態,也沒有值。
    + +
    Note: 這個錯誤並沒有在頁面載入完成後就發生,因為這個錯誤發生在一個函式中(在 checkGuess() { ... } 區塊中)。在之後詳細介紹函式的文章中,你會學到在函式中的程式碼與在函式外的程式碼其實是執行在不同範疇中的。在我們的這個情況裡,有錯誤的程式碼在 checkGuess() 在 86 行被執行前都並沒有執行,也因此錯誤並沒有在頁面一載入就發生。
    +
  6. +
  7. 看看第 78 行,你會看到: +
    lowOrHi.textContent = 'Last guess was too high!';
    +
  8. +
  9. 這行試著將 lowOrHi 的 textContent 屬性設為一個字串。但是這行沒有執行成功,因為 lowOrHi 並沒有存著它應該要存著的值。讓我們來看看為什麼 — 試試在程式碼中搜尋其他 lowOrHi 有出現的地方。在第 48 行你會看到: +
    var lowOrHi = document.querySelector('lowOrHi');
    +
  10. +
  11. 這行程式碼試著將一個 HTML 元素的參照存起來。讓我們檢查一下在這行程式碼執行後,變數中的值是否為 null。在第 49 行加上: +
    console.log(lowOrHi);
    + +
    +

    Note: console.log() 是一個非常好用的除錯功能,它能夠將值印出至主控台中。所以這行程式碼會在第 48 行賦值給 lowOrHi 後,將它的值印出至主控台中。

    +
    +
  12. +
  13. 存檔並重整,你應該會在主控台中看到 console.log() 輸出的結果。在這個時間點,lowOrHi 的值是 null。所以很明顯的,第 48 行一定出了什麼問題。
  14. +
  15. 讓我們思考一下發生了什麼問題。第 48 行呼叫了 document.querySelector() 方法來透過 CSS 選擇器取得一個 HTML 元素參照。打開我們的網頁看看我們想要取得的段落元素: +
    <p class="lowOrHi"></p>
    +
  16. +
  17. 所以我們需要的是一個開頭是小數點 (.) 的 class 選擇器,但傳進第48 行 querySelector() 方法的選擇器並沒有開頭的小數點。這也許就是問題所在了!試著將第 48 行的 lowOrHi 改成 .lowOrHi
  18. +
  19. 再次存檔並重整,你的 console.log() 現在應該會輸出我們想要的 <p> 元素了。呼!又修好了另一個錯誤!你現在可以把你的 console.log() 那行移除了,或是你想要留著之後查看 — 取決於你。
  20. +
+ +
+

Note: 看看這個 TypeError: "x" is (not) "y" 連結來了解更多有關這類錯誤的資訊。

+
+ +

語法錯誤:第三回合

+ +
    +
  1. 現在如果你試著再次玩這個遊戲應該會相當順利,直到該讓遊戲結束的時機點才會發生錯誤:無論是猜對還是10次用完。
  2. +
  3. 此時console提供錯誤訊息跟一開始一樣: "TypeError: resetButton.addeventListener is not a function"! 然而此次錯誤來自第94行。查看第94行後,我們可以輕易發現依舊是屬性大小寫問題,一樣把addeventListener 改成 .addEventListener就沒問題了。
  4. +
+ +

邏輯錯誤

+ +

到這邊為止遊戲應該可以進行得很順利,然而玩幾次下來無疑地你會發現「隨機」數字總是0或1,這可不是我們想要的!

+ +
    +
  1. 搜尋位於44行的變數randomNumber,其內容是設定遊戲一開始的隨機數字: + +
    var randomNumber = Math.floor(Math.random()) + 1;
    +
  2. +
  3. 另一個開始新回合時產生隨機數字的變數則在113行左右: +
    randomNumber = Math.floor(Math.random()) + 1;
    +
  4. +
  5. 為了測試問題是否出在這兩段程式碼,我們需要再次邀請console.log() 好朋友,將之分別放到44、113行的程式碼下一行: +
    console.log(randomNumber);
    +
  6. +
  7. 儲存程式碼並更新頁面,然後再試玩幾次,你會看到randomNumber 在console中總是等於1,這就是問題所在。
  8. +
+ +

修正小錯誤

+ +

為了修正這個錯誤,我們得先了解它是怎麼運作的。首先,我們呼叫Math.random()以產生一個介於0到1的隨機小數,例如: 0.5675493843

+ +
Math.random()
+ +

接著,我們將Math.random() 產生的隨機小數傳進Math.floor(),函式會回傳小於等於所給數字的最大整數,然後為這個整數值加1:

+ +
Math.floor(Math.random()) + 1
+ +

由於Math.floor是無條件捨去取整數(地板值),所以一個介於0到1的隨機小數永遠只會得到0,幫這個小數加1的話又會永遠只得到1。所以進位前我們先幫隨機小數乘上100 ,如此一來我們就能得到介於0到99的隨機數字了:

+ +
Math.floor(Math.random()*100);
+ +

別忘了還要加上1,數字範圍才能成功介於1到100:

+ +
Math.floor(Math.random()*100) + 1;
+ +

試著自己動手更新這兩行程式碼吧,儲存並更新頁面後你應該能看到遊戲如預期般進行!

+ +

其他常見錯誤

+ +

還有些初學者非常容易忽略的小問題,這小節讓我們來概覽一下:

+ +

語法錯誤:語句缺少「 ; 」
+ (SyntaxError: missing ; before statement)

+ +

這個錯誤是指每行程式碼結束時必須加上英文輸入法的分號;(請注意不要打成中文輸入法),分號被遺忘的錯誤有時不太容易發現,此外另舉一例:如果我們改動下方變數checkGuess() 中的程式碼:

+ +
var userGuess = Number(guessField.value);
+ +

改成

+ +
var userGuess === Number(guessField.value);
+ +

此時程式碼會回報錯誤,因為瀏覽器會認為你想設定不同的東西;我們需要確保自己沒有誤用、混用指派運算子(=):用於賦予變數值跟嚴格比較運算子(===):用於比較兩個值是否完全相等,並回覆true/false布林值。

+ +
+

Note: 更多細節請參考右方關於缺少分號的語法錯誤文章頁面: SyntaxError: missing ; before statement 。

+
+ +

無論輸入什麼,程序總是顯示「你贏了」

+ +

還有另一種混用指派運算子(=)與嚴格比較運算子(===)的狀況,舉例如果我們將變數 checkGuess()中的嚴格比較運算子(===)

+ +
if (userGuess === randomNumber) {
+ +

改成指派運算子(=)

+ +
if (userGuess = randomNumber) {
+ +

這個檢查就失效了,程式會永遠回傳 true而勝利並結束遊戲。請小心!

+ +

語法錯誤:參數列表後面缺少「)」 
+ (SyntaxError: missing ) after argument list)

+ +

給完函數或方法參數時別忘了放上)右括號(請注意不要打成中文輸入法)。

+ +
+

Note: 更多細節請參考右方關於缺少右括號的語法錯誤文章頁面:SyntaxError: missing ) after argument list 。

+
+ +

語法錯誤:屬性ID後缺少「:」
+ SyntaxError: missing : after property id

+ +

This error usually relates to an incorrectly formed JavaScript object, but in this case we managed to get it by changing

+ +
function checkGuess() {
+ +

to

+ +
function checkGuess( {
+ +

This has caused the browser to think that we are trying to pass the contents of the function into the function as an argument. Be careful with those parentheses!

+ +

語法錯誤:「}」缺少SyntaxError: missing } after function body

+ +

This is easy — it generally means that you've missed one of your curly braces from a function or conditional structure. We got this error by deleting one of the closing curly braces near the bottom of the checkGuess() function.

+ +

SyntaxError: expected expression, got 'string' or SyntaxError: unterminated string literal

+ +

These errors generally mean that you've missed off a string value's opening or closing quote mark. In the first error above, string would be replaced with the unexpected character(s) that the browser found instead of a quote mark at the start of a string. The second error means that the string has not been ended with a quote mark.

+ +

For all of these errors, think about how we tackled the examples we looked at in the walkthrough. When an error arises, look at the line number you are given, go to that line and see if you can spot what's wrong. Bear in mind that the error is not necessarily going to be on that line, and also that the error might not be caused by the exact same problem we cited above!

+ +
+

Note: See our SyntaxError: Unexpected token and SyntaxError: unterminated string literal reference pages for more details about these errors.

+
+ +

小結

+ +

So there we have it, the basics of figuring out errors in simple JavaScript programs. It won't always be that simple to work out what's wrong in your code, but at least this will save you a few hours of sleep and allow you to progress a bit faster when things don't turn out right earlier on in your learning journey.

+ +

See also

+ +
+ +
+ +

{{PreviousMenuNext("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps")}}

+ +

在這個學習模組中

+ + diff --git a/files/zh-tw/learn/javascript/howto/index.html b/files/zh-tw/learn/javascript/howto/index.html new file mode 100644 index 0000000000..5e5f7257c2 --- /dev/null +++ b/files/zh-tw/learn/javascript/howto/index.html @@ -0,0 +1,294 @@ +--- +title: JavaScript 解決常見的問題 +slug: Learn/JavaScript/Howto +translation_of: Learn/JavaScript/Howto +--- +
{{LearnSidebar}}
+以下鏈接針對您需要修復的常見問題的解決方案,以便讓您的JavaScript語法正確執行。
+ +

初學者常見的錯誤

+ +

糾正語法和代碼

+ +


+  

+ +

如果您的代碼毫無反映或瀏覽器反饋某些內容「未定義」,請檢查您是否「正確輸入」所有變量名稱,函數名稱等。

+ +

以下的常見造成問題的內置瀏覽器功能比對:

+ +

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
正確 錯誤 
getElementsByTagName()getElementbyTagName()
getElementsByName()getElementByName()
getElementsByClassName()getElementByClassName()
getElementById()getElementsById()
+ +

分號位置

+ +

You need to make sure you don't place any semi-colons incorrectly. For example:

+ + + + + + + + + + + + +
CorrectWrong
elem.style.color = 'red';elem.style.color = 'red;'
+ +

功能內容

+ +

There are a number of things that can go wrong with functions.

+ +

One of the most common errors is to declare the function, but not call it anywhere. For example:

+ +
function myFunction() {
+  alert('This is my function.');
+};
+ +

This code won't do anything unless you call it, for example with

+ +
myFunction();
+ +

功能範圍

+ +

Remember that functions have their own scope — you can't access a variable value set inside a function from outside the function, unless you declared the variable globally (i.e. not inside any functions), or return the value out of the function.

+ +

在return語句後執行語法

+ +

Remember also that when you return a value out of a function, the JavaScript interpreter exits the function — no code declared after the return statement will run.

+ +

In fact, some browsers (like Firefox) will give you an error message in the developer console if you have code after a return statement. Firefox gives you "unreachable code after return statement".

+ +

對象表示法與正確的指派

+ +

When you assign something normally in JavaScript, you use a single equals sign, e.g.:

+ +
const myNumber = 0;
+ +

This doesn't work in Objects, however — with objects you need to separate member names from their values using colons, and separate each member with a comma, for example:

+ +
const myObject = {
+  name: 'Chris',
+  age: 38
+}
+ +

基本定義

+ +
+ + + +
+ +

基本使用例子

+ +
+ + +
+

序列

+ + + +

Debugging JavaScript

+ + + +

For more information on JavaScript debugging, see Handling common JavaScript problems; also see Other common errors for a description of common errors.

+ +

Making decisions in code

+ + + +

Looping/iteration

+ + +
+
+ +

進階使用例子

+ +
+ + + +
diff --git a/files/zh-tw/learn/javascript/index.html b/files/zh-tw/learn/javascript/index.html new file mode 100644 index 0000000000..17fed115be --- /dev/null +++ b/files/zh-tw/learn/javascript/index.html @@ -0,0 +1,71 @@ +--- +title: JavaScript — 動態的客戶端指令 +slug: Learn/JavaScript +tags: + - Beginner + - CodingScripting + - JavaScript + - Landing + - NeedsTranslation + - Topic + - TopicStub + - 初學者 +translation_of: Learn/JavaScript +--- +
{{LearnSidebar}}
+ +

{{Glossary("JavaScript")}} 程式語言可讓你在網頁上建構複雜的事物。當網頁不僅僅呆板呈現給你靜態的內容(像是即時的內容更新,互動式地圖、2D/3D 動畫、滑鼠操控影片播放…等等),你可以大膽猜測 JavaScript 已經參與其中。

+ +

學習途徑

+ +

JavaScript 相較於 HTML 和 CSS 這些技術可以說比較困難。開始嘗試學習 JavaScript 之前,強烈建議你起碼先熟悉上述兩項技術,或者了解其它的更好。可以透過以下單元開始:

+ + + +

若你之前有其他程式語言的撰寫經驗,也許會有幫助。

+ +

當熟悉 JavaScript 的基本知識之後,你應該進入一些更進階的主題,像是:

+ + + +

單元

+ +

本主題涵蓋許多單元,建議你依下列順序閱讀。

+ +
+
JavaScript 初探
+
在我們的第一個 JavaScript 單元,在帶你初次實際撰寫 JavaScript 程式之前,我們先回答幾個基本的問題,像是「什麼是 JavaScript?」、「它看起來是什麼樣子?」、「它能做些什麼?」。接著,我們深入地討論幾個 JavaScript 關鍵的組成元素,例如:變數、字串、數字、陣列。
+
JavaScript 構成元素
+
在這個單元,我們繼續含蓋 JavaScript 關鍵的基本元素,把焦點放在常見程式碼區塊的類型,像是條件陳述式、迴圈、函數以及事件。你已經在這個課程中看過這些東西,但只是匆匆一瞥,在這裡我們會明確地討論。
+
JavaScript 物件介紹
+
在 JavaScript 程式語言,絕大部分的東西都是物件,從核心的 JavaScript 元素像是字串(string)和陣列(array)到基於 JavaScript 建構的瀏覽器 API 都是。你甚至可以建立自己的物件,將相關的變數與函數封裝成能有效率操作的集合體。如果你想更深入了解這門程式語言的知識,並撰寫出更有效率的程式碼,了解 JavaScript 物件導向的本質是重要的,因此我們準備這個單元來幫助你。這裡我們教詳細的物件理論與語法,看看要如何建自你自己的物件,以及說明什麼是 JSON 資料和怎麼使用它。
+
非同步的 JavaScript
+
這個單元我們來討論非同步的 JavaScript,它為什麼重要,以及它能如何有效處理像是由伺服器抓取資料這種阻塞性操作(它會造成網頁停頓)。
+
用戶端的 web API
+
當你走在用 JavaScript 撰寫用戶端程式,來建構網站或應用程式的路上,不利用 API 很難走很遠,介接在操控瀏覽器、作業系統的不同功能,或是接收來自其它網站、服務的資料。在這個單元中,我們將討索什麼是 API ,以及如何使用幾個在你開發過程中,十分頻繁被使用到的 API 。
+
+

解決常見的 JavaScript 問題

+ +

在你寫網頁時,可參閱〈透過 JavaScript 解決常見的問題〉內所提供的連結,解決許多常見問題。

+
+
+ +

參考資源

+ +
+
JavaScript on MDN
+
MDN 上連結到各篇 JavaScript 核心文件的主要,在這裡你可以找到關於 JavaScript 程式語言各方面廣泛的參考文件,還有一些進階的指引幫助你成為熟練的 JavaScript 使用者。
+
Learn JavaScript
+
對於想成為網站開發者一個很好的資源,以互動的方式學習 JavaScript ,包含短課程、互動測驗,自動評估狀況給予指引。前 40 堂課是免費,完整的課程可以在一次付費買下。
+
JavaScript Fundamentals on EXLskills
+
在免費的 EXLskills 開源課程中,介紹給你所有開始建構 JavaScript 應用程式所需要的東西。
+
Coding math
+
一系列優質的教學影片,教你需要了解哪些數學知識,來讓你成為有效率的程式設計師。(作者:Keith Peters
+
diff --git a/files/zh-tw/learn/javascript/objects/adding_bouncing_balls_features/index.html b/files/zh-tw/learn/javascript/objects/adding_bouncing_balls_features/index.html new file mode 100644 index 0000000000..33cb338c8d --- /dev/null +++ b/files/zh-tw/learn/javascript/objects/adding_bouncing_balls_features/index.html @@ -0,0 +1,184 @@ +--- +title: 為彈跳彩球添增其他功能 +slug: Learn/JavaScript/Objects/Adding_bouncing_balls_features +translation_of: Learn/JavaScript/Objects/Adding_bouncing_balls_features +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}
+ +

在本文中,你將繼續使用前一篇文章的彈跳彩球展示程式,另外加入幾項有趣的新功能。

+ + + + + + + + + + + + +
必備條件:在開始本文所提的實作之前,應先看過先前的相關文章。
要點:測試 JavaScript 物件與 OO 架構的完整性。
+ +

開始

+ +

在開始之前,請先複製先前文章所提供的 index-finished.htmlstyle.cssmain-finished.js 等檔案,儲存於本端磁碟的新資料夾中。

+ +
+

注意:你也可透過如 JSBinThimble 等網站進行此一實作。你可將 HTML、CSS、JavaScript 貼入相關線上編輯器之一。如果你所用的線上編輯器並未提供獨立的 JavaScript/CSS 面板,則可將之放入 HTML 頁面內的行內 <script>/<style> 元素中。

+
+ +

專案簡介

+ +

彈跳彩球很有趣,但接著我們要加入使用者可控制的「邪惡圈」,在碰到彩球之後隨即吃掉彩球,添加更多互動性。也希望透過邪惡圈與彩球所繼承的通用 Shape() 物件,測試你的物件技術。最後還要加上計分功能,顯示尚未吃掉的彩球數量。

+ +

下方擷圖則讓你了解最終成品的樣子:

+ +

+ + + +

可先參考完成範例讓心裡有個底 (別偷看原始碼啊!)

+ +

須進行的步驟

+ +

下列段落將逐步說明。

+ +

建立新物件

+ +

首先將現有的 Ball() 建構子變更為 Shape() 建構子,以及新的 Ball() 建構子:

+ +
    +
  1. Shape() 建構子對 xyvelXvelY 屬性的定義方式,就如同 Ball() 建構子所用的方式。
  2. +
  3. 另須定義新的 exists 屬性,用以追蹤球體是否存在於程式之中 (也就是尚未遭邪惡圈所吃掉)。此屬性必為布林值 (Boolean),初始值為 true
  4. +
  5. Ball() 建構子應從 Shape() 建構子繼承 xyvelXvelYexists 等屬性。另必須將這些屬性定義為參數以利呼叫之。
  6. +
  7. 必須定義 colorsize 屬性各 1 組,且由於兩者均來自於原始的 Ball() 建構子之中,所以剛開始的隨機值亦須相同。
  8. +
  9. 記得應正確設定 Ball() 建構子的 prototypeconstructor
  10. +
+ +

彩球的 draw()update()collisionDetect() 函式定義,均與之前完全相同。

+ +

到此為止可重新載入程式碼,搭配重新設計的物件也應該運作無誤。

+ +

定義 EvilCircle()

+ +

再來見見這個壞蛋 — EvilCircle()!這個遊戲要加入 1 個會吃球的邪惡圈,而且要透過繼承自 Shape() 的建構子來定義這個邪惡圈。你可能也想添增另個讓第二個玩家控制的圈圈,或許多加幾個由電腦控制的邪惡圈。當然,光一個邪惡圈並無法統治世界,但可為此遊戲增添不少樂趣。

+ +

EvilCircle() 建構子應繼承 Shape()x、y、exists。

+ +

亦可定義自有的屬性如下:

+ + + +

再次提醒,請記得要將所繼承的屬性在建構子中定義為參數,並應正確設定 prototypeconstructor 屬性。

+ +

定義 EvilCircle() 的函式

+ +

EvilCircle() 應具備 4 個函式,如下:

+ +

draw()

+ +

此函式的功能與 Ball()draw() 函式相同,就是在 canvas 上繪製物件實體;且運作的方式也類似,所以你可以複製 Ball.prototype.draw 定義來開始。接著要完成下列改變:

+ + + +

checkBounds()

+ +

此函式功能就與 Ball()update() 函式第一部分相同,負責邪惡圈是否跳出螢幕邊界之外並適時阻止。同樣的,你還是可以複製 Ball.prototype.update 定義來用,但須更改下列:

+ + + +

setControls()

+ +

This method will add an onkeydown event listener to the window object so that when certain keyboard keys are pressed, we can move the evil circle around. The following code block should be put inside the method definition:

+ +
var _this = this;
+window.onkeydown = function(e) {
+    if(e.keyCode === 65) {
+      _this.x -= _this.velX;
+    } else if(e.keyCode === 68) {
+      _this.x += _this.velX;
+    } else if(e.keyCode === 87) {
+      _this.y -= _this.velY;
+    } else if(e.keyCode === 83) {
+      _this.y += _this.velY;
+    }
+  }
+ +

So when a key is pressed, the event object's keyCode property is consulted to see which key is pressed. If it is one of the four represented by the specified keycodes, then the evil circle will move left/right/up/down.

+ + + +

collisionDetect()

+ +

This method will act in a very similar way to Ball()'s collisionDetect() method, so you can use a copy of that as the basis of this new method. But there are a couple of differences:

+ + + +

Bringing the evil circle into the program

+ +

Now we've defined the evil circle, we need to actually make it appear in our scene. To do this, you need to make some changes to the loop() function.

+ + + +

Implementing the score counter

+ +

To implement the score counter, follow the following steps:

+ +
    +
  1. In your HTML file, add a {{HTMLElement("p")}} element just below the {{HTMLElement("h1")}} element containing the text "Ball count: ".
  2. +
  3. In your CSS file, add the following rule at the bottom: +
    p {
    +  position: absolute;
    +  margin: 0;
    +  top: 35px;
    +  right: 5px;
    +  color: #aaa;
    +}
    +
  4. +
  5. In your JavaScript, make the following updates: +
      +
    • Create a variable that stores a reference to the paragraph.
    • +
    • Keep a count of the number of balls on screen in some way.
    • +
    • Increment the count and display the updated number of balls each time a ball is added to the scene.
    • +
    • Decrement the count and display the updated number of balls each time the evil circle eats a ball (causes it not to exist).
    • +
    +
  6. +
+ +

Hints and tips

+ + + +

交作業

+ +

如果你是在某個課堂上操作這份作業,那麼請將成品交給您的老師 / 助教;如果您是自學者,在我們的專屬討論區Mozilla IRC 上的 #mdn 頻道都可以很輕鬆地找到人給予指教。記得先認真做一下習題,要怎麼收獲先那麼栽呀!

+ +

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}

diff --git a/files/zh-tw/learn/javascript/objects/basics/index.html b/files/zh-tw/learn/javascript/objects/basics/index.html new file mode 100644 index 0000000000..3b70536656 --- /dev/null +++ b/files/zh-tw/learn/javascript/objects/basics/index.html @@ -0,0 +1,243 @@ +--- +title: JavaScript 物件基礎概念 +slug: Learn/JavaScript/Objects/Basics +translation_of: Learn/JavaScript/Objects/Basics +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}
+ +

第一篇談到 JavaScript 物件的文章中,我們了解到基本的 JavaScript 物件語法,複習了某些先前提過的 JavaScript 功能,也再次強調你現正使用中的許多功能其實就是物件。

+ + + + + + + + + + + + +
必要條件:基本的電腦素養、對 HTML 與 CSS 已有初步認識、熟悉 JavaScript 基本概念 (參閱〈First steps〉與〈Building blocks〉)。
主旨:了解「物件導向 (OO)」程式設計背後的基礎理論、其與 JavaScript (多屬於物件) 之間的關係、該如何使用 JavaScript 物件進行開發。
+ +

物件基礎概念

+ +

物件是一批相關的數據以及/或者功能(通常包含了幾個變數及函式 — 當它們包含在物件中時被稱做「屬性」(properties)或「函式」(methods)),讓我們用一個範例來看看物件的長相。

+ +

在開始之前,請先複製一份 oojs.html 檔案到你自己的本端硬碟中。此檔案內容物不多,就 1 組 {{HTMLElement("script")}} 元素可寫入我們的原始碼;在繪製頁面時,1 組元素可輸入簡易指令;幾個變數定義;1 組函式可針對輸入至 input 的程式碼,將之輸出到 {{HTMLElement("p")}} 元素。我們將透過此檔案說明基礎的物件語法。

+ +

JavaScript 內的大多數東西,均是透過定義並初始設定變數來建立物件。

+ +

現在, 請在自己的 oojs.html 檔案中、JavaScript 程式碼中加入下列程式碼,接著儲存並重新整理:

+ +
var person = {};
+ +

然後在瀏覽器中開啟 oojs.html, 再打開瀏覽器的開發者工具, 在 JavaScript 的控制台下, 輸入person, 並按下 Enter 鈕,就會得到下列結果:

+ +
[object Object]
+ +

恭喜, 你已經建立了自己的第一個物件。但這仍是空的物件,所以能做的事不多。接下來, 再如下所示, 幫 person 物件更新內容:

+ +
var person = {
+  name : ['Bob', 'Smith'],
+  age : 32,
+  gender : 'male',
+  interests : ['music', 'skiing'],
+  bio : function() {
+    alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
+  },
+  greeting: function() {
+    alert('Hi! I\'m ' + this.name[0] + '.');
+  }
+};
+
+ +

改完後同樣儲存 oojs.html、重新整理瀏覽器之後,再到控制台輸入 person, 將會看到新的結果:

+ +
person.name[0]
+person.age
+person.interests[1]
+person.bio()
+person.greeting()
+ +

現在你的物件裡面已經有了某些資料與功能,而且能透過某些簡易語法存取之。

+ +
+

注意:如果你無法完成上述步驟,可先和我們的版本比較一下。參閱 oojs-finished.html (或觀看 實際執行)。你最容易犯下的錯誤是在物件中的最後一個成員 (member)末端加上逗號,如此就會造成錯誤。

+
+ +

目前為止發生了什麼事呢?現在這個物件是由多個成員所構成,各個成員均有 1 個名稱 (如上述的 nameage) 以及 1 組數值 (如 ['Bob', 'Smith']32)。由名稱與數值構成的組合均以逗號區隔,而名稱與數值之間則以冒號隔開。語法應如下所示:

+ +
var objectName = {
+  member1Name : member1Value,
+  member2Name : member2Value,
+  member3Name : member3Value
+}
+ +

物件成員的數值可能是任何東西,像上述的範例物件就有 1 組字串、1 組數字、2 個陣列、2 組函式。前 4 組項目均為資料項目,可說是該物件的屬性。最後 2 組項目的功能則是用以指定物件對該筆資料所應進行的作業,可說是物件的函式 (Method)

+ +

類似這種物件即稱為「實字物件 (Object literal)」,按照字面上的意思寫出物件內容;與其相對的就是根據「類別」做出的物件實體。我們稍後會再說明。

+ +

在傳送一系列結構化的相關資料項目時 (例如傳送請求至伺服器並置入資料庫中),就常常會透過實字物件的方式建立物件。另與「分別傳送多個項目」相較,送出單一物件當然效率更高,且當你想根據名稱找出各個項目時,更易於搭配陣列。

+ +

點記法 (Dot notation)

+ +

你可透過點記法 (Dot notation) 存取物件的屬性與函式。物件名稱 (這裡是 person) 作為命名空間 (Namespace) —為了能存取物件所封裝的所有東西,這也是必須首先輸入的項目。接著你寫一個「點」以及你所想存取的項目,可能是簡單屬性的名稱、陣列屬性的項目,又或是針對物件函式之一的呼叫。舉例來說:

+ +
person.age
+person.interests[1]
+person.bio()
+ +

子命名空間

+ +

甚至可以將物件成員的數值轉為另一個物件。舉例來說,你可將名稱成員從

+ +
name : ['Bob', 'Smith'],
+ +

改變為

+ +
name : {
+  first : 'Bob',
+  last : 'Smith'
+},
+ +

我們這裡以極高效率建立了子命名空間。看起來複雜但其實不然。若要存取這些項目,你只要透過另一個點,將 onto the end 的額外步驟串連起來即可。如下所示:

+ +
person.name.first
+person.name.last
+ +

重要:現在你必須看過自己的函式碼,將實例

+ +
name[0]
+name[1]
+ +

改變為

+ +
name.first
+name.last
+ +

否則你的函式就不能運作了。

+ +

括弧記法 (Bracket notation)

+ +

括弧記法 (Bracket notation) 是另個存取物件屬性的方法。之前的:

+ +
person.age
+person.name.first
+ +

可寫成

+ +
person['age']
+person['name']['first']
+ +

這很像在陣列中存取項目的方法。其實基本上是一樣的東西 ─ 但前者是透過指數  (index number) 選擇項目;括弧記法則是透過各成員數值相關的名稱來選擇項目。因此物件有時亦稱作「相聯陣列 (Associative array)」;也就是說,其「將字串對應到數值」的方式,與陣列「將數字對應到數值」的方式相同。

+ +

設定物件成員

+ +

到目前為止,我們只說明了檢索 (或取得) 物件成員。你也可以簡單宣告你所要設定的成員 (用點或括弧記法均可),設定 (更新) 物件成員的數值,如下:

+ +
person.age = 45
+person['name']['last'] = 'Cratchit'
+ +

試著輸入下列程式碼,再次取得成員之後看看變更的結果:

+ +
person.age
+person['name']['last']
+ +

設定成員不只是更新現有屬性與函式的數值,也可以建立全新的成員,如下:

+ +
person['eyes'] = 'hazel'
+person.farewell = function() { alert("Bye everybody!") }
+ +

現在可以測試自己的新成員了:

+ +
person['eyes']
+person.farewell()
+ +

此外,括弧記法不僅可動態設定成員數值,亦可設定成員名稱。假設使用者可在自己的人事資料中儲存自訂的數值類型,例如鍵入成員名稱與數值為 2 組文字輸入項,就會類似:

+ +
var myDataName = nameInput.value
+var myDataValue = nameValue.value
+ +

接著可將此新的成員名稱與數值加進 person 這個物件:

+ +
person[myDataName] = myDataValue
+ +

若要測試,可將下列程式碼加進自己的程式碼,加在宣告玩 person 物件的大括號後:

+ +
var myDataName = 'height'
+var myDataValue = '1.75m'
+person[myDataName] = myDataValue
+ +

現在儲存並重新整理,將下列輸入你的文字輸入項中:

+ +
person.height
+ +

因為點記法只接受字母表示的成員名稱,不能是指向名稱的變數值,所以並無法使用。

+ +

這個「this」是什麼?

+ +

你可能注意到我們函式有怪怪的地方。看看以下範例:

+ +
greeting: function() {
+  alert('Hi! I\'m ' + this.name.first + '.');
+}
+ +

你可能會想這個「this」是幹嘛用的。「this」是指目前寫入程式碼的物件;所以此範例的 this 就等於 person。那又為何不寫 person 就好呢?如同你在〈初學者的物件導向 JavaScript〉一文中所看過的,當我們開始設定建構子等東西時,有用的「this」就可在成員內文改變時 (例如 2 個不同 person 物件實例可能具備不同的名稱,但打招呼時仍要使用自己的名稱),確保仍使用了正確的值。

+ +

先用簡化的一對 person 物件說明:

+ +
var person1 = {
+  name : 'Chris',
+  greeting: function() {
+    alert('Hi! I\'m ' + this.name + '.');
+  }
+}
+
+var person2 = {
+  name : 'Brian',
+  greeting: function() {
+    alert('Hi! I\'m ' + this.name + '.');
+  }
+}
+ +

此範例中的函式碼雖然完全一樣,但 person1.greeting() 將輸出「Hi! I'm Chris.」;person2.greeting() 則會呈現「Hi! I'm Brian.」。如我們剛剛說過的,「this」等於「已於內部放置程式碼」的物件。如果你是依字面意義寫出物件,那可能沒什麼感覺,但如果你是用動態方式產生物件 (例如使用建構子) 的話,就能明顯感覺到方便之處了。再看下去你更清楚原因。

+ +

其實你一直在使用物件

+ +

隨著你看完這些範例,你應該會覺得跟自己使用的點記法很類似。這是因為你整個課程都在使用點記法。每次我們透過內建的瀏覽器 API 或 JavaScript 物件寫出範例時,我們就是在用物件;因為這些功能也就是以本文提及完全相同的物件結構所寫成。即便是更複雜的範例也是一樣。

+ +

所以當你使用字串函式如下:

+ +
myString.split(',');
+ +

你就是在使用 String 類別實例可用的方法。每次只要你在程式碼中建立字串,該字串就會自動建立成為 String 的實例,並具備有多個常見的方法與屬性。

+ +

若你透過下列程式碼存取文件物件模型 (DOM):

+ +
var myDiv = document.createElement('div');
+var myVideo = document.querySelector('video');
+ +

你也就在使用 Document 類別實例上的函式。當載入網頁時,就會建立 Document 的實例,亦所謂的 document,將呈現整個網頁的架構、內容,以及其他功能 (如網址)。同樣的,這代表其上已有多個常見的函式\屬性。

+ +

同理可證,目前你在使用的許多物件\API (如 ArrayMath 等) 也都是類似情形。

+ +

另該注意的是,內建的物件\API 不見得會自動建立物件實例。像以 Notifications API  (它可以幫助你使用現代瀏覽器向使用者發送通知 ) 為例,就需要你針對想要觸發的通知,使用建構子逐一建立新的物件實例。試著將下列程式碼丟進你的 JavaScript 主控台:

+ +
var myNotification = new Notification('Hello!');
+ +

我們會在後續文章中說明建構子 (Constructor)。

+ +
+

注意:可思考一下物件「訊息傳遞」的溝通方式。當某個物件需要其他物件執行其他作業時,往往會透過其函式之一傳送訊息給其他物件並等待回應。這也是我們所謂的回傳值。

+
+ +

摘要

+ +

恭喜你已經快讀完我們第一篇 JS 物件的文章了。你應該已經知道該如何使用 JavaScript 中的物件,並建立自己的簡單物件了。你也應該了解物件在儲存相關資料的好用之處。如果你將 person 物件中的所有屬性與函式,當做個別的變數與函式並試著追蹤,肯定吃力不討好;且其他具備相同名稱的變數與函式也可能發生問題。「物件」讓我們能在其封包中安全的與資訊相互區隔。

+ +

下一篇文章將說明「物件導向程式設計 (OOP)」理論,並了解相關技術是如何用於 JavaScript 之中。

+ +

{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}

diff --git a/files/zh-tw/learn/javascript/objects/index.html b/files/zh-tw/learn/javascript/objects/index.html new file mode 100644 index 0000000000..aa4b296a95 --- /dev/null +++ b/files/zh-tw/learn/javascript/objects/index.html @@ -0,0 +1,42 @@ +--- +title: JavaScript 物件介紹 +slug: Learn/JavaScript/Objects +translation_of: Learn/JavaScript/Objects +--- +
{{LearnSidebar}}
+ +

在 JavaScript 裡面,從諸如字串與陣列的核心功能、到以 JavaScript 建構的瀏覽器 API,大部分的東西都可算是「物件 (Object)」。你甚至可建立自己的物件,將相關函式與變數封裝 (Encapsulate) 為有效封包,並可作為多樣的資料容器 (Data container)。如果你想更精進既有的程式語言知識,就必須了解 JavaScript 的「物件導向 (Object-Oriented;OO)」本質。為此,我們設計了相關文章來協助你更進一步。本文將先說明物件理論和語法的細節,再引導你建立自己的物件。

+ +

必備條件

+ +

在開始閱讀本文之前,你應該已經對 HTML 與 CSS 有一定程度的認識。建議你先看過〈HTML 介紹〉以及〈CSS 介紹〉,再開始了解 JavaScript。

+ +

你也應該已經初步了解過 JavaScript 基本概念,再進一步閱讀 JavaScript 物件。所以另請先看過〈JavaScript 的第一步〉與〈JavaScript 基礎要件〉。

+ +
+

注意:如果你在使用的桌機\平板\其他裝置,無法讓你建立自己的檔案,則可透過如 JSBinThimble 的線上編碼程式,來體驗 (大多數的) 範例程式碼。

+
+ +

指南

+ +
+
物件基本概念
+
第一篇主述 JavaScript 物件。我們將說明基本的 JavaScript 物件語法,並重新講解某些先前已經說過的 JavaScript 功能,也會再提及許多物件是你現正使用中的功能。
+
適合初學者的 OO JaveScript
+
說明過基本概念之後,就會將重點放在物件導向的 JavaScript (OOJS) 本質上。本文會先介紹 OO 程式設計的基礎理論,再說明 JavaScript 是如何透過建構子 (Constructor) 函式模擬物件類別並建立物件實體 (Instance)。
+
物件原型
+
原型 (Prototype) 是 JavaScript 物件用以互相繼承功能的機制,且其與典型 OO 程式語言中的繼承機制有所不同。本文將探討其中相異性、說明原型鏈的運作方式,並透過原型屬性將函式新增至現有建構子。
+
JavaScript 中的繼承
+
再說明了 JavaScript 大多數的 OO 特性之後,將說明應如何建立「子」物件類別 (建構子) 並繼承其「母」類別的功能。此外,我們將針對你可能使用 OOJS 的時機提供建言。
+
利用 JSON 資料
+
JavaScript Object Notation (JSON) 為標準格式,用以將「結構化資料 (Structured data)」呈現為 JavaScript 物件,並常用於網站之間呈現\傳輸資料 (如從伺服器傳送資料到用戶端,以於網頁上顯示內容)。你一定會常接觸到類似情形,所以本文將提供用 JavaScript 搭配 JSON 開發時的所有資訊,包含在 JSON 物件中存取資料項目,以及撰寫你自己的 JSON。
+
物件打造實例
+
前幾篇文章帶領你看過基本的 JavaScript 物件理論和語法細節,幫你打下厚實的基礎。而本文要讓你實際操作,透過更多實例自訂出 JavaScript 物件,讓你享受多采多姿的學習過程 (讓你寫出彩色的跳跳球喔)。
+
+ +

評量

+ +
+
為彩色跳跳球展示範例新增其他功能
+
在此評量中,你已經先寫出了跳跳球範例。接著要讓你新增其他有趣的功能。
+
diff --git a/files/zh-tw/learn/javascript/objects/inheritance/index.html b/files/zh-tw/learn/javascript/objects/inheritance/index.html new file mode 100644 index 0000000000..f9db84dae8 --- /dev/null +++ b/files/zh-tw/learn/javascript/objects/inheritance/index.html @@ -0,0 +1,210 @@ +--- +title: JavaScript 中的「繼承」 +slug: Learn/JavaScript/Objects/Inheritance +translation_of: Learn/JavaScript/Objects/Inheritance +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}
+ +

在解釋過大部分的 OOJS 細節之後,本文將說明該如何建立「子」物件類別 (建構子),並從其「母」類別繼承功能。此外,也將建議開發者應於何時、於何處使用 OOJS。

+ + + + + + + + + + + + +
必備條件:基本的電腦素養、已了解 HTML 與 CSS 基本概念、熟悉 JavaScript 基礎 (可參閱〈First steps〉與〈Building blocks〉) 與 OOJS 的基礎 (可參閱〈Introduction to objects〉)。
主旨:了解應如何建構 JavaScript 中的繼承。
+ +

原型繼承

+ +

目前為止,我們看過幾個繼承的實作範例:原型鍊的運作方式,以及繼承的成員如何形成原型鍊。但這些大部分都與內建的瀏覽器函式有關。那我們又該如何在 JavaScript 建立物件且由其他物件繼承而來呢?

+ +

如稍早的系列文章中所述,某些人認為 JavaScript 並非真正的物件導向 (OO) 語言。在「典型 OO」中,你必須定義特定的類別物件,才能定義哪些類別所要繼承的類別 (可參閱〈C++ inheritance〉了解簡易範例)。JavaScript 則使用不同的系統 —「繼承」的物件並不會一併複製功能過來,而是透過原型鍊連接其所繼承的功能,亦即所謂的原型繼承 (Prototypal inheritance)。

+ +

就透過範例了解此一概念吧。

+ +

入門

+ +

首先將 oojs-class-inheritance-start.html 檔案 (亦可參考實際執行) 複製到本端磁碟。可在裡面找到本課程一直沿用的 Person() 建構子範例,但這裡有些許不同,也就是該建構子只定義了屬性:

+ +
function Person(first, last, age, gender, interests) {
+  this.name = {
+    first,
+    last
+  };
+  this.age = age;
+  this.gender = gender;
+  this.interests = interests;
+};
+ +

這些函式均已定義於建構子的原型之上,例如:

+ +
Person.prototype.greeting = function() {
+  alert('Hi! I\'m ' + this.name.first + '.');
+};
+ +

假設要建立一個像前面 OO 定義中說過的 Teacher 類別,且除了繼承 Person 的所有成員,還要包含:

+ +
    +
  1. 新的 subject 屬性,可包含老師所傳授的科目。
  2. +
  3. 更新過的 greeting() 函式,要比標準的 greeting() 函式更正式一點,更適合老師在校對學生使用。
  4. +
+ +

定義 Teacher() 建構子函式

+ +

首先必須建立 Teacher() 建構子,將下列程式碼加到現有程式碼之下:

+ +
function Teacher(first, last, age, gender, interests, subject) {
+  Person.call(this, first, last, age, gender, interests);
+
+  this.subject = subject;
+}
+ +

這看起來和 Person 建構子有許多地方類似,但比較奇怪的就是之前沒看過的 call() 函式。此函式基本上可讓你呼叫在其他地方定義的函數,而非目前內文 (context) 中定義的函式。當執行函式時,第一個參數用來指定你要使用 this 值,其他參數則指定應該傳送到該函式的參數。

+ +
+

注意:我們此範例中建立新的物件實例時,會指定所要繼承的屬性。但必須注意的是,即使實例不需將屬性指定為參數,你還是必須在建構子中將屬性指定為參數  (在建立物件時,你可能獲得設定為隨意值的屬性)。

+
+ +

所以這裡可在 Teacher() 建構子函式之內有效執行 Person() 建構子函式 (如上述),藉以在 Teacher() 之內定義相同的屬性,但使用的是傳送到 Teacher() 的屬性值,而非 Person() 的屬性值 (我們將 this 值設為簡單的「this」並傳送到 call(),代表這個 thisTeacher() 的函式)。

+ +

建構子的最後一行則定義了新的 subject 屬性,代表只有老師具備,一般人不會有。

+ +

我們也可以單純這樣做:

+ +
function Teacher(first, last, age, gender, interests, subject) {
+  this.name = {
+    first,
+    last
+  };
+  this.age = age;
+  this.gender = gender;
+  this.interests = interests;
+  this.subject = subject;
+}
+ +

但這樣只是重新定義了新的屬性,而不是繼承自 Person() 而來,所以無法達到我們預設的目標,也需要更多程式碼才能達成。

+ +

設定 Teacher() 的原型與建構子參考

+ +

到目前為止發現一個問題:我們定義了新的建構子,但預設只有 1 個空白的 prototype 屬性。接著要讓 Teacher() 繼承 Person() 原型中所定義的函式,該怎麼做呢?

+ +
    +
  1. 繼續在現有程式碼下方加入: +
    Teacher.prototype = Object.create(Person.prototype);
    + 這裡再次用好朋友 create() 解救。我們透過 create() 並搭配等同於 Person.prototype 的原型,建立新的 prototype 屬性值 (它本身就是物件,包含屬性與函式) ,並將之設定為 Teacher.prototype 的值。也就是說 Teacher.prototype 現在會繼承 Person.prototype 上的所有可用函式。
  2. +
  3. 此外,基於我們的繼承方式,Teacher() prototype 的建構子屬性目前設定為 Person()。可參閱 Stack Overflow post 進一步了解原因。可先儲存自己的程式碼、在瀏覽器中載入頁面,再將下列程式碼輸入至 JavaScript 主控台以驗證: +
    Teacher.prototype.constructor
    +
  4. +
  5. 這樣可能會產生問題,所以要設定正確。你可回到自己的原始碼並在最下方加入下列程式碼: +
    Teacher.prototype.constructor = Teacher;
    +
  6. +
  7. 如果儲存並重新整理之後,只要輸入 Teacher.prototype.constructor 應該就會回傳 Teacher()
  8. +
+ +

給 Teacher() 新的 greeting() 函式

+ +

接著必須在 Teacher() 建構子上定義新的 greeting() 函式。

+ +

最簡單的方法就是在 Teacher() 的原型上定義此函式。將下列加入程式碼最底部:

+ +
Teacher.prototype.greeting = function() {
+  var prefix;
+
+  if(this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') {
+    prefix = 'Mr.';
+  } else if(this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') {
+    prefix = 'Mrs.';
+  } else {
+    prefix = 'Mx.';
+  }
+
+  alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.');
+};
+ +

這樣就會顯示老師的問候語,也會針對老師的性別使用合適的稱呼,可用於條件陳述式。

+ +

簡易範例

+ +

現在你已經輸入所有程式碼了,可以試著用Teacher() 建立物件實例。將下列 (或是你想用的類似程式碼) 加入現有程式碼的底部:

+ +
var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');
+ +

儲存並重新整理之後,試著存取新 teacher1 物件的屬性語函式,例如:

+ +
teacher1.name.first;
+teacher1.interests[0];
+teacher1.bio();
+teacher1.subject;
+teacher1.greeting();
+ +

這樣應該運作無虞。前 3 行的存取成員即繼承自一般 Person() 建構子 (類別)。最後 2 行的存取成員只能用於特定的 Teacher() 建構子 (類別) 之上。

+ +
+

注意:如果你無法進行到現有進度,可比較自己與完整版本 (亦可看實際執行的情形) 的程式碼。

+
+ +

這裡所提的技巧,當然不是在 JavaScript 建立繼承類別的唯一方法,但足以堪用。並可讓你了解應如何於 JavaScript 實作繼承。

+ +

你可能也想看看某些新的 {{glossary("ECMAScript")}} 功能,可更簡潔的在 JavaScript 中繼承 (參閱 Classes)。但由於這些功能尚未廣泛支援其他瀏覽器,這裡先略過不提。本系列文章中提到的其他程式碼,均可回溯支援到 IE9 或更早版本。當然還是有辦法支援更舊的版本。

+ +

一般方法就是使用 JavaScript 函式庫,且最常見的就是簡單集結可用的功能,更快、更輕鬆的完成繼承。例如 CoffeeScript 即提供了 class、extends 等等。

+ +

進階習題

+ +

〈OOP 理論〉段落中,我們也納入了 Student 類別並繼承了 Person 的所有功能,此外也提供不同的 greeting() 函式,且較 Teacher 的問候語沒那麼正式。在看了該段落中的學生問候語之後,可試著實作自己的 Student() 建構子,並繼承 Person(), 的所有功能,再實作不同的 greeting() 函式。

+ +
+

注意:如果你無法進行到現有進度,可參考完成版本 (亦可看實際執行的情形)。

+
+ +

物件成員摘要

+ +

簡單來說,你基本上需要考量 3 種類型的屬性\函式:

+ +
    +
  1. 已於建構子函式中定義,會交給物件實體的屬性\函式。這應該很容易處理。在你自己的程式碼中,就是透過 this.x = x 類別行並在建構子中定義的成員;在瀏覽器程式碼中,就是僅限物件實體可用的成員 (一般是透過 new 關鍵字並呼叫建構子所建立,例如 var myInstance = new myConstructor())。
  2. +
  3. 直接在建構子上定義,並僅能用於該建構子的屬性\函式。這類屬性\函式往往只能用於內建瀏覽器物件之上,並直接「鍊接」至建構子 (而非實例) 以利識別,例如 Object.keys()
  4. +
  5. 定義於建構子原型上的屬性\函式,交由所有的實例繼承,亦繼承了物件類別。這類屬性\函式包含建構子原型屬性之上定義的所有成員,例如 myConstructor.prototype.x()
  6. +
+ +

如果你不確定到底屬於上述的哪一個,也別擔心。現在你還在學習階段,往後定會熟能生巧。

+ +

在 JavaScript 中使用繼承的時機?

+ +

看到這裡,你心裡應該覺得很複雜。沒錯。「原型」與「繼承」可說是 JavaScript 最複雜的概念之二,但許多 JavaScript 的強大功能與彈性,均來自於其物件結構與繼承,也值得你了解運作方式。

+ +

不論是使用 WebAPI 的多樣功能,或是你在字串、陣列等所呼叫的函式\屬性 (定義於內建瀏覽器物件之上),你都可以不斷繼承下去。

+ +

在自己的程式碼裡,特別是剛接觸或小型專案時,你用繼承的頻率可能沒那麼高。若沒真正需要,只是「為使用而使用」繼承,老實說只是浪費時間。但隨著程式碼規模越來越大,你就會找到使用的時間。如果你發現自己開始建立類似功能的多個物件時,就可先建立通用的物件類型,來概括所有共用的功能,並在特定物件類型中繼承這些功能,既方便又有效率。

+ +
+

注意:基於 JavaScript 運作的方式 (如原型鍊等),物件之間的功能共享一般稱為委託 (Delegation)」,即特定物件將功能委託至通用物件類型。「委託」其實比繼承更精確一點。因為「所繼承的功能」並不會複製到「進行繼承的物件」之上,卻是保留在通用物件之中。

+
+ +

當使用繼承時,建議你不要設定太多層的繼承關係,並時時留意你所定義的函式與屬性。在開始寫程式碼時,你可能會暫時修改內建瀏覽器物件的原型,除非你真的需要,否則儘量別這麼做。太多繼承可能連你自己都搞混,而且一旦需要除錯就會痛苦萬分。

+ +

最後,物件可說是另一種形式的程式碼再利用,如同函式或迴圈一般,且有其專屬的角色與優點。如果你正建立一堆相關變數與函式,並要全部一起追蹤、封裝,就可以透過物件。你也能以物件方式傳送整個資料集合。而且上述兩種情況均不需使用建構子或繼承就能夠達成。如果你只需要某一物件的單一實作,那麼單純使用物件就好,完全不需要繼承。

+ +

摘要

+ +

本文為大家溫習了 OOJS 核心理論和語法。現在你應該了解 JavaScript 物件與 OOP 的基本概念、原型及原型繼承、建立類別 (建構子) 與物件實例的方法、為類別新增功能、建立從其他類別繼承而來的子類別。

+ +

下篇文章就要來看看該如何搭配 JavaScript Object Notation (JSON),使用 JavaScript 物件的常見資料交換格式。

+ +

另可參閱

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}

diff --git a/files/zh-tw/learn/javascript/objects/json/index.html b/files/zh-tw/learn/javascript/objects/json/index.html new file mode 100644 index 0000000000..71a4a3776a --- /dev/null +++ b/files/zh-tw/learn/javascript/objects/json/index.html @@ -0,0 +1,325 @@ +--- +title: 使用 JSON 資料 +slug: Learn/JavaScript/Objects/JSON +tags: + - JSON +translation_of: Learn/JavaScript/Objects/JSON +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}
+ +

JavaScript Object Notation (JSON) 為將結構化資料 (structured data) 呈現為 JavaScript 物件的標準格式,常用於網站上的資料呈現、傳輸 (例如將資料從伺服器送至用戶端,以利顯示網頁)。你應該會常常遇到,因此本文將說明 JavaScript 搭配 JSON 時所應知道的觀念,包含如何在 JSON 物件中存取資料項目,並寫出你自己的 JSON。

+ + + + + + + + + + + + +
必要條件:基礎的計算機素養、了解 HTML 與 CSS 的基本概念、熟悉 JavaScript (參閱〈First steps〉與〈Building blocks〉) 與 OOJS 基本概念 (參閱〈Introduction to objects〉)。
主旨:了解應如何使用 JSON 格式所儲存的資料,建立自己的 JSON 物件。
+ +

說真的,到底什麼是 JSON?

+ +

{{glossary("JSON")}} 是依照 JavaScript 物件語法的資料格式,經 Douglas Crockford 推廣普及。雖然 JSON 是以 JavaScript 語法為基礎,但可獨立使用,且許多程式設計環境亦可讀取 (剖析) 並產生 JSON。

+ +

JSON 可能是物件或字串。當你想從 JSON中讀取資料時,JSON可作為物件;當要跨網路傳送 JSON 時,就會是字串。這不是什麼大問題 —  JavaScript 提供全域 JSON 物件,其內的函式可進行切換。

+ +

JSON 物件可儲存於其自有的檔案中,基本上就是副檔名為 .json 的文字檔案,以及 application/json 的 {{glossary("MIME type")}}。

+ +

JSON 的架構

+ +

我們剛提到「JSON 物件基本上就是 JavaScript 物件」,而這敘述在大多數情況下都對。如同標準的 JavaScript 物件,你當然可在 JSON 之內加入相同的基本資料類型,如字串、數字、陣列、布林值,以及其他物件,接著同樣能再建構出資料繼承,如:

+ +
{
+  "squadName" : "Super hero squad",
+  "homeTown" : "Metro City",
+  "formed" : 2016,
+  "secretBase" : "Super tower",
+  "active" : true,
+  "members" : [
+    {
+      "name" : "Molecule Man",
+      "age" : 29,
+      "secretIdentity" : "Dan Jukes",
+      "powers" : [
+        "Radiation resistance",
+        "Turning tiny",
+        "Radiation blast"
+      ]
+    },
+    {
+      "name" : "Madame Uppercut",
+      "age" : 39,
+      "secretIdentity" : "Jane Wilson",
+      "powers" : [
+        "Million tonne punch",
+        "Damage resistance",
+        "Superhuman reflexes"
+      ]
+    },
+    {
+      "name" : "Eternal Flame",
+      "age" : 1000000,
+      "secretIdentity" : "Unknown",
+      "powers" : [
+        "Immortality",
+        "Heat Immunity",
+        "Inferno",
+        "Teleportation",
+        "Interdimensional travel"
+      ]
+    }
+  ]
+}
+ +

舉例來說,如果將此物件載入至 JavaScript 程式並將之儲存為「superHeroes」變數,如同〈JavaScript 物件基本概念〉一文中提過的,接著能以相同的  存取其內部的資料,如下:

+ +
superHeroes.hometown
+superHeroes["active"]
+ +

若要順著繼承往下存取資料,只要將必要的屬性名稱與陣列索引「鍊」在一起即可。舉例來說,如果要存取成員列表中的第二位英雄的第三項超能力,你必須:

+ +
superHeroes["members"][1]["powers"][2]
+ +
    +
  1. 首先要有變數名稱 — superHeroes
  2. +
  3. 要在變數中存取 members 屬性,所以用 ["members"]
  4. +
  5. members 包含由物件產生陣列。我們要存取陣列中的第二個物件,所以用 [1]
  6. +
  7. 在此物件中,我們要存取 powers 屬性,所以用 ["powers"]
  8. +
  9. powers 屬性中有 1 個陣列具備所選超級英雄的能力。我們要選第三種能力,所以用 [2]
  10. +
+ +
+

注意:我們在 JSONText.html 範例 (參閱原始碼) 的變數中,示範上述可用的 JSON。你可在自己瀏覽器的 JavaScript 主控台載入此程式碼,並存取變數中的資料。

+
+ +

陣列作為 JSON

+ +

我們在上面提過「 JSON 物件基本上就是 JavaScript 物件,而這敘述在大多數情況下都對」。其中「在大多數情況下都對」的理由,就是因為陣列也可以是有效的 JSON 物件,例如:

+ +
[
+  {
+    "name" : "Molecule Man",
+    "age" : 29,
+    "secretIdentity" : "Dan Jukes",
+    "powers" : [
+      "Radiation resistance",
+      "Turning tiny",
+      "Radiation blast"
+    ]
+  },
+  {
+    "name" : "Madame Uppercut",
+    "age" : 39,
+    "secretIdentity" : "Jane Wilson",
+    "powers" : [
+      "Million tonne punch",
+      "Damage resistance",
+      "Superhuman reflexes"
+    ]
+  }
+]
+ +

上面程式碼絕對是有效的 JSON。你可用陣列指數為開頭來存取陣列項目,例如 [0]["powers"][0]

+ +

其他附註

+ + + +

主動學習:完成 JSON 範例

+ +

現在就試著在網站上,透過某些 JSON 資料完成範例吧。

+ +

入門

+ +

在開始之前,先複製我們的 heroes.htmlstyle.css 到你的本端硬碟中。後者包含某些簡易的 CSS 可塑造網頁風格;前者則提供極簡單主體 HTML:

+ +
<header>
+</header>
+
+<section>
+</section>
+ +

加上 {{HTMLElement("script")}} 元素,才能納入稍後會在此習題中寫出來的 JavaScript 程式碼。目前只有 2 行程式碼,用以取得 {{HTMLElement("header")}} 與 {{HTMLElement("section")}} 元素的參考,並將之儲存於變數之中:

+ +
var header = document.querySelector('header');
+var section = document.querySelector('section');
+ +

你可到 GitHub 上找到此 JSON 資料:https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json

+ +

接著載入到頁面之中,並使用某些有趣的 DOM 操控 (DOM manipulation) 來顯示,如下:

+ +

+ +

載入我們的 JSON

+ +

若要將 JSON 載入至頁面,就要透過 {{domxref("XMLHttpRequest")}} API (通常稱為 XHR)。此是極好用的 JavaScript 物件,可讓網路請求透過 JavaScript (例如圖片、文字、JSON,甚至 HTML 片段) 來檢索伺幅器的資源,這也代表我們不需載入整個頁面,就能更新小部分的內容。如此可讓網頁反應速度更快;聽起來很棒吧?但可惜本文無法再深入講解更多細節。

+ +
    +
  1. 一開始,我們先針對要在變數中檢索的 JSON 檔案,將其網址儲存起來。把下列程式碼加到你 JavaScript 程式碼的最下方: +
    var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
    +
  2. +
  3. 為了建立請求,我們必須透過 new 關鍵字,先從 XMLHttpRequest 建構子建立新的請求物件實例。把下列加到最後一行: +
    var request = new XMLHttpRequest();
    +
  4. +
  5. 現在用 open() 函式開啟新的請求。加入下列程式碼: +
    request.open('GET', requestURL);
    + +

    這樣就顧到至少 2 個參數。當然也有其他參數可選擇。但這個簡易範例只需要 2 個強制參數:

    + +
      +
    • 在設立網路請求時,應使用 HTTP 函式。因為這裡只要檢索簡單的資料,所以用 GET 就可以。
    • +
    • URL 提供請求目的地 — 這也就是我們剛剛儲存的 JSON 檔案網址。
    • +
    +
  6. +
  7. 接著加入下面 2 行程式碼。我們為 JSON 設定了 responseType,告知伺服器應回傳 JSON 物件,再以 send() 函式傳送請求: +
    request.responseType = 'json';
    +request.send();
    +
  8. +
  9. 最後就是等待由伺服器所回傳的反應,再接著處理。把下列程式碼加入現有程式碼的最下方: +
    request.onload = function() {
    +  var superHeroes = request.response;
    +  populateHeader(superHeroes);
    +  showHeroes(superHeroes);
    +}
    +
  10. +
+ +

在這裡,我們將所獲得的響應 (可到 response 屬性中找到) 儲存到 superHeroes 變數之中。此變數現在會納入我們的 JSON。接著再把此 JSON 檔案送到 2 個函式呼叫。第一個函式呼叫會將正確資料填入 <header>;第二個函式呼叫則會為團隊中的各個英文建立資訊卡,再插入至 <section> 內。

+ +

當於請求物件上觸發載入事件時,會執行一個事件處理器。我們就將程式碼包裹至此處理器之中 (參閱 onload) — 只要成功回傳響應,就會觸發載入事件。之所以這樣做,是為了確保當我們要以 request.response 進行某件事時,此 request.response 絕對可用。

+ +

產生標頭

+ +

現在檢索過了 JSON 資料,接著就寫出上面參照過的 2 個函式來利用 JSON 資料吧。首先將下列函式定義加到先前的程式碼中:

+ +
function populateHeader(jsonObj) {
+  var myH1 = document.createElement('h1');
+  myH1.textContent = jsonObj['squadName'];
+  header.appendChild(myH1);
+
+  var myPara = document.createElement('p');
+  myPara.textContent = 'Hometown: ' + jsonObj['homeTown'] + ' // Formed: ' + jsonObj['formed'];
+  header.appendChild(myPara);
+}
+ +

我們已經將參數命名為 jsonObj,所以在這個函式之內就要用 jsonObj 呼叫此參數。這裡先以 createElement() 建立 1 組 {{HTMLElement("h1")}} 元素、將其 textContent 指定為 JSON 的 squadName 屬性、透過 appendChild() 將之附加到標頭。接著 {{HTMLElement("p")}} 元素依樣畫葫蘆一遍:建立、設定其文字內容、附加到標頭。唯一不同之處,就是將該文字設定為 1 組串接字串 (Concatenated string),其內包含 JSON 的 homeTownformed 屬性。

+ +

建立超級英雄的資訊卡片

+ +

現在將下列函式加到程式碼底端,用以建立並顯示超級英雄的卡片:

+ +
function showHeroes(jsonObj) {
+  var heroes = jsonObj['members'];
+
+  for(i = 0; i < heroes.length; i++) {
+    var myArticle = document.createElement('article');
+    var myH2 = document.createElement('h2');
+    var myPara1 = document.createElement('p');
+    var myPara2 = document.createElement('p');
+    var myPara3 = document.createElement('p');
+    var myList = document.createElement('ul');
+
+    myH2.textContent = heroes[i].name;
+    myPara1.textContent = 'Secret identity: ' + heroes[i].secretIdentity;
+    myPara2.textContent = 'Age: ' + heroes[i].age;
+    myPara3.textContent = 'Superpowers:';
+
+    var superPowers = heroes[i].powers;
+    for(j = 0; j < superPowers.length; j++) {
+      var listItem = document.createElement('li');
+      listItem.textContent = superPowers[j];
+      myList.appendChild(listItem);
+    }
+
+    myArticle.appendChild(myH2);
+    myArticle.appendChild(myPara1);
+    myArticle.appendChild(myPara2);
+    myArticle.appendChild(myPara3);
+    myArticle.appendChild(myList);
+
+    section.appendChild(myArticle);
+  }
+}
+ +

我們先把 JSON 的 members 屬性儲存到新的變數中。此陣列所具備的多個物件,均包含了各個超級英雄的資訊。

+ +

接著我們以 for 迴圈循環陣列中的各個物件。針對每個物件都會:

+ +
    +
  1. 建立數個新的元素:1 組 <article>、1 組 <h2>、3 組 <p>、1 組 <ul>。
  2. +
  3. 讓 <h2> 納入目前超級英雄的 name
  4. +
  5. 接著 3 個段落分別是英雄的 secretIdentityage、Superpowers,在列表中帶出相關資訊。
  6. +
  7. 另以新變數 superPowers 儲存 powers 屬性 — 其中包含 1 組陣列以列出目前英雄的超能力。
  8. +
  9. 再用另一個 for 迴圈逐一巡過目前英雄的超能力。針對每一項超能力,我們再建立 1 組 <li> 元素,把超能力放進該元素之中,再透過 appendChild()listItem 放入 <ul> 元素之內 (myList)。
  10. +
  11. 最後就是在 <article> (myArticle) 之內附加 <h2>、<p>、<ul>;再把 <article> 附加於 <section> 之內。這附加的順序極為重要,因為這也會是 HTML 中的顯示順序。
  12. +
+ +
+

注意:如果你無法讓此範例運作,可參閱我們的 heroes-finished.html 原始碼 (亦可看到實際執行情況。)

+
+ +
+

注意:如果你無法用我們說過的點記法 (dot-)\括弧記法 (bracket notation) 來存取 JSON,則可用新分頁或自己的文字編輯器開啟 superheroes.json 檔案並參考之。你也可再回去看看 JavaScript 物件基礎概念 ,再次了解點\括弧記法。

+
+ +

物件與文字交互轉換

+ +

上述是存取 JSON 的簡易範例,因為我們設定要回傳響應的 XHR 已經是 JSON 格式。透過:

+ +
request.responseType = 'json';
+ +

但有時候沒這麼好運。我們有時會接收到文字字串格式的 JSON 資料,且必須將之轉換為物件。且當我們要以某種訊息傳送 JSON 資料時,也必須將之轉換為字串才能正確運作。還好,這 2 種問題在 Web 開發過程中甚為常見。內建的 JSON 物件很早就新增到瀏覽器之中,且包含下列 2 種函式:

+ + + +

你可到 heroes-finished-json-parse.html 範例 (參閱原始碼) 中看到第一個函式的運作情形。這其實跟我們先前範例所進行的事情一模一樣,不同之處在於我們設定 XHR 要回傳 JSON 為文字,接著再使用 parse() 轉換為實際的 JSON 物件。關鍵程式碼片段如下:

+ +
request.open('GET', requestURL);
+request.responseType = 'text'; // now we're getting a string!
+request.send();
+
+request.onload = function() {
+  var superHeroesText = request.response; // get the string from the response
+  var superHeroes = JSON.parse(superHeroesText); // convert it to an object
+  populateHeader(superHeroes);
+  showHeroes(superHeroes);
+}
+ +

你可能會猜 stringify() 就是反過來運作了吧?可在瀏覽器的 JavaScript 主控台上輸入下列程式碼,看看其運作方式:

+ +
var myJSON = { "name" : "Chris", "age" : "38" };
+myJSON
+var myString = JSON.stringify(myJSON);
+myString
+ +

這樣就建立了 JSON 物件了。接著檢查內容物之後,就可透過 stringify() 將之轉換為字串。將回傳值儲存到新變數之中,再檢查一次即可。

+ +

摘要

+ +

我們透過本文簡單介紹了該如何在程式中使用 JSON、該如何建立\剖析 JSON、該如何存取其內的資料。接著就要說明物件導向 JavaScript (OOJS)。

+ +

另可參閱

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}

diff --git a/files/zh-tw/learn/javascript/objects/object-oriented_js/index.html b/files/zh-tw/learn/javascript/objects/object-oriented_js/index.html new file mode 100644 index 0000000000..1504f5fc49 --- /dev/null +++ b/files/zh-tw/learn/javascript/objects/object-oriented_js/index.html @@ -0,0 +1,277 @@ +--- +title: 初學者應知道的物件導向 JavaScript +slug: Learn/JavaScript/Objects/Object-oriented_JS +translation_of: Learn/JavaScript/Objects/Object-oriented_JS +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}
+ +

在看完了基本概念之後,接著要說明物件導向 JavaScript (OOJS)。本文將概述物件導向程式設計 (OOP) 的理論,另說明 JavaScript 是如何透過建構子函式來模擬物件類別,又是如何建立物件實體 (Instance)。

+ + + + + + + + + + + + +
必備條件:基本的電腦素養、已初步了解 HTML 與 CSS、熟悉 JavaScript (參閱〈First steps〉與〈Building blocks〉以及 OOJS 基礎概念 (參閱〈物件基礎概念〉。
主旨:了解物件導向程式設計的基本理論、其與 JavaScript (幾乎所有東西都是物件) 之間的關係、應如何寫出建構子與物件實體。
+ +

基本物件導向程式設計

+ +

最先,讓我們從簡單、高層次的視角來看物件導向程式設計 (Object-oriented programming;OOP) 最基本的概念。我們說簡單是因為 OOP 很容易變得複雜,就算現在就設法完整解釋,也可能讓大家越來越混亂。OOP 基本概念是:採用物件(objects)來模塑真實的實物世界:也就是在程式中的呈現是透過 objects 來塑造其模型,且\或提供簡單方式存取其「難以或不可能採用的功能」。

+ +

物件可裝載相關的資料與程式碼,資料部分是你塑造某個模型的資訊,而程式碼部分則用是操作行為(Method)實現。Object data  -- 函式部分通常也使用 ---可工整地儲存 (正式一點應該是封裝 Encapsulated) 在物件包裹(這個包裹有特定的稱呼方式,有時候即所謂的命名空間 Namespace) ,使其能輕鬆地建構性存取。物件也常作為「資料儲存 (Datastore),促成簡易實現跨網傳送。

+ +

定義物件範本

+ +

我們先找個簡單程式,如同學校裡用來顯示師生資訊的程式。本文只是要了解一般的 OOP 理論,並非以特定程式語言為出發點。

+ +

我們先拿第一篇物件文章中的「Person」物件類型為範例,其中定義了一個人的一般資料與功能。其實有很多資訊可助你了解一個人 (像是住址、身高、鞋子尺寸、DNA、護照號碼、明顯的人格特質等......),但我們這裡只列出了姓名、年齡、性別、興趣。我們另希望根據這些資料寫出簡介,初步了解這個人。上述這些即所謂的「抽象 (Abstraction)」。為某個複雜東西建立簡單的模型,藉以代表其最重要的概念或特質,且該模型建立方式極易於搭配我們的程式設計用途。

+ +

+ +

建立實際物件

+ +

我們可從這個「類別」建立物件實體 (Object instance) — 即該物件包含了類別中所定義的資料與功能。而「Person」類別可設定出幾個實際的人物:

+ +

+ +

在根據類別建立物件實體時,就是執行類別的「建構子 (Constructor) 函式」所建立。而這個「根據類別來建立物件實體」的過程即稱為「實體化 (Instantiation)」。物件實體就是從類別實體化而來。

+ +

特殊類別

+ +

如果我們不要一般人物,而想建立老師與學生這類比較特定類型的人物。在 OOP 中,我們可根據其他類別建立新的類別。新的子類別則可繼承 (Inherit) 母類別的資料與程式碼特性。你可重複使用所有物件類型共有的功能,而不需再複製之。若功能需與類別有所差異,則可直接於其上定義特殊功能。

+ +

+ +

這樣很方便。因為老師與學生也同樣使用了如姓名、性別、年齡等的共通特性,所以只要定義這些特性 1 次即可。你也可以分別在不同的類別中定義相同特性,各個特性的定義就置於不同的命名空間中。舉例來說,學生的打招呼方式可以是「Yo, I'm [firstName]」;老師的招呼方式就正式一點,如「Hello, my name is [Prefix] [lastName]」。

+ +
+

注意:所謂的「多型 (Polymorphism)」,即是用多個物件類別建置相同功能。

+
+ +

現在你可根據子類別來建立物件實例了。例如:

+ +

+ +

本文後面將講解應如何將 OOP 理論實際用於 JavaScript 中。

+ +

建構子與物件實例

+ +

JavaScript 使用稱為建構子函式(constructor function)的特殊函式,定義物件與功能。開發者常常會不知道到底需建立多少物件,這時建構子可讓你高效率建立所需物件,並依需要為其添加資料與函式。

+ +

在新的物件實例透過建構子函式產生後,其核心將透過一種稱為原型鏈(Prototype chain,由原型定義,可參閱 Object prototypes)的參照鏈連在一起。

+ +

接著就在 JS 中,透過建構子建立類別及其物件實例。首先請你先在本端磁碟中再另外複製一份前面文章提過的 oojs.html 檔案。

+ +

簡易範例

+ +
    +
  1. 先看看該如何用一般函式定義一個人。將下列函式加到 script 元素裡面: + +
    function createNewPerson(name) {
    +  var obj = {};
    +  obj.name = name;
    +  obj.greeting = function () {
    +    alert('Hi! I\'m ' + this.name + '.');
    +  }
    +  return obj;
    +}
    +
  2. +
  3. 呼叫此函式之後即可建立新的 1 個人,另在瀏覽器的 JavaScript 主控台中測試下列程式碼: +
    var salva = createNewPerson('salva');
    +salva.name;
    +salva.greeting();
    + 目前為止沒什麼問題,但有點囉嗦。如果早知道要建立物件的話,又何必要建立新的空白物件再回傳呢?幸好 JavaScript 透過建構子函式提供了方便的捷徑。現在就來試試看!
  4. +
  5. 用下列程式碼替代之前的函式: +
    function Person(name) {
    +  this.name = name;
    +  this.greeting = function() {
    +    alert('Hi! I\'m ' + this.name + '.');
    +  };
    +}
    +
  6. +
+ +

建構子也就是 JavaScript 版本的「類別」之一。你可以注意到,除了無法回傳任何數值或明確建立物件之外,建構子其實已具備函式中的所有功能,並已基本定義了屬性與函式 (Method)。你也能看到這裡同樣用了「this」關鍵字,即不論何時建立了這裡的任一物件實例,物件的「name」屬性均同等於「傳送至建構子呼叫的名稱值」;且 greeting() 函式也會使用相同「傳送至建構子呼叫的名稱值」。

+ +
+

注意:建構子函式名稱往往以大寫字母起頭,如此可方便你在程式碼中找出建構子函式。

+
+ +

我們又該如何呼叫建構子以建立物件呢?

+ +
    +
  1. 將下列程式碼加到目前的程式碼之下: +
    var person1 = new Person('Bob');
    +var person2 = new Person('Sarah');
    +
  2. +
  3. 儲存程式碼並在瀏覽器中重新載入,試著將下列程式碼輸入到文字輸入畫面中: +
    person1.name
    +person1.greeting()
    +person2.name
    +person2.greeting()
    +
  4. +
+ +

現在你應該能在頁面上看到兩組新物件,且各自以不同的命名空間儲存。若要存取其屬性與函式,就要以 person1person2 開始呼叫。這些物件均完整封包,不致與其他功能衝突;但仍具備相同的 name 屬性與 greeting() 函式。另請注意,物件均使用當初建立時所各自指派的 name 值;這也是「this」如此重要的原因之一,以確保物件可使用自己的值而不致混淆其他數值。

+ +

再看一次建構子呼叫:

+ +
var person1 = new Person('Bob');
+var person2 = new Person('Sarah');
+ +

這裡用了「new」關鍵字告知瀏覽器「我們要建立新的物件實例」,並接著在函式名稱之後的括號內傳入函式所需要的參數,並將結果儲存於變數之中 — 相當類似普通函式被呼叫的方式 。各個實例均根據此定義所建立:

+ +
function Person(name) {
+  this.name = name;
+  this.greeting = function() {
+    alert('Hi! I\'m ' + this.name + '.');
+  };
+}
+ +

在建立新的物件之後,person1person2 的變數將有效率地納入下列物件:

+ +
{
+  name : 'Bob',
+  greeting : function() {
+    alert('Hi! I\'m ' + this.name + '.');
+  }
+}
+
+{
+  name : 'Sarah',
+  greeting : function() {
+    alert('Hi! I\'m ' + this.name + '.');
+  }
+}
+ +

剛剛說的「有效率」,是因為實際功能仍定義於類別中,而非物件實例之中。這情況與我們稍早談過的物件實字 (Object literal) 相反。

+ +

建立完整的建構子

+ +

上面不過是入門的簡單範例。接著繼續建立最後的 Person() 建構子。

+ +
    +
  1. 將截至目前為止的程式碼移除,加入下列取代用的建構子。原則上與簡易範例完全一樣,只是比較複雜一點: +
    function Person(first, last, age, gender, interests) {
    +  this.name = {
    +    first,
    +    last
    +  };
    +  this.age = age;
    +  this.gender = gender;
    +  this.interests = interests;
    +  this.bio = function() {
    +    alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
    +  };
    +  this.greeting = function() {
    +    alert('Hi! I\'m ' + this.name.first + '.');
    +  };
    +};
    +
  2. +
  3. 再接著加入下列程式碼,就可建立物件實例: +
    var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
    +
  4. +
+ +

現在可存取我們為第一個物件所定義的屬性與函式:

+ +
person1['age']
+person1.interests[1]
+person1.bio()
+// etc.
+ +
+

注意:如果你到這裡有點吃力,請先比較自己與我們的程式碼。可參閱 oojs-class-finished.html (也可看實際執行的情況)。

+
+ +

進階習題

+ +

在開始之前,先試著自己添加更多物件建立程式碼,再針對產生的物件實例取得並設定其成員。

+ +

此外,原來的 bio() 函式其實有點問題。即使你的「人」是女性,其輸出一定會有「He」這個代名詞。而且即使 interests 陣列中列出超過 2 個以上的「興趣」,這個 bio 函式也只會有 2 個興趣。你能試著在類別定義 (建構子) 中修正這個問題嗎?你可在建構子中放入任何你喜歡的程式碼 (但可能會需要幾個 conditionals 搭配 1 個迴圈)。想想應如何根據性別以及列出的興趣 (1 或 2 個以上),建構出不同的程式碼。

+ +
+

注意:如果你卡在這裡,我們也在 GitHub repo 上提供了解答 (立刻觀看)。先試著自己解決問題吧!

+
+ +

建立物件實例的其他方法

+ +

目前解釋了 2 種建立物件實例的方法 — 宣告物件實字,以及使用建構子函式。

+ +

當然還有別的方法,但我們希望你先熟悉此 2 種方法,以免你日後的 Web 旅程上會再遇到。

+ +

Object() 建構子

+ +

首先可使用 Object() 建構子建立新的物件。沒錯,即使是泛型物件 (Generic object) 也具備建構子,可用以產生空白物件。

+ +
    +
  1. 將下列輸入瀏覽器的 JavaScript 主控台內: +
    var person1 = new Object();
    +
  2. +
  3. 如此會在 person1 變數中儲存 1 組空白物件。接著可透過點 (dot-) 或括弧記法 (bracket notation) 為此物件新增屬性與函式。如下列範例: +
    person1.name = 'Chris';
    +person1['age'] = 38;
    +person1.greeting = function() {
    +  alert('Hi! I\'m ' + this.name + '.');
    +}
    +
  4. +
  5. 你可將一組物件實字傳送給 Object() 建構子作為參數,藉以預先填入屬性\函式。如下所示: +
    var person1 = new Object({
    +  name : 'Chris',
    +  age : 38,
    +  greeting : function() {
    +    alert('Hi! I\'m ' + this.name + '.');
    +  }
    +});
    +
  6. +
+ +

使用 create() 函式

+ +

建構子可以幫助你保持程式的可讀性 — 你可以將建構子建立在同一個地方,並根據需求從這些建構子中建立物件實例,這樣做可以讓你清楚地得知它們的來源。

+ +

不過,有些人偏好建立物件實例,而不先做建構子,尤其是他們的物件不會用很多實例時。JavaScript 有個稱作 create() 的內建函式能讓你這麼做。有了它,你就能根據現有物件,建立新的物件。

+ +
    +
  1. 在 JavaScript 主控台裡測試: +
    var person2 = Object.create(person1);
    +
  2. +
  3. 再測試以下: +
    person2.name
    +person2.greeting()
    +
  4. +
+ +

你會看到 person2 是根據 person1 所建立:它具備了相同的屬性以及可用的函式。

+ +

create() 的其中一個限制,就是 IE8 並不支援。因此,如果你需要支援舊版瀏覽器,建構子會比較有用。

+ +

我們後續會再說明 create() 的效果。

+ +

總結

+ +

本文簡略說明了 OO 理論,雖然還沒全部講完,至少也讓你初步了解到本文所要闡述的重點。此外,我們已經開始說明 JavaScript 與 OO 之間的關係、其與「傳統 OO」之間的差異、使用建構子於 JavaScript 中實作類別的方法,以及其他產生物件實例的方式。

+ +

下一篇文章將說明 JavaScript 物件原型。

+ +

{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/javascript/objects/object_building_practice/index.html b/files/zh-tw/learn/javascript/objects/object_building_practice/index.html new file mode 100644 index 0000000000..4a47aa39eb --- /dev/null +++ b/files/zh-tw/learn/javascript/objects/object_building_practice/index.html @@ -0,0 +1,283 @@ +--- +title: 物件建構實作 +slug: Learn/JavaScript/Objects/Object_building_practice +tags: + - Canvas + - JavaScript +translation_of: Learn/JavaScript/Objects/Object_building_practice +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}
+ +

我們解說完必要的 JavaScript 物件理論以及語法細節,想先幫你把根紮好。接著就透過實作範例,讓你實際建立自己有趣又多彩的 JavaScript 物件。

+ + + + + + + + + + + + +
必備條件:基礎的計算機素養、了解 HTML 與 CSS 的基本概念、熟悉 JavaScript (參閱〈First steps〉與〈Building blocks〉) 與 OOJS 基本概念 (參閱〈Introduction to objects〉)。
要點:親手實作物件與物件導向 (OO) 技術。
+ +

弄一些彈跳彩球

+ +

本文將帶領你實作經典的「彈跳球」展示網頁,讓你了解物件在 JavaScript 中的用處。這些小球會在畫面上四處彈跳,而且互相碰撞時變換顏色。範例成品如下:

+ +

+ +
    +
+ +

此範例將透過 Canvas API 在畫面上繪製球體,requestAnimationFrame API 則是繪製整個動畫;而且你不需先了解此兩個 API。但我們希望在看完本文之後,能引起大家深入探究此兩個 API 的興趣。整個過程會利用某些花俏的物件,並讓你看到幾項有趣技術,像是球體從牆上回彈,並檢查球體是否互相碰撞 (也就是碰撞偵測)。

+ +

著手開始

+ +

先複製 index.htmlstyle.cssmain.js 檔案到你的本機磁碟中。這些檔案分別具備下列:

+ +
    +
  1. 極簡的 HTML 文件,具備 1 個 {{HTMLElement("h1")}} 元素、1 個 {{HTMLElement("canvas")}} 元素可繪製彩球,以及其他元素可將 CSS 與 JavaScript 套用到 HTML 之上。
  2. +
  3. 一些極簡單的樣式,主要可作為 <h1> 的樣式風格與定位之用,並省去網頁邊緣的捲動棒或空白 (看起來更簡約)。
  4. +
  5. 某些 JavaScript 可用以設定 <canvas> 元素,另有通用函式可供我們往後使用。
  6. +
+ +

指令碼第一部分就像:

+ +
var canvas = document.querySelector('canvas');
+
+var ctx = canvas.getContext('2d');
+
+var width = canvas.width = window.innerWidth;
+var height = canvas.height = window.innerHeight;
+ +

此指令碼將為 <canvas> 元素提供參照,接著於其上呼叫 getContext() 函式,藉以提供能開始繪圖的內文 (Context)。所產生的變數 (ctx) 也就是物件,將直接呈現 canvas 的繪圖區域,讓我們繪製 2D 圖像。

+ +

接著設定 widthheight 共 2 個變數,也就是 canvas 元素的寬度與高度 (透過 canvas.widthcanvas.height 屬性呈現) 即等於瀏覽器可視區的寬度與高度 (也就是網頁顯示的區域 — 可經由 {{domxref("Window.innerWidth")}} 與 {{domxref("Window.innerHeight")}} 屬性得知)。

+ +

你會看到我們在這裡串連了多個指定式,以快速設定所有變數,而且運作無虞。

+ +

剛開始的指令碼後半部如下:

+ +
function random(min, max) {
+  var num = Math.floor(Math.random()*(max-min)) + min;
+  return num;
+}
+ +

此函式共有 2 組參數 (argument),並會回傳此範圍之內的任意值。

+ +

在程式中設定球體的模型

+ +

我們的程式會讓一堆彩球在畫面中彈來彈去。因為這些球體的行動方式均相同,所以透過物件呈現這些彩球也合情合理。先在程式碼底部加入下列建構子:

+ +
function Ball() {
+  this.x = random(0,width);
+  this.y = random(0,height);
+  this.velX = random(-7,7);
+  this.velY = random(-7,7);
+  this.color = 'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')';
+  this.size = random(10,20);
+}
+ +

這裡我們要定義某些屬性,以利彩球能在程式中動作:

+ + + +

屬性講完了,那函式呢?程式中的彩球要實際運作才行。

+ +

繪製球體

+ +

先將下列 draw() 函式加到 Ball() 的 prototype 之中:

+ +
Ball.prototype.draw = function() {
+  ctx.beginPath();
+  ctx.fillStyle = this.color;
+  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
+  ctx.fill();
+}
+ +

透過此函式,再呼叫我們之前定義在 2D canvas 內文(ctx)中的物件成員,就能讓球體自己在螢幕上畫出自己。此內文就像是白紙一樣,接著就用筆在紙上畫出點東西:

+ + + +

你已經可以開始測試自己的物件了。

+ +
    +
  1. 儲存目前的程式碼,在瀏覽器中載入此 HTML 檔案。
  2. +
  3. 開啟瀏覽器的 JavaScript 主控台,並在主控台開啟時重新整理網頁,讓 canvas 尺寸變更為左側較小型的可視區域。
  4. +
  5. 鍵入下列程式碼以建立新的球體實例: +
    var testBall = new Ball();
    +
  6. +
  7. 再呼叫其成員: +
    testBall.x
    +testBall.size
    +testBall.color
    +testBall.draw()
    +
  8. +
  9. 輸入最後一行之後,應該就能看到 canvas 上出現自己產生的球體。
  10. +
+ +

更新球體的資料

+ +

現在可以繪製彩球了。但在讓球彈跳之前,我們必須先更新幾個函式。將下列程式碼加到 JavaScript 檔案底端,把 update() 函式加到 Ball()prototype 之中:

+ +
Ball.prototype.update = function() {
+  if((this.x + this.size) >= width) {
+    this.velX = -(this.velX);
+  }
+
+  if((this.x - this.size) <= 0) {
+    this.velX = -(this.velX);
+  }
+
+  if((this.y + this.size) >= height) {
+    this.velY = -(this.velY);
+  }
+
+  if((this.y - this.size) <= 0) {
+    this.velY = -(this.velY);
+  }
+
+  this.x += this.velX;
+  this.y += this.velY;
+}
+ +

函式的前 4 個部分負責檢查球體是否碰到 canvas 邊緣。如果球體抵達邊緣,我們就反轉相對加速度的方向,讓球反方向行進。以球體向上 (正向 velX) 時為例,接著就會改變水平速度,球體也就反向運動。

+ +

在這 4 個情境中,我們:

+ + + +

在各情境中,因為 x/y 座標為球體的中心,所以我們把球體的 size 納入計算,但我們不要球體在回彈之前在半路上就跳出畫面之外。

+ +

最後 2 行則是將 velX 與 velY 值分別加入 x\y 座標之中;每次只要呼叫此函式,球體就會依照應有的效果移動。

+ +

到這裡沒有問題的話,就開始弄動畫吧!

+ +

球體動起來

+ +

接著來玩玩吧。我們要加更多球到 canvas 中並開始動畫效果。

+ +
    +
  1. 首先要弄個地方儲存所有的彩球。將下方陣列加到現有程式碼底部即可: +
    var balls = [];
    + +

    所有可提供動畫效果的程式,一般都會採用動畫迴圈,可用以更新程式中的資訊,並接著在動畫的各個畫格上繪製產生的結果。這也是大部分遊戲或類似程式的基礎。

    +
  2. +
  3. 再將下列程式碼加到現有程式碼底部: +
    function loop() {
    +  ctx.fillStyle = 'rgba(0,0,0,0.25)';
    +  ctx.fillRect(0,0,width,height);
    +
    +  while(balls.length < 25) {
    +    var ball = new Ball();
    +    balls.push(ball);
    +  }
    +
    +  for(i = 0; i < balls.length; i++) {
    +    balls[i].draw();
    +    balls[i].update();
    +  }
    +
    +  requestAnimationFrame(loop);
    +}
    + +

    我們的 loop() 函式可進行:

    + +
      +
    • 設定 canvas 填滿色彩或是半透明的黑色。接著透過 fillRect() (共 4 個參數提供起始座標,以及繪製矩形的高度與寬度),跨 canvas 的寬度與高度繪製整個矩型的色彩。如此可在繪製下一個畫格之前,先覆蓋前一個已存在的畫格;否則會看到許多隻長長的蛇爬來爬去。填充顏色已設定為半透明狀態:rgba(0,0,0,0.25) 可讓先前的畫格微微發亮,製造出球體移動時的小尾巴效果。如果將 0.25 更改為 1,就會完全消除尾巴。你可自己測試不同的數值,找出自己喜歡的效果。
    • +
    • 可對 Ball() 建立新的實作,接著將之 push() 到球體陣列的最後,且彩球數量必須少於 25 個。所以整個畫面最多顯示 25 個球。你可嘗試變更 balls.length < 25 中的數值,畫面中的彩球數量也會隨著變化。依你所用電腦\瀏覽器處理效能的不同,若繪製上千個彩球就會拖慢整個動畫的速度。
    • +
    • 迴圈將巡過 balls 陣列中的所有彩球,並執行各個彩球的 draw()update() 函式,以於畫面中逐一繪製,接著對下個畫格的位置與速度執行必要更新。
    • +
    • 再以 requestAnimationFrame() 函式執行過此函式 — 當此函式持續執行並傳送相同的函式名稱時,就會每秒執行此函式達特定次數,以產生流暢的動畫。接著重複執行此作業,也就是函式每次執行時均會呼叫自身 1 次,進而循環執行。
    • +
    +
  4. +
  5. 最後將下列程式碼加入最底端,呼叫函式 1 次讓動畫開始運作。 +
    loop();
    +
  6. +
+ +

基本就是這樣了。試著儲存並重新整理檔案,讓你的彩球開始跳動吧!

+ +

另增碰撞偵測

+ +

現在弄點有趣的東西,就把碰撞偵測 (Collision detection) 加進程式裡,讓彩球知道自己碰到其他球了。

+ +
    +
  1. 首先將下列函式定義加進你自己定義 update() 函式中 (例如 Ball.prototype.update 區塊): + +
    Ball.prototype.collisionDetect = function() {
    +  for(j = 0; j < balls.length; j++) {
    +    if( (!(this.x === balls[j].x && this.y === balls[j].y && this.velX === balls[j].velX && this.velY === balls[j].velY)) ) {
    +      var dx = this.x - balls[j].x;
    +      var dy = this.y - balls[j].y;
    +      var distance = Math.sqrt(dx * dx + dy * dy);
    +
    +      if (distance < this.size + balls[j].size) {
    +        balls[j].color = this.color = 'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')';
    +      }
    +    }
    +  }
    +}
    + +

    這函式有點複雜,所以現在不瞭解如何運作的也別擔心。解釋如下:

    + +
      +
    • 對每個彩球來說,我們必須檢查是否碰撞到其他球。所以要設定另一個 for 迴圈以循環檢視 balls[] 陣列中的所有彩球。
    • +
    • 在我們的 for 迴圈中,我們立刻使用 if 陳述式檢查「現正透過迴圈循環檢查中」的彩球,是否即為我們目前檢查中的同一彩球。我們不需要檢查彩球是否碰撞到自己!為了達到此效果,我們檢查彩球目前的 x/y 座標與速度,是否等同於迴圈檢查的彩球。接著透過「!」否定檢查,所以在 if 陳述式中的程式碼,只有在彩球相異時才會執行。
    • +
    • 接著使用一般演算法檢查 2 個球體之間的碰撞。我們基本上會檢查任 2 個球體的範圍是否重疊。另將透過〈2D 碰撞偵測〉一文進一步解釋。
    • +
    • 如果偵測到碰撞,則隨即執行內部 if 陳述式的程式碼。在本範例中,我們剛設定了 2 個球體的 color 屬性為新的隨機色彩。但當然可以更複雜點,像是讓彩球更逼真的互相反彈,但這實作起來就更複雜了。對這類的物理模擬,開發者就必須使用如 PhysicsJSmatter.jsPhaser 等的遊戲\物理函式庫。
    • +
    +
  2. +
  3. 你也可以在動畫的每一畫格中呼叫此一函式。在 balls[i].update(); 這一行下方新增下列程式碼即可: +
    balls[i].collisionDetect();
    +
  4. +
  5. 儲存並重新整理之後,就能看到球體在碰撞時變更其色彩了!
  6. +
+ +
+

注意:如果你無法讓此範例順利運作,可比較我們的最後版本 (另可參閱實際執行情形)。

+
+ +

摘要

+ +

希望你喜歡撰寫出隨機彩球碰撞範例,其內並包含我們前面說過的多樣物件與 OO 技術!本文應該已提供你有用的物件實作與絕佳的實際文本。

+ +

物件實體就到這裡。接著就是你要磨練自己的物件技術了!

+ +

另可參閱

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}

diff --git a/files/zh-tw/learn/javascript/objects/object_prototypes/index.html b/files/zh-tw/learn/javascript/objects/object_prototypes/index.html new file mode 100644 index 0000000000..9bfbc98fea --- /dev/null +++ b/files/zh-tw/learn/javascript/objects/object_prototypes/index.html @@ -0,0 +1,236 @@ +--- +title: 物件原型 +slug: Learn/JavaScript/Objects/Object_prototypes +translation_of: Learn/JavaScript/Objects/Object_prototypes +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}
+ +

JavaScript 的物件即透過原型 (Prototype) 機制相互繼承功能,且與典型的物件導向 (OO) 程式語言相較,其運作方式有所差異。我們將透過本文說明相異之處、解釋原型鍊 (Prototype chain) 運作的方式,並了解原型屬性是如何將函式新增至現有的建構子 (Constructor) 之中。

+ + + + + + + + + + + + +
必備條件:基本的電腦素養、已初步了解 HTML 與 CSS、熟悉 JavaScript (參閱〈First steps〉與〈Building blocks〉以及 OOJS 基礎概念 (參閱〈Introduction to objects〉。
主旨:了解 JavaScript 的物件原型、原型鍊的運作方式、應如何將新的函式加入原型屬性之中。
+ +

「原型」架構的程式語言?

+ +

常有人說 JavaScript 是原型架構的程式語言 — 各個物件均具備 1 組原型物件作為範本物件,用以繼承函式與屬性。物件的原型物件可能也具備原型物件,並繼承了其上的函式與屬性。這就是我們所謂的「原型鍊 (Prototype chain)」,同時正好說明為何 A 物件的屬性與函式是透過 B 物件的屬性與函式所定義。

+ +

精確點說,這些屬性與函式都是透過物件的建構子函式所定義,並非物件實例本身。

+ +

傳統的 OOP 都是先定義了類別,接著在建立物件實例之後,在類型上定義的所有屬性與函式均複製到此實例。但 JavaScript 不會複製這些屬性與函式,卻是在物件實例與其建構子之間設定連結 (原型鍊中的連結),只要順著原型鍊就能在建構子之中找到屬性與函式。

+ +

先看個範例會比較清楚點。

+ +

了解原型物件

+ +

先回到我們寫過的 Person() 建構子範例。在你的瀏覽器裡載入範例。如果你還沒看完前篇文章並製作出此範例,可先使用 oojs-class-further-exercises.html 這個範例 (可看到原始碼)。

+ +

我們在此範例中定義了建構子函式:

+ +
function Person(first, last, age, gender, interests) {
+
+  // property and method definitions
+
+};
+ +

接著建立如下的物件實例:

+ +
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
+ +

如果你在自己的 JavaScript 主控台中鍵入「person1.」,應該會看到瀏覽器根據此物件可用的成員名稱開始自動補完:

+ +

+ +

在此列表中,可以看到 person1 原型物件上所定義的成員,也就是 Person() 建構子 — nameagegenderinterestsbiogreeting。你也會看到其他如 watchvalueOf 等,同樣也是定義在 Person() 建構子原型物件之上的成員,如此構成 Object。下圖顯示原型鍊的運作方式。

+ +

+ +

所以當你在 person1 上呼叫了「實際上是定義於 Object 上的函式」,會發生什麼事呢?舉例來說:

+ +
person1.valueOf()
+ +

此函式僅回傳所呼叫的物件數值。此範例所將發生的是:

+ + + +
+

注意:再次重申,在原型鍊中的函式與屬性並不是從任一物件複製到另一個物件,而是如上述的,沿著該原型鍊向上存取而得。

+
+ +
+

注意:直接存取物件的原型物件,並沒有一定的方式。原型鍊中,項目之間的「連結」均定義於內部屬性之內,即 JavaScript 規格中的 [[prototype]] (可參閱 {{glossary("ECMAScript")}})。新版瀏覽器均具備所謂的「__proto__ (兩邊都是 2 個底線)」屬性,其中就包含了物件的原型物件。舉例來說,你可嘗試「person1.__proto__」與「person1.__proto__.__proto__」看看程式碼中的鍊會是什麼樣子!

+
+ +

原型屬性也定義所要繼承的成員

+ +

所以該在哪裡定義所要繼承的屬性與函式呢?若看一下 Object 參考頁面,你就會看到左邊列出許多屬性與函式,遠超過上方擷圖所列 person1 物件所繼承的成員數量。有些繼承了,有些則無?為什麼呢?

+ +

原因在於,繼承的成員就是在 prototype 屬性 (你也能稱之為子命名空間 sub namespace) 中定義的成員,也就是以「Object.prototype.」開頭的成員;並非只以「Object.」開頭的成員。prototype 屬性值就是 1 個物件,基本上儲存了許多我們想「讓原型鍊上的物件一路繼承下去」的屬性與函式。

+ +

所以如 Object.prototype.watch()Object.prototype.valueOf() 等等,均可用於繼承自 Object() 的任何物件類型,包含以建構子建立的新物件實例。

+ +

Object.is()Object.keys(),及其他未於 prototype 內定義的成員,也就不會繼承至 1). 物件實例或 2). 從 Object() 繼承而來的物件類型。這些函式\屬性都只能用於 Object() 建構子本身。

+ +
+

注意:這看起來很奇怪:你怎麼能在建構子上定義函式 (Method),而且這建構子本身也是函式 (Function)?其實「Function」也屬於一個物件類型,可參閱 Function() 建構子參考以進一步了解。

+
+ +
    +
  1. 你可自行檢查現有的原型屬性。回到我們之前的範例,試著於 JavaScript 主控台中輸入: +
    Person.prototype
    +
  2. +
  3. 輸出結果很平淡,畢竟我們並未在自定的建構子原型上定義任何東西。依預設值,建構子的 prototype 都是從空白開始。現在可嘗試下列: +
    Object.prototype
    +
  4. +
+ +

這樣就會看到 Objectprototype 屬性中所定義的許多函式,而繼承自 Object 的物件也能找到這些函式。

+ +

只要試著尋找如 StringDateNumberArray 等全域物件的原型上定義的函式與屬性,就會看到 JavaScript 中的其他原型鍊繼承範例。這些物件都在其原型上定義了多個成員,因此可作為你建立字串時的範例:

+ +
var myString = 'This is my string.';
+ +

myString 上立刻就有多個有用的函式,如 split()indexOf()replace() 等。

+ +
+

重要:prototype 這個屬性,是 JavaScript 中最讓人混淆的名稱之一。你可能會認為this屬性即指目前物件(current object)的原型物件(prototype object),但它其實不是原型 (應該是可透過 __proto__ 存取的內部物件(internal object)才對,記得上面說過的嗎?)。prototype是一個物件(object),內含了你定義所應該繼承的成員。

+
+ +

再次溫習 create()

+ +

我們先前講過用 Object.create() 函式建立新物件實例的方法。

+ +
    +
  1. 舉例來說,你可先在前面的 JavaScript 主控台範例中試著輸入: +
    var person2 = Object.create(person1);
    +
  2. +
  3. create() 實際上是透過特定的原型物件,來建立新的物件。我們在這裡將 person1 作為原型物件,建立了 person2。你可於主控台輸入下列以測試之: +
    person2.__proto__
    +
  4. +
+ +

如此將回傳 person1 物件。

+ +

建構子的屬性

+ +

每個物件實例都具備 1 個建構子屬性,指向「用以建立實例」的原始建構子函式。

+ +
    +
  1. 舉例來說,若在主控台中輸入下列指令: +
    person1.constructor
    +person2.constructor
    + +

    應該兩者都會回傳 Person() 建構子,因為此建構子包含這些實例的原始定義。

    + +

    偷吃步的方法,是將圓括弧加到 constructor 屬性 (須包含任何必要參數) 末端,以從該建構子建立其他物件實例。畢竟建構子也是函式 (Function),所以可透過圓括弧將之觸發。你只要納入 new 這個關鍵字,即可將此函式作為建構子。

    +
  2. +
  3. 在主控台中輸入: +
    var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);
    +
  4. +
  5. 現在可試著存取新物件的功能,例如: +
    person3.name.first
    +person3.age
    +person3.bio()
    +
  6. +
+ +

這樣運作得還不差。你不需常常用這方法,但當你要建立新的實例,又因為某些原因找不到原始建構子的參照,這就特別有用了。

+ +

此外,constructor 屬性還有其他用處。舉例來說,如果你有個物件實例,並要回傳建構子 (本身就是實例) 的名稱,就透過:

+ +
instanceName.constructor.name
+ +

也可嘗試:

+ +
person1.constructor.name
+ +

修改原型

+ +

先看看建構子的 prototype 屬性的修改範例:

+ +
    +
  1. 回到 oojs-class-further-exercises.html 範例,先在本機儲存 1 份原始碼的副本。在現成的 JavaScript 中加入下列程式碼,即是將新函式新增到建構子的 prototype 屬性: + +
    Person.prototype.farewell = function() {
    +  alert(this.name.first + ' has left the building. Bye for now!');
    +}
    +
  2. +
  3. 儲存程式碼並在瀏覽器中載入頁面,再輸入下列程式碼: +
    person1.farewell();
    +
  4. +
+ +

這時應該會看到警示訊息且內含了建構子所定義的人名。這樣很有用,但如果能動態更新整個繼承鍊,且從建構子分割出來的所有物件實例都能使用此新的函式,就會更有用!

+ +

花個 1 分鐘想想,我們的程式碼中定義了建構子,然後根據建構子建立實例物件,接著將新函式添增到建構子的原型:

+ +
function Person(first, last, age, gender, interests) {
+
+  // property and method definitions
+
+};
+
+var person1 = new Person('Tammi', 'Smith', 32, 'neutral', ['music', 'skiing', 'kickboxing']);
+
+Person.prototype.farewell = function() {
+  alert(this.name.first + ' has left the building. Bye for now!');
+}
+ +

但是 farewell() 函式仍可用於 person1 物件實例,其可用的功能已自動更新過。如此證明了我們之前對原型鍊的說明,也代表瀏覽器會沿著鍊往上找「尚未於物件實例上定義的函式」,而非「複製到實例中的函式」。如此可建構強大且靈活的系統。

+ +
+

注意:如果你在讓此範例運作時感覺有點困難,可參閱 oojs-class-prototype.html 範例 (也可看即時運作的情形)。

+
+ +

你很少會看到在 prototype 屬性上定義的屬性,因為照此範例定義的屬性彈性較低,舉例來說,你可新增如下的屬性:

+ +
Person.prototype.fullName = 'Bob Smith';
+ +

但因為幾乎不會有人取這名字,所以就沒什麼彈性。最好可以在 name.firstname.last 之外建立 fullName:

+ +
Person.prototype.fullName = this.name.first + ' ' + this.name.last;
+ +

但因為這樣會參照全域範圍,而非函式範圍,所以也不適用。若呼叫此屬性,則將回傳 undefined undefined。這種模式適合我們先前於原型中定義的函式,因為該函式就是在功能範圍之內,且可成功轉移至物件實例的的範圍。因此你可能會在原型中定義常數屬性 (也就是永遠不需更改的屬性),但一般來說會比較適合在建構子中定義屬性。

+ +

事實上,許多物件定義較常見的模式,就是在建構子中定義屬性,而在原型中定義函式。這樣一來,建構子只有屬性定義;函式則切分到不同的區塊,讓整個程式碼較清楚易讀。舉例來說:

+ +
// Constructor with property definitions
+
+function Test(a,b,c,d) {
+  // property definitions
+};
+
+// First method definition
+
+Test.prototype.x = function () { ... }
+
+// Second method definition
+
+Test.prototype.y = function () { ... }
+
+// etc.
+ +

你可在 Piotr Zalewa 的「school plan app」範例中看到實際運作的範例。

+ +

摘要

+ +

本文說明了 JavaScript 物件原型,包含原型物件鍊是如何讓物件能互相繼承其特性、原型屬性的本質、原型屬性又是如何能將函式新增至建構子,以及其他相關概念。

+ +

接著我們將讓你在自己的任 2 個自訂物件之間,實作功能的繼承。

+ +

{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}

diff --git a/files/zh-tw/learn/performance/index.html b/files/zh-tw/learn/performance/index.html new file mode 100644 index 0000000000..9cd34ae5a9 --- /dev/null +++ b/files/zh-tw/learn/performance/index.html @@ -0,0 +1,124 @@ +--- +title: Web performance +slug: Learn/Performance +tags: + - CSS + - HTML + - HTTP + - JavaScript + - Learn + - NeedsTranslation + - Performance + - TopicStub + - Web Performance +translation_of: Learn/Performance +--- +

{{LearnSidebar}}{{draft}}

+ +

Building websites requires HTML, CSS, and JavaScript. To build websites and applications people want to use, which attract and retain users, you need to create a good user experience. Part of good user experience is ensuring the content is quick to load and responsive to user interaction. This is known as web performance, and in this module you'll learn all you need to build performant websites.

+ +

Web performance is the objective measurement and the perceived user experience of load time and runtime. Web performance is how long a site takes to load, become interactive and responsive, and how smooth the content is during user interactions. Is the scrolling smooth? Are buttons clickable? Are pop-ups quick to open up, and do they animate smoothly as they do so? Web performance includes both objective measurements like time to load, frames per second, and time to interactive, and subjective experiences of how long it felt like it took the content to load.

+ +

Many features impact performance including latency, application size, the number of DOM nodes, the number of resource requests made, JavaScript performance, CPU load, and more.  It is important to minimize the loading and response times, and add additional features to conceal latency by making the experience as available and interactive as possible, as soon as possible, while asynchronously loading in the longer tail parts of the experience.

+ +

Web performance involves measuring the actual and perceived speeds of an application, optimizing where possible, and then monitoring the performance, to ensure that what you've optimized stays optimized.

+ +

There are tools, APIs, and best practices that help us measure, improve performance, and monitor performance. We'll look at these too in the course of this module.

+ +

Learning pathway

+ +

While knowing HTML, CSS, and JavaScript is needed for implementing many web performance improvement recommendations, knowing how to build applications is not a necessary pre-condition for understanding and measuring web performance.

+ +

Several of the introductory modules below do not require programming knowledge, though an understanding of HTML is needed for the HTML and performance module, an understanding of CSS is needed for the CSS and performance module, etc. We recommend that you work through our introductory modules first, starting with what is web performance first. The introductory modules provide an overview of web performance. The first three should be considered required reading whether you are a developer or project manager. The tech topic focused modules are more appropriate for developers using these technologies.

+ +

The advanced modules delve deeper into topics overviewed in the introductory modules and provide overviews of performance APIs, testing and analysis tools, and performance bottleneck gotchas.

+ +

It is recommended that you work through Getting started with the web before proceeding with this topic. However, doing so isn't absolutely necessary.

+ +

Introductory modules

+ +

This topic contains the following modules, in a suggested order for working through them. You should definitely start with the first one.

+ +
+
What is web performance?
+
This article starts the module off with a good look at what performance actually is — this includes the tools, metrics, APIs, networks, and groups of people we need to consider when thinking about performance, and how we can make performance part of our web development workflow.
+
How do users perceive performance?
+
+

More important than how fast your website is in milliseconds, is how fast your users perceive your site to be. These perceptions are impacted by actual page load time, idling, responsiveness to user interaction, and the smoothness of scrolling and other animations. In this article, we discuss the various loading metrics, animation, and responsiveness metrics, along with best practices to improve user perception, if not the actual timings.

+
+
Web performance basics
+
In addition to the front end components of HTML, CSS, JavaScript, and media files, there are features that can make applications slower and features that can make applications subjectively and objectively faster. There are many APIs, developer tools, best practices, and bad practices relating to web performance. Here we'll introduce many of these features ad the basic level and provide links to deeper dives to improve performance for each topic.
+
HTML performance features
+
Some attributes and the source order of your mark-up can impact the performance or your website. By minimizing the number of DOM nodes, making sure the best order and attributes are used for including content such as styles, scripts, media, and third-party scripts, you can drastically improve the user experience. This article looks in detail at how HTML can be used to ensure maximum performance.
+
Multimedia: images and video
+
The lowest hanging fruit of web performance is often media optimization. Serving different media files based on each user agent's capability, size, and pixel density is possible. Additional tips like removing audio tracks from background videos can improve performance even further. In this article we discuss the impact video, audio, and image content has on performance, and the methods to ensure that impact is as minimal as possible.
+
Responsive Images
+
While optimizing images is vital to high-performance media-rich user experiences, ensuring that images are sized appropriately for the devices that download them is especially important. In this article, we'll discuss the role of native browser features such as the <picture> element and the srcset attribute in efficient image delivery, and how you can use them with confidence.
+
Alternative media formats
+
When it comes to images and videos, there are more formats than you're likely aware of. Some of these formats can take your highly optimized media-rich pages even further by offering additional reductions in file size. In this guide we'll discuss some alternative media formats, how to use them responsibly so that non-supporting browsers don't get left out in the cold, and some advanced guidance on transcoding your existing assets to them.
+
CSS performance features
+
CSS may be a less important optimization focus for improved performance, but there are some CSS features that impact performance more than others. In this article we look at some CSS properties that impact performance and suggested ways of handling styles to ensure performance is not negatively impacted.
+
JavaScript performance best practices
+
JavaScript, when used properly, can allow for interactive and immersive web experiences — or it can significantly harm download time, render time, in-app performance, battery life, and user experience. This article outlines some JavaScript best practices that should be considered to ensure even complex content is as performant as possible.
+
Web font performance
+
An often overlooked aspect of performance landscape are web fonts. Web fonts are more prominent in web design than ever, yet many developers simply embed them from a third party service and think nothing of it. In this article, we'll covers methods for getting your font files as small as possible with efficient file formats and sub setting. From there, we'll go on to talk about how browsers text, and how you can use CSS and JavaScript features to ensure your fonts render quickly, and with minimal disruption to the user experience.
+
+ +
+
Mobile performance
+
With web access on mobile devices being so popular, and all mobile platforms having fully-fledged web browsers, but possibly limited bandwidth, CPU and battery life, it is important to consider the performance of your web content on these platforms. This article looks at mobile-specific performance considerations.
+
+ +

In this section

+ +

{{LandingPageListSubpages}}

+ +

Advanced Modules

+ +
+
Populating the page
+
An HTTP request is made and, hopefully, a few seconds later, the site appears. Displaying the content involves executing JavaScript, possibly modifying the DOM, calculating styles, calculating layout, and finally rendering the content, which involves painting and compositing, and can involve GPU acceleration on a separate thread.
+
Performance bottlenecks
+
+
Understanding latency
+
+

Latency is the amount of time it takes between the browser making a request for a resource, and the browser receiving back the first byte of the resource requested. This article explains what latency is, how it impacts performance, and how to measure and improve latency.

+
+
Understanding bandwidth
+
+

Bandwidth is the amount of data (measured in Mbps or Kbps) that can be sent per second. This article explains the role of bandwidth in media-rich internet applications, how it can be measured, and how you can optimize applications to make the best use of available bandwidth.

+
+
HTTP/2 and you
+
+

The transport layer—that is, HTTP—is utterly essential to the functioning of the web, and it has only been relatively recently that it has seen a major update in the form of HTTP/2. Out of the box, HTTP/2 provides many performance improvements and advantages over its predecessor, but it also changes the landscape. In this article, you'll learn what HTTP/2 does for you, and how to fine-tune your application to make it do go even further.

+
+
The role of TLS in performance
+
+

TLS—or HTTPS as we tend to call it—is crucial in creating secure and safe user experiences. While hardware has reduced the negative impacts TLS has had on server performance, it's still represents a substantial slice of the time we spend waiting for browsers to connect to servers. This article explains the TLS handshake process, and offers some tips for reducing this time, such as OCSP stapling, HSTS preload headers, and the potential role of resource hints in masking TLS latency for third parties.

+
+
Profiling with the built-in profiler
+
Learn how to profile app performance with Firefox's built-in profiler.
+
Reading performance charts
+
Developer tools provide information on performance, memory, and network requests. Knowing how to read  waterfall charts, call trees, traces, flame charts , and allocations in your browser developer tools will help you understand waterfall and flame charts in other performance tools.
+
CSS and JavaScript animation performance
+
Animations are critical for a pleasurable user experience. This article discusses the performance differences between CSS and JavaScript-based animations.
+
Analyzing JavaScript bundles
+
No doubt, JavaScript is a big part of modern web development. While you should always strive to reduce the amount of JavaScript you use in your applications, it can be difficult to know where to start. In this guide, we'll show you how to analyze your application's script bundles, so you know what you're using, as well how to detect if there are duplicated scripts between bundles in your app.
+
Lazy-loading JavaScript with dynamic imports
+
When developers hear the term "lazy loading", they immediately think of below-the-fold imagery that loads when it scrolls into the viewport. But did you know you can lazy load JavaScript as well? In this guide we'll talk about the dynamic import() statement, which is a feature in modern browsers that loads a JavaScript module on demand. Of course, since this feature isn't available everywhere, we'll also show you how you can configure your tooling to use this feature in a widely compatible fashion.
+
+ +
+
Controlling resource delivery with resource hints
+
Browsers often know better than we do when it comes to resource prioritization and delivery—but they're far from clairvoyant. Native browser features enable us to hint to the browser when it should connect to another server, or preload a resource before the browser knows it ever needs it. When used judiciously, this can make fast experience seem even faster. In this article, we cover native browser features like rel=preconnect, rel=dns-prefetch, rel=prefetch, and rel=preload, and how to use them to your advantage.
+
DNS-Prefetch
+
+ +

See Also

+ + + +

{{LandingPageListSubpages}}

diff --git "a/files/zh-tw/learn/performance/\345\244\232\345\252\222\351\253\224/index.html" "b/files/zh-tw/learn/performance/\345\244\232\345\252\222\351\253\224/index.html" new file mode 100644 index 0000000000..cbd3d8e23a --- /dev/null +++ "b/files/zh-tw/learn/performance/\345\244\232\345\252\222\351\253\224/index.html" @@ -0,0 +1,130 @@ +--- +title: '多媒體: 圖像跟影片' +slug: Learn/Performance/多媒體 +translation_of: Learn/Performance/Multimedia +--- +

媒體,換句話說就是圖像跟影片,平均占了網站超過70%的下載流量。以下載的效能來考慮的話,減少媒體數量和檔案大小是一個簡單可以實現的目標。 這篇文章聚焦在優化圖像跟影片來改善網站的效能。

+ +
+

這是一篇進階的在 web 上優化多媒體的介紹,包含基本的原則還有技巧,想了更多的話,可以看  https://images.guide

+
+ +

為什麼要優化你的多媒體

+ +

對於平均的網站, 51% 的頻寬消耗來自圖像, 而影像則是 25%,所以我們可以說處理和優化你的多媒體是很重要的。

+ +

你必須考慮流量的使用. 很多的人都是使用流量有限制的上網方案, 或是用多少付多少的上網方案,也就是根據用了多少 MB 來付費。這樣的問題不是只發生在新興國家的市場. 在 2018 年, 英國仍有 24% 在使用「用多少付多少」的方案

+ +

你還需要考慮記憶體的問題,因為許多移動設備的 RAM 都有限。有一件很重要的事你必須要記住,下載的圖像是被儲存在記憶體裡的。

+ +

優化圖像傳送

+ +

儘管是頻寬的最大消耗者,但因為圖像是非同步載入的,所以訪問者可以在下載的同時看到頁面。因此,它們對感知性能的影響遠低於許多人的預期。 然而,圖像在內容中很常被使用,因此,重要的應該是讓訪問者盡快地看到它們,以獲得良好的體驗。

+ +

載入策略

+ +

對於大多數網站來說,最大改進之一是將不在視窗裡的圖像做 lazy-loading ,而不是在初始頁面載入時就全部下載下來,不管訪問者是否之後會往下滾動查看它們。 許多 JavaScript 函式庫都可以為你實現這個功能,例如說 lazysize,並且瀏覽器的供應商也正在著手原生的 lazyload 屬性,然而目前還處於實驗階段。

+ +

除了載入圖像的子集之外,接下來您還應該研究一下圖像本身的格式:

+ + + +

最佳格式

+ +

這非常值得用一個章節來介紹。因為為圖像選擇正確的格式可能很棘手。格式通常取決於圖像的用途:

+ + + +

優先在不需要移動卷軸就能看到的網頁區域使用 Progressive JPEG 的原因是因為它們會逐漸地進行渲染(因此得名),這意味著用戶可以先看到低解析度的版本,然後再逐漸地變得清晰。而不是從頂部一行一行的以最高解析度來載入圖像,或甚至只有在完全下載好後才顯示。

+ +

控制下載圖像的優先級別(和順序)

+ +

將最重要的圖像更早地呈現在訪問者面前,可以改善感知性能。

+ +

第一件要確認的事情是,你的前景圖像標籤 <img /> 跟你定義在 CSS 裡 background-image 的背景圖像 — 前景圖像比背景圖像被賦予更高的優先級別。

+ +

其次,通過採用優先級別提示,你可以在圖像標籤中添加importance 屬性來進一步控制優先級別。輪播是一個在圖像上使用優先級別提示的例子,它的第一個圖像的優先級高於其他的圖像。

+ +

渲染策略

+ +

由於圖像是非同步載入的,並且會在第一次渲染後繼續載入,因此,如果在載入之前未定義尺寸的話,則可能會導致頁面內容的重新編排。比如說,當圖像載入時,文字內容可能會被擠壓到下面。所以, 很重要的是,定義 width 跟 height 或是新的 intrinsicsize 屬性。

+ +

對於任何的背景圖像,設置 background-color 的值非常重要,因為在圖像下載之前,它能讓上面的內容是能夠被閱讀的。

+ +

優化影像傳送

+ +

為了確保您不會將不必要的大文件發送給用戶,最好 壓縮所有你要傳輸的影像優化<source> 順序, 設定 autoplay移除靜音影像的聲音, 優化影像預載, 還有 考慮串流 這部影像。

+ +

壓縮所有影像

+ +

大多數的影像壓縮工作都包含,比較影像裡的相鄰幀,並刪除原始幀和後續幀中相同的細節。你想同時壓縮影像並將其匯出為多種影像格式, 包含 WebM,MPEG-4/H.264,以及 Ogg/Theora.

+ +

你用來創建影像的軟體可能包含優化檔案大小的功能。如果沒有的話,那麼可以考慮幾種線上工具,像是之後篇章會討論的 FFmpeg,他可以協助編碼,解碼,轉換,以及呈現其他神奇的功能。

+ +

優化 <source> 順序

+ +

從最小到最大來排序影像的來源。例如說,給定三個壓縮影像,分別為 10 MB,12MB,以及13MB, 把最小的擺在第一個,最大的擺在最後一格。

+ +
<video width="400" height="300" controls="controls">
+  <!-- WebM: 10 MB -->
+  <source src="video.webm" type="video/webm" />
+  <!-- MPEG-4/H.264: 12 MB -->
+  <source src="video.mp4" type="video/mp4" />
+  <!-- Ogg/Theora: 13 MB -->
+  <source src="video.ogv" type="video/ogv" />
+</video>
+ +

就順序的角度來說,瀏覽器會下載它看到的第一個影像來源,因此先讓他載入一個較小的影像。就"最小"的角度來說,要確認你的壓縮影響仍然看起來不會太糟。有幾個演算法可能會讓你的影像看起來像是個會動的 gif 。雖然 128 Kb 的影像可能在用戶體驗上會比 10 MB 的影像好,可是把看起來像是 gif 粒狀的影像放在內容後面,也可能會對你的品牌產生負面影響。

+ +

查看 CanIUse.com 來確認現今瀏覽器對於影像以及不同媒體格式的支持。  

+ +

影像自動播放

+ +

為了確保循環播放背景影像,你需要向影像標籤裡添加多個屬性: autoplay, muted, 以及 playsinline.

+ +
<video autoplay="" loop="" muted="true" playsinline="" src="backgroundvideo.mp4">
+ +

雖然屬性 loop 和 autoplay 在對於影像的循環跟自動播放很合理,可是 muted 屬性在行動裝置的瀏覽器裡是必須添加的。

+ +

Playsinline 在行動裝置裡的 Safari 是必須的,他讓影像可以在不需要全螢幕的模式下被播放。

+ +

移除靜音影像的聲音

+ +

如果你有一個 hero-video 或是其他靜音影片, 請將聲音從影像中移除。 

+ +
<video autoplay="" loop="" muted="true" playsinline="" id="hero-video">
+  <source src="banner_video.webm"
+          type='video/webm; codecs="vp8, vorbis"'>
+  <source src="web_banner.mp4" type="video/mp4">
+</video>
+ +

這段 hero-video 代碼, 常出現在許多研討會網站以及公司的主頁, 它是個包括自動播放,循環播放和靜音的影像。它不包含任何控制選單,因此無法收聽聲音。通常它是沒有聲音的,但仍然存在音軌,因此它仍會消耗頻寬。然而,我們沒有理由將頻寬分給靜音影像的聲音。移除聲音可以節省 20% 的頻寬。這代表,如果你的影像是 10 MB,則節省了 2 MB。

+ +

根據您的影像創作軟體,你也許可以在匯出和壓縮過程中刪除聲音。 如果沒有,那麼有一個免費的工具 FFmpeg ,可以使用以下指令來為你完成此任務

+ +
ffmpeg -i original.mp4 -an -c:v copy audioFreeVersion.mp4
+ +

FFmpeg 稱自己為"用於記錄,轉換和串流音頻和影像的完整,跨平台解決方案"。

+ +

影像預載

+ +

preload 屬性具有3個可用選項:auto|metadata|none。預設選項是 metadata.

+ +

將選項更改為 auto 會告訴瀏覽器自動下載整個影像。僅有在極有可能播放時才應該執行此操作,否則會浪費大量的頻寬。

+ +

preload="metadata" 最多可讓 3% 的影像在頁面加載時被下載。 然後對於較大的影像來說,這可能或是大量的頻寬。

+ +

preload="none" 不會在播放之前下載任何的影像。 這會延遲影像的啟動時間,但能夠為播放可能性較低的影像保存大量的頻寬。

+ +

考慮串流

+ +

串流影像讓適當的影像大小和頻寬 (根據網路速度) 被傳遞給用戶。 就像使用響應式圖像一樣,正確大小的影像將被傳遞到瀏覽器,從而確保用戶的快速影像啟動、低緩衝以及優化的播放。

diff --git a/files/zh-tw/learn/server-side/django/admin_site/index.html b/files/zh-tw/learn/server-side/django/admin_site/index.html new file mode 100644 index 0000000000..2fce622972 --- /dev/null +++ b/files/zh-tw/learn/server-side/django/admin_site/index.html @@ -0,0 +1,354 @@ +--- +title: 'Django Tutorial Part 4: Django admin site' +slug: Learn/Server-side/Django/Admin_site +translation_of: Learn/Server-side/Django/Admin_site +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}
+ +

現在,我們已經為本地圖書館網站 LocalLibrary 創建了模型,我們接下來使用 Django 管理網站,去添加 一些 “真實的“ 書本數據。首先,我們展示如何用管理網站註冊模型,然後展示如何登錄和創建一些數據。本文最後,我們介紹可以進一步改進管理網站的建議。

+ + + + + + + + + + + + +
前提:先完成: Django Tutorial Part 3: Using models.
目標: +

了解 Django 管理站的優點與侷限,並使用它來為我們的模型新增一些資料。

+
+ +

概覽

+ +

Django 管理應用程序可以使用您的模型,自動構建可用於創建,查看,更新和刪除記錄的網站區域。這可以在開發過程中,節省大量的時間,從而很容易測試您的模型,並了解您是否擁有正確的數據。根據網站的類型,管理應用程序也可用於管理生產中的數據。 Django 項目建議僅用於內部數據管理(即僅供管理員或組織內部人員使用),因為以模型為中心的方法,不一定是所有用戶最好的界面,並且暴露了大量不必要的關於模型的細節。

+ +

創建基礎項目時,自動完成所有的配置文件,包含您的網站中的管理應用程序在內(有關所需實際依賴關係的信息,如有需要請看 Django docs here)。其結果是,要將模型添加到管理應用程序,你必須做的,僅僅是註冊他們。在本文末尾,我們將簡要介紹,如何進一步配置管理區域,以更好地顯示我們的模型數據。

+ +

註冊模型後,我們將展示,如何創建一個新的 “超級用戶”,登錄到該網站,並創建一些書籍,作者,書籍實例和書籍類別。這些將有助於測試我們將在下一個教程中,開始創建的視圖和模板。

+ +

註冊模型(Registering models )

+ +

首先,我們從 catalog app 中打開 admin.py (/locallibrary/catalog/admin.py),目前它長的像下面區塊,注意它已經幫你導入 django.contrib.admin

+ +
from django.contrib import admin
+
+# Register your models here.
+ +

將下方的程式碼複製貼在 admin.py 文件下方以註冊所有模型,這段程式碼簡單來說就是先將模型導入,再呼叫 admin.site.register 函式來註冊每個模型。

+ +
from .models import Author, Genre, Book, BookInstance
+
+admin.site.register(Book)
+admin.site.register(Author)
+admin.site.register(Genre)
+admin.site.register(BookInstance)
+ +
注意:如果你在上一章節最後有接受挑戰並建立一個書本的「語言模型」 (查看模型教學文章),你必需也要導入並註冊該模型!
+ +

這是註冊模型最簡單的方式。

+ +

而管理站則是高度用戶化的,我們會在接下來繼續說明其它註冊你的模型的方式。

+ +

創建超級用戶(Creating a superuser)

+ +

為了能夠登入管理站,我們需要一個有啟用員工狀態(Staff status)的使用者帳號,另外為了要能檢視與產生資料,我們也需要讓這個使用者帳號擁有管理所有物件的權限,因此,你可以透過 manage.py 來創建一個擁有所有網站存取權限的超級用戶(superuser)。

+ +

在與 manage.py 同一個資料夾中執行下方指令,建立一個超級用戶,你會被提示要輸入「使用者名稱」、「使用者 e-mail」和「強度夠高的密碼」。

+ +
python3 manage.py createsuperuser
+ +

當完成指令輸入後,一個新的超級用戶就會被加進資料庫中,再來只要重新啟動開發用 server ,你便可以進行登入測試:

+ +
python3 manage.py runserver
+
+ +

登入並開始使用網站

+ +

要登入網站,必須先連上  /admin URL (e.g. http://127.0.0.1:8000/admin) 並且輸入你的超級用戶的使用者名稱與密碼(你會被重新導向登入頁面,輸入你的帳密後會再回到  /admin URL)。

+ +

網站中的這部分羅列了所有以我們安裝的 app 分組的模型,你可以點擊模型名稱進入陳列所有與其相關連資料的頁面,而你可以進一步編輯它們,或者你也可以直接點擊模型名稱旁邊的 Add 連結來開始創建該類型的資料。

+ +

Admin Site - Home page

+ +

點擊 Books 右邊的 Add 連結來新增一本新書(會產生如下方的對話方塊),可以去觀察每個字段(field)、小部件、提示文字(如果有的話)是如何對應到你的模型的。

+ +

在字段中輸入值,你可以透過各個字段旁邊的 + 按鈕來新增「作者」或「書籍類別」(或者從列表中選擇你已經新增的值),當你完成後可以點選 SAVE, Save and add another, 或 Save and continue editing 來儲存該筆資料。

+ +

Admin Site - Book Add

+ +
+

注意:在這邊我們希望你花點時間在你的 app 中新增一些書本、作者和書及類型(例如:奇幻等)。請確保每位作者與每種書籍類型都分別關聯了一本以上的書(這在文章稍後的實作的時候,會讓你的列表與細節視圖更加豐富有趣)

+
+ +

當你新增完書本後,點擊上方書籤的 Home 連結回到主要管理頁面,接著點擊 Books 連結來展示目前的書本清單(你也可以點及其他連結看看其他模型的列表),現在你已經加了幾本書,畫面應該會與下方截圖類似,你可以看到下方陳列了每本書的標題,這是我們在上一篇文章所提到的 Book 模型中的 __str__() 方法所回傳的值。

+ +

Admin Site - List of book objects

+ +

在列表中,如果要刪掉你不想要的書,只需要先勾選欲刪除書本的勾選方框,從動作下拉選單選擇刪除動作(delete action),接著點選 GO 按鈕即可,另外你也可以點選 ADD BOOK 按鈕來新增一本書。

+ +

你可以點擊書名來編輯它,下方顯示的書本編輯頁面幾乎與 Add 頁面相同,主要差異在於頁面的標題(Change book)以及增加了 Delete, HISTORY 和 VIEW ON SITE 按鈕(會有這個按鈕出現是因為我們之前在模型中有定義了 get_absolute_url() 的方法)

+ +

Admin Site - Book Edit

+ +

現在透過頁面上方的索引連結回到 Home 頁面,然後看看 Author 和 Genre 列表,你在新增書本的時候應該已經新增了一些資料,不過你還可以再新增更多。

+ +

你還沒有任何書本實例(Book Instances),因為這不會在建立書本時就產生(但你可以在新增 BookInstance 資料時新增 Book  ,這是 ForeignKey 字段的性質)。現在回到 Home 頁面然後點擊 Book instances 的 Add 按鈕,畫面會呈現如下圖的頁面,注意第一列有個很長、全域唯一的 id 編碼,它可以用來區分每本書在圖書館裡的每個副本。

+ +

Admin Site - BookInstance Add

+ +

幫你的每本書都新增幾筆不同的資料,有些資料的狀態(Status)請設成 Available ,有些則設成 On loan,如果狀態為 not Available,那記得需要設定到期日(Due back date)。

+ +

就是這樣!你現在已經學會了如何建立與使用管理站(administration site),你也為你的 Book, BookInstance, Genre, 和 Author 模型建立了幾筆資料,再來當我們建立好視圖(Views)以及模板(Templates)後,就會開始來使用它們。

+ +

進階組態(Advanced configuration)

+ +

Django 在「透過註冊模型的資訊建立管理站」這方面做得非常好:

+ + + +

你可以進一步訂製介面讓它更好用,以下是你可以進一步做的:

+ + + +

這部分我們將要來看幾個有助於改善 LocalLibrary 介面的小變化,包含了添加更多資訊到 Book 和 Author 模型列表,以及改善編輯視圖的排版。我們不會改變 Language 和 Genre 的模型外貌因為他們都各只有1個字段,這樣做沒好處!

+ +

你可以在 The Django Admin site (Django Docs) 找到關於管理站訂製選擇的完整參考。

+ +

註冊一個 模型管理 類別 (ModelAdmin class)

+ +

為了要改變模型在管理站的陳列方式,你需要定義一個模型管理(ModelAdmin)類別 (他是用來描述排版的),並且將它與其他模型一起註冊。

+ +

我們現在先從 Author 模型開始。打開 catalog app 中的 admin.py 檔案(/locallibrary/catalog/admin.py),並將先前註冊 Author 模型的程式碼註解(在程式碼前面加一個 # 前綴):

+ +
# admin.site.register(Author)
+ +

現在加上一個新的 AuthorAdmin 類別與註冊函式,如下方所示:

+ +
# Define the admin class
+class AuthorAdmin(admin.ModelAdmin):
+    pass
+
+# Register the admin class with the associated model
+admin.site.register(Author, AuthorAdmin)
+
+ +

現在我們要為 Book 以及 BookInstance 模型添加 ModelAdmin 類別,我們一樣要先把原本的註冊程式碼註解:

+ +
#admin.site.register(Book)
+#admin.site.register(BookInstance)
+ +

現在我們要創造並註冊新的模型;為了達到示範的目的,我們會使用 @register 裝飾器替代先前做法來註冊模型(這跟 admin.site.register() 的語法做的事情完全一樣):

+ +
# Register the Admin classes for Book using the decorator
+@admin.register(Book)
+class BookAdmin(admin.ModelAdmin):
+    pass
+
+# Register the Admin classes for BookInstance using the decorator
+@admin.register(BookInstance)
+class BookInstanceAdmin(admin.ModelAdmin):
+    pass
+ +

目前為止我們的管理類別都是空的(可以看到 "pass"),所以我們的管理行為都不會改變!現在我們可以來進一步定義我們的「特定模型的管理行為」。

+ +

配置列表視圖(Configure list views)

+ +

我們的 LocalLibrary 目前條列出所有作者,而他們都是使用以模型的 __str__() 方法產生的物件名稱。如過你只有少數幾個作者,那倒還好,但如果作者很多,你最後可能會有非常多副本。因此為了區別他們,或者你只是想呈現更多作者的有趣訊息,你可以使用「列表展示」(list_display)來位視圖添加額外的字段。

+ +

將你的 AuthorAdmin 類別以下方程式碼取代。下方程式碼可以看出來,列表中被展示出來的字段名稱會被以需要的排序宣告為元組(tuple)形式。

+ +
class AuthorAdmin(admin.ModelAdmin):
+    list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')
+ +

現在把網站導向作者列表,上方所設定的字段應該會被陳列出來,如下:

+ +

Admin Site - Improved Author List

+ +

至於我們的 Book 模型,我們將額外添加 author 和 genre 兩樣。author 是一個ForeignKey 外鍵字段(一對一)關係,因此他將會透過關聯紀錄的 __str__() 值來表示。

+ +

將 BookAdmin 類別以下方區段程式碼取代:

+ +
class BookAdmin(admin.ModelAdmin):
+    list_display = ('title', 'author', 'display_genre')
+ +

很不幸地,我們無法直接在 list_display 中指定「書籍類別」(genre field)字段,因為它是一個 ManyToManyField (多對多字段),因為如果這樣做會造成很大的資料庫讀寫「成本」,所以 Django 會預防這樣的狀況發生,因此,取而代之,我們將定義一個 display_genre 函式以「字串」形式得到書籍類別。(下方有定義此函式)

+ +
+

Note: Getting the genre may not be a good idea here, because of the "cost" of the database operation. We're showing you how because calling functions in your models can be very useful for other reasons — for example to add a Delete link next to every item in the list.

+
+ +

將以下程式碼添加到Book模型(models.py)。 這會從genre記錄的的頭三個值(如果有的話)創建一個字符串, 和創建一個在管理者網站中出現的short_description標題。

+ +
    def display_genre(self):
+        """Create a string for the Genre. This is required to display genre in Admin."""
+        return ', '.join(genre.name for genre in self.genre.all()[:3])
+
+    display_genre.short_description = 'Genre'
+
+ +

保存模型並更新管理員後,打開您的網站並轉到“Books”列表頁面; 您應該會看到類似以下的書籍清單:

+ +

Admin Site - Improved Book List

+ +

Genre 模型(如果定義了語言模型,則還有 Language 模型)都有一個欄位,因此沒有必要為它們創建其他模型以顯示欄位。

+ +
+

注意: 更新 BookInstance 模型列表用來顯示狀態和預期的返回日期是有價值的。 我們在本文結尾處添加了一個挑戰!

+
+ +

加入列表過濾器 (List Filter)

+ +

當你的列表有很多個記錄時, 加入列表過濾器可以幫助你過濾想顯示的記錄。加入list_filter這個屬性就可以。請用以下的程式碼來取代原本的 BookInstanceAdmin 類別

+ +
class BookInstanceAdmin(admin.ModelAdmin):
+    list_filter = ('status', 'due_back')
+
+ +

現在的列表視圖右邊會多了一個過濾器。你可以選擇 dates 和 status 來做過濾:

+ +

Admin Site - BookInstance List Filters

+ +

組織詳細視圖佈局

+ +

默認情況下,局部視圖按照模型中聲明的順序垂直排列所有字段。 您可以更改聲明的順序,顯示(或排除)哪些字段,使用分段來組織資訊,水平顯示還是垂直顯示字段,甚至管理表單中使用哪些編輯小部件。

+ +
+

注意:  LocalLibrary 模型相對簡單,因此我們無須更改佈局。 但我們仍然會進行一些更改,向您展示如何進行。

+
+ +

控制那些欄位顯示並佈置

+ +

更新你的 AuthorAdmin 類別用來新增 fields 這行,如同下列所示 (粗體):

+ +
class AuthorAdmin(admin.ModelAdmin):
+    list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')
+    fields = ['first_name', 'last_name', ('date_of_birth', 'date_of_death')]
+
+ +

fields 屬性僅按順序列出了要在表單上顯示的那些欄位。 默認情況下,字段是垂直顯示的,但是如果您進一步將它們分組到一個元組中,它們將水平顯示(如上面的“日期”字段中所示)。

+ +

在您的網站上,轉到作者詳細信息視圖-現在應如下所示:

+ +

Admin Site - Improved Author Detail

+ +
+

注意: 您還可以使用 exclude 屬性來聲明要從表單中排除的屬性列表(將顯示模型中的所有其他屬性)。

+
+ +

Sectioning the detail view

+ +

You can add "sections" to group related model information within the detail form, using the fieldsets attribute.

+ +

In the BookInstance model we have information related to what the book is (i.e. name, imprint, and id) and when it will be available (status, due_back). We can add these in different sections by adding the text in bold to our BookInstanceAdmin class. 

+ +
@admin.register(BookInstance)
+class BookInstanceAdmin(admin.ModelAdmin):
+    list_filter = ('status', 'due_back')
+
+    fieldsets = (
+        (None, {
+            'fields': ('book', 'imprint', 'id')
+        }),
+        ('Availability', {
+            'fields': ('status', 'due_back')
+        }),
+    )
+ +

Each section has its own title (or None, if you don't want a title) and an associated tuple of fields in a dictionary — the format is complicated to describe, but fairly easy to understand if you look at the code fragment immediately above.

+ +

Now navigate to a book instance view in your website; the form should appear as shown below:

+ +

Admin Site - Improved BookInstance Detail with sections

+ +

Inline editing of associated records

+ +

Sometimes it can make sense to be able to add associated records at the same time. For example, it may make sense to have both the book information and information about the specific copies you've got on the same detail page.

+ +

You can do this by declaring inlines, of type TabularInline (horizonal layout) or StackedInline (vertical layout, just like the default model layout). You can add the BookInstance information inline to our Book detail by adding the lines below in bold near your BookAdmin:

+ +
class BooksInstanceInline(admin.TabularInline):
+    model = BookInstance
+
+@admin.register(Book)
+class BookAdmin(admin.ModelAdmin):
+    list_display = ('title', 'author', 'display_genre')
+    inlines = [BooksInstanceInline]
+
+ +

Now navigate to a view for a Book in your website — at the bottom you should now see the book instances relating to this book (immediately below the book's genre fields):

+ +

Admin Site - Book with Inlines

+ +

In this case all we've done is declare our tabular inline class, which just adds all fields from the inlined model. You can specify all sorts of additional information for the layout, including the fields to display, their order, whether they are read only or not,  etc. (see TabularInline for more information). 

+ +
+

Note: There are some painful limits in this functionality! In the screenshot above we have three existing book instances, followed by three placeholders for new book instances (which look very similar!). It would be better to have NO spare book instances by default and just add them with the Add another Book instance link, or to be able to just list the BookInstances as non-readable links from here. The first option can be done by setting the extra attribute to 0 in BooksInstanceInline model, try it by yourself.

+
+ +

自我挑戰

+ +

在本節中我們學到了很多東西,所以現在該您嘗試一些事情了。

+ +
    +
  1. 對於BookInstance列表視圖(list view),添加代碼以顯示booksstatusdue back dateid(而不是默認的__str __()文本)。
  2. +
  3. 使用與Book/BookInstance相同的方法將Book項目的內聯列表添加到Author 的詳細視圖(detail view)中。
  4. +
+ + + +

小結

+ +

就是這樣! 您現在已經了解瞭如何以最簡單和改進的形式設置管理者網站,如何創建超級用戶,以及如何瀏覽管理者網站,查看,刪除和更新記錄。 在此過程中,您已經創建了許多Books,BookInstances,Genres和Authors,一旦我們創建了自己的view和templates,便可以列出和顯示這些記錄。

+ +

延伸閱讀

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/server-side/django/authentication/index.html b/files/zh-tw/learn/server-side/django/authentication/index.html new file mode 100644 index 0000000000..ec15ddeffd --- /dev/null +++ b/files/zh-tw/learn/server-side/django/authentication/index.html @@ -0,0 +1,698 @@ +--- +title: 'Django Tutorial Part 8: User authentication and permissions' +slug: Learn/Server-side/Django/Authentication +translation_of: Learn/Server-side/Django/Authentication +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}
+ +

在本教程中,我們將會展示如何允許用戶使用自己的帳戶登入到您的網站,以及如何根據用戶是否已登入和權限的不同來控制他們可以執行和查看的內容。作為展示的一部分,我們會擴展 LocalLibrary 網站,添加登入頁面和登出頁面,以及用來查看已借閱的圖書的頁面 - 分為用戶與員工兩種不同頁面。

+ + + + + + + + + + + + +
前提:完成至 Django 線上教學 7: 會話(Sessions)框架為止的所有主題。
目標:了解如何設定與運用使用者驗證與權限機制。
+ +

大綱

+ +

Django提供認證和授權(“ permission”)系統,該系統建立在上一教程中討論的會話框架的基礎上。透過它可以驗證用戶憑證並定義個別用戶能夠執行的操作。 該框架包括用於UsersGroups 的內置模型(一般常用來一次性套用權限於一群用戶上的方式),用於指定用戶是否可以執行任務的權限/旗標,用於登入用戶的表單和視圖,以及 查看用於限制內容的工具。

+ +
+

注意: 從Django角度而言,身份驗證系統需要做到非常通用,因此不提供其他網頁身份驗證系統中提供的某些功能。 需要解決一些常見問題的話可以透過第三方軟件包。 例如,限制登錄嘗試和透過第三方進行身份驗證(例如OAuth)。

+
+ +

在本教程中,我們將會展示如何在LocalLibrary網站中啟用用戶身份驗證,並建立自己的登入和登出頁面,為模型添加權限以及控制對頁面的訪問。 我們將根據身份驗證/權限顯示為用戶或是圖書館員設計的已借出書籍列表。

+ +

身份驗證系統非常有彈性,您可以根據需要從頭開始構建URL,表單,視圖和模板,只透過提供的API來登入用戶。 但是,在本文中,我們將為登入與登出頁面使用Django的“ stock”身份驗證視圖和表單。 我們仍然需要建立一些模板,但這很簡單。

+ +

我們還將向您展示如何建立權限,並在視圖和模板中檢查登入狀態和權限。

+ +

Enabling authentication

+ +

當我們創建框架網站時(在教程2中),身份驗證已自動啟用,因此您此時無需執行任何其他操作。

+ +
+

注意: 當我們使用django-admin startproject命令創建應用程序時,所有必要的配置都為我們完成了。 用戶和模型權限的數據庫表是在我們首次調用python manage.py migrate時創建的。

+
+ +

該配置是在項目文件(locallibrary/locallibrary/settings.py)的INSTALLED_APPSMIDDLEWARE 部分中設置的,如下所示:

+ +
INSTALLED_APPS = [
+    ...
+    'django.contrib.auth',  #Core authentication framework and its default models.
+    'django.contrib.contenttypes',  #Django content type system (allows permissions to be associated with models).
+    ....
+
+MIDDLEWARE = [
+    ...
+    'django.contrib.sessions.middleware.SessionMiddleware',  #Manages sessions across requests
+    ...
+    'django.contrib.auth.middleware.AuthenticationMiddleware',  #Associates users with requests using sessions.
+    ....
+
+ +

Creating users and groups

+ +

當我們在教程4中查看Django管理站點時,您已經創建了第一個用戶(這是一個超級用戶,使用命令ppython manage.py createsuperuser創建)。 我們的超級用戶已經通過身份驗證,並且具有所有權限,因此我們需要創建一個測試用戶來代表普通站點用戶。 我們將使用管理站點來創建本地圖書館組和網站登錄名,因為這是最快的方法之一。

+ +
+

注意: 您還可以通過編程方式創建用戶,如下所示。 例如,如果要開發一個界面以允許用戶創建自己的登錄名,則必須這樣做(您不應授予用戶訪問管理站點的權限)。

+ +
from django.contrib.auth.models import User
+
+# Create user and save to the database
+user = User.objects.create_user('myusername', 'myemail@crazymail.com', 'mypassword')
+
+# Update fields and then save again
+user.first_name = 'John'
+user.last_name = 'Citizen'
+user.save()
+
+
+ +

在下面,我們將首先創建一個組,然後創建一個用戶。 即使我們還沒有添加庫成員的任何權限,但是如果以後需要添加,將它們一次添加到組中要比分別添加到每個成員要容易得多。

+ +

啟動開發服務器,然後在本地Web瀏覽器(http://127.0.0.1:8000/admin/)中導航到管理站點。 使用您的超級用戶帳戶的憑據登錄到該站點。 管理站點的頂層顯示所有模型,按“ django應用程序”排序。 在“Authentication and Authorisation”部分,您可以單擊Users 或Groups鏈接以查看其現有記錄。

+ +

Admin site - add groups or users

+ +

首先,讓我們為圖書館成員創建一個新組。

+ +
    +
  1. 單擊Add按鈕(在組旁邊)以創建一個新組; 輸入該組的名稱“Library Members”。
    + Admin site - add group
  2. +
  3. 我們不需要該組的任何權限,因此只需按SAVE (您將被帶到組列表)。
  4. +
+ +

現在讓我們創建一個用戶:

+ +
    +
  1. 導航回到管理站點的主頁
  2. +
  3. 單擊“用戶”旁邊的“添加”按鈕以打開“添加用戶”對話框。
    + Admin site - add user pt1
  4. +
  5. 輸入適合您的測試用戶的用戶名和密碼/密碼確認
  6. +
  7. SAVE創建用戶。
    + 管理站點將創建新用戶,並立即將您帶到“更改用戶”視窗,您可以在其中更改用戶名並為用戶模型的可選字段添加信息。 這些字段包括名字,姓氏,電子郵件地址,用戶狀態和權限(僅應設置“活動”標誌)。 在更下方的位置,您可以指定用戶的組和權限,並查看與該用戶相關的重要日期(例如,他們的加入日期和上次登錄日期)。
    + Admin site - add user pt2
  8. +
  9. 在“組”部分中,從“可用組”列表中選擇“Library Member”組,然後按框之間的右箭頭將其移至“選擇的組”框中。Admin site - add user to group
  10. +
  11. 我們在這裡不需要執行任何其他操作,因此只需再次選擇SAVE 即可進入用戶列表。
  12. +
+ +

就是這樣而已! 現在,您將擁有一個“普通庫成員”帳戶,您將可以使用該帳戶進行測試(一旦我們實現了頁面以使其能夠登錄)。

+ +
+

注意:您應該嘗試創建另一個庫成員用戶。 另外,為圖書館員創建一個組,並為其添加用戶!

+
+ +

Setting up your authentication views

+ +

Django提供了創建身份驗證頁面所需的幾乎所有內容,以處理“開箱即用”的登錄,註銷和密碼管理。 這包括URL映射器,視圖和表單,但不包括模板-我們必須創建自己的模板!

+ +

在本節中,我們顯示如何將默認系統集成到LocalLibrary網站中並創建模板。 我們將它們放在主項目URL中。

+ +
+

注意: 您不必使用任何代碼,但是您可能想要使用它,因為它使事情變得容易得多。 如果您更改用戶模型(一個高級主題!),幾乎可以肯定需要更改表單處理代碼,但是即使如此,您仍然可以使用庫存視圖功能。

+
+ +
+

注意: 在這種情況下,我們可以合理地將身份驗證頁面(包括URL和模板)放入目錄應用程序中。 但是,如果我們有多個應用程序,最好將這種共享的登錄行為分開,並使其在整個站點中都可用,這就是我們在此處顯示的內容!

+
+ +

Project URLs

+ +

將以下內容添加到項目urls.py文件(locallibrary/locallibrary/urls.py)文件的底部:

+ +
#Add Django site authentication urls (for login, logout, password management)
+urlpatterns += [
+    path('accounts/', include('django.contrib.auth.urls')),
+]
+
+ +

導航到http://127.0.0.1:8000/accounts/ URL(注意尾隨斜杠!),然後Django將顯示一個錯誤,指出找不到此URL,並列出了它嘗試的所有URL。 從中您可以看到將起作用的URL,例如:

+ +
+

注意: 使用上述方法會在方括號中添加以下網址,這些網址可用於反轉網址映射。 您無需執行其他任何操作-上面的url映射會自動映射以下提到的URL。

+
+ +
+
accounts/ login/ [name='login']
+accounts/ logout/ [name='logout']
+accounts/ password_change/ [name='password_change']
+accounts/ password_change/done/ [name='password_change_done']
+accounts/ password_reset/ [name='password_reset']
+accounts/ password_reset/done/ [name='password_reset_done']
+accounts/ reset/<uidb64>/<token>/ [name='password_reset_confirm']
+accounts/ reset/done/ [name='password_reset_complete']
+
+ +

現在嘗試導航到登錄URL(http://127.0.0.1:8000/accounts/login/)。 這將再次失敗,但是會顯示一條錯誤消息,告訴您我們在模板搜索路徑上缺少必需的模板(registration/login.html)。 您會在頂部黃色部分看到以下幾行:

+ +
Exception Type:    TemplateDoesNotExist
+Exception Value:    registration/login.html
+ +

下一步是在搜索路徑上創建註冊目錄,然後添加login.html文件。

+ +

Template directory

+ +

我們剛剛添加的url(和隱式視圖)期望在模板搜索路徑中某個目錄/registration/ 中找到它們的關聯模板。

+ +

對於這個網站,我們將HTML頁面放在templates/registration/目錄中。 此目錄應位於您的項目根目錄中,即與cataloglocallibrary 文件夾相同的目錄中)。 請立即創建這些文件夾。

+ +
+

Note: Your folder structure should now look like the below:
+ locallibrary (django project folder)
+    |_catalog
+    |_locallibrary
+    |_templates (new)
+                 |_registration

+
+ +

為了使這些目錄對模板加載器可見(即將該目錄放置在模板搜索路徑中),請打開項目設置(/locallibrary/locallibrary/settings.py),並更新TEMPLATES 部分的DIRS行,如圖所示。

+ +
TEMPLATES = [
+    {
+        ...
+        'DIRS': ['./templates',],
+        'APP_DIRS': True,
+        ...
+
+ +

Login template

+ +
+

重要信息:本文提供的身份驗證模板是Django演示登錄模板的非常基本/稍作修改的版本。 您可能需要自定義它們以供自己使用!

+
+ +

創建一個名為/locallibrary/templates/registration/login.html的新HTML文件。 為其提供以下內容:

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+
+{% if form.errors %}
+  <p>Your username and password didn't match. Please try again.</p>
+{% endif %}
+
+{% if next %}
+  {% if user.is_authenticated %}
+    <p>Your account doesn't have access to this page. To proceed,
+    please login with an account that has access.</p>
+  {% else %}
+    <p>Please login to see this page.</p>
+  {% endif %}
+{% endif %}
+
+<form method="post" action="{% url 'login' %}">
+{% csrf_token %}
+
+<div>
+  <td>\{{ form.username.label_tag }}</td>
+  <td>\{{ form.username }}</td>
+</div>
+<div>
+  <td>\{{ form.password.label_tag }}</td>
+  <td>\{{ form.password }}</td>
+</div>
+
+<div>
+  <input type="submit" value="login" />
+  <input type="hidden" name="next" value="\{{ next }}" />
+</div>
+</form>
+
+{# Assumes you setup the password_reset view in your URLconf #}
+<p><a href="{% url 'password_reset' %}">Lost password?</a></p>
+
+{% endblock %}
+ +

該模板與我們之前看到的模板有一些相似之處-它擴展了我們的基本模板並覆蓋了內容塊。 其餘代碼是相當標準的表單處理代碼,我們將在以後的教程中進行討論。 現在您只需要知道的是,這將顯示一個表格,您可以在其中輸入用戶名和密碼,並且如果輸入無效的值,則在頁面刷新時會提示您輸入正確的值。

+ +

保存模板後,導航回到登錄頁面(http://127.0.0.1:8000/accounts/login/),您應該看到類似以下內容:

+ +

Library login page v1

+ +

如果嘗試登錄將成功,並且您將被重定向到另一個頁面(默認情況下為http://127.0.0.1:8000/accounts/profile/)。 這裡的問題是,默認情況下,Django期望登錄後將您帶到個人資料頁面,情況可能與否。 由於您尚未定義此頁面,因此會出現另一個錯誤!

+ +

打開項目設置(/locallibrary/locallibrary/settings.py) ,然後將下面的文本添加到底部。 現在,當您登錄時,默認情況下應將您重定向到網站主頁。

+ +
# Redirect to home URL after login (Default redirects to /accounts/profile/)
+LOGIN_REDIRECT_URL = '/'
+
+ +

Logout template

+ +

如果您導航到登出URL (http://127.0.0.1:8000/accounts/logout/) ,則會看到一些奇怪的行為-您的用戶將被確定地註銷,但是您將被帶到Admin 註銷頁面。 那不是您想要的,僅僅是因為該頁面上的登錄鏈接將您帶到Admin 登錄屏幕(並且僅對具有is_staff 權限的用戶可用)。

+ +

創建並打開 /locallibrary/templates/registration/logged_out.html。 複製以下文本:

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <p>Logged out!</p>
+  <a href="{% url 'login'%}">Click here to login again.</a>
+{% endblock %}
+ +

這個模板非常簡單。 它僅顯示一條消息,通知您已註銷,並提供一個鏈接,您可以按此鏈接返回登錄屏幕。 如果再次進入註銷URL,您應該看到以下頁面:

+ +

Library logout page v1

+ +

Password reset templates

+ +

默認的密碼重置系統使用電子郵件向用戶發送重置鏈接。 您需要創建表格以獲取用戶的電子郵件地址,發送電子郵件,允許他們輸入新密碼並在整個過程完成時註明。

+ +

以下模板可以用作起點。

+ +

密碼重設表格

+ +

這是用於獲取用戶電子郵件地址(用於發送密碼重置電子郵件)的表格。 創建/locallibrary/templates/registration/password_reset_form.html,並為其提供以下內容:

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <form action="" method="post">
+  {% csrf_token %}
+  {% if form.email.errors %}
+    {{ form.email.errors }}
+  {% endif %}
+      <p>\{{ form.email }}</p>
+    <input type="submit" class="btn btn-default btn-lg" value="Reset password">
+  </form>
+{% endblock %}
+
+ +

密碼重置完成

+ +

收集您的電子郵件地址後,將顯示此表單。創建 /locallibrary/templates/registration/password_reset_done.html,並為其提供以下內容:

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <p>We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.</p>
+{% endblock %}
+
+ +

密碼重置電子郵件

+ +

該模板提供了HTML電子郵件的文本,其中包含我們將發送給用戶的重置鏈接。 創建/locallibrary/templates/registration/password_reset_email.html,並為其提供以下內容:

+ +
Someone asked for password reset for email \{{ email }}. Follow the link below:
+\{{ protocol}}://\{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
+
+ +

密碼重置確認

+ +

單擊密碼重置電子郵件中的鏈接後,即可在此頁面輸入新密碼。 創建 /locallibrary/templates/registration/password_reset_confirm.html,並為其提供以下內容:

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+    {% if validlink %}
+        <p>Please enter (and confirm) your new password.</p>
+        <form action="" method="post">
+            <div style="display:none">
+                <input type="hidden" value="\{{ csrf_token }}" name="csrfmiddlewaretoken">
+            </div>
+            <table>
+                <tr>
+                    <td>\{{ form.new_password1.errors }}
+                        <label for="id_new_password1">New password:</label></td>
+                    <td>\{{ form.new_password1 }}</td>
+                </tr>
+                <tr>
+                    <td>\{{ form.new_password2.errors }}
+                        <label for="id_new_password2">Confirm password:</label></td>
+                    <td>\{{ form.new_password2 }}</td>
+                </tr>
+                <tr>
+                    <td></td>
+                    <td><input type="submit" value="Change my password" /></td>
+                </tr>
+            </table>
+        </form>
+    {% else %}
+        <h1>Password reset failed</h1>
+        <p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
+    {% endif %}
+{% endblock %}
+
+ +

密碼重置完成

+ +

這是最後一個密碼重設模板,密碼重設成功後將顯示此模板以通知您。 創建/locallibrary/templates/registration/password_reset_complete.html,並為其提供以下內容:

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <h1>The password has been changed!</h1>
+  <p><a href="{% url 'login' %}">log in again?</a></p>
+{% endblock %}
+ +

Testing the new authentication pages

+ +

現在您已經添加了URL配置並創建了所有這些模板,身份驗證頁面現在應該可以正常工作了!

+ +

您可以通過嘗試使用以下URL登錄然後註銷超級用戶帳戶來測試新的身份驗證頁面:

+ + + +

您可以通過登錄頁面中的鏈接測試密碼重置功能。 請注意,Django只會將重置電子郵件發送到已經存儲在其數據庫中的地址(用戶)!

+ +
+

筆記:密碼重設系統要求您的網站支持電子郵件,這不在本文的討論範圍之內,因此該部分尚無法使用。 要進行測試,請將以下行放在settings.py文件的末尾。 這將記錄發送到控制台的所有電子郵件(因此您可以從控制台複製密碼重置鏈接)。

+ +
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
+
+ +

有關更多信息,請參閱發送電子郵件(Sending emailDjango文檔)。

+
+ +

針對經過身份驗證的用戶進行測試

+ +

本節介紹如何根據用戶是否登錄來有選擇地控制用戶看到的內容。

+ +

在模板中測試

+ +

您可以使用 \{{ user }}模板變量在模板中獲取有關當前登錄用戶的信息(默認情況下,就像我們在框架中一樣設置項目時,該信息會添加到模板上下文中)。

+ +

通常,您將首先針對 \{{ user.is_authenticated }}模板變量進行測試,以確定該用戶是否有資格查看特定內容。 為了演示這一點,接下來,我們將更新邊欄,以在用戶註銷時顯示“登錄”鏈接,在用戶登錄時顯示“註銷”鏈接。

+ +

打開基礎模板。 (/locallibrary/catalog/templates/base_generic.html) ,然後將以下文本複製到sidebar 塊中,緊接在endblock 模板標籤之前。

+ +
  <ul class="sidebar-nav">
+
+    ...
+
+   {% if user.is_authenticated %}
+     <li>User: \{{ user.get_username }}</li>
+     <li><a href="{% url 'logout'%}?next=\{{request.path}}">Logout</a></li>
+   {% else %}
+     <li><a href="{% url 'login'%}?next=\{{request.path}}">Login</a></li>
+   {% endif %} 
+  </ul>
+ +

如您所見,我們使用 if-else-endif 模板標籤根據 \{{ user.is_authenticated }} \ {{user.is_authenticated}}是否為真來有條件地顯示文本。 如果用戶通過了身份驗證,那麼我們知道我們有一個有效的用戶,因此我們調用 \{{ user.get_username }} 來顯示其名稱。

+ +

我們使用url 模板標記和相應URL配置的名稱來創建登錄和註銷鏈接URL。 還要注意我們如何將?next=\{{request.path}}附加到URL的末尾。 這是在鏈接的URL的末尾添加一個URL參數,其中包含當前頁面的地址(URL)。 用戶成功登錄/註銷後,視圖將使用此``next''值將用戶重定向到他們首先單擊 login/logout 鏈接的頁面。

+ +
+

注意:試試看! 如果您在主頁上,然後單擊側欄中的“Login/Logout”,那麼在操作完成後,您應該回到同一頁面。

+
+ +

在視圖中測試

+ +

如果您使用的是基於函數的視圖,則限制訪問函數的最簡單方法是將login_required 裝飾器應用於視圖函數,如下所示。 如果用戶已登錄,則您的視圖代碼將正常執行。 如果用戶未登錄,它將重定向到項目設置(settings.LOGIN_URL)中定義的登錄URL,並將當前的絕對路徑作為next URL參數傳遞。 如果用戶成功登錄,則他們將返回此頁面,但這次已通過身份驗證。

+ +
from django.contrib.auth.decorators import login_required
+
+@login_required
+def my_view(request):
+    ...
+ +
+

注意: 您可以通過在request.user.is_authenticated上進行測試來手動執行相同的操作,但是裝飾器要方便得多!

+
+ +

同樣,在基於類的視圖中限制對登錄用戶的訪問權限的最簡單方法是從 LoginRequiredMixin. 派生。 您需要首先在父類列表中,在主視圖類之前聲明此混合。

+ +
from django.contrib.auth.mixins import LoginRequiredMixin
+
+class MyView(LoginRequiredMixin, View):
+    ...
+ +

它具有與 login_required 裝飾器完全相同的重定向行為。 如果用戶未通過身份驗證,也可以指定其他位置來重定向用戶 (login_url),並使用URL參數名稱代替“ next”來插入當前的絕對路徑(redirect_field_name).。

+ +
class MyView(LoginRequiredMixin, View):
+    login_url = '/login/'
+    redirect_field_name = 'redirect_to'
+
+ +

有關更多詳細信息,請在此處查看Django文檔

+ +

範例—列出當前用戶的書籍

+ +

現在,我們知道瞭如何將頁面限制為特定用戶,讓我們創建當前用戶借閱的書籍的視圖。

+ +

不幸的是,我們還沒有任何方式讓用戶借書! 因此,在創建圖書清單之前,我們將首先擴展BookInstance 模型以支持借用的概念,並使用Django Admin應用程序將大量圖書借給我們的測試用戶。

+ +

模型

+ +

首先,我們將必須使用戶可以藉用BookInstance (我們已經具有statusdue_back ,但是在該模型和User之間還沒有任何關聯。我們將創建 一個使用ForeignKey (一對多)字段的方法,我們還需要一種簡單的機制來測試借出的書是否過期。
+
+ 打開catalog/models.py,然後從 django.contrib.auth.models導入User 模型(將其添加到文件頂部的前一個導入行下面,因此User 可供使用它的後續代碼使用):

+ +
from django.contrib.auth.models import User
+
+ +

Ne接下來,將borrower 字段添加到BookInstance 模型中:

+ +
borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
+
+ +

當我們在這裡時,讓我們添加一個屬性,我們可以從模板中調用該屬性,以告知特定的圖書實例是否過期。 儘管我們可以在模板本身中進行計算,但是使用如下所示的屬性會更加高效。

+ +

將此添加到文件頂部附近:

+ +
from datetime import date
+ +

現在,在BookInstance類中添加以下屬性定義:

+ +
@property
+def is_overdue(self):
+    if self.due_back and date.today() > self.due_back:
+        return True
+    return False
+ +
+

Note: 在進行比較之前,我們首先要驗證due_back是否為空。 空的 due_back字段將導致Django拋出錯誤而不是顯示頁面:空值不可比。 這不是我們希望用戶體驗的東西!

+
+ +

現在,我們已經更新了模型,我們需要在項目上進行新的遷移,然後應用這些遷移:

+ +
python3 manage.py makemigrations
+python3 manage.py migrate
+
+ +

Admin

+ +

現在打開catalog/admin.py,然後將list_displayfieldsets 中的borrower 字段添加到BookInstanceAdmin 類中,如下所示。 這將使該字段在“管理”部分中可見,以便我們可以在需要時將User 分配給BookInstance

+ +
@admin.register(BookInstance)
+class BookInstanceAdmin(admin.ModelAdmin):
+    list_display = ('book', 'status', 'borrower', 'due_back', 'id')
+    list_filter = ('status', 'due_back')
+
+    fieldsets = (
+        (None, {
+            'fields': ('book','imprint', 'id')
+        }),
+        ('Availability', {
+            'fields': ('status', 'due_back','borrower')
+        }),
+    )
+ +

Loan a few books

+ +

現在可以將書借給特定用戶了,然後借出許多BookInstance 記錄。 將他們的borrowed 字段設置為測試用戶,status 為“借用”,並設置將來和將來的到期日。

+ +
+

注意:我們不會詳細說明該過程,因為您已經知道如何使用管理網站!

+
+ +

On loan view

+ +

現在,我們將添加一個視圖,以獲取已借給當前用戶的所有書籍的列表。 我們將使用我們熟悉的相同的通用的基於類的列表視圖,但是這次我們還將導入並從LoginRequiredMixin派生,以便只有登錄的用戶才能調用此視圖。 我們還將選擇聲明template_name,而不使用默認值,因為我們最終可能會擁有一些不同的BookInstance記錄列表,並具有不同的視圖和模板。
+
+ 將以下內容添加到catalog / views.py

+ +
from django.contrib.auth.mixins import LoginRequiredMixin
+
+class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
+    """Generic class-based view listing books on loan to current user."""
+    model = BookInstance
+    template_name ='catalog/bookinstance_list_borrowed_user.html'
+    paginate_by = 10
+
+    def get_queryset(self):
+        return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')
+ +

為了將查詢限制為僅針對當前用戶的BookInstance 對象,我們重新實現了 get_queryset(),如上所示。 請注意,“ o”是“借出”的存儲代碼,我們在due_back 日期之前訂購,以便最先顯示最早的項目。

+ +

URL conf for on loan books

+ +

現在打開/catalog/urls.py並添加指向上面視圖的path()(您可以將下面的文本複製到文件末尾)。

+ +
urlpatterns += [
+    path('mybooks/', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'),
+]
+ +

Template for on loan books

+ +

現在,我們需要為此頁面添加模板。 首先,創建模板文件 /catalog/templates/catalog/bookinstance_list_borrowed_user.html 並為其提供以下內容:

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+    <h1>Borrowed books</h1>
+
+    {% if bookinstance_list %}
+    <ul>
+
+      {% for bookinst in bookinstance_list %}
+      <li class="{% if bookinst.is_overdue %}text-danger{% endif %}">
+        <a href="{% url 'book-detail' bookinst.book.pk %}">\{{bookinst.book.title}}</a> (\{{ bookinst.due_back }})
+      </li>
+      {% endfor %}
+    </ul>
+
+    {% else %}
+      <p>There are no books borrowed.</p>
+    {% endif %}
+{% endblock %}
+ +

該模板與我們先前為BookAuthor 物件創建的模板非常相似。 這裡唯一的“新內容”是我們檢查在模型中添加的方法(bookinst.is_overdue),並使用它來更改過期項目的顏色。

+ +

開發服務器運行時,現在應該可以在瀏覽器中的 http://127.0.0.1:8000/catalog/mybooks/ 上查看已登錄用戶的列表。 在您的用戶登錄和註銷後進行嘗試(在第二種情況下,應將您重定向到登錄頁面)。

+ +

Add the list to the sidebar

+ +

最後一步是將此新頁面的鏈接添加到側欄中。 我們將其放在同一部分中,在該部分中為登錄用戶顯示其他信息。

+ +

打開基本模板 (/locallibrary/catalog/templates/base_generic.html) 並將粗體顯示的行添加到側邊欄中,如圖所示。

+ +
 <ul class="sidebar-nav">
+   {% if user.is_authenticated %}
+   <li>User: \{{ user.get_username }}</li>
+   <li><a href="{% url 'my-borrowed' %}">My Borrowed</a></li>
+   <li><a href="{% url 'logout'%}?next=\{{request.path}}">Logout</a></li>
+   {% else %}
+   <li><a href="{% url 'login'%}?next=\{{request.path}}">Login</a></li>
+   {% endif %}
+ </ul>
+
+ +

What does it look like?

+ +

當任何用戶登錄後,他們將在邊欄中看到“My Borrowed ”,並且書的列表顯示如下(第一本書沒有截止日期,這是我們希望在以後的教程中解決的錯誤!) 。

+ +

Library - borrowed books by user

+ +

Permissions

+ +

權限與模型相關聯,並定義了具有權限的用戶可以在模型實例上執行的操作。 默認情況下,Django會自動為所有模型賦予添加,更改和刪除權限,從而允許具有權限的用戶通過管理站點執行關聯的操作。 您可以定義自己的模型權限,並將其授予特定用戶。 您還可以更改與同一模型的不同實例關聯的權限。

+ +

這樣,對視圖和模板中的權限進行的測試就非常類似於對身份驗證狀態的測試(實際上,對權限的測試也對身份驗證進行了測試)。

+ +

Models

+ +

使用permissions 字段在模型“class Meta”部分中完成權限的定義。 您可以在元組中根據需要指定任意數量的權限,每個權限本身都在嵌套的元組中定義,其中包含權限名稱和權限顯示值。 例如,我們可以定義一個權限,以允許用戶標記已退回一本書,如下所示:

+ +
class BookInstance(models.Model):
+    ...
+    class Meta:
+        ...
+        permissions = (("can_mark_returned", "Set book as returned"),)   
+ +

然後,我們可以將權限分配給管理站點中的“圖書管理員”組。

+ +

打開catalog/models.py,然後添加權限,如上所示。 您將需要重新運行遷移(調用 python3 manage.py makemigrationspython3 manage.py migrate)以適當地更新數據庫。

+ +

模板

+ +

當前用戶的權限存儲在名為 \{{ perms }}. 的模板變量中。 您可以使用關聯的Django "app"“應用”中的特定變量名稱來檢查當前用戶是否具有特定權限,例如 如果用戶具有此權限,則 \{{ perms.catalog.can_mark_returned }} 將為 True ,否則為False。 我們通常使用模板 {% if %} 標籤測試權限,如下所示:

+ +
{% if perms.catalog.can_mark_returned %}
+    <!-- We can mark a BookInstance as returned. -->
+    <!-- Perhaps add code to link to a "book return" view here. -->
+{% endif %}
+
+ +

視圖

+ +

可以在功能視圖中使用permission_required 裝飾器來測試權限,或者在基於類的視圖中使用PermissionRequiredMixin. 來測試權限。 模式和行為與登錄身份驗證的模式和行為相同,儘管當然您可能必須合理地添加多個權限。

+ +

視圖裝飾器函數:

+ +
from django.contrib.auth.decorators import permission_required
+
+@permission_required('catalog.can_mark_returned')
+@permission_required('catalog.can_edit')
+def my_view(request):
+    ...
+ +

基於類的視圖需要權限的混合。

+ +
from django.contrib.auth.mixins import PermissionRequiredMixin
+
+class MyView(PermissionRequiredMixin, View):
+    permission_required = 'catalog.can_mark_returned'
+    # Or multiple permissions
+    permission_required = ('catalog.can_mark_returned', 'catalog.can_edit')
+    # Note that 'catalog.can_edit' is just an example
+    # the catalog application doesn't have such permission!
+ +

範例

+ +

我們不會在這裡更新LocalLibrary; 也許在下一個教程中!

+ +

挑戰自己

+ +

在本文的前面,我們向您展示瞭如何為當前用戶創建一個頁面,列出他們所借用的書。 現在的挑戰是創建一個僅對圖書館員可見的相似頁面,該頁面顯示所有已借書的書,其中包括每個借書人的名字。

+ +

您應該能夠遵循與其他視圖相同的模式。 主要區別在於您只需要將視圖限制為圖書館員即可。 您可以根據用戶是否是工作人員來執行此操作(函數裝飾器:staff_member_required,模板變量: user.is_staff),但是我們建議您改用can_mark_returned 權限和PermissionRequiredMixin,如上一節所述。

+ +
+

重要:請記住不要將您的超級用戶用於基於權限的測試(即使尚未定義權限,權限檢查也始終對超級用戶返回true!)。 而是創建一個圖書管理員用戶,並添加所需的功能。

+
+ +

完成後,您的頁面應類似於以下屏幕截圖。All borrowed books, restricted to librarian

+ + + +

總結

+ +

出色的工作-您現在已經創建了一個網站,圖書館成員可以登錄並查看他們自己的內容,館員(具有正確的權限)可以用來查看所有借出的書及其借書人。 目前,我們仍在查看內容,但是當您要開始修改和添加數據時,將使用相同的原理和技術。

+ +

在下一篇文章中,我們將研究如何使用Django表單來收集用戶輸入,然後開始修改一些存儲的數據。

+ +

也可以看看

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/server-side/django/deployment/index.html b/files/zh-tw/learn/server-side/django/deployment/index.html new file mode 100644 index 0000000000..752714dabb --- /dev/null +++ b/files/zh-tw/learn/server-side/django/deployment/index.html @@ -0,0 +1,675 @@ +--- +title: 'Django Tutorial Part 11: Deploying Django to production' +slug: Learn/Server-side/Django/Deployment +translation_of: Learn/Server-side/Django/Deployment +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}
+ +

現在,您已經創建(並測試)了一個令人敬畏的 LocalLibrary 網站,如果您希望將其安裝在公共 Web 服務器上,以便圖書館工作人員、和成員,可以通過 Internet 訪問它。本文概述如何找到主機來部署您的網站,以及您需要做什麼,才能讓您的網站準備好生產環境。

+ + + + + + + + + + + + +
Prerequisites:Complete all previous tutorial topics, including Django Tutorial Part 10: Testing a Django web application.
Objective:To learn where and how you can deploy a Django app to production.
+ +

Overview

+ +

Once your site is finished (or finished "enough" to start public testing) you're going to need to host it somewhere more public and accessible than your personal development computer.

+ +

Up to now you've been working in a development environment, using the Django development web server to share your site to the local browser/network, and running your website with (insecure) development settings that expose debug and other private information. Before you can host a website externally you're first going to have to:

+ + + +

This tutorial provides some guidance on your options for choosing a hosting site, a brief overview of what you need to do in order to get your Django app ready for production, and a worked example of how to install the LocalLibrary website onto the Heroku cloud hosting service.

+ +

What is a production environment?

+ +

The production environment is the environment provided by the server computer where you will run your website for external consumption. The environment includes:

+ + + +
+

Note: Depending on how your production is configured you might also have a reverse proxy, load balancer, etc.

+
+ +

The server computer could be located on your premises and connected to the Internet by a fast link, but it is far more common to use a computer that is hosted "in the cloud". What this actually means is that your code is run on some remote computer (or possibly a "virtual" computer) in your hosting company's data center(s). The remote server will usually offer some guaranteed level of computing resources (e.g. CPU, RAM, storage memory, etc.) and Internet connectivity for a certain price.

+ +

This sort of remotely accessible computing/networking hardware is referred to as Infrastructure as a Service (IaaS). Many IaaS vendors provide options to preinstall a particular operating system, onto which you must install the other components of your production environment. Other vendors allow you to select more fully-featured environments, perhaps including a complete Django and web-server setup.

+ +
+

Note: Pre-built environments can make setting up your website very easy because they reduce the configuration, but the available options may limit you to an unfamiliar server (or other components) and may be based on an older version of the OS. Often it is better to install components yourself, so that you get the ones that you want, and when you need to upgrade parts of the system, you have some idea where to start!

+
+ +

Other hosting providers support Django as part of a Platform as a Service (PaaS) offering. In this sort of hosting you don't need to worry about most of your production environment (web server, application server, load balancers) as the host platform takes care of those for you (along with most of what you need to do in order to scale your application). That makes deployment quite easy, because you just need to concentrate on your web application and not all the other server infrastructure.

+ +

Some developers will choose the increased flexibility provided by IaaS over PaaS, while others will appreciate the reduced maintenance overhead and easier scaling of PaaS. When you're getting started, setting up your website on a PaaS system is much easier, and so that is what we'll do in this tutorial.

+ +
+

Tip: If you choose a Python/Django-friendly hosting provider they should provide instructions on how to set up a Django website using different configurations of webserver, application server, reverse proxy, etc (this won't be relevant if you choose a PaaS). For example, there are many step-by-step guides for various configurations in the Digital Ocean Django community docs.

+
+ +

Choosing a hosting provider

+ +

There are well over 100 hosting providers that are known to either actively support or work well with Django (you can find a fairly extensive list at Djangofriendly hosts). These vendors provide different types of environments (IaaS, PaaS), and different levels of computing and network resources at different prices.

+ +

Some of the things to consider when choosing a host:

+ + + +

The good news when you're starting out is that there are quite a few sites that provide "evaluation", "developer", or "hobbyist" computing environments for "free". These are always fairly resource constrained/limited environments, and you do need to be aware that they may expire after some introductory period. They are however great for testing low traffic sites in a real environment, and can provide an easy migration to paying for more resources when your site gets busier. Popular choices in this category include Heroku, Python Anywhere, Amazon Web Services, Microsoft Azure, etc.

+ +

Many providers also have a "basic" tier that provides more useful levels of computing power and fewer limitations. Digital Ocean and Python Anywhere are examples of popular hosting providers that offer a relatively inexpensive basic computing tier (in the $5 to $10USD per month range).

+ +
+

Note: Remember that price is not the only selection criteria. If your website is successful, it may turn out that scalability is the most important consideration.

+
+ +

Getting your website ready to publish

+ +

The Django skeleton website created using the django-admin and manage.py tools are configured to make development easier. Many of the Django project settings (specified in settings.py) should be different for production, either for security or performance reasons.

+ +
+

Tip: It is common to have a separate settings.py file for production, and to import sensitive settings from a separate file or an environment variable. This file should then be protected, even if the rest of the source code is available on a public repository.

+
+ +

The critical settings that you must check are:

+ + + +

Let's change the LocalLibrary application so that we read our SECRET_KEY and DEBUG variables from environment variables if they are defined, but otherwise use the default values in the configuration file.

+ +

Open /locallibrary/settings.py, disable the original SECRET_KEY configuration and add the new lines as shown below in bold. During development no environment variable will be specified for the key, so the default value will be used (it shouldn't matter what key you use here, or if the key "leaks", because you won't use it in production).

+ +
# SECURITY WARNING: keep the secret key used in production secret!
+# SECRET_KEY = 'cg#p$g+j9tax!#a3cup@1$8obt2_+&k3q+pmu)5%asj6yjpkag'
+import os
+SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'cg#p$g+j9tax!#a3cup@1$8obt2_+&k3q+pmu)5%asj6yjpkag')
+
+ +

Then comment out the existing DEBUG setting and add the new line shown below.

+ +
# SECURITY WARNING: don't run with debug turned on in production!
+# DEBUG = True
+DEBUG = bool( os.environ.get('DJANGO_DEBUG', True) )
+
+ +

The value of the DEBUG will be True by default, but will be False if the value of the DJANGO_DEBUG environment variable is set to an empty string, e.g. DJANGO_DEBUG=''.

+ +
+

Note: It would be more intuitive if we could just set and unset the DJANGO_DEBUG environment variable to True and False directly, rather than using "any string" or "empty string" (respectively). Unfortunately environment variable values are stored as Python strings, and the only string that evaluates as False is the empty string (e.g. bool('')==False).

+
+ +

A full checklist of settings you might want to change is provided in Deployment checklist (Django docs). You can also list a number of these using the terminal command below:

+ +
python3 manage.py check --deploy
+
+ +

Example: Installing LocalLibrary on Heroku

+ +

This section provides a practical demonstration of how to install LocalLibrary on the Heroku PaaS cloud.

+ +

Why Heroku?

+ +

Heroku is one of the longest running and popular cloud-based PaaS services. It originally supported only Ruby apps, but now can be used to host apps from many programming environments, including Django!

+ +

We are choosing to use Heroku for several reasons:

+ + + +

While Heroku is perfect for hosting this demonstration it may not be perfect for your real website. Heroku makes things easy to set up and scale, at the cost of being less flexible, and potentially a lot more expensive once you get out of the free tier.

+ +

How does Heroku work?

+ +

Heroku runs Django websites within one or more "Dynos", which are isolated, virtualized Unix containers that provide the environment required to run an application. The dynos are completely isolated and have an ephemeral file system (a short-lived file system that is cleaned/emptied every time the dyno restarts). The only thing that dynos share by default are application configuration variables. Heroku internally uses a load balancer to distribute web traffic to all "web" dynos. Since nothing is shared between them, Heroku can scale an app horizontally simply by adding more dynos (though of course you may also need to scale your database to accept additional connections).

+ +

Because the file system is ephemeral you can't install services required by your application directly (e.g. databases, queues, caching systems, storage, email services, etc). Instead Heroku web applications use backing services provided as independent "add-ons" by Heroku or 3rd parties. Once attached to your web application, the dynos access the services using information contained in application configuration variables.

+ +

In order to execute your application Heroku needs to be able to set up the appropriate environment and dependencies, and also understand how it is launched. For Django apps we provide this information in a number of text files:

+ + + +

Developers interact with Heroku using a special client app/terminal, which is much like a Unix bash script. This allows you to upload code that is stored in a git repository, inspect the running processes, see logs, set configuration variables and much more!

+ +

In order to get our application to work on Heroku we'll need to put our Django web application into a git repository, add the files above, integrate with a database add-on, and make changes to properly handle static files.

+ +

Once we've done all that we can set up a Heroku account, get the Heroku client, and use it to install our website.

+ +
+

Note: The instructions below reflect how to work with Heroku at time of writing. If Heroku significantly change their processes, you may wish to instead check their setup documents: Getting Started on Heroku with Django.

+
+ +

That's all the overview you need in order to get started (see How Heroku works for a more comprehensive guide).

+ +

Creating an application repository in Github

+ +

Heroku is closely integrated with the git source code version control system, using it to upload/synchronise any changes you make to the live system. It does this by adding a new heroku "remote" repository named heroku pointing to a repository for your source on the Heroku cloud. During development you use git to store changes on your "master" repository. When you want to deploy your site, you sync your changes to the Heroku repository.

+ +
+

Note: If you're used to following good software development practices you are probably already using git or some other SCM system. If you already have a git repository, then you can skip this step.

+
+ +

There are a lot of ways of to work with git, but one of the easiest is to first set up an account on Github, create the repository there, and then sync to it locally:

+ +
    +
  1. Visit https://github.com/ and create an account.
  2. +
  3. Once you are logged in, click the + link in the top toolbar and select New repository.
  4. +
  5. Fill in all the fields on this form. While these are not compulsory, they are strongly recommended. +
      +
    • Enter a new repository name (e.g. django_local_library), and description (e.g. "Local Library website written in Django".
    • +
    • Choose Python in the Add .gitignore selection list.
    • +
    • Choose your preferred license in the Add license selection list.
    • +
    • Check Initialize this repository with a README.
    • +
    +
  6. +
  7. Press Create repository.
  8. +
  9. Click the green "Clone or download" button on your new repo page.
  10. +
  11. Copy the URL value from the text field inside the dialog box that appears (it should be something like: https://github.com/<your_git_user_id>/django_local_library.git).
  12. +
+ +

Now the repository ("repo") is created we are going to want to clone it on our local computer:

+ +
    +
  1. Install git for your local computer (you can find versions for different platforms here).
  2. +
  3. Open a command prompt/terminal and clone your repository using the URL you copied above: +
    git clone https://github.com/<your_git_user_id>/django_local_library.git
    +
    + This will create the repository below the current point.
  4. +
  5. Navigate into the new repo. +
    cd django_local_library.git
    +
  6. +
+ +

The final step is to copy in your application and then add the files to your repo using git:

+ +
    +
  1. Copy your Django application into this folder (all the files at the same level as manage.py and below, not their containing locallibrary folder).
  2. +
  3. Open the .gitignore file, copy the following lines into the bottom of it, and then save (this file is used to identify files that should not be uploaded to git by default). +
    # Text backup files
    +*.bak
    +
    +#Database
    +*.sqlite3
    +
  4. +
  5. Open a command prompt/terminal and use the add command to add all files to git. +
    git add -A
    +
    +
  6. +
  7. Use the status command to check all files that you are about to add are correct (you want to include source files, not binaries, temporary files etc.). It should look a bit like the listing below. +
    > git status
    +On branch master
    +Your branch is up-to-date with 'origin/master'.
    +Changes to be committed:
    +  (use "git reset HEAD <file>..." to unstage)
    +
    +        modified:   .gitignore
    +        new file:   catalog/__init__.py
    +        ...
    +        new file:   catalog/migrations/0001_initial.py
    +        ...
    +        new file:   templates/registration/password_reset_form.html
    +
  8. +
  9. When you're satisfied commit the files to your local repository: +
    git commit -m "First version of application moved into github"
    +
  10. +
  11. Then synchronise your local repository to the Github website, using the following: +
    git push origin master
    +
  12. +
+ +

When this operation completes, you should be able to go back to the page on Github where you created your repo, refresh the page, and see that your whole application has now been uploaded. You can continue to update your repository as files change using this add/commit/push cycle.

+ +
+

Tip: This is a good point to make a backup of your "vanilla" project — while some of the changes we're going to be making in the following sections might be useful for deployment on any platform (or development) others might not.

+ +

The best way to do this is to use git to manage your revisions. With git you can not only go back to a particular old version, but you can maintain this in a separate "branch" from your production changes and cherry-pick any changes to move between production and development branches. Learning Git is well worth the effort, but is beyond the scope of this topic.

+ +

The easiest way to do this is to just copy your files into another location. Use whichever approach best matches your knowledge of git!

+
+ +

Update the app for Heroku

+ +

This section explains the changes you'll need to make to our LocalLibrary application to get it to work on Heroku. While Heroku's Getting Started on Heroku with Django instructions assume you will use the Heroku client to also run your local development environment, our changes here are compatible with the existing Django development server and ways of working we've already learned.

+ +

Procfile

+ +

Create the file Procfile (no extension) in the root of your GitHub repository to declare the application's process types and entry points. Copy the following text into it:

+ +
web: gunicorn locallibrary.wsgi --log-file -
+ +

The "web:" tells Heroku that this is a web dyno and can be sent HTTP traffic. The process to start in this dyno is gunicorn, which is a popular web application server that Heroku recommends. We start Gunicorn using the configuration information in the module locallibrary.wsgi (created with our application skeleton: /locallibrary/wsgi.py).

+ +

Gunicorn

+ +

Gunicorn is the recommended HTTP server for use with Django on Heroku (as referenced in the Procfile above). It is a pure-Python HTTP server for WSGI applications that can run multiple Python concurrent processes within a single dyno (see Deploying Python applications with Gunicorn for more information).

+ +

While we won't need Gunicorn to serve our LocalLibrary application during development, we'll install it so that it becomes part of our requirements for Heroku to set up on the remote server.

+ +

Install Gunicorn locally on the command line using pip (which we installed when setting up the development environment):

+ +
pip3 install gunicorn
+
+ +

Database configuration

+ +

We can't use the default SQLite database on Heroku because it is file-based, and it would be deleted from the ephemeral file system every time the application restarts (typically once a day, and every time the application or its configuration variables are changed).

+ +

The Heroku mechanism for handling this situation is to use a database add-on and configure the web application using information from an environment configuration variable, set by the add-on. There are quite a lot of database options, but we'll use the hobby tier of the Heroku postgres database as this is free, supported by Django, and automatically added to our new Heroku apps when using the free hobby dyno plan tier.

+ +

The database connection information is supplied to the web dyno using a configuration variable named DATABASE_URL. Rather than hard-coding this information into Django, Heroku recommends that developers use the dj-database-url package to parse the DATABASE_URL environment variable and automatically convert it to Django’s desired configuration format. In addition to installing the dj-database-url package we'll also need to install psycopg2, as Django needs this to interact with Postgres databases.

+ +
dj-database-url (Django database configuration from environment variable)
+ +

Install dj-database-url locally so that it becomes part of our requirements for Heroku to set up on the remote server:

+ +
$ pip3 install dj-database-url
+
+ +
settings.py
+ +

Open /locallibrary/settings.py and copy the following configuration into the bottom of the file:

+ +
# Heroku: Update database configuration from $DATABASE_URL.
+import dj_database_url
+db_from_env = dj_database_url.config(conn_max_age=500)
+DATABASES['default'].update(db_from_env)
+ +
+

Note:

+ + +
+ +
psycopg2 (Python Postgres database support)
+ +

Django needs psycopg2 to work with Postgres databases and you will need to add this to the requirements.txt for Heroku to set this up on the remote server (as discussed in the requirements section below).

+ +

Django will use our SQLite database locally by default, because the DATABASE_URL environment variable isn't set in our local environment. If you want to switch to Postgres completely and use our Heroku free tier database for both development and production then you can. For example, to install psycopg2 and its dependencies locally on a Linux-based system you would use the following bash/terminal commands:

+ +
sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib
+pip3 install psycopg2
+
+ +

Installation instructions for the other platforms can be found on the psycopg2 website here.

+ +

However, you don't need to do this — you don't need PostGreSQL active on the local computer, as long as you give it to Heroku as a requirement, in requirements.txt (see below).

+ +

Serving static files in production

+ +

During development we used Django and the Django development web server to serve our static files (CSS, JavaScript, etc.). In a production environment we instead typically serve static files from a content delivery network (CDN) or the web server.

+ +
+

Note: Serving static files via Django/web application is inefficient because the requests have to pass through unnecessary additional code (Django) rather than being handled directly by the web server or a completely separate CDN. While this doesn't matter for local use during development, it would have a significant performance impact if we were to use the same approach in production. 

+
+ +

To make it easy to host static files separately from the Django web application, Django provides the collectstatic tool to collect these files for deployment (there is a settings variable that defines where the files should be collected when collectstatic is run). Django templates refer to the hosting location of the static files relative to a settings variable (STATIC_URL), so that this can be changed if the static files are moved to another host/server.

+ +

The relevant setting variables are:

+ + + +
settings.py
+ +

Open /locallibrary/settings.py and copy the following configuration into the bottom of the file. The BASE_DIR should already have been defined in your file (the STATIC_URL may already have been defined within the file when it was created. While it will cause no harm, you might as well delete the duplicate previous reference).

+ +
# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.0/howto/static-files/
+
+# The absolute path to the directory where collectstatic will collect static files for deployment.
+STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
+
+# The URL to use when referring to static files (where they will be served from)
+STATIC_URL = '/static/'
+
+ +

We'll actually do the file serving using a library called WhiteNoise, which we install and configure in the next section.

+ +

For more information, see Django and Static Assets (Heroku docs).

+ +

Whitenoise

+ +

There are many ways to serve static files in production (we saw the relevant Django settings in the previous sections). Heroku recommends using the WhiteNoise project for serving of static assets directly from Gunicorn in production.

+ +
+

Note: Heroku automatically calls collectstatic and prepares your static files for use by WhiteNoise after it uploads your application. Check out WhiteNoise documentation for an explanation of how it works and why the implementation is a relatively efficient method for serving these files.

+
+ +

The steps to set up WhiteNoise to use with the project are:

+ +
WhiteNoise
+ +

Install whitenoise locally using the following command:

+ +
$ pip3 install whitenoise
+
+ +
settings.py
+ +

To install WhiteNoise into your Django application, open /locallibrary/settings.py, find the MIDDLEWARE setting and add the WhiteNoiseMiddleware near the top of the list, just below the SecurityMiddleware:

+ +
MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'whitenoise.middleware.WhiteNoiseMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ +

Optionally, you can reduce the size of the static files when they are served (this is more efficient). Just add the following to the bottom of /locallibrary/settings.py:

+ +
# Simplified static file serving.
+# https://warehouse.python.org/project/whitenoise/
+STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
+
+ +

Requirements

+ +

The Python requirements of your web application must be stored in a file requirements.txt in the root of your repository. Heroku will then install these automatically when it rebuilds your environment. You can create this file using pip on the command line (run the following in the repo root):

+ +
pip3 freeze > requirements.txt
+ +

After installing all the different dependencies above, your requirements.txt file should have at least these items listed (though the version numbers may be different). Please delete any other dependencies not listed below, unless you've explicitly added them for this application.

+ +
dj-database-url==0.4.1
+Django==2.0
+gunicorn==19.6.0
+psycopg2==2.6.2
+whitenoise==3.2.2
+
+ +
+

Make sure that a psycopg2 line like the one above is present! Even iIf you didn't install this locally then you should still add this to the requirements.txt.

+
+ +

Runtime

+ +

The runtime.txt file, if defined, tells Heroku which programming language to use. Create the file in the root of the repo and add the following text:

+ +
python-3.6.4
+ +
+

Note: Heroku only supports a small number of Python runtimes (at time of writing, this includes the one above). Heroku will use a supported runtime irrespective of the value specified in this file.

+
+ +

Save changes to Github and re-test

+ +

Next lets save all our changes to Github. In the terminal (whist inside our repository), enter the following commands:

+ +
git add -A
+git commit -m "Added files and changes required for deployment to heroku"
+git push origin master
+ +

Before we proceed, lets test the site again locally and make sure it wasn't affected by any of our changes above. Run the development web server as usual and then check the site still works as you expect on your browser.

+ +
python3 manage.py runserver
+ +

We should now be ready to start deploying LocalLibrary on Heroku.

+ +

Get a Heroku account

+ +

To start using Heroku you will first need to create an account:

+ + + +

Install the client

+ +

Download and install the Heroku client by following the instructions on Heroku here.

+ +

After the client is installed you will be able run commands. For example to get help on the client:

+ +
heroku help
+
+ +

Create and upload the website

+ +

To create the app we run the "create" command in the root directory of our repository. This creates a git remote ("pointer to a remote repository") named heroku in our local git environment.

+ +
heroku create
+ +
+

Note: You can name the remote if you like by specifying a value after "create". If you don't then you'll get a random name. The name is used in the default URL.

+
+ +

We can then push our app to the Heroku repository as shown below. This will upload the app, package it in a dyno, run collectstatic, and start the site.

+ +
git push heroku master
+ +

If we're lucky, the app is now "running" on the site, but it won't be working properly because we haven't set up the database tables for use by our application. To do this we need to use the heroku run command and start a "one off dyno" to perform a migrate operation. Enter the following command in your terminal:

+ +
heroku run python manage.py migrate
+ +

We're also going to need to be able to add books and authors, so lets also create our administration superuser, again using a one-off dyno:

+ +
heroku run python manage.py createsuperuser
+ +

Once this is complete, we can look at the site. It should work, although it won't have any books in it yet. To open your browser to the new website, use the command:

+ +
heroku open
+ +

Create some books in the admin site, and check out whether the site is behaving as you expect.

+ +

Managing addons

+ +

You can check out the add-ons to your app using the heroku addons command. This will list all addons, and their price tier and state.

+ +
>heroku addons
+
+Add-on                                     Plan       Price  State
+─────────────────────────────────────────  ─────────  ─────  ───────
+heroku-postgresql (postgresql-flat-26536)  hobby-dev  free   created
+ └─ as DATABASE
+ +

Here we see that we have just one add-on, the postgres SQL database. This is free, and was created automatically when we created the app. You can open a web page to examine the database add-on (or any other add-on) in more detail using the following command:

+ +
heroku addons:open heroku-postgresql
+
+ +

Other commands allow you to create, destroy, upgrade and downgrade addons (using a similar syntax to opening). For more information see Managing Add-ons (Heroku docs).

+ +

Setting configuration variables

+ +

You can check out the configuration variables for the site using the heroku config command. Below you can see that we have just one variable, the DATABASE_URL used to configure our database.

+ +
>heroku config
+
+=== locallibrary Config Vars
+DATABASE_URL: postgres://uzfnbcyxidzgrl:j2jkUFDF6OGGqxkgg7Hk3ilbZI@ec2-54-243-201-144.compute-1.amazonaws.com:5432/dbftm4qgh3kda3
+ +

If you recall from the section on getting the website ready to publish, we have to set environment variables for DJANGO_SECRET_KEY and DJANGO_DEBUG. Let's do this now.

+ +
+

Note: The secret key needs to be really secret! One way to generate a new key is to create a new Django project (django-admin startproject someprojectname) and then get the key that is generated for you from its settings.py.

+
+ +

We set DJANGO_SECRET_KEY using the config:set command (as shown below). Remember to use your own secret key!

+ +
>heroku config:set DJANGO_SECRET_KEY=eu09(ilk6@4sfdofb=b_2ht@vad*$ehh9-)3u_83+y%(+phh&=
+
+Setting DJANGO_SECRET_KEY and restarting locallibrary... done, v7
+DJANGO_SECRET_KEY: eu09(ilk6@4sfdofb=b_2ht@vad*$ehh9-)3u_83+y%(+phh
+
+ +

We similarly set DJANGO_DEBUG:

+ +
>heroku config:set DJANGO_DEBUG=
+
+Setting DJANGO_DEBUG and restarting locallibrary... done, v8
+ +

If you visit the site now you'll get a "Bad request" error, because the ALLOWED_HOSTS setting is required if you have DEBUG=False (as a security measure). Open /locallibrary/settings.py and change the ALLOWED_HOSTS setting to include your base app url (e.g. 'locallibrary1234.herokuapp.com') and the URL you normally use on your local development server.

+ +
ALLOWED_HOSTS = ['<your app URL without the https:// prefix>.herokuapp.com','127.0.0.1']
+# For example:
+# ALLOWED_HOSTS = ['fathomless-scrubland-30645.herokuapp.com','127.0.0.1']
+
+ +

Then save your settings and commit them to your Github repo and to Heroku:

+ +
git add -A
+git commit -m 'Update ALLOWED_HOSTS with site and development server URL'
+git push origin master
+git push heroku master
+ +
+

After the site update to Heroku completes, enter an URL that does not exist (e.g. /catalog/doesnotexist/). Previously this would have displayed a detailed debug page, but now you should just see a simple "Not Found" page.

+
+ +

Debugging

+ +

The Heroku client provides a few tools for debugging:

+ +
heroku logs  # Show current logs
+heroku logs --tail # Show current logs and keep updating with any new results
+heroku config:set DEBUG_COLLECTSTATIC=1 # Add additional logging for collectstatic (this tool is run automatically during a build)
+heroku ps   #Display dyno status
+
+ +

If you need more information than these can provide you will need to start looking into Django Logging.

+ + + +

Summary

+ +

That's the end of this tutorial on setting up Django apps in production, and also the series of tutorials on working with Django. We hope you've found them useful. You can check out a fully worked-through version of the source code on Github here.
+
+ The next step is to read our last few articles, and then complete the assessment task.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}

+ +

 

+ +

In this module

+ + + +

 

diff --git a/files/zh-tw/learn/server-side/django/development_environment/index.html b/files/zh-tw/learn/server-side/django/development_environment/index.html new file mode 100644 index 0000000000..c3d4c5c823 --- /dev/null +++ b/files/zh-tw/learn/server-side/django/development_environment/index.html @@ -0,0 +1,429 @@ +--- +title: 架設 Django 開發環境 +slug: Learn/Server-side/Django/development_environment +translation_of: Learn/Server-side/Django/development_environment +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}
+ +

現在,你知道什麼是Django。那麼我們將向你展示如何在Windows,Linux(Ubuntu)和Mac OSX上設置和測試Django開發環境—無論你常用哪種操作系統,本文應該都能讓你開始開發Django應用程序。

+ + + + + + + + + + + + +
先備知識:知道如何打開終端或命令行。了解如何在計算機的操作系統上安裝軟件包。
目標:在你的計算機操作系統上運行Django(2.0)開發環境。
+ +

Django 開發環境概覽

+ +

Django 使你輕鬆設置自己的電腦,以便開始開發網絡應用。這部分介紹在開發環境可以取得什麼,並概述了部分設置和配置選項。本文的其餘部分,介紹了在Ubuntu,Mac OS X 和 Windows 上,安裝 Django 開發環境的推薦方法,以及如何測試。

+ +

什麼是 Django 開發環境?

+ +

開發環境是在本地計算機上安裝 Django,你可以在將 Django 部署到生產環境之前,用於開發和測試 Django 應用程序。

+ +

Django 本身提供的主要工具,是一組用於創建和使用 Django 項目的 Python 腳本,以及可用於在你的計算機的瀏覽器上,測試本地(即,你的計算機,而不是外部 Web 服務器)Django 網絡應用程序的簡單開發網路服務器 。

+ +

還有其他外部工具, 它們構成了開發環境的一部分, 我們將不再贅述。這些包括 文本編輯器 text editor 或編輯代碼的 IDE,以及像 Git 這樣的源代碼控制管理工具,用於安全地管理不同版本的代碼。我們假設你已經安裝了一個文本編輯器。

+ +

什麼是Django設置選項?

+ +

Django 如何在安裝和配置方面非常靈活。Django可以:

+ + + +

每個選項都需要略微不同的配置和設置。以下小節解釋了你的一些選擇。對於本文的其餘部分,我們將介紹Django在少見的操作系統上的設置,考量該模塊的其餘部分。

+ +
+

注意: 其他可能的安裝選項在官方Django文檔中介紹。相應文件點擊這裡

+
+ +

支持哪些操作系統?

+ +

幾乎任何可以運行Python編程語言的機器可以運行Django 網絡應用程序:Windows,Mac OSX,Linux/Unix,Solaris,僅舉幾例。幾乎任何計算機都應該在開發過程中運行Django所需的性能。

+ +

在本文中。我們將提供Windows,Mac OS X 和Linux/Unix的說明。

+ +

你應該使用什麼版本的Python?

+ +

我們建議您使用最新版本 - 在編寫本文時,這是Python 3.7。

+ +

如果需要,可以使用Python 3.4或更高版本(將來的版本中將刪除Python 3.4支持)。

+ +
+

注意: Python 2.7不能與Django 2.0一起使用(Django 1.11.x系列是最後一個支持Python 2.7的系列)。

+
+ +

我們在哪裡下載Django?

+ +

有三個地方可以下載Django:

+ + + +

本文介紹如何從PyPi安裝Django,從獲得最新的穩定版本。

+ +

哪個數據庫?

+ +

Django支持四個主要數據庫(PostgreSQL,MySQL,Oracle和SQLite),還有一些社區庫,可以為其他流行的SQL和NOSQL數據庫,提供不同級別的支持。我們建議你為生產和開發,選擇相同的數據庫(儘管Django使用其對象關係映射器(ORM)抽像出許多數據庫差異,但是仍然存在可以避免的潛在問題 ).

+ +

對於本文(和本模塊的大部分),我們將使用將數據存放在文件中的SQLite數據庫。SQLite旨在用作輕量級數據庫,不能支持高級並發。然而,這確實是唯讀的應用程序的絕佳選擇。

+ +
+

注意 :當你使用標準工具(django-admin)啟動你的網站項目時,Django將默認配置為使用SQLite。用來入門,這是一個很好的選擇,因為它不需要額外的配置和設置。

+
+ +

安裝到整個本機系統還是Python虛擬環境中?

+ +

安裝Python3時,您將獲得一個由所有Python3代碼共享的單一全局環境。雖然您可以在環境中,安裝任何您喜歡的Python軟件包,但您一次只能安裝每個軟件包的一個特定版本。

+ +
+

注意: 安裝到全局環境中的Python應用程序可能會相互衝突(即,如果它們依賴於同一程序包的不同版本)。

+
+ +

如果您將Django安裝到默認/全局環境中,那麼您將只能在計算機上,定位一個版本的Django。如果您想要創建新網站(使用最新版本的Django)同時仍然維護依賴舊版本的網站,這可能是一個問題。

+ +

因此,經驗豐富的Python / Django開發人員,通常在獨立的Python虛擬環境中,運行Python應用程序。這樣可以在一台計算機上,實現多個不同的Django環境。 Django開發團隊本身建議您使用Python虛擬環境!

+ +

本模塊假設您已將Django安裝到虛擬環境中,我們將向您展示如何做。

+ +

安裝 Python 3

+ +

為了使用Django,你需要安裝Python3.同樣你需要Python包管理工具   — pip3 —用來管理(安裝,更新和刪除)Django和其他Python應用程序使用的Python軟件包/庫。

+ +

本書簡要說明如何根據需要檢查什麼版本,並根據需要安裝新版本,適用於Ubuntu Linux 16.04, Mac OS X, and Windows 10。

+ +
+

注意 :根據你的平台,您還可以從操作系統自己的軟件包管理器或其他機制安裝Python / pip。對於大多數平台,您可以從https://www.python.org/downloads/下載所需的安裝文件,並使用適當的平台特定方法進行安裝。

+
+ +

Ubuntu 18.04

+ +

Ubuntu Linux 18.04 LTS默認包含Python 3.6.5。您可以通過在bash終端中運行以下命令來確認:

+ +
python3 -V
+ Python 3.6.5
+ +

然而,在默認情況下,為Python 3(包括Django)安裝軟件包的Python包管理工具不可用。可以使用以下方式將pip3安裝在bash終端

+ +
sudo apt install python3-pip
+
+ +

macOS X

+ +

Mac OS X "El Capitan" 不包括Python 3.你可以通過在bash終端中運行一下命令來確認:

+ +
python3 -V
+ -bash: python3: command not found
+ +

你可以輕鬆從python.org安裝Python 3(以及pip3工具):

+ +
    +
  1. 下載所需的安裝程序: + +
      +
    1. 點擊https://www.python.org/downloads/
    2. +
    3. 選擇Download Python 3.7.0按鈕(確切的版本號可能不同).
    4. +
    +
  2. +
  3. 使用Finder找到文件,然後雙擊包文件。遵循安裝提示。
    + (一般能拖拽就拖拽)
  4. +
+ +

你現在可以檢查Pyhon 3來確認成功安裝,如下所示:

+ +
python3 -V
+ Python 3.7.0
+
+ +

你也可以通過列出可用的軟件包來檢查pip3是否安裝:

+ +
pip3 list
+ +

Windows 10

+ +

windows默認不安裝,但你可以從python.org輕鬆安裝它(以及pip3工具):

+ +
    +
  1. 下載所需版本: + +
      +
    1. 點擊https://www.python.org/downloads/
    2. +
    3. 選擇Download Python 3.7.0 按鈕(確切的版本號可能不同).
    4. +
    5. 通過雙擊下載的文件並按照提示安裝Python
    6. +
    +
  2. +
+ +

你可以通過在命令提示符中輸入以下文本來驗證是否安裝了Python:

+ +
py -3 -V
+ Python 3.7.0
+
+ +

默認情況下,Windows安裝程序包含pip3(python包管理器,你可以列出安裝的軟件包):

+ +
pip3 list
+
+ +
+

注意: 安裝程序應設置上述命令工作所需的一切。但是,如果您收到無法找到Python 的消息,則可能忘記將其添加到系統路徑中。您可以通過再次運行安裝程序,選擇“修改”"Modify",然後選中第二頁上標有“將Python添加到環境變量”"Add Python to environment variables"的框來執行此操作。

+
+ +

在Python虛擬環境中使​​用Django

+ +

我們將用於創建虛擬環境的庫是 virtualenvwrapper(Linux和macOS X)和 virtualenvwrapper-win (Windows),後者又使用 virtualenv工具。包裝工具為所有平台上的接口管理創建了一致的界面。

+ +

安裝虛擬環境軟體

+ +

Ubuntu虛擬環境設置

+ +

安裝Python和pip之後,你可以安裝 virtualenvwrapper(包括virtualenv)。可在此處找到官方安裝指南,或按照以下說明操作。

+ +

使用pip3安裝該工具:

+ +
sudo pip3 install virtualenvwrapper
+ +

然後將以下行添加到shell啟動文件的末尾(這是主目錄中的隱藏文件名.bashrc)。這些設置了虛擬環境應該存在的位置,開發項目目錄的位置以及使用此軟件包安裝的腳本的位置 :

+ +
export WORKON_HOME=$HOME/.virtualenvs
+export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
+export VIRTUALENVWRAPPER_VIRTUALENV_ARGS=' -p /usr/bin/python3 '
+export PROJECT_HOME=$HOME/Devel
+source /usr/local/bin/virtualenvwrapper.sh
+
+ +
+

注意: VIRTUALENVWRAPPER_PYTHONVIRTUALENVWRAPPER_VIRTUALENV_ARGS 變量指向Python3的正常安裝位置,source /usr/local/bin/virtualenvwrapper.sh指向virtualenvwrapper.sh腳本的正常位置。如果virtualenv在測試時不起作用,那麼要檢查的一件事是Python和腳本位於預期的位置(然後適當地更改啟動文件)。

+ +

您可以使用which virtualenvwrapper.shwhich python3.的命令找到系統的正確位置。

+
+ +

然後在終端中運行以下命令重新加載啟動文件:

+ +
source ~/.bashrc
+ +

此時您應該看到一堆腳本正在運行,如下所示:

+ +
virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/premkproject
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postmkproject
+...
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/preactivate
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postactivate
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/get_env_details
+
+ +

現在,您可以使用mkvirtualenv命令創建新的虛擬環境。

+ +

macOS X 虛擬環境設置

+ +

在 macOS X上設置 virtualenvwrapper 與在 Ubuntu上幾乎完全相同(同樣,您可以按照官方安裝指南或下面的說明進行操作。

+ +

使用 pip 安裝 virtualenvwrapper(並捆綁 virtualenv),如圖所示。

+ +
sudo pip3 install virtualenvwrapper
+ +

然後將以下幾行添加到 shell 啟動文件的末尾。

+ +
export WORKON_HOME=$HOME/.virtualenvs
+export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
+export PROJECT_HOME=$HOME/Devel
+source /usr/local/bin/virtualenvwrapper.sh
+ +
+

注意: VIRTUALENVWRAPPER_PYTHON變量指向Python3的正常安裝位置,source /usr/local/bin/virtualenvwrapper.sh指向virtualenvwrapper.sh腳本的正常位置。如果virtualenv在測試時不起作用,那麼要檢查的一件事,是Python和腳本位於預期的位置(然後適當地更改啟動文件)。

+ +

例如,對macOS進行的一次安裝測試,最終在啟動文件中需要以下幾行:

+ +
export WORKON_HOME=$HOME/.virtualenvs
+export VIRTUALENVWRAPPER_PYTHON=/Library/Frameworks/Python.framework/Versions/3.7/bin/python3
+export PROJECT_HOME=$HOME/Devel
+source /Library/Frameworks/Python.framework/Versions/3.7/bin/virtualenvwrapper.sh
+ +

您可以使用which virtualenvwrapper.shwhich python3的命令找到系統的正確位置。

+
+ +

這幾行與Ubuntu相同,但啟動文件是主目錄中、名稱不同的隱藏文件.bash_profile

+ +
+

注意: 如果在查找程序中找不到要編輯的.bash-profile,也可以使用nano在終端中打開它。

+ +

命令看起來像這樣:

+ +
cd ~  # Navigate to my home directory
+ls -la #List the content of the directory. YOu should see .bash_profile
+nano .bash_profile # Open the file in the nano text editor, within the terminal
+# Scroll to the end of the file, and copy in the lines above
+# Use Ctrl+X to exit nano, Choose Y to save the file.
+
+ +

 

+
+ +

然後通過在終端中,進行以下調用,來重新加載啟動文件:

+ +
source ~/.bash_profile
+ +

此時,您可能會看到一堆腳本正在運行(與Ubuntu安裝相同的腳本)。您現在應該能夠使用mkvirtualenv命令,創建新的虛擬環境。

+ +

Windows 10 虛擬環境設置

+ +

安裝virtualenvwrapper-win比設置virtualenvwrapper更簡單,因為您不需要配置工具存放虛擬環境信息的位置(有默認值)。您需要做的就是,在命令提示符中運行以下命令:

+ +
pip3 install virtualenvwrapper-win
+ +

現在,您可以使用mkvirtualenv命令創建新的虛擬環境

+ +

創建虛擬環境

+ +

一旦你安裝了virtualenvwrapper或virtualenvwrapper-win,那麼在所有平台上使用虛擬環境都非常相似。

+ +

現在,您可以使用mkvirtualenv命令創建新的虛擬環境。當此命令運行時,您將看到正在設置的環境(您看到的是略微特定​​於平台的)。當命令完成時,新的虛擬環境,將處於活動狀態 - 您可以看到這一點,因為提示的開頭,將是括號中環境的名稱(如下所示)。

+ +
$ mkvirtualenv my_django_environment
+
+Running virtualenv with interpreter /usr/bin/python3
+...
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/t_env7/bin/get_env_details
+(my_django_environment) ubuntu@ubuntu:~$
+
+ +

現在,您可以在虛擬環境中,安裝Django,並開始開發。

+ +
+

注意: 從本文開始(實際上是本系列教學),請假設任何命令都在Python虛擬環境中運行,就像我們在上面設置的那樣。

+
+ +

使用虛擬環境

+ +

您應該知道其他一些有用的命令(工具文檔中有更多,但這些是您經常使用的命令):

+ + + +

安裝 Django

+ +

一旦你創建了一個虛擬環境,並調用了workon來輸入它,就可以使用pip3來安裝Django。

+ +
pip3 install django
+
+ +

您可以通過運行以下命令來測試Django是否安裝(這只是測試Python可以找到Django模塊):

+ +
# Linux/macOS X
+python3 -m django --version
+ 2.0
+
+# Windows
+py -3 -m django --version
+ 2.0
+
+ +
+

注意: 如果上面的Windows命令沒有顯示django模塊,請嘗試:

+ +
py -m django --version
+在Windows中,Python 3腳本通過在命令前面加上py -3來啟動,儘管這可能會因具體安裝而異。如果遇到任何命令問題,請嘗試省略-3修飾符。在Linux / macOS X中,命令是python3
+ +
+

重要提示:本教程的其餘部分,使用Linux命令來調用Python 3(python3)。如果您在Windows上工作,只需將此前綴替換為: py -3

+
+ +

測試你的安裝

+ +

上面的測試可以工作,但它不是很有趣。一個更有趣的測試是創建一個骨架項目並看到它工作。要做到這一點,先在你的命令提示符/終端導航到你想存儲你Django應用程序的位置。為您的測試站點創建一個文件夾並瀏覽它。

+ +
mkdir django_test
+cd django_test
+
+ +

然後,您可以使用django-admin工具創建一個名為“ mytestsite ”的新骨架站點,如圖所示。創建網站後,您可以導航到文件夾,您將在其中找到管理項目的主要腳本,名為manage.py

+ +
django-admin startproject mytestsite
+cd mytestsite
+ +

我們可以使用manage.pyrunserver 命令,從此文件夾內運行開發Web服務器,如圖所示。

+ +
$ python3 manage.py runserver
+Performing system checks...
+
+System check identified no issues (0 silenced).
+
+You have 14 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
+Run 'python manage.py migrate' to apply them.
+
+December 29, 2017 - 03:03:47
+Django version 2.0, using settings 'mytestsite.settings'
+Starting development server at http://127.0.0.1:8000/
+Quit the server with CONTROL-C.
+
+ +
+

注意: 以上命令顯示Linux / macOS X命令。此時您可以忽略有關“14個未應用的遷移”的警告!("14 unapplied migration(s)" )

+
+ +

一旦服務器運行,您可以通過導航到本地Web瀏覽器上的以下URL來查看該站點:http://127.0.0.1:8000/你應該看到一個如下所示的網站:

+ +

Django Skeleton App Homepage

+ + + +

總結Summary

+ +

您現在已在計算機上啟動並運行Django開發環境。

+ +

在測試部分,您還簡要了解了,我們如何使用django-admin startproject,創建一個新的Django網站,並使用開發Web服務器(python3 manage.py runserver)在瀏覽器中運行它。在下一篇文章中,我們將擴展此過程,構建一個簡單、但完整的Web應用程序。

+ +

參閱

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}

+ +

本教程連結

+ + + +

 

diff --git a/files/zh-tw/learn/server-side/django/django_assessment_blog/index.html b/files/zh-tw/learn/server-side/django/django_assessment_blog/index.html new file mode 100644 index 0000000000..d584b8259c --- /dev/null +++ b/files/zh-tw/learn/server-side/django/django_assessment_blog/index.html @@ -0,0 +1,316 @@ +--- +title: 'Assessment: DIY Django mini blog' +slug: Learn/Server-side/Django/django_assessment_blog +tags: + - django + - 初學者 + - 部落格 +translation_of: Learn/Server-side/Django/django_assessment_blog +--- +
{{LearnSidebar}}
+ +
{{PreviousMenu("Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}
+ +

在這個評估中,您將使用您在 Django Web Framework (Python) 模組中獲得的知識,來創建一個非常基本的部落格。

+ + + + + + + + + + + + +
+

前提:

+
在開始時做這章節的任務之前,你應該已經看完這個模組的所有文章了。
目標: +

測試Django基礎的綜合應用,包含URL設定、模型、視圖、表單和模板。

+
+ +

專案簡介

+ +

需要顯示的頁面與對應的URLs和需求提列於下表:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
頁面URL需求
首頁/ 和 /blog/關於此站的說明。
所有部落格文章的清單/blog/blogs/ +

所有部落格文章的清單。

+ +
    +
  • 所有使用者都能從側邊選單進入此頁。
  • +
  • 清單按發布日期排序(新至舊)。
  • +
  • 清單依照每頁5筆文章分頁。
  • +
  • 清單內的每一筆項目顯示文章標題、發布日期與作者的名字。
  • +
  • 文章標題連結至該至文章的詳細頁面。
  • +
  • 作者的名字連結至該作者的詳細頁面。
  • +
+
部落格作者(blogger) 詳細頁面/blog/blogger/<author-id> +

特定作者(由id指定)的資訊與他所發布的部落格文章。

+ +
    +
  • 所有使用者都能從作者連結進入此頁(例如文章內的作者連結)。
  • +
  • 包含一些關於作者本身的資訊。
  • +
  • 文章清單按發布日期排序(新至舊)。
  • +
  • 不用分頁。
  • +
  • 文章清單只顯示文章標題與發佈日期。
  • +
  • 文章標題連結至文章詳細頁面。
  • +
+
部落格文章詳細頁面/blog/<blog-id> +

部落格文章詳細內容。

+ +
    +
  • 任何使用者都能從部落格文章的清單進入此頁。
  • +
  • 包含文章標題、作者、發布日期與內容。
  • +
  • 文章的回覆必須呈現於底部。
  • +
  • 文章的回覆必須按回覆時間排序(舊至新)。
  • +
  • 已登入的使用者能看見新增回覆的連結。
  • +
  • 文章與回覆需以純文字的方式顯示。不需要支援任何markup(例如連結、圖片、粗體/斜體等)。
  • +
+
部落格作者清單/blog/bloggers/ +

系統內的部落格作者清單。

+ +
    +
  • 任何使用者都可以從側邊選單進入此頁。
  • +
  • 作者名字連結至該作者的詳細頁面。
  • +
+
回覆表單頁/blog/<blog-id>/create +

新增回覆於特定文章。

+ +
    +
  • 只有登入的使用者可以由文章詳細頁面底部連結進入此頁。
  • +
  • 提供能輸入回覆的表單(發布日期和文章標題不可被編輯)。
  • +
  • 回覆被發表之後,頁面會轉址回該文章詳細頁。
  • +
  • 使用者無法修改或是刪除他發表的回覆。
  • +
  • 未登入的使用者會先被導至登入頁,登入之後才能發表回覆。一旦登入之後,他們便會被導至他們想發表回覆的文章頁。
  • +
  • 回覆表單頁必須包含該文章的標題與連結。
  • +
+
使用者身分認證頁/accounts/<standard urls> +

標準的Django身分驗證頁面,用來登入、登出及修改密碼。

+ +
    +
  • 使用者能從側欄連結進入登入/登出頁面。
  • +
+
管理者網頁/admin/<standard urls> +

管理者網頁必須能新增/編輯/刪除部落格文章、作者及回覆。

+ +
    +
  • 管理者網頁的每筆文章記錄必須一併於其底下陳列出相關的回覆。
  • +
  • 管理者網頁的每一筆回覆都要以75字的回覆內容作為顯示名稱。
  • +
  • 其餘的紀錄使用基本的註冊即可。
  • +
+
+ +

另外您應該要寫一些基本的測試來驗證:

+ + + +
+

Note: 當然你也可以跑很多其他的測試。但是我們會希望您至少實作以上列出的測試項目。

+
+ +

下一區塊顯示符合以上需求的網頁截圖

+ +

截圖

+ +

The following screenshot provide an example of what the finished program should output.

+ +

列出所有的部落格文章

+ +

這個頁面會列出所有部落格內的文章(可以從側邊選單的“所有文章”連結進入)。
+ 幾項提醒:

+ + + +

List of all blogs

+ +

列出所有部落客(文章作者)

+ +

可以由側邊選單的“所有部落客”進入此頁面,並於頁面上提供連結至每一位部落客。
+ 從截圖可以發現到,並沒有任何一位使用者登入。

+ +

List of all bloggers

+ +

部落格詳細頁

+ +

顯示某篇特定部落格文章的詳細內容。

+ +

Blog detail with add comment link

+ +

請注意每個評論都有日期與時間,並且由最後至最新排列(與部落格文章相反)。
+ 我們可以看見最底下有個連結連到新增評論的表單。當使用者沒有登入時,我們改以要求登入的連結代替。

+ +

Comment link when not logged in

+ +

新增評論表單

+ +

這張表單用來新增評論,且使用者必須是登入狀態。當表單送出成功之後,我們必須回到相對應的部落格文章內容頁。

+ +

Add comment form

+ +

作者資料

+ +

這頁顯示部落客的介紹資料以及列出他們所發表的部落格文章。

+ +

Blogger detail page

+ +

一步一腳印Steps to complete

+ +

以下說明實作的步驟。

+ +
    +
  1. 建立一個此網站的專案及app骨架(可以參考Django 教學2 : 建立一個網站骨架)。你也許會用'diyblog'作為專案名稱,‘blog'作為app的名稱。
  2. +
  3. 建立部落格文章、評論與其他任何所需物件的模型。當你在思考怎麼設計的時候,請記得: +
      +
    • 每一個評論都只屬於一篇部落格文章,但每一個部落格文章可以有很多筆評論。
    • +
    • 部落格文章必須要依照發布時間排序(新至舊),評論要依照發布排序(舊至新)。
    • +
    • 不是每位使用者都是部落客,但是每一位使用者都可以留下評論。
    • +
    • 部落客必須有介紹資訊。
    • +
    +
  4. +
  5. 跑migrations以及創建一個新的超級使用者(superuser)。
  6. +
  7. 透過admin網站新稱一些部落格文章和評論。
  8. +
  9. 幫部落格文章列表頁與部落客列表頁建立視圖、模板及設定URL。
  10. +
  11. 幫部落格文章詳細頁與部落客詳細頁建立視圖、模板及設定URL。
  12. +
  13. 建立一個頁面包含可以新增評論的表單(記得只有已登入的使用者可以進入此頁!)
  14. +
+ +

提示與小技巧

+ +

This project is very similar to the LocalLibrary tutorial. You will be able to set up the skeleton, user login/logout behaviour, support for static files, views, URLs, forms, base templates and admin site configuration using almost all the same approaches.

+ +

Some general hints:

+ +
    +
  1. The index page can be implemented as a basic function view and template (just like for the locallibrary).
  2. +
  3. The list view for blog posts and bloggers, and the detail view for blog posts can be created using the generic list and detail views.
  4. +
  5. The list of blog posts for a particular author can be created by using a generic list Blog list view and filtering for blog object that match the specified author. +
      +
    • You will have to implement get_queryset(self) to do the filtering (much like in our library class LoanedBooksAllListView) and get the author information from the URL.
    • +
    • You will also need to pass the name of the author to the page in the context. To do this in a class-based view you need to implement get_context_data() (discussed below).
    • +
    +
  6. +
  7. The add comment form can be created using a function-based view (and associated model and form) or using a generic CreateView. If you use a CreateView (recommended) then: +
      +
    • You will also need to pass the name of the blog post to the comment page in the context (implement get_context_data() as discussed below).
    • +
    • The form should only display the comment "description" for user entry (date and associated blog post should not be editable). Since they won't be in the form itself, your code will need to set the comment's author in the form_valid() function so it can be saved into the model (as described here — Django docs). In that same function we set the associated blog. A possible implementation is shown below (pk is a blog id passed in from the URL/URL configuration). +
          def form_valid(self, form):
      +        """
      +        Add author and associated blog to form data before setting it as valid (so it is saved to model)
      +        """
      +        #Add logged-in user as author of comment
      +        form.instance.author = self.request.user
      +        #Associate comment with blog based on passed id
      +        form.instance.blog=get_object_or_404(Blog, pk = self.kwargs['pk'])
      +        # Call super-class form validation behaviour
      +        return super(BlogCommentCreate, self).form_valid(form)
      +
      +
    • +
    • You will need to provide a success URL to redirect to after the form validates; this should be the original blog. To do this you will need to override get_success_url() and "reverse" the URL for the original blog. You can get the required blog ID using the self.kwargs attribute, as shown in the form_valid() method above.
    • +
    +
  8. +
+ +

We briefly talked about passing a context to the template in a class-based view in the Django Tutorial Part 6: Generic list and detail views topic. To do this you need to override get_context_data() (first getting the existing context, updating it with whatever additional variables you want to pass to the template, and then returning the updated context). For example, the code fragment below shows how you can add a blogger object to the context based on their BlogAuthor id.

+ +
class SomeView(generic.ListView):
+    ...
+
+    def get_context_data(self, **kwargs):
+        # Call the base implementation first to get a context
+        context = super(SomeView, self).get_context_data(**kwargs)
+        # Get the blogger object from the "pk" URL parameter and add it to the context
+        context['blogger'] = get_object_or_404(BlogAuthor, pk = self.kwargs['pk'])
+        return context
+
+ +

Assessment

+ +

The assessment for this task is available on Github here. This assessment is primarily based on how well your application meets the requirements we listed above, though there are some parts of the assessment that check your code uses appropriate models, and that you have written at least some test code. When you're done, you can check out our the finished example which reflects a "full marks" project.

+ +

Once you've completed this module you've also finished all the MDN content for learning basic Django server-side website programming! We hope you enjoyed this module and feel you have a good grasp of the basics!

+ +

{{PreviousMenu("Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/server-side/django/forms/index.html b/files/zh-tw/learn/server-side/django/forms/index.html new file mode 100644 index 0000000000..a4553d2d73 --- /dev/null +++ b/files/zh-tw/learn/server-side/django/forms/index.html @@ -0,0 +1,661 @@ +--- +title: 'Django Tutorial Part 9: Working with forms' +slug: Learn/Server-side/Django/Forms +translation_of: Learn/Server-side/Django/Forms +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}
+ +

在本教程中,我們將向您展示,如何在 Django 中使用 HTML 表單,特別是編寫表單以創建,更新和刪除模型實例的最簡單方法。作為本演示的一部分,我們將擴展 LocalLibrary 網站,以便圖書館員,可以使用我們自己的表單(而不是使用管理員應用程序)更新圖書,創建,更新和刪除作者。

+ + + + + + + + + + + + +
 前提:完成先前所有的教程, 包含 Django Tutorial Part 8: User authentication and permissions.
目的:了解如何製作表單來向用戶取得資訊並更新資料庫。了解通用類別表單編輯視圖 ( generic class-based form editing views ) 能夠大幅簡化用於單一模型的表單製作。
+ +

概述

+ +

HTML表單是網頁上的一組一個或多個字段/小組件,可用於從用戶收集信息以提交到服務器。 表單是一種用於收集用戶輸入的靈活機制,因為有合適的小部件可以輸入許多不同類型的數據,包括文本框,複選框,單選按鈕,日期選擇器等。表單也是與服務器共享數據的相對安全的方式, 因為它們允許我們在具有跨站點請求偽造保護的POST 請求中發送數據。

+ +

儘管到目前為止,本教程中尚未創建任何表單,但我們已經在Django Admin網站中遇到過這些表單-例如,下面的屏幕截圖顯示了一種用於編輯我們的Book 模型的表單,該表單由許多選擇列表和 文字編輯器。

+ +

Admin Site - Book Add

+ +

使用表單可能會很複雜!開發人員需要為表單編寫HTML,在服務器上(也可能在瀏覽器中)驗證並正確清理輸入的數據,使用錯誤消息重新發布表單以通知用戶任何無效字段,並在成功提交數據後處理數據,最後以某種方式回應用戶以表示成功。 Django表單通過提供一個框架使您能夠以編程方式定義表單及其字段,然後使用這些對像生成表單HTML代碼並處理許多驗證和用戶交互,從而完成了所有這些步驟中的大量工作。

+ +

在本教程中,我們將向您展示創建和使用表單的幾種方法,尤其是通用編輯表單視圖如何顯著減少創建表單來操縱表單所需的工作量。楷模。在此過程中,我們將擴展本地圖書館應用程序,方法是添加一個允許圖書館員續訂圖書的表格,並創建頁面以創建,編輯和刪除圖書和作者(複製上面顯示的表格的基本版本以編輯圖書) )。

+ +

HTML 表單

+ +

首先簡要介紹一下 HTML Forms。 考慮一個簡單的 HTML 表單,其中有一個用於輸入某些“團隊”名稱的文本字段及其相關標籤:

+ +

Simple name field example in HTML form

+ +

表單在HTML中定義為 <form>...</form> 標記內元素的集合,其中至少包含type="submit".的input元素。

+ +
<form action="/team_name_url/" method="post">
+    <label for="team_name">Enter name: </label>
+    <input id="team_name" type="text" name="name_field" value="Default name for team.">
+    <input type="submit" value="OK">
+</form>
+ +

雖然這裡只有一個用於輸入團隊名稱的文本字段,但是表單可以具有任意數量的其他輸入元素及其關聯的標籤。字段的type 屬性定義將顯示哪種小部件。字段的 nameid 用於標識JavaScript / CSS / HTML中的字段,而 value定義該字段在首次顯示時的初始值。匹配的團隊標籤是使用label 標籤指定的(請參見上面的“輸入名稱”),其中的  for 字段包含相關inputid 值。

+ +

submit 輸入將顯示為一個按鈕(默認情況下),用戶可以按下該按鈕以將表單中所有其他輸入元素中的數據上載到服務器(在這種情況下,僅是team_name)。表單屬性定義用於發送數據的HTTPmethod 以及服務器上數據的目的地(action):
+  

+ + + +

服務器的角色是首先呈現初始表單狀態-包含空白字段,或預填充初始值。用戶按下“提交”按鈕後,服務器將從Web瀏覽器接收帶有值的表單數據,並且必須驗證信息。如果表單包含無效數據,則服務器應再次顯示該表單,這一次將在“有效”字段中顯示用戶輸入的數據,並顯示描述無效字段問題的消息。服務器收到包含所有有效表單數據的請求後,便可以執行適當的操作(例如,保存數據,返回搜索結果,上傳文件等),然後通知用戶。

+ +

可以想像,創建HTML,驗證返回的數據,在需要時使用錯誤報告重新顯示輸入的數據以及對有效數據執行所需的操作都需要花費大量精力才能“正確”。 Django通過刪除一些繁瑣且重複的代碼,使此操作變得更加容易!

+ +

Django表單處理流程

+ +

Django的表單處理使用了我們在以前的教程中學到的所有相同技術(用於顯示有關模型的信息):視圖獲取請求,執行所需的任何操作,包括從模型中讀取數據,然後生成並返回HTML頁面( 從模板中,我們傳遞一個包含要顯示的數據的上下文)。 使事情變得更加複雜的是,服務器還需要能夠處理用戶提供的數據,並在出現任何錯誤時重新顯示頁面。

+ +

下面顯示了Django處理表單請求的過程流程圖,該流程圖從對包含表單的頁面的請求(以綠色顯示)開始。
+ Updated form handling process doc.

+ +

根據上圖,Django表單處理的主要功能是:

+ +
    +
  1. 在用戶第一次請求時顯示默認表單。 +
      +
    • 該表單可能包含空白字段(例如,如果您正在創建新記錄),或者可能會預先填充有初始值(例如,如果您正在更改記錄或具有有用的默認初始值)。
    • +
    • 由於此表單與任何用戶輸入的數據均不相關(儘管它可能具有初始值),因此在這一點上被稱為未綁定。
    • +
    +
  2. +
  3. 從提交請求中接收數據並將其綁定到表單。 +
      +
    • 將數據綁定到表單意味著當我們需要重新顯示表單時,用戶輸入的數據和任何錯誤均可用。
    • +
    +
  4. +
  5. 清理並驗證數據。 +
      +
    • 清理數據會對輸入執行清理操作(例如,刪除可能用於向服務器發送惡意內容的無效字符),並將其轉換為一致的Python類型。
    • +
    • 驗證會檢查該值是否適合該字段(例如,日期範圍正確,時間不要太短或太長等)
    • +
    +
  6. +
  7. 如果任何數據無效,則這次重新顯示該表單,其中包含用戶填充的所有值和問題字段的錯誤消息。
  8. +
  9. 如果所有數據均有效,請執行所需的操作(例如,保存數據,發送和發送電子郵件,返回搜索結果,上傳文件等)
  10. +
  11. 完成所有操作後,將用戶重定向到另一個頁面。
  12. +
+ +

Django提供了許多工具和方法來幫助您完成上述任務。 最基本的是 Form類,它簡化了表單HTML的生成和數據清除/驗證的過程。 在下一節中,我們將使用頁面的實際示例描述表單如何工作,以使圖書館員可以續訂書籍。

+ +
+

注意: 當我們討論Django的更多“高級”表單框架類時,了解Form的使用方式將對您有所幫助。

+
+ +

使用表單和功能視圖續訂表單

+ +

接下來,我們將添加一個頁面,以使圖書館員可以續借借來的書。 為此,我們將創建一個允許用戶輸入日期值的表單。 我們將從當前日期(正常藉閱期)起3週內為該字段提供初始值,並添加一些驗證以確保館員不能輸入過去的日期或將來的日期。 輸入有效日期後,我們會將其寫入當前記錄的BookInstance.due_back 字段中。

+ +

該示例將使用基於函數的視圖和Form 類。 以下各節說明表單的工作方式,以及您需要對正在進行的LocalLibrary項目進行的更改。

+ +

Form

+ +

Form類是Django表單處理系統的核心。 它指定表單中的字段,其佈局,顯示小部件,標籤,初始值,有效值,以及(一旦驗證)與無效字段關聯的錯誤消息。 該類還提供了使用預定義格式(表,列表等)在模板中呈現自身的方法,或用於獲取任何元素的值(啟用細粒度手動呈現)的方法。

+ +

申報表格

+ +

Form 的聲明語法與聲明Model的語法非常相似,並且具有相同的字段類型(和一些相似的參數)。 這是有道理的,因為在兩種情況下,我們都需要確保每個字段都處理正確的數據類型,被限制為有效數據並具有顯示/文檔描述。

+ +

要創建一個表單,我們導入Form 庫,從Form 類派生,並聲明表單的字段。 下面顯示了我們的圖書館圖書續訂表格的一個非常基本的表格類:

+ +
from django import forms
+
+class RenewBookForm(forms.Form):
+    renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")
+
+ +

Form fields

+ +

In this case we have a single DateField for entering the renewal date that will render in HTML with a blank value, the default label "Renewal date:", and some helpful usage text: "Enter a date between now and 4 weeks (default 3 weeks)." As none of the other optional arguments are specified the field will accept dates using the input_formats: YYYY-MM-DD (2016-11-06), MM/DD/YYYY (02/26/2016), MM/DD/YY (10/25/16), and will be rendered using the default widget: DateInput.

+ +

There are many other types of form fields, which you will largely recognise from their similarity to the equivalent model field classes: BooleanField, CharField, ChoiceField, TypedChoiceField, DateField, DateTimeField, DecimalField, DurationField, EmailField, FileField, FilePathField, FloatField, ImageField, IntegerField, GenericIPAddressField, MultipleChoiceField, TypedMultipleChoiceField, NullBooleanField, RegexField, SlugField, TimeField, URLField, UUIDField, ComboField, MultiValueField, SplitDateTimeField, ModelMultipleChoiceField, ModelChoiceField​​​​.

+ +

The arguments that are common to most fields are listed below (these have sensible default values):

+ + + +

Validation

+ +

Django provides numerous places where you can validate your data. The easiest way to validate a single field is to override the method clean_<fieldname>() for the field you want to check. So for example, we can validate that entered renewal_date values are between now and 4 weeks by implementing clean_renewal_date() as shown below.

+ +
from django import forms
+
+from django.core.exceptions import ValidationError
+from django.utils.translation import ugettext_lazy as _
+import datetime #for checking renewal date range.
+
+class RenewBookForm(forms.Form):
+    renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")
+
+    def clean_renewal_date(self):
+        data = self.cleaned_data['renewal_date']
+
+        #Check date is not in past.
+        if data < datetime.date.today():
+            raise ValidationError(_('Invalid date - renewal in past'))
+
+        #Check date is in range librarian allowed to change (+4 weeks).
+        if data > datetime.date.today() + datetime.timedelta(weeks=4):
+            raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))
+
+        # Remember to always return the cleaned data.
+        return data
+ +

There are two important things to note. The first is that we get our data using self.cleaned_data['renewal_date'] and that we return this data whether or not we change it at the end of the function. This step gets us the data "cleaned" and sanitised of potentially unsafe input using the default validators, and converted into the correct standard type for the data (in this case a Python datetime.datetime object).

+ +

The second point is that if a value falls outside our range we raise a ValidationError, specifying the error text that we want to display in the form if an invalid value is entered. The example above also wraps this text in one of Django's translation functions ugettext_lazy() (imported as _()), which is good practice if you want to translate your site later.

+ +
+

Note: There are numerious other methods and examples for validating forms in Form and field validation (Django docs). For example, in cases where you have multiple fields that depend on each other, you can override the Form.clean() function and again raise a ValidationError.

+
+ +

That's all we need for the form in this example!

+ +

Copy the Form

+ +

Create and open the file locallibrary/catalog/forms.py and copy the entire code listing from the previous block into it.

+ +

URL Configuration

+ +

Before we create our view, let's add a URL configuration for the renew-books page. Copy the following configuration to the bottom of locallibrary/catalog/urls.py.

+ +
urlpatterns += [
+    path('book/<uuid:pk>/renew/', views.renew_book_librarian, name='renew-book-librarian'),
+]
+ +

The URL configuration will redirect URLs with the format /catalog/book/<bookinstance id>/renew/ to the function named renew_book_librarian() in views.py, and send the BookInstance id as the parameter named pk. The pattern only matches if pk is a correctly formatted uuid.

+ +
+

Note: We can name our captured URL data "pk" anything we like, because we have complete control over the view function (we're not using a generic detail view class that expects parameters with a certain name). However pk, short for "primary key", is a reasonable convention to use!

+
+ +

View

+ +

As discussed in the Django form handling process above, the view has to render the default form when it is first called and then either re-render it with error messages if the data is invalid, or process the data and redirect to a new page if the data is valid. In order to perform these different actions, the view has to be able to know whether it is being called for the first time to render the default form, or a subsequent time to validate data. 

+ +

For forms that use a POST request to submit information to the server, the most common pattern is for the view to test against the POST request type (if request.method == 'POST':) to identify form validation requests and GET (using an else condition) to identify the initial form creation request. If you want to submit your data using a GET request then a typical approach for identifying whether this is the first or subsequent view invocation is to read the form data (e.g. to read a hidden value in the form).

+ +

The book renewal process will be writing to our database, so by convention we use the POST request approach. The code fragment below shows the (very standard) pattern for this sort of function view. 

+ +
from django.shortcuts import get_object_or_404
+from django.http import HttpResponseRedirect
+from django.urls import reverse
+import datetime
+
+from .forms import RenewBookForm
+
+def renew_book_librarian(request, pk):
+    book_inst=get_object_or_404(BookInstance, pk = pk)
+
+    # If this is a POST request then process the Form data
+    if request.method == 'POST':
+
+        # Create a form instance and populate it with data from the request (binding):
+        form = RenewBookForm(request.POST)
+
+        # Check if the form is valid:
+        if form.is_valid():
+            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
+            book_inst.due_back = form.cleaned_data['renewal_date']
+            book_inst.save()
+
+            # redirect to a new URL:
+            return HttpResponseRedirect(reverse('all-borrowed') )
+
+    # If this is a GET (or any other method) create the default form.
+    else:
+        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
+        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})
+ +

First we import our form (RenewBookForm) and a number of other useful objects/methods used in the body of the view function:

+ + + +

In the view we first use the pk argument in get_object_or_404() to get the current BookInstance (if this does not exist, the view will immediately exit and the page will display a "not found" error). If this is not a POST request (handled by the else clause) then we create the default form passing in an initial value for the renewal_date field (as shown in bold below, this is 3 weeks from the current date). 

+ +
    book_inst=get_object_or_404(BookInstance, pk = pk)
+
+    # If this is a GET (or any other method) create the default form
+    else:
+        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
+        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})
+ +

After creating the form, we call render() to create the HTML page, specifying the template and a context that contains our form. In this case the context also contains our BookInstance, which we'll use in the template to provide information about the book we're renewing.

+ +

If however this is a POST request, then we create our form object and populate it with data from the request. This process is called "binding" and allows us to validate the form. We then check if the form is valid, which runs all the validation code on all of the fields — including both the generic code to check that our date field is actually a valid date and our specific form's clean_renewal_date() function to check the date is in the right range. 

+ +
    book_inst=get_object_or_404(BookInstance, pk = pk)
+
+    # If this is a POST request then process the Form data
+    if request.method == 'POST':
+
+        # Create a form instance and populate it with data from the request (binding):
+        form = RenewBookForm(request.POST)
+
+        # Check if the form is valid:
+        if form.is_valid():
+            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
+            book_inst.due_back = form.cleaned_data['renewal_date']
+            book_inst.save()
+
+            # redirect to a new URL:
+            return HttpResponseRedirect(reverse('all-borrowed') )
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})
+ +

If the form is not valid we call render() again, but this time the form value passed in the context will include error messages. 

+ +

If the form is valid, then we can start to use the data, accessing it through the form.cleaned_data attribute (e.g. data = form.cleaned_data['renewal_date']). Here we just save the data into the due_back value of the associated BookInstance object.

+ +
+

Important: While you can also access the form data directly through the request (for example request.POST['renewal_date'] or request.GET['renewal_date'] (if using a GET request) this is NOT recommended. The cleaned data is sanitised, validated, and converted into Python-friendly types.

+
+ +

The final step in the form-handling part of the view is to redirect to another page, usually a "success" page. In this case we use HttpResponseRedirect and reverse() to redirect to the view named 'all-borrowed' (this was created as the "challenge" in Django Tutorial Part 8: User authentication and permissions). If you didn't create that page consider redirecting to the home page at URL '/').

+ +

That's everything needed for the form handling itself, but we still need to restrict access to the view to librarians. We should probably create a new permission in BookInstance ("can_renew"), but to keep things simple here we just use the @permission_required function decorator with our existing can_mark_returned permission.

+ +

The final view is therefore as shown below. Please copy this into the bottom of locallibrary/catalog/views.py.

+ +
from django.contrib.auth.decorators import permission_required
+
+from django.shortcuts import get_object_or_404
+from django.http import HttpResponseRedirect
+from django.urls import reverse
+import datetime
+
+from .forms import RenewBookForm
+
+@permission_required('catalog.can_mark_returned')
+def renew_book_librarian(request, pk):
+    """
+    View function for renewing a specific BookInstance by librarian
+    """
+    book_inst=get_object_or_404(BookInstance, pk = pk)
+
+    # If this is a POST request then process the Form data
+    if request.method == 'POST':
+
+        # Create a form instance and populate it with data from the request (binding):
+        form = RenewBookForm(request.POST)
+
+        # Check if the form is valid:
+        if form.is_valid():
+            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
+            book_inst.due_back = form.cleaned_data['renewal_date']
+            book_inst.save()
+
+            # redirect to a new URL:
+            return HttpResponseRedirect(reverse('all-borrowed') )
+
+    # If this is a GET (or any other method) create the default form.
+    else:
+        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
+        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})
+
+ +

The template

+ +

Create the template referenced in the view (/catalog/templates/catalog/book_renew_librarian.html) and copy the code below into it:

+ +
{% extends "base_generic.html" %}
+{% block content %}
+
+    <h1>Renew: \{{bookinst.book.title}}</h1>
+    <p>Borrower: \{{bookinst.borrower}}</p>
+    <p{% if bookinst.is_overdue %} class="text-danger"{% endif %}>Due date: \{{bookinst.due_back}}</p>
+
+    <form action="" method="post">
+        {% csrf_token %}
+        <table>
+        \{{ form }}
+        </table>
+        <input type="submit" value="Submit" />
+    </form>
+
+{% endblock %}
+ +

Most of this will be completely familiar from previous tutorials. We extend the base template and then redefine the content block. We are able to reference \{{bookinst}} (and its variables) because it was passed into the context object in the render() function, and we use these to list the book title, borrower and the original due date.

+ +

The form code is relatively simple. First we declare the form tags, specifying where the form is to be submitted (action) and the method for submitting the data (in this case an "HTTP POST") — if you recall the HTML Forms overview at the top of the page, an empty action as shown, means that the form data will be posted back to the current URL of the page (which is what we want!). Inside the tags we define the submit input, which a user can press to submit the data. The {% csrf_token %} added just inside the form tags is part of Django's cross-site forgery protection.

+ +
+

Note: Add the {% csrf_token %} to every Django template you create that uses POST to submit data. This will reduce the chance of forms being hijacked by malicious users.

+
+ +

All that's left is the \{{form}} template variable, which we passed to the template in the context dictionary. Perhaps unsurprisingly, when used as shown this provides the default rendering of all the form fields, including their labels, widgets, and help text — the rendering is as shown below:

+ +
<tr>
+  <th><label for="id_renewal_date">Renewal date:</label></th>
+  <td>
+    <input id="id_renewal_date" name="renewal_date" type="text" value="2016-11-08" required />
+    <br />
+    <span class="helptext">Enter date between now and 4 weeks (default 3 weeks).</span>
+  </td>
+</tr>
+
+ +
+

Note: It is perhaps not obvious because we only have one field, but by default every field is defined in its own table row (which is why the variable is inside table tags above).​​​​​​ This same rendering is provided if you reference the template variable \{{ form.as_table }}.

+
+ +

If you were to enter an invalid date, you'd additionally get a list of the errors rendered in the page (shown in bold below).

+ +
<tr>
+  <th><label for="id_renewal_date">Renewal date:</label></th>
+   <td>
+      <ul class="errorlist">
+        <li>Invalid date - renewal in past</li>
+      </ul>
+      <input id="id_renewal_date" name="renewal_date" type="text" value="2015-11-08" required />
+      <br />
+      <span class="helptext">Enter date between now and 4 weeks (default 3 weeks).</span>
+    </td>
+</tr>
+ +

Other ways of using form template variable

+ +

Using \{{form}} as shown above, each field is rendered as a table row. You can also render each field as a list item (using \{{form.as_ul}} ) or as a paragraph (using \{{form.as_p}}).

+ +

What is even more cool is that you can have complete control over the rendering of each part of the form, by indexing its properties using dot notation. So for example we can access a number of separate items for our renewal_date field:

+ + + +

For more examples of how to manually render forms in templates and dynamically loop over template fields, see Working with forms > Rendering fields manually (Django docs).

+ +

Testing the page

+ +

If you accepted the "challenge" in Django Tutorial Part 8: User authentication and permissions you'll have a list of all books on loan in the library, which is only visible to library staff. We can add a link to our renew page next to each item using the template code below.

+ +
{% if perms.catalog.can_mark_returned %}- <a href="{% url 'renew-book-librarian' bookinst.id %}">Renew</a>  {% endif %}
+ +
+

Note: Remember that your test login will need to have the permission "catalog.can_mark_returned" in order to access the renew book page (perhaps use your superuser account).

+
+ +

You can alternatively manually construct a test URL like this — http://127.0.0.1:8000/catalog/book/<bookinstance_id>/renew/ (a valid bookinstance id can be obtained by navigating to a book detail page in your library, and copying the id field).

+ +

What does it look like?

+ +

If you are successful, the default form will look like this:

+ +

+ +

The form with an invalid value entered, will look like this:

+ +

+ +

The list of all books with renew links will look like this:

+ +

+ +

ModelForms

+ +

Creating a Form class using the approach described above is very flexible, allowing you to create whatever sort of form page you like and associate it with any model or models.

+ +

However if you just need a form to map the fields of a single model then your model will already define most of the information that you need in your form: fields, labels, help text, etc. Rather than recreating the model definitions in your form, it is easier to use the ModelForm helper class to create the form from your model. This ModelForm can then be used within your views in exactly the same way as an ordinary Form.

+ +

A basic ModelForm containing the same field as our original RenewBookForm is shown below. All you need to do to create the form is add class Meta with the associated model (BookInstance) and a list of the model fields to include in the form (you can include all fields using fields = '__all__', or you can use exclude (instead of fields) to specify the fields not to include from the model).

+ +
from django.forms import ModelForm
+from .models import BookInstance
+
+class RenewBookModelForm(ModelForm):
+    class Meta:
+        model = BookInstance
+        fields = ['due_back',]
+
+ +
+

Note: This might not look like all that much simpler than just using a Form (and it isn't in this case, because we just have one field). However if you have a lot of fields, it can reduce the amount of code quite significantly!

+
+ +

The rest of the information comes from the model field definitions (e.g. labels, widgets, help text, error messages). If these aren't quite right, then we can override them in our class Meta, specifying a dictionary containing the field to change and its new value. For example, in this form we might want a label for our field of "Renewal date" (rather than the default based on the field name: Due date), and we also want our help text to be specific to this use case. The Meta below shows you how to override these fields, and you can similarly set widgets and error_messages if the defaults aren't sufficient.

+ +
class Meta:
+    model = BookInstance
+    fields = ['due_back',]
+    labels = { 'due_back': _('Renewal date'), }
+    help_texts = { 'due_back': _('Enter a date between now and 4 weeks (default 3).'), } 
+
+ +

To add validation you can use the same approach as for a normal Form — you define a function named clean_field_name() and raise ValidationError exceptions for invalid values. The only difference with respect to our original form is that the model field is named due_back and not "renewal_date".

+ +
from django.forms import ModelForm
+from .models import BookInstance
+
+class RenewBookModelForm(ModelForm):
+    def clean_due_back(self):
+       data = self.cleaned_data['due_back']
+
+       #Check date is not in past.
+       if data < datetime.date.today():
+           raise ValidationError(_('Invalid date - renewal in past'))
+
+       #Check date is in range librarian allowed to change (+4 weeks)
+       if data > datetime.date.today() + datetime.timedelta(weeks=4):
+           raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))
+
+       # Remember to always return the cleaned data.
+       return data
+
+    class Meta:
+        model = BookInstance
+        fields = ['due_back',]
+        labels = { 'due_back': _('Renewal date'), }
+        help_texts = { 'due_back': _('Enter a date between now and 4 weeks (default 3).'), }
+
+ +

The class RenewBookModelForm below is now functionally equivalent to our original RenewBookForm. You could import and use it wherever you currently use RenewBookForm.

+ +

Generic editing views

+ +

The form handling algorithm we used in our function view example above represents an extremely common pattern in form editing views. Django abstracts much of this "boilerplate" for you, by creating generic editing views for creating, editing, and deleting views based on models. Not only do these handle the "view" behaviour, but they automatically create the form class (a ModelForm) for you from the model.

+ +
+

Note: In addition to the editing views described here, there is also a FormView class, which lies somewhere between our function view and the other generic views in terms of "flexibility" vs "coding effort". Using FormView you still need to create your Form, but you don't have to implement all of the standard form-handling pattern. Instead you just have to provide an implementation of the function that will be called once the submitted is known to be be valid.

+
+ +

In this section we're going to use generic editing views to create pages to add functionality to create, edit, and delete Author records from our library — effectively providing a basic reimplementation of parts of the Admin site (this could be useful if you need to offer admin functionality in a more flexible way that can be provided by the admin site).

+ +

Views

+ +

Open the views file (locallibrary/catalog/views.py) and append the following code block to the bottom of it:

+ +
from django.views.generic.edit import CreateView, UpdateView, DeleteView
+from django.urls import reverse_lazy
+from .models import Author
+
+class AuthorCreate(CreateView):
+    model = Author
+    fields = '__all__'
+    initial={'date_of_death':'05/01/2018',}
+
+class AuthorUpdate(UpdateView):
+    model = Author
+    fields = ['first_name','last_name','date_of_birth','date_of_death']
+
+class AuthorDelete(DeleteView):
+    model = Author
+    success_url = reverse_lazy('authors')
+ +

As you can see, to create the views you need to derive from CreateView, UpdateView, and DeleteView (respectively) and then define the associated model.

+ +

For the "create" and "update" cases you also need to specify the fields to display in the form (using in same syntax as for ModelForm). In this case we show both the syntax to display "all" fields, and how you can list them individually. You can also specify initial values for each of the fields using a dictionary of field_name/value pairs (here we arbitrarily set the date of death for demonstration purposes — you might want to remove that!). By default these views will redirect on success to a page displaying the newly created/edited model item, which in our case will be the author detail view we created in a previous tutorial. You can specify an alternative redirect location by explicitly declaring parameter success_url (as done for the AuthorDelete class).

+ +

The AuthorDelete class doesn't need to display any of the fields, so these don't need to be specified. You do however need to specify the success_url, because there is no obvious default value for Django to use. In this case we use the reverse_lazy() function to redirect to our author list after an author has been deleted — reverse_lazy() is a lazily executed version of reverse(), used here because we're providing a URL to a class-based view attribute.

+ +

Templates

+ +

The "create" and "update" views use the same template by default, which will be named after your model: model_name_form.html (you can change the suffix to something other than _form using the template_name_suffix field in your view, e.g. template_name_suffix = '_other_suffix')

+ +

Create the template file locallibrary/catalog/templates/catalog/author_form.html and copy in the text below.

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+
+<form action="" method="post">
+    {% csrf_token %}
+    <table>
+    \{{ form.as_table }}
+    </table>
+    <input type="submit" value="Submit" />
+
+</form>
+{% endblock %}
+ +

This is similar to our previous forms, and renders the fields using a table. Note also how again we declare the {% csrf_token %} to ensure that our forms are resistant to CSRF attacks.

+ +

The "delete" view expects to find a template named with the format model_name_confirm_delete.html (again, you can change the suffix using template_name_suffix in your view). Create the template file locallibrary/catalog/templates/catalog/author_confirm_delete.html and copy in the text below.

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+
+<h1>Delete Author</h1>
+
+<p>Are you sure you want to delete the author: \{{ author }}?</p>
+
+<form action="" method="POST">
+  {% csrf_token %}
+  <input type="submit" action="" value="Yes, delete." />
+</form>
+
+{% endblock %}
+
+ +

URL configurations

+ +

Open your URL configuration file (locallibrary/catalog/urls.py) and add the following configuration to the bottom of the file:

+ +
urlpatterns += [
+    path('author/create/', views.AuthorCreate.as_view(), name='author_create'),
+    path('author/<int:pk>/update/', views.AuthorUpdate.as_view(), name='author_update'),
+    path('author/<int:pk>/delete/', views.AuthorDelete.as_view(), name='author_delete'),
+]
+ +

There is nothing particularly new here! You can see that the views are classes, and must hence be called via .as_view(), and you should be able to recognise the URL patterns in each case. We must use pk as the name for our captured primary key value, as this is the parameter name expected by the view classes.

+ +

The author create, update, and delete pages are now ready to test (we won't bother hooking them into the site sidebar in this case, although you can do so if you wish).

+ +
+

Note: Observant users will have noticed that we didn't do anything to prevent unauthorised users from accessing the pages! We leave that as an exercise for you (hint: you could use the PermissionRequiredMixin and either create a new permission or reuse our can_mark_returned permission).

+
+ +

Testing the page

+ +

First login to the site with an account that has whatever permissions you decided are needed to access the author editing pages.

+ +

Then navigate to the author create page: http://127.0.0.1:8000/catalog/author/create/, which should look like the screenshot below.

+ +

Form Example: Create Author

+ +

Enter values for the fields and then press Submit to save the author record. You should now be taken to a detail view for your new author, with a URL of something like http://127.0.0.1:8000/catalog/author/10.

+ +

You can test editing records by appending /update/ to the end of the detail view URL (e.g. http://127.0.0.1:8000/catalog/author/10/update/) — we don't show a screenshot, because it looks just like the "create" page!

+ +

Last of all we can delete the page, by appending delete to the end of the author detail-view URL (e.g. http://127.0.0.1:8000/catalog/author/10/delete/). Django should display the delete page shown below. Press Yes, delete. to remove the record and be taken to the list of all authors.

+ +

+ +

Challenge yourself

+ +

Create some forms to create, edit and delete Book records. You can use exactly the same structure as for Authors. If your book_form.html template is just a copy-renamed version of the author_form.html template, then the new "create book" page will look like the screenshot below:

+ +

+ + + +

Summary

+ +

Creating and handling forms can be a complicated process! Django makes it much easier by providing programmatic mechanisms to declare, render and validate forms. Furthermore, Django provides generic form editing views that can do almost all the work to define pages that can create, edit, and delete records associated with a single model instance.

+ +

There is a lot more that can be done with forms (check out our See also list below), but you should now understand how to add basic forms and form-handling code to your own websites.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/server-side/django/generic_views/index.html b/files/zh-tw/learn/server-side/django/generic_views/index.html new file mode 100644 index 0000000000..240354cd6b --- /dev/null +++ b/files/zh-tw/learn/server-side/django/generic_views/index.html @@ -0,0 +1,612 @@ +--- +title: 'Django Tutorial Part 6: Generic list and detail views' +slug: Learn/Server-side/Django/Generic_views +translation_of: Learn/Server-side/Django/Generic_views +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}
+ +

本教程擴充了 LocalLibrary 網站,為書本與作者增加列表與細節頁面。此處我們將學到通用類別視圖,並演示如何降低你必須為一般使用案例撰寫的程式碼數量。我們也會更加深入 URL 處理細節,演示如何實施基本模式匹配。

+ + + + + + + + + + + + +
前提:Complete all previous tutorial topics, including Django Tutorial Part 5: Creating our home page.
目的:To understand where and how to use generic class-based views, and how to extract patterns from URLs and pass the information to views.
+ +

Overview

+ +

本教程中,通過為書本和作者添加列表和詳細信息頁面,我們將完成第一個版本的 LocalLibrary 網站(或者更準確地說,我們將向您展示如何實現書頁,並讓您自己創建作者頁面!) )

+ +

該過程在創建索引頁面,我們在上一個教程中展示了該頁面。我們仍然需要創建URL地圖,視圖和模板。主要區別在於,對於詳細信息頁面,我們還有一個額外的挑戰,即從URL對於這些頁面,我們將演示一種完全不同的視圖類型:基於類別的通用列表和詳細視圖。這些可以顯著減少所需的視圖代碼量,有助於更容易編寫和維護。

+ +

本教程的最後一部分,將演示在使用基於類別的通用列表視圖時,如何對數據進行分頁。

+ +

Book list page

+ +

該書將顯示每條記錄的標題和作者,標題是指向相關圖書詳細信息頁面的超鏈接。該頁面將具有與站點中,所有其他頁面相同的結構和導航,因此,我們可以擴展在上一個教程中創建的基本模板 (base_generic.html)。

+ +

URL mapping

+ +

開啟/catalog/urls.py,並複製加入下面粗體顯示的代碼。就像索引頁面的方式,這個path()函數,定義了一個與URL匹配的模式('books /'),如果URL匹配,將調用視圖函數(views.BookListView.as_view())和一個對應的特定映射的名稱。

+ +
urlpatterns = [
+    path('', views.index, name='index'),
+    path('books/', views.BookListView.as_view(), name='books'),
+]
+ +

正如前一個教程中所討論的,URL必須已經先匹配了/ catalog,因此實際上將為URL調用的視圖是:/ catalog / books /。

+ +

我們將繼承現有的泛型視圖函數,該函數已經完成了我們希望此視圖函數執行的大部分工作,而不是從頭開始編寫自己的函數。對於基於Django類的視圖,我們通過調用類方法as_view(),來訪問適當的視圖函數。由此可以創建類的實例,並確保為HTTP請求正確的處理程序方法。

+ +

View (class-based)

+ +

我們可以很容易地,將書本列表列表編寫為常規函數(就像我們之前的索引視圖一樣),進入查詢數據庫中的所有書本,然後調用render(),將列表傳遞給指定的模板。然而,我們用另一種方​​法取代,我們將使用基於類的通用列表視圖(ListView)-一個繼承自現有視圖的類。因為通用視圖,已經實現了我們需要的大部分功能,並且遵循Django最佳實踐,我們將能夠創建更強大的列表視圖,代碼更多,重複次數最多,最終維護所需。

+ +

開啟catalog / views.py,將以下代碼複製到文件的底部:

+ +
from django.views import generic
+
+class BookListView(generic.ListView):
+    model = Book
+ +

就是這樣!通用view將查詢數據庫,以獲取指定模型(Book)的所有記錄,然後呈現/locallibrary/catalog/templates/catalog/book_list.html的模板(我們將在下面創建)。在模板中,您可以使用所謂的object_list或book_list的模板變量(即通常為“ the_model_name_list”),以訪問書本列表。

+ +
+

Note: This awkward path for the template location isn't a misprint — the generic views look for templates in /application_name/the_model_name_list.html (catalog/book_list.html in this case) inside the application's /application_name/templates/ directory (/catalog/templates/).

+
+ +

您可以添加屬性,以更改上面的某種行為。例如,如果需要使用同一模型的多個視圖,則可以指定另一個模板文件,或者如果book_list對於特定模板用例不直觀,則可能需要使用不同的模板變量名稱。可能最有用的變更,是更改/過濾返回的結果子集-因此,您可能會列出其他用戶閱讀的前5本書,而不是列出所有書本。

+ +
class BookListView(generic.ListView):
+    model = Book
+    context_object_name = 'my_book_list'   # your own name for the list as a template variable
+    queryset = Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war
+    template_name = 'books/my_arbitrary_template_name_list.html'  # Specify your own template name/location
+ +

Overriding methods in class-based views

+ +

雖然我們不需要在這裡執行此操作,但您也可以覆寫某些類別方法。

+ +

例如,我們可以覆寫get_queryset()方法,來更改返回的記錄列表。這比單獨設置queryset屬性更靈活,就像我們在前面的代碼片段中進行的那樣(儘管在這案例中沒有太大用處):

+ +
class BookListView(generic.ListView):
+    model = Book
+
+    def get_queryset(self):
+        return Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war
+
+ +

我們還可以重寫get_context_data() 以便將其他上下文變數傳遞給模組 (例如,默認情況下傳遞書籍列表). 下面的片段顯示瞭如何向上下文添加名為"some_data" 的變數(然後它將用作模組變數)

+ +
class BookListView(generic.ListView):
+    model = Book
+
+    def get_context_data(self, **kwargs):
+        # Call the base implementation first to get the context
+        context = super(BookListView, self).get_context_data(**kwargs)
+        # Create any data and add it to the context
+        context['some_data'] = 'This is just some data'
+        return context
+ +

執行此操作時,務必遵循上面使用的模式:

+ + + +
+

Note: Check out Built-in class-based generic views (Django docs) for many more examples of what you can do.

+
+ +

Creating the List View template

+ +

建立HTML及複製以下文字串到/locallibrary/catalog/templates/catalog/book_list.html , 這是基於通用類的列表視圖所期望的默認模板文件 (默認在catalog中名稱為Book 的模組).

+ +

通用的views模板跟其他的模板沒有不同 (儘管傳遞給模板的內文/訊息當然可以不同). 與index模板一樣,我們在第一行中擴展了基本模板,然後更替名為 content的區塊。

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <h1>Book List</h1>
+  {% if book_list %}
+  <ul>
+    {% for book in book_list %}
+      <li>
+        <a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}})
+      </li>
+    {% endfor %}
+  </ul>
+  {% else %}
+    <p>There are no books in the library.</p>
+  {% endif %} 
+{% endblock %}
+ +

該視圖默認將上下文(書籍列表)作為object_list 和 book_list 別名傳遞;兩者都會起作用.

+ +

Conditional execution

+ +

我們使用 if, else 和 endif 模組標籤,以檢查book_list 是否已定義並且不為空。 如果 book_list 為空值, 則 else 子句回傳text 說明沒有書可以列出. 如果book_list不是空值, 然後我們遍曆書籍清單。

+ +
{% if book_list %}
+  <!-- code here to list the books -->
+{% else %}
+  <p>There are no books in the library.</p>
+{% endif %}
+
+ +

The condition above only checks for one case, but you can test on additional conditions using the elif template tag (e.g. {% elif var2 %} ). For more information about conditional operators see: if, ifequal/ifnotequal, and ifchanged in Built-in template tags and filters (Django Docs).

+ +

For loops

+ +

The template uses the for and endfor template tags to loop through the book list, as shown below. Each iteration populates the book template variable with information for the current list item.

+ +
{% for book in book_list %}
+  <li> <!-- code here get information from each book item --> </li>
+{% endfor %}
+
+ +

While not used here, within the loop Django will also create other variables that you can use to track the iteration. For example, you can test the forloop.last variable to perform conditional processing the last time that the loop is run.

+ +

Accessing variables

+ +

The code inside the loop creates a list item for each book that shows both the title (as a link to the yet-to-be-created detail view) and the author.

+ +
<a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}})
+
+ +

We access the fields of the associated book record using the "dot notation" (e.g. book.title and book.author), where the text following the book item is the field name (as defined in the model).

+ +

We can also call functions in the model from within our template — in this case we call Book.get_absolute_url() to get an URL you could use to display the associated detail record. This works provided the function does not have any arguments (there is no way to pass arguments!)

+ +
+

Note: We have to be a little careful of "side effects" when calling functions in templates. Here we just get a URL to display, but a function can do pretty much anything — we wouldn't want to delete our database (for example) just by rendering our template!

+
+ +

Update the base template

+ +

Open the base template (/locallibrary/catalog/templates/base_generic.html) and insert {% url 'books' %} into the URL link for All books, as shown below. This will enable the link in all pages (we can successfully put this in place now that we've created the "books" url mapper).

+ +
<li><a href="{% url 'index' %}">Home</a></li>
+<li><a href="{% url 'books' %}">All books</a></li>
+<li><a href="">All authors</a></li>
+ +

What does it look like?

+ +

You won't be able to build book list yet, because we're still missing a dependency — the URL map for the book detail pages, which is needed to create hyperlinks to individual books. We'll show both list and detail views after the next section.

+ +

Book detail page

+ +

The book detail page will display information about a specific book, accessed using the URL catalog/book/<id> (where <id> is the primary key for the book). In addition to fields in the Book model (author, summary, ISBN, language, and genre), we'll also list the details of the available copies (BookInstances) including the status, expected return date, imprint, and id. This will allow our readers not just to learn about the book, but also to confirm whether/when it is available.

+ +

URL mapping

+ +

Open /catalog/urls.py and add the 'book-detail' URL mapper shown in bold below. This path() function defines a pattern, associated generic class-based detail view, and a name.

+ +
urlpatterns = [
+    path('', views.index, name='index'),
+    path('books/', views.BookListView.as_view(), name='books'),
+    path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail'),
+]
+ +

For the book-detail path the URL pattern uses a special syntax to capture the specific id of the book that we want to see. The syntax is very simple: angle brackets define the part of the URL to be captured, enclosing the name of the variable that the view can use to access the captured data. For example, <something> , will capture the marked pattern and pass the value to the view as a variable "something". You can optionally precede the variable name with a converter specification that defines the type of data (int, str, slug, uuid, path).

+ +

In this case we use '<int:pk>'  to capture the book id, which must be an integer, and pass it to the view as a parameter named pk (short for primary key).

+ +
+

Note: As discussed previously, our matched URL is actually catalog/book/<digits> (because we are in the catalog application, /catalog/ is assumed).

+
+ +
+

Important: The generic class-based detail view expects to be passed a parameter named pk. If you're writing your own function view you can use whatever parameter name you like, or indeed pass the information in an unnamed argument.

+
+ +

Advanced path matching/regular expression primer

+ +
+

Note: You won't need this section to complete the tutorial! We provide it because knowing this option is likely to be useful in your Django-centric future.

+
+ +

The pattern matching provided by path() is simple and useful for the (very common) cases where you just want to capture any string or integer. If you need more refined filtering (for example, to filter only strings that have a certain number of characters) then you can use the re_path() method.

+ +

This method is used just like path() except that it allows you to specify a pattern using a Regular expression. For example, the previous path could have been written as shown below:

+ +
re_path(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view(), name='book-detail'),
+
+ +

Regular expressions are an incredibly powerful pattern mapping tool. They are, frankly, quite unintuitive and scary for beginners. Below is a very short primer!

+ +

The first thing to know is that regular expressions should usually be declared using the raw string literal syntax (i.e. they are enclosed as shown: r'<your regular expression text goes here>').

+ +

The main parts of the syntax you will need to know for declaring the pattern matches are:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SymbolMeaning
^Match the beginning of the text
$Match the end of the text
\dMatch a digit (0, 1, 2, ... 9)
\wMatch a word character, e.g. any upper- or lower-case character in the alphabet, digit or the underscore character (_)
+Match one or more of the preceding character. For example, to match one or more digits you would use \d+. To match one or more "a" characters, you could use a+
*Match zero or more of the preceding character. For example, to match nothing or a word you could use \w*
( )Capture the part of the pattern inside the brackets. Any captured values will be passed to the view as unnamed parameters (if multiple patterns are captured, the associated parameters will be supplied in the order that the captures were declared).
(?P<name>...)Capture the pattern (indicated by ...) as a named variable (in this case "name"). The captured values are passed to the view with the name specified. Your view must therefore declare an argument with the same name!
[  ]Match against one character in the set. For example, [abc] will match on 'a' or 'b' or 'c'. [-\w] will match on the '-' character or any word character.
+ +

Most other characters can be taken literally!

+ +

Lets consider a few real examples of patterns:

+ + + + + + + + + + + + + + + + + + + + + + +
PatternDescription
r'^book/(?P<pk>\d+)$' +

This is the RE used in our url mapper. It matches a string that has book/ at the start of the line (^book/), then has one or more digits (\d+), and then ends (with no non-digit characters before the end of line marker).

+ +

It also captures all the digits (?P<pk>\d+) and passes them to the view in a parameter named 'pk'. The captured values are always passed as a string!

+ +

For example, this would match book/1234 , and send a variable pk='1234' to the view.

+
r'^book/(\d+)$'This matches the same URLs as the preceding case. The captured information would be sent as an unnamed argument to the view.
r'^book/(?P<stub>[-\w]+)$' +

This matches a string that has book/ at the start of the line (^book/), then has one or more characters that are either a '-' or a word character ([-\w]+), and then ends. It also captures this set of characters and passes them to the view in a parameter named 'stub'.

+ +

This is a fairly typical pattern for a "stub". Stubs are URL-friendly word-based primary keys for data. You might use a stub if you wanted your book URL to be more informative. For example /catalog/book/the-secret-garden rather than /catalog/book/33.

+
+ +

You can capture multiple patterns in the one match, and hence encode lots of different information in a URL.

+ +
+

Note: As a challenge, consider how you might encode an url to list all books released in a particular year, month, day, and the RE that could be used to match it.

+
+ +

Passing additional options in your URL maps

+ +

One feature that we haven't used here, but which you may find valuable, is that you can declare and pass additional options to the view. The options are declared as a dictionary that you pass as the third un-named argument to the path() function. This approach can be useful if you want to use the same view for multiple resources, and pass data to configure its behaviour in each case (below we supply a different template in each case).

+ +
path('url/', views.my_reused_view, {'my_template_name': 'some_path'}, name='aurl'),
+path('anotherurl/', views.my_reused_view, {'my_template_name': 'another_path'}, name='anotherurl'),
+
+ +
+

Note: Both extra options and named captured patterns are passed to the view as named arguments. If you use the same name for both a captured pattern and an extra option then only the captured pattern value will be sent to the view (the value specified in the additional option will be dropped). 

+
+ +

View (class-based)

+ +

Open catalog/views.py, and copy the following code into the bottom of the file:

+ +
class BookDetailView(generic.DetailView):
+    model = Book
+ +

That's it! All you need to do now is create a template called /locallibrary/catalog/templates/catalog/book_detail.html, and the view will pass it the database information for the specific Book record extracted by the URL mapper. Within the template you can access the list of books with the template variable named object OR book (i.e. generically "the_model_name").

+ +

If you need to, you can change the template used and the name of the context object used to reference the book in the template. You can also override methods to, for example, add additional information to the context.

+ +

What happens if the record doesn't exist?

+ +

If a requested record does not exist then the generic class-based detail view will raise an Http404 exception for you automatically — in production this will automatically display an appropriate "resource not found" page, which you can customise if desired.

+ +

Just to give you some idea of how this works, the code fragment below demonstrates how you would implement the class-based view as a function, if you were not using the generic class-based detail view.

+ +
def book_detail_view(request, primary_key):
+    try:
+        book = Book.objects.get(pk=primary_key)
+    except Book.DoesNotExist:
+        raise Http404('Book does not exist')
+
+    # from django.shortcuts import get_object_or_404
+    # book = get_object_or_404(Book, pk=primary_key)
+
+    return render(request, 'catalog/book_detail.html', context={'book': book})
+
+ +

The view first tries to get the specific book record from the model. If this fails the view should raise an Http404 exception to indicate that the book is "not found". The final step is then, as usual, to call render() with the template name and the book data in the context parameter (as a dictionary).

+ +
+

Note: The get_object_or_404() (shown commented out above) is a convenient shortcut to raise an Http404 exception if the record is not found.

+
+ +

Creating the Detail View template

+ +

Create the HTML file /locallibrary/catalog/templates/catalog/book_detail.html and give it the below content. As discussed above, this is the default template file name expected by the generic class-based detail view (for a model named Book in an application named catalog).

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <h1>Title: \{{ book.title }}</h1>
+
+  <p><strong>Author:</strong> <a href="">\{{ book.author }}</a></p> <!-- author detail link not yet defined -->
+  <p><strong>Summary:</strong> \{{ book.summary }}</p>
+  <p><strong>ISBN:</strong> \{{ book.isbn }}</p>
+  <p><strong>Language:</strong> \{{ book.language }}</p>
+  <p><strong>Genre:</strong> {% for genre in book.genre.all %} \{{ genre }}{% if not forloop.last %}, {% endif %}{% endfor %}</p>
+
+  <div style="margin-left:20px;margin-top:20px">
+    <h4>Copies</h4>
+
+    {% for copy in book.bookinstance_set.all %}
+    <hr>
+    <p class="{% if copy.status == 'a' %}text-success{% elif copy.status == 'm' %}text-danger{% else %}text-warning{% endif %}">\{{ copy.get_status_display }}</p>
+    {% if copy.status != 'a' %}<p><strong>Due to be returned:</strong> \{{copy.due_back}}</p>{% endif %}
+    <p><strong>Imprint:</strong> \{{copy.imprint}}</p>
+    <p class="text-muted"><strong>Id:</strong> \{{copy.id}}</p>
+    {% endfor %}
+  </div>
+{% endblock %}
+ + + +
+

The author link in the template above has an empty URL because we've not yet created an author detail page. Once that exists, you should update the URL like this:

+ +
<a href="{% url 'author-detail' book.author.pk %}">\{{ book.author }}</a>
+
+
+ +

Though a little larger, almost everything in this template has been described previously:

+ + + +

The one interesting thing we haven't seen before is the function book.bookinstance_set.all(). This method is "automagically" constructed by Django in order to return the set of BookInstance records associated with a particular Book.

+ +
{% for copy in book.bookinstance_set.all %}
+<!-- code to iterate across each copy/instance of a book -->
+{% endfor %}
+ +

需要這方法是因為我們僅在“一”那側model(Book)定義一個ForeignKey (一對多)字段的關聯,也因為沒有任何的關聯被定義在“多”那側model(BookInstance),故無法透過字段來取得相關的紀錄。為了克服這個問題,Django建立一個function取名為“reverse lookup”供使用。function的名字以一對多關係中該 ForeignKey 被定義在的那個模型名稱小寫,再在字尾加上_set(因此在 Book 創建的function名是 bookinstance_set())。

+ +
+

Note: 在這我們使用 all() 取得所有紀錄 (預設),你無法直接在template做是因為你無法指定引數到function,但你可用 filter() 方法取得一個紀錄的子集 。

+ +

順帶一提,若你不再基於類的view或model定義順序(order),開發伺服器會將會報錯類似的訊息:

+ +
[29/May/2017 18:37:53] "GET /catalog/books/?page=1 HTTP/1.1" 200 1637
+/foo/local_library/venv/lib/python3.5/site-packages/django/views/generic/list.py:99: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <QuerySet [<Author: Ortiz, David>, <Author: H. McRaven, William>, <Author: Leigh, Melinda>]>
+  allow_empty_first_page=allow_empty_first_page, **kwargs)
+
+ +

That happens because the paginator object expects to see some ORDER BY being executed on your underlying database. Without it, it can't be sure the records being returned are actually in the right order!

+ +

This tutorial didn't reach Pagination (yet, but soon enough), but since you can't use sort_by() and pass a parameter (the same with filter() described above) you will have to choose between three choices:

+ +
    +
  1. Add a ordering inside a class Meta declaration on your model.
  2. +
  3. Add a queryset attribute in your custom class-based view, specifying a order_by().
  4. +
  5. Adding a get_queryset method to your custom class-based view and also specify the order_by().
  6. +
+ +

If you decide to go with a class Meta for the Author model (probably not as flexible as customizing the class-based view, but easy enough), you will end up with something like this:

+ +
class Author(models.Model):
+    first_name = models.CharField(max_length=100)
+    last_name = models.CharField(max_length=100)
+    date_of_birth = models.DateField(null=True, blank=True)
+    date_of_death = models.DateField('Died', null=True, blank=True)
+
+    def get_absolute_url(self):
+        return reverse('author-detail', args=[str(self.id)])
+
+    def __str__(self):
+        return f'{self.last_name}, {self.first_name}'
+
+    class Meta:
+        ordering = ['last_name']
+ +

Of course, the field doesn't need to be last_name: it could be any other.

+ +

And last, but not least, you should sort by an attribute/column that actually has a index (unique or not) on your database to avoid performance issues. Of course, this will not be necessary here (and we are probably getting ourselves too much ahead) if such small amount of books (and users!), but it is something to keep in mind for future projects.

+
+ +

What does it look like?

+ +

At this point we should have created everything needed to display both the book list and book detail pages. Run the server (python3 manage.py runserver) and open your browser to http://127.0.0.1:8000/.

+ +
+

Warning: Don't click any author or author detail links yet — you'll create those in the challenge!

+
+ +

Click the All books link to display the list of books. 

+ +

Book List Page

+ +

Then click a link to one of your books. If everything is set up correctly, you should see something like the following screenshot.

+ +

Book Detail Page

+ +

Pagination

+ +

If you've just got a few records, our book list page will look fine. However, as you get into the tens or hundreds of records the page will take progressively longer to load (and have far too much content to browse sensibly). The solution to this problem is to add pagination to your list views, reducing the number of items displayed on each page. 

+ +

Django has excellent in-built support for pagination. Even better, this is built into the generic class-based list views so you don't have to do very much to enable it!

+ +

Views

+ +

Open catalog/views.py, and add the paginate_by line shown in bold below.

+ +
class BookListView(generic.ListView):
+    model = Book
+    paginate_by = 10
+ +

With this addition, as soon as you have more than 10 records the view will start paginating the data it sends to the template. The different pages are accessed using GET parameters — to access page 2 you would use the URL: /catalog/books/?page=2.

+ +

Templates

+ +

Now that the data is paginated, we need to add support to the template to scroll through the results set. Because we might want to do this in all list views, we'll do this in a way that can be added to the base template. 

+ +

Open /locallibrary/catalog/templates/base_generic.html and copy in the following pagination block below our content block (highlighted below in bold). The code first checks if pagination is enabled on the current page. If so then it adds next and previous links as appropriate (and the current page number). 

+ +
{% block content %}{% endblock %}
+
+{% block pagination %}
+  {% if is_paginated %}
+    <div class="pagination">
+      <span class="page-links">
+        {% if page_obj.has_previous %}
+          <a href="\{{ request.path }}?page=\{{ page_obj.previous_page_number }}">previous</a>
+        {% endif %}
+        <span class="page-current">
+          <p>Page \{{ page_obj.number }} of \{{ page_obj.paginator.num_pages }}.</p>
+        </span>
+        {% if page_obj.has_next %}
+          <a href="\{{ request.path }}?page=\{{ page_obj.next_page_number }}">next</a>
+        {% endif %}
+      </span>
+    </div>
+  {% endif %}
+{% endblock %} 
+ +

The page_obj is a Paginator object that will exist if pagination is being used on the current page. It allows you to get all the information about the current page, previous pages, how many pages there are, etc. 

+ +

We use \{{ request.path }} to get the current page URL for creating the pagination links. This is useful, because it is independent of the object that we're paginating.

+ +

Thats it!

+ +

What does it look like?

+ +

The screenshot below shows what the pagination looks like — if you haven't entered more than 10 titles into your database, then you can test it more easily by lowering the number specified in the paginate_by line in your catalog/views.py file. To get the below result we changed it to paginate_by = 2.

+ +

The pagination links are displayed on the bottom, with next/previous links being displayed depending on which page you're on.

+ +

Book List Page - paginated

+ +

Challenge yourself

+ +

The challenge in this article is to create the author detail and list views required to complete the project. These should be made available at the following URLs:

+ + + +

The code required for the URL mappers and the views should be virtually identical to the Book list and detail views we created above. The templates will be different, but will share similar behaviour.

+ +
+

Note:

+ + +
+ +

When you are finished, your pages should look something like the screenshots below.

+ +

Author List Page

+ + + +

Author Detail Page

+ + + +

Summary

+ +

Congratulations, our basic library functionality is now complete! 

+ +

In this article we've learned how to use the generic class-based list and detail views and used them to create pages to view our books and authors. Along the way we've learned about pattern matching with regular expressions, and how you can pass data from URLs to your views. We've also learned a few more tricks for using templates. Last of all we've shown how to paginate list views, so that our lists are managable even when we have many records.

+ +

In our next articles we'll extend this library to support user accounts, and thereby demonstrate user authentication, permissons, sessions, and forms.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/server-side/django/home_page/index.html b/files/zh-tw/learn/server-side/django/home_page/index.html new file mode 100644 index 0000000000..a01d71608e --- /dev/null +++ b/files/zh-tw/learn/server-side/django/home_page/index.html @@ -0,0 +1,383 @@ +--- +title: 'Django Tutorial Part 5: Creating our home page' +slug: Learn/Server-side/Django/Home_page +translation_of: Learn/Server-side/Django/Home_page +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}
+ +

我們現在可以添加代碼,來顯示我們的第一個完整頁面 - LocalLibrary 網站的主頁,顯示每個模型類型有多少條記錄,並提供我們其他頁面的側邊欄導航鏈接。一路上,我們將獲得編寫基本URL 地圖和視圖、從數據庫獲取記錄、以及使用模板的實踐經驗。

+ + + + + + + + + + + + +
前提:讀 the Django Introduction. 完成上章節 (including Django Tutorial Part 4: Django admin site).
目的:了解如何創建簡單的URL映射和視圖(沒有數據編碼在URL中)以及如何從模型中獲取數據並創建模版。
+ 概要
+ +

總覽

+ +

在定義了模型並創建了一些可以使用的初始庫記錄之後,是時候編寫將這些信息呈現給用戶的代碼了。 我們要做的第一件事是確定我們要在頁面中顯示的信息,並定義用於返回這些資源的URL。 然後,我們將創建一個URL映射器,視圖和模板來顯示頁面。

+ +

下圖描述了主要數據流,以及處理HTTP請求和響應時所需的組件。 當我們已經實現了模型時,我們將創建的主要組件是:

+ + + +

+ +

正如您將在下一節中看到的那樣,我們將顯示5頁,這是太多信息,無法在一篇文章中進行記錄。 因此,本文將重點介紹如何實現主頁,我們將在後續文章中介紹其他頁面。 這應該使您對URL映射器,視圖和模型在實踐中如何工作有很好的端到端理解。

+ +

定義資源URL

+ +

由於此版本的LocalLibrary對於最終用戶基本上是只讀的,因此我們只需要提供該網站的登錄頁面(主頁),以及顯示書籍和作者的列表和詳細視圖的頁面。

+ +

我們頁面所需的URL是:

+ + + +

前三個URL用於列出索引,書籍和作者。 它們不對任何其他信息進行編碼,並且雖然返回的結果將取決於數據庫中的內容,但為獲取信息而運行的查詢將始終相同。

+ +

相比之下,最後兩個URL用於顯示有關特定書籍或作者的詳細信息-這些URL編碼要顯示在URL中的項目的標識(如上顯示為<id>)。 URL映射器可以提取編碼信息並將其傳遞給視圖,然後將動態確定從數據庫中獲取哪些信息。 通過在我們的URL中編碼信息,我們只需要一個URL映射,視圖和模板即可處理每本書(或作者)。

+ +
+

注意: Django允許您以自己喜歡的任何方式來構造URL-您可以如上所示在URL主體中編碼信息或使用URL GET 參數(例如/book/?id=6)。 無論使用哪種方法,都應保持URL的整潔,邏輯和可讀性(在此處查看W3C建議).

+ +

Django文檔傾向於建議在URL正文中編碼信息,他們認為這種做法鼓勵更好的URL設計。

+
+ +

如概述中所述,本文的其餘部分描述瞭如何構造索引頁。

+ +

創建索引頁面

+ +

我們將創建的第一頁是索引頁 (catalog/)。 這將顯示一些靜態HTML,以及數據庫中不同記錄的一些計算出的“計數”。 為了完成這項工作,我們必須創建一個URL映射,視圖和模板。

+ +
+

注意:值得在本節中多加註意。 大多數材料是所有頁面共有的。

+
+ +

URL mapping

+ +

創建skeleton website 時,我們更新了locallibrary/urls.py文件,以確保每當收到以 catalog/  開頭的URL時, URLConf 模組 catalog.urls 都將處理其餘的子字符串。

+ +

來自 locallibrary/urls.py的以下代碼片段包括catalog.urls 模塊:

+ +
urlpatterns += [
+    path('catalog/', include('catalog.urls')),
+]
+
+ +
+

注意: 每當Django遇到導入函數 django.urls.include()時,它都會在指定的結束字符處分割URL字符串,並將剩餘的子字符串發送到所包含的URLconf 模塊以進行進一步處理。

+
+ +

我們還為URLConf 模塊創建了一個佔位符文件,名為 /catalog/urls.py。 將以下行添加到該文件:

+ +
urlpatterns = [
+    path('', views.index, name='index'),
+]
+ +

path()函數定義以下內容:

+ + + +

path()  函數還指定一個name參數,它是此特定URL映射的唯一標識符。 您可以使用該名稱來“反向”映射器,即,動態創建指向映射器旨在處理的資源的URL。 例如,通過在模板中添加以下鏈接,我們可以使用name參數從任何其他頁面鏈接到我們的主頁:

+ +
<a href="{% url 'index' %}">Home</a>.
+ +
+

注意: 我們可以對上面的鏈接進行硬編碼 (例如<a href="/catalog/">Home</a>), 但是如果我們更改主頁的模式 (例如更改為 /catalog/index) 則模板將不再 正確鏈接。 使用反向URL映射更加靈活和健壯!

+
+ +

View (function-based)

+ +

View是一個用來處理 HTTP 請求的函式,根據需求從資料庫取得資料,通過使用 HTML 模板呈現此數據來生成 HTML , 並且在一個 HTTP 回應中返回 HTML 來呈現給用戶。Index view 遵循這個模型 — 獲取有關數據庫中有多少 Book, BookInstance, 可用的 BookInstance 還有 Author 的訊息, 然後把他們傳遞給模板進行顯示。

+ +

打開catalog/views.py, 並且注意該文件已經導入 render() 快捷功能已使用模板和數據生成HTML文件。 

+ +
from django.shortcuts import render
+
+# Create your views here.
+
+ +

將以下代碼複製到文件底部。 第一行導入將用於訪問所有視圖中的數據的模型類。

+ +
from .models import Book, Author, BookInstance, Genre
+
+def index(request):
+    """View function for home page of site."""
+
+    # Generate counts of some of the main objects
+    num_books = Book.objects.all().count()
+    num_instances = BookInstance.objects.all().count()
+
+    # Available books (status = 'a')
+    num_instances_available = BookInstance.objects.filter(status__exact='a').count()
+
+    # The 'all()' is implied by default.
+    num_authors = Author.objects.count()
+
+    context = {
+        'num_books': num_books,
+        'num_instances': num_instances,
+        'num_instances_available': num_instances_available,
+        'num_authors': num_authors,
+    }
+
+    # Render the HTML template index.html with the data in the context variable
+    return render(request, 'index.html', context=context)
+ +

視圖函數的第一部分使用模型類上的 objects.all() 屬性獲取記錄數。 它還獲取具有狀態字段值為“ a”(可用)的BookInstance 物件列表。 在上一教程(Django Tutorial Part 3: Using models > Searching for records)中,您可以找到更多有關如何從模型進行訪問的信息。.

+ +

在函數的最後,我們調用 render() 函數來創建並返回HTML頁面作為響應(此快捷功能包裝了許多其他函數,從而簡化了這種非常常見的用例)。它以原始 request 物件 (一個 HttpRequest), 帶有數據佔位符的HTML模板以及上下文 context 變量包含將插入到這些佔位符中的數據的Python字典)為參數。

+ +

在下一節中,我們將詳細討論模板和上下文變量。 讓我們開始創建模板,以便實際上可以向用戶顯示內容!

+ +

Template

+ +

模板是一個文本文件,用於定義文件(例如HTML頁面)的結構或佈局,並使用佔位符表示實際內容。 Django會在您的應用程序名為'templates'的目錄中自動查找模板。 因此,例如,在我們剛剛添加的索引視圖中, render() 函數將有望能夠找到文件 /locallibrary/catalog/templates/index.html,如果找不到該文件,則會引發錯誤。 如果您保存以前的更改並返回瀏覽器,則可以看到此信息-訪問127.0.0.1:8000現在將為您提供一個相當直觀的錯誤消息"TemplateDoesNotExist at /catalog/"以及其他詳細信息。

+ +
+

注意: Django將根據項目的設置文件在許多位置查找模板(搜索已安裝的應用程序是默認設置!)。 您可以在 Templates (Django docs)中找到有關Django如何查找模板及其支持的模板格式的更多信息。

+
+ +

Extending templates

+ +

索引模板的頭部和身體將需要標準的HTML標記,以及用於導航的部分(到我們尚未創建的站點中的其他頁面)以及用於顯示一些介紹性文本和我們的書籍數據的部分。 對於我們網站上的每個頁面,大部分文本(HTML和導航結構)都是相同的。 Django模板語言允許您聲明一個基本模板,然後擴展它,而不是強迫開發人員在每個頁面中都複製此"樣板" ,只需替換每個特定頁面上不同的部分即可。

+ +

例如,基本模板 base_generic.html 可能類似於以下文本。 如您所見,其中包含一些"通用" HTML以及標題,側邊欄和內容的部分,這些部分使用命名的blockendblock 模板標記進行了標記(以粗體顯示)。 區塊可以為空,或包含將在默認情況下用於派生頁面的內容。

+ +
+

注意:模板tags 類似於可以在模板中使用的功能,可以在模板中循環使用列表,基於變量的值執行條件操作等。除了模板標記之外,模板語法還允許您引用模板變量(傳遞給 模板),並使用template filters,該過濾器可重新格式化變量(例如,將字符串設置為小寫)。

+
+ +
<!DOCTYPE html>
+<html lang="en">
+<head>
+  {% block title %}<title>Local Library</title>{% endblock %}
+</head>
+
+<body>
+  {% block sidebar %}<!-- insert default navigation text for every page -->{% endblock %}
+  {% block content %}<!-- default content text (typically empty) -->{% endblock %}
+</body>
+</html>
+
+ +

當我們想為特定視圖定義模板時,我們首先指定基本模板(帶有extends 模板標籤-請參見下一個代碼清單)。 如果我們要在模板中替換任何節,則使用與基本模板中相同的block/endblock節來聲明這些節。

+ +

例如,下面的代碼片段顯示了我們如何使用extends 模板標籤並覆蓋content 區塊。 生成的最終HTML將具有基本模板中定義的所有HTML和結構(包括您在title 區塊中定義的默認內容),但是將新的content 區塊插入到默認模板中。

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <h1>Local Library Home</h1>
+  <p>Welcome to LocalLibrary, a website developed by <em>Mozilla Developer Network</em>!</p>
+{% endblock %}
+ +

The LocalLibrary base template

+ +

下面列出了我們計劃用於LocalLibrary 網站的基本模板。 如您所見,其中包含一些HTML以及 title, sidebar, 和 content。 我們有一個默認標題(我們可能想要更改)和一個默認側邊欄,其中帶有指向所有書籍和作者列表的鏈接(我們可能不想更改,但是如果需要的話,我們允許範圍通過將其放在 在一個區塊中)。

+ +
+

注意: 我們還引入了兩個附加的模板標籤:urlload static。 這些將在以下各節中討論。

+
+ +

創建一個新文件/locallibrary/catalog/templates/base_generic.html ,並為其提供以下內容:

+ +
<!DOCTYPE html>
+<html lang="en">
+<head>
+  {% block title %}<title>Local Library</title>{% endblock %}
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
+
+  <!-- Add additional CSS in static file -->
+  {% load static %}
+  <link rel="stylesheet" href="{% static 'css/styles.css' %}">
+</head>
+<body>
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-sm-2">
+      {% block sidebar %}
+      <ul class="sidebar-nav">
+        <li><a href="{% url 'index' %}">Home</a></li>
+        <li><a href="">All books</a></li>
+        <li><a href="">All authors</a></li>
+      </ul>
+     {% endblock %}
+      </div>
+      <div class="col-sm-10 ">
+      {% block content %}{% endblock %}
+      </div>
+    </div>
+  </div>
+</body>
+</html>
+ +

該模板包括來自Bootstrap的CSS,以改進HTML頁面的佈局和表示方式。 使用Bootstrap或其他客戶端Web框架是創建吸引人的頁面的快速方法,該頁面可以在不同的瀏覽器大小上很好地擴展。

+ +

基本模板還引用了本地CSS文件 (styles.css) ,該文件提供了一些其他樣式。 創建 /locallibrary/catalog/static/css/styles.css並為其提供以下內容:

+ +
.sidebar-nav {
+    margin-top: 20px;
+    padding: 0;
+    list-style: none;
+}
+ +

The index template

+ +

創建HTML文件 /locallibrary/catalog/templates/index.html 並為其提供以下內容。 如您所見,我們在第一行中擴展了基本模板,然後使用該模板的新內容塊替換默認content 區塊。

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <h1>Local Library Home</h1>
+  <p>Welcome to LocalLibrary, a website developed by <em>Mozilla Developer Network</em>!</p>
+
+  <h2>Dynamic content</h2>
+  <p>The library has the following record counts:</p>
+  <ul>
+    <li><strong>Books:</strong> \{{ num_books }}</li>
+    <li><strong>Copies:</strong> \{{ num_instances }}</li>
+    <li><strong>Copies available:</strong> \{{ num_instances_available }}</li>
+    <li><strong>Authors:</strong> \{{ num_authors }}</li>
+  </ul>
+{% endblock %}
+ +

Dynamic content 部分中,我們聲明了要從視圖中包含的信息的佔位符(template variables)。 變量使用“雙括號”或“把手”語法標記(請參見上面的粗體)。

+ +
+

注意:因為變量具有雙括號 (\{{ num_books }}),而標籤則用百分號括在單括號中擴展為 ({% extends "base_generic.html" %}),所以您可以輕鬆識別是要處理模板變量還是模板標籤(函數)。

+
+ +

這裡要注意的重要一點是,這些變量是使用我們在視圖的render() 函數中傳遞給context 字典的鍵命名的(請參見下文); 呈現模板時,這些將被其values 替換。

+ +
context = {
+    'num_books': num_books,
+    'num_instances': num_instances,
+    'num_instances_available': num_instances_available,
+    'num_authors': num_authors,
+}
+
+return render(request, 'index.html', context=context)
+ +

Referencing static files in templates

+ +

您的項目可能會使用靜態資源,包括JavaScript,CSS和圖像。 由於這些文件的位置可能未知(或可能會更改),因此Django允許您相對於STATIC_URL 全局設置在模板中指定這些文件的位置(默認框架網站將STATIC_URL 的值設置為'/static/',但您可以選擇將其託管在內容分發網絡或其他地方)。

+ +

在模板中,您首先調用指定為“ static”的load 模板標籤以添加此模板庫(如下所示)。 加載靜態文件後,您可以使用static 模板標籤,指定感興趣文件的相對URL。

+ +
<!-- Add additional CSS in static file -->
+{% load static %}
+<link rel="stylesheet" href="{% static 'css/styles.css' %}">
+ +

如果需要,您可以以相同的方式將圖像添加到頁面中。 例如:

+ +
{% load static %}
+<img src="{% static 'catalog/images/local_library_model_uml.png' %}" alt="UML diagram" style="width:555px;height:540px;">
+
+ +
+

注意:上面的更改指定了文件的位置,但是Django默認不提供文件。創建網站框架時 (created the website skeleton),雖然我們在全局URL映射器(/locallibrary/locallibrary/urls.py)中啟用了由開發Web服務器提供的服務,但您仍需要安排它們在生產中提供。 我們待會再看。

+
+ +

有關使用靜態文件的更多信息,請參閱管理靜態文件 Managing static files (Django docs)。

+ +

Linking to URLs

+ +

上面的基本模板引入了url 模板標籤。

+ +
<li><a href="{% url 'index' %}">Home</a></li>
+
+ +

此標記採用在 urls.py中調用的 path()函數的名稱以及關聯視圖將從該函數接收的任何參數的值,並返回可用於鏈接到資源的URL。

+ +

What does it look like?

+ +

此時,我們應該已經創建了顯示索引頁面所需的所有內容。 運行服務器(python3 manage.py runserver),然後打開瀏覽器到http://127.0.0.1:8000/。 如果一切設置正確,則您的站點應類似於以下螢幕截圖。

+ +

Index page for LocalLibrary website

+ +
+

注意:您將無法使用All booksAll authors鏈接,因為尚未定義這些頁面的路徑,視圖和模板(當前我們僅在base_generic.html html模板中插入了這些鏈接的佔位符)。

+
+ +

Challenge yourself

+ +

這裡有兩個任務可以測試您對模型查詢,視圖和模板的熟悉程度。

+ +
    +
  1. LocalLibrary base template 已定義title 欄。 在 index template中覆蓋此塊並為頁面創建一些新標題。 + +
    +

    提示 :Extending templates 部分介紹瞭如何創建塊並將其擴展到另一個模板中。
    +  

    +
    +
  2. +
  3. 修改 view以生成包含特定單詞(不區分大小寫)的流派計數和書籍計數,並將其傳遞給context (這與我們創建並使用num_booksnum_instances_available的方式大致相同)。 然後更新 index template 以使用這些變量。
  4. +
+ + + +

Summary

+ +

現在,我們已經為網站創建了主頁-一個HTML頁面,該頁面顯示了數據庫中的一些記錄計數,並具有指向其他尚待創建頁面的鏈接。 在此過程中,我們學習了很多有關url映射器,視圖,使用我們的模型查詢數據庫,如何從視圖中將信息傳遞到模板以及如何創建和擴展模板的基本信息。

+ +

在下一篇文章中,我們將基於我們的知識來創建其他四個頁面。

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/server-side/django/index.html b/files/zh-tw/learn/server-side/django/index.html new file mode 100644 index 0000000000..7bb4840e06 --- /dev/null +++ b/files/zh-tw/learn/server-side/django/index.html @@ -0,0 +1,115 @@ +--- +title: Django 網站框架 (Python) +slug: Learn/Server-side/Django +translation_of: Learn/Server-side/Django +--- +
{{LearnSidebar}}
+ +

Django 使用 Python 語言編寫,是一個廣受歡迎、且功能完整的服務器端網站框架。本模塊將為您展示,為什麼 Django 能夠成為一個廣受歡迎的服務器端框架,如何設置開發環境,以及如何開始創建你自己的網絡應用。

+ +

先決條件

+ +

開始學習本模塊,並不需要任何 Django 知識. 但您要理解什麼是服務器端網絡編程、什麼是網絡框架,最好能夠閱讀我們的服務端網站編程的第一步模塊

+ +

最好能有基本的編程概念、並了解 Python 語言,但並不是理解本教程的核心概念的必然條件。

+ +
+

Note: 對於初學者來說,Python 是最容易閱讀和理解的編程語言之一。也就是說,如果您想更好的理解本教程,網上有很多免費書籍及免費教程可供參考學習(建議初學者查看 Python 官網的 Python for Non Programmers )。

+
+ +

指引

+ +
+
Django 簡介
+
在第一篇關於 Django 的文章裡,我們會回答"什麼是Django?",並概述這個網絡框架的特殊之處。我們會列出主要的功能,包括一些高級的功能特性,這些高級特性我們在這部分教程裡沒有時間詳細說明。在你設置好 Django 應用、並開始把玩它之前,我們會展示 Django 應用的一些主要模塊,讓你明白 Django 應用能做什麼。  
+
架設 Django 開發環境
+
現在你知道 Django 是做什麼的,我們會展示怎樣在 Windows、Linux(Ubuntu)、和 Mac OS X上,創建和測試 Django 的開發環境—不管你是用什麼操作系統,這篇文章會教給你能夠開發 Django 應用所需要的開發環境。
+
Django 教學 1: 本地圖書館網站
+
我們實用教程系列的第一篇文章,會解釋你將學習到什麼,並提供 "本地圖書館" 網站這個例子的概述。我們會在接下來的文章裡,完成並不斷的改進這個網站。
+
Django 教學 2: 創建骨架網站
+
這篇文章會教你,怎樣創建一個網站的 "框架" 。以這個網站為基礎,你可以填充網站特定的 settings、urls、models、views 和 templates。
+
Django 教學 3: 使用模型
+
這篇文章會為 “本地圖書館網站” 定義數據模板—數據模板是我們為應用存儲的數據結構。並且允許 Django 在資料庫中存儲數據(以後可以修改)。此文章解釋了什麼是數據模板、怎樣聲明它、和一些主要的數據種類。文章還簡要的介紹了一些,你可以獲得數據模板的方法。
+
Django 教學 4: Django 管理員頁面
+
現在我們已經為本地圖書館網站,創建了模型,我們將使用 Django 管理員頁面添加一些 ‘真實的’ 的圖書數據。首先,我們將向你介紹,如何使用管理員頁面註冊模型,然後我們介紹如何登錄和創建一些數據。最後我們展示一些,進一步改進管理員頁面呈現的方法。
+
Django 教學 5: 創建我們的首頁
+
我們現在可以添加代碼,來展示我們的第一個完整頁面—本地圖書館主頁,來顯示我們對每個模型類型有多少條記錄,並提供我們其他頁面的側邊欄導航鏈接。一路上,我們將獲得編寫基本 URL 地圖和視圖、從數據庫獲取記錄、以及使用模版的實踐經驗。.
+
Django 教學 6: 通用列表與詳細視圖
+
本教學課程擴展了我們的本地圖書館網站,添加書籍和作者和詳細頁面。在這裡,我們將了解基於類別的通用視圖,並展示如何減少常用代碼用例的代碼量。我們還將更詳細地深入理解 URL 處理,展示如何執行基本模式匹配。   
+
Django 教學 7: 會話框架
+
本教學擴展本地圖書館網站,向首頁添加了一個基於會話的訪問計數器。這是個比較簡單的例子,但它顯示如何使用會話框架,為你自己的網站中的匿名用戶,提供一致的行為。
+
Django 教學 8: 使用者身份驗証和權限
+
本教程,我們將向你展示,如何允許使用者用自己的賬戶,登錄到你的網站,以及如何根據他們是否登錄、及其權限,來控制他們可以做什麼、和看到什麼。作為此次演示的一部分,我們將擴展本地圖書館網站,添加登錄和登出頁面,以及使用者和工作人員特定頁面,以查看已借用的書籍。
+
Django 教學 9: 使用表單
+
本教程,我們將向你展示如何使用 Django 中的 HTML Forms 表單,特別是編寫表單以創建、更新、和刪除模型實例的最簡單方法。作為此次演示的一部分,我們將擴展本地圖書館網站,以便圖書館員,可以使用我們自己的表單 (而不是使用管理應用程序) 來更新書籍,創建、更新、刪除作者。
+
Django 教學 10: 測試 Django 網頁應用
+
隨著網站的的發展,手工測試越來越難測試—不僅要測試更多,而且隨著組件之間的相互作用變得越來越複雜,一個領域的一個小的變化,可能需要許多額外的測試,來驗證其對其他領域的影響。減輕這些問題的一種方法,是編寫自動化測試,每次更改時,都可以輕鬆可靠地運行。本教程將介紹如何使用 Django 的測試框架,對你的網站進行單元測試自動化。
+
Django 教學 11: 部署 Django 到生產環境
+
現在,你已創建(並測試)一個很酷的 “本地圖書館網站”,你將要把它安裝在公共 Web 服務器上,以便圖書館員工和成員,可以通過 Internet 訪問。本文概述如何找到主機,來部署你的網站,以及你需要做什麼,才能使你的網站準備好投入生產環境。
+
Django 網頁應用安全
+
保護用戶數據,是任何網站設計的重要組成部分,我們以前解釋了Web 安全文章中,一些更常見的安全威脅—本文提供了 Django 內置、如何保護處理這種危險的實際演示。
+
+ +

評估

+ +

以下評估,將測試你對如何使用 Django 創建網站的理解,如上述指南中所列出的項目。

+ +
+
DIY Django 微博客
+
在這個評估中,你將使用你從本單元中學到的一些知識,來創建自己的博客。
+
+
{{LearnSidebar}}
+ +

Django 使用 Python 語言編寫,是一個廣受歡迎、且功能完整的服務器端網站框架。本模塊將為您展示,為什麼 Django 能夠成為一個廣受歡迎的服務器端框架,如何設置開發環境,以及如何開始創建你自己的網絡應用。

+ +

先決條件

+ +

開始學習本模塊,並不需要任何 Django 知識. 但您要理解什麼是服務器端網絡編程、什麼是網絡框架,最好能夠閱讀我們的服務端網站編程的第一步模塊

+ +

最好能有基本的編程概念、並了解 Python 語言,但並不是理解本教程的核心概念的必然條件。

+ +
+

Note: 對於初學者來說,Python 是最容易閱讀和理解的編程語言之一。也就是說,如果您想更好的理解本教程,網上有很多免費書籍及免費教程可供參考學習(建議初學者查看 Python 官網的 Python for Non Programmers )。

+
+ +

指引

+ +
+
Django 簡介
+
在第一篇關於 Django 的文章裡,我們會回答"什麼是Django?",並概述這個網絡框架的特殊之處。我們會列出主要的功能,包括一些高級的功能特性,這些高級特性我們在這部分教程裡沒有時間詳細說明。在你設置好 Django 應用、並開始把玩它之前,我們會展示 Django 應用的一些主要模塊,讓你明白 Django 應用能做什麼。  
+
架設 Django 開發環境
+
現在你知道 Django 是做什麼的,我們會展示怎樣在 Windows、Linux(Ubuntu)、和 Mac OS X上,創建和測試 Django 的開發環境—不管你是用什麼操作系統,這篇文章會教給你能夠開發 Django 應用所需要的開發環境。
+
Django 教學 1: 本地圖書館網站
+
我們實用教程系列的第一篇文章,會解釋你將學習到什麼,並提供 "本地圖書館" 網站這個例子的概述。我們會在接下來的文章裡,完成並不斷的改進這個網站。
+
Django 教學 2: 創建骨架網站
+
這篇文章會教你,怎樣創建一個網站的 "框架" 。以這個網站為基礎,你可以填充網站特定的 settings、urls、models、views 和 templates。
+
Django 教學 3: 使用模型
+
這篇文章會為 “本地圖書館網站” 定義數據模板—數據模板是我們為應用存儲的數據結構。並且允許 Django 在資料庫中存儲數據(以後可以修改)。此文章解釋了什麼是數據模板、怎樣聲明它、和一些主要的數據種類。文章還簡要的介紹了一些,你可以獲得數據模板的方法。
+
Django 教學 4: Django 管理員頁面
+
現在我們已經為本地圖書館網站,創建了模型,我們將使用 Django 管理員頁面添加一些 ‘真實的’ 的圖書數據。首先,我們將向你介紹,如何使用管理員頁面註冊模型,然後我們介紹如何登錄和創建一些數據。最後我們展示一些,進一步改進管理員頁面呈現的方法。
+
Django 教學 5: 創建我們的首頁
+
我們現在可以添加代碼,來展示我們的第一個完整頁面—本地圖書館主頁,來顯示我們對每個模型類型有多少條記錄,並提供我們其他頁面的側邊欄導航鏈接。一路上,我們將獲得編寫基本 URL 地圖和視圖、從數據庫獲取記錄、以及使用模版的實踐經驗。.
+
Django 教學 6: 通用列表與詳細視圖
+
本教學課程擴展了我們的本地圖書館網站,添加書籍和作者和詳細頁面。在這裡,我們將了解基於類別的通用視圖,並展示如何減少常用代碼用例的代碼量。我們還將更詳細地深入理解 URL 處理,展示如何執行基本模式匹配。   
+
Django 教學 7: 會話框架
+
本教學擴展本地圖書館網站,向首頁添加了一個基於會話的訪問計數器。這是個比較簡單的例子,但它顯示如何使用會話框架,為你自己的網站中的匿名用戶,提供一致的行為。
+
Django 教學 8: 使用者身份驗証和權限
+
本教程,我們將向你展示,如何允許使用者用自己的賬戶,登錄到你的網站,以及如何根據他們是否登錄、及其權限,來控制他們可以做什麼、和看到什麼。作為此次演示的一部分,我們將擴展本地圖書館網站,添加登錄和登出頁面,以及使用者和工作人員特定頁面,以查看已借用的書籍。
+
Django 教學 9: 使用表單
+
本教程,我們將向你展示如何使用 Django 中的 HTML Forms 表單,特別是編寫表單以創建、更新、和刪除模型實例的最簡單方法。作為此次演示的一部分,我們將擴展本地圖書館網站,以便圖書館員,可以使用我們自己的表單 (而不是使用管理應用程序) 來更新書籍,創建、更新、刪除作者。
+
Django 教學 10: 測試 Django 網頁應用
+
隨著網站的的發展,手工測試越來越難測試—不僅要測試更多,而且隨著組件之間的相互作用變得越來越複雜,一個領域的一個小的變化,可能需要許多額外的測試,來驗證其對其他領域的影響。減輕這些問題的一種方法,是編寫自動化測試,每次更改時,都可以輕鬆可靠地運行。本教程將介紹如何使用 Django 的測試框架,對你的網站進行單元測試自動化。
+
Django 教學 11: 部署 Django 到生產環境
+
現在,你已創建(並測試)一個很酷的 “本地圖書館網站”,你將要把它安裝在公共 Web 服務器上,以便圖書館員工和成員,可以通過 Internet 訪問。本文概述如何找到主機,來部署你的網站,以及你需要做什麼,才能使你的網站準備好投入生產環境。
+
Django 網頁應用安全
+
保護用戶數據,是任何網站設計的重要組成部分,我們以前解釋了 Web 安全文章中,一些更常見的安全威脅—本文提供了 Django 內置、如何保護處理這種危險的實際演示。
+
+ +

評估

+ +

以下評估,將測試你對如何使用 Django 創建網站的理解,如上述指南中所列出的項目。

+ +
+
Django 小部落格 DIY
+
在這個評估中,你將使用你從本單元中學到的一些知識,來創建自己的部落格。
+
diff --git a/files/zh-tw/learn/server-side/django/introduction/index.html b/files/zh-tw/learn/server-side/django/introduction/index.html new file mode 100644 index 0000000000..f0a9e2caa5 --- /dev/null +++ b/files/zh-tw/learn/server-side/django/introduction/index.html @@ -0,0 +1,306 @@ +--- +title: Django 介紹 +slug: Learn/Server-side/Django/Introduction +translation_of: Learn/Server-side/Django/Introduction +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}
+ +

在這第一篇Django文章中,我們將回答“什麼是Django”這個問題,並概述這個網絡框架有什麼特性。我們將描述主要功能,包括一些高級功能,但我們並不會在本單元中詳細介紹。我們還會展示一些Django應用程序的主要構建模塊(儘管此時你還沒有要測試的開發環境)。

+ + + + + + + + + + + + +
先備知識:基本的電腦知識.對服務器端網站編程的一般了解 ,特別是網站中客戶端-服務器交互的機制 .
目標:了解Django是什麼,它提供了哪些功能,以及Django應用程序的主要構建塊。
+ +

什麼是 Django?

+ +

Django 是一個高級的 Python 網路框架,可以快速開發安全和可維護的網站。由經驗豐富的開發者構建,Django 負責處理網站開發中麻煩的部分,因此你可以專注於編寫應用程序,而無需重新開發。

+ +

它是免費和開源的,有活躍繁榮的社區、豐富的文檔、以及很多免費和付費的解決方案。

+ +

Django 可以使你的應用具有以下優點:

+ +
+
完備
+
Django 遵循 “功能完備” 的理念,提供開發人員可能想要 “開箱即用” 的幾乎所有功能。因為你需要的一切,都是一個 ”產品“ 的一部分,它們都可以無縫結合在一起,遵循一致性設計原則,並且具有廣泛、和最新的文檔
+
通用
+
+

Django 可以(並已經)用於構建幾乎任何類型的網站—從內容管理系統和維基,到社交網絡和新聞網站。它可以與任何客戶端框架一起工作,並且可以提供幾乎任何格式(包括 HTML、RSS、JSON、XML等)的內容。你正在閱讀的網站就是基於 Django。

+ +

在內部,儘管它為幾乎所有可能需要的功能(例如幾個流行的資料庫,模版引擎等)提供了選擇,但是如果需要,它也可以擴展到使用其他組件。

+
+
安全
+
+

Django 幫助開發人員,通過提供一個被設計為 “做正確的事情” 來自動保護網站的框架,來避免許多常見的安全錯誤。例如,Django 提供了一種安全的方式,來管理用戶帳號和密碼,避免了常見的錯誤,比如將 session 放在 cookie 中這種易受攻擊的做法(取而代之的是,cookies 只包含一個密鑰,實際數據存儲在數據庫中),或直接存儲密碼,而不是密碼的 hash 值。

+ +

密碼 hash ,是讓密碼通過加密 hash 函數,而創建的固定長度值。 Django 能通過運行 hash 函數,來檢查輸入的密碼 - 就是將輸出的 hash 值,與存儲的 hash 值進行比較是否正確。然而由於功能的 “單向” 性質,假使存儲的 hash 值受到威脅,攻擊者也難以解出原始密碼。 (但其實有彩虹表-譯者觀點)

+ +

默認情況下,Django 可以防範許多漏洞,包括 SQL 注入,跨站點腳本,跨站點請求偽造,和點擊劫持 (請參閱 網站安全 相關信息,如有興趣)。

+
+
可擴展
+
Django 使用基於組件的 “無共享” 架構 (架構的每一部分獨立於其他架構,因此可以根據需要進行替換或更改)。在不同部分之間,有明確的分隔,意味著它可以通過在任何級別添加硬件,來擴展服務:緩存服務器,數據庫服務器,或應用程序服務器。一些最繁忙的網站,已經在 Django 架構下成功地縮放了網站的規模大小,以滿足他們的需求(例如 Instagram 和 Disqus,僅舉兩個例子,可自行添加)。
+
可維護
+
Django 代碼編寫,是遵照設計原則和模式,鼓勵創建可維護和可重複使用的代碼。特別是,它使用了不要重複自己(DRY)原則,所以沒有不必要的重複,減少了代碼的數量。 Django 還將相關功能,分組到可重用的 “應用程序” 中,並且在較低級別,將相關代碼分組或模塊( 模型視圖控制器 Model View Controller (MVC) 模式)。
+
可移植
+
Django 是用 Python 編寫的,它在許多平台上運行。這意味著,你不受任務特定的服務器平台的限制,並且可以在許多種類的 Linux,Windows 和 Mac OS X 上運行應用程序。此外,Django 得到許多網路託管提供商的好評,他們經常提供特定的基礎設施,和託管 Django 網站的文檔。
+
+ +

Django的起源?

+ +

Django 最初在 2003 年到 2005 年間,由負責創建和維護報紙網站的網絡團隊開發。在創建了許多網站後,團隊開始考慮、並重用許多常見的代碼和設計模式。這個共同的代碼,演變一個通用的網絡開發框架,2005 年 7 月,被開源為 “Django” 項目。

+ +

Django 不斷發展壯大 — 從 2008 年 9 月的第一個里程碑版本(1.0),到最近發布的(2.0)-(2018)版本。每個版本都添加了新功能,和錯誤修復,從支持新類型的數據庫,模版引擎和緩存,到添加 “通用” 視圖函數和類別(這減少了開發人員在一些編程任務必須編寫的代碼量)。

+ +
+

注意: 查看 Django 網站上的發行說明 release notes,看看最近版本發生了什麼變化,以及 Django 能做多少工作

+
+ +

Django 現在是一個蓬勃發展的合作開源項目,擁有數千個用戶和貢獻者。雖然它仍然具有反映其起源的一些功能,但 Django 已經發展成為,能夠開發任何類型的網站的多功能框架。

+ +

Django有多受歡迎?

+ +

服務器端框架的受歡迎程度沒有任何可靠和明確的測量(儘管Hot Frameworks網站嘗試使用諸如計算每個平台的GitHub項目數量和StackOverflow問題的機制來評估流行度)。一個更好的問題是Django是否“足夠流行”,以避免不受歡迎的平台的問題。它是否繼續發展?如果您需要幫助,可以幫您嗎?如果您學習Django,有機會獲得付費工作嗎?

+ +

基於使用Django的流行網站數量,為代碼庫貢獻的人數以及提供免費和付費支持的人數,那麼是的,Django是一個流行的框架!

+ +

使用Django的流行網站包括:Disqus,Instagram,騎士基金會,麥克阿瑟基金會,Mozilla,國家地理,開放知識基金會,Pinterest和開放棧(來源:Django home page ).

+ +

Django 是特定用途的?

+ +

Web框架通常將自己稱為“特定”或“無限制”。

+ +

特定框架是對處理任何特定任務的“正確方法”有意見的框架。他們經常支持特定領域的快速發展(解決特定類型的問題),因為正確的做法是通常被很好地理解和記錄在案。然而,他們在解決其主要領域之外的問題時可能不那麼靈活,並且傾向於為可以使用哪些組件和方法提供較少的選擇。

+ +

相比之下,无限制的框架对于将组件粘合在一起以实现目标或甚至应使用哪些组件的最佳方式的限制较少。它们使开发人员更容易使用最合适的工具来完成特定任务,尽管您需要自己查找这些组件。

+ +

Django“有點有意義”,因此提供了“兩個世界的最佳”。它提供了一組組件來處理大多數Web開發任務和一個(或兩個)首選的使用方法。然而,Django的解耦架構意味著您通常可以從多個不同的選項中進行選擇,也可以根據需要添加對全新的支持。

+ +

Django 代碼是什麼樣子?

+ +

在傳統的數據驅動網站中,Web應用程序會等待來自Web瀏覽器(或其他客戶端)的HTTP 請求。當接收到請求時,應用程序根據URL 和可能的POST 數據或GET 數據中的信息確定需要的內容。根據需要,可以從數據庫讀取或寫入信息,或執行滿足請求所需的其他任務。然後,該應用程序將返回對Web瀏覽器的響應,通常通過將檢索到的數據插入HTML模板中的佔位符來動態創建用於瀏覽器顯示的HTML 頁面。

+ +

Django 網絡應用程序通常將處理每個步驟的代碼分組到單獨的文件中:

+ +

+ + + +
+

注意 : Django將此組織稱為“模型視圖模板(MVT)”架構。它與更加熟悉的Model View Controller架構有許多相似之處.

+
+ + + +

以下部分將為您提供Django應用程序的這些主要部分的想法(稍後我們將在進一步詳細介紹後,我們將在開發環境中進行更詳細的介紹)。

+ +

將請求發送到正確的視圖(urls.py)

+ +

URL映射器通常存儲在名為urls.py的文件中。在下面的示例中,mapper(urlpatterns)定義了特定URL 模式和相應視圖函數之間的映射列表。如果接收到具有與指定模式匹配的URL(例如r'^$',下面)的HTTP請求,則將調用相關聯的視圖功能(例如 views.index)並傳遞請求。

+ +
urlpatterns = [
+    path('admin/', admin.site.urls),
+    path('book/<int:id>/', views.book_detail, name='book_detail'),
+    path('catalog/', include('catalog.urls')),
+    re_path(r'^([0-9]+)/$', views.best),
+]
+
+ +

urlpatterns對像是path()和/或re_path()函數的列表(Python列表使用方括號定義,其中項目用逗號分隔,可以有一個可選的尾隨逗號。例如:[item1, item2, item3, ])。

+ +

兩種方法的第一個參數,是將要匹配的路由(模式)。 path()方法使用尖括號,來定義將被捕獲、並作為命名參數傳遞給視圖函數的 URL 的部分。 re_path()函數使用靈活的模式匹配方法,稱為正則表達式。我們將在後面的文章中討論這些內容!

+ +

第二個參數,是在匹配模式時將調用的另一個函數。註釋 views.book_detail表示該函數名為book_detail(),可以在名為views的模塊中找到(即在名為views.py的文件中)

+ +

處理請求(views.py)

+ + + +

視圖是Web應用程序的核心,從Web客戶端接收HTTP請求並返回HTTP響應。在兩者之間,他們編制框架的其他資源來訪問數據庫,渲染模板等。

+ +

下面的例子顯示了一個最小的視圖功能index(),這可以通過我們的URL映射器在上一節中調用。像所有視圖函數一樣,它接收一個HttpRequest對像作為參數(request)並返回一個HttpResponse對象。在這種情況下,我們對請求不做任何事情,我們的響應只是返回一個硬編碼的字符串。我們會向您顯示一個請求,在稍後的部分中會提供更有趣的內容。

+ + + +
## filename: views.py (Django view functions)
+
+from django.http import HttpResponse
+
+def index(request):
+    # Get an HttpRequest - the request parameter
+    # perform operations using information from the request.
+    # Return HttpResponse
+    return HttpResponse('Hello from Django!')
+
+ +
+

注意 :一點點Python:

+ + + + +
+ + + +

視圖通常存放在一個名為views.py的文件中。

+ +

定義數據模型(models.py)

+ + + +

Django Web應用程序,通過被稱為模型的Python對象,來管理和查詢數據。模型定義存儲數據的結構,包括字段類型 以及字段可能的最大值,默認值,選擇列表選項,文檔幫助文本,表單的標籤文本等。模型的定義與底層數據庫無關-您可以選擇其中一個,作為項目設置的一部分。一旦您選擇了要使用的數據庫,您就不需要直接與之交談- 只需編寫模型結構和其他代碼,Django可以處理與數據庫通信的所有辛苦的工作。

+ +

下面的代碼片段為Team對象,展示了一個非常簡單的Django模型。本Team類別是從Django的類別派生models.Model。它將團隊名稱和團隊級別,定義為字符字段,並為每個記錄指定了要存放的最大字符數。team_level可以是幾個值中的一個,因此,我們將其定義為一個選擇字段,並在被展示的數據、和被儲存的數據之間,建立映射,並設置一個默認值。

+ + + +
# filename: models.py
+
+from django.db import models
+
+class Team(models.Model):
+    team_name = models.CharField(max_length=40)
+
+    TEAM_LEVELS = (
+        ('U09', 'Under 09s'),
+        ('U10', 'Under 10s'),
+        ('U11', 'Under 11s'),
+        ...  #list other team levels
+    )
+    team_level = models.CharField(max_length=3,choices=TEAM_LEVELS,default='U11')
+
+ +
+

注意 : Python小知識:

+ + + + +
+ +

查詢數據(views.py)

+ + + +

Django模型提供了一個,用於搜索數據庫的簡單查詢API。這可以使用不同的標準(例如,精確,不區分大小寫,大於等等)來匹配多個字段,並且可以支持複雜語句(例如,您可以在擁有一個團隊的U11團隊上指定搜索名稱以“Fr ”開頭或以“al”結尾)。

+ +

代碼片段顯示了一個視圖函數(資源處理程序),用於顯示我們所有的U09團隊。粗體顯示如何使用模型查詢API,過濾所有記錄,其中該 team_level字段,具有正確的文本“ U09 ”(請注意,該條件如何filter()作為參數傳遞給該函數,該字段名稱和匹配類型由雙下劃線: team_level__exact

+ + + +
## filename: views.py
+
+from django.shortcuts import render
+from .models import Team
+
+def index(request):
+    list_teams = Team.objects.filter(team_level__exact="U09")
+    context = {'youngest_teams': list_teams}
+    return render(request, '/best/index.html', context)
+
+ +
+
+ +

此功能使用render ()功能創建HttpResponse發送回瀏覽器的功能。這個函數是一個快捷方式;它通過組合指定的HTML模版和一些數據來插入模版(在名為“ content ”的變量中提供)來創建一個HTML文件。在下一節中,我們將介紹如何在其中插入數據以創建HTML

+ +

呈現數據(HTML模版)

+ +

模板系統允許您使用佔位符指定輸出文檔的結構,以便在生成頁面時填充數據。模板通常用於創建HTML,但也可以創建其他類型的文檔。 Django支持其本機模板系統,和另一個流行的Python庫,名為 Jinja2(如果需要,它也可以支持其他系統)。

+ +

代碼片段,顯示了上一節中render()函數調用的HTML模板的外觀。這個模板的編寫假設它在渲染時可以訪問名為youngest_teams的列表變量(包含在上面render()函數中的上下文變量context中)。在HTML框架內部,我們有一個表達式,首先檢查youngest_teams變量是否存在,然後在for循環中迭代它。在每次迭代中,模板在{{htmlelement(“li”)}}元素中顯示每個團隊的team_name值。

+ +
## filename: best/templates/best/index.html
+
+<!DOCTYPE html>
+<html lang="en">
+<body>
+
+ {% if youngest_teams %}
+    <ul>
+    {% for team in youngest_teams %}
+        <li>\{\{ team.team_name \}\}</li>
+    {% endfor %}
+    </ul>
+{% else %}
+    <p>No teams are available.</p>
+{% endif %}
+
+</body>
+</html>
+ +

你還能做什麼?

+ + + +

前面的部分,展示了幾乎每個Web應用程序將使用的主要功能:URL映射,視圖,模型和模版。Django提供的其他內容包括:

+ + + + + +

總結

+ + + +

恭喜,您已經完成了Django之旅的第一步!您現在應該了解Django的主要優點,一些關於它的歷史,以及Django應用程序的每個主要部分可能是什麼樣子。您還應該了解Python編程語言的一些內容,包括列表,函數和類別的語法。

+ +

您已經看到上面的一些真正的Django代碼,但與客戶端代碼不同,您需要設置一個開發環境來運行它。這是我們的下一步。

+ + + +
{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}
+ +

本教學連結

+ + diff --git a/files/zh-tw/learn/server-side/django/models/index.html b/files/zh-tw/learn/server-side/django/models/index.html new file mode 100644 index 0000000000..c075d8d35a --- /dev/null +++ b/files/zh-tw/learn/server-side/django/models/index.html @@ -0,0 +1,475 @@ +--- +title: 'Django Tutorial Part 3: Using models' +slug: Learn/Server-side/Django/Models +translation_of: Learn/Server-side/Django/Models +--- +
,{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}
+ +

+ +

本文介紹如何為 LocalLibrary 網站定義模型。它解釋了模型是什麼、聲明的方式以及一些主要字段類型。它還簡要展示了您可以訪問模型數據的幾個主要方法。

+ + + + + + + + + + + + +
前提:Django 教學 2: 創建骨架網站。
目標: +

能夠設計和創建自己的模型,選擇適當的欄位。

+
+ +

概覽

+ +

Django Web 應用程序通過被稱為模型的 Python 對象,訪問和管理數據。模型定義儲存數據的結構,包括欄位類型、以及可能還有最大大小,默認值,選擇列表選項,幫助文檔,表單的標籤文本等。模型的定義與底層數據庫無關 — 你可以選擇其中一個,作為項目設置的一部分。一旦你選擇了要使用的數據庫,你就不需要直接與之交談 — 只需編寫模型結構和其他代碼,Django 可以處理與數據庫通信的所有繁瑣工作。

+ +

本教程將介紹如何定義和訪問 LocalLibrary 範例網站的模型。

+ +

設計LocalLibrary模型

+ +

在你投入開始編寫模型之前,花幾分鐘時間考慮我們需要存放的數據、以及不同物件之間的關係。

+ +

我們知道,我們需要存放書籍的信息(標題,摘要,作者,語言,類別,ISBN),並且我們可能有多個副本(具有全域唯一的ID,可用狀態等)。我們可以存放更多關於作者的信息,而不僅僅是他的名字,或多個作者的相同或相似的名稱。我們希望能根據書名,作者名,語言和類別對信息進行排序。

+ +

在設計模型時,為每個“物件”分別設置模型(相關信息分組)是有意義的。在這種情況下,明顯的物件是書籍,書本實例和作者。

+ +

你可能想要使用模型,來表示選擇列表選項(例如:選擇下拉列表),而不是硬編碼,將選項編寫進網站—這是當所有選項面臨未知、或改變時候的建議。在本網站,模型的明顯候選,包括書籍類型(例如:科幻小說,法國詩歌等)和語言(英語,法語,日語)。

+ +

一旦我們已經決定了我們的模型和字段,我們需要考慮它們的關聯性。Django允許你來定義一對一的關聯(OneToOneField),一對多(ForeignKey)和多對多(ManyToManyField)。

+ +

思考一下,在網站中,我們將定義模型展示在下面UML關聯圖中(下圖)。如以上,我們創建了書的模型(書的通用細節),書本實例(系統中特定物理副本的書籍狀態),和作者。我們也決定了各類型模型,以便通過管理界面創建/選擇值。我們決定不給BookInstance:status一個模型 —我們硬編碼了(LOAN_STATUS)的值,因為我們不希望其改變。在每個框中,你可以看到模型名稱,字段名稱和類型,以及方法和返回類型。

+ +

該圖顯示模型之間的關係,包括它們的多重性。多重性是圖中的數字,顯示可能存在於關係中的每個模型的數量(最大值和最小值)。例如,盒子之間的連接線,顯示書和類型相關。書模型中數字表明,一本書必須有一個或多個類型(想要多少就多少),而類型(Genres)模型線的另一端的數字(0..*),表明它可以有零個或多個關聯書本(可以有這個書籍類別,也有對應的書;也可以是有這個書籍類別,但沒有對應的書)。

+ +

LocalLibrary Model UML

+ +
+

注意 :下一節提供一個基本解釋模型的定義與使用,當你在讀的時候,也需要一邊考慮如何構建上圖中的每個模型。
+  

+
+ +

模型入門

+ +

本節簡要概述了模型定義,和一些重要的字段、和字段參數。

+ +

模型定義

+ +

模型通常在 app 中的 models.py 檔案中定義。它們是繼承自  django.db.models.Model的子類, 可以包括屬性,方法和描述性資料(metadata)。下面區段為一個名為MyModelName的「典型」模型範例碼:

+ +
from django.db import models
+
+class MyModelName(models.Model):
+    """A typical class defining a model, derived from the Model class."""
+
+    # Fields
+    my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')
+    ...
+
+    # Metadata
+    class Meta:
+        ordering = ['-my_field_name']
+
+    # Methods
+    def get_absolute_url(self):
+         """Returns the url to access a particular instance of MyModelName."""
+         return reverse('model-detail-view', args=[str(self.id)])
+
+    def __str__(self):
+        """String for representing the MyModelName object (in Admin site etc.)."""
+        return self.field_name
+ +

在下面章節中,我們將更詳細解釋模型的每個功能。

+ +

字段

+ +

模型可以有任意數量的字段、任何類型的字段 — 每個字段都表示我們要存放在我們的一個資料庫中的一欄數據(a column of data)。每筆資料庫記錄(列 row)將由每個字段值之一組成。我們來看看上面看到的例子。

+ +
my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')
+ + + +

在上面例子中,有個叫 my_field_name 的單一字段,其類型為 models.CharField  — 這意味著這個字段將會包含字母、數字字符串。使用特定的類別分配字段類型,這些類別,決定了用於將數據存放在資料庫中的記錄的類型,以及從HTML表單接收到值(即構成有效值)時使用的驗證標準。字段類型還可以獲取參數,進一步指定字段如何存放或如何被使用。在這裡的情況下,我們給了字段兩個參數:

+ + + +

字段名稱用於在視圖和模版中引用它。字段還有一個標籤,它被指定一個參數(verbose_name),或者通過大寫字段的變量名的第一個字母,並用空格替換下劃線(例如my_field_name 的默認標籤為 My field name )。

+ +

如果模型在表單中呈現(例如:在管理站點中),則聲明該字段的順序,將影響其默認順序,但可能會被覆蓋。

+ +
常用字段參數
+ +

當聲明很多/大多數不同的字段類型時,可以使用以下常用參數:

+ + + +

還有許多其他選項 — 你可以在這裡看到完整的字段選項

+ +
常用字段類型
+ +

以下列表描述了一些更常用的字段類型。

+ + + +

還有許多其他類型的字段,包括不同類型數字的字段(大整數,小整數,浮點數),布林值,URLs,唯一 ids 和其他 “時間相關” 的信息(持續時間,時間等)。你可以查閱完整列表 .

+ +

+ +

元數據(Metadata)

+ +

你可以通過宣告 class Meta 來宣告模型級別的元數據,如圖所示:

+ +
class Meta:
+    ordering = ['-my_field_name']
+
+ +

此元數據最有用的功能之一是控制在查詢模型類型時返回之記錄的默認排序。你可以透過在ordering 屬性的字段名稱列表中指定匹配順序來執行此操作,如上所示。排序將依賴字段的類型(字符串字段按字母順序排序,而日期字段按時間順序排序)。如上所示,你可以使用減號(-)前綴字段名稱以反轉排序順序。

+ +

例如,如果我們選擇依照此預設來排列書單:

+ +
ordering = ['title', '-pubdate']
+ +

書單通過標題依據--字母排序--排列,從A到Z,然後再依每個標題的出版日期,從最新到最舊排列。

+ +

另一個常見的屬性是 verbose_name ,一個 verbose_name 說明單數和複數形式的類別。

+ +
verbose_name = 'BetterName'
+ +

其他有用的屬性允許你為模型創建和應用新的“訪問權限”(預設權限會被自動套用),允許基於其他的字段排序,或聲明該類是”抽象的“(你無法創建的記錄基類,並將由其他型號派生)。

+ +

許多其他元數據選項控制模型中必須使用哪些數據庫以及數據的存儲方式。(如果你需要模型映射一個現有數據庫,這會有用)。

+ +

完整有用的元數據選項在這裡Model metadata options (Django docs).

+ +

方法(Methods)

+ +

一個模型也可以有方法。

+ +

最起碼,在每個模型中,你應該定義標準的Python 類方法__str__() 來為每個物件返回一個人類可讀的字符串此字符用於表示管理站點的各個記錄(以及你需要引用模型實例的任何其他位置)。通常這將返回模型中的標題或名稱字段。

+ +
def __str__(self):
+    return self.field_name
+ +

Django 方法中另一個常用方法是 get_absolute_url() ,這函數返回一個在網站上顯示個人模型記錄的 URL(如果你定義了該方法,那麼 Django 將自動在“管理站點”中添加“在站點中查看“按鈕在模型的記錄編輯欄)。get_absolute_url()的典型示例如下:

+ +
def get_absolute_url(self):
+    """Returns the url to access a particular instance of the model."""
+    return reverse('model-detail-view', args=[str(self.id)])
+
+ +
+

注意 :假設你將使用URL/myapplication/mymodelname/2 來顯示模型的單個記錄(其中“2”是id特定記錄),則需要創建一個URL映射器來將響應和id傳遞給“模型詳細視圖” (這將做出顯示記錄所需的工作)。以上示例中,reverse()函數可以“反轉”你的url映射器(在上訴命名為“model-detail-view”的案例中,以創建正確格式的URL。

+ +

當然要做這個工作,你還是要寫URL映射,視圖和模版!

+
+ +

你可以定義一些你喜歡的其他方法,並從你的代碼或模版調用它們(只要它們不帶任何參數)。

+ +

模型管理

+ +

一旦你定義了模型類,你可以使用它們來創建,更新或刪除記錄,並運行查詢獲取所有記錄或特定的記錄子集。當我們定義我們的視圖,我們將展示給你在這個教程如何去做。

+ +

創建和修改記錄

+ +

要創建一個記錄,你可以定義一個模型實例,然後呼叫 save()

+ +
# Create a new record using the model's constructor.
+record = MyModelName(my_field_name="Instance #1")
+
+# Save the object into the database.
+record.save()
+ +
+

註:如果沒有任何的欄位被宣告為主鍵,這筆新的紀錄會被自動的賦予一個主鍵並將主鍵欄命名為 id。上例的那筆資料被儲存後,試著查詢這筆紀錄會看到它被自動賦予 1 的編號。

+
+ +

你可以透過「點(dot)的語法」取得或變更這筆新資料的欄位(字段)。你需要呼叫 save() 將變更過的資料存進資料庫。

+ +
# Access model field values using Python attributes.
+print(record.id) #should return 1 for the first record.
+print(record.my_field_name) # should print 'Instance #1'
+
+# Change record by modifying the fields, then calling save().
+record.my_field_name = "New Instance Name"
+record.save()
+
+ +

搜尋紀錄

+ +

你可以使用模型的 objects 屬性(由 base class 提供)搜尋符合某個條件的紀錄。You can search for records that match a certain criteria using the model's attribute (provided by the base class).

+ +
+

Note: 要用"抽象的"模型還有欄位說明怎麼搜尋紀錄可能會有點令人困惑。我們會以一個Book模型,其包含titlegenre字段,而genre 也是一個僅有name一個字段的模型。

+
+ +

我們可以取得一個模型的所有紀錄,為一個 QuerySet 使用objects.all()。 QuerySet 是一個可迭代的物件,表示他含有多個物件,而我們可以藉由迭代/迴圈取得每個物件。

+ +
all_books = Book.objects.all()
+
+ +

Django的 filter() 方法讓我們可以透過符合特定文字或數值的字段篩選回傳的QuerySet。例如篩選書名裡有 "wild" 的書並且計算總數,如下面所示。

+ +
wild_books = Book.objects.filter(title__contains='wild')
+number_wild_books = Book.objects.filter(title__contains='wild').count()
+
+ +

要比對的字段與比對方法都要被定義在篩選的參數名稱裡,並且使用這個格式:比對字段__比對方法 (請注意上方範例中的 title 與 contains 中間隔了兩個底線唷)。在上面我們使用大小寫區分的方式比對title 。還有很多比對方式可以使用: icontains (不區分大小寫), iexact (大小寫區分且完全符合), exact (不區分大小寫但完全符合) 還有 in, gt (大於), startswith, 之類的。全部的用法在這裡。

+ +

有時候你會須要透過某個一對多的字段來篩選(例如一個 外鍵)。 這樣的狀況下,你可以使用兩個底線來指定相關模型的字段。例如透過某個特定的genre名稱篩選書籍,如下所示:

+ +
# 會比對到: Fiction, Science fiction, non-fiction etc.
+books_containing_genre = Book.objects.filter(genre__name__icontains='fiction')
+
+ +
+

Note: 你可隨心地使用雙底線 (__) 來探索更多層的關係 (ForeignKey/ManyToManyField). 例如, 一本 Book 有許多不同的 types, 其進一步定義有參數 name 關聯的"cover":type__cover__name__exact='hard'.

+
+ +

還有很多是你可以用索引(queries)來做的,包含從相關的模型做向後查詢(backwards searches)、連鎖過濾器(chaining filters)、回傳「值的小集合」等。更多資訊可以到 Making queries (Django Docs) 查詢。

+ +

定義 LocalLibrary 模型

+ +

這部份我們會開始定義圖書館的模型。

+ +

先打開 models.py (在 /locallibrary/catalog/),頁面的最上方可以看到樣板導入了 models 模組,其包含了模型的基本類別 models.Model ,能使我們的模型能夠繼承。

+ +
from django.db import models
+
+# Create your models here.
+ +

書籍類型模型 (Genre model)

+ +

複製下方 Genre 模型的程式碼,並貼在你的 models.py 檔案底部,這個模型是用來儲存書籍類型的資訊 — 例如:該本書是否為科幻小說、羅曼史、軍事歷史等。

+ +

就像先前提到的,我們以「模型」的方式建立一個書籍類型模型,而非以自由文本(free text)或者選擇列表(selection list)的方式,這樣做讓我們可以透過資料庫的形式而非硬編碼(hard coded)的方式來管理所有可能的值。

+ +
class Genre(models.Model):
+    """Model representing a book genre."""
+    name = models.CharField(max_length=200, help_text='Enter a book genre (e.g. Science Fiction)')
+
+    def __str__(self):
+        """String for representing the Model object."""
+        return self.name
+ +

此模型有一個單一的 CharField 字段(name) 被用來描述書籍類別(限制輸入字元長度最多200個,同時也有提示文本(help_text) )。

+ +

在模型最下方我們宣告一個 __str__() 方法來簡單回傳被特定一筆紀錄定義的書籍類別名稱。

+ +

因為詳細名稱(verbose name)沒有被定義,所以字段在形式上會被稱為 Name 。

+ +

書本模型 (Book model)

+ +

複製下方 Book 模型的程式碼,並貼在你的 models.py 檔案底部,這個 Book 模型一般來說代表一個可用書本的所有資訊,但並非包含特定的物理實例(physical instance)或者副本資訊(copy),此模型使用 CharField 來表示書的 title 和 isbn (國際標準書號)(note how the isbn specifies its label as "ISBN" using the first unnamed parameter because the default label would otherwise be "Isbn").,另外此模型使用 TextField 來存 summary ,因為此文本可能會很長。

+ +
from django.urls import reverse #Used to generate URLs by reversing the URL patterns
+
+class Book(models.Model):
+    """Model representing a book (but not a specific copy of a book)."""
+    title = models.CharField(max_length=200)
+    author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
+
+    # Foreign Key used because book can only have one author, but authors can have multiple books
+    # Author as a string rather than object because it hasn't been declared yet in the file.
+    summary = models.TextField(max_length=1000, help_text='Enter a brief description of the book')
+    isbn = models.CharField('ISBN', max_length=13, help_text='13 Character <a href="https://www.isbn-international.org/content/what-isbn">ISBN number</a>')
+
+    # ManyToManyField used because genre can contain many books. Books can cover many genres.
+    # Genre class has already been defined so we can specify the object above.
+    genre = models.ManyToManyField(Genre, help_text='Select a genre for this book')
+
+    def __str__(self):
+        """String for representing the Model object."""
+        return self.title
+
+    def get_absolute_url(self):
+        """Returns the url to access a detail record for this book."""
+        return reverse('book-detail', args=[str(self.id)])
+
+
+ +

「書籍類別」(genre)是一個 ManyToManyField ,因此一本書可以有很多書籍類別,而一個書結類別也能夠對應到很多本書。作者(author)被宣告為外鍵(ForeignKey),因此每本書只會有一名作者,但一名作者可能會有多本書(實際上,一本書可能會有多名作者,不過這個案例不會有,所以在別的例子這種作法可能會有問題)

+ +

在上面兩個宣告關聯性模型的敘述句內,關聯的對象都是用對象的模型類或字串的方式作為首個未具名參數的方式傳入句內做宣告。在關聯對象尚未被定義前,若要參照到該對象,必須使用該對象名稱字串的方式來宣告關聯性!還有一些 author 欄位的其它值得一提的參數:null=True 表示如果沒有作者的話,允許在資料庫中存入 Null 值;on_delete=models.SET_NULL 表示如果某筆作者紀錄被刪除的話,與該作者相關連的欄位都會被設成 Null

+ +

這個模型也定義了 __str__() ,使用書本的 title 字段來表示一筆 Book 的紀錄。而最後一個方法,get_absolute_url() ,則會回傳一個可以被用來存取該模型細節紀錄的 URL (要讓其有效運作,我們必須定義一個 URL 的映射,我們將其命名為 book-detail ,另外還得定義一個關聯示圖(view)與模板(template) )。

+ +

書本詳情模型 (BookInstance model)

+ +

接下來,複製下方 BookInstance 的模型,貼在其他模型下面,這個 BookInstance 模型表示一個特定的書籍副本(可會被某人借走),並且包含如「副本是否可用」、「預計歸還日期」、「版本說明」或「版本細節」等資訊,還有一個在圖書館中唯一的 id 。

+ +

有些字段(fields)和方法(methods)現在你也熟悉了。此模型使用了:

+ + + +
import uuid # Required for unique book instances
+
+class BookInstance(models.Model):
+    """Model representing a specific copy of a book (i.e. that can be borrowed from the library)."""
+    id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular book across whole library')
+    book = models.ForeignKey('Book', on_delete=models.SET_NULL, null=True)
+    imprint = models.CharField(max_length=200)
+    due_back = models.DateField(null=True, blank=True)
+
+    LOAN_STATUS = (
+        ('m', 'Maintenance'),
+        ('o', 'On loan'),
+        ('a', 'Available'),
+        ('r', 'Reserved'),
+    )
+
+    status = models.CharField(
+        max_length=1,
+        choices=LOAN_STATUS,
+        blank=True,
+        default='m',
+        help_text='Book availability',
+    )
+
+    class Meta:
+        ordering = ['due_back']
+
+    def __str__(self):
+        """String for representing the Model object."""
+        return f'{self.id} ({self.book.title})'
+ +

我們額外宣告了一些新的字段(field)類別(types):

+ + + +

而 __str__() 模型用來表示 BookInstance 這個物件的「唯一 ID」和「相關之 Book 書本名稱(title)」的組合。

+ +
+

Note: 關於 Python 的小提醒:

+ + +
+ +

作者模型(Author model)

+ +

複製下方 Author 的模型程式碼並貼在 models.py 文件的最下方。

+ +

現在所有的字段(fields)與方法(methods)你應該都熟悉了,此模型定義了作者的「名」、「姓」、「出生年月日」、「死亡日期(非必填)」。該模型也指定,預設情況下,__str__() 方法會回傳作者姓名(按照姓、名排序)。而 get_absolute_url() 方法會反轉 author-detail 的URL映射,來獲得顯示單個作者的URL。

+ +
class Author(models.Model):
+    """Model representing an author."""
+    first_name = models.CharField(max_length=100)
+    last_name = models.CharField(max_length=100)
+    date_of_birth = models.DateField(null=True, blank=True)
+    date_of_death = models.DateField('Died', null=True, blank=True)
+
+    class Meta:
+        ordering = ['last_name', 'first_name']
+
+    def get_absolute_url(self):
+        """Returns the url to access a particular author instance."""
+        return reverse('author-detail', args=[str(self.id)])
+
+    def __str__(self):
+        """String for representing the Model object."""
+        return f'{self.last_name}, {self.first_name}'
+
+
+ +

再次執行資料庫遷移(database migrations)

+ +

你的所有模型都建立好了,現在必須再次執行你的資料庫 migrations 指令來將這些修改內容更信到資料庫中。

+ +
python3 manage.py makemigrations
+python3 manage.py migrate
+ +

語言模型(Language model) — 挑戰

+ +

請想像一下,現在來了一位善心人士捐了一堆用不同語言寫的書(例如:波斯語),而你的挑戰是必須制定一個最好在我們的圖說館網站呈現的方式,並把它做成模組。

+ +

幾件事情需要思考:

+ + + +

當你決定好了,就開始動手吧!你可以在Github的這裡看到我們是怎麼思考的。

+ + + + + +

小結

+ +

在這篇文章我們學到如何定義模型,並且利用這些資訊來設計與實作適合的模型給 LocalLibrary 網站。

+ +

再來我們要稍微撇開建立網站,先來看看 Django 的管理站(Django Administration site),這個管理站能讓我們加入一些資料到圖書館中,讓我們再來能夠透過「示圖(views)與模板(templates)」(當然我們現在都還沒建立)來展示。

+ +

延伸閱讀

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/server-side/django/sessions/index.html b/files/zh-tw/learn/server-side/django/sessions/index.html new file mode 100644 index 0000000000..86b534adaf --- /dev/null +++ b/files/zh-tw/learn/server-side/django/sessions/index.html @@ -0,0 +1,185 @@ +--- +title: 'Django Tutorial Part 7: Sessions framework' +slug: Learn/Server-side/Django/Sessions +translation_of: Learn/Server-side/Django/Sessions +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django")}}
+ +

本教程擴展了我們的LocalLibrary 網站,為主頁添加了一個基於會話的訪問計數器。這是一個相對簡單的例子,但它確實顯示了,如何使用會話框架,為匿名用戶提供持久的行為。

+ + + + + + + + + + + + +
Prerequisites:Complete all previous tutorial topics, including Django Tutorial Part 6: Generic list and detail views
Objective:To understand how sessions are used.
+ +

概覽

+ +

我們在之前的教程中創建的LocalLibrary 網站允許用戶瀏覽目錄中的書籍和作者。 雖然內容是從數據庫動態生成的,但每個用戶在使用該網站時基本上都可以訪問相同的頁面和信息類型。

+ +

在一個"真實"的庫中,您可能希望根據用戶以前對網站的使用,首選項等為單個用戶提供定制的體驗。例如,您可以隱藏或存儲用戶下次訪問網站時之前已確認的警告消息,或尊重他們的偏好(例如,他們希望在每個頁面上顯示的搜索結果的數量)。

+ +

會話框架允許您實現這種行為,從而允許您基於每個站點訪問者存儲和檢索任意數據。

+ +

What are sessions?

+ +

Web瀏覽器和服務器之間的所有通信都是通過HTTP協議進行的,該協議是無狀態的。該協議是無狀態的事實意味著客戶端和服務器之間的消息是完全相互獨立的-沒有基於先前消息的“序列”或行為的概念。因此,如果您想擁有一個跟踪與客戶之間正在進行的關係的站點,則需要自己實施。

+ +

會話是Django(以及大多數Internet)使用的機制,用於跟踪站點與特定瀏覽器之間的“狀態”。會話允許您在每個瀏覽器中存儲任意數據,並且只要瀏覽器連接,該數據就可用於站點。然後,與會話相關聯的單個數據項被一個``鍵''引用,該鍵既用於存儲又用於檢索數據。

+ +

Django使用包含特殊會話ID的cookie來標識每個瀏覽器及其與站點的關聯會話。默認情況下,實際會話數據默認存儲在站點數據庫中(這比將數據存儲在cookie中更安全,因為cookie在cookie中更容易受到惡意用戶的攻擊)。您可以將Django配置為將會話數據存儲在其他位置(緩存,文件或是“安全” Cookie),但是默認位置是一個很好且相對安全的選擇。

+ +

Enabling sessions

+ +

當我們創建框架網站時(在教程2中),將自動啟用會話。

+ +

在項目文件的INSTALLED_APPS 和MIDDLEWARE 部分中進行配置(locallibrary/locallibrary/settings.py),如下所示:

+ +
INSTALLED_APPS = [
+    ...
+    'django.contrib.sessions',
+    ....
+
+MIDDLEWARE = [
+    ...
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    ....
+ +

Using sessions

+ +

您可以從request 參數(作為視圖的第一個參數傳入的HttpRequest )中訪問視圖中的session 屬性。 此會話屬性表示與當前用戶的特定連接(或更確切地說,與當前瀏覽器的連接,由該站點的瀏覽器cookie中的會話ID標識)。

+ +

session 屬性是一個類似於字典的對象,您可以在視圖中隨意讀取和寫入多次,並根據需要對其進行修改。 您可以執行所有正常的字典操作,包括清除所有數據,測試是否存在鍵,循環訪問數據等。儘管如此,在大多數情況下,您只會使用標準的``字典''API來獲取和設置值。

+ +

下面的代碼片段顯示瞭如何獲取,設置和刪除與當前會話(瀏覽器)相關的鍵“ my_car”的某些數據。

+ +
+

注意: Django的一大優點是,您無需考慮將會話綁定到視圖中當前請求的機制。 如果我們在視圖中使用以下片段,我們將知道有關my_car 的信息僅與發送當前請求的瀏覽器相關聯。

+
+ +
# Get a session value by its key (e.g. 'my_car'), raising a KeyError if the key is not present
+my_car = request.session['my_car']
+
+# Get a session value, setting a default if it is not present ('mini')
+my_car = request.session.get('my_car', 'mini')
+
+# Set a session value
+request.session['my_car'] = 'mini'
+
+# Delete a session value
+del request.session['my_car']
+
+ +

該API還提供了許多其他方法,這些方法主要用於管理關聯的會話cookie。 例如,有一些方法可以測試客戶端瀏覽器是否支持cookie,設置和檢查cookie到期日期以及從數據存儲中清除過期的會話。 您可以在如 How to use sessions 找到完整的API(Django文檔)。

+ +

Saving session data

+ +

默認情況下,當會話已被修改(分配)或刪除時,Django僅保存到會話數據庫並將會話cookie發送給客戶端。 如果您要使用上一節中所示的會話密鑰更新某些數據,則無需擔心! 例如:

+ +
# This is detected as an update to the session, so session data is saved.
+request.session['my_car'] = 'mini'
+ +

如果您要更新會話數據中的某些信息,則Django將不會識別您已對會話進行了更改並保存了數據(例如,如果要在“ my_car”數據中更改“ wheels”數據, 如下所示)。 在這種情況下,您需要將會話明確標記為已修改。

+ +
# Session object not directly modified, only data within the session. Session changes not saved!
+request.session['my_car']['wheels'] = 'alloy'
+
+# Set session as modified to force data updates/cookie to be saved.
+request.session.modified = True
+
+ +
+

注意:您可以更改行為,以便站點可以通過在您的項目設置(locallibrary/locallibrary/settings.py)中添加SESSION_SAVE_EVERY_REQUEST = True 來更新每個請求的數據庫/發送cookie。

+
+ +

Simple example — getting visit counts

+ +

作為一個簡單的真實示例,我們將更新我們的庫以告知當前用戶他們訪問LocalLibrary主頁的次數。

+ +

打開/ /locallibrary/catalog/views.py,然後進行以下粗體顯示的更改。

+ +
def index(request):
+    ...
+
+    num_authors = Author.objects.count()  # The 'all()' is implied by default.
+
+    # Number of visits to this view, as counted in the session variable.
+    num_visits = request.session.get('num_visits', 0)
+    request.session['num_visits'] = num_visits + 1
+
+    context = {
+        'num_books': num_books,
+        'num_instances': num_instances,
+        'num_instances_available': num_instances_available,
+        'num_authors': num_authors,
+        'num_visits': num_visits,
+    }
+
+    # Render the HTML template index.html with the data in the context variable.
+    return render(request, 'index.html', context=context)
+ +

在這裡,我們首先獲取'num_visits'會話密鑰的值,如果之前未設置,則將其設置為0。 每次接收到請求時,我們都將增加該值並將其存儲回會話中(對於下一次用戶訪問該頁面)。 然後將num_visits 變量傳遞到我們的上下文變量中的模板。

+ +
+

注意:我們也可能會在此處測試瀏覽器是否甚至支持cookie(例如,請參閱How to use sessions)或設計我們的UI,以便無論是否支持cookie都無關緊要。

+
+ +

將以下區塊底部看到的行添加到``動態內容''部分底部的主HTML模板(/locallibrary/catalog/templates/index.html)中以顯示上下文變量:

+ +
<h2>Dynamic content</h2>
+
+<p>The library has the following record counts:</p>
+<ul>
+  <li><strong>Books:</strong> \{{ num_books }}</li>
+  <li><strong>Copies:</strong> \{{ num_instances }}</li>
+  <li><strong>Copies available:</strong> \{{ num_instances_available }}</li>
+  <li><strong>Authors:</strong> \{{ num_authors }}</li>
+</ul>
+
+<p>You have visited this page \{{ num_visits }}{% if num_visits == 1 %} time{% else %} times{% endif %}.</p>
+
+ +

保存更改,然後重新啟動測試服務器。 每次刷新頁面時,數字都會更新。

+ +

總結

+ +

現在,您知道使用會話來改善與匿名用戶的交互是多麼容易。

+ +

在接下來的文章中,我們將說明身份驗證和授權(權限)框架,並向您展示如何支持用戶帳戶。

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/Authentication", "Learn/Server-side/Django")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/server-side/django/skeleton_website/index.html b/files/zh-tw/learn/server-side/django/skeleton_website/index.html new file mode 100644 index 0000000000..b57b351eae --- /dev/null +++ b/files/zh-tw/learn/server-side/django/skeleton_website/index.html @@ -0,0 +1,388 @@ +--- +title: 'Django 教學 2: 創建一個骨架網站' +slug: Learn/Server-side/Django/skeleton_website +translation_of: Learn/Server-side/Django/skeleton_website +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}
+ +

Django 教學的第二篇文章,會展示怎樣創建一個網站的"框架",在這個框架的基礎上,你可以繼續填充整站使用的 settings, urls,模型(models),視圖(views)和模板(templates )。

+ + + + + + + + + + + + +
前提:創建 Django 的開發環境。複習 Django 教學。
目標:能夠使用 Django 提供的工具,搭建你自己的網站。
+ +

概覽

+ +

這篇文章會展示怎樣創建一個網站的"框架",在這個框架的基礎上,你可以繼續填充整站使用的settings, urls,模型(models),視圖(views)和模板(templates)(我們會在接下來的文章裡討論)。

+ +

搭建 “框架” 的過程很直接:

+ +
    +
  1. 使用 django-admin工具創建工程的文件夾,基本的文件模板和工程管理腳本(manage.py)。
  2. +
  3. manage.py 創建一個或多個應用。 +
    +

    注意:一個網站可能由多個部分組成,比如,主要頁面,博客,wiki,下載區域等。Django鼓勵將這些部分作為分開的應用開發。如果這樣的話,在需要可以在不同的工程中復用這些應用。

    +
    +
  4. +
  5. 工程裡註冊新的應用。
  6. +
  7. 為每個應用分配url。
  8. +
+ +

為  locallibrary  這個項目創建的網站文件夾和它的工程文件夾都命名為locallibrary我們只創建一個名為catalog的應用。最高層的項目文件結構如下所示:

+ +
locallibrary/         # Website foldermanage.py         # Script to run Django tools for this project (created using django-admin)
+    locallibrary/     # Website/project folder (created using django-admin)
+    catalog/          # Application folder (created using manage.py)
+
+ +

接下來的部分,會詳細討論創建網站框架的過程,並會展示怎麼測試這些變化。最後,我們會討論在這個階段裡,你可以設置的全站配置。

+ +

創建專案項目

+ +

首先打開命令提示符/終端,確保您在虛擬環境中,導航到您要存放Django應用程序的位置(在文檔文件夾中,輕鬆找到它的位置),並為您的新網站,創建一個文件夾(在這種情況下:locallibrary)。然後使用cd命令進入該文件夾:

+ +
mkdir locallibrary
+cd locallibrary
+ +

django-admin startproject命令創建新項目,並進入該文件夾。

+ +
django-admin startproject locallibrary
+cd locallibrary
+ +

django-admin工具會創建如下所示的文件夾結構

+ +
locallibrary/
+    manage.py
+    locallibrary/
+        __init__.py
+        settings.py
+        urls.py
+        wsgi.py
+ +

locallibrary項目的子文件夾是整個網站的進入點:

+ + + +

manage.py腳本可以創建應用,和資料庫通訊,啟動開發用網絡服務器。

+ +

創建 catalog 應用

+ +

接下來,在locallibrary項目裡,使用下面的命令創建catalog應用(和您項目的manage.py在同一個文件夾下)

+ +
python3 manage.py startapp catalog
+ +
+

注意: Linux/Mac OS X應用可以使用上面的命令。在windows平台下應該改為: py -3 manage.py startapp catalog

+ +

如果你是windows系統,在這個部分用py -3替代python3

+ +

如果您使用的是Python 3.7.0,則應使用py manage.py startapp catalog

+
+ +

這個工具創建了一個新的文件夾,並為該應用創建了不同的文件(下面黑體所示)。絕大多數文件的命名和它們的目的有關(比如視圖函數就是views.py,模型就是models.py,測試是tests.py,網站管理設置是admin.py,註冊應用是apps.py),並且還包含了為項目所用的最小模板。

+ +

執行命令後的文件夾結構如下所示:

+ +
locallibrary/
+    manage.py
+    locallibrary/
+    catalog/
+        admin.py
+        apps.py
+        models.py
+        tests.py
+        views.py
+        __init__.py
+        migrations/
+
+ +

除上面所說的文件外,我們還有:

+ + + +
+

注意 :你注意到上面的文件裡有些缺失嘛?儘管有了 views 和 models 的文件,可是 url 映射,網站模板,靜態文件在哪裡呢?我們會在接下來的部分展示如何創建它們(並不是每個網站都需要,不過這個例子需要)。

+
+ +

註冊catalog應用

+ +

既然應用已經創建好了,我們還必須在項目裡註冊它,以便工具在運行時它會包括在裡面(比如在數據庫裡添加模型時)。在項目的settings裡,把應用添加進INSTALLED_APPS ,就完成了註冊。

+ +

打開項目設置文件  locallibrary/locallibrary/settings.py找到   INSTALLED_APPS 列表裡的定義。如下所示,在列表的最後添加新的一行。

+ +
INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'catalog.apps.CatalogConfig', 
+]
+ +

新的這行,詳細說明了應用配置文件在( CatalogConfig/locallibrary/catalog/apps.py  裡,當你創建應用時就完成了這個過程。

+ +
+

注意 :注意到INSTALLED_APPS已经有许多其他的应用了 (還有 MIDDLEWARE,在settings的下面)。這些應用為   Django administration site  提供了支持和許多功能(包括會話,認證系統等)。

+
+ +

配置資料庫

+ +

現在可以為項目配置資料庫了——為了避免性能上的差異,最好在生產和開發中使用同一種資料庫。你可以在資料庫  裡找到不同的設置方法(Django文檔)。 

+ +

在這個項目裡,我們使用SQLite。因為在展示用的數據庫中,我們不會有很多並發存取的行為。同時,也因為SQLite不需要額外的配置工作。你可以在settings.py裡看到這個數據庫怎樣配置的。(更多信息如下所示)

+ +
DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+    }
+}
+
+ +

因為我們使用SQLite,不需要其他的設置了。我們繼續吧!

+ +

其他項目設置

+ +

settings.py裡還包括其他的一些設置,現在只需要改變時區 —改為和標準tz時區數據表  裡的字符串相同就可以了(數據表裡的TZ列有你想要的時區)。TIME_ZONE的值改為你的時區,比如

+ +
TIME_ZONE = 'Europe/London'
+ +

有兩個設置你現在不會用到,不過你應該留意:

+ + + +

鏈接URL映射器

+ +

在項目文件夾裡,創建網站時同時生成了URL映射器(urls.py)。儘管你可以用它來管理所有的URL映射,但是更常用的做法是把URL映射留到它們相關的應用中。

+ +

打開locallibrary/locallibrary/urls.py  注意指導文字解釋了一些使用URL映射器的方法。

+ +
"""locallibrary URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/2.0/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
+Including another URLconf
+    1. Import the include() function: from django.urls import include, path
+    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import path
+
+urlpatterns = [
+    path('admin/', admin.site.urls),
+]
+
+ +

URL映射通過urlpatterns 變量管理,它是一個path()函數的Python列表。每個path()函數,要么將URL式樣(URL pattern)關聯到特定視圖( specific view),當模式匹配時將會顯示,要么關聯到某個URL式樣列表的測試代碼。(第二種情況下,URL式樣是目標模型裡的“基本URL”). urlpatterns 列表初始化定義了單一函數,把所有帶有 'admin/' 模式的 URL,映射到admin.site.urls。這個函數,包含了Administration應用自己的URL映射定義。

+ +
+

注意: path()中的路由是一個字符串,用於定義要匹配的URL模式。該字符串可能包括一個命名變量(在尖括號中),例如'catalog/<id>/'。此模式將匹配 /catalog/any_chars/ 等URL,並將any_chars 作為參數名稱為id 的字符串,傳遞給視圖。我們將在後面的主題中,進一步討論路徑方法和路由模式

+
+ +

urlpatterns 列表的下面一行,插入下面的代码。這個新項目包括一個 path() ,它使用模式 catalog/ 轉發請求到模塊 catalog.urls(具有相對 URL /catalog/urls.py 的文件)。

+ +
# Use include() to add paths from the catalog application
+from django.conf.urls import include
+from django.urls import path
+
+urlpatterns += [
+    path('catalog/', include('catalog.urls')),
+]
+
+ +

現在我們把我們網站的根URL(例如127.0.0.1:8000),重新導向URL 127.0.0.1:8000/catalog/;這是項目中唯一的應用,所以我們最好這樣做。為了完成這個目標,我們使用一個特別的視圖函數( RedirectView),當path()函數中的 url 式樣被識別以後(在這個例子中是根 url),就會把第一個參數,也就是新的相對 URL ,重定向到(/catalog/)。

+ +

把下面的代碼加到文件最後:

+ +
#Add URL maps to redirect the base URL to our application
+from django.views.generic import RedirectView
+urlpatterns += [
+    path('', RedirectView.as_view(url='/catalog/')),
+]
+ +

將路徑函數的第一個參數留空,用以表示'/'。如果您將第一個參數寫為'/',Django會在您啟動開發服務器時給出以下警告:

+ +
System check identified some issues:
+
+WARNINGS:
+?: (urls.W002) Your URL pattern '/' has a route beginning with a '/'.
+Remove this slash as it is unnecessary.
+If this pattern is targeted in an include(), ensure the include() pattern has a trailing '/'.
+
+ +

Django默認不提供CSS,JavaScript和圖像等靜態文件,但在創建站點時,開發Web服務器這樣做是有用的。作為此URL映射器的最終添加,您可以通過附加以下幾行,在開發期間啟用靜態文件的提供。

+ +

現在將以下最終區塊,添加到文件的底部:

+ +
# Use static() to add url mapping to serve static files during development (only)
+from django.conf import settings
+from django.conf.urls.static import static
+
+urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
+
+ +
+

注意: 有許多方法可以擴充urlpatterns列表(上面我們只是使用+= 運算符,附加一個新的列表項,來清楚地分隔舊代碼和新代碼)。我們可以改為在原始列表定義中,包含這個新的模式映射:

+ +
urlpatterns = [
+    path('admin/', admin.site.urls),
+    path('catalog/', include('catalog.urls')),
+    path('', RedirectView.as_view(url='/catalog/', permanent=True)),
+] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
+
+ +

此外,我們將導入行(from django.urls import include)包含在使用它的代碼中(因此很容易看到我們添加的內容),但通常將所有導入行包含在一個Python文件的頂部。

+
+ +

最後一步,在catalog文件夾中,創建一個名為urls.py的文件,並添加以下文本,以定義(空)導入的urlpatterns。這是我們在構建應用程序時,添加模式的地方。

+ +
from django.urls import path
+from . import views
+
+
+urlpatterns = [
+
+]
+
+ +

測試網站框架

+ +

現在我們有了一個完整的框架項目。這個網站現在還什麼都不能做,但是我們仍然要運行,以確保我們的更改是有效的。

+ +

在運行前,我們應該先運行數據庫遷移這會更新我們的數據庫並且包含所有安裝的應用(同時去除一些警告)。

+ +

運行資料庫遷移

+ +

Django使用對象關係映射器(ORM),將Django代碼中的模型定義,映射到底層資料庫使用的數據結構。當我們更改模型定義時,Django會跟踪更改,並創建資料庫遷移腳本(位於 /locallibrary/catalog/migrations/ ),來自動遷移資料庫中的底層數據結構。

+ +

當我們創建網站時,Django會自動添加一些模型,供網站的管理部分使用(稍後我們會解釋)。運行以下命令,來定義資料庫中這些模型的表(確認你位於包含 manage.py 的目錄中):

+ +
python3 manage.py makemigrations
+python3 manage.py migrate
+
+ +
+

重要: 每次模型改變,都需要運行以上命令,來影響需要存放的數據結構(包括添加和刪除整個模型和單個字段)。

+
+ +

makemigrations命令,創建(但不實施)項目中安裝的所有應用程序的遷移(你可以指定應用程序名稱,也可以為單個項目運行遷移)。這讓你有機會在應用這些遷移之前,檢查這些遷移代碼—當你是Django專家時,你可以選擇稍微調整它們。

+ +

這個 migrate命令,真正對你的資料庫實施遷移(Django跟踪哪些已添加到當前資料庫)。

+ +
+

注意: 參見 Migrations (Django 文件) ,了解較少使用的遷移命令的其他信息。

+
+ +

運行網站

+ +

在開發期間,你首先要使用開發網頁服務器,然後用你本機的瀏覽器觀看,來測試你的網站。

+ +
+

注意: 這個開發網頁服務器並不夠強大,不足以用於生產使用,但是它使你在開發期間,能非常容易獲得你的 Django 網站和運行它,以此來進行快速測試。默認情況下,服務器會開通(http://127.0.0.1:8000/),但你也可以選擇其他端口。有關更多信息,查閱(django-admin and manage.py: runserver)(Django docs).

+
+ +

通過如下runserver命令,運行開發網頁服務器。(同樣的要在manage.py的目錄)

+ +
python3 manage.py runserver
+
+ Performing system checks...
+
+ System check identified no issues (0 silenced).
+ September 22, 2016 - 16:11:26
+ Django version 1.10, using settings 'locallibrary.settings'
+ Starting development server at http://127.0.0.1:8000/
+ Quit the server with CTRL-BREAK.
+
+ +

一旦服務器運行,你可以用你的瀏覽器導航到http://127.0.0.1:8000/ 查看。你應該會看到一個錯誤頁面,如下。

+ +

Django Debug page for Django 2.0

+ +

別擔心,這個錯誤頁面是預期的結果。因為我們沒有在 catalogs.urls模塊中,定義任何頁面或網址(即是當我們使用一個指向根目錄的URL時,會被重新定向的地方)。

+ +
+

注意: 上面的頁面,演示了一個很棒的Django功能 - 自動除錯日誌記錄。只要找不到頁面,或者代碼引發任何錯誤,就會顯示錯誤畫面,其中包含有用的信息。在這種情況下,我們可以看到我們提供的URL,與我們的任何URL模式都不匹配(如列出的那樣)。在生產期間(當我們將網站放在網上時),日誌記錄將被關閉,在這種情況下,將提供信息量較少、但用戶友好的頁面。

+
+ +

這個時候,我們知道Django正在工作!

+ +
+

注意: 在進行重大更改時,你應該重新運行遷移,並重新測試站點。這不需要很長時間!

+
+ +

挑戰自我

+ +

catalog/  目錄包含應用程序的視圖、模型、和應用的其他部分,你可以打開這些文件並查看樣板。

+ +

如上所述,管理站點的URL映射,已經添加到項目的 urls.py在瀏覽器中查看管理區域,看看會發生什麼(你可以從上面映射,推斷正確的URL)。

+ + + +

總結

+ +

你現在已經創建了一個完整的骨架網站項目,你可以繼續加入網址、模型、視圖、和模版。

+ +

現在,Local Library website的骨架已經完成並運行了,是時候開始寫些代碼,讓網站做些它應該做的事了。

+ +

參見

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}

+ + + +

本教程連結

+ + diff --git a/files/zh-tw/learn/server-side/django/testing/index.html b/files/zh-tw/learn/server-side/django/testing/index.html new file mode 100644 index 0000000000..d559585a50 --- /dev/null +++ b/files/zh-tw/learn/server-side/django/testing/index.html @@ -0,0 +1,907 @@ +--- +title: 'Django Tutorial Part 10: Testing a Django web application' +slug: Learn/Server-side/Django/Testing +translation_of: Learn/Server-side/Django/Testing +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}
+ +

隨著網站的增長,他們越來越難以手動測試。不僅要進行更多的測試,而且隨著組件之間的互動,變得越來越複雜,一個區域的小改變,可能會影響到其他區域,所以需要做更多的改變,來確保一切正常運行,並且在進行更多更改時,不會引入錯誤。減輕這些問題的一種方法,是編寫自動化測試,每當您進行更改時,都可以輕鬆可靠地運行測試。本教程演示如何使用 Django 的測試框架,自動化您的網站的單元測試。

+ + + + + + + + + + + + +
Prerequisites:Complete all previous tutorial topics, including Django Tutorial Part 9: Working with forms.
Objective:To understand how to write unit tests for Django-based websites.
+ +

Overview

+ +

The LocalLibrary currently has pages to display lists of all books and authors, detail views for Book and Author items, a page to renew BookInstances, and pages to create, update, and delete Author items (and Book records too, if you completed the challenge in the forms tutorial). Even with this relatively small site, manually navigating to each page and superficially checking that everything works as expected can take several minutes. As we make changes and grow the site, the time required to manually check that everything works "properly" will only grow. If we were to continue as we are, eventually we'd be spending most of our time testing, and very little time improving our code.

+ +

Automated tests can really help with this problem! The obvious benefits are that they can be run much faster than manual tests, can test to a much lower level of detail, and test exactly the same functionality every time (human testers are nowhere near as reliable!) Because they are fast, automated tests can be executed more regularly, and if a test fails, they point to exactly where code is not performing as expected.

+ +

In addition, automated tests can act as the first real-world "user" of your code, forcing you to be rigorous about defining and documenting how your website should behave. Often they are basis for your code examples and documentation. For these reasons, some software development processes start with test definition and implementation, after which the code is written to match the required behavior (e.g. test-driven and behaviour-driven development).

+ +

This tutorial shows how to write automated tests for Django, by adding a number of tests to the LocalLibrary website.

+ +

Types of testing

+ +

There are numerous types, levels, and classifications of tests and testing approaches. The most important automated tests are:

+ +
+
Unit tests
+
Verify functional behavior of individual components, often to class and function level.
+
Regression tests
+
Tests that reproduce historic bugs. Each test is initially run to verify that the bug has been fixed, and then re-run to ensure that it has not been reintroduced following later changes to the code.
+
Integration tests
+
Verify how groupings of components work when used together. Integration tests are aware of the required interactions between components, but not necessarily of the internal operations of each component. They may cover simple groupings of components through to the whole website.
+
+ +
+

Note: Other common types of tests include black box, white box, manual, automated, canary, smoke, conformance, acceptance, functional, system, performance, load, and stress tests. Look them up for more information.

+
+ +

What does Django provide for testing?

+ +

Testing a website is a complex task, because it is made of several layers of logic – from HTTP-level request handling, queries models, to form validation and processing, and template rendering.

+ +

Django provides a test framework with a small hierarchy of classes that build on the Python standard unittest library. Despite the name, this test framework is suitable for both unit and integration tests. The Django framework adds API methods and tools to help test web and Django-specific behaviour. These allow you to simulate requests, insert test data, and inspect your application's output. Django also provides an API (LiveServerTestCase) and tools for using different testing frameworks, for example you can integrate with the popular Selenium framework to simulate a user interacting with a live browser.

+ +

To write a test you derive from any of the Django (or unittest) test base classes (SimpleTestCaseTransactionTestCaseTestCaseLiveServerTestCase) and then write separate methods to check that specific functionality works as expected (tests use "assert" methods to test that expressions result in True or False values, or that two values are equal, etc.) When you start a test run, the framework executes the chosen test methods in your derived classes. The test methods are run independently, with common setup and/or tear-down behaviour defined in the class, as shown below.

+ +
class YourTestClass(TestCase):
+
+    def setUp(self):
+        #Setup run before every test method.
+        pass
+
+    def tearDown(self):
+        #Clean up run after every test method.
+        pass
+
+    def test_something_that_will_pass(self):
+        self.assertFalse(False)
+
+    def test_something_that_will_fail(self):
+        self.assertTrue(False)
+
+ +

The best base class for most tests is django.test.TestCase.  This test class creates a clean database before its tests are run, and runs every test function in its own transaction. The class also owns a test Client that you can use to simulate a user interacting with the code at the view level. In the following sections we're going to concentrate on unit tests, created using this TestCase base class.

+ +
+

Note: The django.test.TestCase class is very convenient, but may result in some tests being slower than they need to be (not every test will need to set up its own database or simulate the view interaction). Once you're familiar with what you can do with this class, you may want to replace some of your tests with the available simpler test classes.

+
+ +

What should you test?

+ +

You should test all aspects of your own code, but not any libraries or functionality provided as part of Python or Django.

+ +

So for example, consider the Author model defined below. You don't need to explicitly test that first_name and last_name have been stored properly as CharField in the database because that is something defined by Django (though of course in practice you will inevitably test this functionality during development). Nor do you need to test that the date_of_birth has been validated to be a date field, because that is again something implemented in Django.

+ +

However you should check the text used for the labels (First name, Last_name, Date of birth, Died), and the size of the field allocated for the text (100 chars), because these are part of your design and something that could be broken/changed in future.

+ +
class Author(models.Model):
+    first_name = models.CharField(max_length=100)
+    last_name = models.CharField(max_length=100)
+    date_of_birth = models.DateField(null=True, blank=True)
+    date_of_death = models.DateField('Died', null=True, blank=True)
+
+    def get_absolute_url(self):
+        return reverse('author-detail', args=[str(self.id)])
+
+    def __str__(self):
+        return '%s, %s' % (self.last_name, self.first_name)
+ +

Similarly, you should check that the custom methods get_absolute_url() and __str__() behave as required because they are your code/business logic. In the case of get_absolute_url() you can trust that the Django reverse() method has been implemented properly, so what you're testing is that the associated view has actually been defined.

+ +
+

Note: Astute readers may note that we would also want to constrain the date of birth and death to sensible values, and check that death comes after birth. In Django this constraint would be added to your form classes (although you can define validators for the fields these appear to only be used at the form level, not the model level).

+
+ +

With that in mind lets start looking at how to define and run tests.

+ +

Test structure overview

+ +

Before we go into the detail of "what to test", let's first briefly look at where and how tests are defined.

+ +

Django uses the unittest module’s built-in test discovery, which will discover tests under the current working directory in any file named with the pattern test*.py. Provided you name the files appropriately, you can use any structure you like. We recommend that you create a module for your test code, and have separate files for models, views, forms, and any other types of code you need to test. For example:

+ +
catalog/
+  /tests/
+    __init__.py
+    test_models.py
+    test_forms.py
+    test_views.py
+
+ +

Create a file structure as shown above in your LocalLibrary project. The __init__.py should be an empty file (this tells Python that the directory is a package). You can create the three test files by copying and renaming the skeleton test file /catalog/tests.py.

+ +
+

Note: The skeleton test file /catalog/tests.py was created automatically when we built the Django skeleton website. It is perfectly "legal" to put all your tests inside it, but if you test properly, you'll quickly end up with a very large and unmanageable test file.

+ +

Delete the skeleton file as we won't need it.

+
+ +

Open /catalog/tests/test_models.py. The file should import django.test.TestCase, as shown:

+ +
from django.test import TestCase
+
+# Create your tests here.
+
+ +

Often you will add a test class for each model/view/form you want to test, with individual methods for testing specific functionality. In other cases you may wish to have a separate class for testing a specific use case, with individual test functions that test aspects of that use-case (for example, a class to test that a model field is properly validated, with functions to test each of the possible failure cases). Again, the structure is very much up to you, but it is best if you are consistent.

+ +

Add the test class below to the bottom of the file. The class demonstrates how to construct a test case class by deriving from TestCase.

+ +
class YourTestClass(TestCase):
+
+    @classmethod
+    def setUpTestData(cls):
+        print("setUpTestData: Run once to set up non-modified data for all class methods.")
+        pass
+
+    def setUp(self):
+        print("setUp: Run once for every test method to setup clean data.")
+        pass
+
+    def test_false_is_false(self):
+        print("Method: test_false_is_false.")
+        self.assertFalse(False)
+
+    def test_false_is_true(self):
+        print("Method: test_false_is_true.")
+        self.assertTrue(False)
+
+    def test_one_plus_one_equals_two(self):
+        print("Method: test_one_plus_one_equals_two.")
+        self.assertEqual(1 + 1, 2)
+ +

The new class defines two methods that you can use for pre-test configuration (for example, to create any models or other objects you will need for the test):

+ + + +
+

The test classes also have a tearDown() method which we haven't used. This method isn't particularly useful for database tests, since the TestCase base class takes care of database teardown for you.

+
+ +

Below those we have a number of test methods, which use Assert functions to test whether conditions are true, false or equal (AssertTrue, AssertFalse, AssertEqual). If the condition does not evaluate as expected then the test will fail and report the error to your console.

+ +

The AssertTrue, AssertFalse, AssertEqual are standard assertions provided by unittest.  There are other standard assertions in the framework, and also Django-specific assertions to test if a view redirects (assertRedirects), to test if a particular template has been used (assertTemplateUsed), etc.

+ +
+

You should not normally include print() functions in your tests as shown above. We do that here only so that you can see the order that the setup functions are called in the console (in the following section).

+
+ +

How to run the tests

+ +

The easiest way to run all the tests is to use the command:

+ +
python3 manage.py test
+ +

This will discover all files named with the pattern test*.py under the current directory and run all tests defined using appropriate base classes (here we have a number of test files, but only /catalog/tests/test_models.py currently contains any tests.) By default the tests will individually report only on test failures, followed by a test summary.

+ +
+

If you get errors similar to: ValueError: Missing staticfiles manifest entry ... this may be because testing does not run collectstatic by default and your app is using a storage class that requires it (see manifest_strict for more information). There are a number of ways you can overcome this problem - the easiest is to simply run collectstatic before running the tests:

+ +
python3 manage.py collectstatic
+
+
+ +

Run the tests in the root directory of LocalLibrary. You should see an output like the one below.

+ +
>python3 manage.py test
+
+Creating test database for alias 'default'...
+setUpTestData: Run once to set up non-modified data for all class methods.
+setUp: Run once for every test method to setup clean data.
+Method: test_false_is_false.
+.setUp: Run once for every test method to setup clean data.
+Method: test_false_is_true.
+FsetUp: Run once for every test method to setup clean data.
+Method: test_one_plus_one_equals_two.
+.
+======================================================================
+FAIL: test_false_is_true (catalog.tests.tests_models.YourTestClass)
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "D:\Github\django_tmp\library_w_t_2\locallibrary\catalog\tests\tests_models.py", line 22, in test_false_is_true
+    self.assertTrue(False)
+AssertionError: False is not true
+
+----------------------------------------------------------------------
+Ran 3 tests in 0.075s
+
+FAILED (failures=1)
+Destroying test database for alias 'default'...
+ +

Here we see that we had one test failure, and we can see exactly what function failed and why (this failure is expected, because False is not True!).

+ +
+

Tip: The most important thing to learn from the test output above is that it is much more valuable if you use descriptive/informative names for your objects and methods.

+
+ +

The text shown in bold above would not normally appear in the test output (this is generated by the print() functions in our tests). This shows how the setUpTestData() method is called once for the class and setUp() is called before each method.

+ +

The next sections show how you can run specific tests, and how to control how much information the tests display.

+ +

Showing more test information

+ +

If you want to get more information about the test run you can change the verbosity. For example, to list the test successes as well as failures (and a whole bunch of information about how the testing database is set up) you can set the verbosity to "2" as shown:

+ +
python3 manage.py test --verbosity 2
+ +

The allowed verbosity levels are 0, 1, 2, and 3, with the default being "1".

+ +

Running specific tests

+ +

If you want to run a subset of your tests you can do so by specifying the full dot path to the package(s), module, TestCase subclass or method:

+ +
python3 manage.py test catalog.tests   # Run the specified module
+python3 manage.py test catalog.tests.test_models  # Run the specified module
+python3 manage.py test catalog.tests.test_models.YourTestClass # Run the specified class
+python3 manage.py test catalog.tests.test_models.YourTestClass.test_one_plus_one_equals_two  # Run the specified method
+
+ +

LocalLibrary tests

+ +

Now we know how to run our tests and what sort of things we need to test, let's look at some practical examples.

+ +
+

Note: We won't write every possible test, but this should give you and idea of how tests work, and what more you can do.

+
+ +

Models

+ +

As discussed above, we should test anything that is part of our design or that is defined by code that we have written, but not libraries/code that is already tested by Django or the Python development team.

+ +

For example, consider the Author model below. Here we should test the labels for all the fields, because even though we haven't explicitly specified most of them, we have a design that says what these values should be. If we don't test the values, then we don't know that the field labels have their intended values. Similarly while we trust that Django will create a field of the specified length, it is worthwhile to specify a test for this length to ensure that it was implemented as planned.

+ +
class Author(models.Model):
+    first_name = models.CharField(max_length=100)
+    last_name = models.CharField(max_length=100)
+    date_of_birth = models.DateField(null=True, blank=True)
+    date_of_death = models.DateField('Died', null=True, blank=True)
+
+    def get_absolute_url(self):
+        return reverse('author-detail', args=[str(self.id)])
+
+    def __str__(self):
+        return '%s, %s' % (self.last_name, self.first_name)
+ +

Open our /catalog/tests/test_models.py, and replace any existing code with the following test code for the Author model.

+ +

Here you'll see that we first import TestCase and derive our test class (AuthorModelTest) from it, using a descriptive name so we can easily identify any failing tests in the test output. We then call setUpTestData() to create an author object that we will use but not modify in any of the tests.

+ +
from django.test import TestCase
+
+# Create your tests here.
+
+from catalog.models import Author
+
+class AuthorModelTest(TestCase):
+
+    @classmethod
+    def setUpTestData(cls):
+        #Set up non-modified objects used by all test methods
+        Author.objects.create(first_name='Big', last_name='Bob')
+
+    def test_first_name_label(self):
+        author=Author.objects.get(id=1)
+        field_label = author._meta.get_field('first_name').verbose_name
+        self.assertEquals(field_label,'first name')
+
+    def test_date_of_death_label(self):
+        author=Author.objects.get(id=1)
+        field_label = author._meta.get_field('date_of_death').verbose_name
+        self.assertEquals(field_label,'died')
+
+    def test_first_name_max_length(self):
+        author=Author.objects.get(id=1)
+        max_length = author._meta.get_field('first_name').max_length
+        self.assertEquals(max_length,100)
+
+    def test_object_name_is_last_name_comma_first_name(self):
+        author=Author.objects.get(id=1)
+        expected_object_name = '%s, %s' % (author.last_name, author.first_name)
+        self.assertEquals(expected_object_name,str(author))
+
+    def test_get_absolute_url(self):
+        author=Author.objects.get(id=1)
+        #This will also fail if the urlconf is not defined.
+        self.assertEquals(author.get_absolute_url(),'/catalog/author/1')
+ +

The field tests check that the values of the field labels (verbose_name) and that the size of the character fields are as expected. These methods all have descriptive names, and follow the same pattern:

+ +
author=Author.objects.get(id=1)   # Get an author object to test
+field_label = author._meta.get_field('first_name').verbose_name   # Get the metadata for the required field and use it to query the required field data
+self.assertEquals(field_label,'first name')  # Compare the value to the expected result
+ +

The interesting things to note are:

+ + + +
+

Note: Tests for the last_name and date_of_birth labels, and also the test for the length of the last_name field have been omitted. Add your own versions now, following the naming conventions and approaches shown above.

+
+ +

We also need to test our custom methods. These essentially just check that the object name was constructed as we expected using "Last Name", "First Name" format, and that the URL we get for an Author item is as we would expect.

+ +
def test_object_name_is_last_name_comma_first_name(self):
+    author=Author.objects.get(id=1)
+    expected_object_name = '%s, %s' % (author.last_name, author.first_name)
+    self.assertEquals(expected_object_name,str(author))
+
+def test_get_absolute_url(self):
+    author=Author.objects.get(id=1)
+    #This will also fail if the urlconf is not defined.
+    self.assertEquals(author.get_absolute_url(),'/catalog/author/1')
+ +

Run the tests now. If you created the Author model as we described in the models tutorial it is quite likely that you will get an error for the date_of_death label as shown below. The test is failing because it was written expecting the label definition to follow Django's convention of not capitalising the first letter of the label (Django does this for you).

+ +
======================================================================
+FAIL: test_date_of_death_label (catalog.tests.test_models.AuthorModelTest)
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "D:\...\locallibrary\catalog\tests\test_models.py", line 32, in test_date_of_death_label
+    self.assertEquals(field_label,'died')
+AssertionError: 'Died' != 'died'
+- Died
+? ^
++ died
+? ^
+ +

This is a very minor bug, but it does highlight how writing tests can more thoroughly check any assumptions you may have made.

+ +
+

Note: Change the label for the date_of_death field (/catalog/models.py) to "died" and re-run the tests.

+
+ +

The patterns for testing the other models are similar so we won't continue to discuss these further. Feel free to create your own tests for the our other models.

+ +

Forms

+ +

The philosophy for testing your forms is the same as for testing your models; you need to test anything that you've coded or your design specifies, but not the behaviour of the underlying framework and other third party libraries.

+ +

Generally this means that you should test that the forms have the fields that you want, and that these are displayed with appropriate labels and help text. You don't need to verify that Django validates the field type correctly (unless you created your own custom field and validation) — i.e. you don't need to test that an email field only accepts emails. However you would need to test any additional validation that you expect to be performed on the fields and any messages that your code will generate for errors.

+ +

Consider our form for renewing books. This has just one field for the renewal date, which will have a label and help text that we will need to verify.

+ +
class RenewBookForm(forms.Form):
+    """
+    Form for a librarian to renew books.
+    """
+    renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")
+
+    def clean_renewal_date(self):
+        data = self.cleaned_data['renewal_date']
+
+        #Check date is not in past.
+        if data < datetime.date.today():
+            raise ValidationError(_('Invalid date - renewal in past'))
+        #Check date is in range librarian allowed to change (+4 weeks)
+        if data > datetime.date.today() + datetime.timedelta(weeks=4):
+            raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))
+
+        # Remember to always return the cleaned data.
+        return data
+ +

Open our /catalog/tests/test_forms.py file and replace any existing code with the following test code for the RenewBookForm form. We start by importing our form and some Python and Django libraries to help test time-related functionality. We then declare our form test class in the same way as we did for models, using a descriptive name for our TestCase-derived test class.

+ +
from django.test import TestCase
+
+# Create your tests here.
+
+import datetime
+from django.utils import timezone
+from catalog.forms import RenewBookForm
+
+class RenewBookFormTest(TestCase):
+
+    def test_renew_form_date_field_label(self):
+        form = RenewBookForm()
+        self.assertTrue(form.fields['renewal_date'].label == None or form.fields['renewal_date'].label == 'renewal date')
+
+    def test_renew_form_date_field_help_text(self):
+        form = RenewBookForm()
+        self.assertEqual(form.fields['renewal_date'].help_text,'Enter a date between now and 4 weeks (default 3).')
+
+    def test_renew_form_date_in_past(self):
+        date = datetime.date.today() - datetime.timedelta(days=1)
+        form_data = {'renewal_date': date}
+        form = RenewBookForm(data=form_data)
+        self.assertFalse(form.is_valid())
+
+    def test_renew_form_date_too_far_in_future(self):
+        date = datetime.date.today() + datetime.timedelta(weeks=4) + datetime.timedelta(days=1)
+        form_data = {'renewal_date': date}
+        form = RenewBookForm(data=form_data)
+        self.assertFalse(form.is_valid())
+
+    def test_renew_form_date_today(self):
+        date = datetime.date.today()
+        form_data = {'renewal_date': date}
+        form = RenewBookForm(data=form_data)
+        self.assertTrue(form.is_valid())
+
+    def test_renew_form_date_max(self):
+        date = timezone.now() + datetime.timedelta(weeks=4)
+        form_data = {'renewal_date': date}
+        form = RenewBookForm(data=form_data)
+        self.assertTrue(form.is_valid())
+
+ +

The first two functions test that the field's label and help_text are as expected. We have to access the field using the fields dictionary (e.g. form.fields['renewal_date']). Note here that we also have to test whether the label value is None, because even though Django will render the correct label it returns None if the value is not explicitly set.

+ +

The rest of the functions test that the form is valid for renewal dates just inside the acceptable range and invalid for values outside the range. Note how we construct test date values around our current date (datetime.date.today()) using datetime.timedelta() (in this case specifying a number of days or weeks). We then just create the form, passing in our data, and test if it is valid.

+ +
+

Note: Here we don't actually use the database or test client. Consider modifying these tests to use SimpleTestCase.

+ +

We also need to validate that the correct errors are raised if the form is invalid, however this is usually done as part of view processing, so we'll take care of that in the next section.

+
+ +

That's all for forms; we do have some others, but they are automatically created by our generic class-based editing views, and should be tested there! Run the tests and confirm that our code still passes!

+ +

Views

+ +

To validate our view behaviour we use the Django test Client. This class acts like a dummy web browser that we can use to simulate GET and POST requests on a URL and observe the response. We can see almost everything about the response, from low-level HTTP (result headers and status codes) through to the template we're using to render the HTML and the context data we're passing to it. We can also see the chain of redirects (if any) and check the URL and status code at each step. This allows us to verify that each view is doing what is expected.

+ +

Let's start with one of our simplest views, which provides a list of all Authors. This is displayed at URL /catalog/authors/ (an URL named 'authors' in the URL configuration).

+ +
class AuthorListView(generic.ListView):
+    model = Author
+    paginate_by = 10
+
+ +

As this is a generic list view almost everything is done for us by Django. Arguably if you trust Django then the only thing you need to test is that the view is accessible at the correct URL and can be accessed using its name. However if you're using a test-driven development process you'll start by writing tests that confirm that the view displays all Authors, paginating them in lots of 10.

+ +

Open the /catalog/tests/test_views.py file and replace any existing text with the following test code for AuthorListView. As before we import our model and some useful classes. In the setUpTestData() method we set up a number of Author objects so that we can test our pagination.

+ +
from django.test import TestCase
+
+# Create your tests here.
+
+from catalog.models import Author
+from django.urls import reverse
+
+class AuthorListViewTest(TestCase):
+
+    @classmethod
+    def setUpTestData(cls):
+        #Create 13 authors for pagination tests
+        number_of_authors = 13
+        for author_num in range(number_of_authors):
+            Author.objects.create(first_name='Christian %s' % author_num, last_name = 'Surname %s' % author_num,)
+
+    def test_view_url_exists_at_desired_location(self):
+        resp = self.client.get('/catalog/authors/')
+        self.assertEqual(resp.status_code, 200)
+
+    def test_view_url_accessible_by_name(self):
+        resp = self.client.get(reverse('authors'))
+        self.assertEqual(resp.status_code, 200)
+
+    def test_view_uses_correct_template(self):
+        resp = self.client.get(reverse('authors'))
+        self.assertEqual(resp.status_code, 200)
+
+        self.assertTemplateUsed(resp, 'catalog/author_list.html')
+
+    def test_pagination_is_ten(self):
+        resp = self.client.get(reverse('authors'))
+        self.assertEqual(resp.status_code, 200)
+        self.assertTrue('is_paginated' in resp.context)
+        self.assertTrue(resp.context['is_paginated'] == True)
+        self.assertTrue( len(resp.context['author_list']) == 10)
+
+    def test_lists_all_authors(self):
+        #Get second page and confirm it has (exactly) remaining 3 items
+        resp = self.client.get(reverse('authors')+'?page=2')
+        self.assertEqual(resp.status_code, 200)
+        self.assertTrue('is_paginated' in resp.context)
+        self.assertTrue(resp.context['is_paginated'] == True)
+        self.assertTrue( len(resp.context['author_list']) == 3)
+ +

All the tests use the client (belonging to our TestCase's derived class) to simulate a GET request and get a response (resp). The first version checks a specific URL (note, just the specific path without the domain) while the second generates the URL from its name in the URL configuration.

+ +
resp = self.client.get('/catalog/authors/')
+resp = self.client.get(reverse('authors'))
+
+ +

Once we have the response we query it for its status code, the template used, whether or not the response is paginated, the number of items returned, and the total number of items.

+ +

The most interesting variable we demonstrate above is resp.context, which is the context variable passed to the template by the view. This is incredibly useful for testing, because it allows us to confirm that our template is getting all the data it needs. In other words we can check that we're using the intended template and what data the template is getting, which goes a long way to verifying that any rendering issues are solely due to template.

+ +

Views that are restricted to logged in users

+ +

In some cases you'll want to test a view that is restricted to just logged in users. For example our LoanedBooksByUserListView is very similar to our previous view but is only available to logged in users, and only displays BookInstance records that are borrowed by the current user, have the 'on loan' status, and are ordered "oldest first".

+ +
from django.contrib.auth.mixins import LoginRequiredMixin
+
+class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
+    """
+    Generic class-based view listing books on loan to current user.
+    """
+    model = BookInstance
+    template_name ='catalog/bookinstance_list_borrowed_user.html'
+    paginate_by = 10
+
+    def get_queryset(self):
+        return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')
+ +

Add the following test code to /catalog/tests/test_views.py. Here we first use SetUp() to create some user login accounts and BookInstance objects (along with their associated books and other records) that we'll use later in the tests. Half of the books are borrowed by each test user, but we've initially set the status of all books to "maintenance". We've used SetUp() rather than setUpTestData() because we'll be modifying some of these objects later.

+ +
+

Note: The setUp() code below creates a book with a specified Language, but your code may not include the Language model as this was created as a challenge. If this is the case, simply  comment out the parts of the code that create or import Language objects. You should also do this in the RenewBookInstancesViewTest section that follows.

+
+ +
import datetime
+from django.utils import timezone
+
+from catalog.models import BookInstance, Book, Genre, Language
+from django.contrib.auth.models import User #Required to assign User as a borrower
+
+class LoanedBookInstancesByUserListViewTest(TestCase):
+
+    def setUp(self):
+        #Create two users
+        test_user1 = User.objects.create_user(username='testuser1', password='12345')
+        test_user1.save()
+        test_user2 = User.objects.create_user(username='testuser2', password='12345')
+        test_user2.save()
+
+        #Create a book
+        test_author = Author.objects.create(first_name='John', last_name='Smith')
+        test_genre = Genre.objects.create(name='Fantasy')
+        test_language = Language.objects.create(name='English')
+        test_book = Book.objects.create(title='Book Title', summary = 'My book summary', isbn='ABCDEFG', author=test_author, language=test_language)
+        # Create genre as a post-step
+        genre_objects_for_book = Genre.objects.all()
+        test_book.genre.set(genre_objects_for_book) #Direct assignment of many-to-many types not allowed.
+        test_book.save()
+
+        #Create 30 BookInstance objects
+        number_of_book_copies = 30
+        for book_copy in range(number_of_book_copies):
+            return_date= timezone.now() + datetime.timedelta(days=book_copy%5)
+            if book_copy % 2:
+                the_borrower=test_user1
+            else:
+                the_borrower=test_user2
+            status='m'
+            BookInstance.objects.create(book=test_book,imprint='Unlikely Imprint, 2016', due_back=return_date, borrower=the_borrower, status=status)
+
+    def test_redirect_if_not_logged_in(self):
+        resp = self.client.get(reverse('my-borrowed'))
+        self.assertRedirects(resp, '/accounts/login/?next=/catalog/mybooks/')
+
+    def test_logged_in_uses_correct_template(self):
+        login = self.client.login(username='testuser1', password='12345')
+        resp = self.client.get(reverse('my-borrowed'))
+
+        #Check our user is logged in
+        self.assertEqual(str(resp.context['user']), 'testuser1')
+        #Check that we got a response "success"
+        self.assertEqual(resp.status_code, 200)
+
+        #Check we used correct template
+        self.assertTemplateUsed(resp, 'catalog/bookinstance_list_borrowed_user.html')
+
+ +

To verify that the view will redirect to a login page if the user is not logged in we use assertRedirects, as demonstrated in test_redirect_if_not_logged_in(). To verify that the page is displayed for a logged in user we first log in our test user, and then access the page again and check that we get a status_code of 200 (success). 

+ +

The rest of the tests verify that our view only returns books that are on loan to our current borrower. Copy the (self-explanatory) code at the end of the test class above.

+ +
    def test_only_borrowed_books_in_list(self):
+        login = self.client.login(username='testuser1', password='12345')
+        resp = self.client.get(reverse('my-borrowed'))
+
+        #Check our user is logged in
+        self.assertEqual(str(resp.context['user']), 'testuser1')
+        #Check that we got a response "success"
+        self.assertEqual(resp.status_code, 200)
+
+        #Check that initially we don't have any books in list (none on loan)
+        self.assertTrue('bookinstance_list' in resp.context)
+        self.assertEqual( len(resp.context['bookinstance_list']),0)
+
+        #Now change all books to be on loan
+        get_ten_books = BookInstance.objects.all()[:10]
+
+        for copy in get_ten_books:
+            copy.status='o'
+            copy.save()
+
+        #Check that now we have borrowed books in the list
+        resp = self.client.get(reverse('my-borrowed'))
+        #Check our user is logged in
+        self.assertEqual(str(resp.context['user']), 'testuser1')
+        #Check that we got a response "success"
+        self.assertEqual(resp.status_code, 200)
+
+        self.assertTrue('bookinstance_list' in resp.context)
+
+        #Confirm all books belong to testuser1 and are on loan
+        for bookitem in resp.context['bookinstance_list']:
+            self.assertEqual(resp.context['user'], bookitem.borrower)
+            self.assertEqual('o', bookitem.status)
+
+    def test_pages_ordered_by_due_date(self):
+
+        #Change all books to be on loan
+        for copy in BookInstance.objects.all():
+            copy.status='o'
+            copy.save()
+
+        login = self.client.login(username='testuser1', password='12345')
+        resp = self.client.get(reverse('my-borrowed'))
+
+        #Check our user is logged in
+        self.assertEqual(str(resp.context['user']), 'testuser1')
+        #Check that we got a response "success"
+        self.assertEqual(resp.status_code, 200)
+
+        #Confirm that of the items, only 10 are displayed due to pagination.
+        self.assertEqual( len(resp.context['bookinstance_list']),10)
+
+        last_date=0
+        for copy in resp.context['bookinstance_list']:
+            if last_date==0:
+                last_date=copy.due_back
+            else:
+                self.assertTrue(last_date <= copy.due_back)
+ +

You could also add pagination tests, should you so wish!

+ +

Testing views with forms

+ +

Testing views with forms is a little more complicated than in the cases above, because you need to test more code paths: initial display, display after data validation has failed, and display after validation has succeeded. The good news is that we use the client for testing in almost exactly the same way as we did for display-only views.

+ +

To demonstrate, let's write some tests for the view used to renew books (renew_book_librarian()):

+ +
from .forms import RenewBookForm
+
+@permission_required('catalog.can_mark_returned')
+def renew_book_librarian(request, pk):
+    """
+    View function for renewing a specific BookInstance by librarian
+    """
+    book_inst=get_object_or_404(BookInstance, pk = pk)
+
+    # If this is a POST request then process the Form data
+    if request.method == 'POST':
+
+        # Create a form instance and populate it with data from the request (binding):
+        form = RenewBookForm(request.POST)
+
+        # Check if the form is valid:
+        if form.is_valid():
+            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
+            book_inst.due_back = form.cleaned_data['renewal_date']
+            book_inst.save()
+
+            # redirect to a new URL:
+            return HttpResponseRedirect(reverse('all-borrowed') )
+
+    # If this is a GET (or any other method) create the default form
+    else:
+        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
+        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})
+ +

We'll need to test that the view is only available to users who have the can_mark_returned permission, and that users are redirected to an HTTP 404 error page if they attempt to renew a BookInstance that does not exist. We should check that the initial value of the form is seeded with a date three weeks in the future, and that if validation succeeds we're redirected to the "all-borrowed books" view. As part of checking the validation-fail tests we'll also check that our form is sending the appropriate error messages.

+ +

Add the first part of the test class (shown below) to the bottom of /catalog/tests/test_views.py. This creates two users and two book instances, but only gives one user the permission required to access the view. The code to grant permissions during tests is shown in bold:

+ +
from django.contrib.auth.models import Permission # Required to grant the permission needed to set a book as returned.
+
+class RenewBookInstancesViewTest(TestCase):
+
+    def setUp(self):
+        #Create a user
+        test_user1 = User.objects.create_user(username='testuser1', password='12345')
+        test_user1.save()
+
+        test_user2 = User.objects.create_user(username='testuser2', password='12345')
+        test_user2.save()
+        permission = Permission.objects.get(name='Set book as returned')
+        test_user2.user_permissions.add(permission)
+        test_user2.save()
+
+        #Create a book
+        test_author = Author.objects.create(first_name='John', last_name='Smith')
+        test_genre = Genre.objects.create(name='Fantasy')
+        test_language = Language.objects.create(name='English')
+        test_book = Book.objects.create(title='Book Title', summary = 'My book summary', isbn='ABCDEFG', author=test_author, language=test_language,)
+        # Create genre as a post-step
+        genre_objects_for_book = Genre.objects.all()
+        test_book.genre.set(genre_objects_for_book) # Direct assignment of many-to-many types not allowed.
+        test_book.save()
+
+        #Create a BookInstance object for test_user1
+        return_date= datetime.date.today() + datetime.timedelta(days=5)
+        self.test_bookinstance1=BookInstance.objects.create(book=test_book,imprint='Unlikely Imprint, 2016', due_back=return_date, borrower=test_user1, status='o')
+
+        #Create a BookInstance object for test_user2
+        return_date= datetime.date.today() + datetime.timedelta(days=5)
+        self.test_bookinstance2=BookInstance.objects.create(book=test_book,imprint='Unlikely Imprint, 2016', due_back=return_date, borrower=test_user2, status='o')
+ +

Add the following tests to the bottom of the test class. These check that only users with the correct permissions (testuser2) can access the view. We check all the cases: when the user is not logged in, when a user is logged in but does not have the correct permissions, when the user has permissions but is not the borrower (should succeed), and what happens when they try to access a BookInstance that doesn't exist. We also check that the correct template is used.

+ +
    def test_redirect_if_not_logged_in(self):
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) )
+        #Manually check redirect (Can't use assertRedirect, because the redirect URL is unpredictable)
+        self.assertEqual( resp.status_code,302)
+        self.assertTrue( resp.url.startswith('/accounts/login/') )
+
+    def test_redirect_if_logged_in_but_not_correct_permission(self):
+        login = self.client.login(username='testuser1', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) )
+
+        #Manually check redirect (Can't use assertRedirect, because the redirect URL is unpredictable)
+        self.assertEqual( resp.status_code,302)
+        self.assertTrue( resp.url.startswith('/accounts/login/') )
+
+    def test_logged_in_with_permission_borrowed_book(self):
+        login = self.client.login(username='testuser2', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance2.pk,}) )
+
+        #Check that it lets us login - this is our book and we have the right permissions.
+        self.assertEqual( resp.status_code,200)
+
+    def test_logged_in_with_permission_another_users_borrowed_book(self):
+        login = self.client.login(username='testuser2', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) )
+
+        #Check that it lets us login. We're a librarian, so we can view any users book
+        self.assertEqual( resp.status_code,200)
+
+    def test_HTTP404_for_invalid_book_if_logged_in(self):
+        import uuid
+        test_uid = uuid.uuid4() #unlikely UID to match our bookinstance!
+        login = self.client.login(username='testuser2', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':test_uid,}) )
+        self.assertEqual( resp.status_code,404)
+
+    def test_uses_correct_template(self):
+        login = self.client.login(username='testuser2', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) )
+        self.assertEqual( resp.status_code,200)
+
+        #Check we used correct template
+        self.assertTemplateUsed(resp, 'catalog/book_renew_librarian.html')
+
+ +

Add the next test method, as shown below. This checks that the initial date for the form is three weeks in the future. Note how we are able to access the value of the initial value of the form field (shown in bold).

+ +
    def test_form_renewal_date_initially_has_date_three_weeks_in_future(self):
+        login = self.client.login(username='testuser2', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) )
+        self.assertEqual( resp.status_code,200)
+
+        date_3_weeks_in_future = datetime.date.today() + datetime.timedelta(weeks=3)
+        self.assertEqual(resp.context['form'].initial['renewal_date'], date_3_weeks_in_future )
+
+ +

The next test (add this to the class too) checks that the view redirects to a list of all borrowed books if renewal succeeds. What differs here is that for the first time we show how you can POST data using the client. The post data is the second argument to the post function, and is specified as a dictionary of key/values.

+ +
    def test_redirects_to_all_borrowed_book_list_on_success(self):
+        login = self.client.login(username='testuser2', password='12345')
+        valid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=2)
+        resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future} )
+        self.assertRedirects(resp, reverse('all-borrowed') )
+
+ +
+

The all-borrowed view was added as a challenge, and your code may instead redirect to the home page '/'. If so, modify the last two lines of the test code to be like the code below. The follow=True in the request ensures that the request returns the final destination URL (hence checking /catalog/ rather than /).

+ +
 resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future},follow=True )
+ self.assertRedirects(resp, '/catalog/')
+
+ +

Copy the last two functions into the class, as seen below. These again test POST requests, but in this case with invalid renewal dates. We use assertFormError() to verify that the error messages are as expected.

+ +
    def test_form_invalid_renewal_date_past(self):
+        login = self.client.login(username='testuser2', password='12345')
+        date_in_past = datetime.date.today() - datetime.timedelta(weeks=1)
+        resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':date_in_past} )
+        self.assertEqual( resp.status_code,200)
+        self.assertFormError(resp, 'form', 'renewal_date', 'Invalid date - renewal in past')
+
+    def test_form_invalid_renewal_date_future(self):
+        login = self.client.login(username='testuser2', password='12345')
+        invalid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=5)
+        resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':invalid_date_in_future} )
+        self.assertEqual( resp.status_code,200)
+        self.assertFormError(resp, 'form', 'renewal_date', 'Invalid date - renewal more than 4 weeks ahead')
+
+ +

The same sorts of techniques can be used to test the other view.

+ +

Templates

+ +

Django provides test APIs to check that the correct template is being called by your views, and to allow you to verify that the correct information is being sent. There is however no specific API support for testing in Django that your HTML output is rendered as expected.

+ + + +

Django's test framework can help you write effective unit and integration tests — we've only scratched the surface of what the underlying unittest framework can do, let alone Django's additions (for example, check out how you can use unittest.mock to patch third party libraries so you can more thoroughly test your own code).

+ +

While there are numerous other test tools that you can use, we'll just highlight two:

+ + + +

Challenge yourself

+ +

There are a lot more models and views we can test. As a simple task, try to create a test case for the AuthorCreate view.

+ +
class AuthorCreate(PermissionRequiredMixin, CreateView):
+    model = Author
+    fields = '__all__'
+    initial={'date_of_death':'12/10/2016',}
+    permission_required = 'catalog.can_mark_returned'
+ +

Remember that you need to check anything that you specify or that is part of the design. This will include who has access, the initial date, the template used, and where the view redirects on success.

+ +

Summary

+ +

Writing test code is neither fun nor glamorous, and is consequently often left to last (or not at all) when creating a website. It is however an essential part of making sure that your code is safe to release after making changes, and cost-effective to maintain.

+ +

In this tutorial we've shown you how to write and run tests for your models, forms, and views. Most importantly we've provided a brief summary of what you should test, which is often the hardest thing to work out when you're getting started. There is a lot more to know, but even with what you've learned already you should be able to create effective unit tests for your websites.

+ +

The next and final tutorial shows how you can deploy your wonderful (and fully tested!) Django website.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}

+ +

 

+ +

In this module

+ + + +

 

diff --git a/files/zh-tw/learn/server-side/django/tutorial_local_library_website/index.html b/files/zh-tw/learn/server-side/django/tutorial_local_library_website/index.html new file mode 100644 index 0000000000..3e2cae3be5 --- /dev/null +++ b/files/zh-tw/learn/server-side/django/tutorial_local_library_website/index.html @@ -0,0 +1,92 @@ +--- +title: 'Django 教學 1: 本地圖書館網站' +slug: Learn/Server-side/Django/Tutorial_local_library_website +tags: + - django + - 初學者 +translation_of: Learn/Server-side/Django/Tutorial_local_library_website +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}
+ +

我們實戰教學系列的第一篇,會解釋你將學到什麼。並提供一個“本地圖書館” 的例子,作為概述。在接下來的教學裡,我們會不斷完善和改進這個網站。

+ + + + + + + + + + + + +
前提:閱讀 Django 介紹。在接下來的文章裡,你需要創建 Django 開發環境.
目標:介紹教學裡使用的網站應用,讓讀者明白要討論的主題。
+ +

概覽

+ +

歡迎來到 MDN 的 ”本地圖書館“ Django 教學。在教學裡,我們會開發一個網站,用來管理本地圖書館的目錄。

+ +

在這一系列的教學裡,你將:

+ + + +

關於這些主題,你已經學會了一些,並對其他的也有了簡單的了解。在這系列教學的最後,你會學到足夠多,而可以自己開發簡單的Django 應用了。

+ +

本地圖書館網站

+ +

本地圖書館,是我們在本系列教學裡,創建和不斷改善的網站。跟你期望的一樣,這個網站的目標,是為一個小型的圖書館,提供一個線上目錄。在這個小型圖書館裡,用戶能瀏覽書籍,和管理他們的帳號。

+ +

這個例子是精心挑選出來的,因為它可以根據我們的需要,增加或多或少的細節。也能用來展示,幾乎所有的 Django 特性。更重要的是,它提供了一條指南式的路線,在這條路線中,我們會用到 Django 網路框架最重要的功能:

+ + + +

儘管這是一個非常容易擴展的例子,它被稱為本地圖書館是有原因的——我們希望用最少的訊息,幫助你快速創建、和運用 Django。最後,我們會存儲圖書訊息,圖書數量,作者和其他重要訊息。我們不會儲存圖書館可能會儲存的其他訊息,或是提供一個支持多個圖書館、或是 ”大型圖書館“ 功能的建構。

+ +

我卡住了,從哪裡獲得源程式碼呢?

+ +

在學習本系列教程時,我們會提供合適的代碼片段,你可以粘貼複製,但是有些代碼我們希望你能自己擴展(在提示下)。

+ +

如果你卡在某個地方,你可以在 Github 裡找到網站的完整代碼。

+ +

總結

+ +

現在你對本地圖書館網站有了一些了解並知道你會學到什麼。是時候創建我們例子會用到的網站框架了。

+ +

{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}

+ +

本系列教學

+ + diff --git a/files/zh-tw/learn/server-side/django/web_application_security/index.html b/files/zh-tw/learn/server-side/django/web_application_security/index.html new file mode 100644 index 0000000000..f644f400b9 --- /dev/null +++ b/files/zh-tw/learn/server-side/django/web_application_security/index.html @@ -0,0 +1,180 @@ +--- +title: Django web application security +slug: Learn/Server-side/Django/web_application_security +translation_of: Learn/Server-side/Django/web_application_security +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}
+ +

保護用戶數據是任何網站設計的重要部分。我們之前在文章 web 安全中,解釋了一些更常見的安全威脅 -- 本文提供了 Django 的內置保護如何處理這些威脅的實際演示。

+ + + + + + + + + + + + +
Prerequisites:Read the Server-side progamming "Website security" topic. Complete the Django tutorial topics up to (and including) at least Django Tutorial Part 9: Working with forms.
Objective:To understand the main things you need to do (or not do) to secure your Django web application.
+ +

Overview

+ +

The Website security topic provides an overview of what website security means for server-side design, and some of the more common threats that you may need to protect against. One of the key messages in that article is that almost all attacks are successful when the web application trusts data from the browser.

+ +
+

Important: The single most important lesson you can learn about website security is to never trust data from the browser. This includes GET request data in URL parameters, POST data, HTTP headers and cookies, user-uploaded files, etc. Always check and sanitize all incoming data. Always assume the worst.

+
+ +

The good news for Django users is that many of the more common threats are handled by the framework! The Security in Django (Django docs) article explains Django's security features and how to secure a Django-powered website.

+ +

Common threats/protections

+ +

Rather than duplicate the Django documentation here, in this article we'll demonstrate just a few of the security features in the context of our Django LocalLibrary tutorial.

+ +

Cross site scripting (XSS)

+ +

XSS is a term used to describe a class of attacks that allow an attacker to inject client-side scripts through the website into the browsers of other users. This is usually achieved by storing malicious scripts in the database where they can be retrieved and displayed to other users, or by getting users to click a link that will cause the attacker’s JavaScript to be executed by the user’s browser.

+ +

Django's template system protects you against the majority of XSS attacks by escaping specific characters that are "dangerous" in HTML. We can demonstrate this by attempting to inject some JavaScript into our LocalLibrary website using the Create-author form we set up in Django Tutorial Part 9: Working with forms.

+ +
    +
  1. Start the website using the development server (python3 manage.py runserver).
  2. +
  3. Open the site in your local browser and login to your superuser account.
  4. +
  5. Navigate to the author-creation page (which should be at URL: http://127.0.0.1:8000/catalog/author/create/).
  6. +
  7. Enter names and date details for a new user, and then append the following text to the Last Name field:
    + <script>alert('Test alert');</script>.
    + Author Form XSS test +
    +

    Note: This is a harmless script that, if executed, will display an alert box in your browser. If the alert is displayed when you submit the record then the site is vulnerable to XSS threats.

    +
    +
  8. +
  9. Press Submit to save the record.
  10. +
  11. When you save the author it will be displayed as shown below. Because of the XSS protections the alert() should not be run. Instead the script is displayed as plain text.Author detail view XSS test
  12. +
+ +

If you view the page HTML source code, you can see that the dangerous characters for the script tags have been turned into their harmless escape code equivalents (e.g. > is now &gt;)

+ +
<h1>Author: Boon&lt;script&gt;alert(&#39;Test alert&#39;);&lt;/script&gt;, David (Boonie) </h1>
+
+ +

Using Django templates protects you against the majority of XSS attacks. However it is possible to turn off this protection, and the protection isn't automatically applied to all tags that wouldn't normally be populated by user input (for example, the help_text in a form field is usually not user-supplied, so Django doesn't escape those values).

+ +

It is also possible for XSS attacks to originate from other untrusted source of data, such as cookies, Web services or uploaded files (whenever the data is not sufficiently sanitized before including in a page). If you're displaying data from these sources, then you may need to add your own sanitisation code.

+ +

Cross site request forgery (CSRF) protection

+ +

CSRF attacks allow a malicious user to execute actions using the credentials of another user without that user’s knowledge or consent. For example consider the case where we have a hacker who wants to create additional authors for our LocalLibrary.

+ +
+

Note: Obviously our hacker isn't in this for the money! A more ambitious hacker could use the same approach on other sites to perform much more harmful tasks (e.g. transfer money to their own accounts, etc.)

+
+ +

In order to do this, they might create an HTML file like the one below, which contains an author-creation form (like the one we used in the previous section) that is submitted as soon as the file is loaded. They would then send the file to all the Librarians and suggest that they open the file (it contains some harmless information, honest!). If the file is opened by any logged in librarian, then the form would be submitted with their credentials and a new author would be created.

+ +
<html>
+<body onload='document.EvilForm.submit()'>
+
+<form action="http://127.0.0.1:8000/catalog/author/create/" method="post" name='EvilForm'>
+  <table>
+    <tr><th><label for="id_first_name">First name:</label></th><td><input id="id_first_name" maxlength="100" name="first_name" type="text" value="Mad" required /></td></tr>
+    <tr><th><label for="id_last_name">Last name:</label></th><td><input id="id_last_name" maxlength="100" name="last_name" type="text" value="Man" required /></td></tr>
+    <tr><th><label for="id_date_of_birth">Date of birth:</label></th><td><input id="id_date_of_birth" name="date_of_birth" type="text" /></td></tr>
+    <tr><th><label for="id_date_of_death">Died:</label></th><td><input id="id_date_of_death" name="date_of_death" type="text" value="12/10/2016" /></td></tr>
+  </table>
+  <input type="submit" value="Submit" />
+</form>
+
+</body>
+</html>
+
+ +

Run the development web server, and log in with your superuser account. Copy the text above into a file and then open it in the browser. You should get a CSRF error, because Django has protection against this kind of thing!

+ +

The way the protection is enabled is that you include the {% csrf_token %} template tag in your form definition. This token is then rendered in your HTML as shown below, with a value that is specific to the user on the current browser.

+ +
<input type='hidden' name='csrfmiddlewaretoken' value='0QRWHnYVg776y2l66mcvZqp8alrv4lb8S8lZ4ZJUWGZFA5VHrVfL2mpH29YZ39PW' />
+
+ +

Django generates a user/browser specific key and will reject forms that do not contain the field, or that contain an incorrect field value for the user/browser.

+ +

To use this type of attack the hacker now has to discover and include the CSRF key for the specific target user. They also can't use the "scattergun" approach of sending a malicious file to all librarians and hoping that one of them will open it, since the CSRF key is browser specific.

+ +

Django's CSRF protection is turned on by default. You should always use the {% csrf_token %} template tag in your forms and use POST for requests that might change or add data to the database.

+ +

Other protections

+ +

Django also provides other forms of protection (most of which would be hard or not particularly useful to demonstrate):

+ +
+
SQL injection protection
+
SQL injection vulnerabilities enable malicious users to execute arbitrary SQL code on a database, allowing data to be accessed, modified, or deleted irrespective of the user's permissions. In almost every case you'll be accessing the database using Django’s querysets/models, so the resulting SQL will be properly escaped by the underlying database driver. If you do need to write raw queries or custom SQL then you'll need to explicitly think about preventing SQL injection.
+
Clickjacking protection
+
In this attack a malicious user hijacks clicks meant for a visible top level site and routes them to a hidden page beneath. This technique might be used, for example, to display a legitimate bank site but capture the login credentials in an invisible <iframe> controlled by the attacker. Django contains clickjacking protection in the form of the X-Frame-Options middleware which, in a supporting browser, can prevent a site from being rendered inside a frame.
+
Enforcing SSL/HTTPS
+
SSL/HTTPS can be enabled on the web server in order to encrypt all traffic between the site and browser, including authentication credentials that would otherwise be sent in plain text (enabling HTTPS is highly recommended). If HTTPS is enabled then Django provides a number of other protections you can use:
+
+ + + +
+
Host header validation
+
Use ALLOWED_HOSTS to only accept requests from trusted hosts.
+
+ +

There are many other protections, and caveats to the usage of the above mechanisms. While we hope that this has given you an overview of what Django offers, you should still read the Django security documentation.

+ + + +

Summary

+ +

Django has effective protections against a number of common threats, including XSS and CSRF attacks. In this article we've demonstrated how those particular threats are handled by Django in our LocalLibrary website. We've also provided a brief overview of some of the other protections.

+ +

This has been a very brief foray into web security. We strongly recommend that you read Security in Django to gain a deeper understanding.

+ +

The next and final step in this module about Django is to complete the assessment task.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}

+ +

 

+ +

In this module

+ + + +

 

diff --git a/files/zh-tw/learn/server-side/express_nodejs/deployment/index.html b/files/zh-tw/learn/server-side/express_nodejs/deployment/index.html new file mode 100644 index 0000000000..d7c2089cd1 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/deployment/index.html @@ -0,0 +1,521 @@ +--- +title: 'Express 教學 7: 佈署到生產環境' +slug: Learn/Server-side/Express_Nodejs/deployment +translation_of: Learn/Server-side/Express_Nodejs/deployment +--- +
{{LearnSidebar}}
+ +
{{PreviousMenu("Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}
+ +

現在你已經創建(並測試)了一個不錯的 本地圖書館 網站了,你打算把它發佈到一個公共網絡服務器,這樣圖書館管理員和網路上的其他成員就可以訪問它了。這篇文章總結了你可以怎樣找到一台主機部署你的網站,以及你需要為網站準備好佈署到生產環境該做什麼。

+ + + + + + + + + + + + +
預備知識:完成前面所有的指南主題,包括 Express Tutorial Part 6: Working with forms.
目標:學習你可以怎樣以及在哪裡部署一個 Express 應用到生產環境。
+ +

概覽

+ +

一旦您的站點完成(或完成 “足夠” 以開始公共測試),您將需要將其託管在比您的個人開發計算機,更公開和可訪問的地方。

+ +

到目前為止,您一直在開發環境中工作,使用Express / Node 作為 Web 服務器,將您的站點共享到本地瀏覽器/網路,並使用(不安全的)開發設置運行您的網站,以顯示調試和其他私人信息。在您可以在外部託管網站之前,您首先必須:

+ + + +

本教程提供了,有關選擇託管站點的選項的一些指導,簡要概述了為使您的Express 應用程序準備好生產,所需執行的操作,以及一個工作示例,演示如何將 LocalLibrary 網站安裝到 Heroku 雲託管上的服務。

+ +

請記住,您不必使用 Heroku - 還有其他託管服務可用。我們還提供了一個單獨的教程,以展示如何在 PWS/Cloud Foundry 上安裝 LocalLibrary。

+ +

什麼是生產環境?

+ +

生產環境是服務器計算機提供的環境,您可以在其中運行網站,以供外部使用。環境包括:

+ + + +

服務器計算機,可以位於您的場所,並通過快速鏈接,連接到 Internet,但使用 “託管在雲上” 的計算機更為常見。這實際上意味著,您的代碼運行在託管公司的數據中心的某台遠程計算機(或可能是“虛擬”計算機)。遠程服務器,通常會以特定價格提供互聯網連接,和一些保證級別的計算資源(例如CPU,RAM,存儲器等)。

+ +

這種可遠程訪問的計算/網絡硬件,稱為基礎架構即服務(IaaS)。許多 IaaS 供應商,提供預安裝特定操作系統的選項,您必須在其上,安裝生產環境的其他組件。其他供應商,允許您選擇功能更全面的環境,可能包括完整的 node 設置。

+ +
+

注意: 預構建環境,可以使您的網站設置變得非常簡單,因為它們會減少配置,但可用選項可能會限制您使用不熟悉的服務器(或其他組件),並且可能基於較舊版本的操作系統。通常最好自己安裝組件,以便獲得所需的組件,並且當您需要升級系統的某些部分時,您可以知道從哪裡開始!

+
+ +

其他託管服務提供商,支持 Express 作為平台即服務(PaaS)產品的一部分。使用此類託管時,您無需擔心大多數生產環境(服務器,負載平衡器等),因為主機平台會為您處理這些問題。這使得部署非常簡單,因為您只需要專注於 Web 應用程序,而不是任何其他服務器基礎結構。

+ +

一些開發人員選擇 IaaS ,相對於 PaaS ,IaaS 提供更高靈活性,而其他開發人員偏好 PaaS 的降低維護開銷,和更輕鬆的擴展性。當您在一開始使用時,在 PaaS 系統上設置您的網站,要容易得多,因此我們將在本教程中使用 PaaS。

+ +
+

提示: 如果您選擇 Node/Express 友好的託管服務提供商,他們應該提供,有關如何使用 Web 服務器,應用程序服務器,反向代理等不同配置,來設置 Express 網站的說明。例如,在 Digital Ocean 的node 社區文檔中,有許多各種配置的手把手指南。

+
+ +

選擇一個主機供應商

+ +

眾所周知,眾多託管服務提供商,都積極支持或與 Node(和Express)合作。這些供應商提供不同類型的環境(IaaS,PaaS),以及不同價格的不同級別的計算和網絡資源。

+ +
+

提示: 有很多託管解決方案,他們的服務和定價,可能會隨著時間而改變。雖然我們在下面介紹幾個選項,但在選擇託管服務提供商之前,有必要自己進行互聯網搜索。

+
+ +

選擇主機時需要考慮的一些事項:

+ + + +

當你剛開始時,好消息是有很多網站提供“免費”的計算環境,儘管有一些條件。例如, Heroku  “永遠” 提供免費但資源有限的 PaaS 環境,而 Amazon Web Services, Microsoft Azure 和開源選項 PWS/Cloud Foundry 在您第一次加入時,提供免費信用額度。

+ +

許多提供商還擁有“基本”層,可提供更多有用的計算能力,和更少的限制。舉例來說, Digital Ocean 是一個流行的託管服務提供商,它提供了一個相對便宜的基本計算層(在本教程寫作時,是每月5美元的較低範圍)。

+ +
+

注意: 請記住,價格不是唯一的選擇標準。如果您的網站成功,可能會發現可擴展性是最重要的考慮因素。

+
+ +

準備好發布你的網站

+ +

發佈網站時,要考慮的主要問題是網絡安全性和性能。至少,您需要刪除開發期間,錯誤頁面上包含的堆棧跟踪,整理日誌記錄,並設置適當的標頭,以避免許多常見的安全威脅。

+ +

在以下小節中,我們概述了您應該對應用進行的、最重要的更改。

+ +
+

提示: Express文檔中還有其他有用的提示 - 請參閱“生產最佳實踐:性能和可靠性”,以及“生產最佳實踐:安全性”。

+
+ +

設置 NODE_ENV 為 'production'

+ +

我們可以通過將 NODE_ENV 環境變量,設置為 production ,來刪除錯誤頁面中的堆棧跟踪(默認設置為 “development” )。除了生成較為不詳細的錯誤消息之外,還要將變量設置為生產緩存視圖模板,和從 CSS 擴展生成的 CSS 文件。測試表明,將NODE_ENV設置為生產,可以將應用程序性能提高三倍!

+ +

可以使用導出或環境文件,或使用 OS 初始化系統,以進行此更改。

+ +
+

注意: 這實際上是在環境設置,而不是應用中所做的更改,但重要的是,要注意這裡!我們將在下面,展示我們的託管示例要如何設置。

+
+ +

Log appropriately

+ +

記錄呼叫會對高流量網站產生影響。在生產環境中,您可能需要記錄網站活動(例如,跟踪流量,或記錄API調用),但您應嘗試最小化為調試目的而添加的日誌記錄量。

+ +

在生產環境中,最小化“調試”日誌記錄的一種方法,是使用類似調試 debug  的模塊,允許您通過設置環境變量,來控制執行的日誌記錄。例如,下面的代碼片段,顯示如何設置 “author” 日誌記錄。調試變量使用名稱 “author” 聲明,並且將自動顯示,來自此對象的所有日誌的前綴 “author”。

+ +
var debug = require('debug')('author');
+
+// Display Author update form on GET
+exports.author_update_get = function(req, res, next) {
+
+    req.sanitize('id').escape().trim();
+    Author.findById(req.params.id, function(err, author) {
+        if (err) {
+            debug('update error:' + err);
+            return next(err);
+        }
+        //On success
+        res.render('author_form', { title: 'Update Author', author: author });
+    });
+
+};
+ +

然後,您可以通過在 DEBUG 環境變量中,將它們指定為逗號分隔列表,來啟用特定日誌集。您可以設置顯示作者和書籍日誌的變量,如圖所示(也支持通配符)。

+ +
#Windows
+set DEBUG=author,book
+
+#Linux
+export DEBUG="author,book"
+
+ +
+

挑戰: 調用debug可以替換您以前使用 console.log()console.error()執行的日誌記錄。通過調試模塊 debug 進行日誌記錄,替換代碼中的所有console.log()調用。通過設置 DEBUG 變量,並在其中記錄對日誌記錄的影響,在開發環境中,打開和關閉日誌記錄。

+
+ +

如果您需要記錄網站活動,可以使用 Winston 或 Bunyan 等日誌庫。有關此主題的更多信息,請參閱:生產最佳實踐:性能和可靠性

+ +

使用 gzip/deflate 壓縮響應

+ +

Web 服務器,通常可以壓縮發送回客戶端的 HTTP 響應,從而顯著減少客戶端獲取和加載頁面所需的時間。使用的壓縮方法,取決於客戶端在請求中支持的解壓縮方法(如果不支持壓縮方法,則響應將以未壓縮的方式發送)。

+ +

您可以使用壓縮中間件 compression,將其添加到您的站點。通過在項目的根目錄下,運行以下命令,將其安裝到項目中。

+ +
npm install compression
+ +

打開./app.js,並導入壓縮庫,如圖所示。使用 use()方法,將壓縮庫添加到中間件鏈(這應該出現在您想要壓縮的任何路由之前 - 在本教程這種情況下,全部都是!)

+ +
var catalogRouter = require('./routes/catalog'); //Import routes for "catalog" area of site
+var compression = require('compression');
+
+// Create the Express application object
+var app = express();
+
+...
+
+app.use(compression()); //Compress all routes
+
+app.use(express.static(path.join(__dirname, 'public')));
+
+app.use('/', indexRouter);
+app.use('/users', usersRouter);
+app.use('/catalog', catalogRouter);  // Add catalog routes to middleware chain.
+
+...
+
+ +
+

注意: 對於生產中流量較大的網站,您不會使用此中間件。相反,你會使用像 Nginx 這樣的反向代理。

+
+ +

使用 Helmet 避免被常見漏洞侵襲

+ +

Helmet 是一個中間件包,可以通過設置適當的 HTTP 標頭,來幫助保護您的應用,免受一些眾所周知的 Web 漏洞的影響(有關它設置的標頭/防護漏洞的詳細信息,請參閱文檔 docs) 。

+ +

通過在項目的根目錄下,運行以下命令,將其安裝到項目中。

+ +
npm install helmet
+
+ +

打開./app.js,並導入如圖所示的 helmet 庫。然後使用use()方法,將模塊添加到中間件鏈。

+ +
var compression = require('compression');
+var helmet = require('helmet');
+
+// Create the Express application object
+var app = express();
+
+app.use(helmet());
+...
+ +
+

注意: 上面的命令,添加了對大多數站點有意義的可用標頭子集。您可以按照 npm 上的說明,根據需要添加/禁用特定標頭。

+
+ +

例子:在 Heroku 上安裝本地圖書館

+ +

本節提供如何在 Heroku PaaS cloud 雲上安裝 LocalLibrary 的實際演示。

+ +

為什麼選擇 Heroku?

+ +

Heroku 是運行時間最長,且最受歡迎的基於雲的 PaaS 服務之一。它最初只支持 Ruby 應用程序,但現在可用於託管來自許多編程環境的應用程序,包括 Node(以及Express)!

+ +

我們選擇使用 Heroku 有以下幾個原因:

+ + + +

雖然 Heroku 非常適合舉辦此演示,但它可能並不適合您的真實網站。 Heroku 可以輕鬆設置和擴展,但代價是靈活性較低,而且一旦退​​​​出免費套餐,可能會花費更多。

+ +

Heroku 如何工作?

+ +

Heroku在一個或多個 "Dynos" 中運行網站,這些 “Dynos” 是獨立的虛擬化Unix容器,提供運行應用程序所需的環境。 Dynos 是完全隔離的,並且有一個短暫的文件系統(一個短暫的文件系統,每次dyno重新啟動時都會清理/清空)。 dynos 默認共享的唯一內容,是應用程序配置變量 configuration variables。 Heroku 內部使用負載均衡器,將Web流量分配給所有 “web” dynos。由於它們之間沒有任何共享,Heroku 可以通過添加更多 dynos,來水平擴展應用程序(當然,您可能還需要擴展數據庫,以接受其他連接)。

+ +

由於文件系統是短暫的,因此無法直接安裝應用程序所需的服務(例如數據庫,隊列,緩存系統,存儲,電子郵件服務等)。相反,Heroku Web應用程序使用 Heroku 或第三方作為獨立“附加組件”提供的支持服務。連接到Web應用程序後,可以通過環境變量,在Web應用程序中訪問附加服務。

+ +

為了執行您的應用程序,Heroku 需要能夠設置適當的環境和依賴關係,並了解它是如何啟動的。對於 Node 應用程序,它所需的所有信息都是從 package.json文件中獲取的。

+ +

開發人員使用特殊的客戶端應用程序/終端,與 Heroku 交互,這很像 Unix bash 腳本。這允許您上傳存儲在 git 儲存庫中的代碼,檢查正在運行的進程,查看日誌,設置配置變量等等!

+ +

為了讓我們的應用程序在 Heroku 上工作,我們需要將我們的 Express Web 應用程序放入 git 儲存庫,並對 package.json 進行一些小的更改。完成後,我們可以設置Heroku 帳戶,獲取 Heroku 客戶端,並使用它來安裝我們的網站。

+ +

這是您開始教程所需的全部概述(有關更全面的指南,請參閱帶有 Node.js 的Heroku 入門)。

+ +

在 Github 上創建一個應用倉庫

+ +

Heroku 與 git 源代碼版本控制系統緊密集成,使用它來上傳/同步您對實時運行系統所做的任何更改。它通過添加一個名為 heroku 的新 Heroku“遠程”儲存庫,來指向您在Heroku雲上的源儲存庫。在開發期間,您使用 git 在“主”儲存庫 master 中儲存更改。如果要部署站點,請將更改同步到 Heroku 存儲庫。

+ +
+

注意: 如果您習慣於遵循良好的軟件開發實踐,那麼您可能已經在使用 git 或其他一些 SCM 系統。如果您已有 git 儲存庫,則可以跳過此步驟。

+
+ +

有很多方法可以使用git,但最簡單的方法之一,是首先在 GitHub 上建立一個帳戶,在那裡創建儲存庫,然後在本地同步它:

+ +
    +
  1. 訪問 https://github.com/ 並創建一個帳戶。
  2. +
  3. 登錄後,單擊頂部工具欄中的 + 號鏈接,然後選擇新建儲存庫  New repository
  4. +
  5. 填寫此表單上的所有字段。雖然這些不是強制性的,但強烈建議使用它們。 +
      +
    • 輸入新的存儲庫名稱(例如,express-locallibrary-tutorial)和描述(例如 “以Express(node)編寫的本地圖書館網站”)。
    • +
    • 在 Add .gitignore 選擇列表中選擇 Node
    • +
    • 在添加許可證 Add license 選擇列表中,選擇您偏好的許可證。
    • +
    • 點選 使用自述文件初始化此儲存庫 Initialize this repository with a README.
    • +
    +
  6. +
  7. Create repository.
  8. +
  9. 單擊新倉庫頁面上的綠色“克隆或下載”按鈕 "Clone or download" 。
  10. +
  11. 從顯示的對話框的文本字段,複製 URL值(它應該類似於:https://github.com/<your_git_user_id>/express-locallibrary-tutorial.git)。
  12. +
+ +

現在創建了儲存庫(“repo”),我們將要在本地計算機上克隆它:

+ +
    +
  1. 為您的本地計算機安裝 git(您可以在此處找到不同平台的版本)。
    +  
  2. +
  3. 打開命令提示符/終端,並使用您在上面複製的 URL ,克隆儲存庫: +
    git clone https://github.com/<your_git_user_id>/express-locallibrary-tutorial.git
    +
    + 這將在當前時間點之後,創建儲存庫。
  4. +
  5. 到新的儲存庫。 +
    cd express-locallibrary-tutorial
    +
  6. +
+ +

最後一步,是複制你的應用程序,然後使用 git ,將文件添加到你的倉庫:

+ +
    +
  1. 將Express應用程序,複製到此文件夾中(不包括 /node_modules,其中包含您應根據需要,從 NPM 獲取的依賴項文件)。
  2. +
  3. 打開命令提示符/終端,並使用 add 命令,將所有文件添加到 git。
  4. +
  5. +
    git add -A
    +
    +
  6. +
  7. 使用 status 命令,檢查要添加的所有文件是否正確(您希望包含源文件,而不是二進製文件,臨時文件等)。它應該看起來有點像下面的列表。 +
    > git status
    +On branch master
    +Your branch is up-to-date with 'origin/master'.
    +Changes to be committed:
    +  (use "git reset HEAD <file>..." to unstage)
    +
    +        new file:   ...
    +
  8. +
  9. 如果您滿意,請將文件提交到本地儲存庫: +
    git commit -m "First version of application moved into github"
    +
  10. +
  11. 然後使用以下內容,將本地儲存庫同步到 Github 網站: +
    git push origin master
    +
  12. +
+ +

完成此操作後,您應該可以返回創建儲存庫的 Github 上的頁面,刷新頁面,並查看您的整個應用程序現已上傳。使用此添加/提交/推送循環,您可以在文件更改時,繼續更新儲存庫。

+ +
+

提示: 這是備份你的“vanilla”項目的好時機 - 雖然我們將在以下部分中進行的一些更改,可能對任何平台(或開發)上的部署有用,而一些其他的更改可能沒有用。

+ +

執行此操作的最佳方法,是使用 git 來管理您的修訂。使用 git,您不僅可以回到特定的舊版本,而且可以在生產變更的單獨“分支”中進行維護,並選擇在生產和開發分支之間移動的任何更改。學習Git非常值得,但超出了本主題的範圍。

+ +

最簡單的方法,是將文件複製到另一個位置。以您對 git 了解,使用最符合的方法!

+
+ +

更新 Heroku 的應用程序

+ +

本節介紹了您需要對 LocalLibrary 應用程序進行的更改,以使其在 Heroku 上運行。

+ +

設置 node 版本

+ +

package.json 包含解決應用程序依賴項所需的所有內容,以及啟動站點時,應啟動的文件。 Heroku 檢測到此文件的存在,並將使用它來配置您的應用程序環境。

+ +

我們當前的 package.json 中,缺少的唯一有用信息,是 node 的版本。我們可以通過輸入命令,找到我們用於開發的 node 版本:

+ +
>node --version
+v8.9.1
+ +

打開 package.json,並將此信息添加為 engines > node 部分,如圖所示(使用系統的版本號)。

+ +
{
+  "name": "express-locallibrary-tutorial",
+  "version": "0.0.0",
+  "engines": {
+    "node": "8.9.1"
+  },
+  "private": true,
+  ...
+
+ +

數據庫配置

+ +

到目前為止,在本教程中,我們使用了一個硬編碼到 app.js 的單個數據庫。通常我們希望,能夠為生產和開發創建不同的數據庫,接下來我們將修改 LocalLibrary 網站,以從 OS 環境獲取數據庫 URI(如果已定義),否則使用我們的開發數據庫。

+ +

打開 app.js,並找到設置 mongoDB 連接變量的行。它看起來像這樣:

+ +
var mongoDB = 'mongodb://your_user_id:your_password@ds119748.mlab.com:19748/local_library';
+ +

使用以下代碼替換該行,該代碼使用 process.env.MONGODB_URI 從名為 MONGODB_URI 的環境變量中,獲取連接字符串(如果已設置)(使用您自己的數據庫URL,而不是下面的佔位符。)

+ +
var mongoDB = process.env.MONGODB_URI || 'mongodb://your_user_id:your_password@ds119748.mlab.com:19748/local_library';
+
+ +

安裝依賴並重新測試

+ +

在我們繼續之前,讓我們再次測試該網站,並確保它不受我們的任何更改的影響。

+ +

首先,我們需要獲取我們的依賴項(你會記得,我們​​沒有將 node_modules文件夾,複製到我們的 git 樹中)。您可以通過在項目根目錄的終端中,運行以下命令來執行此操作:

+ +
npm install
+
+ +

現在運行該站點(請參閱測試路由的相關命令),並檢查該站點,是否仍按預期運行。

+ +

將更改保存到 Github

+ +

接下來,讓我們將所有更改保存到 Github。在終端中(在我們的儲存庫中),輸入以下命令:

+ +
git add -A
+git commit -m "Added files and changes required for deployment to heroku"
+git push origin master
+ +

我們現在應該準備開始在 Heroku 上,部署 LocalLibrary。

+ +

獲取一個 Heroku 帳戶

+ +

要開始使用 Heroku,您首先需要創建一個帳戶(如果您已經擁有一個帳戶,並安裝了 Heroku 客戶端,請跳過創建並上傳網站):

+ + + +

安裝客戶端

+ +

按照 Heroku 上的說明,下載並安裝 Heroku 客戶端。

+ +

安裝客戶端后,您將能夠運行命令。例如,要獲得客戶端的幫助說明:

+ +
heroku help
+
+ +

創建並上傳網站

+ +

要創建應用程序,我們在儲存庫的根目錄中,運行 “create” 命令。這將在我們的本地git 環境中,創建一個名為 heroku 的 git remote(“指向遠程儲存庫的指針”)。

+ +
heroku create
+ +
+

注意: 如果您願意,可以在“創建”create 之後指定遠程儲存庫的命名。如果你不這樣做,你會得到一個隨機的名字。該名稱用於默認 URL。

+
+ +

然後,我們可以將我們的應用程序,推送到 Heroku 儲存庫,如下所示。這將上傳應用程序,獲取所有依賴項,將其打包到 dyno 中,然後啟動該站點。

+ +
git push heroku master
+ +

如果我們很幸運,該應用程序現在正在網站上“運行”。要打開瀏覽器並運行新網站,請使用以下命令:

+ +
heroku open
+ +
+

注意: 該站點將使用我們的開發數據庫運行。創建一些書本和其他對象,並檢查該網站是否按預期運行。在下一節中,我們將其設置為使用我們的新數據庫。

+
+ +

設定配置變量

+ +

您將從前一節回憶起,我們需要將 NODE_ENV 設置為 'production',以便提高性能,並生成更簡潔的錯誤消息。我們通過輸入以下命令,來完成此操作:

+ +
>heroku config:set NODE_ENV='production'
+Setting NODE_ENV and restarting limitless-tor-18923... done, v13
+NODE_ENV: production
+
+ +

我們還應該使用單獨的數據庫進行生產,在MONGODB_URI環境變量中,設置其URI。您可以完全按照我們原來的方式,設置新數據庫和數據庫用戶,並獲取其URI。您可以如下圖所示設置URI(顯然,要使用您自己的URI!)

+ +
>heroku config:set MONGODB_URI='mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production'
+Setting MONGODB_URI and restarting limitless-tor-18923... done, v13
+MONGODB_URI: mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production
+
+ +

您可以使用 heroku config 命令,隨時檢查配置變量 - 立即嘗試:

+ +
>heroku config
+=== limitless-tor-18923 Config Vars
+MONGODB_URI: mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production
+NODE_ENV:    production
+
+ +

Heroku 會在更新變量時,重新啟動應用程序。如果您現在檢查主頁,它應該顯示對象計數的零值,因為上面的更改,意味著我們現在正在使用新的(空)數據庫。

+ +

管理附加組件

+ +

Heroku 使用獨立的附加組件,為應用程序提供支持服務 - 例如電子郵件或數據庫服務。我們不在本網站中使用任何插件,但它們是使用 Heroku 的重要部分,因此您可能需要查看主題 - 管理插件(Heroku 官方文件)

+ +

除錯

+ +

Heroku 客戶端提供了一些除錯工具:

+ +
heroku logs  # Show current logs
+heroku logs --tail # Show current logs and keep updating with any new results
+heroku ps   #Display dyno status
+
+ + + +

總結

+ +

本教程介紹在生產環境中,如何配置 Express 應用。是Express系列教程的最後一個。我們希望你覺得這些教程有用。你可以在 Github 上取得完整的源碼。

+ +

相關鏈接

+ + + +

{{PreviousMenu("Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}

+ +

 

+ +

本教學鏈接

+ + + +

 

diff --git a/files/zh-tw/learn/server-side/express_nodejs/development_environment/index.html b/files/zh-tw/learn/server-side/express_nodejs/development_environment/index.html new file mode 100644 index 0000000000..3e556ada3a --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/development_environment/index.html @@ -0,0 +1,385 @@ +--- +title: Setting up a Node development environment +slug: Learn/Server-side/Express_Nodejs/development_environment +translation_of: Learn/Server-side/Express_Nodejs/development_environment +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}
+ +

現在你已經了解Express的目的了,接下來繼續說明如何設定和測試 Windows、Linux (Ubuntu)和Mac OS X上的Node/Express開發環境。不管你用的是什麼作業系統,你都能在本文中找到開發Express應用的入門需知。

+ + + + + + + + + + + + +
前置需求:了解如何開啟terminal / command line. 了解如何在開發系統上安裝套件。
目標:在你的電腦上設定Express(X.XX)開發環境。
+ +

Express 開發環境概覽

+ +

為了使你能快速的開發web應用,Node 和 Express 非常容易安裝,這個部分說明哪些工具是需要的、在Ubuntu、macOS和Windows中安裝Node和Express的最簡單方法、展示如何測試安裝成功與否。

+ +

什麼是Express開發環境?

+ +

Express 開發環境包含 Nodejs、NPM 套件管理器的安裝, 還有 Express Application 產生器(可選)

+ +

Node 和 NPM 套件管理器會從準備好的 binary package、安裝檔、 作業系統的套件管理器或是從源檔一起安裝。接著 Express 會透過 NPM 進行安裝,成為你所有個別 Express web 應用的依賴項(以及其他函式庫,如模板引擎,資料庫驅動程式,身份驗證中間層,用於提供靜態文件的中間件等)

+ +

NPM 也可用來安裝 Express 應用程式產生器(全域用),一個方便的工具幫助你創造符合 MVC模式的 Express web app 骨架。你不一定要使用應用程式產生器,因為每個Express應用程式不需要擁有同樣的檔案結構或依賴項。但為了專注於學習本身以及習慣模組化架構,我們會在接下來的教學中使用它。

+ +
+

注意: 與其他不包含單獨的web開發伺服器的Web框架不同。 在Node / Express中,Web應用程式創建並運行自己的Web伺服器!

+
+ +

典型的開發環境還包含其他工具,例如:編輯程式碼使用的文字編輯器、IDE,進行版本控置管理不同版本程式碼的Git。這邊假設你已經有這種工具了(尤其是文字編輯器)

+ +

哪些作業系統有支援?

+ +

Node 可以執行在 Windows、macOS、各種 Linux、Docker 等等(nodejs 的下載頁面有完整的列表),在開發階段中個人電腦應該都有足夠的效能來執行 Node 。Express 執行在 Node 環境中,所以也能所有有安裝Node的平台上執行。

+ +

在這份教學中我們提供 Windows、macOS 和 Ubuntu Linux 的 Node 安裝教學。

+ +

該用什麼版本的 Node/Express?

+ +

Node 有許多版本,更新的版本代表著 bug 的修復、支援更新版本的 ECMAScript(JavaScript)標準和更好的 Node APIs 。

+ +

基本上你應該使用最新的 LTS 版本(long-term supported,長期維護版)。這種版本比『Current』版本更穩定而且還擁有最新的功能及持續性的更新維護。除非LTS不支援你需要的功能才使用『Current』版本。

+ +

而 Express ?永遠使用最新版!

+ +

關於資料庫和其他依賴項呢?

+ +

諸如資料庫、模版引擎、驗證引擎等等都屬於應用程式的一部分,這些依賴項會透過NPM導入應用程式環境中,在後續的章節將會進一步探討。

+ +

安裝Node

+ +

為了使用Express,首先要在你的電腦上安裝Node和Node Package Manager (NPM)。接下來用最簡單的方法在 Ubuntu Linux 16.04、 macOS和 Windows 10上安裝Nodejs的 Long Term Supported (LTS)版本吧

+ +
+

以下的部分用最簡單的方法在上述的作業系統中安裝Node和NPM。如果你使用其他作業系統或想看看其他平台的安裝方式,請查閱透過套件管理器安裝Node.js (nodejs.org)。

+
+ +

Windows 和macOS

+ +

直接使用安裝檔吧!

+ +
    +
  1. 下載需要的安裝檔: +
      +
    1. 開啟 https://nodejs.org/en/
    2. +
    3. 對於大部分的使用者來說,直接下載LTS版本
    4. +
    +
  2. +
  3. 下載完成後雙擊安裝檔,並照著安裝流程繼續。
  4. +
+ +

Ubuntu 16.04

+ +

安裝Node 8.x LTS版本最簡單的方法是使用套件管理器,只要在terminal上執行兩行指令

+ +
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
+sudo apt-get install -y nodejs
+
+
+ +
+

警告: 不要直接從普通的Ubuntu repositories 安裝,那邊只有很舊的版本。

+
+ +
    +
+ +

測試 Nodejs 和NPM 的安裝

+ +

測試Node安裝最簡單的方法是在terminal/command上執行"version"這個指令,它會顯示當前的Node版本:

+ +
>node -v
+v8.9.4
+ +

NPM應該會隨著Node一起安裝,可以用相同的方法進行測試:

+ +
>npm -v
+5.6.0
+ +

接著用稍為令人興奮的方法來測試吧!讓我們創件一個非常基本的『純Node』伺服器,當你開啟正確的網頁時它會在瀏覽器上顯示"Hello World"

+ +
    +
  1. 複製以下的文字到名為hellonode.js的檔案中,目前我們只用到Node而已。 + +
    //載入HTTP模組
    +var http = require("http");
    +
    +//創建HTTP 伺服器並監聽8000埠
    +http.createServer(function (request, response) {
    +
    +   // Set the response HTTP header with HTTP status and Content type
    +   response.writeHead(200, {'Content-Type': 'text/plain'});
    +
    +   // Send the response body "Hello World"
    +   response.end('Hello World\n');
    +}).listen(8000);
    +
    +// Print URL for accessing server
    +console.log('Server running at http://127.0.0.1:8000/')
    +
    + +

    這段程式載入『http』模組,並創建一個伺服器 (createServer(),並在8000埠上監聽HTTP requests。 The script then prints a message to the console about what browser URL you can use to test the server. The createServer() function takes as an argument a callback function that will be invoked when an HTTP request is received — this simply returns a response with an HTTP status code of 200 ("OK") and the plain text "Hello World".

    +
  2. +
  3. +
    +

    Note:  Don't worry if you don't understand exactly what this code is doing yet! We'll explain our code in greater detail once we start using Express!

    +
    +
  4. +
  5. Start the server by navigating into the same directory as your hellonode.js file in your command prompt, and calling node along with the script name, like so: +
    >node hellonode.js
    +Server running at http://127.0.0.1:8000/
    +
    +
  6. +
  7. Navigate to the URL (http://127.0.0.1:8000/). If everything is working, the browser should simply display the string "Hello World".
  8. +
+ +

Using NPM

+ +

Next to Node itself, NPM is the most important tool for working with Node applications. NPM is used to fetch any packages (JavaScript libraries) that an application needs for development, testing, and/or production, and may also be used to run tests and tools used in the development process. 

+ +
+

Note: From Node's perspective, Express is just another package that you need to install using NPM and then require in your own code.

+
+ +

You can manually use NPM to separately fetch each needed package. Typically we instead manage dependencies using a plain-text definition file named package.json. This file lists all the dependencies for a specific JavaScript "package", including the package's name, version, description, initial file to execute, production dependencies, development dependencies, versions of Node it can work with, etc. The package.json file should contain everything NPM needs to fetch and run your application (if you were writing a reusable library you could use this definition to upload your package to the npm respository and make it available for other users).

+ +

Adding dependencies

+ +

The following steps show how you can use NPM to download a package, save it into the project dependencies, and then require it in a Node application.

+ +
+

Note: Here we show the instructions to fetch and install the Express package. Later on we'll show how this package, and others, are already specified for us using the Express Application Generator. This section is provided because it is useful to understand how NPM works and what is being created by the application generator.

+
+ +
    +
  1. First create a directory for your new application and navigate into it: +
    mkdir myapp
    +cd myapp
    +
  2. +
  3. Use the npm init command to create a package.json file for your application. This command prompts you for a number of things, including the name and version of your application and the name of the initial entry point file (by default this is index.js). For now, just accept the defaults: +
    npm init
    + +

    If you display the package.json file (cat package.json), you will see the defaults that you accepted, ending with the license.

    + +
    {
    +  "name": "myapp",
    +  "version": "1.0.0",
    +  "description": "",
    +  "main": "index.js",
    +  "scripts": {
    +    "test": "echo \"Error: no test specified\" && exit 1"
    +  },
    +  "author": "",
    +  "license": "ISC"
    +}
    +
    +
  4. +
  5. Now install the Express library in the myapp directory. The package will automatically be saved to the dependencies list in your package.json file. +
    npm install express
    + +

    The dependencies section of your package.json will now appear at the end of the package.json file and will include Express.

    + +
    {
    +  "name": "myapp",
    +  "version": "1.0.0",
    +  "description": "",
    +  "main": "index.js",
    +  "scripts": {
    +    "test": "echo \"Error: no test specified\" && exit 1"
    +  },
    +  "author": "",
    +  "license": "ISC",
    +  "dependencies": {
    +    "express": "^4.16.2"
    +  }
    +}
    +
    +
  6. +
  7. To use the library you call the require() function as shown below. +
    var express = require('express')
    +var app = express()
    +
    +app.get('/', function (req, res) {
    +  res.send('Hello World!')
    +})
    +
    +app.listen(8000, function () {
    +  console.log('Example app listening on port 8000!')
    +})
    +
    + +

    This code shows a minimal "HelloWorld" Express web application. This imports the "express" module and uses it to create a server (app) that listens for HTTP requests on port 8000 and prints a message to the console explaining what browser URL you can use to test the server. The app.get() function only responds to HTTP GET requests with the specified URL path ('/'), in this case by calling a function to send our Hello World! message. 
    +
    + Create a file named index.js in the root of the "myapp" application directory and give it the contents shown above.

    +
  8. +
  9. You can start the server by calling node with the script in your command prompt: +
    >node index.js
    +Example app listening on port 8000
    +
    +
  10. +
  11. Navigate to the URL (http://127.0.0.1:8000/). If everything is working, the browser should simply display the string "Hello World!".
  12. +
+ +

Development dependencies

+ +

If a dependency is only used during development, you should instead save it as a "development dependency" (so that your package users don't have to install it in production). For example, to use the popular JavaScript Linting tool eslint you would call NPM as shown:

+ +
npm install eslint --save-dev
+ +

The following entry would then be added to your application's package.json:

+ +
  "devDependencies": {
+    "eslint": "^4.12.1"
+  }
+
+ +
+

Note: "Linters" are tools that perform static analysis on software in order to recognise and report adherence/non-adherance to some set of coding best practice.

+
+ +

Running tasks

+ +

In addition to defining and fetching dependencies you can also define named scripts in your package.json files and call NPM to execute them with the run-script command. This approach is commonly used to automate running tests and parts of the development or build toolchain (e.g., running tools to minify JavaScript, shrink images, LINT/analyse your code, etc).

+ +
+

Note: Task runners like Gulp and Grunt can also be used to run tests and other external tools.

+
+ +

For example, to define a script to run the eslint development dependency that we specified in the previous section we might add the following script block to our package.json file (assuming that our application source is in a folder /src/js):

+ +
"scripts": {
+  ...
+  "lint": "eslint src/js"
+  ...
+}
+
+ +

To explain a little further, eslint src/js is a command that we could enter in our terminal/command line to run eslint on JavaScript files contained in the src/js directory inside our app directory. Including the above inside our app's package.json file provides a shortcut for this command — lint.

+ +

We would then be able to run eslint using NPM by calling:

+ +
npm run-script lint
+# OR (using the alias)
+npm run lint
+
+ +

This example may not look any shorter than the original command, but you can include much bigger commands inside your npm scripts, including chains of multiple commands. You could identify a single npm script that runs all your tests at once.

+ +

Installing the Express Application Generator

+ +

The Express Application Generator tool generates an Express application "skeleton". Install the generator using NPM as shown (the -g flag installs the tool globally so that you can call it from anywhere):

+ +
npm install express-generator -g
+ +

To create an Express app named "helloworld" with the default settings, navigate to where you want to create it and run the app as shown:

+ +
express helloworld
+ +
+

Note: You can also specify the template library to use and a number of other settings. Use the help command to see all the options:

+ +
express --help
+
+
+ +

NPM will create the new Express app in a sub folder of your current location, displaying build progress on the console. On completion, the tool will display the commands you need to enter to install the Node dependencies and start the app.

+ +
+

The new app will have a package.json file in its root directory. You can open this to see what dependencies are installed, including Express and the template library Jade:

+ +
{
+  "name": "helloworld",
+  "version": "0.0.0",
+  "private": true,
+  "scripts": {
+    "start": "node ./bin/www"
+  },
+  "dependencies": {
+    "body-parser": "~1.18.2",
+    "cookie-parser": "~1.4.3",
+    "debug": "~2.6.9",
+    "express": "~4.15.5",
+    "jade": "~1.11.0",
+    "morgan": "~1.9.0",
+    "serve-favicon": "~2.4.5"
+  }
+}
+
+ +

Install all the dependencies for the helloworld app using NPM as shown:

+ +
cd helloworld
+npm install
+
+ +

Then run the app (the commands are slightly different for Windows and Linux/macOS), as shown below:

+ +
# Run the helloworld on Windows
+SET DEBUG=helloworld:* & npm start
+
+# Run helloworld on Linux/macOS
+DEBUG=helloworld:* npm start
+
+ +

The DEBUG command creates useful logging, resulting in an output like that shown below.

+ +
>SET DEBUG=helloworld:* & npm start
+
+> helloworld@0.0.0 start D:\Github\expresstests\helloworld
+> node ./bin/www
+
+  helloworld:server Listening on port 3000 +0ms
+ +

Open a browser and navigate to http://127.0.0.1:3000/ to see the default Express welcome page.

+ +

Express - Generated App Default Screen

+ +

We'll talk more about the generated app when we get to the article on generating a skeleton application.

+ + + +

總結

+ +

你現在有一個 Node 開發環境在你的電腦上運行,可以用來創造 Express 網頁應用。你也看到如何用 NPM 來加載 Express到一個應用中,以及看到如何使用 Express 應用產生器,創建應用,然後執行它們。

+ +

下一篇文章,我們開始跟著教程一步一步實作,使用這個開發環境與搭配工具,建立一個完整的網頁應用。

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}

+ + + +

In this module

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_detail_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_detail_page/index.html new file mode 100644 index 0000000000..df7a5180e5 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_detail_page/index.html @@ -0,0 +1,89 @@ +--- +title: 作者詳情頁面 +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page +--- +

作者細節頁面,需要呈現指定作者 Author 的信息,使用 _id 欄位的值(自動產生)識別,接著是這個作者 Author 的所有書本物件 Book 的列表。

+ +

Controller 控制器

+ +

打開 /controllers/authorController.js.

+ +

在檔案最上方,加入底下幾行,引入 asyncBook 模組(作者細節頁面需要它們)。

+ +
var async = require('async');
+var Book = require('../models/book');
+ +

找到 exported author_detail() 控制器方法,並用底下代碼置換。

+ +
// Display detail page for a specific Author.
+exports.author_detail = function(req, res, next) {
+
+    async.parallel({
+        author: function(callback) {
+            Author.findById(req.params.id)
+              .exec(callback)
+        },
+        authors_books: function(callback) {
+          Book.find({ 'author': req.params.id },'title summary')
+          .exec(callback)
+        },
+    }, function(err, results) {
+        if (err) { return next(err); } // Error in API usage.
+        if (results.author==null) { // No results.
+            var err = new Error('Author not found');
+            err.status = 404;
+            return next(err);
+        }
+        // Successful, so render.
+        res.render('author_detail', { title: 'Author Detail', author: results.author, author_books: results.authors_books } );
+    });
+
+};
+
+ +

此處的控制器方法使用 async.parallel(),用平行的方式,查詢作者 Author和相應的書本實例,並附加上繪製本頁面的回調,如果 2 個要求都成功完成,就運行回調。這個方式,就跟前面的種類細節頁面所說明的完全相同。

+ +

View 視圖

+ +

創建 /views/author_detail.pug ,並複制貼上底下的文字。

+ +
extends layout
+
+block content
+
+  h1 Author: #{author.name}
+  p #{author.date_of_birth} - #{author.date_of_death}
+
+  div(style='margin-left:20px;margin-top:20px')
+
+    h4 Books
+
+    dl
+      each book in author_books
+        dt
+          a(href=book.url) #{book.title}
+        dd #{book.summary}
+
+      else
+        p This author has no books.
+
+ +

本模板裡的所有事物,都在先前的章節演示過了。

+ +

它看起來像是?

+ +

運行本應用,並打開瀏覽器訪問 http://localhost:3000/。選擇 All Authors 連結,然後選擇一個作者。如果每個東西都設定正確了,你的網站看起來應該會像底下的截圖。

+ +

Author Detail Page - Express Local Library site

+ +
+

注意:  作者的出生與死亡日期的外觀很醜!我們將在本文最後的自我挑戰處理它。

+
+ +

下一步

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html new file mode 100644 index 0000000000..f207126ed1 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html @@ -0,0 +1,85 @@ +--- +title: Author list page and Genre list page challenge +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page +--- +

作者列表頁面,需要呈現數據庫中所有作者的列表,有每位作者的名字,並連結到作者詳細內容頁面。出生與死亡日期應該在名字後面,並且在同一列。

+ +

Controller 控制器

+ +

作者列表控制器函數,需要獲取所有作者實例的列表,然後將這些實例傳遞給模板進行渲染。

+ +

打開 /controllers/authorController.js。在文件頂部附近,找到導出的 author_list() 控制器方法,並將其替換為以下代碼(更改後的代碼以粗體顯示)。

+ +
// Display list of all Authors.
+exports.author_list = function(req, res, next) {
+
+  Author.find()
+    .sort([['family_name', 'ascending']])
+    .exec(function (err, list_authors) {
+      if (err) { return next(err); }
+      //Successful, so render
+      res.render('author_list', { title: 'Author List', author_list: list_authors });
+    });
+
+};
+ +

The method uses the model's find(), sort() and exec() functions to return all Author objects sorted by family_name in alphabetic order. The callback passed to the exec() method is called with any errors (or null) as the first parameter, or a list of all authors on success. If there is an error it calls the next middleware function with the error value, and if not it renders the author_list(.pug) template, passing the page title and the list of authors (author_list).

+ +

View

+ +

Create /views/author_list.pug and replace its content with the text below.

+ +
extends layout
+
+block content
+  h1= title
+
+  ul
+    each author in author_list
+      li
+        a(href=author.url) #{author.name}
+        |  (#{author.date_of_birth} - #{author.date_of_death})
+
+    else
+      li There are no authors.
+ +

The view follows exactly the same pattern as our other templates.

+ +

What does it look like?

+ +

Run the application and open your browser to http://localhost:3000/. Then select the All authors link. If everything is set up correctly, the page should look something like the following screenshot.

+ +

Author List Page - Express Local Library site

+ +
+

Note: The appearance of the author lifespan dates is ugly! You can improve this using the same approach as we used for the BookInstance list (adding the virtual property for the lifespan to the Author model). This time, however, there are missing dates, and references to nonexistent properties are ignored unless strict mode is in effect. moment() returns the current time, and you don't want missing dates to be formatted as if they were today. One way to deal with this is to define the body of the function that returns a formatted date so it returns a blank string unless the date actually exists. For example:

+ +

return this.date_of_birth ? moment(this.date_of_birth).format('YYYY-MM-DD') : '';

+
+ +

Genre list page—challenge!Edit

+ +

In this section you should implement your own genre list page. The page should display a list of all genres in the database, with each genre linked to its associated detail page. A screenshot of the expected result is shown below.

+ +

Genre List - Express Local Library site

+ +

The genre list controller function needs to get a list of all Genre instances, and then pass these to the template for rendering.

+ +
    +
  1. You will need to edit genre_list() in /controllers/genreController.js
  2. +
  3. The implementation is almost exactly the same as the author_list() controller. +
      +
    • Sort the results by name, in ascending order.
    • +
    +
  4. +
  5. The template to be rendered should be named genre_list.pug.
  6. +
  7. The template to be rendered should be passed the variables title ('Genre List') and genre_list (the list of genres returned from your Genre.find() callback.
  8. +
  9. The view should match the screenshot/requirements above (this should have a very similar structure/format to the Author list view, except for the fact that genres do not have dates).
  10. +
+ +

Next steps

+ +

Return to Express Tutorial Part 5: Displaying library data.

+ +

Proceed to the next subarticle of part 5: Genre detail page.

diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_detail_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_detail_page/index.html new file mode 100644 index 0000000000..31f3d65284 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_detail_page/index.html @@ -0,0 +1,112 @@ +--- +title: 書本詳情頁面 +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page +--- +

書本細節頁面需要呈現一本指定書本(Book)的信息, 使用它的 _id 字段值(自動產生)做為識別,接著是圖書館中書本實例(BookInstance)的信息。無論我們在哪裡呈現一個作者、種類、或書本實例,都應該連結到它的細節頁面。

+ +

Controller 控制器

+ +

打開 /controllers/bookController.js. ,找到 exported book_detail() 控制器方法,用底下的代碼置換。

+ +
// Display detail page for a specific book.
+exports.book_detail = function(req, res, next) {
+
+    async.parallel({
+        book: function(callback) {
+
+            Book.findById(req.params.id)
+              .populate('author')
+              .populate('genre')
+              .exec(callback);
+        },
+        book_instance: function(callback) {
+
+          BookInstance.find({ 'book': req.params.id })
+          .exec(callback);
+        },
+    }, function(err, results) {
+        if (err) { return next(err); }
+        if (results.book==null) { // No results.
+            var err = new Error('Book not found');
+            err.status = 404;
+            return next(err);
+        }
+        // Successful, so render.
+        res.render('book_detail', { title: 'Title', book:  results.book, book_instances: results.book_instance } );
+    });
+
+};
+
+
+ +
+

注意:  我們不需要用 require 導入 asyncBookInstance,當我們實作主頁面控制器的時候,我們就已經引入這些模組。

+
+ +

此處的控制器方法使用 async.parallel(),用平行的方式找到 Book 以及它的相應複本 (BookInstances) 。這樣的處理方式,就跟上面的 種類細節頁面 所說明的完全相同。

+ +

View 視圖

+ +

創建 /views/book_detail.pug 並加入底下文字。

+ +
extends layout
+
+block content
+  h1 #{title}: #{book.title}
+
+  p #[strong Author:]
+    a(href=book.author.url) #{book.author.name}
+  p #[strong Summary:] #{book.summary}
+  p #[strong ISBN:] #{book.isbn}
+  p #[strong Genre:]&nbsp;
+    each val, index in book.genre
+      a(href=val.url) #{val.name}
+      if index < book.genre.length - 1
+        |,
+
+  div(style='margin-left:20px;margin-top:20px')
+    h4 Copies
+
+    each val in book_instances
+      hr
+      if val.status=='Available'
+        p.text-success #{val.status}
+      else if val.status=='Maintenance'
+        p.text-danger #{val.status}
+      else
+        p.text-warning #{val.status}
+      p #[strong Imprint:] #{val.imprint}
+      if val.status!='Available'
+        p #[strong Due back:] #{val.due_back}
+      p #[strong Id:]&nbsp;
+        a(href=val.url) #{val._id}
+
+    else
+      p There are no copies of this book in the library.
+
+ +

在這個模板裡,幾乎每個東西都在先前的章節演示過了。

+ +
+

注意:  與該書相關的種類列表,在模板中的實作,如以下代碼。除了最後一本書之外,在與本書相關的每個種類之後,都會添加一個逗號。

+ +
  p #[strong Genre:]
+    each val, index in book.genre
+      a(href=val.url) #{val.name}
+      if index < book.genre.length - 1
+        |, 
+
+ +

它看起來像是?

+ +

運行本應用,並打開瀏覽器訪問 http://localhost:3000/。選擇 All books 連結,然後選擇其中一本書。如果每個東西都設定正確了,你的頁面看起來應該像是底下的截圖。

+ +

Book Detail Page - Express Local Library site

+ +

下一步

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html new file mode 100644 index 0000000000..a35b31767d --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html @@ -0,0 +1,72 @@ +--- +title: 書本清單頁面 +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page +--- +

接下做我們將實作書本列表頁面。這個頁面需要呈現數據庫中所有書本的列表,包含每本書的作者、標題,標題將成為一個超連結,連到書本詳細內容頁面。

+ +

控制器

+ +

書本列表控制器函數,需要獲取數據庫中所有 Book對象的列表,然後將這些對像傳給模板進行呈現。

+ +

打開 /controllers/bookController.js. 找到導出的 book_list()控制器方法,並替換為下面的代碼。

+ +
// Display list of all Books.
+exports.book_list = function(req, res, next) {
+
+  Book.find({}, 'title author')
+    .populate('author')
+    .exec(function (err, list_books) {
+      if (err) { return next(err); }
+      //Successful, so render
+      res.render('book_list', { title: 'Book List', book_list: list_books });
+    });
+
+};
+ +

該方法使用模型的find()函數,返回所有 Book 對象,選擇僅返回標題 title 和作者 author,因為我們不需要其他字段(它也會返回 _id 和虛擬欄位字段)。這裡我們還調用 Book 上的 populate(),指定作者 author欄位字段 — 這將用完整的作者信息,替換儲存的書本作者 id。

+ +

成功時,傳遞給查詢的回調,將呈現 book_list(.pug) 模板,將標題 title book_list(包含作者的書本列表)作為變量傳遞。

+ +

View視圖

+ +

創建 /views/book_list.pug 並複制底下的文字。

+ +
extends layout
+
+block content
+  h1= title
+
+  ul
+    each book in book_list
+      li
+        a(href=book.url) #{book.title}
+        |  (#{book.author.name})
+
+    else
+      li There are no books.
+ +

這個視圖擴展了 layout.pug 基本模板,並覆蓋了名為 'content' 的 block 區塊 。它顯示我們從控制器傳入的標題 title(通過 render()方法),然後使用 each-in-else 語法,遍歷 book_list變量。為每本圖書創建一個列表項,以顯示書名,並作為書的詳細信息頁面的鏈接,後面跟著作者姓名。如果 book_list中沒有書,則執行 else 子句,並顯示文字 “沒有書本” 'There are no books'。

+ +

 

+ +
+

注意:   我們使用 book.url,為每本書提供詳細記錄鏈接(我們已經實現了此路由,但尚未實現此頁面)。這是 Book 模型的一個虛擬屬性,它使用模型實例的 _id 字段,生成唯一的 URL 路徑。

+
+ +

在這裡,我們感興趣的是,每本書被定義為兩行,第二行使用管道(上面高亮顯示)。這種方法是必要的,因為如果作者姓名位於上一行,那麼它將成為超鏈接的一部分。

+ +

它看起來像是?

+ +

運行本應用 (參見 測試路由 有相關的命令) ,並打開你的瀏覽器,訪問 http://localhost:3000/。然後選擇所有書本連結 All books。如果每樣東西都設定正確了,你的網站看起來應該像底下的截圖。

+ +

 

+ +

Book List Page - Express Local Library site

+ +

下一步

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_detail_page_and_challenge/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_detail_page_and_challenge/index.html new file mode 100644 index 0000000000..e04981411c --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_detail_page_and_challenge/index.html @@ -0,0 +1,91 @@ +--- +title: 書本實例詳情頁面與自我挑戰 +slug: >- + Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_detail_page_and_challenge +translation_of: >- + Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_detail_page_and_challenge +--- +

書本實例詳情頁面

+ +

BookInstance 詳情頁面,需要呈現每一個 BookInstance 的信息,用 _id 欄位字段值(自動產生)做識別。它包含了 Book 名稱 (也是一個連結,連到 書本細節頁面),接著是紀錄中的其它的信息。

+ +

Controller 控制器

+ +

打開 /controllers/bookinstanceController.js. 找到 exported bookinstance_detail() 控制器方法,並用底下代碼置換。

+ +
// Display detail page for a specific BookInstance.
+exports.bookinstance_detail = function(req, res, next) {
+
+    BookInstance.findById(req.params.id)
+    .populate('book')
+    .exec(function (err, bookinstance) {
+      if (err) { return next(err); }
+      if (bookinstance==null) { // No results.
+          var err = new Error('Book copy not found');
+          err.status = 404;
+          return next(err);
+        }
+      // Successful, so render.
+      res.render('bookinstance_detail', { title: 'Book:', bookinstance:  bookinstance});
+    })
+
+};
+
+ +

該方法使用從 URL(使用路由)中提取的特定書本實例的ID,調用BookInstance.findById(),並通過請求參數(req.params.id),在控制器中訪問。然後調用populate()來獲取相關 Book 的詳細信息。

+ +

View 視圖

+ +

創建 /views/bookinstance_detail.pug ,並複製下面的內容。

+ +
extends layout
+
+block content
+
+  h1 ID: #{bookinstance._id}
+
+  p #[strong Title:]
+    a(href=bookinstance.book.url) #{bookinstance.book.title}
+  p #[strong Imprint:] #{bookinstance.imprint}
+
+  p #[strong Status:]
+    if bookinstance.status=='Available'
+      span.text-success #{bookinstance.status}
+    else if bookinstance.status=='Maintenance'
+      span.text-danger #{bookinstance.status}
+    else
+      span.text-warning #{bookinstance.status}
+
+  if bookinstance.status!='Available'
+    p #[strong Due back:] #{bookinstance.due_back}
+
+ +

本模組中的所有東西,都在先前的章節演示過了。

+ +

它看起來像是?

+ +

運行本應用,並打開瀏覽器訪問 http://localhost:3000//。選擇 All book-instances 連結,然後選擇其中一本。如果每個東西都設定正確了,你的網站看起來應該像是底下的截圖。

+ +

BookInstance Detail Page - Express Local Library site

+ +

自我挑戰

+ +

目前,我們網站上顯示的大多數日期,都使用默認的 JavaScript 格式(例如 Tue Dec 06 2016 15:49:58 GMT+1100 (AUS東部夏令時間))。本文的挑戰,是改善作者Author生命週期日期顯示的外觀信息(死亡/誔生日期)和BookInstance詳細信息頁面,使用格式:December 6th, 2016。

+ +
+

注意:  您可以使用與我們用於 Book Instance List 的相同方法(將生命週期的虛擬屬性,添加到Author模型,並使用 moment 來設置日期字符串的格式)。

+
+ +

這個挑戰的要求:  

+ +
    +
  1. 用 BookInstance 詳細信息頁面中的 due_back_formatted 替換 due_back
  2. +
  3. 更新作者模塊以添加壽命虛擬屬性。壽命應該有兩個值: date_of_birth - date_of_death,這兩個值的格式與 BookInstance.due_back_formatted的日期格式相同。
  4. +
  5. 在當前使用 date_of_birthdate_of_death的所有視圖中,使用 Author.lifespan
  6. +
+ +

下一步

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html new file mode 100644 index 0000000000..1b1656258e --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html @@ -0,0 +1,71 @@ +--- +title: 書本實例清單頁面 +slug: Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page +--- +

接下來,我們將實作圖書館中所有書本實例 (BookInstance) 的列表頁面。這個頁面需要包含與每個 BookInstance (鏈接到其詳細信息頁面) 關聯的書本 Book 標題,以及 BookInstance模型中的其他信息,包含每個副本的狀態,印記和唯一ID。唯一ID的文字,應該鏈接到 BookInstance 詳細信息頁面。

+ +

Controller 控制器

+ +

BookInstance列表控制器函數,需要獲取所有書本實例的列表,填充關聯的書本信息,然後將列表傳遞給模板以進行呈現。

+ +

打開 /controllers/bookinstanceController.js。找到導出的 bookinstance_list()控制器方法,並用以下代碼替換它(更改後的代碼以粗體顯示)。

+ +
// Display list of all BookInstances.
+exports.bookinstance_list = function(req, res, next) {
+
+  BookInstance.find()
+    .populate('book')
+    .exec(function (err, list_bookinstances) {
+      if (err) { return next(err); }
+      // Successful, so render
+      res.render('bookinstance_list', { title: 'Book Instance List', bookinstance_list: list_bookinstances });
+    });
+
+};
+ +

此方法使用模型的find()函數,返回所有 BookInstance對象。然後它將一個調用,以菊花鏈方式連接到 populate(),附加書本 book欄位字段,這將使用完整的 Book文檔,替換每個 BookInstance儲存的書本 ID。

+ +

成功時,傳遞給查詢的回調,會呈現 bookinstance_list (.pug)模板,並將標題title和書籍實例列表 bookinstance_list作為變量傳遞。

+ +

View 視圖

+ +

創建 /views/bookinstance_list.pug ,並複制貼上底下的文字。

+ +
extends layout
+
+block content
+  h1= title
+
+  ul
+    each val in bookinstance_list
+      li
+        a(href=val.url) #{val.book.title} : #{val.imprint} -
+        if val.status=='Available'
+          span.text-success #{val.status}
+        else if val.status=='Maintenance'
+          span.text-danger #{val.status}
+        else
+          span.text-warning #{val.status}
+        if val.status!='Available'
+          span  (Due: #{val.due_back} )
+
+    else
+      li There are no book copies in this library.
+ +

這個視圖與其他視圖非常相似。它擴展了佈局,替換內容區塊,顯示從控制器傳入的標題 title,並遍歷 bookinstance_list 中的所有書籍副本。對於每個副本,我們都會顯示它的狀態(用顏色編碼),如果書本不可用,則顯示其預期返回日期。這裡引入了一個新功能 — 我們可以在標籤之後使用點符號表示法,來指定一個類別。因此,span.text-success 將被編譯為 <span class="text-success"> (也可以用 Pug 編寫為 span(class="text-success")。

+ +

 

+ +

它看起來像是?

+ +

運行本應用,打開瀏覽器訪問 http://localhost:3000/,然後選擇 All book-instances 連結。假如每個東西都設定正確了,你的網站看起來應該像是底下的截圖。

+ +

BookInstance List Page - Express Local Library site

+ +

下一步

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html new file mode 100644 index 0000000000..ecd3ee7f0d --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html @@ -0,0 +1,60 @@ +--- +title: 使用 moment 做日期格式化 +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment +--- +

我們模型的日期預設呈現很難看: Tue Dec 06 2016 15:49:58 GMT+1100 (AUS Eastern Daylight Time)。在本節中,我們將展示如何更新上一節中的 書本實例 BookInstance 列表頁面,以更友好的格式顯示due_date欄位字段:December 6th, 2016。

+ +

我們將使用的方法,是在我們的BookInstance模型中,創建一個返回格式化日期的虛擬屬性。我們將使用 moment 來做實際的格式化,這是一個輕量級 JavaScript日期庫,用於解析,驗證,操作和格式化日期。

+ +
+

注意:  我們可以直接在 Pug 模板中,使用 moment 格式化字符串,或者可以在許多其它地方格式化字符串。使用虛擬屬性,可以使我們獲得格式化的日期,這與我們當前獲取 due_date 的方式完全相同。

+
+ +

安裝 moment

+ +

在項目的根目錄,輸入下列命令

+ +

 

+ +
npm install moment
+ +

創建虛擬屬性

+ +
    +
  1. 打開 ./models/bookinstance.js.
  2. +
  3. 在此頁面最上方,引入 moment. +
    var moment = require('moment');
    +
  4. +
+ +

在 url 屬性後面,加入虛擬屬性 due_back_formatted

+ +
BookInstanceSchema
+.virtual('due_back_formatted')
+.get(function () {
+  return moment(this.due_back).format('MMMM Do, YYYY');
+});
+ +
+

注意:  格式化方法可以使用幾乎任何模式顯示日期。 moment文檔中,可以找到表示不同日期組件的語法。

+
+ +

更新視圖

+ +

打開 /views/bookinstance_list.pug ,然後用 due_back_formatted 取代 due_back

+ +
      if val.status!='Available'
+        //span  (Due: #{val.due_back} )
+        span  (Due: #{val.due_back_formatted} )       
+ +

這就是本章節的全部了。如果你訪問側邊欄的 All book-instances ,你應該會看到所有的歸還日期都更吸引人了!

+ +

下一步

+ + + +

 

diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html new file mode 100644 index 0000000000..5271bd6722 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html @@ -0,0 +1,137 @@ +--- +title: 使用 async 進行非同步流控制 +slug: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async +--- +

有些本地圖書館網頁的控制器代碼,會依賴多重非同步要求的結果,可能會需要以某種特定次序運行,或者以平行方式運行。為了管理流控制,並在我們所有需要用到的信息,都已經可以取用的時候,再繪製網頁,我們將使用許多人採用的 node async 模組。

+ +
+

注意:  在 JavaScript 中有許多其他方法,可以管理異步行為和流控制,包括相對較新的 JavaScript 語言功能,如 Promises

+
+ +

Async 有很多有用的方法(請查看文檔)。一些最重要的功能是:

+ +

 

+ + + +

為什麼需要這麼做?

+ +

我們在 Express 中使用的大多數方法,都是異步的 - 您指定要執行的操作,傳遞回調。該方法立即返回,並在請求的操作完成時,調用回調。按照 Express 中的慣例,回調函數將錯誤值作為第一個參數傳遞(或成功時為 null),並將函數的結果(如果有的話)作為第二個參數傳遞。

+ +

如果控制器只需要執行一個異步操作,來獲取呈現頁面所需的信息,那麼實現很簡單 - 我們只需在回調中呈現模板。下面的代碼片段,顯示了一個函數,該函數呈現模型 SomeModel 的計數(使用Mongoose count()方法):

+ +
exports.some_model_count = function(req, res, next) {
+
+  SomeModel.count({ a_model_field: 'match_value' }, function (err, count) {
+    // ... do something if there is an err
+
+    // On success, render the result by passing count into the render function (here, as the variable 'data').
+    res.render('the_template', { data: count } );
+  });
+}
+
+ +

但是,如果您需要進行多個異步查詢,並且在完成所有操作之前,無法呈現頁面,該怎麼辦?一個單純的實現可以用 “菊花鏈” 連接請求,在先前請求的回調中,啟動後續請求,並在最終回調中呈現響應。這種方法的問題,是我們的請求必須串行運行,即使並行運行它們可能更有效。這也可能導致複雜的嵌套代碼,通常稱為回調地獄

+ +

一個更好的解決方案,是並行執行所有請求,然後在所有查詢完成後執行單個回調。這是 Async 模塊簡化的流操作!

+ +

Asynchronous operations in parallel

+ +

The method async.parallel() is used to run multiple asynchronous operations in parallel.

+ +

The first argument to async.parallel() is a collection of the asynchronous functions to run (an array, object or other iterable). Each function is passed a callback(err, result) which it must call on completion with an error err (which can be null) and an optional results value.

+ +

The optional second argument to  async.parallel() is a callback that will be run when all the functions in the first argument have completed. The callback is invoked with an error argument and a result collection that contains the results of the individual asynchronous operations. The result collection is of the same type as the first argument (i.e. if you pass an array of asynchronous functions, the final callback will be invoked with an array of results). If any of the parallel functions reports an error the callback is invoked early (with the error value).

+ +

The example below shows how this works when we pass an object as the first argument. As you can see, the results are returned in an object with the same property names as the original functions that were passed in.

+ +
async.parallel({
+  one: function(callback) { ... },
+  two: function(callback) { ... },
+  ...
+  something_else: function(callback) { ... }
+  },
+  // optional callback
+  function(err, results) {
+    // 'results' is now equal to: {one: 1, two: 2, ..., something_else: some_value}
+  }
+);
+ +

If you instead pass an array of functions as the first argument, the results will be an array (the array order results will match the original order that the functions were declared—not the order in which they completed).

+ +

Asynchronous operations in series

+ +

The method async.series() is used to run multiple asynchronous operations in sequence, when subsequent functions do not depend on the output of earlier functions. It is essentially declared and behaves in the same way as async.parallel().

+ +
async.series({
+  one: function(callback) { ... },
+  two: function(callback) { ... },
+  ...
+  something_else: function(callback) { ... }
+  },
+  // optional callback after the last asynchronous function completes.
+  function(err, results) {
+    // 'results' is now equals to: {one: 1, two: 2, ..., something_else: some_value} 
+  }
+);
+ +
+

Note: The ECMAScript (JavaScript) language specification states that the order of enumeration of an object is undefined, so it is possible that the functions will not be called in the same order as you specify them on all platforms. If the order really is important, then you should pass an array instead of an object, as shown below.

+
+ +
async.series([
+  function(callback) {
+    // do some stuff ...
+    callback(null, 'one');
+  },
+  function(callback) {
+    // do some more stuff ... 
+    callback(null, 'two');
+  }
+ ],
+  // optional callback
+  function(err, results) {
+  // results is now equal to ['one', 'two'] 
+  }
+);
+ +

Dependent asynchronous operations in series

+ +

The method async.waterfall() is used to run multiple asynchronous operations in sequence when each operation is dependent on the result of the previous operation.

+ +

The callback invoked by each asynchronous function contains null for the first argument and results in subsequent arguments. Each function in the series takes the results arguments of the previous callback as the first parameters, and then a callback function. When all operations are complete, a final callback is invoked with the result of the last operation. The way this works is more clear when you consider the code fragment below (this example is from the async documentation):

+ +
async.waterfall([
+  function(callback) {
+    callback(null, 'one', 'two');
+  },
+  function(arg1, arg2, callback) {
+    // arg1 now equals 'one' and arg2 now equals 'two' 
+    callback(null, 'three');
+  },
+  function(arg1, callback) {
+    // arg1 now equals 'three'
+    callback(null, 'done');
+  }
+], function (err, result) {
+  // result now equals 'done'
+}
+);
+ +

Installing async

+ +

Install the async module using the NPM package manager so that we can use it in our code. You do this in the usual way, by opening a prompt in the root of the LocalLibrary project and enter the following command:

+ +
npm install async
+ +

Next steps

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html new file mode 100644 index 0000000000..2c7f1e938b --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html @@ -0,0 +1,123 @@ +--- +title: Genre detail page +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page +--- +

種類細節頁面,需要利用_id 字段值 (自動生成) ,以呈現特定種類實例的信息。此頁面應該呈現種類名稱,各個種類的所有書本列表(每本書都連結到書本的細節頁面)。

+ +

 

+ +

Controller 控制器

+ +

打開 /controllers/genreController.js ,並在檔案最上方引用 asyncBook 模組。

+ +
var Book = require('../models/book');
+var async = require('async');
+
+ +

Find the exported genre_detail() controller method and replace it with the following code.

+ +
// Display detail page for a specific Genre.
+exports.genre_detail = function(req, res, next) {
+
+    async.parallel({
+        genre: function(callback) {
+            Genre.findById(req.params.id)
+              .exec(callback);
+        },
+
+        genre_books: function(callback) {
+          Book.find({ 'genre': req.params.id })
+          .exec(callback);
+        },
+
+    }, function(err, results) {
+        if (err) { return next(err); }
+        if (results.genre==null) { // No results.
+            var err = new Error('Genre not found');
+            err.status = 404;
+            return next(err);
+        }
+        // Successful, so render
+        res.render('genre_detail', { title: 'Genre Detail', genre: results.genre, genre_books: results.genre_books } );
+    });
+
+};
+
+ +

The method uses async.parallel() to query the genre name and its associated books in parallel, with the callback rendering the page when (if) both requests complete successfully.

+ +

The ID of the required genre record is encoded at the end of the URL and extracted automatically based on the route definition (/genre/:id). The ID is accessed within the controller via the request parameters: req.params.id. It is used in Genre.findById() to get the current genre. It is also used to get all Book objects that have the genre ID in their genre field: Book.find({ 'genre': req.params.id }).

+ +
+

Note: If the genre does not exist in the database (i.e. it may have been deleted) then findById()  will return successfully with no results. In this case we want to display a "not found" page, so we create an Error object and pass it to the next middleware function in the chain. 

+ +
if (results.genre==null) { // No results.
+    var err = new Error('Genre not found');
+    err.status = 404;
+    return next(err);
+}
+
+ +

The message will then propagate through to our error handling code (this was set up when we generated the app skeleton - for more information see Handling Errors).

+
+ +

The rendered view is genre_detail and it is passed variables for the title, genre and the list of books in this genre (genre_books).

+ +

View

+ +

Create /views/genre_detail.pug and fill it with the text below:

+ +
extends layout
+
+block content
+
+  h1 Genre: #{genre.name}
+
+  div(style='margin-left:20px;margin-top:20px')
+
+    h4 Books
+
+    dl
+    each book in genre_books
+      dt
+        a(href=book.url) #{book.title}
+      dd #{book.summary}
+
+    else
+      p This genre has no books
+
+ +

The view is very similar to all our other templates. The main difference is that we don't use the title passed in for the first heading (though it is used in the underlying layout.pug template to set the page title).

+ +

What does it look like?

+ +

Run the application and open your browser to http://localhost:3000/. Select the All genres link, then select one of the genres (e.g. "Fantasy"). If everything is set up correctly, your page should look something like the following screenshot.

+ +

Genre Detail Page - Express Local Library site

+ +
+

You might get an error similar to this:

+ +
Cast to ObjectId failed for value " 59347139895ea23f9430ecbb" at path "_id" for model "Genre"
+
+ +

This is a mongoose error coming from the req.params.id. To solve this problem, first you need to require mongoose on the genreController.js page like this:

+ +
 var mongoose = require('mongoose');
+
+ +

Then use mongoose.Types.ObjectId() to convert the id to a that can be used. For example:

+ +
exports.genre_detail = function(req, res, next) {
+    var id = mongoose.Types.ObjectId(req.params.id);
+    ...
+
+
+ +

Next steps

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/home_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/home_page/index.html new file mode 100644 index 0000000000..8adc4b11f9 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/home_page/index.html @@ -0,0 +1,133 @@ +--- +title: 主頁 +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Home_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Home_page +--- +

我們創建的第一個頁面,是網站的主頁面,可以從網站的根目錄 ('/') ,或者 catalog 的根目錄 (catalog/) 訪問。這將呈現一些網站的靜態文字描述,以及動態計算數據庫中不同記錄類型的“計數”。

+ +

我們已經為主頁創建了一個路由。為了完成頁面,我們需要更新控制器函數,以從數據庫中提取記錄的“計數”,並創建一個可用於呈現頁面的視圖(模板)。

+ +

路由

+ +

前面的教程,我們創建 index 頁面路由。此處要提醒的是,所有的路由函式,都定義在 /routes/catalog.js:

+ +
// GET catalog home page.
+router.get('/', book_controller.index);  //This actually maps to /catalog/ because we import the route with a /catalog prefix
+ +

Where the callback function parameter (book_controller.index) is defined in /controllers/bookController.js:

+ +
exports.index = function(req, res, next) {
+    res.send('NOT IMPLEMENTED: Site Home Page');
+}
+ +

It is this controller function that we extend to get information from our models and then render it using a template (view).

+ +

Controller

+ +

The index controller function needs to fetch information about how many Book, BookInstance, available BookInstance, Author, and Genre records we have in the database, render this data in a template to create an HTML page, and then return it in an HTTP response.

+ +
+

Note: We use the countDocuments() method to get the number of instances of each model. This is called on a model with an optional set of conditions to match against in the first argument and a callback in the second argument (as discussed in Using a Database (with Mongoose), and you can also return a Query and then execute it with a callback later. The callback will be returned when the database returns the count, with an error value (or null) as the first parameter and the count of records (or null if there was an error) as the second parameter.

+ +
SomeModel.countDocuments({ a_model_field: 'match_value' }, function (err, count) {
+ // ... do something if there is an err
+ // ... do something with the count if there was no error
+ });
+
+ +

Open /controllers/bookController.js. Near the top of the file you should see the exported index() function.

+ +
var Book = require('../models/book')
+
+exports.index = function(req, res, next) {
+ res.send('NOT IMPLEMENTED: Site Home Page');
+}
+ +

Replace all the code above with the following code fragment. The first thing this does is import (require()) all the models (highlighted in bold). We need to do this because we'll be using them to get our counts of records. It then imports the async module.

+ +
var Book = require('../models/book');
+var Author = require('../models/author');
+var Genre = require('../models/genre');
+var BookInstance = require('../models/bookinstance');
+
+var async = require('async');
+
+exports.index = function(req, res) {
+
+    async.parallel({
+        book_count: function(callback) {
+            Book.countDocuments({}, callback); // Pass an empty object as match condition to find all documents of this collection
+        },
+        book_instance_count: function(callback) {
+            BookInstance.countDocuments({}, callback);
+        },
+        book_instance_available_count: function(callback) {
+            BookInstance.countDocuments({status:'Available'}, callback);
+        },
+        author_count: function(callback) {
+            Author.countDocuments({}, callback);
+        },
+        genre_count: function(callback) {
+            Genre.countDocuments({}, callback);
+        },
+    }, function(err, results) {
+        res.render('index', { title: 'Local Library Home', error: err, data: results });
+    });
+};
+ +

The async.parallel() method is passed an object with functions for getting the counts for each of our models. These functions are all started at the same time. When all of them have completed the final callback is invoked with the counts in the results parameter (or an error).

+ +

On success the callback function calls res.render(), specifying a view (template) named 'index' and an object containing the data that is to be inserted into it (this includes the results object that contains our model counts). The data is supplied as key-value pairs, and can be accessed in the template using the key.

+ +
+

Note: The callback function from async.parallel() above is a little unusual in that we render the page whether or not there was an error (normally you might use a separate execution path for handling the display of errors).

+
+ +

View

+ +

Open /views/index.pug and replace its content with the text below.

+ +
extends layout
+
+block content
+  h1= title
+  p Welcome to #[em LocalLibrary], a very basic Express website developed as a tutorial example on the Mozilla Developer Network.
+
+  h1 Dynamic content
+
+  if error
+    p Error getting dynamic content.
+  else
+    p The library has the following record counts:
+
+    ul
+      li #[strong Books:] !{data.book_count}
+      li #[strong Copies:] !{data.book_instance_count}
+      li #[strong Copies available:] !{data.book_instance_available_count}
+      li #[strong Authors:] !{data.author_count}
+      li #[strong Genres:] !{data.genre_count}
+ +

The view is straightforward. We extend the layout.pug base template, overriding the block named 'content'. The first h1 heading will be the escaped text for the title variable that was passed into the render() function—note the use of the 'h1=' so that the following text is treated as a JavaScript expression. We then include a paragraph introducing the LocalLibrary.

+ +

Under the Dynamic content heading we check whether the error variable passed in from the render() function has been defined. If so, we note the error. If not, we get and list the number of copies of each model from the data variable.

+ +
+

Note: We didn't escape the count values (i.e. we used the !{} syntax) because the count values are calculated. If the information was supplied by end-users then we'd escape the variable for display.

+
+ +

What does it look like?

+ +

At this point we should have created everything needed to display the index page. Run the application and open your browser to http://localhost:3000/. If everything is set up correctly, your site should look something like the following screenshot.

+ +

Home page - Express Local Library site

+ +
+

Note: You won't be able to use the sidebar links yet because the urls, views, and templates for those pages haven't been defined. If you try you'll get errors like "NOT IMPLEMENTED: Book list" for example, depending on the link you click on.  These string literals (which will be replaced with proper data) were specified in the different controllers that live inside your "controllers" file.

+
+ +

Next steps

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/index.html new file mode 100644 index 0000000000..2073a02bc8 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/index.html @@ -0,0 +1,87 @@ +--- +title: 'Express 教程 5: 呈現圖書館數據' +slug: Learn/Server-side/Express_Nodejs/Displaying_data +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}
+ +

我們現在準備好要新增網頁,以顯示本地圖書館網站的書本與其它資料。這些網頁將包括一個主頁 ,顯示我們每個模型的型態有多少筆紀錄,以及我們所有模型的清單與細節頁面。藉此,我們將得到從數據庫取得紀錄、以及使用樣版的實務經驗。

+ + + + + + + + + + + + +
前置條件:完成先前教程主題 (包含 Express 教程 4: 路由與控制器)。
目標:了解如何使用非同步模組與 Pug 樣版語言,以及如何從我們的控制器函式中的 URL 得取資料。
+ +

概覽

+ +

在我們先前的教程中,定義了可以用來跟資料庫互動的 Mongoose models ,並創建了一些初始的圖書館紀錄。我們接著創建本地圖書館網站需要的所有路由,但僅使用"空殼控制器" 函式(這些是骨架控制器函式,當一個網頁被存取時,只回傳一個"未實作" 信息)。

+ +

下一步,是為這些顯示圖書館信息的網頁,提供充分的實作(我們將在後面的文章,檢視網頁表單的實作,像是創建、更新、刪除信息)。這包含了更新控制器函式,以利用我們的模型取得紀錄,並定義模板,為使用者顯示這些信息。

+ +

我們在一開始,提供概略的總覽/重點主題,解釋在控制器函式中,如何管理非同步操作,以及如何使用 Pug 撰寫模板。然後我們將為每一個主要的 "唯讀" 網頁提供實作步驟,並且在使用到任何特別的、或新的特性時,會附上簡短的解釋說明。

+ +

本教程的最後,你對路由、非同步函式、視圖、模型如何實際運作,應該有了更好的理解。

+ +

本教程的章節

+ +

本教程分為下列章節,說明為了顯示圖書館網站頁面,如何新增各種特性 。在進入下一個教程之前,你需要閱讀並逐一實作下列章節。

+ +
    +
  1. 使用 async 控制非同步流
  2. +
  3. 模板入門
  4. +
  5. 本地圖書館基礎模板
  6. +
  7. 主頁
  8. +
  9. 書本清單頁面
  10. +
  11. 書本實例清單頁面
  12. +
  13. 日期格式化 - 使用 moment
  14. +
  15. 作者清單頁面、分類清單頁面、與自我挑戰
  16. +
  17. 分類詳情頁面
  18. +
  19. 書本詳情頁面
  20. +
  21. 作者詳情頁面
  22. +
  23. 書本實例詳情頁面與自我挑戰
  24. +
+ +

總結

+ +

我們現在已經為我們的網站,創建了所有 "唯讀" 的頁面: 一個主頁,可以顯示每一個模組的實例數量,書本的列表與詳細信息頁面,書本的實例、作者、分類。沿著目前的學習路徑,我們學到了許多基本知識,有控制器、在非同步作業時管理流控制、使用 Pug 創建視圖、使用模型查詢數據庫、如何從視圖傳送信息到模板、如何創建並擴展模板。而完成挑戰的人,還會學到如何用 moment 處理日期。

+ +

在下一篇文章,我們將依據目前為止學到的知識,創建HTML 表單以及表單管理代碼,開始修改儲存在網站中的資料。

+ +

參閱

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}

+ +

 

+ +

本教學連結

+ + + +

 

diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html new file mode 100644 index 0000000000..c67e82f07e --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html @@ -0,0 +1,71 @@ +--- +title: 本地圖書館基礎模板 +slug: Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template +--- +

 

+ +

現在我們了解如何使用 Pug 拓展模板,讓我們開始項目,創建一個基礎模板。這個模板會有一個側邊欄,連結到本教程中將要創建的各個頁面(例如,呈現並創建書本、種類、作者等等),以及一個主要內容區域,我們將在每個頁面中進行覆寫。

+ +

開啟 /views/layout.pug ,並以下列代碼,置換其內容。

+ +
doctype html
+html(lang='en')
+  head
+    title= title
+    meta(charset='utf-8')
+    meta(name='viewport', content='width=device-width, initial-scale=1')
+    link(rel='stylesheet', href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css')
+    script(src='https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js')
+    script(src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js')
+    link(rel='stylesheet', href='/stylesheets/style.css')
+  body
+    div(class='container-fluid')
+      div(class='row')
+        div(class='col-sm-2')
+          block sidebar
+            ul(class='sidebar-nav')
+              li
+                a(href='/catalog') Home
+              li
+                a(href='/catalog/books') All books
+              li
+                a(href='/catalog/authors') All authors
+              li
+                a(href='/catalog/genres') All genres
+              li
+                a(href='/catalog/bookinstances') All book-instances
+              li
+                hr
+              li
+                a(href='/catalog/author/create') Create new author
+              li
+                a(href='/catalog/genre/create') Create new genre
+              li
+                a(href='/catalog/book/create') Create new book
+              li
+                a(href='/catalog/bookinstance/create') Create new book instance (copy)
+
+        div(class='col-sm-10')
+          block content
+ +

此模板使用(並包含)來自 Bootstrap 的 JavaScript 和 CSS ,以改進 HTML 頁面的佈局和呈現方式。使用 Bootstrap 或其它客戶端網頁框架,是一種快速的方式,可以創建吸引人的網頁,能夠良好地適應不同的瀏覽器尺寸,並且允許我們處理頁面的呈現,而不需要糾纒於任何不同尺寸的細節—此處我們只想專注於伺服端代碼!

+ +

佈局的安排應該相當明白,假如你已經閱讀了之前的 模板入門。注意,使用 block content 當做定位符號,放到頁面內容將要放置的地方。

+ +

基礎模板也參考了一個本地 css 檔 (style.css) ,此檔提供了一些額外的樣式。打開 /public/stylesheets/style.css ,並用底下的 CSS 代碼,取代它的內容:

+ +
.sidebar-nav {
+    margin-top: 20px;
+    padding: 0;
+    list-style: none;
+}
+ +

當我們開始運行網站時,我們應該看到側邊欄出現!在本教程的下個部分,我們將使用以上的佈局,來定義各個頁面。

+ +

下一步

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/template_primer/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/template_primer/index.html new file mode 100644 index 0000000000..af976b7155 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/template_primer/index.html @@ -0,0 +1,149 @@ +--- +title: 模板入門 +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer +--- +

模板是一個文字檔,定義了一個輸出檔的結構或者排版,使用定位符號表示,當模板被繪製時,資料將插入到何處(在Express,模板被稱為視圖)。

+ +

Express 模板選擇

+ +

Express 可以與許多不同的模板渲染引擎一起使用。在本教程中,我們使用 Pug(以前稱為 Jade)作為模板。這是最流行的 Node 模板語言,並且官方將自身描述為 “用於編寫 HTML,語法乾淨且空格敏感,受 Haml 影響很大”。

+ +

不同的模板語言使用不同的方法,來定義佈局和標記數據的佔位符 — 一些使用 HTML 來定義佈局,而另一些則使用可以編譯為 HTML 的不同標記格式。 Pug 是第二種類型;它使用 HTML 的表示形式,其中任何行中的第一個單詞,通常表示HTML元素,後續行中的縮進,用於表示嵌套在這些元素中的任何內容。結果是一個頁面定義直接轉換為 HTML,但可以說更簡潔,更容易閱讀。

+ +
+

Note: The downside of using Pug is that it is sensitive to indentation and whitespace (if you add an extra space in the wrong place you may get an unhelpful error code). However once you have your templates in place, they are very easy to read and maintain.

+
+ +

Template configuration

+ +

The LocalLibrary was configured to use Pug when we created the skeleton website. You should see the pug module included as a dependency in the website's package.json file, and the following configuration settings in the app.js file. The settings tell us that we're using pug as the view engine, and that Express should search for templates in the /views subdirectory.

+ +
// View engine setup.
+app.set('views', path.join(__dirname, 'views'));
+app.set('view engine', 'pug');
+ +

If you look in the views directory you will see the .pug files for the project's default views. These include the view for the home page (index.pug) and base template (layout.pug) that we will need to replace with our own content.

+ +
/express-locallibrary-tutorial  //the project root
+  /views
+    error.pug
+    index.pug
+    layout.pug
+
+ +

Template syntax

+ +

The example template file below shows off many of Pug's most useful features.

+ +

The first thing to notice is that the file maps the structure of a typical HTML file, with the first word in (almost) every line being an HTML element, and indentation being used to indicate nested elements. So for example, the body element is inside an html element, and paragraph elements (p) are within the body element, etc. Non-nested elements (e.g. individual paragraphs) are on separate lines.

+ +
doctype html
+html(lang="en")
+  head
+    title= title
+    script(type='text/javascript').
+  body
+    h1= title
+
+    p This is a line with #[em some emphasis] and #[strong strong text] markup.
+    p This line has un-escaped data: !{'<em> is emphasised</em>'} and escaped data: #{'<em> is not emphasised</em>'}.
+      | This line follows on.
+    p= 'Evaluated and <em>escaped expression</em>:' + title
+
+    <!-- You can add HTML comments directly -->
+    // You can add single line JavaScript comments and they are generated to HTML comments
+    //- Introducing a single line JavaScript comment with "//-" ensures the comment isn't rendered to HTML
+
+    p A line with a link
+      a(href='/catalog/authors') Some link text
+      |  and some extra text.
+
+    #container.col
+      if title
+        p A variable named "title" exists.
+      else
+        p A variable named "title" does not exist.
+      p.
+        Pug is a terse and simple template language with a
+        strong focus on performance and powerful features.
+
+    h2 Generate a list
+
+    ul
+      each val in [1, 2, 3, 4, 5]
+        li= val
+ +

Element attributes are defined in parentheses after their associated element. Inside the parentheses, the attributes are defined in comma- or whitespace- separated lists of the pairs of attribute names and attribute values, for example:

+ + + +

The values of all attributes are escaped (e.g. characters like ">" are converted to their HTML code equivalents like "&gt;") to prevent injection of JavaScript/cross-site scripting attacks.

+ +

If a tag is followed by the equals sign, the following text is treated as a JavaScript expression. So for example, in the first line below, the content of the h1 tag will be variable title (either defined in the file or passed into the template from Express). In the second line the paragraph content is a text string concatented with the title variable. In both cases the default behaviour is to escape the line.

+ +
h1= title
+p= 'Evaluated and <em>escaped expression</em>:' + title
+ +

If there is no equals symbol after the tag then the content is treated as plain text. Within the plain text you can insert escaped and unescaped data using the #{} and !{} syntax, as shown below. You can also add raw HTML within the plain text.

+ +
p This is a line with #[em some emphasis] and #[strong strong text] markup.
+p This line has an un-escaped string: !{'<em> is emphasised</em>'}, an escaped string: #{'<em> is not emphasised</em>'}, and escaped variables: #{title}.
+ +
+

Tip: You will almost always want to escape data from users (via the #{} syntax). Data that can be trusted (e.g. generated counts of records, etc.) may be displayed without escaping the values.

+
+ +

You can use the pipe ('|') character at the beginning of a line to indicate "plain text". For example, the additional text shown below will be displayed on the same line as the preceding anchor, but will not be linked.

+ +
a(href='http://someurl/') Link text
+| Plain text
+ +

Pug allows you to perform conditional operations using if, else , else if and unless—for example:

+ +
if title
+  p A variable named "title" exists
+else
+  p A variable named "title" does not exist
+ +

You can also perform loop/iteration operations using each-in or while syntax. In the code fragment below we've looped through an array to display a list of variables (note the use of the 'li=' to evaluate the "val" as a variable below. The value you iterate across can also be passed into the template as a variable!

+ +
ul
+  each val in [1, 2, 3, 4, 5]
+    li= val
+ +

The syntax also supports comments (that can be rendered in the output—or not—as you choose), mixins to create reusable blocks of code, case statements, and many other features. For more detailed information see The Pug docs.

+ +

Extending templates

+ +

Across a site, it is usual for all pages to have a common structure, including standard HTML markup for the head, footer, navigation, etc. Rather than forcing developers to duplicate this "boilerplate" in every page, Pug allows you to declare a base template and then extend it, replacing just the bits that are different for each specific page.

+ +

For example, the base template layout.pug created in our skeleton project looks like this:

+ +
doctype html
+html
+  head
+    title= title
+    link(rel='stylesheet', href='/stylesheets/style.css')
+  body
+    block content
+ +

The block tag is used to mark up sections of content that may be replaced in a derived template (if the block is not redefined then its implementation in the base class is used).

+ +

The default index.pug (created for our skeleton project) shows how we override the base template. The extends tag identifies the base template to use, and then we use block section_name to indicate the new content of the section that we will override.

+ +
extends layout
+
+block content
+  h1= title
+  p Welcome to #{title}
+ +

Next steps

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/create_author_form/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/create_author_form/index.html new file mode 100644 index 0000000000..9d4563376e --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/forms/create_author_form/index.html @@ -0,0 +1,155 @@ +--- +title: Create Author form +slug: Learn/Server-side/Express_Nodejs/forms/Create_author_form +translation_of: Learn/Server-side/Express_Nodejs/forms/Create_author_form +--- +

Edi本章節演示,如何為創建作者對象 Author定義一個頁面。

+ +

導入驗證和清理方法

+ +

為了在種類表單使用 express 驗證器,我們必須用 require 導入我們想用的函式。

+ +

打開 /controllers/authorController.js,並在檔案最上方,加入底下幾行:

+ +
const { body,validationResult } = require('express-validator/check');
+const { sanitizeBody } = require('express-validator/filter');
+ +

Controller—get route

+ +

Find the exported author_create_get() controller method and replace it with the following code. This simply renders the author_form.pug view, passing a title variable.

+ +
// Display Author create form on GET.
+exports.author_create_get = function(req, res, next) {
+    res.render('author_form', { title: 'Create Author'});
+};
+ +

Controller—post route

+ +

Find the exported author_create_post() controller method, and replace it with the following code.

+ +
// Handle Author create on POST.
+exports.author_create_post = [
+
+    // Validate fields.
+    body('first_name').isLength({ min: 1 }).trim().withMessage('First name must be specified.')
+        .isAlphanumeric().withMessage('First name has non-alphanumeric characters.'),
+    body('family_name').isLength({ min: 1 }).trim().withMessage('Family name must be specified.')
+        .isAlphanumeric().withMessage('Family name has non-alphanumeric characters.'),
+    body('date_of_birth', 'Invalid date of birth').optional({ checkFalsy: true }).isISO8601(),
+    body('date_of_death', 'Invalid date of death').optional({ checkFalsy: true }).isISO8601(),
+
+    // Sanitize fields.
+    sanitizeBody('first_name').trim().escape(),
+    sanitizeBody('family_name').trim().escape(),
+    sanitizeBody('date_of_birth').toDate(),
+    sanitizeBody('date_of_death').toDate(),
+
+    // Process request after validation and sanitization.
+    (req, res, next) => {
+
+        // Extract the validation errors from a request.
+        const errors = validationResult(req);
+
+        if (!errors.isEmpty()) {
+            // There are errors. Render form again with sanitized values/errors messages.
+            res.render('author_form', { title: 'Create Author', author: req.body, errors: errors.array() });
+            return;
+        }
+        else {
+            // Data from form is valid.
+
+            // Create an Author object with escaped and trimmed data.
+            var author = new Author(
+                {
+                    first_name: req.body.first_name,
+                    family_name: req.body.family_name,
+                    date_of_birth: req.body.date_of_birth,
+                    date_of_death: req.body.date_of_death
+                });
+            author.save(function (err) {
+                if (err) { return next(err); }
+                // Successful - redirect to new author record.
+                res.redirect(author.url);
+            });
+        }
+    }
+];
+ +

The structure and behaviour of this code is almost exactly the same as for creating a Genre object. First we validate and sanitize the data. If the data is invalid then we re-display the form along with the data that was originally entered by the user and a list of error messages. If the data is valid then we save the new author record and redirect the user to the author detail page.

+ +
+

Note:  Unlike with the Genre post handler, we don't check whether the Author object already exists before saving it. Arguably we should, though as it is now we can have multiple authors with the same name.

+
+ +

The validation code demonstrates several new features:

+ + + + + +

View

+ +

Create /views/author_form.pug and copy in the text below.

+ +
extends layout
+
+block content
+  h1=title
+
+  form(method='POST' action='')
+    div.form-group
+      label(for='first_name') First Name:
+      input#first_name.form-control(type='text' placeholder='First name (Christian) last' name='first_name' required='true' value=(undefined===author ? '' : author.first_name) )
+      label(for='family_name') Family Name:
+      input#family_name.form-control(type='text' placeholder='Family name (surname)' name='family_name' required='true' value=(undefined===author ? '' : author.family_name))
+    div.form-group
+      label(for='date_of_birth') Date of birth:
+      input#date_of_birth.form-control(type='date' name='date_of_birth' value=(undefined===author ? '' : author.date_of_birth) )
+    button.btn.btn-primary(type='submit') Submit
+  if errors
+    ul
+      for error in errors
+        li!= error.msg
+ +

The structure and behaviour for this view is exactly the same as for the genre_form.pug template, so we won't describe it again.

+ +
+

Note: Some browsers don’t support the input type=“date”, so you won’t get the datepicker widget or the default dd/mm/yyyy placeholder, but will instead get an empty plain text field. One workaround is to explicitly add the attribute placeholder='dd/mm/yyyy' so that on less capable browsers you will still get information about the desired text format.

+
+ +

Challenge: Adding the date of death

+ +

The template above is missing a field for entering the date_of_death. Create the field following the same pattern as the date of birth form group!

+ +

What does it look like?

+ +

Run the application, open your browser to http://localhost:3000/, then select the Create new author link. If everything is set up correctly, your site should look something like the following screenshot. After you enter a value, it should be saved and you'll be taken to the author detail page.

+ +

Author Create Page - Express Local Library site

+ +
+

Note: If you experiment with various input formats for the dates, you may find that the format yyyy-mm-dd misbehaves. This is because JavaScript treats date strings as including the time of 0 hours, but additionally treats date strings in that format (the ISO 8601 standard) as including the time 0 hours UTC, rather than the local time. If your time zone is west of UTC, the date display, being local, will be one day before the date you entered. This is one of several complexities (such as multi-word family names and multi-author books) that we are not addressing here.

+
+ +

Next steps

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/create_book_form/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/create_book_form/index.html new file mode 100644 index 0000000000..c15b2ca385 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/forms/create_book_form/index.html @@ -0,0 +1,214 @@ +--- +title: Create Book form +slug: Learn/Server-side/Express_Nodejs/forms/Create_book_form +translation_of: Learn/Server-side/Express_Nodejs/forms/Create_book_form +--- +

Edit此章節展示如何定義頁面/表單以創建Book對象。這比相同的作者Author或種類Genre頁面稍微複雜一點,因為我們需要在我們的書本表單中,獲取並顯示可用的作者和種類記錄。

+ +

 

+ +

導入驗證和清理方法

+ +

打開 /controllers/bookController.js,並在文件頂部添加以下幾行:

+ +
const { body,validationResult } = require('express-validator/check');
+const { sanitizeBody } = require('express-validator/filter');
+ +

Controller—get route

+ +

Find the exported book_create_get() controller method and replace it with the following code.

+ +
// Display book create form on GET.
+exports.book_create_get = function(req, res, next) {
+
+    // Get all authors and genres, which we can use for adding to our book.
+    async.parallel({
+        authors: function(callback) {
+            Author.find(callback);
+        },
+        genres: function(callback) {
+            Genre.find(callback);
+        },
+    }, function(err, results) {
+        if (err) { return next(err); }
+        res.render('book_form', { title: 'Create Book', authors: results.authors, genres: results.genres });
+    });
+
+};
+ +

This uses the async module (described in Express Tutorial Part 5: Displaying library data) to get all Author and Genre objects. These are then passed to the view book_form.pug as variables named authors and genres (along with the page title).

+ +

Controller—post route

+ +

Find the exported book_create_post() controller method and replace it with the following code.

+ +
// Handle book create on POST.
+exports.book_create_post = [
+    // Convert the genre to an array.
+    (req, res, next) => {
+        if(!(req.body.genre instanceof Array)){
+            if(typeof req.body.genre==='undefined')
+            req.body.genre=[];
+            else
+            req.body.genre=new Array(req.body.genre);
+        }
+        next();
+    },
+
+    // Validate fields.
+    body('title', 'Title must not be empty.').isLength({ min: 1 }).trim(),
+    body('author', 'Author must not be empty.').isLength({ min: 1 }).trim(),
+    body('summary', 'Summary must not be empty.').isLength({ min: 1 }).trim(),
+    body('isbn', 'ISBN must not be empty').isLength({ min: 1 }).trim(),
+
+    // Sanitize fields (using wildcard).
+    sanitizeBody('*').trim().escape(),
+
+    // Process request after validation and sanitization.
+    (req, res, next) => {
+
+        // Extract the validation errors from a request.
+        const errors = validationResult(req);
+
+        // Create a Book object with escaped and trimmed data.
+        var book = new Book(
+          { title: req.body.title,
+            author: req.body.author,
+            summary: req.body.summary,
+            isbn: req.body.isbn,
+            genre: req.body.genre
+           });
+
+        if (!errors.isEmpty()) {
+            // There are errors. Render form again with sanitized values/error messages.
+
+            // Get all authors and genres for form.
+            async.parallel({
+                authors: function(callback) {
+                    Author.find(callback);
+                },
+                genres: function(callback) {
+                    Genre.find(callback);
+                },
+            }, function(err, results) {
+                if (err) { return next(err); }
+
+                // Mark our selected genres as checked.
+                for (let i = 0; i < results.genres.length; i++) {
+                    if (book.genre.indexOf(results.genres[i]._id) > -1) {
+                        results.genres[i].checked='true';
+                    }
+                }
+                res.render('book_form', { title: 'Create Book',authors:results.authors, genres:results.genres, book: book, errors: errors.array() });
+            });
+            return;
+        }
+        else {
+            // Data from form is valid. Save book.
+            book.save(function (err) {
+                if (err) { return next(err); }
+                   //successful - redirect to new book record.
+                   res.redirect(book.url);
+                });
+        }
+    }
+];
+ +

The structure and behaviour of this code is almost exactly the same as for creating a Genre or Author object. First we validate and sanitize the data. If the data is invalid then we re-display the form along with the data that was originally entered by the user and a list of error messages. If the data is valid, we then save the new Book record and redirect the user to the book detail page.

+ +

The first main difference with respect to the other form handling code is that we use a wildcard to trim and escape all fields in one go (rather than sanitising them individually):

+ +
sanitizeBody('*').trim().escape(),
+ +

The next main difference with respect to the other form handling code is how we sanitize the genre information. The form returns an array of Genre items (while for other fields it returns a string). In order to validate the information we first convert the request to an array (required for the next step).

+ +
// Convert the genre to an array.
+(req, res, next) => {
+    if(!(req.body.genre instanceof Array)){
+        if(typeof req.body.genre==='undefined')
+        req.body.genre=[];
+        else
+        req.body.genre=new Array(req.body.genre);
+    }
+    next();
+},
+ +

We then use a wildcard (*) in the sanitiser to individually validate each of the genre array entries. The code below shows how - this translates to "sanitise every item below key genre".

+ +
sanitizeBody('genre.*').trim().escape(),
+ +

The final difference with respect to the other form handling code is that we need to pass in all existing genres and authors to the form. In order to mark the genres that were checked by the user we iterate through all the genres and add the checked='true' parameter to those that were in our post data (as reproduced in the code fragment below).

+ +
// Mark our selected genres as checked.
+for (let i = 0; i < results.genres.length; i++) {
+    if (book.genre.indexOf(results.genres[i]._id) > -1) {
+        // Current genre is selected. Set "checked" flag.
+        results.genres[i].checked='true';
+    }
+}
+ +

View

+ +

Create /views/book_form.pug and copy in the text below.

+ +
extends layout
+
+block content
+  h1= title
+
+  form(method='POST' action='')
+    div.form-group
+      label(for='title') Title:
+      input#title.form-control(type='text', placeholder='Name of book' name='title' required='true' value=(undefined===book ? '' : book.title) )
+    div.form-group
+      label(for='author') Author:
+      select#author.form-control(type='select', placeholder='Select author' name='author' required='true' )
+        for author in authors
+          if book
+            option(value=author._id selected=(author._id.toString()==book.author ? 'selected' : false) ) #{author.name}
+          else
+            option(value=author._id) #{author.name}
+    div.form-group
+      label(for='summary') Summary:
+      input#summary.form-control(type='textarea', placeholder='Summary' name='summary' value=(undefined===book ? '' : book.summary) required='true')
+    div.form-group
+      label(for='isbn') ISBN:
+      input#isbn.form-control(type='text', placeholder='ISBN13' name='isbn' value=(undefined===book ? '' : book.isbn) required='true')
+    div.form-group
+      label Genre:
+      div
+        for genre in genres
+          div(style='display: inline; padding-right:10px;')
+            input.checkbox-input(type='checkbox', name='genre', id=genre._id, value=genre._id, checked=genre.checked )
+            label(for=genre._id) #{genre.name}
+    button.btn.btn-primary(type='submit') Submit
+
+  if errors
+    ul
+      for error in errors
+        li!= error.msg
+ +

The view structure and behaviour is almost the same as for the genre_form.pug template.

+ +

The main differences are in how we implement the selection-type fields: Author and Genre.

+ + + +

What does it look like?

+ +

Run the application, open your browser to http://localhost:3000/, then select the Create new book link. If everything is set up correctly, your site should look something like the following screenshot. After you submit a valid book, it should be saved and you'll be taken to the book detail page.

+ +

+ +

Next steps

+ +

Return to Express Tutorial Part 6: Working with forms.

+ +

Proceed to the next subarticle of part 6: Create BookInstance form.

diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html new file mode 100644 index 0000000000..14288f4678 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html @@ -0,0 +1,150 @@ +--- +title: Create BookInstance form +slug: Learn/Server-side/Express_Nodejs/forms/Create_BookInstance_form +translation_of: Learn/Server-side/Express_Nodejs/forms/Create_BookInstance_form +--- +

Edi本章節演示如何定義一個頁面/表單,以創建 BookInstance 物件。這很像我們用來創建書本 Book 物件的表單。

+ +

導入驗證和清理方法

+ +

打開 /controllers/bookinstanceController.js,並在檔案最上方,加入以下幾行:

+ +
const { body,validationResult } = require('express-validator/check');
+const { sanitizeBody } = require('express-validator/filter');
+ +

Controller—get route

+ +

At the top of the file, require the Book module (needed because each BookInstance is associated with a particular Book).

+ +
var Book = require('../models/book');
+ +

Find the exported bookinstance_create_get() controller method and replace it with the following code.

+ +
// Display BookInstance create form on GET.
+exports.bookinstance_create_get = function(req, res, next) {
+
+    Book.find({},'title')
+    .exec(function (err, books) {
+      if (err) { return next(err); }
+      // Successful, so render.
+      res.render('bookinstance_form', {title: 'Create BookInstance', book_list:books});
+    });
+
+};
+ +

The controller gets a list of all books (book_list) and passes it to the view bookinstance_form.pug (along with the title)

+ +

Controller—post route

+ +

Find the exported bookinstance_create_post() controller method and replace it with the following code.

+ +
// Handle BookInstance create on POST.
+exports.bookinstance_create_post = [
+
+    // Validate fields.
+    body('book', 'Book must be specified').isLength({ min: 1 }).trim(),
+    body('imprint', 'Imprint must be specified').isLength({ min: 1 }).trim(),
+    body('due_back', 'Invalid date').optional({ checkFalsy: true }).isISO8601(),
+
+    // Sanitize fields.
+    sanitizeBody('book').trim().escape(),
+    sanitizeBody('imprint').trim().escape(),
+    sanitizeBody('status').trim().escape(),
+    sanitizeBody('due_back').toDate(),
+
+    // Process request after validation and sanitization.
+    (req, res, next) => {
+
+        // Extract the validation errors from a request.
+        const errors = validationResult(req);
+
+        // Create a BookInstance object with escaped and trimmed data.
+        var bookinstance = new BookInstance(
+          { book: req.body.book,
+            imprint: req.body.imprint,
+            status: req.body.status,
+            due_back: req.body.due_back
+           });
+
+        if (!errors.isEmpty()) {
+            // There are errors. Render form again with sanitized values and error messages.
+            Book.find({},'title')
+                .exec(function (err, books) {
+                    if (err) { return next(err); }
+                    // Successful, so render.
+                    res.render('bookinstance_form', { title: 'Create BookInstance', book_list : books, selected_book : bookinstance.book._id , errors: errors.array(), bookinstance:bookinstance });
+            });
+            return;
+        }
+        else {
+            // Data from form is valid.
+            bookinstance.save(function (err) {
+                if (err) { return next(err); }
+                   // Successful - redirect to new record.
+                   res.redirect(bookinstance.url);
+                });
+        }
+    }
+];
+ +

The structure and behaviour of this code is the same as for creating our other objects. First we validate and sanitize the data. If the data is invalid, we then re-display the form along with the data that was originally entered by the user and a list of error messages. If the data is valid, we save the new BookInstance record and redirect the user to the detail page.

+ +

View

+ +

Create /views/bookinstance_form.pug and copy in the text below.

+ +
extends layout
+
+block content
+  h1=title
+
+  form(method='POST' action='')
+    div.form-group
+      label(for='book') Book:
+      select#book.form-control(type='select' placeholder='Select book' name='book' required='true')
+        for book in book_list
+          if bookinstance
+            option(value=book._id selected=(bookinstance.book.toString()==book._id.toString() ? 'selected' : false)) #{book.title}
+          else
+            option(value=book._id) #{book.title}
+
+    div.form-group
+      label(for='imprint') Imprint:
+      input#imprint.form-control(type='text' placeholder='Publisher and date information' name='imprint' required='true' value=(undefined===bookinstance ? '' : bookinstance.imprint))
+    div.form-group
+      label(for='due_back') Date when book available:
+      input#due_back.form-control(type='date' name='due_back' value=(undefined===bookinstance ? '' : bookinstance.due_back))
+
+    div.form-group
+      label(for='status') Status:
+      select#status.form-control(type='select' placeholder='Select status' name='status' required='true')
+        option(value='Maintenance') Maintenance
+        option(value='Available') Available
+        option(value='Loaned') Loaned
+        option(value='Reserved') Reserved
+
+    button.btn.btn-primary(type='submit') Submit
+
+  if errors
+    ul
+      for error in errors
+        li!= error.msg
+ +

The view structure and behaviour is almost the same as for the book_form.pug template, so we won't go over it again.

+ +
+

Note: The above template hard-codes the Status values (Maintenance, Available, etc.) and does not "remember" the user's entered values. Should you so wish, consider reimplementing the list, passing in option data from the controller and setting the selected value when the form is re-displayed.

+
+ +

What does it look like?

+ +

Run the application and open your browser to http://localhost:3000/. Then select the Create new book instance (copy) link. If everything is set up correctly, your site should look something like the following screenshot. After you submit a valid BookInstance, it should be saved and you'll be taken to the detail page.

+ +

+ +

Next steps

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/create_genre_form/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/create_genre_form/index.html new file mode 100644 index 0000000000..3e648e48ea --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/forms/create_genre_form/index.html @@ -0,0 +1,294 @@ +--- +title: 創建種類表單 +slug: Learn/Server-side/Express_Nodejs/forms/Create_genre_form +translation_of: Learn/Server-side/Express_Nodejs/forms/Create_genre_form +--- +

本章節演示如何定義我們的頁面,創建Genre 物件(這是一個很好的起點,因為類型Genre只有一個欄位,就是它的名稱 name,沒有依賴項)。像任何其他頁面一樣,我們需要設置路由,控制器和視圖。

+ +

 

+ +

引入驗證與無害化方法

+ +

在我們的控制器中使用 express-validator 驗證器,我們必須導入我們想要從 'express-validator/check' 和 'express-validator/filter' 模塊中使用的函數。

+ +

打開 /controllers/genreController.js,並在文件頂部添加以下幾行:

+ +
const { body,validationResult } = require('express-validator/check');
+const { sanitizeBody } = require('express-validator/filter');
+ +

Controller—get route

+ +

Find the exported genre_create_get() controller method and replace it with the following code. This simply renders the genre_form.pug view, passing a title variable.

+ +
// Display Genre create form on GET.
+exports.genre_create_get = function(req, res, next) {
+    res.render('genre_form', { title: 'Create Genre' });
+};
+ +

Controller—post route

+ +

Find the exported genre_create_post() controller method and replace it with the following code.

+ +
// Handle Genre create on POST.
+exports.genre_create_post =  [
+
+    // Validate that the name field is not empty.
+    body('name', 'Genre name required').isLength({ min: 1 }).trim(),
+
+    // Sanitize (trim and escape) the name field.
+    sanitizeBody('name').trim().escape(),
+
+    // Process request after validation and sanitization.
+    (req, res, next) => {
+
+        // Extract the validation errors from a request.
+        const errors = validationResult(req);
+
+        // Create a genre object with escaped and trimmed data.
+        var genre = new Genre(
+          { name: req.body.name }
+        );
+
+
+        if (!errors.isEmpty()) {
+            // There are errors. Render the form again with sanitized values/error messages.
+            res.render('genre_form', { title: 'Create Genre', genre: genre, errors: errors.array()});
+        return;
+        }
+        else {
+            // Data from form is valid.
+            // Check if Genre with same name already exists.
+            Genre.findOne({ 'name': req.body.name })
+                .exec( function(err, found_genre) {
+                     if (err) { return next(err); }
+
+                     if (found_genre) {
+                         // Genre exists, redirect to its detail page.
+                         res.redirect(found_genre.url);
+                     }
+                     else {
+
+                         genre.save(function (err) {
+                           if (err) { return next(err); }
+                           // Genre saved. Redirect to genre detail page.
+                           res.redirect(genre.url);
+                         });
+
+                     }
+
+                 });
+        }
+    }
+];
+ +

The first thing to note is that instead of being a single middleware function (with arguments (req, res, next)) the controller specifies an array of middleware functions. The array is passed to the router function and each method is called in order.

+ + + +
+

Note: This approach is needed, because the sanitisers/validators are middleware functions.

+
+ +

The first method in the array defines a validator (body) to check that the name field is not empty (calling trim() to remove any trailing/leading whitespace before performing the validation). The  second method in the array (sanitizeBody()) creates a sanitizer to trim() the name field and escape() any dangerous  HTML characters.

+ +
// Validate that the name field is not empty.
+body('name', 'Genre name required').isLength({ min: 1 }).trim(),
+
+// Sanitize (trim and escape) the name field.
+sanitizeBody('name').trim().escape(),
+ + + +
+

Note: Sanitizers run during validation do not modify the request. That is why we have to call trim() in both steps above!

+
+ +

After specifying the validators and sanitizers we create a middleware function to extract any validation errors. We use isEmpty() to check whether there are any errors in the validation result. If there are then we render the form again, passing in our sanitised genre object and the array of error messages (errors.array()).

+ +
// Process request after validation and sanitization.
+(req, res, next) => {
+
+    // Extract the validation errors from a request.
+    const errors = validationResult(req);
+
+    // Create a genre object with escaped and trimmed data.
+    var genre = new Genre(
+      { name: req.body.name }
+    );
+
+    if (!errors.isEmpty()) {
+        // There are errors. Render the form again with sanitized values/error messages.
+        res.render('genre_form', { title: 'Create Genre', genre: genre, errors: errors.array()});
+    return;
+    }
+    else {
+        // Data from form is valid.
+        ... <save the result> ...
+    }
+}
+ +

If the genre name data is valid then we check if a Genre with the same name already exists (as we don't want to create duplicates). If it does we redirect to the existing genre's detail page. If not, we save the new Genre and redirect to its detail page.

+ +
// Check if Genre with same name already exists.
+Genre.findOne({ 'name': req.body.name })
+    .exec( function(err, found_genre) {
+    if (err) { return next(err); }
+        if (found_genre) {
+            // Genre exists, redirect to its detail page.
+            res.redirect(found_genre.url);
+            }
+        else {
+            genre.save(function (err) {
+                if (err) { return next(err); }
+                    // Genre saved. Redirect to genre detail page.
+                    res.redirect(genre.url);
+                });
+        }
+});
+ +

This same pattern is used in all our post controllers: we run validators, then sanitisers,  then check for errors and either re-render the form with error information or save the data. 

+ +

View

+ +

The same view is rendered in both the GET and POST controllers/routes when we create a new Genre (and later on it is also used when we updateGenre). In the GET case the form is empty and we just pass a title variable. In the POST case the user has previously entered invalid data—in the genre variable we pass back a sanitized version of the entered data and in the errors variable we pass back an array of error messages.

+ +
res.render('genre_form', { title: 'Create Genre'});
+res.render('genre_form', { title: 'Create Genre', genre: genre, errors: errors.array()});
+ +

Create /views/genre_form.pug and copy in the text below.

+ +
extends layout
+
+block content
+  h1 #{title}
+
+  form(method='POST' action='')
+    div.form-group
+      label(for='name') Genre:
+      input#name.form-control(type='text', placeholder='Fantasy, Poetry etc.' name='name' value=(undefined===genre ? '' : genre.name))
+    button.btn.btn-primary(type='submit') Submit
+
+  if errors
+    ul
+      for error in errors
+        li!= error.msg
+ +

Much of this template will be familiar from our previous tutorials. First we extend the layout.pug base template and override the block named 'content'. We then have a heading with the title we passed in from the controller (via the render() method).

+ +

Next we have the pug code for our HTML form that uses the POST method to send the data to the server, and because the action is an empty string, will send the data to the same URL as the page.

+ +

The form defines a single required field of type "text" called "name". The default value of the field depends on whether the genre variable is defined. If called from the GET route it will be empty as this is a new form. If called from a POST route it will contain the (invalid) value originally entered by the user.

+ +

The last part of the page is the error code. This simply prints a list of errors, if the error variable has been defined (in other words, this section will not appear when the template is rendered on the GET route).

+ +
+

Note: This is just one way to render the errors. You can also get the names of the affected fields from the error variable, and use these to control where the error messages are rendered, whether to apply custom CSS, etc.

+
+ +

What does it look like?

+ +

Run the application, open your browser to http://localhost:3000/, then select the Create new genre link. If everything is set up correctly, your site should look something like the following screenshot. After you enter a value, it should be saved and you'll be taken to the genre detail page.

+ +

Genre Create Page - Express Local Library site

+ +

The only error we validate against server-side is that the genre field must not be empty. The screenshot below shows what the error list would look like if you didn't supply a genre (highlighted in red).

+ +

+ +
+

Note: Our validation uses trim() to ensure that whitespace is not accepted as a genre name. We can also validate that the field is not empty on the client side by adding the value required='true' to the field definition in the form:

+ +
input#name.form-control(type='text', placeholder='Fantasy, Poetry etc.' name='name' value=(undefined===genre ? '' : genre.name), required='true' )
+
+ +

Next steps

+ + + +
+ + + + + +
diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/delete_author_form/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/delete_author_form/index.html new file mode 100644 index 0000000000..f26b87bce7 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/forms/delete_author_form/index.html @@ -0,0 +1,167 @@ +--- +title: Delete Author form +slug: Learn/Server-side/Express_Nodejs/forms/Delete_author_form +translation_of: Learn/Server-side/Express_Nodejs/forms/Delete_author_form +--- +

 

+ +

此子文檔展示,如何定義頁面以刪除 Author對象。

+ +

正如表單設計部分所討論的那樣,我們的策略是,只允許刪除“未被其他對象引用” 的對象(在這種情況下,這意味著如果作者Author被一本書Book引用,我們將不允許刪除作者)。在實現方面,這意味著,表單需要在刪除作者之前,先確認沒有關聯的書籍。如果存在關聯的書籍,則應顯示它們,並說明在刪除Author對象之前,必須刪除它們。

+ +

Controller—get route

+ +

Open /controllers/authorController.js. Find the exported author_delete_get() controller method and replace it with the following code.

+ +
// Display Author delete form on GET.
+exports.author_delete_get = function(req, res, next) {
+
+    async.parallel({
+        author: function(callback) {
+            Author.findById(req.params.id).exec(callback)
+        },
+        authors_books: function(callback) {
+          Book.find({ 'author': req.params.id }).exec(callback)
+        },
+    }, function(err, results) {
+        if (err) { return next(err); }
+        if (results.author==null) { // No results.
+            res.redirect('/catalog/authors');
+        }
+        // Successful, so render.
+        res.render('author_delete', { title: 'Delete Author', author: results.author, author_books: results.authors_books } );
+    });
+
+};
+ +

The controller gets the id of the Author instance to be deleted from the URL parameter (req.params.id). It uses the async.parallel() method to get the author record and all associated books in parallel. When both operations have completed it renders the author_delete.pug view, passing variables for the title, author, and author_books.

+ +
+

Note: If  findById() returns no results the author is not in the database. In this case there is nothing to delete, so we immediately render the list of all authors. 

+ +
}, function(err, results) {
+    if (err) { return next(err); }
+    if (results.author==null) { // No results.
+        res.redirect('/catalog/authors')
+    }
+
+ +

Controller—post route

+ +

Find the exported author_delete_post() controller method, and replace it with the following code.

+ +
// Handle Author delete on POST.
+exports.author_delete_post = function(req, res, next) {
+
+    async.parallel({
+        author: function(callback) {
+          Author.findById(req.body.authorid).exec(callback)
+        },
+        authors_books: function(callback) {
+          Book.find({ 'author': req.body.authorid }).exec(callback)
+        },
+    }, function(err, results) {
+        if (err) { return next(err); }
+        // Success
+        if (results.authors_books.length > 0) {
+            // Author has books. Render in same way as for GET route.
+            res.render('author_delete', { title: 'Delete Author', author: results.author, author_books: results.authors_books } );
+            return;
+        }
+        else {
+            // Author has no books. Delete object and redirect to the list of authors.
+            Author.findByIdAndRemove(req.body.authorid, function deleteAuthor(err) {
+                if (err) { return next(err); }
+                // Success - go to author list
+                res.redirect('/catalog/authors')
+            })
+        }
+    });
+};
+ +

First we validate that an id has been provided (this is sent via the form body parameters, rather than using the version in the URL). Then we get the author and their associated books in the same way as for the GET route. If there are no books then we delete the author object and redirect to the list of all authors. If there are still books then we just re-render the form, passing in the author and list of books to be deleted.

+ +
+

Note: We could check if the call to findById() returns any result, and if not,  immediately render the list of all authors.  We've left the code as it is above for brevity (it will still return the list of authors if the id is not found, but this will happen after findByIdAndRemove()).

+
+ +

View

+ +

Create /views/author_delete.pug and copy in the text below.

+ +
extends layout
+
+block content
+  h1 #{title}: #{author.name}
+  p= author.lifespan
+
+  if author_books.length
+
+    p #[strong Delete the following books before attempting to delete this author.]
+
+    div(style='margin-left:20px;margin-top:20px')
+
+      h4 Books
+
+      dl
+      each book in author_books
+        dt
+          a(href=book.url) #{book.title}
+        dd #{book.summary}
+
+  else
+    p Do you really want to delete this Author?
+
+    form(method='POST' action='')
+      div.form-group
+        input#authorid.form-control(type='hidden',name='authorid', required='true', value=author._id )
+
+      button.btn.btn-primary(type='submit') Delete
+ +

The view extends the layout template, overriding the block named content. At the top it displays the author details. It then includes a conditional statement based on the number of author_books (the if and else clauses).

+ + + +

Add a delete control

+ +

Next we will add a Delete control to the Author detail view (the detail page is a good place from which to delete a record).

+ +
+

Note: In a full implementation the control would be made visible only to authorised users. However at this point we haven't got an authorisation system in place!

+
+ +

Open the author_detail.pug view and add the following lines at the bottom.

+ +
hr
+p
+  a(href=author.url+'/delete') Delete author
+ +

The control should now appear as a link, as shown below on the Author detail page.

+ +

+ +

What does it look like?

+ +

Run the application and open your browser to http://localhost:3000/. Then select the All authors link, and then select a particular author. Finally select the Delete author link.

+ +

If the author has no books, you'll be presented with a page like this. After pressing delete, the server will delete the author and redirect to the author list.

+ +

+ +

If the author does have books, then you'll be presented with a view like the following. You can then delete the books from their detail pages (once that code is implemented!).

+ +

+ +
+

Note: The other pages for deleting objects can be implemented in much the same way. We've left that as a challenge.

+
+ +

Next steps

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/index.html new file mode 100644 index 0000000000..008d7ae4e8 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/forms/index.html @@ -0,0 +1,274 @@ +--- +title: 'Express 教學 6: 使用表單' +slug: Learn/Server-side/Express_Nodejs/forms +translation_of: Learn/Server-side/Express_Nodejs/forms +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs/deployment", "Learn/Server-side/Express_Nodejs")}}
+ +

在此教程中,我們會教你如何使用 Express ,並且結合 Pug 來實現 HTML 表單,並且如何從數據庫中創建、更新、和刪除文檔。

+ + + + + + + + + + + + +
前提條件:完成前面所有的教程,包括 Express 教程第5章: 展示圖書館數據。
目標:了解如何編寫表單獲取用戶信息,並且將這些數據更新到數據庫中。
+ +

概覽

+ +

HTML 表單是網頁中由一個、或多個字段/小工具形成的一個組合,它被用來收集用戶的信息,並將信息上傳到服務器。表單作為一種用來收集用戶的機制,非常的靈活,因為有各種合適的輸入框,來接受各種類型的數據——文本框,複選框,單選按鈕,時間選擇器等。表單和服務器交互數據也相對安全,因為它使用POST請求發送數據,保護不受跨站點請求偽造攻擊(cross-site request forgery)的威脅。

+ +

但是表單同樣也很複雜!開發者需要編寫給表單編寫 HTML,在服務器上驗證,並且正確去除有害的數據(瀏覽器上也可能需要),對於任何不合法的字段,需要傳給用戶相應的錯誤信息,當數據成功提交後,處理數據,並設法通知用戶提交成功。

+ +

此教程將展示上述的操作,如何在 Express 中實現。在此過程中,我們將擴展 LocalLibrary 網站,以允許用戶創建、編輯、和刪除圖書館中的項目。

+ +
+

注意: 我們還沒有考慮如何將特定路由,限制為經過身份驗證或授權的用戶,因此在這個時間點,任何用戶都可以對數據庫進行更改。

+
+ +

HTML 表單

+ +

首先簡要概述 HTML 表單。考慮一個簡單的 HTML 表單,其中包含一個文本字段,用於輸入某些 “團隊” 的名稱,及其相關標籤:

+ +

Simple name field example in HTML form

+ +

表單在HTML中,定義為 <form>...</form>標記內的元素集合,包含至少一個type="submit"input輸入元素。

+ +
<form action="/team_name_url/" method="post">
+    <label for="team_name">Enter name: </label>
+    <input id="team_name" type="text" name="name_field" value="Default name for team.">
+    <input type="submit" value="OK">
+</form>
+ +

雖然這裡,我們只包含一個(文本)字段,用於輸入團隊名稱,但表單可能包含任意數量的其他輸入元素,及其相關標籤。字段的 type 屬性,定義將顯示哪種窗口小部件。該字段的名稱nameid ,用於標識JavaScript/CSS/HTML 中的字段,而 value定義字段首次顯示時的初始值。匹配團隊標籤使用 label 標籤,指定(請參閱上面的“輸入名稱” "Enter name"),其中 for 字段,包含 input 相關輸入的 id值。

+ +

提交輸入(submit)將顯示為按鈕(默認情況下) - 用戶可以按此按鈕,將其他輸入元素包含的數據,上傳到服務器(在本例中,只有 team_name)。表單屬性,定義用於發送數據的HTTP method方法,和服務器上數據的目標(action):

+ + + +

表單處理流程

+ +

表單處理使用的技術,與我們學習過、用來顯示有關模型的信息的所有技術,是相同的:路由將我們的請求發送到控制器函數,該函數執行所需的任何數據庫操作,包括從模型中讀取數據,然後生成並返回 HTML 頁面。使事情變得更複雜的是,服務器還需要能夠處理用戶提供的數據,並在出現任何問題時,重新顯示帶有錯誤信息的表單。

+ +

下面顯示了處理表單請求的流程圖,從包含表單的頁面請求開始(以綠色顯示):

+ +

+ +

如上圖所示,構成處理代碼所需要做的主要是:  

+ +
    +
  1. 在用戶第一次請求時顯示默認表單。 +
      +
    • 表單可能包含空白字段(例如,如果您正在創建新記錄),或者可能預先填充了初始值(例如,如果您要更改記錄,或者俱有有用的默認初始值)。
    • +
    +
  2. +
  3. 接收用戶提交的數據,通常是在HTTP POST請求中。
  4. +
  5. 驗證並清理數據。
  6. +
  7. 如果任何數據無效,請重新顯示表單 - 這次使用用戶填寫的任何值,和問題字段的錯誤消息。
  8. +
  9. 如果所有數據都有效,請執行所需的操作(例如,將數據保存在數據庫中,發送通知電子郵件,返回搜索結果,上傳文件等)
  10. +
  11. 完成所有操作之後,將用戶重定向到另一個頁面。
  12. +
+ +

表格處理代碼,通常使用 GET路由,以實現表單的初始顯示,以及 POST路由到同一路徑,以處理表單數據的驗證和處理。這是將在本教程中使用的方法!

+ +

Express 本身不提供表單處理操作的任何特定支持,但它可以使用中間件,以處理表單中的 POSTGET參數,並驗證/清理它們的值。

+ +

驗證和清理

+ +

在儲存表單中的數據之前,必須對其進行驗證和清理:

+ + + +

在本教程中,我們將使用流行的 express-validator 模塊,來執行表單數據的驗證和清理。

+ +

安裝

+ +

通過在項目的根目錄中,運行以下命令,來安裝模塊。

+ +
npm install express-validator
+
+ +

使用 express-validator

+ +
+

注意: Github上的 express-validator 指南,提供了API的良好概述。我們建議您閱讀該內容,以了解其所有功能(包括創建自定義驗證程序)。下面我們只介紹一個對 LocalLibrary 有用的子集。

+ +

 

+ +

 

+
+ +

要在我們的控制器中使用驗證器,我們必須從 'express-validator/check'和'express-validator/filter'模塊中,導入我們想要使用的函數,如下所示:

+ +
const { body,validationResult } = require('express-validator/check');
+const { sanitizeBody } = require('express-validator/filter');
+
+ +

有許多可用的功能,允許您一次檢查和清理請求參數,正文,標頭,cookie 等數據,或所有數據。對於本教程,我們主要使用 bodysanitizeBody,和 validationResult(如上面 required 導入的 )。

+ +

功能定義如下:

+ + + +

驗證和清理鏈,是應該傳遞給 Express 路由處理程序的中間件(我們通過控制器,間接地執行此操作)。中間件運行時,每個驗證器/清理程序都按指定的順序運行。

+ +

當我們實現下面的LocalLibrary表單時,我們將介紹一些真實的例子。

+ +

表單設計

+ +

圖書館中的許多模型都是相關/依賴的 - 例如,一本書需要一個作者,也可能有一個或多個種類。這提出了一個問題,即我們應該如何處理用戶希望的情況:

+ + + +

在這個項目,我們為了簡化實作,將聲明表單只能:

+ + + +
+

注意: 更“牢固”的實現,可能允許您在創建新對象時,創建依賴對象,並隨時刪除任何對象(例如,通過刪除依賴對象,或從數據庫中,刪除對已刪除對象的引用) 。

+
+ +

路由

+ +

為了實現我們的表單處理代碼,我們需要兩個具有相同 URL 模式的路由。

+ +

第一個(GET)路由,用於顯示用於創建對象的新空表單。第二個路由(POST),用於驗證用戶輸入的數據,然後保存信息,並重定向到詳細信息頁面(如果數據有效),或重新顯示有錯誤的表單(如果數據無效)。

+ +

我們已經在 /routes/catalog.js(在之前的教程中)為我們所有模型的創建頁面,創建了路徑。例如,種類路由如下所示:

+ +
// GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id).
+router.get('/genre/create', genre_controller.genre_create_get);
+
+// POST request for creating Genre.
+router.post('/genre/create', genre_controller.genre_create_post);
+
+ +

Express 表單子文件

+ +

以下子文件,將帶我們完成向示例應用程序添加所需表單的過程。在進入下一個文件之前,您需要依次閱讀並解決每個問題。

+ +
    +
  1. 創建種類表單 — 定義我們的頁面以創建種類對象 Genre
  2. +
  3. 創建作者表單 — 定義用於創建作者對象 Author 的頁面。
  4. +
  5. 創建書本表單 — 定義頁面/表單以創建書本對象 Book
  6. +
  7. 創建書本實例表單 — 定義頁面/表單以創建書本實例對象 BookInstance
  8. +
  9. 刪除作者表單 — 定義要刪除作者對象 Author 的頁面。
  10. +
  11. 更新書本表單 — 定義頁面以更新書本對象 Book
  12. +
+ +

挑戰自我

+ +

實現 Book, BookInstance, 和 Genre模型的刪除頁面,用跟我們的作者刪除頁面相同的方式,將它們與關聯的詳細信息頁面,鏈接起來。頁面應遵循相同的設計方法:

+ + + +

一些提示:

+ + + +

實現 BookInstance, Author, 和 Genre模型的更新頁面,以與我們的書本更新頁面相同的方式,將它們與關聯的詳細信息頁面,鏈接起來。

+ +

一些提示:

+ + + +

總結

+ +

Express, node, 與NPM上面的第三方套件,提供你需要的每樣東西 ,可用於新增表單到你的網站上。在本文中,您學習如何使用 Pug 創建表單,使用 express-validator 驗證和清理輸入,以及添加,刪除和修改數據庫中的記錄。

+ +

你現在應該了解如何新增基本表單,以及表單處理代碼到你的 node 網站!

+ +

請參閱

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs/deployment", "Learn/Server-side/Express_Nodejs")}}

+ +

本教程連結

+ + + +

 

diff --git a/files/zh-tw/learn/server-side/express_nodejs/index.html b/files/zh-tw/learn/server-side/express_nodejs/index.html new file mode 100644 index 0000000000..c1c6e11ee5 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/index.html @@ -0,0 +1,73 @@ +--- +title: Express web framework (Node.js/JavaScript) +slug: Learn/Server-side/Express_Nodejs +tags: + - Express + - Express.js + - Node + - node.js + - 介紹 + - 伺服器端程式 + - 初學者 + - 學習 +translation_of: Learn/Server-side/Express_Nodejs +--- +
{{LearnSidebar}}
+ +

Express 是一個流行的web框架,使用JavsScript實現,執行在node.js環境上。本系列解釋Express的優點、如何設定開發環境、完成常見的web開發和佈署。

+ +

前置需求

+ +

在開始前你需要了解什麼是伺服器端web程式和什麼是web框架,推薦閱讀伺服器端網站開發第一步。建議了解基本的程式知識和JavaScript,但不需要知道核心概念。

+ +
+

注意: 本網站有許多學習JavaScript應用在客戶端開發的有用資源,如:JavaScriptJavaScript 指南JavaScript 基礎JavaScript (learning)。使用Node.js開發伺服器端使用的JavaScript語言與概念和客戶端是一樣的。Node.js提供額外的APIs以支援無瀏覽器環境,例如:建立HTTP服務和讀取檔案系統。但不支援DOM及瀏覽器相關的 JavaScript API。

+ +

這份指南將提供一些使用Node.js和Express的資訊以及數個優秀的學習資源。部分連結由 How do I get started with Node.js(StackOverflow) 與 What are the best resources for learning Node.js?(Quora) 提供。

+
+ +

指南

+ +
+
Express/Node 介紹
+
第一篇的系列文章中回答了「什麼是Node」和「什麼是Express?」並概略的說明為什麼Express web框架如此特別。此文章將重點放在主要的功能上,並展示一些Express應用常見的建構模塊(儘管此時你還沒有可供測試的開發環境)
+
設定 Node (Express) 開發環境
+
現在你已經了解Express的目的了,接下來繼續說明如何設定和測試 Windows、Linux (Ubuntu)和Mac OS X上的Node/Express開發環境。不管你用的是什麼作業系統,你都能在本文中找到開發Express應用的入門需知。
+
Express 教學(1): The Local Library website
+
在第一篇實務教學系列文章中將說明你將會學到什麼?以及提供範例網站local library的概覽,我們將在後續的文章中繼續改進它。
+
Express 教學(2): 建構網站骨架
+
本文章展示如何建構網站的骨架,接著你可以自己添加路由、模板/畫面和資料庫。
+
Express 教學(3): 使用資料庫(以Mongoose為例)
+
本文簡短的介紹Node/Express如何使用資料庫。接下來展示LocalLibray網站如何透過Mongoose進行資料庫的存取。說明物件綱要(object schema)和模型(models)如何宣告、the main field types和基本驗證。同時簡單的展示幾個讀取資料的主要方法。
+
Express 教學(4): 路由和控制器
+
在本教學中,我們將為LocalLibrary網站中的所有資源終端設定“虛擬”處理函數的路由(URL處理代碼)。 完成後,我們將為我們的路由處理程式提供模組化結構,以便我們可以在後續的教學中擴展真正的處理函數。 我們也將了解如何使用Express創建模組化路由。
+
Express 教學(5): 顯示圖書館的資料
+
現在已經準備好新增頁面來展示館藏和其他資料了。這些頁面包括一個展示我們有多少種model 型態的首頁、所有models的列表和詳細資料頁面。透過本教學你可以得到從資料庫取得紀錄和使用模板的實務經驗。
+
Express 教學(6): 使用表單
+
本教學中展示如何使用Express的插件-Pug來使用HTML Forms,以及如何編寫表單來創造、更新和刪除資料庫的文件。
+
Express 教學(7): 網站佈署
+
現在你完成了很棒的LocalLibrary 網站,你希望圖書館的員工和會員可以透過網路讀取它。本教學概略說明如何找到主機來佈署你的網站以及為了使你的網站正式上線所需做的準備。
+
+ +

或許你也想看

+ +
+
在 PWS/Cloud Foundry上安裝LocalLibrary
+
本文展示如何在Pivotal Web Services PaaS cloud上安裝LocalLibrary ,PWS/Cloud Foundry是一個完整且開源的Heroku替代品,可使用於教學(7)。如果你正在尋找Heroku或其他PaaS的替代品或只是想玩點不同的東西,那PWS/Cloud Foundry絕對值得一試。
+
+ +

新增其他教學

+ +
+

現在已經有了很多教學,但你可能會想寫其他有趣主題的模塊,包括:

+ + + +

當然,如果能作個評估模塊就更好了!

+
diff --git a/files/zh-tw/learn/server-side/express_nodejs/introduction/index.html b/files/zh-tw/learn/server-side/express_nodejs/introduction/index.html new file mode 100644 index 0000000000..6fc3f0a98c --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/introduction/index.html @@ -0,0 +1,522 @@ +--- +title: Express/Node introduction +slug: Learn/Server-side/Express_Nodejs/Introduction +tags: + - Express + - Node + - nodejs + - 伺服器端 + - 初學者 + - 學習 +translation_of: Learn/Server-side/Express_Nodejs/Introduction +--- +
+ + + + +

{{LearnSidebar}}

+ +

{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}

+
+ +

在這篇文章中回答了「什麼是Node?」和「什麼是Express」,同時概述是什麼讓Express框架如此特別。本文將概述主要特性、展示一些Express應用的主要建構模塊(雖然此時你還沒有能測試它的開發環境)

+ + + + + + + + + + + + +
前置需求:基本的電腦知識。 對伺服器端網站程式設計的基本了解,特別是網站中客戶端 - 伺服器交互的機制
目標:提升對Express的了解、如何與Node搭配使用、提供的功能和Express應用的主要建構模塊。
+ +

什麼是Express和Node?

+ +

Node (或者說Node.js) 是一個開源、跨平台和允許開發者使用Javascript創造伺服器端工具和應用的執行環境。運行的目的是為了能在瀏覽器外使用,例如:直接執行在電腦或伺服器上。所以該環境捨棄了瀏覽器限定的JavaScript APIs並增加更多傳統OS APIs的支援,例如:HTTP和檔案系統的程式庫。

+ + + +

從網站伺服器開發的觀點來看Node有幾項優點:

+ + + +

你可以只用Node的HTTP模組創造一個簡單的web伺服器來回應任何請求,如下所示。此教學不會告訴建議的檔案名稱或如何執行該檔案 ;-)

+ +

這將創造一個伺服器並會監聽http://127.0.0.1:8000/上任何種類的HTTP請求,當接收到任何請求時回傳一個「Hello World」的純文字回應。

+ +
// 載入 HTTP 模組
+var http = require("http");
+
+// 創建 HTTP 伺服器並監聽8000 port
+http.createServer(function(request, response) {
+
+   // Set the response HTTP header with HTTP status and Content type
+   response.writeHead(200, {'Content-Type': 'text/plain'});
+
+   // Send the response body "Hello World"
+   response.end('Hello World\n');
+}).listen(8000);
+
+// Print URL for accessing server
+console.log('Server running at http://127.0.0.1:8000/');
+ +

Node並不原生支持其他常見的web開發任務,如果你想為不同的HTTP方法(例如:GET, POST, DELETE等)增加特定的處理、替不同的URL路徑提供靜態檔案、使用樣板或動態性的產生response,你需要自己完成相關的程式或者是避免重新造輪子 - 使用web框架!

+ +

Express 是最受歡迎的Node web框架,還是其他許多流行的Node web框架的底層庫,它提供:

+ + + +

雖然Express本身非常簡單,但開發者們已經創造相容的中間層套件來解決大部份web開發的問題,這些套件能處理cookies, sessions,登入,URL參數,POST資料,安全標頭等等,你能在Express Middleware中找到這些套件的列表(以及其他流行的第三方套件)

+ +
+

注意: 這種靈活性是一把雙刃劍。有一些中間層套件能解決大部份的問題或需求,但使用正確的套件有時會是一個問題。也沒有「正確的方法」來創建應用,你在網路上找到的範例也並非都是最佳解或是只有開發上所需要做的一小部份。

+
+ +

歷史

+ +

2009年Node在Linux平台上初次發佈. 2010年NPM套件管利器發佈, 2012年增加Windows的原生支援. 現在的LTS版本為Node v8.11.2,最新版本為Node v10.1.0。這只是它深厚歷史的一小片斷,欲知更多詳情請洽 Wikipedia

+ +

2010年11月Express初次發佈,現在的API版本為 4.16。你可以查閱更新紀錄來了解此版本做了甚麼更改或是從GitHub中了解詳細的歷史紀錄。

+ +

Node/Express有多流行?

+ +

對於web 框架而言流行度很重要,這代表他會不會被繼續更新、文件、附加套件和技術支援方面有多少資源

+ +

現在沒有一個明確的指標來評斷伺服器端框架的流行度,雖然有 Hot Frameworks透過計算GitHub的專案數量和StackOverflow的問題來衡量流行度。更好的問題是,Node和Express是否「夠流行」以避免成為不流行的平台。有沒有持續進步?需要時是否能得到幫助?能不能找到Express相關的工作?

+ +

從眾多使用Express的公司、貢獻程式碼的人數和那些提供免費/收費支援的人員來看,是的!Express是一個流行的框架。

+ +

Is Express opinionated?

+ +

Web 框架通常自稱為 "opinionated" 或 "unopinionated".

+ +

Opinionated指的是那些有「正確」方法解決特定問題的框架。在特定的需求上他們通常能快速開發,因為正確的方法通常易懂且有良好的文件,然而在面對其他問題時則會失去靈活性。這類型的框架通常傾向於提供較少的選擇和套件來解決問題。

+ +

反過來說Unopinionated 框架,對於如何組合套件來解決問題尚有較少的限制,開發者可以更輕易的使用適當的套件來解決特定問題,儘管代價是你需要自己找到適合的套件。

+ +

Express是Unopinionated 框架,你可以在request處理流程中使用任何相容套件,使用單一或複數個檔案來建構應用,有時候甚至會覺得擁有太多選擇了。

+ +

Express的程式碼長怎樣?

+ +

傳統的資料驅動網站中,web應用程式會等待來自瀏覽器(或其他客戶端)的HTTP Request,接收到Request後根據URL和可能夾帶的POST/GET資料來決定需要回應什麼動作,根據需要可能對資料庫進行讀寫或執行滿足Request所需的其他任務。web應用程式會回應Response給瀏覽器,通常是藉由插入檢所到的資料到HTML 模板中動態產生HTML頁面讓瀏覽器顯示。

+ + + +

Express provides methods to specify what function is called for a particular HTTP verb (GET, POST, SET, etc.) and URL pattern ("Route"), and methods to specify what template ("view") engine is used, where template files are located, and what template to use to render a response. You can use Express middleware to add support for cookies, sessions, and users, getting POST/GET parameters, etc. You can use any database mechanism supported by Node (Express does not define any database-related behaviour).

+ +

The following sections explain some of the common things you'll see when working with Express and Node code.

+ +

Helloworld Express

+ +

First lets consider the standard Express Hello World example (we discuss each part of this below, and in the following sections).

+ +
+

Tip: If you have Node and Express already installed (or if you install them as shown in the next article), you can save this code in a text file called app.js and run it in a bash command prompt by calling:   

+ +

./node ./app.js

+
+ +
var express = require('express');
+var app = express();
+
+app.get('/', function(req, res) {
+  res.send('Hello World!');
+});
+
+app.listen(3000, function() {
+  console.log('Example app listening on port 3000!');
+});
+
+ +

The first two lines require() (import) the express module and create an Express application. This object, which is traditionally named app, has methods for routing HTTP requests, configuring middleware, rendering HTML views, registering a template engine, and modifying application settings that control how the application behaves (e.g. the environment mode, whether route definitions are case sensitive, etc.)

+ +

The middle part of the code (the three lines starting with app.get) shows a route definition. The app.get() method specifies a callback function that will be invoked whenever there is an HTTP GET request with a path ('/') relative to the site root. The callback function takes a request and a response object as arguments, and simply calls send() on the response to return the string "Hello World!"

+ +

The final block starts up the server on port '3000' and prints a log comment to the console. With the server running, you could go to localhost:3000 in your browser to see the example response returned.

+ +

Importing and creating modules

+ +

A module is a JavaScript library/file that you can import into other code using Node's require() function. Express itself is a module, as are the middleware and database libraries that we use in our Express applications.

+ +

The code below shows how we import a module by name, using the Express framework as an example. First we invoke the require() function, specifying the name of the module as a string ('express'), and calling the returned object to create an Express application. We can then access the properties and functions of the application object.

+ +
var express = require('express');
+var app = express();
+
+ +

You can also create your own modules that can be imported in the same way.

+ +
+

Tip: You will want to create your own modules, because this allows you to organise your code into managable parts — a monolithic single-file application is hard to understand and maintain. Using modules also helps you manage your namespace, because only the variables you explicitly export are imported when you use a module.

+
+ +

To make objects available outside of a module you just need to assign them to the exports object. For example, the square.js module below is a file that exports area() and perimeter() methods:

+ +
exports.area = function(width) { return width * width; };
+exports.perimeter = function(width) { return 4 * width; };
+
+ +

We can import this module using require(), and then call the exported method(s) as shown:

+ +
var square = require('./square'); // Here we require() the name of the file without the (optional) .js file extension
+console.log('The area of a square with a width of 4 is ' + square.area(4));
+ +
+

Note: You can also specify an absolute path to the module (or a name, as we did initially).

+
+ +

If you want to export a complete object in one assignment instead of building it one property at a time, assign it to module.exports as shown below (you can also do this to make the root of the exports object a constructor or other function):

+ +
module.exports = {
+  area: function(width) {
+    return width * width;
+  },
+
+  perimeter: function(width) {
+    return 4 * width;
+  }
+};
+
+ +

For a lot more information about modules see Modules (Node API docs).

+ +

Using asynchronous APIs

+ +

JavaScript code frequently uses asynchronous rather than synchronous APIs for operations that may take some time to complete. A synchronous API is one in which each operation must complete before the next operation can start. For example, the following log functions are synchronous, and will print the text to the console in order (First, Second).

+ +
console.log('First');
+console.log('Second');
+
+ +

By contrast, an asynchronous API is one in which the API will start an operation and immediately return (before the operation is complete). Once the operation finishes, the API will use some mechanism to perform additional operations. For example, the code below will print out "Second, First" because even though setTimeout() method is called first, and returns immediately, the operation doesn't complete for several seconds.

+ +
setTimeout(function() {
+   console.log('First');
+   }, 3000);
+console.log('Second');
+
+ +

Using non-blocking asynchronous APIs is even more important on Node than in the browser, because Node is a single threaded event-driven execution environment. "single threaded" means that all requests to the server are run on the same thread (rather than being spawned off into separate processes). This model is extremely efficient in terms of speed and server resources, but it does mean that if any of your functions call synchronous methods that take a long time to complete, they will block not just the current request, but every other request being handled by your web application.

+ +

There are a number of ways for an asynchronous API to notify your application that it has completed. The most common way is to register a callback function when you invoke the asynchronous API, that will be called back when the operation completes. This is the approach used above.

+ +
+

Tip: Using callbacks can be quite "messy" if you have a sequence of dependent asynchronous operations that must be performed in order, because this results in multiple levels of nested callbacks. This problem is commonly known as "callback hell". This problem can be reduced by good coding practices (see http://callbackhell.com/), using a module like async, or even moving to ES6 features like Promises.

+
+ +
+

Note: A common convention for Node and Express is to use error-first callbacks. In this convention the first value in your callback functions is an error value, while subsequent arguments contain success data. There is a good explanation of why this approach is useful in this blog: The Node.js Way - Understanding Error-First Callbacks (fredkschott.com).

+
+ +

Creating route handlers

+ +

In our Hello World Express example (see above), we defined a (callback) route handler function for HTTP GET requests to the site root ('/').

+ +
app.get('/', function(req, res) {
+  res.send('Hello World!');
+});
+
+ +

The callback function takes a request and a response object as arguments. In this case the method simply calls send() on the response to return the string "Hello World!" There are a number of other response methods for ending the request/response cycle, for example you could call res.json() to send a JSON response or res.sendFile() to send a file.

+ +
+

JavaScript tip: You can use any argument names you like in the callback functions; when the callback is invoked the first argument will always be the request and the second will always be the response. It makes sense to name them such that you can identify the object you're working with in the body of the callback.

+
+ +

The Express application object also provides methods to define route handlers for all the other HTTP verbs, which are mostly used in exactly the same way: post(), put(), delete(), options(), trace(), copy(), lock(), mkcol(), move(), purge(), propfind(), proppatch(), unlock(), report(), mkactivity(), checkout(), merge(), m-search(), notify(), subscribe(), unsubscribe(), patch(), search(), and connect().

+ +

There is a special routing method, app.all(), which will be called in response to any HTTP method. This is used for loading middleware functions at a particular path for all request methods. The following example (from the Express documentation) shows a handler that will be executed for requests to /secret irrespective of the HTTP verb used (provided it is supported by the http module).

+ +
app.all('/secret', function(req, res, next) {
+  console.log('Accessing the secret section ...');
+  next(); // pass control to the next handler
+});
+ +

Routes allow you to match particular patterns of characters in a URL, and extract some values from the URL and pass them as parameters to the route handler (as attributes of the request object passed as a parameter).

+ +

Often it is useful to group route handlers for a particular part of a site together and access them using a common route-prefix (e.g. a site with a Wiki might have all wiki-related routes in one file and have them accessed with a route prefix of /wiki/). In Express this is achieved by using the express.Router object. For example, we can create our wiki route in a module named wiki.js, and then export the Router object, as shown below:

+ +
// wiki.js - Wiki route module
+
+var express = require('express');
+var router = express.Router();
+
+// Home page route
+router.get('/', function(req, res) {
+  res.send('Wiki home page');
+});
+
+// About page route
+router.get('/about', function(req, res) {
+  res.send('About this wiki');
+});
+
+module.exports = router;
+
+ +
+

Note: Adding routes to the Router object is just like adding routes to the app object (as shown previously).

+
+ +

To use the router in our main app file we would then require() the route module (wiki.js), then call use() on the Express application to add the Router to the middleware handling path. The two routes will then be accessible from /wiki/ and /wiki/about/.

+ +
var wiki = require('./wiki.js');
+// ...
+app.use('/wiki', wiki);
+ +

We'll show you a lot more about working with routes, and in particular about using the Router, later on in the linked section Routes and controllers .

+ +

Using middleware

+ +

Middleware is used extensively in Express apps, for tasks from serving static files to error handling, to compressing HTTP responses. Whereas route functions end the HTTP request-response cycle by returning some response to the HTTP client, middleware functions typically perform some operation on the request or response and then call the next function in the "stack", which might be more middleware or a route handler. The order in which middleware is called is up to the app developer.

+ +
+

Note: The middleware can perform any operation, execute any code, make changes to the request and response object, and it can also end the request-response cycle. If it does not end the cycle then it must call next() to pass control to the next middleware function (or the request will be left hanging).

+
+ +

Most apps will use third-party middleware in order to simplify common web development tasks like working with cookies, sessions, user authentication, accessing request POST and JSON data, logging, etc. You can find a list of middleware packages maintained by the Express team (which also includes other popular 3rd party packages). Other Express packages are available on the NPM package manager.

+ +

To use third party middleware you first need to install it into your app using NPM. For example, to install the morgan HTTP request logger middleware, you'd do this:

+ +
$ npm install morgan
+
+ +

You could then call use() on the Express application object to add the middleware to the stack:

+ +
var express = require('express');
+var logger = require('morgan');
+var app = express();
+app.use(logger('dev'));
+...
+ +
+

Note: Middleware and routing functions are called in the order that they are declared. For some middleware the order is important (for example if session middleware depends on cookie middleware, then the cookie handler must be added first). It is almost always the case that middleware is called before setting routes, or your route handlers will not have access to functionality added by your middleware.

+
+ +

You can write your own middleware functions, and you are likely to have to do so (if only to create error handling code). The only difference between a middleware function and a route handler callback is that middleware functions have a third argument next, which middleware functions are expected to call if they are not that which completes the request cycle (when the middleware function is called, this contains the next function that must be called).

+ +

You can add a middleware function to the processing chain with either app.use() or app.add(), depending on whether you want to apply the middleware to all responses or to responses with a particular HTTP verb (GET, POST, etc). You specify routes the same in both cases, though the route is optional when calling app.use().

+ +

The example below shows how you can add the middleware function using both methods, and with/without a route.

+ +
var express = require('express');
+var app = express();
+
+// An example middleware function
+var a_middleware_function = function(req, res, next) {
+  // ... perform some operations
+  next(); // Call next() so Express will call the next middleware function in the chain.
+}
+
+// Function added with use() for all routes and verbs
+app.use(a_middleware_function);
+
+// Function added with use() for a specific route
+app.use('/someroute', a_middleware_function);
+
+// A middleware function added for a specific HTTP verb and route
+app.get('/', a_middleware_function);
+
+app.listen(3000);
+ +
+

JavaScript Tip: Above we declare the middleware function separately and then set it as the callback. In our previous route handler function we declared the callback function when it was used. In JavaScript, either approach is valid.

+
+ +

The Express documentation has a lot more excellent documentation about using and writing Express middleware.

+ +

Serving static files

+ +

You can use the express.static middleware to serve static files, including your images, CSS and JavaScript (static() is the only middleware function that is actually part of Express). For example, you would use the line below to serve images, CSS files, and JavaScript files from a directory named 'public' at the same level as where you call node:

+ +
app.use(express.static('public'));
+
+ +

Any files in the public directory are served by adding their filename (relative to the base "public" directory) to the base URL. So for example:

+ +
http://localhost:3000/images/dog.jpg
+http://localhost:3000/css/style.css
+http://localhost:3000/js/app.js
+http://localhost:3000/about.html
+
+ +

You can call static() multiple times to serve multiple directories. If a file cannot be found by one middleware function then it will simply be passed on to the subsequent middleware (the order that middleware is called is based on your declaration order).

+ +
app.use(express.static('public'));
+app.use(express.static('media'));
+
+ +

You can also create a virtual prefix for your static URLs, rather than having the files added to the base URL. For example, here we specify a mount path so that the files are loaded with the prefix "/media":

+ +
app.use('/media', express.static('public'));
+
+ +

Now, you can load the files that are in the public directory from the /media path prefix.

+ +
http://localhost:3000/media/images/dog.jpg
+http://localhost:3000/media/video/cat.mp4
+http://localhost:3000/media/cry.mp3
+
+ +

For more information, see Serving static files in Express.

+ +

Handling errors

+ +

Errors are handled by one or more special middleware functions that have four arguments, instead of the usual three: (err, req, res, next). For example:

+ +
app.use(function(err, req, res, next) {
+  console.error(err.stack);
+  res.status(500).send('Something broke!');
+});
+
+ +

These can return any content required, but must be called after all other app.use() and routes calls so that they are the last middleware in the request handling process!

+ +

Express comes with a built-in error handler, which takes care of any remaining errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack. If you pass an error to next() and you do not handle it in an error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace.

+ +
+

Note: The stack trace is not included in the production environment. To run it in production mode you need to set the the environment variable NODE_ENV to 'production'.

+
+ +
+

Note: HTTP404 and other "error" status codes are not treated as errors. If you want to handle these, you can add a middleware function to do so. For more information see the FAQ.

+
+ +

For more information see Error handling (Express docs).

+ +

Using databases

+ +

Express apps can use any database mechanism supported by Node (Express itself doesn't define any specific additional behaviour/requirements for database management). There are many options, including PostgreSQL, MySQL, Redis, SQLite, MongoDB, etc.

+ +

In order to use these you have to first install the database driver using NPM. For example, to install the driver for the popular NoSQL MongoDB you would use the command:

+ +
$ npm install mongodb
+
+ +

The database itself can be installed locally or on a cloud server. In your Express code you require the driver, connect to the database, and then perform create, read, update, and delete (CRUD) operations. The example below (from the Express documentation) shows how you can find "mammal" records using MongoDB.

+ +
//this works with older versions of  mongodb version ~ 2.2.33
+var MongoClient = require('mongodb').MongoClient;
+
+MongoClient.connect('mongodb://localhost:27017/animals', function(err, db) {
+  if (err) throw err;
+
+  db.collection('mammals').find().toArray(function (err, result) {
+    if (err) throw err;
+
+    console.log(result);
+  });
+});
+
+
+//for mongodb version 3.0 and up
+let MongoClient = require('mongodb').MongoClient;
+MongoClient.connect('mongodb://localhost:27017/animals', function(err, client){
+   if(err) throw err;
+
+   let db = client.db('animals');
+   db.collection('mammals').find().toArray(function(err, result){
+     if(err) throw err;
+     console.log(result);
+     client.close();
+   });
+}
+
+ + + + + + + +

Another popular approach is to access your database indirectly, via an Object Relational Mapper ("ORM"). In this approach you define your data as "objects" or "models" and the ORM maps these through to the underlying database format. This approach has the benefit that as a developer you can continue to think in terms of JavaScript objects rather than database semantics, and that there is an obvious place to perform validation and checking of incoming data. We'll talk more about databases in a later article.

+ +

For more information see Database integration (Express docs).

+ +

Rendering data (views)

+ +

Template engines (referred to as "view engines" by Express) allow you to specify the structure of an output document in a template, using placeholders for data that will be filled in when a page is generated. Templates are often used to create HTML, but can also create other types of documents. Express has support for a number of template engines, and there is a useful comparison of the more popular engines here: Comparing JavaScript Templating Engines: Jade, Mustache, Dust and More.

+ +

In your application settings code you set the template engine to use and the location where Express should look for templates using the 'views' and 'view engines' settings, as shown below (you will also have to install the package containing your template library too!)

+ +
var express = require('express');
+var app = express();
+
+// Set directory to contain the templates ('views')
+app.set('views', path.join(__dirname, 'views'));
+
+// Set view engine to use, in this case 'some_template_engine_name'
+app.set('view engine', 'some_template_engine_name');
+
+ +

The appearance of the template will depend on what engine you use. Assuming that you have a template file named "index.<template_extension>" that contains placeholders for data variables named 'title' and "message", you would call Response.render() in a route handler function to create and send the HTML response:

+ +
app.get('/', function(req, res) {
+  res.render('index', { title: 'About dogs', message: 'Dogs rock!' });
+});
+ +

For more information see Using template engines with Express (Express docs).

+ +

File structure

+ +

Express makes no assumptions in terms of structure or what components you use. Routes, views, static files, and other application-specific logic can live in any number of files with any directory structure. While it is perfectly possible to have the whole Express application in one file, typically it makes sense to split your application into files based on function (e.g. account management, blogs, discussion boards) and architectural problem domain (e.g. model, view or controller if you happen to be using an MVC architecture).

+ +

In a later topic we'll use the Express Application Generator, which creates a modular app skeleton that we can easily extend for creating web applications.

+ + + +

總結

+ +

恭喜,您已完成 Express / Node之旅的第一步!您現在應該了解 Express 和 Node 的主要優點,以及 Express 應用程序的主要部分(路由,中間件,錯誤處理和模板代碼)。您還應該明白,Express 是一個不固執己見的框架,您將這些組件組合在一起的方式以及您使用的函式庫,在很大程度上取決於您!

+ +

當然,Express是一個非常輕量級的 Web 應用程序框架,它的許多好處和潛力來自第三方函式庫和功能。我們將在以下文章中更詳細地介紹這些內容。在下一篇文章中,我們將介紹如何設置 Node 開發環境,以便您可以開始查看一些 Express 代碼。

+ +

See also

+ + + +
{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}
+ +

In this module

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/mongoose/index.html b/files/zh-tw/learn/server-side/express_nodejs/mongoose/index.html new file mode 100644 index 0000000000..8541c1c37c --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/mongoose/index.html @@ -0,0 +1,792 @@ +--- +title: 'Express 教學 3: 使用資料庫 ( Mongoose)' +slug: Learn/Server-side/Express_Nodejs/mongoose +translation_of: Learn/Server-side/Express_Nodejs/mongoose +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}
+ +

本文簡短介紹數據庫,以及如何搭配 Node / Express 應用,使用數據庫。接下來會演示我們如何使用 Mongoose,為本地圖書館提供數據庫存取。本文說明物件要求與模型如何宣告,主要的欄位型態,以及基本驗證。本文也簡短演示一些存取模型數據的主要方法。

+ + + + + + + + + + + + +
前置條件:Express 教學 2: 創建一個骨架網站
目標:能夠使用Mongoose設計並創造自己的模型。
+ +

概覽

+ +

圖書館職員會使用本地圖書館網站,存放書本和借書者訊息。圖書館使用者會用網站瀏覽與尋找書本,看看是否有可以藉閱的書本複本,然後預約或者藉閱。為了有效率地存放與取用訊息,我們將把它存放到數據庫。

+ +

Express 應用可以使用許多不同的數據庫,並且有好幾種方法可以執行創建 Create、讀取 Read、更新 Update 和刪除 Delete (CRUD) 操作。本教程為一些可用的選項,提供簡短的概覽,然後接著詳細演示該選項的特定運行機制。

+ +

我可以使用什麼數據庫?

+ +

Express 應用程序可以使用 Node 支持的任何數據庫(Express 本身不會為數據庫管理,定義任何特定的附加行為/要求)。有許多流行的選項,包括 PostgreSQL,MySQL,Redis,SQLite 和 MongoDB。

+ +

在選擇數據庫時,您應該考慮時間 - 生產力/學習曲線,性能,易複製/備份,成本,社區支持等等。雖然沒有單一的 “最佳” 數據庫,但幾乎任何流行的解決方案,我們的本地圖書館這樣的中小型網站,應該都可以接受。

+ +

有關選項的更多訊息,請參閱:數據庫集成(Express docs)

+ +

與數據庫互動的最好方式是什麼?

+ +

有兩種與數據庫互動的方法:

+ + + +

通過使用 SQL 或數據庫支持的任何查詢語言,都可以獲得最佳性能。 ODM通常比較慢,因為它們使用翻譯代碼,在對象和數據庫格式之間進行映射,這可能不會使用最有效的數據庫查詢(尤其是如果ODM支持不同的數據庫後端,並且必須在各個數據庫所支持的功能方面,做出更大的折衷)。

+ +

使用 ORM 的好處是,程序員可以繼續用 JavaScript 對象而不是數據庫語義來思考 — 如果您需要使用不同數據庫(在相同或不同的網站上),那麼尤其如此。他們還提供了一個明顯的地方來執行數據驗證和檢查。

+ +
+

提示:  使用ODM / ORM通常可以降低開發和維護成本!除非您非常熟悉本地查詢語言,或者性能對您至關重要,否則您應該強烈考慮使用 ODM。

+
+ +

我應該使用哪個 ORM/ODM ?

+ +

NPM 套件管理器站點上,有許多ODM / ORM 解決方案(查看 odmorm 標籤的子集合!)。

+ +

在撰寫本文時,受歡迎的幾種解決方案是:   

+ + + +

一般來說,在選擇解決方案時,您應該考慮提供的功能和 “社區活動” (下載,貢獻,錯誤報告,文檔質量等)。在撰寫本文時,Mongoose 是迄今為止最受歡迎的 ODM,如果您將MongoDB 用於你的數據庫,那麼它是一個合理的選擇。

+ +

在本地圖書館使用 Mongoose 和 MongoDb

+ +

對於本地圖書館示例(以及本主題的其餘部分),我們將使用 Mongoose ODM 來訪問我們的圖書館數據。 Mongoose 是 MongoDB 的前端,MongoDB 是一個使用面向文檔數據模型的開源 NoSQL 數據庫。在 MongoDB 數據庫中,“文檔” 的 “集合” ,類似於關係數據庫中 “行” 的 “表”。

+ +

這種 ODM 和數據庫的結合在 Node 社區中非常流行,部分原因是文檔存儲和查詢系統,看起來非常像 JSON,因此對 JavaScript 開發人員來說很熟悉。

+ +
+

提示: 使用 Mongoose 時,您不需要事先了解 MongoDB,但是如果您已經熟悉 MongoDB,Mongoose documentation 文檔的一部分會更易於使用和理解。

+
+ +

本教程的其餘部分,將介紹如何為 本地圖書館網站示例,定義和訪問Mongoose 模式和模型。

+ +

設計本地圖書館的模型

+ +

在您開始編寫模型之前,花幾分鐘的時間思考,我們需要儲存的數據以及不同對象之間的關係。

+ +

我們知道,我們需要儲存有關書籍的訊息(標題,摘要,作者,種類,國際標準書號),以及我們可能有多個副本可用(具有全域唯一ID,可用狀態等)。我們可能需要存儲有關作者的更多訊息,而不僅僅是他們的名字,並且可能有多個作者,具有相同或相似的名稱。我們希望能夠根據書名,作者,種類和類別對訊息進行分類。

+ +

在設計模型時,對於每個“對象”(相關訊息組)都有獨立的模型,是有意義的。在這種情況下,明顯的對像是書籍,書籍實例和作者。

+ +

您可能還希望,使用模型來表示選擇列表選項(例如,選擇的下拉列表),而不是將選項硬編碼到網站本身— 在無法預先知道所有選項,或者可能更改時,更建議使用模型來表示。很明顯的,書本類型是這種模型的可能人選(例如科幻小說,法國詩歌等)。

+ +

一旦我們決定了我們的模型和字段,我們就需要考慮它們之間的關係。

+ +

考慮到這一點,下面的UML關聯圖,顯示了我們在這種情況下定義的模型(一個框對應一個模型)。如上所述,我們創建了以下模型,圖書(本書的通用細節),書本實例(系統中可用圖書的特定實際副本的狀態)和作者。我們還決定建立一個種類模型,以便可以動態創建它的值,而不是將下拉選項硬編碼。我們已經決定不為書本實例:狀態BookInstance:status建立模型—我們將硬編碼可接受的值,因為我們不希望這些值發生變化。在下圖每個框中,您可以看到模型名稱,字段名稱和類型,以及方法及其返回類型。

+ +

下圖還顯示了模型之間的關係,包括它們的多重性。多重性是圖中顯示可能存在於關係中的每個模型的數量(最大值和最小值)的數字。例如,框之間的連接線,顯示書本Book和種類Genre是相關的。靠近書本Book模型的數字,表明一本書必須有零個或多個種類(您想要多少都可以),而種類Genre旁邊一行的數字,表明它可以有零個或多個相關書籍。

+ +
+

注意: 正如我們在下面的Mongoose入門中所討論的那樣,通常只需要在一個模型中定義文檔/模型之間關係的字段(通過在另一個模型中搜索相關的_id仍然可以找到反向關係)。下面我們選擇在書本綱要(Book schema)中定義Book/Genre和Book/Author之間的關係,以及書本實例綱要(BookInstance Schema)中Book/BookInstance之間的關係。這種選擇有點武斷—我們同樣可以在其他綱要中擁有該字段。

+
+ +

Mongoose Library Model  with correct cardinality

+ +
+

注意 :下一節提供了一個基本的入門知識,解釋如何定義和使用模型。在您閱讀它時,請想想我們將如何構建上圖中的每個模型。

+
+ +

Mongoose入門

+ +

本節概述如何將Mongoose 連接到MongoDB 數據庫,如何定義模型綱要和模型,以及如何進行基本查詢。

+ +
+

注意:本入門受到npm上的Mongoose快速入門Mongoose官方文檔的“深度影響”。

+
+ +

安裝Mongoose和MongoDB

+ +

Mongoose像任何其他依賴項一樣,安裝在您的項目(package.json)中—使用NPM。要安裝它,請在項目文件夾中,使用以下命令:

+ +
npm install mongoose
+
+ +

安裝Mongoose會添加所有依賴項,包括MongoDB數據庫驅動程序,但它不會安裝MongoDB 。如果你想安裝一個MongoDB服務器,那麼你可以從這裡下載各種操作系統的安裝程序,並在本地安裝。您還可以使用基於雲端的MongoDB實例。

+ +
+

注意:對於本教程,我們將使用基於mLab雲的數據庫,作為服務沙箱層來提供數據庫。這適用於開發,也對於本教程很有意義,因為它使“安裝”與操作系統無關(數據庫即服務,也是您可能會用於生產環境數據庫的一種方法)。

+
+ +

連接到MongoDB

+ +

Mongoose需要連接到MongoDB數據庫。您可以require()並使用mongoose.connect(),以連接到本地託管的數據庫,如下所示。

+ +
//Import the mongoose module
+var mongoose = require('mongoose');
+
+//Set up default mongoose connection
+var mongoDB = 'mongodb://127.0.0.1/my_database';
+mongoose.connect(mongoDB);
+// Get Mongoose to use the global promise library
+mongoose.Promise = global.Promise;
+//Get the default connection
+var db = mongoose.connection;
+
+//Bind connection to error event (to get notification of connection errors)
+db.on('error', console.error.bind(console, 'MongoDB connection error:'));
+ +

您可以使用mongoose.connection獲取默認的Connection對象。一旦連接,在Connection實例上,將觸發打開事件。

+ +
+

提示:如果需要創建其他連接,可以使用mongoose.createConnection()這與connect()採用相同形式的數據庫URI(包含主機,數據庫,端口,選項等),並返回Connection對象。

+
+ +

定義並創建模型

+ +

模型使用Schema接口進行定義。Schema允許您定義存儲在每個文檔中的字段,及其驗證要求和默認值。此外,您可以定義靜態和實例助手方法,以更輕鬆地處理數據類型,以及可以像其他任何字段一樣使用的虛擬屬性,但實際上並不存儲在數據庫中(我們稍後將討論)。

+ +

然後,綱要Schemas被mongoose.model()方法“編譯”為模型。擁有模型後,您可以使用它來查找,創建,更新和刪除給定類型的對象。

+ +
+

注意:每個模型都映射到MongoDB數據庫中的文檔集合。這些文檔將包含模型綱要Schema中定義的字段/綱要型態。

+
+ +

定義綱要Schemas

+ +

下面的代碼片段,顯示了您可以如何定義一個簡單的綱要。首先require()mongoose,然後使用Schema構造函數,創建一個新的Schema實例,在構造函數的對象參數中,定義其中的各個字段。

+ +
//Require Mongoose
+var mongoose = require('mongoose');
+
+//Define a schema
+var Schema = mongoose.Schema;
+
+var SomeModelSchema = new Schema({
+    a_string: String,
+    a_date: Date
+});
+
+ +

在上面的例子中,我們只有兩個字段,一個字符串和一個日期。在接下來的部分中,我們將展示一些其他的字段類型,驗證和其他方法。

+ +

創建模型

+ +

使用mongoose.model()方法從綱要創建模型:

+ +
// Define schema
+var Schema = mongoose.Schema;
+
+var SomeModelSchema = new Schema({
+    a_string: String,
+    a_date: Date
+});
+
+// Compile model from schema
+var SomeModel = mongoose.model('SomeModel', SomeModelSchema );
+ +

第一個參數,是將為模型創建的集合的單數名稱(Mongoose將為上面的SomeModel模型,創建數據庫集合),第二個參數,是您要在創建模型時使用的綱要Shema。

+ +
+

注意:定義模型類後,可以使用它們來創建,更新或刪除記錄,並運行查詢,以獲取記錄的所有記錄,或特定子集。我們將在以下“使用模型”部分,向您展示如何執行上述操作,以及當創建視圖時,如何執行此操作。

+
+ +

綱要型態(字段)

+ +

綱要schema可以有任意數量的字段 — 每個字段代表存儲在MongoDB 文檔中的字段。如下的示例綱要,顯示許多常見字段類型及其聲明方式。

+ +
var schema = new Schema(
+{
+  name: String,
+  binary: Buffer,
+  living: Boolean,
+  updated: { type: Date, default: Date.now },
+  age: { type: Number, min: 18, max: 65, required: true },
+  mixed: Schema.Types.Mixed,
+  _someId: Schema.Types.ObjectId,
+  array: [],
+  ofString: [String], // You can also have an array of each of the other types too.
+  nested: { stuff: { type: String, lowercase: true, trim: true } }
+})
+ +

大多數綱要型態SchemaTypes(“type:”之後或字段名稱之後的描述符)都是自解釋的。例外情況是:

+ + + +

該代碼還顯示了聲明一個字段的兩種方式:

+ + + +

有關選項的更多訊息,請參閱SchemaTypes(Mongoose docs)。

+ +

驗證

+ +

Mongoose 提供內置和自定義驗證器,以及同步和異步驗證器。它允許您在所有情況下,指定可接受的範圍或值,以及驗證失敗的錯誤消息。

+ +

內置的驗證器包括:

+ + + +

下面的示例(從Mongoose文檔稍微修改)顯示瞭如何指定一些驗證器類型和錯誤消息:

+ +

+    var breakfastSchema = new Schema({
+      eggs: {
+        type: Number,
+        min: [6, 'Too few eggs'],
+        max: 12
+        required: [true, 'Why no eggs?']
+      },
+      drink: {
+        type: String,
+        enum: ['Coffee', 'Tea', 'Water',]
+      }
+    });
+
+ +

有關字段驗證的完整訊息,請參閱驗證(Mongoose docs)。

+ +

虛擬屬性

+ +

虛擬屬性是您可以獲取和設置的文檔屬性,但不會持久保存到MongoDB。getter 對格式化或組合字段非常有用,而setter 可用於將單個值分解為多個值,以進行存儲。

+ +

文檔中的示例,從名字和姓氏字段構造(並解構)一個全名虛擬屬性,這比每次在模板中使用全名更簡單,更清晰。

+ +
+

注意:我們將使用庫中的虛擬屬性,來為每個使用路徑和記錄的_id值的模型記錄,定義唯一的URL。

+
+ +

欲了解更多訊息,請參閱虛擬(Mongoose文檔)。

+ +

方法和查詢幫助

+ +

綱要schema也可以有實例方法靜態方法查詢助手實例和靜態方法很相似,但有明顯的區別,即實例方法與特定記錄相關聯,並且可以訪問當前對象。查詢助手允許您擴展mongoose的鍊式查詢構建器API(例如,除了find(), findOne()findById()方法外,還允許您添加一個“byName”查詢。

+ +

使用模型

+ +

一旦創建了綱要,就可以使用它來創建模型。該模型代表數據庫中可以搜索的文檔集合,而模型的實例代表您可以保存和檢索的單個文檔。

+ +

我們在下面簡要介紹一下。有關更多訊息,請參閱:模型(Mongoose docs)。

+ +

創建和修改文檔

+ +

要創建記錄,您可以定義模型的實例,然後調用save()下面的例子假設,SomeModel是我們從綱要創建的模型(帶有單一字段“name” )。

+ +
// Create an instance of model SomeModel
+var awesome_instance = new SomeModel({ name: 'awesome' });
+
+// Save the new model instance, passing a callback
+awesome_instance.save(function (err) {
+  if (err) return handleError(err);
+  // saved!
+});
+
+ +

創建記錄(以及更新,刪除和查詢)是異步操作— 您提供在操作完成時調用的回調。API使用錯誤優先參數約定,因此回調的第一個參數將始終為錯誤值(或null)。如果API返回一些結果,則將作為第二個參數提供。

+ +

您還可以使用create(),同時定義模型實例,並保存模型實例。回調將為第一個參數返回錯誤,為第二個參數返回新創建的模型實例。

+ +
SomeModel.create({ name: 'also_awesome' }, function (err, awesome_instance) {
+  if (err) return handleError(err);
+  // saved!
+});
+ +

每個模型都有一個關聯的連接(當您使用mongoose.model()時,這將成為默認連接)。您創建一個新連接並調用.model(),以在另一個數據庫上創建文檔。

+ +

您可以使用點語法訪問此新記錄中的字段,並更改值。您必須調用save()update(),將修改的值存回數據庫。

+ +
// Access model field values using dot notation
+console.log(awesome_instance.name); //should log 'also_awesome'
+
+// Change record by modifying the fields, then calling save().
+awesome_instance.name="New cool name";
+awesome_instance.save(function (err) {
+   if (err) return handleError(err); // saved!
+   });
+
+ +

尋找紀錄

+ +

可以使用查詢方法搜索記錄,將查詢條件指定為JSON 文檔。下面的代碼片段,顯示瞭如何在數據庫中,找到所有參加網球運動的運動員,只返回運動員姓名和年齡的字段。這裡我們只指定一個匹配的字段(運動 sport),但您可以添加更多條件,指定正則表達式標準,或完全刪除條件以返回所有運動員。

+ +
var Athlete = mongoose.model('Athlete', yourSchema);
+
+// find all athletes who play tennis, selecting the 'name' and 'age' fields
+Athlete.find({ 'sport': 'Tennis' }, 'name age', function (err, athletes) {
+  if (err) return handleError(err);
+  // 'athletes' contains the list of athletes that match the criteria.
+})
+ +

如果您指定回調,如上所示,查詢將立即執行。搜索完成後將調用回調。

+ +
+

注意: Mongoose中的所有回調,都使用此回調模式callback(error, result)如果執行查詢時發生錯誤,錯誤參數error將包含錯誤文檔,並且結果result將為null。如果查詢成功,則error參數將為null,並且結果result 將被填充到查詢結果。

+
+ +

如果您未指定回調,則API將返回Query類型的變量。您可以使用此查詢對象來構建查詢,然後稍後使用exec()方法執行(使用回調)。

+ +
// find all athletes that play tennis
+var query = Athlete.find({ 'sport': 'Tennis' });
+
+// selecting the 'name' and 'age' fields
+query.select('name age');
+
+// limit our results to 5 items
+query.limit(5);
+
+// sort by age
+query.sort({ age: -1 });
+
+// execute the query at a later time
+query.exec(function (err, athletes) {
+  if (err) return handleError(err);
+  // athletes contains an ordered list of 5 athletes who play Tennis
+})
+ +

上面我們在find()方法中,定義了查詢條件。我們也可以使用where()函數來執行此操作,並且我們可以使用點運算符( . )將查詢的所有部分鏈接在一起,而不是分別添加它們。

+ +

下面的代碼片段,與我們上面的查詢相同,並有年齡的附加條件。

+ +
Athlete.
+  find().
+  where('sport').equals('Tennis').
+  where('age').gt(17).lt(50).  //Additional where query
+  limit(5).
+  sort({ age: -1 }).
+  select('name age').
+  exec(callback); // where callback is the name of our callback function.
+ +

find()  方法獲取所有匹配的記錄,但通常你只想獲得一個匹配。以下方法可以查詢單個記錄:

+ + + +
+

注意:還有一個count()方法,您可以使用它來獲取與條件匹配的項目數。如果您想要在不實際提取記錄的情況下執行計數,這非常有用。

+
+ +

查詢可以做更多的事情。有關更多訊息,請參閱:查詢(Mongoose文檔)。

+ +

運用相關文檔— population方法

+ +

您可以使用ObjectId綱要字段,從一個文檔/模型實例,創建一對一引用,或者使用ObjectIds數組,從一個文檔創建一對多的引用。該字段存儲相關模型的ID。如果需要關聯文檔的實際內容,可以在查詢中使用populate()方法,將id替換為實際數據。

+ +

例如,以下綱要定義作者和故事。每個作者可以有多個故事,我們將其表示為一個ObjectId數組。每個故事可以有一個作者。綱要從“ref”(以粗體突出顯示)得知,可以分配給該字段的模型。

+ +
var mongoose = require('mongoose')
+  , Schema = mongoose.Schema
+
+var authorSchema = Schema({
+  name    : String,
+  stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
+});
+
+var storySchema = Schema({
+  author : { type: Schema.Types.ObjectId, ref: 'Author' },
+  title    : String
+});
+
+var Story  = mongoose.model('Story', storySchema);
+var Author = mongoose.model('Author', authorSchema);
+ +

我們可以通過分配_id值,來保存對相關文檔的引用。下面我們創建一個作者,然後創建一個故事,並將作者ID分配給我們的故事作者字段。

+ +
var bob = new Author({ name: 'Bob Smith' });
+
+bob.save(function (err) {
+  if (err) return handleError(err);
+
+  //Bob now exists, so lets create a story
+  var story = new Story({
+    title: "Bob goes sledding",
+    author: bob._id    // assign the _id from the our author Bob. This ID is created by default!
+  });
+
+  story.save(function (err) {
+    if (err) return handleError(err);
+    // Bob now has his story
+  });
+});
+ +

我們的故事文檔,現在有作者文檔ID引用的作者。為了在我們的故事結果中,獲取作者訊息,我們使用populate(),如下所示。

+ +
Story
+.findOne({ title: 'Bob goes sledding' })
+.populate('author') //This populates the author id with actual author information!
+.exec(function (err, story) {
+  if (err) return handleError(err);
+  console.log('The author is %s', story.author.name);
+  // prints "The author is Bob Smith"
+});
+ +
+

注意:敏銳的讀者會注意到,我們在故事中添加了作者,但我們沒有做任何事情,來將我們的故事添加到作者的故事stories數組中。那麼我們怎樣才能得到特定作者的所有故事?

+ +

一種方法,是將作者添加到故事數組中,但這會導致我們需要在兩個地方,維護與作者和故事有關的訊息。更好的方法是獲取作者的_id,然後使用find(),在所有故事的作者字段中搜索此內容。

+ +
Story
+.find({ author : bob._id })
+.exec(function (err, stories) {
+  if (err) return handleError(err);
+  // returns all stories that have Bob's id as their author.
+});
+
+
+ +

這幾乎是您在本教程中,使用相關項目時,需要了解的所有內容。有關更多詳細訊息,請參閱Population(Mongoose docs)。

+ +

一個檔案對應一個綱要/模型

+ +

雖然您可以使用任何喜歡的文件結構創建綱要和模型,但我們強烈建議在每個模型模塊(文件)中,定義每個模型綱要,導出方法以創建模型。如下所示:

+ +
// File: ./models/somemodel.js
+
+//Require Mongoose
+var mongoose = require('mongoose');
+
+//Define a schema
+var Schema = mongoose.Schema;
+
+var SomeModelSchema = new Schema({
+    a_string          : String,
+    a_date            : Date,
+});
+
+//Export function to create "SomeModel" model class
+module.exports = mongoose.model('SomeModel', SomeModelSchema );
+ +

然後,您可以在其他文件中,立即要求並使用該模型。下面我們展示如何使用它,來獲取模型的所有實例。

+ +
//Create a SomeModel model just by requiring the module
+var SomeModel = require('../models/somemodel')
+
+// Use the SomeModel object (model) to find all SomeModel records
+SomeModel.find(callback_function);
+ +

架設MongoDB數據庫

+ +

現在我們了解了Mongoose能做什麼,以及我們想如何設計我們的模型,現在該開始在LocalLibrary網站上工作了。我們想要做的第一件事,就是設置一個MongoDb數據庫,我們可以使用它來儲存我們的圖書館數據。

+ +

本教程,我們將使用mLab免費的雲託管的“ 沙盒 ”數據庫。這個數據庫層不適合生產環境的網站,因為它沒有冗餘設計,但它對於開發和原型設計來說非常有用。我們在這裡使用它,是因為它免費且易於設置,並且因為作為數據庫服務供應商來說,mLab是流行的數據庫選擇之一,您可能會合理選擇您的生產環境數據庫(撰寫本文時,其他流行的選擇包括ComposeScaleGridMongoDB Atlas)。

+ +
+

注意:如果您願意,可以下載並安裝與系統相對應的二進製文件,在本地設置MongoDb數據庫。除了您在連接時指定的數據庫URL之外,本文中的其餘指令將很類似。

+
+ +

您首先需要使用mLab創建一個賬戶(這是免費的,只需要輸入基本聯繫訊息,並確認其服務條款)。

+ +

登錄後,您將進入mLab主畫面:

+ +
    +
  1. 單擊MongoDB Deployments部分中的Create New。
  2. +
  3. 這將打開“雲提供商”Cloud Provider 選擇畫面。
    + MLab - screen for new deployment
    + +
      +
    • 從“計劃類型”Plan Type 部分中,選擇“SANDBOX(免費)”計劃。
    • +
    • 從“雲提供商” Cloud Provider部分,選擇任意提供商。不同的提供商,提供不同的地區(顯示在選定的計劃類型下面)。
    • +
    • 單擊“繼續” Continue按鈕。
    • +
    +
  4. +
  5. 這將打開“選擇區域” Select Region 畫面。 +

    Select new region screen

    + +
      +
    • +

      選擇離您最近的地區,然後選擇繼續Continue .

      +
    • +
    +
  6. +
  7. +

    這將打開 Final Details 畫面
    + New deployment database name

    + +
      +
    • +

      輸入新數據庫的名稱local_library,然後選擇繼續Continue

      +
    • +
    +
  8. +
  9. +

    這將打開訂單確認畫面。
    + Order confirmation screen

    + +
      +
    • +

      單擊“提交訂單” Submit Order以創建數據庫。

      +
    • +
    +
  10. +
  11. +

    您將返回到主畫面。單擊剛剛創建的新數據庫,以打開其詳細訊息畫面。正如你所看到的,數據庫沒有集合(數據)。
    + mLab - Database details screen
    +  您需要用來訪問數據庫的URL,顯示在上面的表單中(如上圖所示)。為了使用它,您需要創建一個可以在URL中指定的數據庫用戶。

    +
  12. +
  13. 單擊用戶Users選項卡,並選擇添加數據庫用戶按鈕Add database user
  14. +
  15. 輸入用戶名和密碼(兩次),然後按創建Create不要選擇只讀read-only
    +
  16. +
+ +

您現在已經創建了數據庫,並且有一個可以用來訪問它的URL(帶有用戶名和密碼)。這看起來像是這樣的:mongodb://your_user_namer:your_password@ds119748.mlab.com:19748/local_library.

+ +

安裝 Mongoose

+ +

打開命令提示符,並到您創建本地圖書館骨架網站的目錄。輸入以下命令,安裝Mongoose(及其依賴項),並將其添加到您的package.json文件中,除非您在閱讀上述Mongoose入門時,已經這樣做了。

+ +
npm install mongoose
+
+ +

連接到 MongoDB

+ +

打開/app.js(位於項目的根目錄),並在宣告Express應用程序對象的位置(在var app = express();之後)複製以下文本。將數據庫url字符串('insert_your_database_url_here')替換為表示您自己的數據庫的位置URL(即是使用來自上面mLab的訊息)。

+ +
//Set up mongoose connection
+var mongoose = require('mongoose');
+var mongoDB = 'insert_your_database_url_here';
+mongoose.connect(mongoDB);
+mongoose.Promise = global.Promise;
+var db = mongoose.connection;
+db.on('error', console.error.bind(console, 'MongoDB connection error:'));
+ +

正如上面的Mongoose入門中所討論的,此代碼創建了與數據庫的默認連接,並綁定到錯誤事件(以便將錯誤打印到控制台)。

+ +

定義本地圖書館綱要

+ +

如上所述,我們將為每個模型定義一個單獨的模塊。首先在項目根目錄(/models)中,為我們的模型創建一個文件夾,然後為每個模型創建單獨的文件:

+ +
/express-locallibrary-tutorial  //the project root
+  /models
+    author.js
+    book.js
+    bookinstance.js
+    genre.js
+
+ +

作者模型

+ +

複製下面顯示的Author作者綱要代碼,並將其粘貼到./models/author.js文件中。該綱要定義了一個作者,具有StringSchemaTypes的第一個名稱和家族名稱,這是必需的,最多有100個字符,Date字段為出生和死亡日期。

+ +
var mongoose = require('mongoose');
+
+var Schema = mongoose.Schema;
+
+var AuthorSchema = new Schema(
+  {
+    first_name: {type: String, required: true, max: 100},
+    family_name: {type: String, required: true, max: 100},
+    date_of_birth: {type: Date},
+    date_of_death: {type: Date},
+  }
+);
+
+// Virtual for author's full name
+AuthorSchema
+.virtual('name')
+.get(function () {
+  return this.family_name + ', ' + this.first_name;
+});
+
+// Virtual for author's URL
+AuthorSchema
+.virtual('url')
+.get(function () {
+  return '/catalog/author/' + this._id;
+});
+
+//Export model
+module.exports = mongoose.model('Author', AuthorSchema);
+
+
+ +

我們還為AuthorSchema,聲明了一個名為“url”的虛擬屬性,它返回獲取模型的特定實例所需的絕對URL — 每當我們需要獲取指向特定作者的鏈接時,我們將在模板中使用該屬性。

+ +
+

注意:在綱要中聲明我們的URL是虛擬的,這是一個好主意,因為一個項目的URL只需要在一個地方更改。此時,使用此URL的鏈接將不起作用,因為我們還沒有任何路由,可以處理個別模型實例的代碼。我們將在後面的文章中介紹這些內容!

+
+ +

在模塊的最後,我們導出了模型。

+ +

書本模型

+ +

複製下面顯示的Book綱要代碼,並將其粘貼到./models/book.js文件中。其中大部分與作者模型相似—我們已經聲明了一個具有多個字符串字段的綱要,以及一個虛擬屬性,用於獲取特定書籍記錄的URL,並且我們已經導出了模型。

+ +
var mongoose = require('mongoose');
+
+var Schema = mongoose.Schema;
+
+var BookSchema = new Schema(
+  {
+    title: {type: String, required: true},
+    author: {type: Schema.Types.ObjectId, ref: 'Author', required: true},
+    summary: {type: String, required: true},
+    isbn: {type: String, required: true},
+    genre: [{type: Schema.Types.ObjectId, ref: 'Genre'}]
+  }
+);
+
+// Virtual for book's URL
+BookSchema
+.virtual('url')
+.get(function () {
+  return '/catalog/book/' + this._id;
+});
+
+//Export model
+module.exports = mongoose.model('Book', BookSchema);
+
+ +

這裡的主要區別,是我們已經創建了兩個對其他模型的引用:

+ + + +

書本實例模型

+ +

最後,複製下面顯示的BookInstance綱要代碼,並將其粘貼到./models/bookinstance.js文件中。BookInstance表示某人可能藉閱的書籍的特定副本,並包含有關該副本是否可用,或預期返回日期的訊息,“印記”或版本詳細訊息。

+ +
var mongoose = require('mongoose');
+
+var Schema = mongoose.Schema;
+
+var BookInstanceSchema = new Schema(
+  {
+    book: { type: Schema.Types.ObjectId, ref: 'Book', required: true }, //reference to the associated book
+    imprint: {type: String, required: true},
+    status: {type: String, required: true, enum: ['Available', 'Maintenance', 'Loaned', 'Reserved'], default: 'Maintenance'},
+    due_back: {type: Date, default: Date.now}
+  }
+);
+
+// Virtual for bookinstance's URL
+BookInstanceSchema
+.virtual('url')
+.get(function () {
+  return '/catalog/bookinstance/' + this._id;
+});
+
+//Export model
+module.exports = mongoose.model('BookInstance', BookInstanceSchema);
+ +

我們在這裡展示的新東西,是字段選項:

+ + + +

其他所有內容,大夥應該在前面教程裡邊已經熟悉了。

+ +

種類模型-自我挑戰!

+ +

打開你的./models/genre.js文件,並創建一個存儲類型的綱要(書本的類別,例如它是小說還是非小說,浪漫史或軍事歷史等)。

+ +

該定義將與其他模型非常相似:

+ + + +

測試—創建一些項目

+ +

就是這樣。我們現在已經為該網站建立了所有模型!

+ +

為了測試這些模型(並創建一些示例書籍,和其他項目以便於我們在後面文章使用),現在我們將運行一個獨立的腳本來創建每種類型的項目:

+ +
    +
  1. 在express-locallibrary-tutorial目錄下(與package.json處於同一級別),下載(或以其他方式創建)文件populatedb.js + +
    +

    注意:您不需要知道populatedb.js的工作原理;它只是將示例數據添加到數據庫中。

    +
    +
  2. +
  3. 在項目根目錄中,輸入以下命令,以安裝腳本所需的異步模塊(我們將在後面的教程中討論這一點) +
    npm install async
    +
  4. +
  5. 在命令提示符下,使用node運行此腳本,傳遞MongoDB數據庫的URL(與之前在app.js中替換insert_your_database_url_here佔位符的那個相同): +
    node populatedb <your mongodb url>​​​​
    +
  6. +
  7. 該腳本應一路運行至完成,並在終端中創建它們時顯示各項目。
  8. +
+ +
+

提示:mLab上的數據庫。您現在應該可以深入到書本籍,作者,種類和書本實例的各個集合中,並查看單個文檔。

+
+ +

總結

+ +

本文中我們學到了一點數據庫和Node/Express的ORMs,更多的是關於如何定義Mongoose綱要與模型。然後我們使用這些知識,為本地圖書館網站設計並實作出書本Book,書本實例BookInstance,作者Author和種類Genre模型。

+ +

最後,我們創建一些實例,以測試模型(使用獨立運作的命令稿)。下一篇文章,我們將關注於如何創建一些網頁,以呈現這些物件。

+ +

參閱

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}

+ +

本教程連結

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/routes/index.html b/files/zh-tw/learn/server-side/express_nodejs/routes/index.html new file mode 100644 index 0000000000..f4549ec598 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/routes/index.html @@ -0,0 +1,646 @@ +--- +title: 'Express 教學 4: 路由與控制器' +slug: Learn/Server-side/Express_Nodejs/routes +translation_of: Learn/Server-side/Express_Nodejs/routes +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs")}}
+ +

在本教程中,我們將為最終在 本地圖書館 網站中需要的所有資源端點,搭配 "空殼" 處理函式來配置路由 (URL handling code) 。完成後,我們的路由處理源碼將會有模組化結構,在接下來的文章中,我們可以用真實的處理函式加以擴充。我們也會對如何使用Express 創建模組化路由,有更好的理解。

+ + + + + + + + + + + + +
先備知識:閱讀 Express/Node 介紹。 完成先前教學主題 (包含 Express 教學 3: 使用資料庫 (Mongoose)).
目標:理解如何創建簡易路由配置。我們所有的URL端點。
+ +

概覽

+ +

上一篇教程文章中,我們定義了Mongoose模型,以與數據庫互動,並使用(獨立)腳本創建一些初始庫記錄。現在我們可以編寫代碼,向用戶展示這些信息。我們需要做的第一件事,是確定我們希望能夠在頁面中顯示哪些信息,然後定義適當的URL,以返回這些資源。然後我們將需要創建路由(URL處理程序)和視圖(模板)來顯示這些頁面。

+ +

下圖是作為處理HTTP請求/響應時,需要實現的主要數據流和事項的提醒。除了視圖和路線之外,圖表還顯示“控制器” — 實際處理請求的函數,那些與路由請求分開的代碼。

+ +

由於我們已經創建了模型,我們需要創建的主要內容是:

+ + + +

 

+ +

+ +

最終,我們可能會有頁面顯示書籍,流派,作者和書籍的列表和詳細信息,以及用於創建,更新和刪除記錄的頁面。對一篇文章來說,這是很多的內容。因此,本文的大部分內容,都將集中在設置我們的路由和控制器,以返回“虛擬”內容。我們將在後續文章中,擴展控制器方法,以使用模型數據。

+ +

下面的第一部分,提供了關於如何使用Express Router中間件的簡要“入門”。當我們設置LocalLibrary路由時,我們將在後面的章節中使用這些知識。

+ +

路由入門

+ +

路由是Express代碼的一部分,它將HTTP動詞(GET, POST, PUT, DELETE等),URL路徑/模式和被調用來處理該模式的函數,相關聯起來。

+ +

有幾種方法可以創建路線。本教程將使用express.Router中間件,因為它允許我們將站點的特定部分的路由處理程序組合在一起,並使用通用的路由前綴訪問它們。我們會將所有與圖書館有關的路由,保存在“目錄”模塊中,如果我們添加路由來處理用戶帳戶或其他功能,我們可以將它們分開保存。

+ +
+

注意:我們在Express簡介>創建路由處理程序中,簡要討論了Express應用程序路由。除了為模塊化提供更好的支持之外(如下面第一小節所述),使用Router非常類似於直接在Express應用程序對像上定義路由。

+
+ +

本節的其餘部分,概述瞭如何使用路由器Router來定義路由。

+ +

定義和使用單獨的路由模塊

+ +

下面的代碼提供了一個具體示例,說明我們如何創建路由模塊,然後在Express應用程序中使用它。首先,我們在一個名為wiki.js的模塊中創建一個wiki的路由。代碼首先導入Express應用程序對象,使用它獲取一個

+ +

Router對象,然後使用get()方法向其添加一對路由。所有模塊的最後一個導出路由器Router對象。

+ +
// wiki.js - Wiki route module.
+
+var express = require('express');
+var router = express.Router();
+
+// Home page route.
+router.get('/', function (req, res) {
+  res.send('Wiki home page');
+})
+
+// About page route.
+router.get('/about', function (req, res) {
+  res.send('About this wiki');
+})
+
+module.exports = router;
+
+
+ +
+

注意:上面我們直接在路由器函數中定義路由處理程序回調。在LocalLibrary中,我們將在一個單獨的控制器模塊中,定義這些回調。

+
+ +

要在主應用程序文件中使用路由器模塊,我們首先require()路由模塊(wiki.js)。然後,我們在Express應用程序上調用use(),將路由器添加到中間件處理路徑,並指定一個'wiki'的URL路徑。

+ +
var wiki = require('./wiki.js');
+// ...
+app.use('/wiki', wiki);
+ +

然後可以從/wiki//wiki/about/,訪問我們的wiki路由模塊中定義的兩個路由。

+ +

路由函數

+ +

我們上面的模塊,定義了幾個典型的路由功能。使用Router.get()方法定義“about”路由(在下面),該方法僅響應HTTP GET請求。此方法的第一個參數是URL路徑,而第二個參數是一個回調函數,如果收到帶有路徑的HTTP GET請求,將會調用該函數。

+ +
router.get('/about', function (req, res) {
+  res.send('About this wiki');
+})
+
+ +

回調函數接受三個參數(通常如下所示命名:req, res, next),它將包含HTTP請求對象,HTTP響應,以及中間件鏈中的下一個函數。

+ +
+

注意:路由器功能是Express中間件,這意味著它們必須完成(響應)請求或調用鏈中的下一個功能next在上面的例子中,我們使用send()完成了請求,所以下一個參數next沒有被使用(我們選擇不指定它)。

+ +

上面的路由器函數只需要一次回調,但您可以根據需要指定任意數量的回調參數,或一組回調函數。每個函數都是中間件鏈的一部分,並且將按照添加到鏈中的順序調用(除非前面的函數完成請求)。

+ +

 

+
+ +

這裡的回調函數,在響應中調用send(),當我們收到帶有路徑(' /about')的GET請求時,返回字符串“About this wiki”。許多其他響應方法,可以結束請求/響應週期。例如,您可以調用res.json(),來發送JSON響應,或調用res.sendFile()來發送文件。構建庫時,我們最常使用的響應方法是render(),它使用模板和數據創建並返回HTML文件—我們將在後面的文章中,進一步討論這個問題!

+ +

 HTTP 動詞

+ +

上面的示例路由使用Router.get()方法,響應具有特定路徑的HTTP GET請求。路由器Router還為所有其他HTTP動詞提供路由方法,這些方法多數以完全相同的方式使用:post(), put(), delete(), options(), trace(), copy(), lock(), mkcol(), move(), purge(), propfind(), proppatch(), unlock(), report(), mkactivity()​​​​​​, checkout(), merge(), m-search(), notify(), subscribe(), unsubscribe(), patch(), search(),和connect()

+ +

例如,下面的代碼就像上一個/about路由一樣,但只響應HTTP POST請求。

+ +
router.post('/about', function (req, res) {
+  res.send('About this wiki');
+})
+ +

路由路徑

+ +

路由路徑定義可以進行請求的端點。我們到目前為止看到的例子,都是字符串,並且完全按照字符串的寫法使用:'/','/ about','/ book','/any-random.path'。

+ +

路由路徑也可以是字符串模式。字符串模式使用正則表達式語法的子集,來定義將匹配的端點模式。下面列出了子集(請注意,連字符(-)和點(.)由字符串路徑字面解釋):

+ + + +

路由路徑也可以是JavaScript正則表達式例如,下面的路由路徑將與鯰魚catfish 和角鯊魚dogfish相匹配,但不包括鯰魚catflap、鯰魚頭catfishhead等。請注意,正則表達式的路徑使用正則表達式語法(它不像以前那樣,是帶引號的字符串)。

+ +
app.get(/.*fish$/, function (req, res) {
+  ...
+})
+ +
+

注意: LocalLibrary的大部分路由,都只使用字符串,而不是字符串模式和正則表達式。我們還將使用下一節中討論的路由參數。

+
+ +

路由參數

+ +

路徑參數是命名的URL段,用於捕獲在URL中的位置指定的值。命名段以冒號為前綴,然後是名稱(例如。捕獲的值,使用參數名稱作為鍵,存在對像中(例如)。/:your_parameter_name/req.paramsreq.params.your_parameter_name

+ +

例如,考慮一個編碼的URL,其中包含有關用戶和書本的信息:http://localhost:3000/users/34/books/8989我們可以使用userIdbookId路徑參數,提取如下所示的信息:

+ +
app.get('/users/:userId/books/:bookId', function (req, res) {
+  // Access userId via: req.params.userId
+  // Access bookId via: req.params.bookId
+  res.send(req.params);
+})
+
+ +

路由參數的名稱,必須由“單詞字符”(AZ,az,0-9和_)組成。

+ +
+

注意: URL /book/create將與/book/:bookId 之類的路由匹配(它將提取要創建' create'的“bookId”值)。將使用與傳入URL匹配的第一個路由,因此,如果要單獨處理/book/createURL,則必須在/book/:bookId路由之前,先定義其路由處理程序。

+
+ +

這就是您開始使用路由所需的全部內容-如果需要,您可以在Express文檔中找到更多信息:基本路由路由指南以下部分顯示了我們如何為LocalLibrary設置路由和控制器。

+ +

本地圖書館需要的路由

+ +

下面列出了我們最終需要用於頁面的URL,其中object被替換為每個模型的名稱(book,bookinstance,genre,author),objects是對象的複數,id是默認情況下,為每個Mongoose模型實例指定的唯一實例字段(_id)。

+ + + +

第一個主頁和列表頁面,不編碼任何其他信息。雖然返回的結果,將取決於模型類型和數據庫中的內容,但為了獲取信息所運行的查詢,將始終相同(類似地,用於創建對象的代碼將始終類似)。相反的,其他URL用於處理特定文檔/模型實例—這些將項目的標識編碼在URL中(如上面的<id>)。

+ +

我們將使用路徑參數,來提取編碼信息,並將其傳遞給路由處理程序(在稍後的文章中,我們將使用它來動態確定從數據庫獲取的信息)。通過對我們的URL中的信息進行編碼,我們只需要一個路由,用於特定類型的每個資源(例如,一個路由來處理每個書本項目的顯示)。

+ +
+

注意 : Express允許您以任何方式構建URL -您可以在URL正文中編碼信息,就像上面一樣,或使用URL GET參數(例如/book/?id=6)。無論您使用哪種方法,URL都應保持乾淨,合理且可讀(請在此處查看W3C建議)。

+
+ +

接下來,我們為所有上述URL,創建路由處理程序回調函數和路由代碼。

+ +

創建路由-handler回調函式

+ +

在我們定義路由之前,我們將首先創建它們將調用的所有虛擬/骨架回調函數。回調將存在Books,BookInstances,Genres 和Authors 的單獨“控制器” 模塊中(您可以使用任何文件/模塊結構,但這似乎是該項目的適當粒度)。

+ +

首先在項目根目錄(/controllers)中,為我們的控制器創建一個文件夾,然後創建單獨的控制器文件/模塊,來處理每個模型:

+ +
/express-locallibrary-tutorial  //the project root
+  /controllers
+    authorController.js
+    bookController.js
+    bookinstanceController.js
+    genreController.js
+ +

作者控制器

+ +

打開/controllers/authorController.js文件,並複制以下代碼:

+ +
var Author = require('../models/author');
+
+// Display list of all Authors.
+exports.author_list = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author list');
+};
+
+// Display detail page for a specific Author.
+exports.author_detail = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author detail: ' + req.params.id);
+};
+
+// Display Author create form on GET.
+exports.author_create_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author create GET');
+};
+
+// Handle Author create on POST.
+exports.author_create_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author create POST');
+};
+
+// Display Author delete form on GET.
+exports.author_delete_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author delete GET');
+};
+
+// Handle Author delete on POST.
+exports.author_delete_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author delete POST');
+};
+
+// Display Author update form on GET.
+exports.author_update_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author update GET');
+};
+
+// Handle Author update on POST.
+exports.author_update_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author update POST');
+};
+
+ +

該模塊首先導入我們稍後將使用的模型,來訪問和更新我們的數據。然後它為我們希望處理的每個URL,導出函數(創建,更新和刪除操作使用表單,因此還有其他方法,來處理表單發布請求- 我們將在稍後的“表單文章” 中討論這些方法) 。

+ +

所有函數都具有Express中間件函數的標準形式,如果方法沒有完成請求週期,則會調用請求,響應和next下一個函數的參數(在所有這些情況下,它都會執行!)。這些方法只返回一個字符串,表明尚未創建關聯的頁面。如果期望控制器函數接收路徑參數,則在消息字符串中,輸出這些參數(參見上面的req.params.id)。

+ +

書本實例控制器

+ +

打開/controllers/bookinstanceController.js文件,並將其複製到以下代碼中(它遵循與Author控制器模塊相同的模式):

+ +
var BookInstance = require('../models/bookinstance');
+
+// Display list of all BookInstances.
+exports.bookinstance_list = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance list');
+};
+
+// Display detail page for a specific BookInstance.
+exports.bookinstance_detail = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance detail: ' + req.params.id);
+};
+
+// Display BookInstance create form on GET.
+exports.bookinstance_create_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance create GET');
+};
+
+// Handle BookInstance create on POST.
+exports.bookinstance_create_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance create POST');
+};
+
+// Display BookInstance delete form on GET.
+exports.bookinstance_delete_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance delete GET');
+};
+
+// Handle BookInstance delete on POST.
+exports.bookinstance_delete_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance delete POST');
+};
+
+// Display BookInstance update form on GET.
+exports.bookinstance_update_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance update GET');
+};
+
+// Handle bookinstance update on POST.
+exports.bookinstance_update_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance update POST');
+};
+
+ +

種類控制器

+ +

打開/controllers/genreController.js文件,並複制以下文本(這與AuthorBookInstance文件的模式相同):

+ +
var Genre = require('../models/genre');
+
+// Display list of all Genre.
+exports.genre_list = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre list');
+};
+
+// Display detail page for a specific Genre.
+exports.genre_detail = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre detail: ' + req.params.id);
+};
+
+// Display Genre create form on GET.
+exports.genre_create_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre create GET');
+};
+
+// Handle Genre create on POST.
+exports.genre_create_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre create POST');
+};
+
+// Display Genre delete form on GET.
+exports.genre_delete_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre delete GET');
+};
+
+// Handle Genre delete on POST.
+exports.genre_delete_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre delete POST');
+};
+
+// Display Genre update form on GET.
+exports.genre_update_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre update GET');
+};
+
+// Handle Genre update on POST.
+exports.genre_update_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre update POST');
+};
+
+ +

書本控制器

+ +

打開/controllers/bookController.js文件,並複制以下代碼。它遵循與其他控制器模塊相同的模式,但另外還有一個index()函數,用於顯示站點歡迎頁面:

+ +
var Book = require('../models/book');
+
+exports.index = function(req, res) {
+    res.send('NOT IMPLEMENTED: Site Home Page');
+};
+
+// Display list of all books.
+exports.book_list = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book list');
+};
+
+// Display detail page for a specific book.
+exports.book_detail = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book detail: ' + req.params.id);
+};
+
+// Display book create form on GET.
+exports.book_create_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book create GET');
+};
+
+// Handle book create on POST.
+exports.book_create_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book create POST');
+};
+
+// Display book delete form on GET.
+exports.book_delete_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book delete GET');
+};
+
+// Handle book delete on POST.
+exports.book_delete_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book delete POST');
+};
+
+// Display book update form on GET.
+exports.book_update_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book update GET');
+};
+
+// Handle book update on POST.
+exports.book_update_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book update POST');
+};
+
+ +

創建目錄路由模組

+ +

接下來,我們為LocalLibrary 網站,創建所需全部URL 的路由,這將調用我們在上一節中定義的控制器功能。

+ +

骨架網站已經有一個./routes文件夾,其中包含索引和用戶的路由。在此文件夾中,創建另一個路徑文件— catalog.js —如下圖所示。

+ +
/express-locallibrary-tutorial //the project root
+  /routes
+    index.js
+    users.js
+    catalog.js
+ +

打開/routes/ catalog.js,複製下面的代碼:

+ +
var express = require('express');
+var router = express.Router();
+
+// Require controller modules.
+var book_controller = require('../controllers/bookController');
+var author_controller = require('../controllers/authorController');
+var genre_controller = require('../controllers/genreController');
+var book_instance_controller = require('../controllers/bookinstanceController');
+
+/// BOOK ROUTES ///
+
+// GET catalog home page.
+router.get('/', book_controller.index);
+
+// GET request for creating a Book. NOTE This must come before routes that display Book (uses id).
+router.get('/book/create', book_controller.book_create_get);
+
+// POST request for creating Book.
+router.post('/book/create', book_controller.book_create_post);
+
+// GET request to delete Book.
+router.get('/book/:id/delete', book_controller.book_delete_get);
+
+// POST request to delete Book.
+router.post('/book/:id/delete', book_controller.book_delete_post);
+
+// GET request to update Book.
+router.get('/book/:id/update', book_controller.book_update_get);
+
+// POST request to update Book.
+router.post('/book/:id/update', book_controller.book_update_post);
+
+// GET request for one Book.
+router.get('/book/:id', book_controller.book_detail);
+
+// GET request for list of all Book items.
+router.get('/books', book_controller.book_list);
+
+/// AUTHOR ROUTES ///
+
+// GET request for creating Author. NOTE This must come before route for id (i.e. display author).
+router.get('/author/create', author_controller.author_create_get);
+
+// POST request for creating Author.
+router.post('/author/create', author_controller.author_create_post);
+
+// GET request to delete Author.
+router.get('/author/:id/delete', author_controller.author_delete_get);
+
+// POST request to delete Author.
+router.post('/author/:id/delete', author_controller.author_delete_post);
+
+// GET request to update Author.
+router.get('/author/:id/update', author_controller.author_update_get);
+
+// POST request to update Author.
+router.post('/author/:id/update', author_controller.author_update_post);
+
+// GET request for one Author.
+router.get('/author/:id', author_controller.author_detail);
+
+// GET request for list of all Authors.
+router.get('/authors', author_controller.author_list);
+
+/// GENRE ROUTES ///
+
+// GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id).
+router.get('/genre/create', genre_controller.genre_create_get);
+
+//POST request for creating Genre.
+router.post('/genre/create', genre_controller.genre_create_post);
+
+// GET request to delete Genre.
+router.get('/genre/:id/delete', genre_controller.genre_delete_get);
+
+// POST request to delete Genre.
+router.post('/genre/:id/delete', genre_controller.genre_delete_post);
+
+// GET request to update Genre.
+router.get('/genre/:id/update', genre_controller.genre_update_get);
+
+// POST request to update Genre.
+router.post('/genre/:id/update', genre_controller.genre_update_post);
+
+// GET request for one Genre.
+router.get('/genre/:id', genre_controller.genre_detail);
+
+// GET request for list of all Genre.
+router.get('/genres', genre_controller.genre_list);
+
+/// BOOKINSTANCE ROUTES ///
+
+// GET request for creating a BookInstance. NOTE This must come before route that displays BookInstance (uses id).
+router.get('/bookinstance/create', book_instance_controller.bookinstance_create_get);
+
+// POST request for creating BookInstance.
+router.post('/bookinstance/create', book_instance_controller.bookinstance_create_post);
+
+// GET request to delete BookInstance.
+router.get('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_get);
+
+// POST request to delete BookInstance.
+router.post('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_post);
+
+// GET request to update BookInstance.
+router.get('/bookinstance/:id/update', book_instance_controller.bookinstance_update_get);
+
+// POST request to update BookInstance.
+router.post('/bookinstance/:id/update', book_instance_controller.bookinstance_update_post);
+
+// GET request for one BookInstance.
+router.get('/bookinstance/:id', book_instance_controller.bookinstance_detail);
+
+// GET request for list of all BookInstance.
+router.get('/bookinstances', book_instance_controller.bookinstance_list);
+
+module.exports = router;
+
+ +

該模塊導入Express,然後使用它來創建一個Router對象。路由都在路由器上設置完成,然後導出。

+ +

路由是使用路由器對像上的.get().post()方法定義的。所有路徑都是使用字符串定義的(我們不使用字符串模式或正則表達式)。作用於某些特定資源(如書籍)的路由,則使用路徑參數從URL中獲取對象標識id。

+ +

處理程序函數,都是從我們在上一節中,創建的控制器模塊導入的。

+ +

更新 index 路由模組

+ +

我們已經設置了所有新路由,但我們仍然有一個到原始頁面的路由。讓我們將其重定向,到我們在路徑'/ catalog' 創建的新索引頁面。

+ +

打開/routes/index.js並使用下面的函數,替換現有路由。

+ +
// GET home page.
+router.get('/', function(req, res) {
+  res.redirect('/catalog');
+});
+ +
+

注意:這是我們第一次使用redirect()響應方法。這會重定向到指定的頁面,默認情況下會發送HTTP狀態代碼“302 Found”。您可以根據需要,更改返回的狀態代碼,並提供絕對路徑或相對路徑。

+
+ +

更新app.js

+ +

最後一步,是將路由,添加到中間件鏈。我們在app.js這樣做。

+ +

打開app.js,並要求其他路由下方的目錄路由(添加下面顯示的第三行,在其他兩個路由下面):

+ +
var indexRouter = require('./routes/index');
+var usersRouter = require('./routes/users');
+var catalogRouter = require('./routes/catalog');  //Import routes for "catalog" area of site
+ +

接下來,將目錄路由,添加到其他路由下面的中間件堆棧(添加下面顯示的第三行,在其他兩行下面):

+ +
app.use('/', indexRouter);
+app.use('/users', usersRouter);
+app.use('/catalog', catalogRouter);  // Add catalog routes to middleware chain.
+ +
+

Note:   我們已在路徑'/catalog'中添加了目錄模塊。它預先添加到目錄模塊中定義的所有路徑。例如,要訪問書本列表,URL將為:/catalog/books/

+
+ +

就是這樣。現在應該為我們最終在LocalLibrary 網站上支持的所有URL,啟用路由和框架功能。

+ +

測試路由

+ +

要測試路由,首先使用您通常的方法啟動網站

+ + + +

然後瀏覽一些上面的LocalLibrary URL,並驗證您沒有收到錯誤頁面(HTTP 404)。為方便起見,下面列出了一小組網址:

+ + + +

總結

+ +

我們現在為網站創建了所有的路由,在稍後的教程,我們可以將實作完成的代碼,填入到空殼控制器函式。以這樣的方式,我們學到了許多關於Express 路由的基本信息,以及一些組織路由和控制器的方式。

+ +

下一篇文章,我們將使用視圖(模板) 和存在模型裡的信息,為網站創建一個合適的歡迎頁面。

+ +

參閱

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs")}}

+ +

 

+ +

本教程連結

+ + + +

 

diff --git a/files/zh-tw/learn/server-side/express_nodejs/skeleton_website/index.html b/files/zh-tw/learn/server-side/express_nodejs/skeleton_website/index.html new file mode 100644 index 0000000000..0139a30dd9 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/skeleton_website/index.html @@ -0,0 +1,506 @@ +--- +title: 'Express 教學 2: 創建一個骨架網站' +slug: Learn/Server-side/Express_Nodejs/skeleton_website +translation_of: Learn/Server-side/Express_Nodejs/skeleton_website +--- +
{{LearnSidebar}}
+ +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}

+ +

Express 教程的第二篇文章,演示如何創建一個 "骨架" 網站項目,你可以接著在裡面加入網站特定的路由、模板/視圖、和數据庫調用。

+ + + + + + + + + + + + +
前置條件:架設一個Node 開發環境。回顧Express 教程。
目標:能夠使用Express 應用產生器,創建自己新的網頁項目。
+ +

概覽

+ +

本文演示如何使用 Express 應用產生器 工具,創建一個 "骨架" 網站,然後您可以使用特定於站點的路由,視圖/模板和數據庫調用來填充它們。在這個教程,我們將使用該工具,為我們的本地圖書館網站創建框架,我們稍後將添加該網站所需的所有其他代碼。該過程非常簡單,只需要在命令行上,用新項目名稱調用生成器,還可以指定站點的模板引擎和 CSS 生成器。

+ +

以下部分向您展示如何調用應用程序生成器,並提供關於視圖或CSS的不同選項的一些解釋。我們還將解釋骨架網站的結構。最後,我們將展示如何運行網站,來驗證它是否有效。

+ +
+

注意: Express Application Generator並非 Express 應用程序的唯一生成器,生成的項目不是構建文件和目錄的唯一可行方式。然而,生成的網站具有易於擴展和理解的模塊化結構。有關最小 Express 應用程序的信息,請參閱 Hello world 示例(Express docs)。

+
+ +

使用應用產生器

+ +

您應該已經安裝了生成器,作為設置 Node 開發環境的一部分。作為快速提醒,您可以使用 NPM 軟件包管理器,在整個站點安裝生成器工具,如下所示:

+ +
npm install express-generator -g
+ +

生成器有許多選項,您可以使用--help(或-h)命令,在命令行上查看它們:

+ +
> express --help
+
+  Usage: express [options] [dir]
+
+  Options:
+
+    -h, --help           output usage information
+        --version        output the version number
+    -e, --ejs            add ejs engine support
+        --pug            add pug engine support
+        --hbs            add handlebars engine support
+    -H, --hogan          add hogan.js engine support
+    -v, --view <engine>  add view <engine> support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
+    -c, --css <engine>   add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
+        --git            add .gitignore
+    -f, --force          force on non-empty directory
+
+ +

您可以使用 Jade 視圖引擎和純 CSS 來指定 express,以在當前目錄中創建項目(如果指定目錄名,則項目將創建在具有該名稱的子文件夾中)。

+ +
express
+ +

您還可以使用--view選擇視圖(模板)引擎,並且/或者使用--css選擇 CSS 生成引擎。

+ +
+

注意: 選擇模板引擎的其他選項(例如 --hogan, --ejs, --hbs等)已被棄用。請用 --view (或 -v)!

+
+ +

我應該用哪個視圖引擎?

+ +

Express Application Generator 允許您配置許多流行的視圖/模板引擎,包括 EJS, Hbs, Pug (Jade), Twig, 和 Vash,但如果您沒有指定視圖選項,它會默認選擇Jade。 Express 本身也可以支持大量其他模板語言,是「開箱即可使用」的。

+ +
+

注意: 如果要使用生成器不支持的模板引擎,請參閱在Express中使用模板引擎(Express文檔),並參閱目標視圖引擎的文檔。

+
+ +

一般來說,您應該選擇一種「可以提供您所需的所有功能」的模板引擎,
+ 並使您能夠儘早提高生產力 - 換句話說,就像您選擇其他組件一樣!比較模板引擎時需要考慮的一些事項如下:

+ + + +
+

提示: 互聯網上有許多資源,可幫助您比較不同的視圖/模板引擎選擇!

+
+ +

對於這個項目,我們將使用 Pug 模板引擎(這是最近更名的 Jade 引擎),因為這是最流行的 Express / JavaScript 模板語言之一,並且應用發生器支持開箱即用。

+ +

我應該用哪個CSS樣式引擎?

+ +

Express 應用生成器允許您創建一個項目,並配置最常見的 CSS 樣式表引擎:LESS, SASS, Compass, Stylus

+ +
+

注意: CSS有一些限制,使某些任務變得困難。 CSS 樣式表引擎允許您使用更強大的語法來定義您的 CSS,然後將定義編譯為純粹的舊式 CSS,以供瀏覽器使用。

+
+ +

與模板引擎一樣,您應該使用樣式表引擎,這樣可以讓您的團隊獲得最高生產力。對於這個項目,我們將使用普通的 CSS(默認值),因為我們的 CSS 要求不夠複雜,沒有必要使用其他任何東西。

+ +

我應該用哪個數據庫?

+ +

生成的代碼不使用/包含任何數據庫。 Express 應用程序可以使用 Node支持的任何數據庫機制(Express 本身並未針對數據庫管理,定義任何特定的附加行為/要求)。
+ 我們將在後面的文章中,討論如何與數據庫集成。

+ +

創建項目

+ +

對於我們要構建的示例 Local Library 應用程序,我們將使用 Pug 模板庫,創建一個名為 express-locallibrary-tutorial 的項目,並且不使用 CSS樣式表引擎。

+ +

首先到要創建項目的位置,然後在命令提示符下,運行 Express 應用生成器,如下所示:

+ +
express express-locallibrary-tutorial --view=pug
+
+ +

成器將創建(並列出)項目的文件。

+ +
   create : express-locallibrary-tutorial
+   create : express-locallibrary-tutorial/package.json
+   create : express-locallibrary-tutorial/app.js
+   create : express-locallibrary-tutorial/public/images
+   create : express-locallibrary-tutorial/public
+   create : express-locallibrary-tutorial/public/stylesheets
+   create : express-locallibrary-tutorial/public/stylesheets/style.css
+   create : express-locallibrary-tutorial/public/javascripts
+   create : express-locallibrary-tutorial/routes
+   create : express-locallibrary-tutorial/routes/index.js
+   create : express-locallibrary-tutorial/routes/users.js
+   create : express-locallibrary-tutorial/views
+   create : express-locallibrary-tutorial/views/index.pug
+   create : express-locallibrary-tutorial/views/layout.pug
+   create : express-locallibrary-tutorial/views/error.pug
+   create : express-locallibrary-tutorial/bin
+   create : express-locallibrary-tutorial/bin/www
+
+   install dependencies:
+     > cd express-locallibrary-tutorial && npm install
+
+   run the app:
+     > SET DEBUG=express-locallibrary-tutorial:* & npm start
+ +

在輸出結束時,生成器提供關於「如何安裝依賴關係」的指示信息(如 package.json 文件中所列),以及如何運行應用程序(上述說明適用於 Windows;在 Linux / macOS上,它們會略有不同)。

+ +

運行骨架網站

+ +

在這一時間點上,我們有一個完整的骨架項目。該網站實際上並沒有做太多工作,但運行它,能夠展示它是如何工作的。

+ +
    +
  1. 首先安裝依賴項(install安裝命令,將獲取項目的 package.json 文件中列出的所有依賴項包)。 + +
    cd express-locallibrary-tutorial
    +npm install
    +
  2. +
  3. 然後運行該應用程序。 +
      +
    • 在Windows上,使用此命令: +
      SET DEBUG=express-locallibrary-tutorial:* & npm start
      +
    • +
    • 在macOS 或 Linux,使用此命令: +
      DEBUG=express-locallibrary-tutorial:* npm start
      +
      +
    • +
    +
  4. +
  5. 然後在瀏覽器中加載 http://localhost:3000/ ,以訪問該應用程序。
  6. +
+ +

你應該會看到一個瀏覽器頁面,就像這樣:

+ +

Browser for default Express app generator website

+ +

你有一個能工作的 Express 應用了,讓它在 http://localhost:3000/ 服務。

+ +
+

注意: 您也可以使用 npm start命令啟動應用程序。如下圖所示,指定 DEBUG 變量可啟用控制台日誌記錄/調試。例如,當你訪問上面的頁面時,你會看到像這樣的調試輸出:

+ +
>SET DEBUG=express-locallibrary-tutorial:* & npm start
+
+> express-locallibrary-tutorial@0.0.0 start D:\express-locallibrary-tutorial
+> node ./bin/www
+
+  express-locallibrary-tutorial:server Listening on port 3000 +0ms
+GET / 200 288.474 ms - 170
+GET /stylesheets/style.css 200 5.799 ms - 111
+GET /favicon.ico 404 34.134 ms - 1335
+
+ +

讓伺服器在檔案更改時重新啟動

+ +

在您重新啟動服務器之前,您對 Express 網站所做的任何更改,目前都不可見。每次進行更改時,必須停止並重新啟動服務器,很快變得非常煩人,因此值得花時間使服務器在需要時,自動重新啟動。

+ +

這種工具中,最簡單的之一就是 nodemon。這通常是全局安裝的(因為它是一個“工具”),但在這裡,我們將在本地安裝和使用它,作為開發人員依賴項,以便任何使用該項目的開發人員,在安裝應用程序時自動獲取它。在骨架項目的根目錄中,使用以下命令:

+ +
npm install --save-dev nodemon
+ +

如果您打開項目的 package.json 文件,您現在將看到一個具有此依賴關係的新區段:

+ +
  "devDependencies": {
+    "nodemon": "^1.14.11"
+  }
+
+ +

由於該工具沒有全局安裝,我們無法從命令行啟動它(除非我們將其添加到路徑中),但是我們可以從 NPM 腳本中調用它,因為 NPM 知道所有關於安裝的軟件包的信息。找到你的 package.json 的腳本 scripts 區塊。我們更新 scripts 區塊,最初的一行,以"start"開頭,在該行的末尾添加逗號,並添加 "devstart" 開頭的一行,如下所示:

+ +
  "scripts": {
+    "start": "node ./bin/www",
+    "devstart": "nodemon ./bin/www"
+  },
+
+ + + +

現在我們可以用與前面幾乎完全相同的方式,啟動服務器,但使用指定的 devstart 命令:

+ + + +
+

注意: 現在,如果您編輯項目中的任何文件,服務器將重新啟動(或者您可以隨時在命令提示符下,鍵入rs來重新啟動它)。您仍需要重新加載瀏覽器,以刷新頁面。

+ +

我們現在必須調用“npm run <scriptname>”而不是 npm start,因為“start”實際上是映射到指定腳本的 NPM 命令。我們可以在啟動腳本中替換該命令,但我們只想在開發期間使用 nodemon,因此創建新的腳本命令是有意義的。

+
+ +

從產生器得到的項目

+ +

現在我們來看看我們剛剛創建的項目。

+ +

目錄結構

+ +

從產生器得到的生成項目,現在已經安裝了依賴項,具有以下文件結構 (不帶前綴 “/” 的項目,表示文件)。 package.json 文件定義了應用程序依賴項,和其他信息。它還定義了一個啟動腳本,它將調用應用程序入口點 JavaScript 文件 /bin/www。這設置了一些應用程序的錯誤處理,然後加載 app.js ,來完成剩下的工作。應用程序路徑,存儲在 /routes 目錄下的單獨模塊中。模板存儲在 /views 目錄下。

+ +
/express-locallibrary-tutorial
+    app.js
+    /bin
+        www
+    package.json
+    /node_modules
+        [about 4,500 subdirectories and files]
+    /public
+        /images
+        /javascripts
+        /stylesheets
+            style.css
+    /routes
+        index.jsusers.js
+    /views
+        error.pug
+        index.puglayout.pug
+
+
+ +

以下各節將詳細介紹這些文件。

+ +

package.json

+ +

package.json 文件定義了應用程序依賴關係,和其他訊息:

+ +
{
+  "name": "express-locallibrary-tutorial",
+  "version": "0.0.0",
+  "private": true,
+  "scripts": {
+    "start": "node ./bin/www",
+    "devstart": "nodemon ./bin/www"
+  },
+  "dependencies": {
+    "body-parser": "~1.18.2",
+    "cookie-parser": "~1.4.3",
+    "debug": "~2.6.9",
+    "express": "~4.16.2",
+    "morgan": "~1.9.0",
+    "pug": "~2.0.0-rc.4",
+    "serve-favicon": "~2.4.5"
+  },
+  "devDependencies": {
+    "nodemon": "^1.14.11"
+  }
+}
+
+ +

依賴關係包括 express 套件,和我們所選視圖引擎(pug)的套件。另外,我們還有以下的套件,在許多 Web 應用程序中很有用:

+ + + +

腳本部分,定義了一個“開始” "start" 腳本,當我們調用 npm start 來啟動服務器時,這就是我們所調用的腳本。從腳本定義中,您可以看到這實際上用 node 啟動了 JavaScript 文件 ./bin/www。它還定義了一個“devstart” 腳本,我們在調用 npm run devstart 時調用它。這將啟動相同的 ./bin/www 文件,但使用 nodemon 調用而不是 node 。

+ +
  "scripts": {
+    "start": "node ./bin/www",
+    "devstart": "nodemon ./bin/www"
+  },
+
+ +

www 文件

+ +

文件 /bin/www 是應用程序入口點!它做的第一件事是 require() “真正的” 應用程序入口點(即項目根目錄中的 app.js ),app.js 會設置並返回 express()應用程序的對象。

+ +
#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+
+var app = require('../app');
+
+ +
+

注意: require() 是一個全局 node 函數,用於將模塊導入當前文件。這裡我們使用相對路徑指定 app.js 模塊,並省略可選的(.js)文件擴展名。

+
+ +

此文件中的其餘代碼,將設置一個node 運行的HTTP 服務器,並將應用app 設置為特定的端口(在環境變量中定義,如果變量未定義,則定義為3000),並開始監聽和報告服務器錯誤和連接。現在你並不需要知道代碼的其他內容(這個文件中的所有內容都是 “樣板文件” ),但如果你感興趣,可以隨時查看它。

+ +

app.js

+ +

此文件創建一個 express 應用程序對象(按傳統命名為 app),使用各種設置和中間件,以設置應用程序,然後從模塊導出應用程序。下面的代碼只顯示了文件的一部分,創建和導出應用程序對象的部分:

+ +
var express = require('express');
+var app = express();
+...
+module.exports = app;
+
+ +

回到上面的 www 入口點文件,它是在導入該文件時,提供給調用者的這個 module.exports 對象。

+ +

讓我們詳細了解 app.js 文件。首先,我們使用 require()將一些有用的 node 庫導入到文件中,其中包括我們先前使用 NPM 為應用程序下載的 express,serve-favicon,morgan,cookie-parser 和body-parser;和path 庫,它是解析文件和目錄路徑的核心 node 庫。

+ +
var express = require('express');
+var path = require('path');
+var favicon = require('serve-favicon');
+var logger = require('morgan');
+var cookieParser = require('cookie-parser');
+var bodyParser = require('body-parser');
+
+ +

然後我們用 require()導入來自我們的路由目錄的模塊。這些模塊/文件包含用於處理特定的相關“路由”集合(URL路徑)的代碼。當我們擴展骨架應用程序,例如列出圖書館中的所有書籍時,我們將添加一個新文件,來處理與書籍相關的路由。

+ +
var indexRouter = require('./routes/index');
+var usersRouter = require('./routes/users');
+
+ +
+

注意: 此時我們剛剛導入了模塊;我們還沒有真正使用過它的路由(在文件的更下方一點將使用到路由)。

+
+ +

接下來,我們使用導入的 express 模塊​​,創建應用程序 app 對象,然後使用它來設置視圖(模板)引擎。引擎的設置有兩個部分。首先我們設置 'views' 值,來指定模板將被存儲的文件夾(在這種情況下是子文件夾 /views)。然後我們設置 'view engine' 的值,來指定模板庫(在本例中為 “pug” )。

+ +
var app = express();
+
+// view engine setup
+app.set('views', path.join(__dirname, 'views'));
+app.set('view engine', 'pug');
+
+ +

下一組函數調用 app.use(),將中間件的庫,添加到請求處理鏈中。除了我們之前導入的第三方庫之外,我們還使用 express.static 中間件,來使 Express 提供在項目根目錄下,/public 目錄中的所有靜態文件。

+ +
// uncomment after placing your favicon in /public
+//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
+app.use(logger('dev'));
+app.use(bodyParser.json());
+app.use(bodyParser.urlencoded({ extended: false }));
+app.use(cookieParser());
+app.use(express.static(path.join(__dirname, 'public')));
+
+ +

現在所有其他中間件都已設置完畢,我們將(先前導入的)路由處理代碼,添加到請求處理鏈中。導入的代碼,將為網站的不同部分定義特定路由:

+ +
app.use('/', indexRouter);
+app.use('/users', usersRouter);
+
+ +
+

注意: 上面指定的路徑 ('/' and '/users'),被視為定義在導入文件中的路由前綴。因此,例如,如果導入的用戶模塊 users/profile定義了路由,則可以在 /users/profile中訪問該路由。我們將在後面的文章中,詳細討論路由。

+
+ +

文件中的最後一個中間件,為錯誤和 HTTP 404 響應添加了處理程序方法。

+ +
// catch 404 and forward to error handler
+app.use(function(req, res, next) {
+  var err = new Error('Not Found');
+  err.status = 404;
+  next(err);
+});
+
+// error handler
+app.use(function(err, req, res, next) {
+  // set locals, only providing error in development
+  res.locals.message = err.message;
+  res.locals.error = req.app.get('env') === 'development' ? err : {};
+
+  // render the error page
+  res.status(err.status || 500);
+  res.render('error');
+});
+
+ +

Express 應用程序對象(app)現已完全完成配置。最後一步,是將其添加到模塊導出(這允許它通過 /bin/www 導入)。

+ +
module.exports = app;
+ +

路由

+ +

路由文檔 /routes/users.js 如下所示(路由文件共享一個類似的結構,所以我們不需要也顯示 index.js)。首先加載 express 模塊​​,並使用它獲取 express.Router對象。然後它在該對像上指定一個路由,最後從模塊中導出路由器(這就是允許將文件導入到 app.js 中的路由)。

+ +
var express = require('express');
+var router = express.Router();
+
+/* GET users listing. */
+router.get('/', function(req, res, next) {
+  res.send('respond with a resource');
+});
+
+module.exports = router;
+
+ +

該路由定義了一個回調,只要檢測到具有正確模式的HTTP GET 請求,就會調用該回調。匹配模式是模塊導入時指定的路由('/users'),加上('/')文件中定義的任何內容。換句話說,當收到/users/的 URL 時,將使用此路由。

+ +
+

提示: 嘗試運行帶有 node 的服務器,並在瀏覽器中訪問以下 URL: http://localhost:3000/users/。您應該看到一條消息:'respond with a resource'。

+
+ +

上面有趣的事情是,回調函數有第三個參數 'next',因此是一個中間件函數,而不是簡單的路由回調。雖然代碼當前不使用 next 參數,但如果要在'/'根路由路徑中,添加多個路由處理程序,將來可能會有用。

+ +

視圖(模板)

+ +

視圖(模板)存儲在 /views 目錄中(如 app.js 中指定的)並且被賦予文件擴展名.pug。方法 Response.render()用於呈現指定的模板,以及在對像中傳遞的命名變量的值,然後將結果作為響應發送。在來自 /routes/index.js 的以下代碼中,您可以看到,該路由如何使用模板 "index" 傳遞模板變量 "title" ,以呈現響應。

+ +
/* GET home page. */
+router.get('/', function(req, res) {
+  res.render('index', { title: 'Express' });
+});
+
+ +

上面路由的相應模板在下面給出(index.pug)。我們稍後會詳細討論這個語法。您現在需要知道的是,標題變量 title(值為 'Express')將插入模板中指定的位置。

+ +
extends layout
+
+block content
+  h1= title
+  p Welcome to #{title}
+
+ +

挑戰自己

+ +

/routes/users.js 中創建一個新路由,它將在 /users/cool/上顯示文本 “You're so cool”。通過運行服務器,並在瀏覽器中訪問 http://localhost:3000/users/cool/ 來測試它。

+ + + +

總結

+ +

你現在為 本地圖書館 創建了一個骨架網站項目,並且用 node 驗證了它能夠運行。最重要的,你也理解了項目的結構,因此你也明白了我們需要為本地圖書館加上路由和視圖。

+ +

接下來我們將開始修改骨架,讓它能像一個圖書館網站一樣運作。

+ +

參閱

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}

+ + + +

本教程連結

+ + diff --git a/files/zh-tw/learn/server-side/express_nodejs/tutorial_local_library_website/index.html b/files/zh-tw/learn/server-side/express_nodejs/tutorial_local_library_website/index.html new file mode 100644 index 0000000000..6804ef3742 --- /dev/null +++ b/files/zh-tw/learn/server-side/express_nodejs/tutorial_local_library_website/index.html @@ -0,0 +1,91 @@ +--- +title: 'Express 教學 1: 本地圖書館網站' +slug: Learn/Server-side/Express_Nodejs/Tutorial_local_library_website +translation_of: Learn/Server-side/Express_Nodejs/Tutorial_local_library_website +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs")}}
+ +

我們實作教程系列的第一篇文章,會說明將學到什麼東西,並提供「本地圖書館」範例網站的概述 。我們將在接下來的文章中一步一步完成這個網站。

+ + + + + + + + + + + + +
前置條件:閱讀 Express 介紹。 在底下的教程,你將需要 架設一個 Node 開發環境。
目標:介紹本教程的範例應用,讓讀者理解包含哪些主題。
+ +

概覽

+ +

歡迎來到 MDN "本地圖書館" Express (Node) 教程,我們將開發一個網站,用於管理本地圖書館的目錄。

+ +

本系列教程文章中,你將會:

+ + + +

這些主題中,有一部分你可能已經學過了,或者曾經簡短的接觸過。在本列系教程的最後,你應該知道的夠多,能夠自己開發簡單的 Express 應用。

+ +

本地圖書館網站

+ +

我們接下來將創建,並隨著本系列教程發展的網站,名字是本地圖書館。如同你的預測,此網站的目的,是為一間小型本地圖書館,提供一個線上目錄,使用者能夠瀏覽可取得的書本,並管理他們的帳号。

+ +

本範例經過細心地考慮,因為它的規模可以放大或縮小,以配合我們的需要,演示盡可能多或少的細節。並且可以用來演示幾乎所有的 Express 特性。更重要的,它允許我們提供一條引導路徑,演示你在任何網站都會需要的功能:

+ + + +

即使這是一個具備相當擴充性的範例,它被叫做本地圖書館是有原因的 — 我們希望呈現給你最少的信息,能夠盡快幫助你上手並運行Express。因此,我們將會存放書本、複本、作者、和其它關鍵信息。然而,我們不會存放其它圖書館可能用到的有關信息,或者提供支持多個圖書館網站的架構,又或者其它 "大型圖書館" 的特性。

+ +

我被卡住了,哪裡可以得到原始碼?

+ +

當你使用本教程,我們將在每個知識點,提供適當的代碼片段,讓你複制貼上,同時有些代碼,我們希望你能自己擴充 (會有一些指引)。

+ +

如果你被卡住了,你可以在 Github 的這裡,找到本地圖書館網站已經開發完成的版本。

+ +
+

注意: 在本教程中,指定版本的 node、Express、還有其它模組,都經過測試,並列出在專案項目的 package.json 檔案中。

+
+ +

總結Edit

+ +

現在,你對本地圖書館網站以及將要學習的東西,有更多一點的認識,是時候開始創建一個 骨架項目,以存放我們的範例。

+ +

 

+ +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs")}}

+ +

 

+ +

 

+ +

本系列教學

+ + + +

 

diff --git a/files/zh-tw/learn/server-side/first_steps/index.html b/files/zh-tw/learn/server-side/first_steps/index.html new file mode 100644 index 0000000000..2afd7bb1d4 --- /dev/null +++ b/files/zh-tw/learn/server-side/first_steps/index.html @@ -0,0 +1,41 @@ +--- +title: 伺服器端程式設計起步走 +slug: Learn/Server-side/First_steps +translation_of: Learn/Server-side/First_steps +--- +
{{LearnSidebar}}
+ +

在我們的伺服器端程式設計模組內,我們會回答一些關於伺服器端編程的問題──「那是什麼?」、「它和用戶端程式設計有何不同?」、還有「為什麼它有用?」。接著,我們會比較各大熱門框架、並佐以一些如何選擇最適合框架的指引。最後,我們還會提供關於伺服器安全的進階介紹性文章。

+ +

(譯者 iigmir 註:你可能常常聽到網路開發有前端與後端。在網路開發的脈落下,這裡講的伺服器端程式設計,就是俗稱的後端。)

+ +

先決條件

+ +

在開始本模組前,你不需要擁有任何與伺服器端、或其他種類的程式設計相關知識。

+ +

你必須知道「網路如何運作」。關於此,我們推薦以下主題:

+ + + +

有了基本理解後,你就可以透過本章節的模組來完成工作。

+ +

指引

+ +
+
介紹伺服器端
+
歡迎來到 MDN 初學者的伺服器端程式設計課程!在這首篇文章中,我們將以很高的角度回答諸如「這是什麼?」、「它和用戶端程式設計有何不同?」、還有「為什麼它有用?」之類的問題。讀完以後,你會明白很多關於伺服器端程式設計的知識。
+
用戶端概覽
+
現在你知道了伺服器端程式設計的目標與益處,而我們現在要檢驗一些細節:當伺服器從瀏覽器那邊收到「動態請求」的時候,究竟發生了什麼事。因為大多數網站都用相近的方法處理請求與回應,所以這一點會幫助你理解自己在撰寫程式碼的時候要幹什麼。
+
伺服器端網路框架
+
最後一篇文章介紹了伺服器端網路程式,為了回應來自瀏覽器的請求,究竟需要些什麼。現在,我們會告訴你網路框架如何簡化那些工作,並幫助你選定自己的第一個網路程式,要用上什麼樣的框架。
+
網站安全
+
網站安全,有賴網頁設計時的高度警覺。這篇概要性的文章不是要讓你變成網站安全大神,而是幫你理解在強化網路程式免受大多數威脅時,第一要務為何。
+
+ +

評估

+ +

這份「概覽」模組不做任何評估,因為我們還沒有給你看過任何程式碼。我們希望到了這裡,你可以對伺服器端程式設計能提供什麼東西,有者良好的理解;我們也希望你能在建立第一個網站時要用什麼框架的方面,能夠下好決定。

diff --git "a/files/zh-tw/learn/server-side/first_steps/\344\273\213\347\264\271/index.html" "b/files/zh-tw/learn/server-side/first_steps/\344\273\213\347\264\271/index.html" new file mode 100644 index 0000000000..a0919697ee --- /dev/null +++ "b/files/zh-tw/learn/server-side/first_steps/\344\273\213\347\264\271/index.html" @@ -0,0 +1,225 @@ +--- +title: 伺服器端的介紹 +slug: Learn/Server-side/First_steps/介紹 +translation_of: Learn/Server-side/First_steps/Introduction +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}
+ +

歡迎來到MDN伺服器端程式設計的初學者課程 !在第一篇文章中,我們會用較為抽象的角度來探討 server-side programming,並且為你解答「這是什麼?」「這個和用戶端的程式有什麼不同?」以及「這個有什麼用?」 。在讀完這篇文章後,你將能明白如何透過 server-side coding 來為你的網站增添力量。

+ + + + + + + + + + + + +
先決條件:基本電腦知識、對網路伺服器有基本了解。
目標:認識伺服器端的程式設計、它可以做什麼、它和用戶端的程式有什麼不一樣?
+ +

大多數的大型網站使用伺服器端程式(server-side code)來動態地顯示各種所需的資料,普遍的做法為從伺服端的資料庫中取出資料,並送至用戶端,再透過一些 code 來顯示它們(例如:HTML 與 JavaScript)。

+ +

也許,使用伺服器端程式的最大好處是為不同的瀏覽者量身打造網頁內容。動態網站根據使用者的偏好設定及興趣提供更為相關的內容,也可以儲存個人設定及資訊讓網站更易於使用 — 例如重複使用已儲存的信用卡資料來使付款流程更為順暢。

+ +

它也能讓網站透過信件或其他方式來和使用者互動,如發送通知與更新。這一切的一切都讓網站更能牢牢抓住使用者的心。

+ +

何謂伺服器端網站程式開發?

+ +

網頁瀏覽器使用超文本傳輸協定(HyperText Transfer Protocol, {{glossary("HTTP")}})與網頁伺服器(web servers)溝通。當您點選網頁上的連結、送出表單,或者執行搜尋,一段 HTTP 請求request)會由您的瀏覽器送至目標伺服器。

+ +

該請求(request)包含一個用來指定受影響資源的 URL、一個定義行為的請求方法(例如對資源進行get、delete或post)與當進行HTTP POST方法時可能包含編碼於URL參數中的額外資訊(經由一段查詢字串送出的各個鍵值對),或是在關聯的{{glossary("Cookie", "cookies")}}中。

+ +

網頁伺服器等待用戶端的請求訊息、獲得後處理它們,並以一個HTTP回應response)訊息回覆至網頁瀏覽器。該回應包含一個狀態訊息說明本次請求是否達成(例如:"HTTP/1.1 200 OK"表示成功)。

+ +

成功對應於一個請求的回應主體(response body)應包含請求的資源(例如:一份新的HTML頁面或一張圖片等),這些可能將被用來顯示在網頁瀏覽器中。

+ +

靜態網站

+ +

以下的靜態網站(static site)圖展示一個基本的網頁伺服器架構,其中靜態網站意謂當無論何時有個特定資源的請求,伺服器始終回傳相同的硬編碼內容(hard-coded content)。當一個使用者想要引導到一個網頁時,瀏覽器送出的HTTP "GET" 請求指的就是該資源的URL。

+ +

此伺服器從它的檔案系統取回被請求的文件,並回傳一個包含此文件以及成功狀態碼(通常為200 OK)的HTTP回應。若檔案因某些原因無法被取回,則回傳一個錯誤狀態(參見 用戶端錯誤回應 與 伺服器端錯誤回應)。

+ +

A simplified diagram of a static web server.

+ +

動態網站

+ +

一個動態網站的回應內容是當需要時動態產生的。在一個動態網站的HTML網頁通常是經由資料庫取得並插入資料至HTML範本的佔位符(placeholders)中而創造出來(相較於靜態網站,這對於儲存大量內容而言,這是一種相當有效率的做法)。 

+ +

一個動態網站可以根據使用者或已存偏好設定提供的URL資訊回傳不同的資料,也可以以其他的作用方式呈現回應(例如:發送通知)。

+ +

用來支援一個動態網站的大部分的程式碼必須在伺服器執行。建立程式碼的方式稱為"伺服端程式設計(server-side programming)"或"後端腳本(back-end scripting)"。

+ +

下圖為動態網站dynamic website)的基本架構。如同先前的圖說,瀏覽器發送HTTP請求至伺服器,接著伺服器處理請求後,回傳合適的HTTP回應。

+ +

對於靜態資源的請求處理方式如同靜態網站的方式(靜態資源為任何不會改變的檔案 — 通常為CSS、JavaScript、圖片、預產生的PDF檔案等)。 

+ +

A simplified diagram of a web server that uses server-side programming to get information from a database and construct HTML from templates. This is the same diagram as is in the Client-Server overview.

+ +

對於動態資源的請求方式則為轉送(2)至伺服端程式碼(如圖中的網頁應用程式 Web Application)。對於"動態請求",伺服器解釋該請求、從資料庫讀取所需資訊(3)、與HTML範本結合取得的資料(4),最後送回一個包含已產生HTML的回應(5,6)。

+ +
+

伺服端與用戶端程式設計是相同的嗎?

+
+ +

讓我們把注意力集中在伺服端與用戶端的程式設計吧!在以下的每個案例中,程式碼完全不一樣:

+ + + +

執行在瀏覽器的程式碼被稱為用戶端程式碼client-side code),它主要用來改善一個渲染的網頁外觀與行為。這包含選取與設定UI元件樣式、建立佈局、導覽、表格驗證等。相對的,伺服端網站程式設計大量涉及要回傳哪些內容給瀏覽器做為對請求的回應。伺服端程式碼處理驗證已提交的資料與請求、使用資料庫儲存及取得資料,和按需求發送正確的資料給用戶等任務。

+ +

用戶端程式碼以HTMLCSSJavaScript撰寫 — 它執行在網頁瀏覽器內,並且僅有或無訪問底層的作業系統(包含對檔案系統的有限存取)。

+ +

網頁開發者不能控制使用者可能使用何種瀏覽器來檢視一個網站 — 瀏覽器與用戶端程式有著不同層度的相容性,並且用戶端程式的挑戰之一是如何妥善地處理瀏覽器支援的差異。

+ +

伺服端程式碼可以為任何程式語言 — 例如有名的伺服端網頁語言包括PHP、Python、Ruby、C#與NodeJS(JavaScript)。該伺服端程式碼擁有完整的作業系統存取權限,而且開發者能夠選擇他們想要的程式語言(以及特定版本)。

+ +

開發者們通常使用網頁框架web frameworks)撰寫程式碼。網頁框架為功能函式、物件、規則與其他程式碼的集合,旨在解決常見問題、加速開發並簡化在特定域中面臨到的不同類型的任務。

+ +

再者,儘管用戶端與伺服端程式碼都使用框架,但會因為非常不同的域,而使得框架也不同。用戶端網頁框架簡化佈局與呈現的任務,而伺服端網頁框架則提供大量"通用"的網頁伺服器功能,否則你可能必須要自己實現(例如:對sessions的支援、對使用者認證的支援、簡易資料庫存取、樣板庫等)。

+ +
+

Note: Client-side frameworks are often used to help speed up development of client-side code, but you can also choose to write all the code by hand; in fact, writing your code by hand can be quicker and more efficient if you only need a small, simple web site UI.

+ +

In contrast, you would almost never consider writing the server-side component of a web app without a framework — implementing a vital feature like an HTTP server is really hard to do from scratch in say Python, but Python web frameworks like Django provide one out of the box, along with other very useful tools.

+
+ +
+

在伺服端,你能做什麼?

+ +

伺服端程式設計是非常有用的,因為它讓我們有效地遞送替單個使用者量身訂做的資訊,從而創造更棒的使用者體驗。

+
+ +

如Amazon這樣的公司使用伺服端程式設計來建構產品搜尋結果、根據顧客偏好與過往購物習慣提供針對性的產品建議、簡化購物過程等。

+ +

銀行使用伺服端程式設計來儲存帳號資訊,並讓已授權用戶檢視與進行交易。其他服務如Facebook、Twitter、Instagram與Wikipedia使用伺服端程式設計來突顯、分享與控制使用者存取到感興趣的內容。

+ +

一些常見的伺服端程式設計使用案例與效益列舉如下。您將會注意到這當中會有些重疊的部分!

+ +

高效率資訊儲存與遞送

+ +

想像一下,在Amazon可以找到多少產品,或者說在Facebook上有多少文章?對各個產品或文章建立各別的靜態網頁完全是不切實際的。

+ +

伺服端程式設計反而是可以讓我們將資訊儲存至資料庫,並且動態建構及回傳HTML與其他型態的檔案(例如:PDF、圖片等)。它也可以藉由合適的用戶端網頁框架(利用這個方式可以降低在伺服器的處理負擔,亦減少需要被送出的大量資料)僅回傳資料({{glossary("JSON")}}、{{glossary("XML")}}等)來進行畫面渲染。

+ +

伺服器並不侷限於從資料庫發送資訊,還可以回傳軟體工具的結果或是來自通訊服務的資料。這些內容甚至可以針對到收到它的用戶裝置類型。

+ +

由於資訊存在於資料庫中,它可以輕易地與其他商業系統進行分享與更新(例如:當產品在線上或在店家中售完,店家可能會更新該產品的庫存資料庫)。

+ +
+

Note: Your imagination doesn't have to work hard to see the benefit of server-side code for efficient storage and delivery of information:

+ +
    +
  1. Go to Amazon or some other e-commerce site.
  2. +
  3. Search for a number of keywords and note how the page structure doesn't change, even though the results do. 
  4. +
  5. Open two or three different products. Note again how they have a common structure and layout, but the content for different products has been pulled from the database.
  6. +
+ +

For a common search term ("fish", say) you can see literally millions of returned values. Using a database allows these to be stored and shared efficiently, and it allows the presentation of the information to be controlled in just one place.

+
+ +

客製化的使用者體驗

+ +

伺服器能保存及使用關於用戶的資訊,來提供一個方便且量身訂做的使用者體驗。例如,許多網站儲存信用卡資料讓這些資料無須再重新輸入。網站如Google Maps能使用已儲存或目前位置來提供導航資訊與搜尋或旅行歷史紀錄,以便於搜尋結果中突顯在地店家。

+ +

一個使用者習慣更深層的分析,可以使用在預測他的興趣以及更進一步客製回應與提醒,例如在地圖中提供你可能想去看得過去遊歷過的或是熱門的地點列表。

+ +
+

Note: Google Maps saves your search and visit history. Frequently visited or frequently searched locations are highlighted more than others.

+ +

Google search results are optimized based on previous searches.

+ +
    +
  1.  Go to Google search.
  2. +
  3.  Search for "football".
  4. +
  5.  Now try typing "favourite" in the search box and observe the autocomplete search predictions.
  6. +
+ +

Coincidence? Nada!

+
+ +

控制內容存取

+ +

伺服器端程式設計允許網站限制僅能由已授權的使用者存取,並提供資訊給那些只被允許觀看的使用者。

+ +

真實世界案例包括:

+ + + +
+

Note: Consider other real examples where access to content is controlled. For example, what can you see if you go to the online site for your bank? Log in to your account — what additional information can you see and modify? What information can you see that only the bank can change?

+
+ +

儲存session/state資訊

+ +

伺服器端程式設計允許開發者利用sessions — 基本上,就是一個機制讓伺服器儲存目前的使用者資訊,並且基於這些資訊發送不同的回應。

+ +

例如,這允許網站了解一個使用者先前已登入過,以及將訂購歷史紀錄在他們的電子郵件中顯示連結,或者也許會儲存一個基本的遊戲狀態,讓使用者能再次回到網站的同時,拿回他們留在網站的資訊。

+ +
+

Note: Visit a newspaper site that has a subscription model and open a bunch of tabs (e.g. The Age). Continue to visit the site over a few hours/days. Eventually, you will start to be redirected to pages explaining how to subscribe, and you will be unable to access articles. This information is an example of session information stored in cookies.

+
+ +

提醒與溝通

+ +

伺服器能透過網站本身或經由電子郵件、SMS、即時通訊、影像或其他通訊服務,發送提醒訊息給一般或特定使用者。

+ +

一些範例包括:

+ + + +
+

Note: The most common type of notification is a "confirmation of registration". Pick almost any large site that you are interested in (Google, Amazon, Instagram, etc.) and create a new account using your email address. You will shortly receive an email confirming your registration, or requiring acknowledgment to activate your account.

+
+ +

資料分析

+ +

一個網站可能會收集很多包括使用者的資料:他們所搜尋的、他們所買的、他們所推薦的、他們在每個網頁停留的時間。伺服器端程式設計能根據資料分析以完善回應。

+ +

例如,Amazon與Google都根據過往搜尋(與購買)紀錄來廣告產品。

+ +
+

Note: If you're a Facebook user, go to your main feed and look at the stream of posts. Note how some of the posts are out of numerical order - in particular, posts with more "likes" are often higher on the list than more recent posts.

+ +

Also look at what kind of ads you are being shown — you might see ads for things you looked at on other sites. Facebook's algorithm for highlighting content and advertising can be a bit of a mystery, but it is clear that it does depend on your likes and viewing habits!

+
+ +

總結

+ +

恭喜,你已經到達關於伺服器端程式設計的第一篇文章的結尾。 

+ +

現在你已經學到伺服器端程式碼運作於網頁伺服器,他的主要任務是控制哪些資訊要發送給使用者(而用戶端程式碼主要掌握資料的結構與呈現給使用者)。

+ +

你也應該了解這是很有用的,當你身為伺服器端開發者時,因為它允許我們創建有效散播客製訊息與有些你可能會去做的好點子給單個使用者的網站。

+ +

最後,你應該了解伺服器端程式碼可以用很多種程式語言來撰寫,以及你應該使用網頁框架來讓整個程序變得更簡便。 

+ +

在未來的文章,我們將協助你選擇最佳的網頁框架,做為你的第一個網站;接著,我們將帶你更詳細了解主要的用戶端-伺服端的互動。

+ +

{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}

+ +

In this module

+ + diff --git a/files/zh-tw/learn/server-side/index.html b/files/zh-tw/learn/server-side/index.html new file mode 100644 index 0000000000..c62f4e8aba --- /dev/null +++ b/files/zh-tw/learn/server-side/index.html @@ -0,0 +1,59 @@ +--- +title: 伺服端網站程式設計 +slug: Learn/Server-side +tags: + - Beginner + - CodingScripting + - Intro + - Landing + - Learn + - NeedsTranslation + - Server + - Server-side programming + - Topic + - TopicStub +translation_of: Learn/Server-side +--- +
{{LearnSidebar}}
+ +

動態網站伺服端網站程式設計是一連串有關如何建立動態網站的模塊:動態網站可以針對 HTTP 請求,發送客製化的資訊。這些模塊將介紹伺服端網站程式設計:還有以初學者的角度,來教你怎麼使用 Django (Python) 與 Express (Node.js/JavaScript) 來架設基本的動態網路程式。

+ +

大多數主流網站會使用伺服端技術,以根據需要呈現動態資料。例如說,來想想亞馬遜(Amazon)上架多少商品、還有臉書(Facebook)貼了多少動態。如果都用靜態頁面來呈現這些內容,開發就會毫無效率可言。因此,我們會使用靜態技術(HTMLCSSJavaScript)來顯示靜態模板;並在需要時,動態更新模板內的資料。一如你在逛亞馬遜時,看著五花八門的產品一般。

+ +

在當今的 Web development 的世界,我們強烈建議學習怎麼開發伺服端網站程式。

+ +

學習路徑

+ +

學習伺服端網站程式設計通常比用戶端網站程式設計簡單,因為動態網站比較傾向執行多次相似的操作(像是從資料庫擷取資料並放到頁面上、驗證用戶輸入的資料並存到資料庫、檢查登入用戶權限之類的)、使用框架建立網站能讓上述操作、以及其他常見操作變得簡單許多。

+ +

基本的程式概念(或是理解特定的語言)會很有用,但不是必須的。同樣地,精於用戶端網站程式設計不是必須,但它能在前端開發時,幫你做得更好。

+ +

首先你要知道「web 是怎麼作動的」。我們建議先看看這些文章:

+ + + +

有了基本觀念後,就可以開始去學習模塊章節的東西了。

+ +

模塊

+ +

本章節包含了以下模塊。你首先要從第一個模塊開始,再循序漸進,學習接下來的模塊。這些模塊將告訴你如何與訪間最熱門的其中兩個伺服器端框架共事。

+ +
+
伺服器端程式設計起步走
+
本模塊會提供與技術無關的伺服器資訊,像是「那什麼?」、「和用戶端有啥不同?」、「有用嗎?」之類的。本模塊也會概述一些比較熱門的伺服器端 web 框架、並告訴你如何選擇。最後,我們還會概述有關伺服器服務的安全性問題。
+
Django 網站框架 (Python)
+
Django 以 Python 寫成,是個非常熱門的伺服器端 web 框架。本模塊會講解 Django 是好框架的理由、如何建立開發環境、還有如何處理常見工作。
+
Express web framework (Node.js/JavaScript)
+
Express 以 JavaScript 寫成、並在 node.js 執行環境執行。它也是個非常熱門的伺服器端 web 框架。本模塊會講解一些有關本框架的重要優點、也同樣會講解如何建立開發環境、還有如何處理常見工作。
+
+ +

參見

+ +
+
不用框架的 Node 伺服器
+
如果不想用框架的話,這篇文章會告訴你如何使用純 Node.js 提供簡易的靜態檔案。
+
diff --git a/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/index.html b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/index.html new file mode 100644 index 0000000000..89c677beac --- /dev/null +++ b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/index.html @@ -0,0 +1,130 @@ +--- +title: 理解 JavaScript 前端框架 +slug: Learn/Tools_and_testing/Client-side_JavaScript_frameworks +translation_of: Learn/Tools_and_testing/Client-side_JavaScript_frameworks +--- +
{{LearnSidebar}}
+ +

JavaScript 框架在前端開發佔有重要的地位:它能讓前端工程師透過千錘百鍊的工具,建立擴展性高、互動性強的網路程式。多數公司也視 JavaScript 框架為重要的前端工具。因此多數前端工程師,會需要擁有前端框架的技能。

+ +

身為一位富有抱負的前端工程師,學習前端框架時,可能很難確定要從哪裡開始:五花八門的框架可供選擇、隨時還有新的框架出現。儘管大多數框架用途類似,但實作方法千變萬化。而在使用框架時,也需要考慮無數情形。

+ +

在這裡,我們旨在理解前端框架方面,提供舒適的學習曲線:我們不會詳細說明 React/ReactDOM 或 Vue 亦或其他特定框架的資訊。框架開發團隊早就針對這方面,寫出了詳細的文件。相反地,我們想先著重回答更基本的問題:

+ + + +

之後,我們將針對坊間主要框架提供教學,以便提供足夠鑽研下去的背景資訊。我們希望以務實且不忘基本實做(如無障礙)的方法,來理解框架這回事。

+ +

從「前端框架簡介」開始吧。

+ +

先決條件

+ +

在理解前端框架前,你需要對 web 核心技術:HTMLCSS、以及最重要的JavaScript,擁有基本程度的理解。

+ +

如果理解構建框架的 Web 技術,你的程式會更豐富(richer)且更專業,同時也能更有信心地除錯。

+ +

概觀性教學

+ +
+
1. 前端框架介紹
+
我們從整體概述來探討框架、提供 JavaScript 與框架的簡要歷史、框架存在的理由、他們提供什麼東西、如何決定選擇哪個框架、以及前端框架的的替代方案。
+
2. 框架的主要功能
+
大多數主要的 JavaScript 前端框架在更動 DOM、處理瀏覽器事件、還有提供良好的開發體驗方面,使出了不同的方法。這篇文章將探討「四大框架」的主要功能、看看他們如完成高層次工作、以及這四個框架的相異之處。
+
+ +

React 教學

+ +
+

:最近一次測試成功的 React 教學在 2020 年五月。版本為 React/ReactDOM 16.13.1 與 create-react-app 3.4.1。

+ +

如果想看看最新的程式,可以從我們的 todo-react repository 或互動性的 https://mdn.github.io/todo-react-build/ 看。

+
+ +
+
1. 開始學 React
+
在這裡我們將開始與 React 打招呼。我們將探索其背景和用途的一些細節、在自己的電腦建立 React 全家桶、還有建立與把玩簡單的程式,以理解 React 是怎麼跑的。
+
2. 建立我們的 React todo list
+
我們的任務是驗證 React 的概念(proof-of-concept):我們將建立一個能讓使用者添加、編輯、刪除需要的工作,同時在不刪除工作的情況下,將它們標記為完成。本文將完成 App 組件的基本架構與樣式,以便為下個文章將探討的組件定義與響應性做準備。
+
3. 把 React app 組件化
+
現在,我們的 app 整個黏在一起了。在做其他事情前,最好把這個程式切成一個個能管理,描述性也好的組件(component)。React 本身對組件的定義不多:那是取決於你的考量!我們將展示如何以聰明的方法,把程式切成一個個組件。
+
4. 響應性 React:事件與狀態
+
在組件化以後,現在開始把原本靜態的 UI,能開始與我們實際互動,並修改資料吧。在這裡除了做這件事以外,我們還會深入探討事件和狀態。
+
5. 響應性 React:編輯、過濾、條件式過濾
+
在初學 React 之路即將結束前(至少從現在來說),我們將在 Todo list app 裡面,添加畫龍點睛的主要功能:包括編輯已存在的工作、透過給定條件過濾全部、已完成、或未完成的工作。我們將不斷探討條件式 UI 渲染。
+
6. React 無障礙
+
在教學最後,我們將削除最後的障礙:像是能增進可用性,同時降低鍵盤與螢幕報讀用戶困惑的 focus 管理。
+
7. React 的資源
+
最後的最後,我們將提供鑽研 React 所需的資源。
+
+ +

Ember 教學

+ +
+

:最近一次測試成功的 Ember 教學在 2020 年五月。版本為 Ember/Ember CLI 3.18.0。

+ +

如果想看看最新的程式,可以從我們的 ember-todomvc-tutorial repository 或互動性的 https://nullvoxpopuli.github.io/ember-todomvc-tutorial/ 看。注意:部分功能沒有放在教學裡面。

+
+ +
+
1. 開始學 Ember
+
首先我們將探討 Ember 的原理與用途,還有如何安裝 Ember 全家桶,建立簡單的 app,最後還有完成開發環境。
+
2. Ember app 架構與組件
+
In this article we'll get right on with planning out the structure of our TodoMVC Ember app, adding in the HTML for it, and then breaking that HTML structure into components.
+
3. 響應性 Ember:事件、類別、狀態
+
此時,我們將開始給 app 添加一些響應性,從而能夠添加和顯示新的待辦事項。在此過程中,我們將研究如何在 Ember 中使用事件,創建組件類以包含用於控制交互功能的 JavaScript 程式,以及設置服務來跟踪應用程序的資料狀態。
+
4. 響應性 Ember:Footer 功能、條件式渲染
+
現在是時候開始處理我們應用程序中的 Footer 功能了。在這裡,我們將更新待辦事項計數器,以顯示仍需完成的正確待辦事項數量,並將樣式正確應用於已完成待辦事項(即已選中復選框的位置)。我們還將連接「清除完成」按鈕。在此過程中,我們將學習在模板中使用條件式渲染的知識。
+
5. Ember 的路由
+
在本文中,我們學習了路由,有時也稱為基於 URL 的過濾。我們將使用它為三個Todo視圖(「全部」、「活動」、「已完成」)中的每個視圖提供唯一的 URL。
+
6. Ember 的資源與除錯
+
最後的最後,我們將提供鑽研 Ember 所需的資源,以及好用的相關資訊。
+
+ +

Vue 教學

+ +
+

:最近一次測試成功的 Vue 教學在 2020 年五月。版本為 Vue 2.6.11。

+ +

如果想看看最新的程式,可以從我們的 todo-vue repository 或互動性的 https://mdn.github.io/todo-vue/dist/ 看。

+
+ +
+
1. 開始學 Vue
+
我們首先來介紹 Vue 吧。首先我們將聊聊 Vue 的背景、理解如何安裝新的專案、研究專案的整體架構與單一組件、如何讓專案在自己的電腦執行、並準備好建立一個新範例。
+
2. 建立第一個 Vue 組件
+
現在來開始鑽研 Vue 並建立第一個組件吧:我們將給 todo list 的各個單元建立獨立的組件。在此同時,我們將學習一些重要概念:比如說在組件內使用組件、透過 prop 傳送資料、還有儲存資料的狀態。
+
3. 渲染 Vue 組件的列表
+
現在我們已經有了一個能動的組件;現在將要給我們的 App 添加 ToDoItem 這個組件了。在這裡,我們將專精於如何給 App.vue 組件,添加一組 todo 的資料,接著使用 v-for 指令(directive)讓 ToDoItem 透過迴圈顯示出來。
+
4. 寫一個 todo 表單:Vue 的事件、方法、model
+
我們已經放了一些資料,同時也透過迴圈把 ToDoItem 渲染出來了。接下來,我們將讓使用者輸入 todo 項目、同時需要文字 <input>、submit 之後的事件觸發、還有能控制資料的 model。這些就是我們會探討的重點。
+
5. 透過 CSS 樣式化 Vue 組件
+
我們的程式看起來終於要漂亮一點了。我們將探討如何透過 CSS 樣式化 Vue 組件。
+
6. 使用 Vue 的計算屬性
+
在這裡我們將使用 Vue 的計算(computed)屬性,加上一個 counter 已便顯示完成工作的數量。計算屬性的功能與 methods 類似,但它只會在資料更新時變動資料。
+
7. Vue 的條件式渲染:編輯已存在的待辦
+
現在來添加一個還沒探討到的重要功能吧:那就是編輯已經存在的項目。要完成這件事,我們將借用 Vue 在條件式渲染的長才——也就是 v-ifv-else——在現有 todo 項目視圖間切換,同時編輯能更新的視圖。我們還會探討如何添加刪除待辦的功能。
+
8. 重點管理 Vue ref
+
我們快講完 Vue 了。最後要看的功能是 focus 管理,或者換句話說,如何消除鍵盤用戶的障礙。我們會看看怎麼透過 Vue ref 完成這件事:這是一項能透過虛擬 DOM、或組件的內部 DOM 結構,直接訪問 DOM 節點的進階功能。
+
9. Vue 的資源
+
最後的最後,我們將提供鑽研 Vue 所需的資源,以及有用的資訊。
+
+ +

該選什麼框架?

+ +

我們在最初發布的文章集,主要介紹了 React/ReactDOM、Ember、Vue。之所以選中這三個框架是因為:

+ + + +

先講一下:我們選什麼框架並不是因為他們最棒,而是因為我們認同他們:這些框架在較吻合以上的考量要點。

+ +

我們以本來希望在一開始包含更多框架,但最後決定先發布,之後再追加其它教學,而非延後。如果屬意的框架沒放進去、而你也想幫忙的話,來和我們聊聊吧!透過 MatrixDiscourse、或 mdn-admins list 與我們聯繫。

diff --git a/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/introduction/index.html b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/introduction/index.html new file mode 100644 index 0000000000..d13116582d --- /dev/null +++ b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/introduction/index.html @@ -0,0 +1,387 @@ +--- +title: 前端框架簡介 +slug: Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction +translation_of: Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}
+ +

我們從整體概述來探討框架、提供 JavaScript 與框架的簡要歷史、框架存在的理由、他們提供什麼東西、如何決定選擇哪個框架、以及前端框架的的替代方案。

+ + + + + + + + + + + + +
先決條件:熟悉 HTMLCSSJavaScript 這些核心技術。
目標:理解 JavaScript 前端框架存在的理由、他們解決的問題、可用的替代方案、還有決定選擇的方法。
+ +

一段簡短的歷史

+ +

在 JavaScript 誕生的 1996,它的作用就只有針對網頁,提供些許的互動和興奮。但之後網路漸漸從拿來看,變成拿來用了。JavaScript 慢慢地紅了起來,JavaScript 開發者也開始針對自己碰上的問題,寫出了能解決問題的工具、接著包成能複用的工具包。他們就能把這個被稱為函式庫(library)的東西,拿去與他人共享。共享的函式庫生態,也有助於塑造網路的增長趨勢。

+ +

目前 JavaScript 已經是網路的必需品了,大約 95% 的網站都又在使用 JavaScript,網路也成了當今生活的必須。使用者可以透過文字與影像,來寫論文、聽音樂、看電影、與人遠距離交流。曾經只能透過裝在電腦內的原生軟體所完成的事情,現在也能網路上做到。這種現代化、複雜度高、還有各種互動的網站,被稱為網路應用程式(web applications)。

+ +

當代 JavaScript 框架的問世,讓構建高度動態的互動式應用,變得簡單許多。框架是個針對軟體構建,提供完整解決方案的函式庫。這些選項能讓應用程式,開始能預測和同質化。可預測性讓軟體能擴展到巨大的規模時依舊能維護;可預測性和可維護性則對軟體的健康和長壽至關重要。

+ +

JavaScript 框架能構建常用的網站裡,許多令人印象深刻的軟體。目前你正在看的 MDN Web Docs 網站,也是用 React/ReactDOM 作為前端支援的。

+ +

那有什麼框架?

+ +

有很多框架,不過主要有以下「四大框架」。

+ +

Ember

+ +

Ember 在 2011 年 12 月發行。這個框架始於 SproutCore 的內部專案。這是個比較老的框架:與 React 或 Vue 之類的替代方案相比,其用戶數比較少,不過在穩定性、社區支持、和一些巧妙的編碼原則方面,仍然享譽無數。

+ +

Angular

+ +

Angular 是個由 Google 內部的 Angular Team 與其他社群所開發的開源專案。這個專案是同一群人由 AngularJS 所重寫的專案。該專案於2016年9月14日發行。

+ +

Angular 是基於組件、並使用指令式 HTML 樣板的框架。在構建時,框架的編譯器會將模板,轉換為優化的 JavaScript 程式。Angular 使用了 JavaScript 超集(superset)的 TypeScript。我們將在下一章中詳細介紹它。

+ +

Vue

+ +

尤雨溪在維護並理解前述的 AngularJS 專案後,於 2014 年發表了 Vue。Vue 是四大框架裡面最年輕的,但成了近年來的當紅炸子雞。

+ +

Vue 除了與 Angular 一樣,使用了一些自定義的 HTML 以外,大部分還是使用現代化的標準 JavaScript。

+ +

React

+ +

Facebook 於 2013 年發表了 React。在發表當時 Facebook 內部早已使用 React 解決許多內部問題。技術上來說 React 並不是框架,而是一個用來渲染 UI 組件的函式庫。React 通常會配合其他函式庫來建立應用程式:例如 React 搭配 React Native 建立手機程式、React 與 ReactDOM 建立網路程式...等等。

+ +

由於 React 與 ReactDOM 通常會搭在一起用,React 在通俗上會被理解為 JavaScript 框架。在閱讀本模塊時,我們將以這種通俗理解為基礎。

+ +

React 使用一種很像是 HTML 的 JavaScript 語法:JSX

+ +

為什麼有框架?

+ +

我們已經討論了啟發框架建立的環境,但那不是開發人員為什麼要製造它們的理由。要探索原因,首先需要首先檢查開發軟體所碰上的挑戰。

+ +

來看看一個常見的例子吧:一個能建立待辦事項程式,我們將會用待辦事項程式為例子,來介紹不同的框架。這個應用程序要能讓使用者執行諸如渲染事項列表,添加新任務和刪除任務之類的操作;還要能可靠地跟踪並更新程式所依賴的資料在軟體開發中,此這些資料稱為狀態(state)。

+ +

每個目標分開來看,理論上都很簡單:我們能遍歷需要渲染的資料、建立新的工作物件、還能用標識符來查詢、編輯或刪除工作。然而,當我們要求程式,讓用戶在瀏覽器完成這一切的話,麻煩就來了。問題在於:更動狀態時,也同時需要更動 UI 的顯示。

+ +

讓我們藉由待辦事項程式的一個功能來看看這個問題有多難搞:把工作清單渲染出來。

+ +

DOM 的冗長變化

+ +

建立 HTML 元素並在瀏覽器上渲染,會需要驚人數量的程式碼。假設我們的狀態,是一個由多個物件組成的陣列:

+ +
const state = [
+  {
+    id: 'todo-0',
+    name: 'Learn some frameworks!'
+  }
+]
+ +

我們如何對用戶顯示工作?我們想將每個工作,都表示為一個列表項目:結構為無序列表元素 <ul> 內,含有一定數量的 <li> 元素。怎麼做呢?看起來就像這樣:

+ +
function buildTodoItemEl(id, name) {
+  const item = document.createElement('li');
+  const span = document.createElement('span');
+  const textContent = document.createTextNode(name);
+
+  span.appendChild(textContent)
+
+  item.id = id;
+  item.appendChild(span);
+  item.appendChild(buildDeleteButtonEl(id));
+
+  return item;
+}
+ +

我們在這裡用上了 document.createElement() 方法建立了 <li>、還有一些程式碼來建立需要的屬性與子元素。

+ +

程式的第十行引用了另一個構建函式:buildDeleteButtonEl()。它與用於構建列表元素的模式很像:

+ +
function buildDeleteButtonEl(id) {
+  const button = document.createElement('button');
+  const textContent = document.createTextNode('Delete');
+
+  button.setAttribute('type', 'button');
+  button.appendChild(textContent);
+
+  return button;
+}
+ +

這個按鈕還派不上用場,但稍後我們會用它來實做刪除功能。這渲染程式,會讓頁面看起來像這樣:

+ +
function renderTodoList() {
+  const frag = document.createDocumentFragment();
+  state.tasks.forEach(task => {
+    const item = buildTodoItemEl(task.id, task.name);
+    frag.appendChild(item);
+  });
+
+  while (todoListEl.firstChild) {
+    todoListEl.removeChild(todoListEl.firstChild);
+  }
+  todoListEl.appendChild(frag);
+}
+ +

光是為了弄 UI 我們就寫了大約三十行左右的程式:這樣就只是為了能讓清單在 DOM 渲染而已喔。更別提之後還需要添加方便樣式化的 class。

+ +

像範例這樣直接操作 DOM 的話,會需要理解很多 DOM 的東西:像是 DOM 的原理、如何建立元素、更改屬性、巢狀排列……同時還要把他們都呈現出來。這些程式甚至還沒有處理與用戶的互動或工作。在增加功能的時候,我們需要在正確的時間、用正確的方法,來更新我們的 UI。

+ +

JavaScript 框架旨在使這類工作更加輕鬆:他們會提供更好的開發體驗。框架本身並沒有給 JavaScript 提供新功能;而是用更容易的方案,建立當代的網站。

+ +

如果想查看本節中的程式碼範例,請參閱 CodePen 的程式:這網站同樣允許用戶添加和刪除新任務。

+ +

閱讀本節中使用的 JavaScript 資訊:

+ + + +

建立 UI 的另一種方法

+ +

JavaScript 框架都會提供一種能更加宣告性撰寫介面的方法。也就是說,框架能讓你描述 UI 看起來要怎麼樣、然後在 DOM 的背後完成這一切。

+ +

原生 JavaScript 試圖重複建立新 DOM 元素的方法,很難一眼理解。相反地,來看看 Vue 的程式碼會怎麼完成吧:

+ +
<ul>
+  <li v-for="task in tasks" v-bind:key="task.id">
+    <span>\{{task.name\}}</span>
+    <button type="button">Delete</button>
+  </li>
+</ul>
+ +

就這樣啦。原本大約三十多行的程式,現在只要六行。如果不太熟悉大括號和 v- 屬性的話,沒關係;那些語法會在 Vue 模塊學到。這裡只是要講說與原生 JavaScript 對比,框架的程式碼看起來更像是實際呈現的 UI。

+ +

也因為有 Vue,我們再也不用自己寫針對 UI 呈現的函式;整個框架會幫我們用最優化、最效率的方法完成這件事。我們只要告訴 Vue 整個排版要怎麼排就好。熟悉 Vue 的開發者,也可以盡快參與我們的專案、搞清楚整個專案到底怎麼做的。不過並不是只有 Vue 這樣:使用框架本身,就可以提高團隊與個人的工作效率。

+ +

要在原生 JavaScript 做類似的事是可以的。樣板文字就能在編寫 HTML 字串的同時,也表示最終元素的外觀。就算是待辦事項列表應用,這樣簡單的事情,這可能是一個有用的想法,但是對於管理成千上萬條數據記錄、並且要在用戶界面中呈現盡可能多唯一元素的大型應用程序而言,這樣子是很難維護的。

+ +

框架給我們的其他東西

+ +

讓我們看看框架賦予的其他優勢。正如之前提,你可以透過原生 JavaScript 實現框架,但是使用框架可以消除自行解決這些問題所需要的認知負擔。

+ +

工具

+ +

本模塊提到的幾個框架,背後都有著龐大而活躍的社群;這些社群形成了各種生態圈、並提供能增進開發體驗的工具:像是確保功能正常的測試、或著維持程式一致性的 linting。

+ +
+

:如果對這方面的概念有興趣,請看看 Client-side tooling overview

+
+ +

切分

+ +

大多數框架鼓勵開發者把介面的各部份,封裝成各種組件(components):也就是一個個可維護、可互通、還可重用的程式碼塊(chunks of code)。與該組件相關連的程式,可獨立為一個、或數個獨立的程式。在原生 JavaScript 裡面要這麼做的話,開發者就必須靠自己的慣例,才能在高效、可擴展的情況下,實現這個目標。但大多數的 JavaScript 開發者,最後會讓 UI 相關的所有程式,都分散在整個文件中。

+ +

路由

+ +

web 最重要的功能之一,就是頁面之間的導航:畢竟它就是相互連接文件的網路。在你點選網站上的連結時,瀏覽器會與伺服器溝通、並獲取新內容以便顯示給你看。也因為這樣,地址欄中的 URL 就會更改。你可以保存這個新的 URL 並稍後回來、或與其他人分享該 URL,以便他們輕鬆地找到同一個頁面。你的瀏覽器會記住這個導航歷史記錄,也能在頁面之間來回導航。這就叫伺服器端路由(server-side routing)。

+ +

現代的網路應用程式通常不獲取和渲染新的 HTML 文件:它們通常載入單個 HTML Shell,並不斷更新其中的 DOM 同時,不導航用戶到新地址(這被稱為單頁應用single page appsSPA)。每個新的虛擬網頁通常稱為 視圖(view),一般來說也不執行路由。

+ +

在 SPA 複雜到一定的程度、也有渲染出足夠獨特的視圖時,給應用程式導入路由功能,就變得很重要:人們習慣在應用程式中,透過連結導航到特定頁面,在導航歷史記錄中前進和後退等,而當這些標準的 Web 功能被破壞時,他們的體驗也會受到影響。如果導航功能以用戶端程式提供,這就叫做用戶端路由(server-side routing)。

+ +

可以透過原生 JavaScript 實做路由功能。但比較活躍的框架都有相對應的函式庫,讓路由功能在開發過程中更加直觀。

+ +

使用框架時要考慮的事情

+ +

想成為一位高效的網路開發,意味著你需要選擇最合適的工具:JavaScript 框架能讓前端開發變簡單,但它並不是萬能仙丹。我們回在這個章節探討選擇框架需要考慮的事情。請注意,你可能完全不需要框架。不要為了用框架而用框架。

+ +

熟悉工具

+ +

如同原生 JavaScript,框架也需要理解它們各自的特性。在選好框架前,確保有足夠的時間熟悉框架,以便讓它成為開發的墊腳石,而不是絆腳石。同時,也要確保你的同事們能接受它。

+ +

過度工程化

+ +

一個 web 專案如果是個只有數個個人頁面、還幾乎沒有交互功能的話,你完全不需要 JavaScript 框架、甚至 JavaScript 本身也不需要。也就是說,框架並不是整體式的,其中一些可能更適合於小型專案。一篇在 Smashing Magazine 的文章中,作者 Sarah Drasner 寫了一篇怎麼用 Vue 取代 jQuery 的文章、讓網頁的一小部分具有交互性。

+ +

更大的程式庫和抽象化

+ +

框架能寫出宣告式程式、有時候還會少寫程式。這一切都是透過框架在背後處理 DOM 互動所達成的。這種抽象化給開發者提供了相當棒的體驗,但這並不是免費的。為了把編寫的程式變成能與 DOM 互動的玩意,框架必須執行自己的程式;而這反過來又會讓專案變大,執行演算的開銷也更高昂。

+ +

不可避免地,這會產生一些額外的程式;而儘管一個支持 tree-shaking(刪除在構建過程中未實際用到的程式)的框架,會讓應用程式保持小巧,但在考慮性能時,這將是必須牢記在心的因素之一,尤其是在受網路/儲存空間受限的設備上(像是手機)。

+ +

框架的抽象化不僅影響你的 JavaScript、它也會影響你對與網絡本質的關係:無論如何構建 Web,最後與用戶交流的都是 HTML。用 JavaScript 編寫整個程式,會讓你看不到 HTML 本身、以及各標籤的用途,最後會生出不語義、且有障礙的 HTML 文件。實際上,你甚至能寫出一個完全依賴 JavaScript,沒有它就完全動不了的脆弱應用程式。

+ +

框架不是問題的根源。如果優先事項設錯了,任何應用程式都會變得脆弱、腫大、且障礙多舛。不過,框架確實擴大了我們作為開發人員的優先事項。如果想做出一個很複雜的 Web 程式,這當然能作到;但如果優先事項無法確保性能與無障礙的話,框架將放大這方面的問題。現在的 Web 不再是一個健壯的,內容優先的文件網絡,而是常將 JavaScript 放在首位,用戶體驗則放在最後。

+ +

框架網站的無障礙議題

+ +

讓我們以上一節的內容為基礎,並進一步討論無障礙問題。消除用戶界面的障礙總是需要點思考與努力,而框架會使該過程複雜化。你通常要用上進階的框架 API 來訪問本機瀏覽器功能,例如 ARIA live region 或 focus 管理。

+ +

在某些情況下,框架應用程式會發生在傳統網站不存在的障礙。最明顯的例子,就是前述的客戶端路由。

+ +

使用傳統(伺服器端)路由瀏覽 Web 會出現可預測的結果。瀏覽器知道將焦點設置在頁面頂部、輔助技術將宣布頁面標題。在導航到新頁面時,這些事情都一定會發生。

+ +

使用客戶端路由時,瀏覽器不會加載新頁面,因此它不知道要自動調整焦點、或宣告新的頁面標題。框架作者會花費大量時間和精力,來編寫可重現這些功能的 JavaScript,但沒有一個框架能做到如此完美。

+ +

結論是,所有的 Web 專案一開始,就要應該考慮無障礙問題。如果專案使用抽象的框架、又不考慮無障礙問題的話,未來衍生的無障礙問題會更嚴重。

+ +

如何選擇框架

+ +

不同模塊的框架,會採用不同的方法。來開發 Web 應用程式。框架都會定期變化、也都有其優缺點。選擇哪個框架的過程,是與團隊及專案息息相關的。你需要透過研究,來找出合適的需求。換句話說,我們已經找出了一些能有效地研究出選擇的問題:

+ +
    +
  1. 框架支援哪些瀏覽器?
  2. +
  3. 框架使用哪個特定領域語言(domain-specific language)?
  4. +
  5. 框架有夠大的社群與夠好的文件(或其他東西)支援嗎?
  6. +
+ +

接下來我們退提供一個表格,來展示各大框架的瀏覽器支援、還有能用的特定領域語言

+ +

一般來說,特定領域語言(domain-specific language, DSL)是一種與的特定領域軟體開發相關的程式語言。以框架的脈絡來說,DSL 是能讓開發更簡單的 JavaScript 或 HTML 變體。最重要的是,沒有哪個框架要求開發者使用某種特定領域語言,但框架們在挑選 DSL 方面,早已心有所屬了。選擇不採用該框架的首選 DSL,可能就會失去本可增添開發人員體驗的功能。

+ +

在為任何新專案做出選擇時,你需要認真考慮框架的支持矩陣(support matrix)和 DSL。瀏覽器要是不支援,會成為用戶的障礙;而 DSL 要是不支援,則會你和你開發團隊的障礙。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
框架瀏覽器支援首選的 DSL支援的 DSL
AngularIE9+TypeScript基於 HTML; TypeScript
React當代瀏覽器(IE9+ 含有 Polyfill)JSXJSX; TypeScript
VueIE9+基於 HTML基於 HTML, JSX, Pug
Ember當代瀏覽器(IE9+ 直到 2.18 為止)HandlebarsHandlebars, TypeScript
+ +
+

:「基於 HTML」的 DSL 並沒有官方名字。雖然它們不完全是 DSL,但也不是標準的 HTML,所在我們在此附帶一題。

+
+ +

表格的引用來源:

+ + + +

框架有堅實的社區嗎?

+ +

這大概是最難評估的,因為社區沒辦法用什麼數字直接估算。你或許可以用 GitHub 的星星、或是 npm 的下載量來看,但有時最好的辦法,是找看看一些論壇、或和其他開發者聊聊看。這不只是社區大小的問題而已,你還需要看看社區多麼熱情和包容、以及文件多好讀。

+ +

Web 的看法

+ +

在選框架這件事,不要只聽我們的話:網路上也有不少的討論。例如說,維基媒體基金會最近就選了 Vue 作為他們的前端框架,還發表了相關的請求意見稿。請求意見稿的作者 Eric Gardner 花了不少時間,概述維基媒體基金會的需求、還有為什麼他認為這個框架,對開發團隊有益。這個請求意見稿,是你在研究要使用什麼框架時,需要考量什麼的一個好例子。

+ +

State of JavaScript survey 也是有用的 JavaScript 開發者反饋集合。它包含了很多 JavaScript 相關的要點、包括有關框架使用情況、還有開發者對各框架看法的數據。網站也有數年的可用數據,以便了解框架的消長。

+ +

Vue 的開發團隊也寫了有關 Vue 與其他框架的詳盡比較。如同他們自知,這種比較可能會有一些偏見,但這仍然是一種寶貴的資源。

+ +

前端框架的替代

+ +

如果在尋找能夠加速開發的工具、卻又發現專案不需要前端 JavaScript 框架的話,可以試試其他用於構建 Web 的解決方案:

+ + + +

內容管理系統

+ +

內容管理系統( Content Management System, CMS)是能讓用戶在不自己寫程式的情況下,創建內容的工具。針對大型專案,尤其是撰寫者不熟悉程式、或者開發者想省時間的情況下,內容管理系統是個相當不錯的解決方案。不過,內容管理系統也需要費神去設定。使用 CMS 也同時意味著你會在最終輸出的控制方面,做出一定程度的退讓。比方說,如果 CMS 不太著墨在無障礙方面,那你也很難在這方面有所改進。

+ +

坊間常見的內容管理系統有 WordpressJoomlaDrupal

+ +

伺服器渲染

+ +

伺服器端渲染(Server-side rendering, SSR)是由伺服器負責渲染單頁應用的程式架構,與構建 JavaScript 程式中最常見,最直接的用戶端渲染(client-side rendering)相對。伺服器端渲染只單純傳送 HTML 檔案,所以對用戶端更友善;但設置起來就比用戶端渲染程式難得多。

+ +

本模塊的所有用戶端渲染框架,都有相對應的伺服器端渲染。像是 React 的 Next.js、Vue 的 Nuxt.js(對這的確很教人困惑,不過兩者沒有關係)、Ember 的 FastBoot、Angular 的 Angular Universal

+ +
+

:某些伺服器端渲染的解決方案,是由社區編寫和維護;但也有「官方」的解決方案,是由框架維護者提供的。

+
+ +

靜態網站產生器

+ +

靜態網站產生器是個可以給網站生成多個網頁的程式──這包括相對應的 CSS 或 JavaScript──以便在任何地方發布。發布主機可以是 GitHub pages 分支、或著 Netlify 實體、抑或著是私人的伺服器。這種方法有很多優點,主要是性能方面(用戶端收到網頁時,已經載入了整個網頁,所以不需要執行 JavaScript)與安全性(靜態網站的攻擊因為變少了)。靜態網站還是能在需要時用上 JavaScript,但靜態網站並不依賴 JavaScript。一如其他工具,靜態網站產生器需要點時間去搞懂。這可能是開發過程的障礙。

+ +

靜態網站的獨立網頁,要多少就能有多少。如同框架能加快開發用戶端 JavaScript 程式一般,靜態網站產生器也能快速產生 HTML 檔案(要不然,你本來要自己寫的)。靜態網站產生器也像框架一樣,能允許用戶給網頁撰寫組件;並在最後建立頁面時,把組件都結合起來。以靜態網站產生器而言,組件被稱為樣板(template)。靜態網站產生器構建的網頁,甚至可以作為框架應用程式的宿主:比方說你可以完成「如果希望用戶造訪某個特定頁面時,啟動 React 程式」這樣的需求。

+ +

靜態網站產生器已經存在好一段時間了,但他們最近在 Web 歷史中再度復興起來。現在有一些強大的選擇,像是 HugoJekyllEleventyGatsby

+ +

如果想深入理解靜態網站產生器的概念,看一下 Tatiana Mac 的 Beginner's guide to Eleventy。在該系列的第一篇文章中,她解釋了什麼是靜態網站生成器,以及它與發布 Web 內容的其他方式之間的關係。

+ +

結論

+ +

我們終於把框架介紹完了。我們還沒有教任何程式,但我們希望提供了有用的背景知識,說明為什麼要使用框架,如何選擇框架,還有燃起想要學習的興趣!

+ +

我們的下一篇文章,將探討更底層的東西,著眼於框架傾向於提供的特定種類的功能,以及它們為什麼能動。

+ +

{{NextMenu("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}

+ +

在本模塊

+ + diff --git a/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/react_todo_list_beginning/index.html b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/react_todo_list_beginning/index.html new file mode 100644 index 0000000000..a76fb04f60 --- /dev/null +++ b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/react_todo_list_beginning/index.html @@ -0,0 +1,614 @@ +--- +title: Beginning our React todo list +slug: >- + Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning +tags: + - Accessibility + - App + - CSS + - React + - component + - 初學者 + - 前端框架 + - 框架 + - 無障礙 +translation_of: >- + Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started","Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}
+ +
我們被賦予做出一個React原型app的任務--這個app將允許使用者新增、編輯、刪除任務;且可以標記任務完成而不被刪除。
+ +
文章將會與您一起完成一個基本 App component 的結構與畫面,以便稍後與其他 component 互動。
+ +
+

小提示:如果您需要檢查自己的程式碼與範例之間的差異,可以連到 todo-react repository,這裡有我們完整的程式碼。 Todo list 作品示範:https://mdn.github.io/todo-react-build/

+
+ + + + + + + + + + + + +
預備知識: +

知道 HTML, CSSJavaScript的核心語法、操作基本終端機指令 terminal/command line.

+
實作目標:介紹待辦事項清單案例研究,並掌握基本App結構和樣式。
+ +


+ 在軟體開發中,user story 透過使用者觀點傳達開發目標。動手開發前先定義好user stories可以幫助我們專注於需要工作的項目,而我們這個案例中的app需要實現以下功能:

+ +

使用者可以...

+ + + +

我們將一一處理這些使用者故事。

+ +

專案開始前,先清理一下

+ +

終端機指令 create-react-app 會產生一些我們這個專案用不到的檔案,讓我們來清理一下。

+ + + +

接著,請複製貼上以下終端機指令,以刪除專案中不需要的檔案;刪除前請確認您在專案的根目錄中!

+ +
# 移動到專案中的src資料夾
+cd src
+# 刪除一些檔案
+rm -- App.test.js App.css logo.svg serviceWorker.js setupTests.js
+# 回到專案上一層
+cd ..
+ +

小提示:

+ + + +

專案起點

+ +

作為專案起始點 starting point ,我們會提供兩件事:一個新的 App() function 來取代原生預設,以及一些 CSS 美化我們的app。

+ +

The JSX

+ +

複製以下片段貼到 App.js 中取代原先的 App() function:

+ +
function App(props) {
+  return (
+    <div className="todoapp stack-large">
+      <h1>TodoMatic</h1>
+      <form>
+        <h2 className="label-wrapper">
+          <label htmlFor="new-todo-input" className="label__lg">
+            What needs to be done?
+          </label>
+        </h2>
+        <input
+          type="text"
+          id="new-todo-input"
+          className="input input__lg"
+          name="text"
+          autoComplete="off"
+        />
+        <button type="submit" className="btn btn__primary btn__lg">
+          Add
+        </button>
+      </form>
+      <div className="filters btn-group stack-exception">
+        <button type="button" className="btn toggle-btn" aria-pressed="true">
+          <span className="visually-hidden">Show </span>
+          <span>all</span>
+          <span className="visually-hidden"> tasks</span>
+        </button>
+        <button type="button" className="btn toggle-btn" aria-pressed="false">
+          <span className="visually-hidden">Show </span>
+          <span>Active</span>
+          <span className="visually-hidden"> tasks</span>
+        </button>
+        <button type="button" className="btn toggle-btn" aria-pressed="false">
+          <span className="visually-hidden">Show </span>
+          <span>Completed</span>
+          <span className="visually-hidden"> tasks</span>
+        </button>
+      </div>
+      <h2 id="list-heading">
+        3 tasks remaining
+      </h2>
+      <ul
+        role="list"
+        className="todo-list stack-large stack-exception"
+        aria-labelledby="list-heading"
+      >
+        <li className="todo stack-small">
+          <div className="c-cb">
+            <input id="todo-0" type="checkbox" defaultChecked={true} />
+            <label className="todo-label" htmlFor="todo-0">
+              Eat
+            </label>
+          </div>
+          <div className="btn-group">
+            <button type="button" className="btn">
+              Edit <span className="visually-hidden">Eat</span>
+            </button>
+            <button type="button" className="btn btn__danger">
+              Delete <span className="visually-hidden">Eat</span>
+            </button>
+          </div>
+        </li>
+        <li className="todo stack-small">
+          <div className="c-cb">
+            <input id="todo-1" type="checkbox" />
+            <label className="todo-label" htmlFor="todo-1">
+              Sleep
+            </label>
+          </div>
+          <div className="btn-group">
+            <button type="button" className="btn">
+              Edit <span className="visually-hidden">Sleep</span>
+            </button>
+            <fbutton type="button" className="btn btn__danger">
+              Delete <span className="visually-hidden">Sleep</span>
+            </button>
+          </div>
+        </li>
+        <li className="todo stack-small">
+          <div className="c-cb">
+            <input id="todo-2" type="checkbox" />
+            <label className="todo-label" htmlFor="todo-2">
+              Repeat
+            </label>
+          </div>
+          <div className="btn-group">
+            <button type="button" className="btn">
+              Edit <span className="visually-hidden">Repeat</span>
+            </button>
+            <button type="button" className="btn btn__danger">
+              Delete <span className="visually-hidden">Repeat</span>
+            </button>
+          </div>
+        </li>
+      </ul>
+    </div>
+  );
+}
+
+ +

再來,請打開 public/index.html 改掉 <title> 元素中的文字,將文字改為 TodoMatic,這樣才能對應到上述 <h1> 的文字。

+ +
<title>TodoMatic</title>
+ +

當您更新瀏覽器,您應該可以看到以下畫面:

+ +

todo-matic app, unstyled, showing a jumbled mess of labels, inputs, and buttons

+ +

畫面醜醜的對吧,而且還沒有實際功能,沒關係讓我們馬上來美化它。

+ +

在此之前,回頭複習一下我們的JSX,以及它與用戶故事的對應關係:

+ + + +

這個表單<form> 允許我們新增、管理任務, <button>幫助我們篩選任務狀態,<ul><li> 則負責展示任務清單。接著由於缺乏編輯任務的UI,讓我們開始來處理畫面美化的部分吧。

+ +

Accessibility features 無障礙設定

+ +

您可能已經注意到一些不常見的屬性,例如:

+ +
<button type="button" className="btn toggle-btn" aria-pressed="true">
+  <span className="visually-hidden">Show </span>
+  <span>all</span>
+  <span className="visually-hidden"> tasks</span>
+</button>
+ +

aria-pressed 元素可以跟輔助工具對話(像是螢幕閱讀器),這個button 總是處於: pressed 或 unpressed其中之一的狀態。可以想像它們如同 on 與 off。設定 true 代表這個button預設開啟pressed

+ +

class visually-hidden 在我們加入CSS前還不會有作用;當我們加入樣式後,這個class會對一般使用者隱藏,因為視覺使用者不需要這些文字;而仰賴閱讀器的使用者則可以聽到更多輔助文字來提高的讀取理解與體驗。

+ +

您還可以發現 <ul> 元素中:

+ +
<ul
+  role="list"
+  className="todo-list stack-large stack-exception"
+  aria-labelledby="list-heading"
+>
+ +

role 屬性會向科技輔具說明各種元素分別代表什麼用途。雖然瀏覽器預設<ul> 為清單,但是由於樣式表會破壞這個功能,因此需要使用role 屬性保留 "list" 清單這個意思。如果您想了解更多role 屬性的重要性,請參照Scott O'Hara’s article, “Fixing Lists”

+ +

aria-labelledby 屬性告訴科技輔具,我們將清單標題list heading 設為label,以描述下方的程式碼片段;將這些關聯設定好會幫助使用科技輔具的朋友更好的理解前因後果。

+ +

最後,我們清單中的labels 與 inputs對JSX而言將會有些特別的屬性:

+ +
<input id="todo-0" type="checkbox" defaultChecked={true} />
+<label className="todo-label" htmlFor="todo-0">
+  Eat
+</label>
+ +

<input/ >中的 defaultChecked 屬性會讓 React 預設勾選某項目。假如我們同一般寫HTML一樣使用 checked,React 會紀錄一些:handling events on the checkbox警告到瀏覽器console中,而這些是我們想避免的。不過先別擔心,我們在稍後討論事件的章節會教大家解決這個問題。

+ +

htmlFor 屬性對應HTML中的 for 屬性 ,我們不能在JSX中使用for 屬性因為 for 是保留字,因此React 使用 htmlFor 取代 for

+ +

備註:

+ + + +

Implementing our styles 實作CSS美化

+ +

將以下的CSS貼進 src/index.css 取代原本的預設內容:

+ +
/* RESETS */
+*,
+*::before,
+*::after {
+  box-sizing: border-box;
+}
+*:focus {
+  outline: 3px dashed #228bec;
+  outline-offset: 0;
+}
+html {
+  font: 62.5% / 1.15 sans-serif;
+}
+h1,
+h2 {
+  margin-bottom: 0;
+}
+ul {
+  list-style: none;
+  padding: 0;
+}
+button {
+  border: none;
+  margin: 0;
+  padding: 0;
+  width: auto;
+  overflow: visible;
+  background: transparent;
+  color: inherit;
+  font: inherit;
+  line-height: normal;
+  -webkit-font-smoothing: inherit;
+  -moz-osx-font-smoothing: inherit;
+  -webkit-appearance: none;
+}
+button::-moz-focus-inner {
+  border: 0;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+  font-family: inherit;
+  font-size: 100%;
+  line-height: 1.15;
+  margin: 0;
+}
+button,
+input {
+  overflow: visible;
+}
+input[type="text"] {
+  border-radius: 0;
+}
+body {
+  width: 100%;
+  max-width: 68rem;
+  margin: 0 auto;
+  font: 1.6rem/1.25 Arial, sans-serif;
+  background-color: #f5f5f5;
+  color: #4d4d4d;
+}
+@media screen and (min-width: 620px) {
+  body {
+    font-size: 1.9rem;
+    line-height: 1.31579;
+  }
+}
+/*END RESETS*/
+/* GLOBAL STYLES */
+.form-group > input[type="text"] {
+  display: inline-block;
+  margin-top: 0.4rem;
+}
+.btn {
+  padding: 0.8rem 1rem 0.7rem;
+  border: 0.2rem solid #4d4d4d;
+  cursor: pointer;
+  text-transform: capitalize;
+}
+.btn.toggle-btn {
+  border-width: 1px;
+  border-color: #d3d3d3;
+}
+.btn.toggle-btn[aria-pressed="true"] {
+  text-decoration: underline;
+  border-color: #4d4d4d;
+}
+.btn__danger {
+  color: #fff;
+  background-color: #ca3c3c;
+  border-color: #bd2130;
+}
+.btn__filter {
+  border-color: lightgrey;
+}
+.btn__primary {
+  color: #fff;
+  background-color: #000;
+}
+.btn-group {
+  display: flex;
+  justify-content: space-between;
+}
+.btn-group > * {
+  flex: 1 1 49%;
+}
+.btn-group > * + * {
+  margin-left: 0.8rem;
+}
+.label-wrapper {
+  margin: 0;
+  flex: 0 0 100%;
+  text-align: center;
+}
+.visually-hidden {
+  position: absolute !important;
+  height: 1px;
+  width: 1px;
+  overflow: hidden;
+  clip: rect(1px 1px 1px 1px);
+  clip: rect(1px, 1px, 1px, 1px);
+  white-space: nowrap;
+}
+[class*="stack"] > * {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+.stack-small > * + * {
+  margin-top: 1.25rem;
+}
+.stack-large > * + * {
+  margin-top: 2.5rem;
+}
+@media screen and (min-width: 550px) {
+  .stack-small > * + * {
+    margin-top: 1.4rem;
+  }
+  .stack-large > * + * {
+    margin-top: 2.8rem;
+  }
+}
+.stack-exception {
+  margin-top: 1.2rem;
+}
+/* END GLOBAL STYLES */
+.todoapp {
+  background: #fff;
+  margin: 2rem 0 4rem 0;
+  padding: 1rem;
+  position: relative;
+  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 2.5rem 5rem 0 rgba(0, 0, 0, 0.1);
+}
+@media screen and (min-width: 550px) {
+  .todoapp {
+    padding: 4rem;
+  }
+}
+.todoapp > * {
+  max-width: 50rem;
+  margin-left: auto;
+  margin-right: auto;
+}
+.todoapp > form {
+  max-width: 100%;
+}
+.todoapp > h1 {
+  display: block;
+  max-width: 100%;
+  text-align: center;
+  margin: 0;
+  margin-bottom: 1rem;
+}
+.label__lg {
+  line-height: 1.01567;
+  font-weight: 300;
+  padding: 0.8rem;
+  margin-bottom: 1rem;
+  text-align: center;
+}
+.input__lg {
+  padding: 2rem;
+  border: 2px solid #000;
+}
+.input__lg:focus {
+  border-color: #4d4d4d;
+  box-shadow: inset 0 0 0 2px;
+}
+[class*="__lg"] {
+  display: inline-block;
+  width: 100%;
+  font-size: 1.9rem;
+}
+[class*="__lg"]:not(:last-child) {
+  margin-bottom: 1rem;
+}
+@media screen and (min-width: 620px) {
+  [class*="__lg"] {
+    font-size: 2.4rem;
+  }
+}
+.filters {
+  width: 100%;
+  margin: unset auto;
+}
+/* Todo item styles */
+.todo {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+}
+.todo > * {
+  flex: 0 0 100%;
+}
+.todo-text {
+  width: 100%;
+  min-height: 4.4rem;
+  padding: 0.4rem 0.8rem;
+  border: 2px solid #565656;
+}
+.todo-text:focus {
+  box-shadow: inset 0 0 0 2px;
+}
+/* CHECKBOX STYLES */
+.c-cb {
+  box-sizing: border-box;
+  font-family: Arial, sans-serif;
+  -webkit-font-smoothing: antialiased;
+  font-weight: 400;
+  font-size: 1.6rem;
+  line-height: 1.25;
+  display: block;
+  position: relative;
+  min-height: 44px;
+  padding-left: 40px;
+  clear: left;
+}
+.c-cb > label::before,
+.c-cb > input[type="checkbox"] {
+  box-sizing: border-box;
+  top: -2px;
+  left: -2px;
+  width: 44px;
+  height: 44px;
+}
+.c-cb > input[type="checkbox"] {
+  -webkit-font-smoothing: antialiased;
+  cursor: pointer;
+  position: absolute;
+  z-index: 1;
+  margin: 0;
+  opacity: 0;
+}
+.c-cb > label {
+  font-size: inherit;
+  font-family: inherit;
+  line-height: inherit;
+  display: inline-block;
+  margin-bottom: 0;
+  padding: 8px 15px 5px;
+  cursor: pointer;
+  touch-action: manipulation;
+}
+.c-cb > label::before {
+  content: "";
+  position: absolute;
+  border: 2px solid currentColor;
+  background: transparent;
+}
+.c-cb > input[type="checkbox"]:focus + label::before {
+  border-width: 4px;
+  outline: 3px dashed #228bec;
+}
+.c-cb > label::after {
+  box-sizing: content-box;
+  content: "";
+  position: absolute;
+  top: 11px;
+  left: 9px;
+  width: 18px;
+  height: 7px;
+  transform: rotate(-45deg);
+  border: solid;
+  border-width: 0 0 5px 5px;
+  border-top-color: transparent;
+  opacity: 0;
+  background: transparent;
+}
+.c-cb > input[type="checkbox"]:checked + label::after {
+  opacity: 1;
+}
+ +

儲存並更新瀏覽器後,您的app應當會有對應的美化。

+ +

小結

+ +

現在我們的待辦清單app終於比較像真正的app了!問題是它還沒真正提供功能,我們將在下一章解決這個問題。

+ +

{{PreviousMenuNext("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started","Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}

+ +

在本模塊

+ + diff --git a/files/zh-tw/learn/tools_and_testing/cross_browser_testing/automated_testing/index.html b/files/zh-tw/learn/tools_and_testing/cross_browser_testing/automated_testing/index.html new file mode 100644 index 0000000000..59126f3334 --- /dev/null +++ b/files/zh-tw/learn/tools_and_testing/cross_browser_testing/automated_testing/index.html @@ -0,0 +1,372 @@ +--- +title: 自動化測試介紹 +slug: Learn/Tools_and_testing/Cross_browser_testing/Automated_testing +translation_of: Learn/Tools_and_testing/Cross_browser_testing/Automated_testing +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Tools_and_testing/Cross_browser_testing/Feature_detection", "Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment", "Learn/Tools_and_testing/Cross_browser_testing")}}
+ +

每天在好幾個瀏覽器與設備上,運行手動測試數次,既乏味又浪費時間。要有效率的處理這種事,就要開始熟悉自動化工具。我們會在這篇文章看看有哪些可用的工具、如何使用它們、以及如何使用如 Sauce Labs 與 Browser Stack 的商業化瀏覽器測試程式之基本講述。

+ + + + + + + + + + + + +
先決條件:熟悉 HTMLCSSJavaScript 核心語言的基本;跨瀏覽器測試的重要原則
目標:提供理解自動化測試的需求、它如何讓你生活變得簡單、還有如何透過一些商業產品令事情更簡易。
+ +

自動化讓事情變簡單

+ +

在這個模組中,我們詳細介紹了不同的方式,來測試你的網站和應用程序,並解釋了跨瀏覽器測試工作應該在哪些瀏覽器上進行測試、輔助功能要點……等等。聽來要做很多事呢,不是嗎?

+ +

我們同意手動測試前述的一切,真的很累。幸好有很多工具,可以讓我們不用這麼累。有兩個主要方法,可以自動執行我們討論過的測試:

+ +
    +
  1. 使用如 GruntGulpGulpnpm scripts 之類的任務執行器(task runner)來跑測試,並在組建過程中清理你的程式碼。這個方法很適合如清理並最小化程式碼、增加 CSS 前輟或最大化跨瀏覽器的 transpiling nascent JavaScript 功能...之類的任務。
  2. +
  3. 使用如 Selenium 之類的瀏覽器自動化系統,在安裝好的瀏覽器跑指定測試並傳回結果,並在瀏覽器出問題的時候警告你。諸如 Sauce LabsBrowser Stack 之類的商業跨瀏覽器測試程式都是基於 Selenium,但能讓你用簡單的介面,遠端訪問他們設好的東西,如此一來,就能省下自己架設測試系統的心力。
  4. +
+ +

我們會在下一篇文章,專注於如何設定基於 Selenium 的個人測試系統。這篇文章則會專注於如何設定任務執行器,並簡單與系統化地,使用前述的商業系統。

+ +
+

注意:這兩件事情並不互斥。我們可以用任務執行器來訪問服務。例如,你可以用 Sauce Labs 的 API 來跑跨瀏覽器測試,並顯示結果。我們會在下面解釋這件事。

+
+ +

使用任務執行器以自動化測試工具

+ +

如同前述,你可以透過任務執行器運行在組建功能中,所有想要自動化的常見任務,例如在每次存檔,或其他時候,清理並壓縮程式碼。在這個章節,我們將專注於如何用對初學者友善的選項,透過 Node 與 Gulp 執行自動化任務。

+ +

設定 Node 與 npm

+ +

今日,此類工具大都基於 {{Glossary("Node.js")}}。所以,你需要從 nodejs.org 安裝它:

+ +
    +
  1. 從上面的網站下載安裝程式。
  2. +
  3. 如同安裝其他程式般地安裝它。注意 Node 還會安裝 Node Package Manager(npm),它能讓你輕易安裝套件(package)、分享你自己寫的套件、還有在你的專案運行腳本。
  4. +
  5. 安裝完成後,請輸入以下指令以測試 node 是否已安裝到電腦裡面,它會回傳 Node 與 npm 的版本: +
    node -v
    +npm -v
    +
  6. +
  7. 如果已經安裝過 Node/npm,你應該更新它們到最新版本。要更新 Node 的最可行方法,是從上述網站下載並安裝更新的軟體包。要更新 npm,請在文字介面輸入以下指令: +
    npm install npm@latest -g
    +
  8. +
+ +
+

注意:如果因為權限問題而失敗,Fixing npm permissions 應該對你有所幫助。

+
+ +

要在專案裡面使用 node/npm 套件,你需要把專案所在目錄設為 npm 專案。它很簡單。

+ +

例如說,先來做個 test 目錄,以便不操心自己搞壞什麼。

+ +
    +
  1. 選個合適的地方建立目錄。可以在檔案管理員的 UI 完成,或是輸入以下指令: +
    mkdir node-test
    +
  2. +
  3. 要把這目錄變成 npm 專案,就要到 test 把此目錄初始化。請輸入: +
    cd node-test
    +npm init
    +
  4. +
  5. 第二個指令(npm init)會問你幾個問題,以便取得專案所需的資訊。你可以把一切都以預設帶過。
  6. +
  7. 問完所有問題後,它會問你是否對設定滿意。輸入 yes 並按下 Enter 鍵,npm 就會在目錄產生一個稱為 package.json 的檔案。
  8. +
+ +

這個檔案基本上就是個專案的設定檔。你可以之後再來設定,但目前它大概長成這個樣子:

+ +
{
+  "name": "node-test",
+  "version": "1.0.0",
+  "description": "Test for npm projects",
+  "main": "index.js",
+  "scripts": {
+    "test": "test"
+  },
+  "author": "Chris Mills",
+  "license": "MIT"
+}
+ +

有了這個檔案,你已經可以開始了。

+ +

設定 Gulp 自動化

+ +

來看看怎麼用 Gulp 設定一些測試工具的自動化。

+ +
    +
  1. 要開始的話,得先建立一個 test npm 專案。使用的程式會在下面的章節提到。
  2. +
  3. 接著,你需要有些簡單的 HTML、CSS、JavaScript 來測試系統:你可以複製我們的 index.htmlmain.jsstyle.css 到專案裡面,一個稱為 src 的目錄。現在你可以隨意嘗試測試內容,不過請注意這些工具不會直接在 JS/CSS 裡面運作:你需要外部的檔案。
  4. +
  5. 首先,你要下這個指令,以全域(意思是說,它能在所有專案使用)的形式安裝 gulp: +
    npm install --global gulp-cli
    +
  6. +
  7. 接著在 npm 專案輸入以下指令,以便專案將 gulp 認定為安裝所須: +
    npm install --save-dev gulp
    +
  8. +
  9. 在專案裡面建立一個叫 gulpfile.js 的檔案。這個檔案能運行所有我們需要做的任務。在檔案裡面加這個指令: +
    var gulp = require('gulp');
    +
    +gulp.task('default', function() {
    +  console.log('Gulp running');
    +});
    + 這檔案需要我們之前安裝過的 gulp 模組,接著會跑些只顯示訊息的基本任務:它至少讓我們知道 Gulp 可以動。每個 gulp task 的基本格式都一樣——gulp 會執行 task() 方法,並給出兩個參數——任務的名稱、還有指示如何完成任務的回傳函式。
  10. +
  11. 現在你可以跑 gulp task 了——輸入這個指令吧: +
    gulp
    +
    +
  12. +
+ +

讓 Gulp 做些實際的工作

+ +

要讓 Gulp 真的能幹些事情,就得先想想我們想要它做什麼。我們的專案想要做這些合理的基本功能:

+ + + +

請詳見上面我們使用的 gulp 套件連結,以獲取完整指引。

+ +

要用套件的話,要先透過 npm 安裝之,之後在 gulpfile.js 上面引用需要的套件,再接著到下面加入想測試的東西,最後把你的任務命名為 default

+ +

在往下一步開始進發以前,把 default task 改成:

+ +
gulp.task('default', [ ]);
+ +

在陣列裡面寫下所有想在命令列輸入 gulp 後,希望 Gulp 運作的命令。

+ +

html-tidy

+ +
    +
  1. 輸入以下指令安裝: +
    npm install --save-dev gulp-htmltidy
    +
    + +
    +

    注意--save-dev 會把此套件加到開發相依設定中。如果去看專案的 package.json 檔,你會在 devDependencies 屬性看到它被放在裡面。

    +
    +
  2. +
  3. gulpfile.js 增加這個相依: +
    var htmltidy = require('gulp-htmltidy');
    +
  4. +
  5. gulpfile.js 的底部加入以下測試: +
    gulp.task('html', function() {
    +  return gulp.src('src/index.html')
    +        .pipe(htmltidy())
    +        .pipe(gulp.dest('build'));
    +});
    +
  6. +
  7. default 任務的陣列裡面加入 'html' 項目。
  8. +
+ +

在這裡我們抓到了 index.html 開發檔:gulp.src() 讓我們抓取需要完成事情所需的原始檔。

+ +

我們接著會用 pipe() 函式以通行另一個執行用的指令。我們可以應自己需求,把盡可能多的指令連接起來。在原始碼裡面,我們先執行能修復錯誤的 htmltidy() 函式。第二個 pipe() 函式會寫出 HTML 檔案的輸出至 build 目錄。

+ +

在 input 版本的檔案內,你可能發現到我們放了空白的 {{htmlelement("p")}} 元素,htmltidy 會在這個輸出檔創建後移除。

+ +

Autoprefixer 與 css-lint

+ +
    +
  1. 輸入以下指令安裝: +
    npm install --save-dev gulp-autoprefixer
    +npm install --save-dev gulp-csslint
    +
  2. +
  3. gulpfile.js 增加這個相依: +
    var autoprefixer = require('gulp-autoprefixer');
    +var csslint = require('gulp-csslint');
    +
  4. +
  5. gulpfile.js 的底部加入以下測試: +
    gulp.task('css', function() {
    +    return gulp.src('src/style.css')
    +        .pipe(csslint())
    +        .pipe(csslint.formatter('compact'))
    +        .pipe(autoprefixer({
    +            browsers: ['last 5 versions'],
    +            cascade: false
    +        }))
    +        .pipe(gulp.dest('build'));
    +});
    +
  6. +
  7. default 任務的陣列裡面加入 'css' 項目。
  8. +
+ +

我們在此選定了 style.css 檔案,對它執行了 csslint(它會在終端機上面列出所有 CSS 的錯誤),接著透過運行 autoprefixer 來增加所有為了在舊瀏覽器運行所需要的前輟修飾子。在 pipe chain 的最後面,我們把已經 modified prefixed CSS 輸出到 build 目錄。注意,這只有在 csslint 沒有找到錯誤的時候才能動──試著把 CSS 檔案內的大括弧移掉,看看會發生什麼事!

+ +

js-hint 與 babel

+ +
    +
  1. 輸入以下指令安裝: +
    npm install --save-dev gulp-babel babel-preset-es2015
    +npm install jshint gulp-jshint --save-dev
    +
    +
  2. +
  3. gulpfile.js 增加這個相依: +
    var babel = require('gulp-babel');
    +var jshint = require('gulp-jshint');
    +
    +
  4. +
  5. gulpfile.js 的底部加入以下測試: +
    gulp.task('js', function() {
    +    return gulp.src('src/main.js')
    +        .pipe(jshint())
    +        .pipe(jshint.reporter('default'))
    +        .pipe(babel({
    +            presets: ['es2015']
    +        }))
    +        .pipe(gulp.dest('build'));
    +});
    +
  6. +
  7. default 任務的陣列裡面加入 'js' 項目。
  8. +
+ +

我們在這裡抓了 main.js 檔案,對其運行 jshint 並使用 jshint.reporter 對終端機輸出結果;我們接著把檔案 pass 到 babel,它將其轉換至舊語法並將結果輸出至 build 目錄。我們原本的程式碼包含了 fat 箭頭函式,babel 會將其編寫為舊語法。

+ +

進一步的點子

+ +

把一切都設定好後,在專案目錄內用運行 gulp 指令,你應該能看到像這樣的輸出:

+ +

+ +

你可以試著把自動任務產生的檔案放在 build 目錄,並從瀏覽器的 build/index.html 觀察之。

+ +

如果出了問題,檢查下是不是加了上面寫的所有相依套件與測試,也請試著把 HTML/CSS/JavaScript 程式碼通通註解掉、接著執行 gulp 以便檢查能否忽略出錯的地方。

+ +

Gulp 還有個 watch() 函式能監視,並在每次存檔完就跑測試。例如,你可以試著在 gulpfile.js 底下增加以下程式碼:

+ +
gulp.task('watch', function(){
+  gulp.watch('src/*.html', ['html']);
+  gulp.watch('src/*.css', ['css']);
+  gulp.watch('src/*.js', ['js']);
+});
+ +

現在來輸入 gulp watch 指令。Gulp 會開始監視目錄,並在儲存 HTML、CSS、JavaScript 檔的時候,運行適當的任務。

+ +
+

* 是通配字符(wildcard character)--這裡的意思是「當任何檔案被儲存的時候,執行這些任務」。你也可以在主要任務內使用通配,例如 gulp.src('src/*.css') 會抓取所有的 CSS 檔案並執行 piped task。

+
+ +
+

:在我們的 watch 指令有個問題,那就是我們的 CSSLint/Autoprefixer combination throws full-blown errors when a CSS error is encountered, which stops the watch working. You'll have to restart the watch once a CSS error is encountered, or find another way to do this.

+
+ +

你還可以用 Gulp 做很多事情。Gulp plugin directory 收錄了近千個可搜尋的套件。

+ +

其他任務執行器

+ +

其實還有很多任務執行器能用。我們不會說 Gulp 是最好的解決方案,但它對我們而言很好用、而且也對新手友善。你可以嘗試這些解決方案:

+ + + +

使用 Sauce Labs 加快瀏覽器測試

+ +

有很多商業化的瀏覽器測試系統可供選擇,不過在這裡我們會探討 Sauce Labs。這並不是說它是可用工具裡面最好的,而是說它對初學者而言,是其中一個好上手的。

+ +

這種程式的基本前提,是存在一家擁有很多伺服器的公司,以便跑很多不同的測試。在使用服務的時候,你會給服務一個需要測試的 URL,還有諸如什麼瀏覽器需要測試之類的資訊。程式接著會設置擁有指定作業系統的虛擬機,並回傳螢幕截圖、視頻、日誌文件,文字之類的測試結果。

+ +

You can then step up a gear, using an API to access functionality programmatically, which means that such apps can be combined with task runners, your own local Selenium environments, etc., to create automated tests.

+ +

開始用 Sauce Labs

+ +

來透過 Sauce Labs Trial 開始熟悉吧。

+ +
    +
  1. 建立 Sauce Labs trial 帳號
  2. +
  3. 登入。通常在驗證電子郵件後,就能自動登入。
  4. +
+ +

基本的手動測試

+ +

Sauce Labs dashboard 有很多可用選項。現在,先確認是否位於 Manual Tests tab。

+ +
    +
  1. 點選 Start a new manual session
  2. +
  3. 在下個螢幕,輸入想測試的 URL(像是本例中要輸入 http://mdn.github.io/learning-area/javascript/building-blocks/events/show-video-box-fixed.html)接著透過不同的按鈕與清單,選擇想測試的瀏覽器/作業系統組合。如你所見,有很多很多的組合!
  4. +
  5. When you click Start session, a loading screen will then appear, which spins up a virtual machine running the combination you chose.
  6. +
  7. When loading has finished, you can then start to remotely test the web site running in the chosen browser.
  8. +
  9. From here you can see the layout as it would look in the browser you are testing, move the mouse around and try clicking buttons, etc. The top menu allows you to: +
      +
    • Stop the session
    • +
    • Give someone else a URL so they can observe the test remotely.
    • +
    • Copy text/notes to a remote clipboard.
    • +
    • Take a screenshot.
    • +
    • Test in full screen mode.
    • +
    +
  10. +
+ +

Once you stop the session, you'll return to the Manual Tests tab, where you'll see an entry for each of the previous manual sessions you started. Clicking on one of these entries shows more data for the session. In here you can for example download any screenshots you took, watch a video of the session, and view data logs for the session.

+ +
+

:This is already very useful, and way more convenient than having to set all these emulators and virtual machines by yourself.

+
+ +

進階:The Sauce Labs API

+ +

Sauce Labs 有個能允許程式化檢索帳號與現有測試詳情的 restful API,並講解測試與進一步細節,如手動測試無法錄製的 pass/fail 狀態。For example, you might want to run one of your own Selenium tests remotely using a Sauce Labs, to test a certain browser/OS combination, and then pass the test results back to Sauce Labs.

+ +

It has a number of clients available to allow you to make calls to the API using your favourite environment, be it PHP, Java, Node.js, etc.

+ +

Let's have a brief look at how we'd access the API using Node.js and node-saucelabs.

+ +
    +
  1. First, set up a new npm project to test this out, as detailed in {{anch("Setting up Node and npm")}}. Use a different directory name than before, like sauce-test for example.
  2. +
  3. 使用以下指令安裝 Node Sauce Labs wrapper: +
    npm install saucelabs
    +
  4. +
  5. 在專案根目錄下建立個稱作 call-sauce.js 的新檔案。寫入以下內容: +
    var SauceLabs = require('saucelabs');
    +
    +var myAccount = new SauceLabs({
    +  username: "your-sauce-username",
    +  password: "your-sauce-api-key"
    +});
    +
    +myAccount.getAccountDetails(function (err, res) {
    +  console.log(res);
    +  myAccount.getServiceStatus(function (err, res) {
    +    // Status of the Sauce Labs services
    +    console.log(res);
    +    myAccount.getJobs(function (err, jobs) {
    +      // Get a list of all your jobs
    +      for (var k in jobs) {
    +        if ( jobs.hasOwnProperty( k )) {
    +          myAccount.showJob(jobs[k].id, function (err, res) {
    +            var str = res.id + ": Status: " + res.status;
    +            if (res.error) {
    +              str += "\033[31m Error: " + res.error + " \033[0m";
    +            }
    +            console.log(str);
    +          });
    +        }
    +      }
    +    });
    +  });
    +});
    +
  6. +
  7. You'll need to fill in your Sauce Labs username and API key in the indicated places. These can be retrieved from your User Settings page. Fill these in now.
  8. +
  9. Make sure everything is saved, and run your file like so: +
    node call-sauce
    +
  10. +
+ +

進階:自動化測試

+ +

我們會在下一章覆蓋實際運行的 Sauce Lab 自動化測試。

+ +

總結

+ +

這是一切都還蠻簡單的,但我想你能看到自動化工具,在測試方面提供了很大的幫助。

+ +

下篇文章我們來關注怎麼用 Selenium 設定你自己的區域自動化系統,並與 Sauce Labs 做結合。

+ +

{{PreviousMenuNext("Learn/Tools_and_testing/Cross_browser_testing/Feature_detection", "Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment", "Learn/Tools_and_testing/Cross_browser_testing")}}

diff --git a/files/zh-tw/learn/tools_and_testing/cross_browser_testing/index.html b/files/zh-tw/learn/tools_and_testing/cross_browser_testing/index.html new file mode 100644 index 0000000000..2158e7ec3a --- /dev/null +++ b/files/zh-tw/learn/tools_and_testing/cross_browser_testing/index.html @@ -0,0 +1,33 @@ +--- +title: 跨瀏覽器測試 +slug: Learn/Tools_and_testing/Cross_browser_testing +translation_of: Learn/Tools_and_testing/Cross_browser_testing +--- +
{{LearnSidebar}}
+ +

此模組專注於測試網路專案的跨瀏覽器領域。在此,我們會辨認你的目標閱聽者(例如你最該對什麼樣的用戶、瀏覽器、還有設備操心?)如何做測試、不同類型的程式碼會碰上的主要問題、如何解決/減輕這些問題、哪些工具最能幫你測試和修復問題、還有如何用自動化加速測試。

+ +

先決條件

+ +

在使用文章所述的工具前,你應該確實理解 HTMLCSSJavaScript 核心語言的基本。

+ +

指引

+ +
+
跨瀏覽器測試介紹
+
這篇文章將透過給予跨瀏覽器測試概覽重點、回答諸如「何謂跨瀏覽器測試?」、「你最有可能碰上什麼問題?」、「測試、找出、並解決錯誤的主要方法有哪些?」的問題,以作為模組的開頭。
+
測試進行策略
+
接著,我們將針對測試執行深入研究、確定目標受眾(像是什麼瀏覽器、設備、或其他需要確認的地方)、低測試策略(low fi testing strategies,讓自己取得需要的設備、虛擬機、還有 adhoc 測試)、進階測試策略(自動化以及使用專用工具)、還有用戶群組間的測試。
+
處理常見的 HTML 與 CSS 問題
+
在這裡,我們將關注可能遇上的,常見跨瀏覽器 HTML 與 CSS 程式相關問題,還有能預防或修復淺在問題的工具。這裡面會有語法標示(linting code)、CSS 前輟處理、使用瀏覽器工具找出問題、使用 polyfill 支援瀏覽器、處理響應式網頁問題...等等。
+
處理常見的 JavaScript 問題
+
我們會開始觀察常見的跨瀏覽器 JavaScript 程式問題,以及修復的辦法。使用瀏覽器工具追蹤並解決問題、使用 Polyfill 與函式庫解決問題、在老舊瀏覽器實作新功能...等等。
+
處理常見的無障礙問題
+
我們要關注無障礙網頁,並提供常見問題的資訊、如何簡易測試、還有使用檢測/自動化工具,以排查無障礙問題。
+
功能檢測實做
+
功能檢測牽涉到確定瀏覽器是否支持某個程式碼,是否依賴他執行不同的程式碼,以便部分瀏覽器能提供可執行的體驗,而不是直接崩潰/錯誤。本文詳細介紹如何編寫自己的簡單功能檢測,如何使用函式庫來加速實現,以及用於功能檢測的本機功能,例如 @supports
+
自動化測試介紹
+
每天在好幾個瀏覽器與設備上,運行手動測試數次,既乏味又浪費時間。要有效率的處理這種事,就要開始熟悉自動化工具。我們會在這篇文章看看有哪些可用的工具、如何使用它們、以及如何使用如 Sauce Labs 與 Browser Stack 的商業化瀏覽器測試程式之基本講述。
+
設定你的自動化測試環境
+
我們會在這篇文章教你如何安裝自己的自動化測試環境、並透過 Selenium/WebDriver 以及 Node 的測試函式庫如 selenium-webdriver 來跑你的測試。我們還會講測試環境如何與上篇文章所講述的商業軟體做整合。
+
diff --git a/files/zh-tw/learn/tools_and_testing/index.html b/files/zh-tw/learn/tools_and_testing/index.html new file mode 100644 index 0000000000..23c9d3f335 --- /dev/null +++ b/files/zh-tw/learn/tools_and_testing/index.html @@ -0,0 +1,31 @@ +--- +title: 工具與測試 +slug: Learn/Tools_and_testing +translation_of: Learn/Tools_and_testing +--- +
{{LearnSidebar}}
+ +

當你開始對網路核心技術(如 HTML、CSS、JavaScript)感到熟悉、累積經驗、閱讀更多資源、學到更多技巧和竅門時,你會碰上一大堆的工具,從 CSS 與 JavaScript 開始,到測試並自動化程式、還有一堆眉眉角角。等到你網路專案變得龐大而複雜時,你可能會想要用上某些工具、並針對你的程式碼,撰寫些可信賴的測試計劃。學習專區的這一區,旨在給你做出明智抉擇的所需。

+ +

網路產業的職場令人興奮,但也並非全無弊病。當今用於建置網站的核心技術已相當成熟,然新功能日益漸增、而方便使用,並由那些技術為基礎的新工具也不斷問世。最重要的是,我們還要把跨瀏覽器支援銘記於心,並確保我們的程式碼遵循專案的最佳做法,以確保它們能在不同用戶使用的瀏覽器和設備上運行,身心障礙人士亦可使用。

+ +

決定該用什麼工具可能是個困難的過程,因此我們寫了這幾篇文章,來告訴你可以使用什麼樣的工具、它們能為你做什麼,以及如何針對產業的偏好利用之。

+ +
+

注意:因為隨時都會有新工具問世、舊工具退出,我們刻意把內容寫得盡可能中立:我們希望先關注這些工具所能完成,最重要的一般類型的任務,並最小化特定工具。很明顯,我們要示範工具使用,以展示具體技術,但請注意我們不一定推薦這些工具為最佳或唯一辦法:大多數情況下其實有其他方法,但我們希望為你提供一個清晰的工作方法論。

+
+ +

學習途徑

+ +

在使用文章所述的工具前,你應該確實理解 HTMLCSSJavaScript 核心語言的基本。比方說,在你開始處理複雜的程式碼錯誤前,要知道這些語言的基本原理、如何活用 JavaScript 函式庫、或是使用 test runner 給你的程式碼寫測試……等等。

+ +

最少,你需要扎實的基礎。

+ +

模組

+ +
+
現實世界的網路開發工具(TBD)
+
在此模組,我們會探索許多可用的網路開發工具。這包括檢查想解決的最常見任務類型,它們如何合併到工作流程中,以及目前可用於執行這些任務的最佳工具。
+
跨瀏覽器測試
+
此模組專注於測試網路專案的跨瀏覽器領域。在此,我們會辨認你的目標閱聽者(例如你最該對什麼樣的用戶、瀏覽器、還有設備操心?)如何做測試、不同類型的程式碼會碰上的主要問題、如何解決/減輕這些問題、哪些工具最能幫你測試和修復問題、還有如何用自動化加速測試。
+
diff --git a/files/zh-tw/localization_quick_start_guide/index.html b/files/zh-tw/localization_quick_start_guide/index.html new file mode 100644 index 0000000000..51fb9d4f8e --- /dev/null +++ b/files/zh-tw/localization_quick_start_guide/index.html @@ -0,0 +1,32 @@ +--- +title: Localization quick start guide +slug: Localization_Quick_Start_Guide +tags: + - Localization + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Localization/Quick_start_guide +--- +

Welcome to Mozilla localization (l10n for short)!

+

Whether you're here to start up your own localization in the Mozilla project or to join the efforts of an existing localization, you've come to the right place. This guide is filled with all of the basic, technical information you need to get involved in the Mozilla l10n program. We will take you through the steps to get started, from the initial environment setup to testing and releasing your own localization. Along the way, you'll learn about the variety of projects you can contribute to and the tools used to localize them.

+

When we get to specific examples, we'll take them from the Firefox project, as it is the most widely localized project within Mozilla. As you near the end of this guide, you should be able to make a change to Firefox in your local setting and then see that change in the Firefox interface. In closing, when you finish this guide, you will have all the tools necessary to start contributing!

+

Remember, this guide will instruct you on the technical aspects of Mozilla l10n only. Visit the L10n Process page to learn about the whole process.

+
+

Initial setup

+ Tech prep work before localizing.
+
+

Translation phase

+ L10n tools tutorials for translation.
+
+

QA phase

+ L10n testing tutorials.
+
+

Release phase

+ Steps to shipping your localization work.
+
+ These four stages make up tech side of the l10n program. To learn more about any of these, click on any of the links above. To get the big picture, we suggest you start with the green bubble and move from stage to stage.
+

 

+
+ Note: This guide is written for two types of contributors: those starting a new localization and those joining an existing localization. It is important to know which information applies to which type of contributor. To help you filter through to the most applicable information, note that all information that is unique to those starting a new localization will be in orange font. All information that is unique to those joining an existing localization will be in blue font.
+

 

+

{{ Next("Localization_Quick_Start_Guide/Initial_setup") }}

diff --git a/files/zh-tw/localization_quick_start_guide/initial_setup/index.html b/files/zh-tw/localization_quick_start_guide/initial_setup/index.html new file mode 100644 index 0000000000..00400f6dac --- /dev/null +++ b/files/zh-tw/localization_quick_start_guide/initial_setup/index.html @@ -0,0 +1,95 @@ +--- +title: Initial setup +slug: Localization_Quick_Start_Guide/Initial_setup +translation_of: Mozilla/Localization/Quick_start_guide/Initial_setup +--- +

在你参与到本地化项目之前,你要做几件事情:获取源码、获取相关工具、配置好本地环境(你的电脑)。同时你也要看一下项目里面是不是已经有你母语的本地化工作已经在进行。下面就来谈谈上面说的这几个事情。

+

新项目还是正在进行的项目

+

首先你要确定你参与的项目是新项目还是正在进行的项目。只有知道了项目的类型,你才能明白在接下来的教程里面哪些信息是针对你的。

+

你可以这么做:

+

浏览 localization community directory to see if one already exists for your locale.

+
    +
  1. If a community already exists, reach out to them and ask how you can help.
  2. +
  3. If a community doesn't exist, send an email to the new-locales newsgroup for additional guidance.
  4. +
+

Accounts

+

There are a handful of accounts that you need to be aware as you begin. They're not required for you to begin contributing, but will be required when you are preparing to produce an official release. For now, simply be aware that these will become important as your efforts progress. These accounts will store your code, contributions, and help you produce an official localization.

+
+
+ hg (Mercurial)
+
+ Mercurial is the revision control environment that houses the main Mozilla source code as well as localized code for each official Mozilla localization. You will need this for localizing Mozilla applications. For anyone to gain access to hg repos, you must visit the Mozilla Commiter page and follow the process outlined there. Here is an example bug that illustrates the process well. Use this bug template when filing your hg account registration bug. Add a request about creating your locale's repository to the new locales newsgroup.
+
+ SVN
+
+ SVN is a revision control environment that Mozilla uses to house Mozilla source websites and their localizations for each official Mozilla localization. See this wiki page about how to gain access to SVN. Add a request about creating your locale's repository to the new locales newsgroup.
+
+
+
+ Web-based L10n tools
+
+ We'll talk about these in a little bit. For now, just be aware that should you choose to use them, you may need to create a personal account.
+
+ Mozilla LDAP
+
+ You will need a Mozilla LDAP account once you're ready to have your localization registered on the main Mozilla repositories. Add a request about creating your LDAP account to the new locales newsgroup.
+
+ Locale-specific Bugzilla component
+
+ Having a Bugzilla component specific to your locale will help us to track your localization's progress from first steps to official release. It will also notify us when you're having problems unique to your localization team's work. Add a request about creating your locale's Bugzilla component to the new locales newsgroup.
+
+

Local environment tools

+

Similar to accounts, there is a number of environment tools that you should install on your personal computer. These tools will help you to store your contributions, build Mozilla applications and language packs, and test your work.

+
+
+ Hg (Mercurial)
+
+ As noted above, we use Mercurial for maintaining Mozilla source code and localized code. Not only will you need a localization repository to store your localizations, but you need to have it installed and configured on your personal computer as well. You can find everything you need to know about installing and configuring Mercurial for your localization work here.
+
+
+
+ compare-locales
+
+ compare-locales is a Python script that helps you check your work without needing to run Firefox or another application. Install intructions are located here.
+
+ L10n checks
+
+ L10n checks is another Python script that helps you check your work without running an application. Install instructions are located here.
+
+ autoconf 2.13
+
+ autoconf is a utility that is vital to manually creating Mozilla application builds and language packs. We use version 2.13 and higher for these builds. You can find the source files and install instructions here.
+
+ wget
+
+ wget is a command-line utility that allows you to retrieve files using internet protocols. We use it for retrieving files from repositories. You can find the source files and install instructions here.
+
+ Perl
+
+ Perl is a programming language that will help you create Mozilla application builds and language packs. You can find the source files and install instructions here.
+
+ Python
+
+ Python is a programming language in which many of our L10n testing scripts are written. You can find the source files and install instructions here.
+
+ Locale Switcher or Quick Locale Switcher
+
+ Both Locale Switcher and Quick Locale Switcher are add-ons for Mozilla applications. Either one is necessary to enable you to see your work within a Mozilla application. You can install either by searching for them in Firefox's add-ons manager or following these links.
+
+ A solid, Unicode-based, text editor
+
+ Here are some suggestions: + +
+
+ GNU make
+
+ Make is a tool which controls the generation of executables. You can find version 3.79.1 or higher here. Unfortunately, other varieties of make won't do.
+
+

End of initial setup

+

Now that you've finished your initial setup, it's time for the best part: translating!

+

{{ PreviousNext("Localization_Quick_Start_Guide", "Localization_Quick_Start_Guide/Translation_phase") }}

diff --git a/files/zh-tw/mdn/about/index.html b/files/zh-tw/mdn/about/index.html new file mode 100644 index 0000000000..9f32937bb2 --- /dev/null +++ b/files/zh-tw/mdn/about/index.html @@ -0,0 +1,104 @@ +--- +title: 關於 MDN +slug: MDN/About +tags: + - 指引 + - 文檔 + - 版權 + - 社群 +translation_of: MDN/About +--- +
{{MDNSidebar}}
+ +
{{IncludeSubNav("/zh-TW/docs/MDN")}}
+ +

MDN Web Docs 是個針對網路技術和基於網路的軟體,持續發展的學習平台。它包含了:

+ + + +

我們的使命

+ +

MDN 的使命非常簡單:提供開發者在開放網站上輕鬆地建立各種專案所需的資訊。只要有一個網路上開放的技術,我們就希望把它寫成文件。

+ +

除此之外,我們提供有關 Mozilla 產品和如何建置與貢獻 Mozilla 專案的方法。另外也涵蓋了 B2G OS(以前叫做 Firefox OS)的文件。

+ +

如果你不知道一個特定的主題適不適合出現在 MDN 上,請參閱:Does this belong on MDN?

+ +

如何幫忙

+ +

想要幫忙 MDN 更加完善,你不需要寫得一手很好的程式碼!你可以透過很多種方式幫忙我們,從檢查文件是否合理、到隨手增添一些文字或是範例程式碼都行。根據你的興趣和時間,你可以到開始入門 MDN 頁面看看有幾種方法可以幫忙我們。

+ +

你也可以在你自己的部落格或網站上推廣 MDN

+ +

MDN 社群

+ +

我們的社群是個地球村!我們傑出的貢獻者遍布全世界、涵蓋各種語言。如果你想更認識我們、或是需要任何幫忙,隨時歡迎你到我們的討論區IRC 頻道!你也可以追蹤我們的 Twitter 帳號「@MozDevNet」獲得最新消息。如果你發現任何錯誤、或是你有任何話想跟我們說,都歡迎你發送推文給我們的作者和貢獻者!

+ +

使用 MDN 的內容

+ +

著作權授權

+ +

MDN wiki 文件 是許多 Mozilla 基金會內外作者的心血結晶。除另有註明,所有內容皆採用創用CC 姓名標示-相同方式分享授權條款(CC BY-SA)的第 2.5 版或任何更新的版本釋出。在引用內容時請務必標示作者為「Mozilla Contributors」、並附上該篇 wiki 的超連結或印出網址。你可以標示如下:

+ +
關於 MDNMozilla Contributors 製作,以 CC-BY-SA 2.5 釋出。
+ +

請注意在以上範例中,「Mozilla Contributors」連結到該頁面的編輯歷史。參閱 Best practices for attribution 獲得更多資訊。

+ +
+

參閱 MDN content on WebPlatform.org 了解更多有關如何在網站上使用和標註 MDN 內容的資訊。

+
+ +

在 2010 年 8 月 20 日以前新增到這個 wiki 的範例程式碼,是採用 MIT 授權條款釋出。你應該在 MIT 模板中增加這些作者資訊:「© <最新的 wiki 更新日期> <寫下這段程式碼的人>」

+ +

在 2010 年 8 月 20 日(含)以後新增到這個 wiki 的範例程式碼,是採用 公有領域授權。你不需要註明任何授權文字。不過你要的話,可以註明:「Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/」

+ +

如果你希望貢獻到這個 wiki,你必須讓你的文件採用姓名標示-相同方式分享(或是你正在編輯的頁面上已經指定好的其他替代授權),同時你的程式碼必須採用Creative Commons CC-0(公有領域)授權。在你編輯這個 wiki 的同時即表示你同意採用這些授權。

+ +

有些比較舊的內容可能會採用和上述不同的授權條款。這些授權條款都會在每個頁面最下方透過 Alternate License Block 列明。

+ +
+

新建立的頁面不得使用替代的授權條款。

+
+ +

除非作者另有聲明,否則所有貢獻素材的版權皆歸屬其作者所有

+ +

如果你對這裡提到的內容有任何問題或疑慮,請聯絡 Eric Shepherd

+ +
+

Mozilla 基金會的商標、Logo、服務標誌,以及這個網站的風格外觀,皆不屬於創用 CC 授權的範圍。它們是其原作者的作品(例如 Logo 和圖形設計),不包含在上述的授權條款中。如果你使用文件中的文字、並同時希望使用以上任一權利,或者你對於遵守我們的授權條款有任何的問題,你應該聯絡 Moziila 基金會:licensing@mozilla.org

+ +

下載內容

+ +

你可以下載 MDN 的完整鏡像檔案(2016-11-30 時約為 2.5GB)。

+ +

單一頁面

+ +

你可以透過在網址增加文件參數指定想要的格式,取得單一頁面的內容。

+ +

第三方工具

+ +

你可以透過第三方工具來閱覽 MDN,例如 Dash(Mac OS 用)和 Zeal(Linux 和 Windows用)。

+ +

Kapeli 也發布了離線 MDN docs 涵蓋 HTML、CSS、JavaScript、SVG 和 XSLT。

+ +

連結到 MDN

+ +

請參閱 linking to MDN 文內的指導,了解連結文件的最佳做法。

+ +

向 MDN 報告問題

+ +

請參閱 How to report a problem on MDN

+ +

MDN 網頁文檔歷史

+ +

MDN Web Docs(前身為Mozilla Developer Network (MDN),更前身為 Mozilla Developer Center (MDC) 或 Devmo)專案始於 2005 年初,Mozilla 基金會從 AOL 得到了原始的 Netscape DevEdge 授權。DevEdge 內容仍被視為可用,之後由志願者合併到今天的這個 wiki 以便日後的更新與維護。

+ +

你可以從我們的十週年慶祝頁面看到更多 MDN 的歷史,包含一些參與者的口述歷史。

+ +

關於 Mozilla

+ +

無論你是想更認識我們、了解如何成為 Mozilla 的一份子,又或是單純想找我們聊天,那你都來對地方了。想知道是什麼驅使我們、讓我們更加與眾不同,請造訪我們的使命一頁。

diff --git a/files/zh-tw/mdn/community/index.html b/files/zh-tw/mdn/community/index.html new file mode 100644 index 0000000000..3c6fcda1a2 --- /dev/null +++ b/files/zh-tw/mdn/community/index.html @@ -0,0 +1,52 @@ +--- +title: 加入 MDN 社群 +slug: MDN/Community +tags: + - 教學 + - 社群 +translation_of: MDN/Community +--- +
{{MDNSidebar}}
+ +
{{IncludeSubnav("/zh-TW/docs/MDN")}}
+ +
+

MDN (Mozilla Developer Network 的縮寫) 比 wiki 更強大: 它是一個屬於開發者們的社群,致力於讓 MDN 這個龐大資源更加傑出。

+
+ +

我們非常感謝您對 MDN 的貢獻,但是我們更希望您加入我們的社群,這裡有三個加入我們社群的方法:

+ +
    +
  1. 建立 MDN 帳戶
  2. +
  3. 加入會談
  4. +
  5. 追蹤新資訊
  6. +
+ +

社群如何運作

+ +

以下更多文章關於更多 MDN 的社群。

+ +
+
+
+
社群角色
+
在MDN社群中,有著許多負責不同部分的角色。
+
文件生成聚會
+
這是一個文件生成聚會的指南。它包含了過去人們舉辦文件生成聚會所提供的一些建議與訣竅,以幫助你也舉辦一個。
+
追蹤新資訊
+
MDN 是由 Mozilla Developer Network community 所維護。 這裡有一些我們分享我們在做什麼的資訊管道。
+
+ +
+
+
+ +
+
+
MDN社群會議
+
許多的社群工作都發生在MDN上,然而社群工作也同時發生在一些 討論(非即時性) 與 線上聊天或會議(即時性)中。
+
與社群一同工作
+
絕大部分相當程度對於MDN文件的貢獻來自於了解如何與社群一同工作。這份文章提供一些訣竅以幫助你與其他文件生成者及開發團隊交流。
+
+
+
diff --git "a/files/zh-tw/mdn/community/\350\253\226\345\243\207/index.html" "b/files/zh-tw/mdn/community/\350\253\226\345\243\207/index.html" new file mode 100644 index 0000000000..955d241ece --- /dev/null +++ "b/files/zh-tw/mdn/community/\350\253\226\345\243\207/index.html" @@ -0,0 +1,53 @@ +--- +title: MDN的社群論壇 +slug: MDN/Community/論壇 +tags: + - MDN 資料 + - 指南 + - 社群論壇 +translation_of: MDN/Community/Conversations +--- +
{{MDNSidebar}}
+ +
MDN的『 工作 』通常在MDN的網頁上,但『社群』也會透過異步討論(Asynchronous discussions),及同步線上討論或會議(Synchronous chat)進行。
+ +

異步討論 Asynchronous discussions

+ +

為了分享資訊及持續的溝通,MDN在Mozilla論壇中有獨立的類別("MDN"),這個類別連結所有與MDN相關的主題,包括文檔內容的創建,翻譯和維護; MDN平台開發;以及計劃,目標設定和進度跟踪。

+ + + +

歷史檔案館

+ +

Prior to June 2017, MDN-related discussions took place in mailings lists that were gatewayed and archived with Google groups. If you want to search these past discussions, you can look at the Google groups corresponding to the old mailing lists. (Yes, we know these names are overlapping and confusing. Historical accident. Sorry about that.)

+ +
+
mozilla.dev.mdc a.k.a. dev-mdc
+
This list was for discussions about documentation content on MDN.
+
mozilla.dev.mdn a.k.a. dev-mdn
+
This list was about the development work on MDN's underlying Kuma platform.
+
mozilla.mdn a.k.a. mdn@
+
This forum was for high-level planning and prioritization discussions, for the MDN website and other related initiatives.
+
+ +

同步討論(Synchronous chat)

+ +

Mozilla's platform for real-time discussions is Matrix, a chat protocol for which Mozilla has its own server.

+ +

The MDN Web docs chat room is a major channel for discussing the content of MDN. We talk about writing, organization of content, and so on. We also have "water cooler" conversations here—it's a way our community can keep in touch and just hang out. This room is most likely to be active during weekdays in North America and Europe.

+ +

You might want to learn more about using Matrix with Mozilla, and, if you're really into it, install a stand-alone Matrix application such as Riot.im.

+ +

 IRC?

+ +

For many years, Mozilla used Internet Relay Chat (IRC) for real-time discussions. As of early 2020, IRC has been deprecated in favor of Matrix. You may see references to IRC channels in many places, including on MDN. You can help by updating links to IRC channels that you find on MDN to point to the corresponding Matrix rooms instead. If you're not sure what the Matrix room is for a topic, ask in the General room. Projects or topics that are no longer active might not have a Matrix room; in such cases, just delete the link.

+ +

參與我們的會議 (或其他活動)

+ +

MDN團隊舉辦了許多對MDN社群開放的常規會議,請參閱Mozilla wiki上的MDN Meetings頁面,可以獲取日程、議程、註釋相關以及如何加入的訊息。

+ +

有關這些會議及其他會議,當地聚會和其他活動,可參閱MDN 活動日曆。定期會議會呈現在MDN Meetings wiki page

diff --git a/files/zh-tw/mdn/contribute/getting_started/index.html b/files/zh-tw/mdn/contribute/getting_started/index.html new file mode 100644 index 0000000000..4218ba895c --- /dev/null +++ b/files/zh-tw/mdn/contribute/getting_started/index.html @@ -0,0 +1,105 @@ +--- +title: 開始入門 MDN +slug: MDN/Contribute/Getting_started +tags: + - Beginner + - Getting Started + - Guide + - MDN Meta + - 入門 +translation_of: MDN/Contribute/Getting_started +--- +
{{MDNSidebar}}{{IncludeSubnav("/zh-TW/docs/MDN")}}
+ +

這是一個開放的開發者和作家社區,不分品牌、瀏覽器、平台,為更好的 Web 構建提供更多資源。每個人都能做出貢獻,而每個貢獻者的付出都讓我們變得更為壯大。要想持續推動 Web 創新、成就更為偉大的事物?就讓我們和您一起,從這裡開始。

+ +

MDN 上的每一個部分(網站本身的程式、文件、程式範例、效果展示等等)都是由一群開發者及文案編輯組成的社群完成。術業有專攻,您也一定有些妙招可以分享,請加入我們!

+ +

MDN 三步驟快速上手

+ +

MDN 是一個 wiki,每個人都可以添加、編撰內容。您不必得是個了解許多技術的程式設計師才能加入,畢竟總有各種事情需要完成,從簡單如校對與糾正拼寫,到複雜如撰寫 API 文件都有。這個導向將引導您開始和幫助您找到可以幫助提升 MDN 内容的方法。

+ +

加入貢獻非常容易,且即使您不慎犯了錯誤,也很容易修正。就算您不知道文件該怎麼編排,或者不太了解語法,也不用煩惱:我們有一群人就是專門努力巡視四周、盡力確保 MDN 上的內容優質依舊;有人會盡力編輯您的貢獻確保文件格式正確。放膽分享您的所學吧,並相信整個社群能幫您做得更好。

+ +

步驟 1:建立 MDN 帳號

+ +

加入貢獻的第一步是要有 MDN 帳號,請參考建立帳號說明。注意,在建立 MDN 帳號之前,您需要有一個 GitHub帳號,因為我們已經使用 GitHub 作為登入驗證。

+ +

如果你想創建一個新的頁面,請參考{{SectionOnPage("/zh-TW/docs/MDN/Contribute/Howto/Create_and_edit_pages", "新增一個新頁面")}},這裏有關於如何獲得創建新頁面許可的重要信息;出於安全考慮,新賬戶默認沒有此功能。

+ +

步驟 2:找件事來完成

+ +

現在您已經登入完畢,請閱讀{{anch("各種工作內容", "下面列表")}}中不同工作的描述,找出最吸引您的一個。您可以任選一個喜歡的工作作為第一步。

+ +

步驟 3:動手

+ +

一旦決定了想做什麼事,就找個特定的頁面、程式碼範例之類的,然後開工吧!

+ +

別擔心您無法做到完美,會有 MDN 成員來幫忙修復問題與錯誤。有任何疑問,都歡迎到社群網頁上查詢郵件群組、聊天頻道等資訊,協助您找尋答案。

+ +
+

如果您想要在編輯 MDN 之前做些實際的試驗,那麽我們有提供一個沙盒(Sandbox)給您體驗。請將您的試驗限制在這個頁面。請不要為了看看會發生什麽而在内容頁做不必要的變動,這會弄得一團糟讓其他人搞不清楚,更糟糕的是,會讓一些衹是想學點或看點什麽的讀者混亂。

+
+ +

完成這項工作以後,歡迎再挑另一件事情做,或者看看{{anch("其他可以在 MDN 上做的事", "其他可以在 MDN 上做的事")}}。

+ +

各種工作內容

+ +

貢獻 MDN 的方法很多,要選哪種就端看您的技能和興趣來決定。儘管有些工作可能很難,但我們也真的有好多比較單純的事情可以做。很多工作大概只需要花您五分鐘時間(甚至不到!)。在每項工作的簡短說明後方,您可以看到各類型工作所需的推估時間。

+ +

選項 1: 給熱愛文字的人

+ +

您可以幫我們審查或編輯現有的文件,並為其加上正確的標籤。

+ + + +
如果您要審查或撰寫新文章,建議先看一下文件體例。這樣能確保文章的一貫性。
+ +

選項 2: 給熱愛程式碼的人

+ +

我們需要更多的代碼示例!你也可以幫助建立我們的網站平臺,Kuma

+ + + +

選項 3: 我喜歡文字和代碼

+ +

我們有需要的技術和語言技能的任務,像寫新文章,審查技術的準確性,或調整文檔。

+ + + +

選項 4: 我希望MDN有我的語言

+ +

所有的本地化和翻譯的工作,都是由我們的驚豔地 MDN 社區志願者所完成。

+ + + +

選項 5: 我發現了一些錯誤的資訊,但我不知道該怎樣修復它

+ +

你可以在 Bugzilla 上提交 bug。(5分鐘)

+ +

其他可以在 MDN 上做的事

+ + diff --git a/files/zh-tw/mdn/contribute/howto/create_an_mdn_account/index.html b/files/zh-tw/mdn/contribute/howto/create_an_mdn_account/index.html new file mode 100644 index 0000000000..6f3f294e88 --- /dev/null +++ b/files/zh-tw/mdn/contribute/howto/create_an_mdn_account/index.html @@ -0,0 +1,34 @@ +--- +title: 如何創建 MDN 帳戶 +slug: MDN/Contribute/Howto/Create_an_MDN_account +translation_of: MDN/Contribute/Howto/Create_an_MDN_account +--- +
{{MDNSidebar}}

要針對 MDN 做出任何改變,你需要一個 MDN 帳戶。不要擔心,如果你只是想閱讀和搜索 MDN,你並不需要帳戶!這個簡單的指南幫助你設置 MDN 帳戶。

+ +
+
為什麼 MDN 需要我的電子郵件地址?

+ +

你的電子郵件地址用於帳戶恢復,MDN 管理員也會在必要時,用它來和你討論你的帳戶或你在網站上的活動。

+

此外,你可以選擇註冊的通知(例如特定頁面被更改時)和信息(例如,如果你選擇加入我們的 beta 測試團隊,你可能會收到需要測試的新功能)的電子郵件。

+

你的電子郵件地址永遠不會在 MDN 顯示,而且只會在符合我們的隱私權政策下使用。

+ +
如果你透過 Github 登入 MDN,而且在 Github 使用了 noreply 的電子郵件地址,你不會收到來自 MDN 的訊息(包含你訂閱頁面的訊息)。
+
+
+ +
    +
  1. 在 MDN 每一頁的最上方,你會發現有一個登入的按鈕。滑鼠滑到那邊後點一下(如果是移動設備就輕按)以表列 MDN 支持的驗證服務列表。
  2. +
  3. 選擇要登入的服務。目前只支持 GitHub。請注意如果選了 GitHub,你的 MDN 公開用戶頁會包含一個指向你 GitHub 頁面的連結。
  4. +
  5. 按照 GitHub 的提示把您的帳戶連接到 MDN。
  6. +
  7. 一旦認證服務把你帶回 MDN 以後,MDN 就會提示你輸入一個用戶名和電子郵件地址。您的用戶名會被公開顯示以表彰你所做的工作。不要使用您的電子郵件地址作為用戶名。
  8. +
  9. 點擊「創建我的 MDN 配置文件」按鈕。
  10. +
  11. 如果您在步驟四指定的電子郵件地址,與認證服務使用的不一樣,你需要檢查這個電子郵件地址,並點擊確認電子郵件中的鏈接。
  12. +
+ +

就是這樣!你有一個MDN帳戶,並可以立即編輯或標籤頁,或者提交演示!

+ +

您可以在任何 MDN 頁面的頂部點擊你的名字,看看你的公開檔案。從那裡,你可以點擊「編輯」按鈕,進行更改或添加到您的個人資料,所以你可以分享更多關於您的利益,把鏈接添加到你的推特帳戶或部落格等等。

+ +
+

用戶名新不能包含空格或“@”字符。請記住,你的用戶名會被公開顯示,以確定你所做的工作!

+
diff --git a/files/zh-tw/mdn/contribute/howto/create_and_edit_pages/index.html b/files/zh-tw/mdn/contribute/howto/create_and_edit_pages/index.html new file mode 100644 index 0000000000..7e4813e5a8 --- /dev/null +++ b/files/zh-tw/mdn/contribute/howto/create_and_edit_pages/index.html @@ -0,0 +1,144 @@ +--- +title: 編輯以及新增頁面 +slug: MDN/Contribute/Howto/Create_and_edit_pages +tags: + - MDN + - 初學者 + - 新頁面 + - 編輯 +translation_of: MDN/Contribute/Howto/Create_and_edit_pages +--- +
{{MDNSidebar}}

幾乎每位MDN的貢獻者在MDN中都會做的兩件基本工作,即為編輯一個已存在的頁面或者是新增一個頁面。這篇文章將介紹如何編輯文件的基本技能。

+ +

編輯一個已存在的頁面

+ +

想要編輯十分的簡單:

+ + + +

預覽修改

+ +

若是要檢視您所做出的變更:

+ + + +

請注意!預覽變更並不等同儲存您的修改,請小心不要太快關閉您的文章編輯頁面。

+ +

版本註解

+ +

在您預覽您的編輯過後,您總會希望送出您的修訂版本。在您送出之前,請在頁面文章下方找版本註解的輸入框,並且留下您於此次所做的變更註解以讓其他貢獻者能了解您做了那些變更。 舉例來說,您可能新增了一個段落,改變一些詞彙使其更符合原意,重新編寫段落以更在地化,或是移除了一些多餘的資訊。

+ +

Tags

+ +

您可以於文章編輯區塊下增加或移除用以描述文章內容以及用途的 tags。請詳見 How to properly tag pages 以了解 tags 如何來提供資訊。

+ +

審核是必要的嗎?

+ +

在您送出您的變更之前,您可以藉由勾選技術審核(針對 code、APIs或是技術內容),編輯審查(針對篇章結構、文法或內容),或是模板審查(針對 KumaScript code ),來讓專家或是經驗豐富的貢獻者審核您的變更。

+ +

附件

+ +

若您想要讓文章更易於理解或是加上插圖,而希望在頁面上夾帶檔案,您可在文章編輯頁面下方找到此功能。{OptimizeImagesNote(1)}}

+ +

儲存、放棄、以及繼續修改

+ +

當您修改完成,以及滿懷希望的預覽修改之後,您可以填寫註解並且透過點擊於文章標題右手邊的「儲存修改」綠色按鈕。若您改變您的心意,您可以透過點擊於文章標題右手邊的「放棄修改」紅色按鈕。

+ +

於版本註解輸入 Enter 和點選「儲存並繼續修改」具有同等的效果。

+ +

新增一個新頁面

+ +

若您不知道能夠在哪裡新增文章,別擔心!您可以隨意存放,我們會找到文章並且移到文章到它所屬的地方,或者與現有內容合併比較合理。您可以不需要為了使其完美而花費太多心力。 我們有快樂的地精幫手可以來為您的內容保持乾淨以及充滿價值。

+ +

以下是一些創造新頁面的方法:

+ + + +

「缺失頁面」連結

+ +

就像大部分的wiki,在MDN上當然可能在頁面上新增還未存在的頁面連結。舉例來說,作者可以在新增API所屬頁面前,新增所有API的成員清單。在MDN上,連結至還未存在的頁面會顯示為紅色。

+ +

要在頁面新增「缺失頁面」連結:

+ +
    +
  1. 請先確認您已經登入MDN(如果您還未登入,點繫「缺失頁」連結會出現404(找不到頁面)錯誤)。
  2. +
  3. 點擊「缺失頁面」連結,將開啟MDN Editor UI,讓您新增缺失頁面。
  4. +
  5. 撰寫頁面內容,並且儲存。
  6. +
+ +

非基於連結而建立的新頁面

+ +

為了建立一個非基於連結而建立的新頁面,您需要於 URL 區塊後輸入一個獨一無二的頁面名稱。舉例來說,若您輸入:

+ +
https://developer.mozilla.org/en-US/docs/FooBar
+ +

MDN 會心建立一個標題為「FooBar」而且會於開啟編輯器讓您能夠編輯此新頁面。請參考 Editing an existing page section of this article for how to use the editor mode.

+ +

從現有的頁面新增子頁面

+ +

為您在現有的頁面架構下新增一個子頁面:

+ +
    +
  1. 在「父」頁面,點選進階目錄 ( 於列表上呈現齒輪圖樣 ),並點選新增子頁面。接著便會出現一個可以編輯新頁面的模式。
  2. +
  3. Title 欄位輸入文章標題。
  4. +
  5. 若有必要,改變 Slug 欄位 ( 舉例來說,若文章標題非常長而您又希望有個較短的 URL)。此欄位會由編輯器自動地來填入, by substituting underscores for spaces in the title. 在此種狀況下,您只能改變 URL 的最後一部分。
  6. +
  7. TOC欄位,選擇您想要自動生成顯示在目錄的標題層級,或者這一頁不需要目錄也可以選擇「不需要目錄」選項。
  8. +
  9. 於編輯器中增添內容並且儲存,請參考 Editing an existing page 文章來了解如何運用編輯模式。
  10. +
+ +

複製現有的頁面

+ +

若您想於您的新頁面上套用某個現存頁面的格式,您可以點選「複製此頁」並於稍後改變該複製頁的內容。

+ +
    +
  1. 於原始的頁面上,點選進階目錄 ( 於列表上呈現齒輪圖樣 ),並且點選複製此頁。接著便可編輯一個以該原始文件為樣本的複製頁面。
  2. +
  3. 您可根據您文章的內容適當地訂下標題Slug 會根據您文章標題如何訂定而自動變換。
  4. +
  5. 如有必要,可以改變 Slug 的部分內容以呈現出新文件於原始架構下的不同。(在大多數的狀況下,此舉是多餘的。因為複製後的頁面對於原始頁面具有相似的內容,因此就必須放在相似的架構之下。)
  6. +
  7. TOC欄位,選擇您想要自動生成顯示在目錄的標題層級,或者這一頁不需要目錄也可以選擇「不需要目錄」選項。
  8. +
  9. 在頁面編輯欄位編寫內容,並且儲存您的變更。請參考 Editing an existing page 文章來了解如何運用編輯模式。
  10. +
+ +

從現有頁面連結

+ +

這種方法算是混合形式,您可以在其他頁面產生連結,接著點擊剛加上去的連結,就會產生新的頁面了。

+ +
    +
  1. 從現有頁面任何地方輸入新頁面的名稱(需合理)。
  2. +
  3. 反白該名子並且於編輯器中點選連結圖樣()。「連結」的訊息框會出現並且詢問該段反白文字需要被導向哪個頁面
  4. +
  5. 「/zh-TW/docs/」 是預設的 URL 欄位內容。您可於「/zh-TW/docs/」之後輸入新頁面的名子(該頁面的名字並不需要和被連結的文字內容相同)。
  6. +
  7. 點擊「確定」來創造和插入新的連結。
  8. +
+ +

當連結呈現紅色時,代表著該頁面尚未存在。當連結呈現藍色時,代表著該頁面已經存在。若您想要建立一個新頁面但他的編題已經存在時,首先去檢查並改善現存的頁面,否則為您的新頁面想個不同的標題名稱並以此產生連結。請參考 page naming guide 以幫助您命名。

+ +

您可點擊您新建立的紅色連結(在您儲存以及關閉編輯器之後),來為您的新頁面增添內容。新頁面將在編輯模式下開啟,此時您就可以編寫內容了。請參考 Editing an existing page 文章來了解如何運用編輯模式。

+ +

重新整理頁面內容

+ +

MDN支援KumaScript巨集和嵌入其他頁面內容插入頁面,有時候因效能因素需要為生成的頁面用快取,而略為延遲內容更新。頁面從原始碼生成,產生的頁面會先產生快取以便未來存取使用。從現在起,所有的巨集(模版)或是嵌入(在該頁使用Page巨集)並不會馬上就會反應更動後的巨集變動,巨集生成頁面,或者嵌入頁面的內容。

+ + + +

參見

+ + diff --git a/files/zh-tw/mdn/contribute/howto/do_a_technical_review/index.html b/files/zh-tw/mdn/contribute/howto/do_a_technical_review/index.html new file mode 100644 index 0000000000..ecb35fe0be --- /dev/null +++ b/files/zh-tw/mdn/contribute/howto/do_a_technical_review/index.html @@ -0,0 +1,50 @@ +--- +title: 如何進行技術審查 +slug: MDN/Contribute/Howto/Do_a_technical_review +translation_of: MDN/Contribute/Howto/Do_a_technical_review +--- +
{{MDNSidebar}}
{{IncludeSubnav("/zh-TW/docs/MDN")}}
+ +

技術審查包含檢查文章的正確與完整性,並在需要時進行修正。若文章作者需要其他人來檢查文章的技術性內容,可以在編輯時勾選「技術審查」(Technical review)。通常由作者連絡特定工程師來進行技術審查,但具備該主題技術專長者亦可參與。

+ +

本文描述如何執行技術審查,以協助確保 MDN 的內容是正確的。

+ +
+
要做什麼?
+
審查並修正文章在技術上的正確與完整性。
+
要審查的文章在哪?
+
找被標記為「技術審查」(technical review)的特定文章。
+
要知道些什麼?
+
+
    +
  • 針對文章主題的專業知識。若閱讀該文章並沒有對你傳授非常新的東西,那就視你自己為專家。
  • +
  • 編輯 MDN 上維基文章的方法。
  • +
+
+
有哪些步驟?
+
+
    +
  1. 選擇要審查的文章 +
      +
    1. 前往技術審查(technical reviews)清單頁面。這裡列出所有請求技術審查的頁面。
    2. +
    3. 選擇一個頁面,而你對該主題非常熟練。
    4. +
    5. 點擊文章連結以載入頁面。
    6. +
    +
  2. +
  3. 閱讀文章並密切關注技術性細節:這篇文章正確嗎?有沒有漏掉什麼?若初次選擇的頁面並不適合由你來審查,不要猶豫,選擇其他頁面。
  4. +
  5. 若沒有錯誤,你不需要透過編輯將文章標記為已審查。找到頁面左方側邊攔的「快速回顧」(quick review),黃色框框會列出任何等待中的審查,並讓你清除審查請求的標記。若有審查請求會顯示如下:
    + Screenshot of the sidebar's box listing reviews that have been requested and allowing the flags to be changed.
  6. +
  7. 取消選取「技術」(Technical),然後點擊「儲存」(Save)。
  8. +
  9. 若發現有錯誤需要修正,亦可在編輯器中改變審查請求的狀態。操作過程如下: +
      +
    1. 點擊靠近頁面頂端的「編輯」(Edit)按鈕以編輯頁面,這會帶你到 MDN editor
    2. +
    3. 修正任何錯誤的技術資訊,並且(或者)增加任何重要但被遺漏的訊息。
    4. +
    5. 在文章底部填寫版本註解Revision Comment)。這是用來描述你做了什麼事的簡短訊息,如:「技術審查完成」。當你做了些修正,將相關資訊納入你的註解,如:「技術審查並修正參數描述」。這會幫助其他貢獻者和網站編輯知道你變更的內容和理由。你也可提出(若有的話)自認不夠資格審查的部分。
    6. +
    7. 在 「需要審核嗎?」(Review Needed?) 下方,取消選取「技術」(Technical),就在頁面底部版本註解區塊附近。
    8. +
    9. 點擊「發布」(PUBLISH)按鈕。
    10. +
    +
  10. +
+

恭喜!你已經完成你的第一份技術審查!感謝你的幫助!

+
+
diff --git a/files/zh-tw/mdn/contribute/howto/do_an_editorial_review/index.html b/files/zh-tw/mdn/contribute/howto/do_an_editorial_review/index.html new file mode 100644 index 0000000000..8ef91de87d --- /dev/null +++ b/files/zh-tw/mdn/contribute/howto/do_an_editorial_review/index.html @@ -0,0 +1,55 @@ +--- +title: 如何進行編輯審查 +slug: MDN/Contribute/Howto/Do_an_editorial_review +tags: + - 如何 + - 指南 + - 文件 + - 編輯審查 +translation_of: MDN/Contribute/Howto/Do_an_editorial_review +--- +
{{MDNSidebar}}
+ +
{{IncludeSubnav("/zh-TW/docs/MDN")}}
+ +

一個主題的編輯審查包含錯字、拼字、文法、語法或其他文字錯誤。並非所有貢獻者都是語言專家,但他們的知識可以提供極為有用的資訊,因此需要審稿和校對。這就是編輯審查在做的事。

+ +

這個主題將會介紹如何進行編輯審查,以幫助確保在 MDN 的資訊是正確的。

+ +
+
有哪些任務?
+
必要的有審稿和校對。
+
有哪些東西需要編輯審查?
+
那些被標記需要審查的主題。
+
進行編輯審查需要知道什麼?
+
你需要具有良好的英文文法和拼字能力(即能準確翻譯英文成中文的能力)。編輯審查在於確保文法、拼字和語法的正確和意義,並遵守 MDN 編輯指南
+
有哪些步驟?
+
+
    +
  1. 選擇一個主題: +
      +
    1. 前往待審查清單。這個表列出了要求審查的主題。
    2. +
    3. 選擇一個中文標題且不帶有 Template: (Template: 包含 MDN 功能碼) 的主題。
    4. +
    5. 點擊該主題的連結。
    6. +
    +
  2. +
  3. 閱讀主題,注意錯字、拼字、文法、語法或其他錯誤。如果你覺得無法應付,請找下一個主題。
  4. +
  5. 如果沒有錯誤,你不需要編輯主題來標記為已審查。在左方導覽列尋找「快速審查」方塊:
    + 快速審查
  6. +
  7. 取消選取 編輯 方塊並點擊 儲存。
  8. +
  9. 如果有錯誤需要被糾正: +
      +
    1. 點擊在頁面頂端附近的 編輯 按鈕,接著會轉到 MDN 編輯器
    2. +
    3. 修正你找到的錯字、拼字、文法、語法或其他錯誤。你並不需要修正所有錯誤,但若你不確定你已經完整的審查主題,請留下編輯審查請求。
    4. +
    5. 在主題尾端留下 版本註解 。像是「編輯審查:修正錯字、文法和拼字」。這能讓其他貢獻者和網站編輯者知道你改了什麼和為什麼。
    6. +
    7. 取消選取在 需要審查嗎? 中的 編輯 方塊。他在版本註解下面。
    8. +
    9. 按下 發布
    10. +
    +
  10. +
+ +
+

你的變更不一定會立刻出現,他可能會因送出和儲存延遲一會。

+
+
+
diff --git a/files/zh-tw/mdn/contribute/howto/index.html b/files/zh-tw/mdn/contribute/howto/index.html new file mode 100644 index 0000000000..e33524d58b --- /dev/null +++ b/files/zh-tw/mdn/contribute/howto/index.html @@ -0,0 +1,14 @@ +--- +title: How-to guides +slug: MDN/Contribute/Howto +tags: + - Documentation + - Landing + - MDN + - NeedsTranslation + - TopicStub +translation_of: MDN/Contribute/Howto +--- +
{{MDNSidebar}}

這些文章將會帶領你一步步完成貢獻 MDN 專案所需完成的目標

+ +

{{LandingPageListSubpages}}

diff --git a/files/zh-tw/mdn/contribute/howto/set_the_summary_for_a_page/index.html b/files/zh-tw/mdn/contribute/howto/set_the_summary_for_a_page/index.html new file mode 100644 index 0000000000..e44a6fb7ce --- /dev/null +++ b/files/zh-tw/mdn/contribute/howto/set_the_summary_for_a_page/index.html @@ -0,0 +1,50 @@ +--- +title: 如何撰寫文章摘要? +slug: MDN/Contribute/Howto/Set_the_summary_for_a_page +tags: + - 摘要 +translation_of: MDN/Contribute/Howto/Set_the_summary_for_a_page +--- +
{{MDNSidebar}}

 

+ +

你可以在MDN用各式各樣的方式來定義一個頁面的摘要,像是搜尋引擎結果,在其他的MDN網頁如某些到達頁(Landing Pages),以及提示中。他應該是在頁面的上下文中有意義的文本,並且在上下文中顯示時,沒有其餘的頁面內容。

+ +

在頁面中摘要是明確定義的。如果沒有被明確定義的話,通成會拿第一句來當摘要,但並不總是最適合的。

+ +
+
+

任務是什麼?

+
+
在頁面中找出可以當成摘要的文字,且用別種文字說明寫成適當的摘要。
+
+

哪些地方需要撰寫摘要?

+
+
缺少摘要的頁面,或是摘要不足的頁面。
+
+

撰寫摘要之前,你需要具備/知道什麼?

+
+
會使用MDN編輯器、擅長寫英文作文以及對於該頁面要有足夠的了解,才能寫出好的摘要。
+
+

撰寫摘要的步驟:

+
+
+
    +
  1. 選一個頁面: +
      +
    1. 在 MDN documentation status 頁面中, 在Sections(章節)下方,點選任何一個你熟悉或是對其有所了解的標題連結(ex:HTML):
      +
    2. +
    3. 在此文件狀態頁面上方的摘要表格內,點選Pages(頁面)。點選後會導向關於這個標題(ex:HTML)的全部頁面的索引頁。左邊欄位顯示這個頁面的連結,右邊則是顯示tags(標籤)以及該頁面的摘要。
    4. +
    5. 挑選一個沒有摘要的頁面,或是摘要太少的頁面:
      +
    6. +
    7. 點選該頁面的連結。
    8. +
    +
  2. +
  3. 點選編輯打開MDN編輯器。
  4. +
  5. 找出一句或是兩句可以總結上下文的摘要。如果需要的話,編輯現有的內容以創造或是修改成好的摘要。
  6. +
  7. 選擇要當成摘要的文字。
  8. +
  9. 點選在編輯器工具列中的格式化樣式,選擇SEO Summary. (在原始碼中,這會在被選起來的文字旁,產生一個HTML元素: {{HTMLElement("span")}} element with class="seoSummary" )
    +
  10. +
  11. 使用修訂評論保存您的更改。評論為非必填項目,但我們鼓勵您填寫。能使其他人更容易追蹤文章的變化。
  12. +
+
+
diff --git a/files/zh-tw/mdn/contribute/howto/tag/index.html b/files/zh-tw/mdn/contribute/howto/tag/index.html new file mode 100644 index 0000000000..515ad7f6ef --- /dev/null +++ b/files/zh-tw/mdn/contribute/howto/tag/index.html @@ -0,0 +1,374 @@ +--- +title: How to properly tag pages +slug: MDN/Contribute/Howto/Tag +translation_of: MDN/Contribute/Howto/Tag +--- +
{{MDNSidebar}}

Article tags are an important way to put visitors in touch with helpful content. Each page should normally have several tags to help keep content organized. This page explains the best way to tag pages so that our readers can find information and we can keep ourselves organized.

+ +

For a help with the user interface for editing tags, see the tagging section in our editor guide.

+ +

Please use tags properly as explained below. If you don't, our automated tools will not correctly generate lists of content, landing pages, and cross-linking of articles.

+ +

How MDN uses tags

+ +

Tags get used on MDN several ways:

+ +
+
Document categorization
+
What type of document is it? Is it a reference? A tutorial? A landing page? Our visitors can use these tags to filter searches, so they're really important!
+
Topic identification
+
What is the article about? Is it about an API? The DOM? Graphics? Again, these tags are important because they can filter searches.
+
Technology status
+
What's the status of the technology? Is it non-standard? Obsolete or deprecated? Experimental?
+
Skill level
+
For tutorials and guides, how advanced is the material covered by the article?
+
Document metadata
+
The writing community needs tags to keep track of which pages need what kind of work.
+
+ +

Tag type guide

+ +

Here's a quick guide to the types of tags and possible values for them.

+ +

Document category

+ +

When you tag an article with one of these categories, you help the automated tools more accurately generate landing pages, tables of contents, and so on. Our new search system will also use these terms so that our visitors can locate reference or guide information at will.

+ +

We use the following category names as standard tagging terms:

+ +
+
{{Tag("Intro")}}
+
The article provides introductory material about a topic. Ideally each technology area should have only one "Intro".
+
{{Tag("Featured")}}
+
The article is critical and will display prominently on landing pages. Use this tag sparingly (never more than three documents in each documentation area).
+
{{Tag("Reference")}}
+
The article contains reference material about an API, element, attribute, property, or the like.
+
{{Tag("Landing")}}
+
The page is a landing page.
+
{{Tag("Guide")}}
+
The article is a how-to or guide page.
+
{{Tag("Example")}}
+
The article is a code sample page, or has code samples (that is, actual snippets of useful code, not one-line "syntax examples").
+
+ +

Topic

+ +

By identifying the article's topic area, you are helping generate better search results (and landing pages and navigation as well).

+ +

While there's some room for flexibility here as we identify new topic areas, we try to limit ourselves to the names of APIs or technologies. Some useful examples:

+ + + +

In general, your topic identification tag should be the name of an interface with a number of related pages (like Node, which has many pages for its various properties and methods), or the name of an overall technology type. You might tag a page about WebGL with Graphics and WebGL, for example, but a page about {{HTMLElement("canvas")}} with HTML, Element, Canvas, and Graphics.

+ +

Technology status

+ +

To help the reader understand how viable a technology is, we use tags to label pages as to the status of the technology's specification. This isn't as detailed as actually explaining what the spec is and how far the technology has come in the specification process (that's what the Specifications table is for), but it helps the reader judge, at a glance, whether it's a good idea to use the technology described in the article.

+ +

Here are possible values for these tags:

+ +
+
{{Tag("Non-standard")}}
+
Indicates that the technology or API described on the page is not part of a standard, but is considered stable in any implementing browser(s). If you don't use this tag, your readers will assume the technology is standard. The compatibility table on the page should clarify which browser(s) support this technology or API.
+
{{Tag("Deprecated")}}
+
The technology or API covered on the page is marked as deprecated in the specification, and is likely to eventually be removed, but is generally still available in current versions of browsers.
+
{{Tag("Obsolete")}}
+
The technology or API has been deemed obsolete and has been removed (or actively being removed) from all or most current browsers.
+
{{Tag("Experimental")}}
+
The technology is not standardized, and is an experimental technology or API that may or may not ever become part of a standard. It is also subject to change in the browser engine (typically only one) that implements it.
+
{{Tag("Needs Privileges")}}
+
The API requires privileged access to the device on which the code is running.
+
{{Tag("Certified Only")}}
+
The API only works in certified code.
+
+ +

These tags are no excuse to leave out the compatibility table in your article!

+ +

Skill level

+ +

Use the skill-level tag type only for guides and tutorials (that is, pages tagged Guide) to help users choose tutorials based on how familiar they are with a technology. There are three values for this:

+ +
+
{{Tag("Beginner")}}
+
Articles designed to introduce the reader to a technology they've never used or have only a passing familiarity with.
+
{{Tag("Intermediate")}}
+
Articles for users who have gotten started with the technology but aren't experts.
+
{{Tag("Advanced")}}
+
Articles about stretching the capabilities of a technology and of the reader.
+
+ +

Document metadata

+ +

The writing community uses tags to label articles as requiring specific types of work. Here's a list of the ones we use most:

+ +
+
{{Tag("junk")}}
+
The article needs to be deleted.
+
{{Tag("NeedsContent")}}
+
The article is a stub, or is otherwise lacking information. This tag means that someone should review the content and add more details and/or finish writing the article.
+
{{Tag("NeedsExample")}}
+
The article needs one or more examples created to help illustrate the article's point. These examples should use the live sample system.
+
{{Tag("NeedsLiveSamples")}}
+
The article has one or more examples that need to be updated to use the live sample system.
+
{{Tag("NeedsUpdate")}}
+
The content is out of date and needs to updating.
+
{{Tag("l10n:exclude")}}
+
The content is not really worth localizing and will not appear on localization status pages.
+
{{Tag("l10n:priority")}}
+
The content is important and should be marked as a priority for MDN translators. Shows up in an extra priority table on localization status pages.
+
+ +

Web Literacy Map

+ +

The WebMaker project, through the Web Literacy Map, has defined skills needed to optimally read, write, and participate on the Web. We use Web literacy skills as tags on MDN to help our users find the resources that best suit their needs:

+ +
+
{{Tag("Navigation")}}
+
how to browse the Web
+
{{Tag("WebMechanics")}}
+
how the Web is organized and how it works
+
{{Tag("Search")}}
+
how to find information, people, and resources on the Web
+
{{Tag("Credibility")}}
+
how to critically evaluate information you find on the Web
+
{{Tag("Security")}}
+
how to keep systems, identities, and content safe
+
{{Tag("Composing")}}
+
how to create and curate content for the Web
+
{{Tag("Remixing")}}
+
how to modify existing Web resources to create something new
+
{{Tag("DesignAccessibility")}}
+
how to create universally effective communications through Web resources
+
{{Tag("CodingScripting")}}
+
how to code and/or create interactive experiences on the Web
+
{{Tag("infrastructure")}}
+
how the Internet's technical stack works
+
{{Tag("Sharing")}}
+
how to create resources with others
+
{{Tag("Collaborating")}}
+
how to work with other people
+
{{Tag("Community")}}
+
how to get involved in Web communities and understand how they work
+
{{Tag("Privacy")}}
+
how to examine the consequences of sharing data online
+
{{Tag("OpenPractices")}}
+
how to help keep the Web accessible to everybody
+
+ +

Putting it all together

+ +

So to each page you assign tags from several tag types, for example

+ +
+
A tutorial about WebGL for beginners
+
WebGL, Graphics, Guide, Beginner
+
Reference page for {{HTMLElement("canvas")}}
+
Canvas, HTML, Element, Graphics, Reference
+
A landing page for Firefox OS developer tools
+
Tools, Firefox OS, Landing
+
+ +

Tagging and search filters

+ +

Search filters won't work properly unless we tag MDN pages properly. Here's a table of search filters and which tags they look for.

+ +
+

Note: If multiple tags are listed under "Tag name," that means any one or more of these tags must be present for the article to match.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Filter groupSearch filter nameTag name
TopicOpen Web Apps{{Tag("Apps")}}
 HTML{{Tag("HTML")}}
 CSS{{Tag("CSS")}}
 JavaScript{{Tag("JavaScript")}}
 APIs and DOM{{Tag("API")}}
 Canvas{{Tag("Canvas")}}
 SVG{{Tag("SVG")}}
 MathML{{Tag("MathML")}}
 WebGL{{Tag("WebGL")}}
 XUL{{Tag("XUL")}}
 Marketplace{{Tag("Marketplace")}}
 Firefox{{Tag("Firefox")}}
 Firefox for Android{{Tag("Firefox Mobile")}}
 Firefox for Desktop{{Tag("Firefox Desktop")}}
 Firefox OS{{Tag("Firefox OS")}}
 Mobile{{Tag("Mobile")}}
 Web Development{{Tag("Web Development")}}
 Add-ons & Extensions{{Tag("Add-ons ")}}|| {{Tag("Extensions")}} || {{Tag("Plugins")}} || {{Tag("Themes")}}
 Games{{Tag("Games")}}
Skill levelI'm an Expert{{Tag("Advanced")}}
 Intermediate{{Tag("Intermediate")}}
 I'm Learning{{Tag("Beginner")}}
Document typeDocsThis restricts the search to docs content, leaving out Hacks and other MDN content.
 DemosThis includes Demo Studio content in the search results.
 Tools{{Tag("Tools")}}
 Code Samples{{Tag("Example")}}
 How-To & Tutorial{{Tag("Guide")}}
 Developer ProfilesThis includes developer profiles from the MDN site in the search results.
 External ResourcesThe dev team is still figuring this out...
+ +

Tagging problems you can fix

+ +

There are several kinds of tag problems you can help fix:

+ +
+
No tags
+
Generally articles should have at least a "category" tag and a "topic" tag. Usually other tags are appropriate as well, but if you can help us ensure that the minimum tags are present, you'll be a documentation hero!
+
Tags that don't follow our tagging standards
+
Please fix any documents whose tags don't follow the standards on this page.
+ Note that due to a bug in Kuma, some localized tags (such as Référence) may show up on some English pages. These tags are likely to reappear even if you delete them; don't bother trying to fix them until the Kuma bug is fixed.
+
Incorrect tags
+
If you're looking at an article about HTML and it's tagged "JavaScript", that's probably wrong! Likewise, if an article discusses Mozilla internals but has a "Web" tag, that's probably wrong too. Remove these tags and add the right tags if they aren't already there. Please also correct misspelled tags (e.g., "Javascript" will still match, since tags are case-insensitive, but let's not be sloppy!).
+
Missing tags
+
If an article has some but not all of the tags it needs, feel free to add more. For example, if a page in JavaScript reference is (correctly) tagged "JavaScript" but nothing else, you're invited to tag the page "Reference" as well!
+
Tag spam
+
This insidious beast is the most revolting tag problem of all: some Web vermin has deposited its droppings in the page tags (like "Free warez!" or "Hey I was browsing your site and wanted to ask you if you could help me solve this problem I'm having with Flash crashing all the time"). We've got to delete these right away!
+
+ +

If you see one (or more) of these problems, please log into MDN and click EDIT at the top right of the MDN window. Once the editor loads up, scroll down to the bottom of the page, where you'll see the tag box. For more details on the tagging interface, see "The tags box" in the MDN editor guide.

diff --git a/files/zh-tw/mdn/contribute/index.html b/files/zh-tw/mdn/contribute/index.html new file mode 100644 index 0000000000..817ac06f4f --- /dev/null +++ b/files/zh-tw/mdn/contribute/index.html @@ -0,0 +1,20 @@ +--- +title: 貢獻 MDN +slug: MDN/Contribute +tags: + - Documentation + - Guide + - Landing + - MCD PROJECT + - MDN +translation_of: MDN/Contribute +--- +
{{MDNSidebar}}
{{IncludeSubnav("/zh-TW/docs/MDN")}}
+ +

歡迎!當你在看這個頁面時,就已經邁向成為 MDN 貢獻者的第一步!

+ +

這份指南涵蓋貢獻 MDN 的各個面向,包括風格指引、使用編輯器和工具的引導……等等。在編輯或建立任何頁面前,請先閱讀並確認同意 Mozilla 網站與通訊使用條款

+ +

如果之前你並沒有貢獻過 MDN 的話,開始入門指南能幫你決定要投入的任務。

+ +

{{LandingPageListSubPages()}}

diff --git a/files/zh-tw/mdn/contribute/localize/index.html b/files/zh-tw/mdn/contribute/localize/index.html new file mode 100644 index 0000000000..4d18dde8a4 --- /dev/null +++ b/files/zh-tw/mdn/contribute/localize/index.html @@ -0,0 +1,33 @@ +--- +title: Localizing MDN +slug: MDN/Contribute/Localize +tags: + - Documentation + - Localization + - MDN + - NeedsTranslation + - TopicStub +translation_of: MDN/Contribute/Localize +--- +
{{MDNSidebar}}

MDN 被全世界的人用來作為 Web 技術的參考和指南,甚至是 Firefox 開發團隊內部的人也使用 MDN。 我們的在地化社群是 Mozilla 社群的關鍵部分;他們將文件翻譯,並有助於世界各地進行 Web 開發的人們,使用他們自己的語言參考文件 如果您想了解有關在地化社群的更多資訊,請加入其中一個團隊,或者甚至開始翻譯新的文件。

+ +

{{LandingPageListSubpages}}

+ +

在地化工具

+ +

你可以使用許多有用的工具來幫助你進行將文件在地化的工作:

+ +
+
Pontoon
+
+

是一個基於web網頁的、所見即所得(WYSIWYG)的在地化(l10n即localization)工具。

+
+
Transvision
+
一個由 Mozilla 法國社群提供的工具。讓你可以搜尋某個英文單字出現的次數,並且可以找尋出所有翻譯該英文單字的該國語言文字。很適合用在,當你不知道某個單字或片語如何翻譯時。
+
+ +

另可參閱

+ + diff --git a/files/zh-tw/mdn/contribute/localize/localization_projects/index.html b/files/zh-tw/mdn/contribute/localize/localization_projects/index.html new file mode 100644 index 0000000000..026d2a7479 --- /dev/null +++ b/files/zh-tw/mdn/contribute/localize/localization_projects/index.html @@ -0,0 +1,1085 @@ +--- +title: 在地化專案 +slug: MDN/Contribute/Localize/Localization_projects +translation_of: MDN/Contribute/Localize/Localization_projects +--- +
{{MDNSidebar}}
+ +

所有在 MDN 上的在地化跟翻譯工作都是由一群志願者所完成的。這篇文章列出了在地化的專案以及積極貢獻這些專案的人們和一些細節。

+ +

如果您想要開始貢獻翻譯,請參見 Translating MDN pages.

+ +
+

備註: 如果你有意願接受其他貢獻者關於某個特定區域的在地化的聯繫,歡迎把你的名字加入本頁面。請確認你的 MDN 個人檔案頁面有聯繫你的方式,例如:推特 (Twitter) 或其他社群網站。如果頁面上的名字在過去 12 個月沒有任何貢獻,該名字會從頁面中被移除。

+
+ +
+

af: Afrikaans

+
+ + +
+ +
+

ar: العربية [Arabic]

+
+ + +
+ +
+

az: Azərbaycanca [Azerbaijani]

+
+ + +
+ +
+

bg: Български [Bulgarian]

+
+ + +
+ +
+

bm: Bamanankan [Bambara]

+
+ + +
+ +
+

bn-BD: বাংলা (বাংলাদেশ) [Bengali, Bangladesh]

+
+ + +
+ +
+

bn-IN: বাংলা (ভারত) [Bengali, India]

+
+ + +
+ +
+

ca: Català [Catalan]

+
+ + +
+ +
+

cs: Čeština [Czech]

+
+ + +
+ +
+

de: Deutsch [German]

+
+ + +
+ +
+

ee: Eʋe [Ewe]

+
+ + +
+ +
+

el: Ελληνικά [Greek]

+
+ + +
+ +
+

es: Español [Spanish]

+
+ + +
+ +
+

fa: فارسی [Persian]

+
+ + +
+ +
+

ff: Pulaar-Fulfulde [Fulah]

+
+ + +
+ +
+

fi: suomi [Finnish]

+
+ + +
+ +
+

fr: Français [French]

+
+ + +
+ +
+

fy-NL: Frysk (Netherlands) [Frisian]

+
+ + +
+ +
+

ga-IE: Gaelige (Ireland) [Gaelic]

+
+ + +
+ +
+

ha: Hausa

+
+ + +
+ +
+

he: עברית [Hebrew]

+
+ + +
+ +
+

hi-IN: हिन्दी (भारत) [Hindi]

+
+ + +
+ +
+

hr: Hrvatski [Croatian]

+
+ + +
+ +
+

hu: magyar [Hungarian]

+
+ + +
+ +
+

id: Bahasa Indonesia [Indonesian]

+
+ + +
+ +
+

ig: Igbo

+
+ + +
+ +
+

it: Italiano [Italian]

+
+ + +
+ +
+

ja: 日本語 [Japanese]

+
+ + +
+ +
+

ka: ქართული [Georgian]

+
+ + +
+ +
+

kab: Taqbaylit [Kabyle]

+
+ + +
+ +
+

ko: 한국어 [Korean]

+
+ + +
+ +
+

ln: Lingála

+
+ + +
+ +
+

mg: Malagasy

+
+ + +
+ +
+

ml: മലയാളം [Malayalam]

+
+ + +
+ +
+

ms: Melayu [Malay]

+
+ + +
+ +
+

my: မြန်မာဘာသာ [Myanmar]

+
+ + +
+ +
+

nl: Nederlands [Dutch]

+
+ + +
+ +
+

pl: Polski [Polish]

+
+ + +
+ +
+

pt-BR: Português (do Brasil) [Portuguese, Brazil]

+
+ + +
+ +
+

pt-PT: Português (Europeu) [Portuguese, Portugal]

+
+ + +
+ +
+

ro: română [Romanian]

+
+ + +
+ +
+

ru: Русский [Russian]

+
+ + +
+ +
+

son: Soŋay [Songhay]

+
+ + +
+ +
+

sr: Српски [Serbian]

+
+ + +
+ +
+

sq: Shqip [Albanian]

+
+ + +
+ +
+

sv-SE: Svenska [Swedish]

+
+ + +
+ +
+

sw: Kiswahili [Swahili]

+
+ + +
+ +
+

ta: தமிழ் [Tamil]

+
+ + +
+ +
+

te: తెలుగు [Telugu]

+
+ + +
+ +
+

th: ไทย [Thai]

+
+ + +
+ +
+

tl: Tagalog

+
+ + +
+ +
+

tn: Setswana [Tswana]

+
+ + +
+ +
+

tr: Türkçe [Turkish]

+
+ + +
+ +
+

uk: Українська [Ukrainian]

+
+ + +
+ +
+

vi: Tiếng Việt [Vietnamese]

+
+ + +
+ +
+

wo: Wolof

+
+ + +
+ +
+

xh: isiXhosa [Xhosa]

+
+ + +
+ +
+

yo: Yorùbá

+
+ + +
+ +
+

zh-CN: 中文 (简体) [Chinese, simplified]

+
+ + +
+ +
+

zh-TW: 中文 (繁體) [Chinese, traditional]

+
+ + +
+ +
+

zu: isiZulu [Zulu]

+
+ + +
+ +

The localization lead is marked by {{ref('*')}}. This is the person who leads a localization community on MDN, guiding their work in localizing content for a specific locale or topic.

+ +

其他區域

+ +

以下這些區域的在地化還沒有在 MDN 上,但可能有人想要貢獻這些區域。如果你對新增一個區域的在地化有興趣,請參見 Starting a new MDN localization 。

+ +

gu: ગુજરાતી [Gujarati]

+ + + +

lo: ພາສາລາວ [Lao]

+ + + +

si: සිංහල [Sinhalese]

+ + + +

ur: اردو [Urdu]

+ + + + diff --git a/files/zh-tw/mdn/contribute/localize/translating_pages/index.html b/files/zh-tw/mdn/contribute/localize/translating_pages/index.html new file mode 100644 index 0000000000..8b36f33fbd --- /dev/null +++ b/files/zh-tw/mdn/contribute/localize/translating_pages/index.html @@ -0,0 +1,52 @@ +--- +title: 翻譯 MDN 頁面 +slug: MDN/Contribute/Localize/Translating_pages +tags: + - 在地化 + - 指南 + - 頁面翻譯 +translation_of: MDN/Contribute/Localize/Translating_pages +--- +
{{MDNSidebar}}
+ +

本文為翻譯 MDN 內容提供基本指南,包括翻譯的運作機制及正確處理各種類型內容的訣竅。

+ +

開始翻譯新的頁面

+ +

當你來到一個欲翻譯成你的語言的頁面時,請按照下述步驟進行:

+ +
    +
  1. 點選語言圖示({{FontAwesomeIcon("icon-language")}})以開啟語言選單,接著點選 Add a Translation,選擇語言頁面將會出現。
  2. +
  3. 點選你想翻譯的語言,開啟翻譯文章介面。原文會顯示於畫面左側。
  4. +
  5. 翻譯描述裡,你可以翻譯標題並(選擇性的)翻譯「條目連結代碼」(slug)。條目連結代碼就是頁面網址的最末段(例如本文網址中的「Translating_pages」)。在某些語言社群中並不翻譯條目名稱,而會保持與英文一致。比較你語言中的其它文章,以了解習慣作法(編按:正體中文版本不翻譯 slug)。當你完成這部份時,你可以點選翻譯描述旁的減號將其隱藏,以讓出更多空間給內容翻譯的部份。
  6. +
  7. 翻譯內容裡翻譯頁面的內容。
  8. +
  9. 為該頁面填至少一個標籤
  10. +
  11. 當你完成時點選儲存修改
  12. +
+ +
注意: 翻譯新文章的使用者介面會以英文顯示。 更新文章時,如果 MDN 的介面有被在地化,則會以適當的語言顯示翻譯介面。 MDN 的使用者介面可以在 Pontoon 上進行在地化。請參見使用 Pontoon 來在地化以詳細了解如何使用該工具。
+ +

編輯已翻譯的頁面

+ + + +

如果英文原文在前次譯文更新之後有所變動,文章翻譯介面會以程式碼的風格,顯示英文版的「前後差異比對」,幫助你找到需要更新的部份。

+ +

翻譯標籤

+ +

幫每個頁面都標上至少一個標籤非常重要,即使這是譯文。

+ +

某些標籤用於搜尋篩選、或是貢獻者之間的約定用法,它們不應該被翻譯。 想要知道有哪些標籤,請閱讀標籤準則一文。如果文章還沒有被任何標準的標籤標記,你可以自由的建立翻譯過的標籤以將內容分組。

+ +

針對新譯者的指引

+ +

如果你是 MDN 的新譯者,這裡有些指引:

+ + diff --git a/files/zh-tw/mdn/editor/basics/index.html b/files/zh-tw/mdn/editor/basics/index.html new file mode 100644 index 0000000000..d33daf9aeb --- /dev/null +++ b/files/zh-tw/mdn/editor/basics/index.html @@ -0,0 +1,55 @@ +--- +title: Editor UI elements +slug: MDN/Editor/Basics +translation_of: MDN/Editor/Basics +--- +
{{MDNSidebar}}

The built-in WYSIWYG editor on MDN is designed to make it as easy as possible to create, edit, and improve articles and other pages almost anywhere on the site. The editor window, shown below, consists of eight key area. This guide provides information about each section so you know how to use our entire editing environment.

+ +
+

We're constantly working on improvements to MDN, so there will be times when this documentation or the screen shots below may be slightly out-of-date. We'll periodically update this documentation, though, to avoid it being unusably behind.

+
+ +

Screenshot of the editor UI (August 2017) with each section labeled

+ +

The editor UI contains the following sections, as shown above. Click a link below to read about that section of the editor.

+ + + +

Revision comment

+ +

After you've made your changes, it's strongly recommended you add a comment to your revision. This is displayed in the revision history for the page, as well as on the Revision Dashboard. It helps to explain or justify your changes to others that may review your work later. To add a revision comment, simply type the note into the revision comment box before clicking either of the Publish buttons at the top or bottom of the page.

+ +

There are a few reasons this is helpful:

+ + + +

Review requests

+ +

The MDN community uses reviews to try to monitor and improve the quality of MDN's content. This works by setting a flag on an article indicating that a review is needed. You can learn more about technical reviews and editorial review in the How to guides.

+ +

To request a review on the article you've worked on, toggle on the checkbox next to the type of review that's needed. Technical reviews should be requested any time you make changes to the explanation of how something technical works, while editorial reviews are a good idea when you've made changes and would like someone to review your writing and style choices.

+ +

While selecting a review checkbox adds the article to the lists of those needing technical review or needing editorial review, it does not guarantee that anyone will immediately review the article. For technical reviews, it's a good idea to directly contact a subject-matter expert in the relevant technical area. For editorial reviews, you can post in the MDN discussion forum to request that someone review your changes.

+ +

Be sure to click one of the Publish buttons after making your selections, to commit your review request.

+ +

See also

+ + + + diff --git a/files/zh-tw/mdn/editor/edit_box/index.html b/files/zh-tw/mdn/editor/edit_box/index.html new file mode 100644 index 0000000000..3c691a124b --- /dev/null +++ b/files/zh-tw/mdn/editor/edit_box/index.html @@ -0,0 +1,134 @@ +--- +title: Edit box of the MDN editor +slug: MDN/Editor/Edit_box +translation_of: MDN/Editor/Keyboard_shortcuts +--- +
{{MDNSidebar}}

The edit box is, of course, where you actually do your writing. Right-clicking in the editor box offers appropriate additional options depending on the context of your click: right-clicking in a table offers table-related options and right-clicking in a list offers list-related options, for example.

+ +

By default, the editor uses its own contextual menu when you right-click on the editor. To access your browser's default contextual menu (such as to access the Firefox spell checker's list of suggested corrections), hold down the Shift or Control key (the Command key on Mac OS X) while clicking.

+ +

鍵盤快捷鍵

+ +

There are a number of convenient keyboard shortcuts available to help you avoid taking your hands off the keyboard while you work. The shortcuts are listed for Windows and Linux; on Mac, instead of using the Control key, you can use the Command key.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
快捷鍵說明
Ctrl + A全選
Ctrl + C複製到剪貼簿
Ctrl + V從剪貼簿貼上
Ctrl + X剪下
Ctrl + Z回到上一步
Ctrl + Y重置
Ctrl + K開啟連結編輯器/新增連結
Ctrl + Shift + K移除連結游標位置。
Ctrl + B粗體
Ctrl + I斜體
Ctrl + O切換 <code> 樣式。
Ctrl + Shift + O +

切換原始碼顯示模式。

+ +
在原始碼模式下編輯時請小心,您需要遵守我們的內容標準。更多細節關於如何使用原始碼模式與使用之優缺點請參照原始碼模式編輯教學
+
Ctrl + P切換 <pre> 樣式在當前區塊中的開啟與關閉。
Ctrl + U底線。
Ctrl + S儲存修改並關閉編輯器。
Ctrl + Shift + S儲存修改但不要關閉編輯器。
Ctrl + 0Remove formatting from the selected area (That's a zero, not the letter "O").
Ctrl + 2 through Ctrl + 6Select heading level 2 through 6. Heading level 1 is reserved for the page title displayed at the top of the article.
Ctrl + Shift + LToggle from bulleted list to numbered list to and paragraph format
TabIncrease indent level if in indent mode, otherwise inserts two spaces as a tab. Inside tables, this moves the cursor to the next cell, or inserts a new row if there is no next cell. If the cursor is currently in the page title or in a heading, the cursor jumps to the next paragraph.
Shift + TabDecrease indent level if in indent mode. Inside tables, this jumps to the previous cell, or inserts a new row if there is no previous cell. If the cursor is currently in the page title or in a heading, the cursor jumps to the next paragraph.
Shift + SpaceInsert a non-breaking space (&nbsp;)
Shift + Enter +

Exits out of the current block. For example, if you're currently editing a <pre> block, Shift + Enter exits the block, putting you back in the body of the article.

+ +
+

Not currently implemented; see {{bug(780055)}}.

+
+
+ +

See also

+ + diff --git a/files/zh-tw/mdn/editor/index.html b/files/zh-tw/mdn/editor/index.html new file mode 100644 index 0000000000..5cf0ac0a43 --- /dev/null +++ b/files/zh-tw/mdn/editor/index.html @@ -0,0 +1,23 @@ +--- +title: Guide to the MDN editor UI +slug: MDN/Editor +tags: + - Documentation + - Guide + - Landing + - MDN + - MDN Meta + - 指南 +translation_of: MDN/Editor +--- +
{{MDNSidebar}}
{{IncludeSubnav("/zh-TW/docs/MDN")}}
+ +

MDN線上文件百科的WYSIWYG (what-you-see-is-what-you-get) 所見即所得編輯器讓人可以輕鬆地對新內容做出貢獻。

+ +

這個指南將教會您如何使用編輯器以及提升你的生產力,在您開始編輯或創造新頁面前,請先閱讀並同意遵守Mozilla Terms

+ +

MDN style guide 提供了內容的編排方法與風格,其中包含了我們建議的文法與拼字規則。

+ +

{{LandingPageListSubpages}}

+ +

{{EditorGuideQuicklinks}}

diff --git a/files/zh-tw/mdn/guidelines/index.html b/files/zh-tw/mdn/guidelines/index.html new file mode 100644 index 0000000000..da94b5a289 --- /dev/null +++ b/files/zh-tw/mdn/guidelines/index.html @@ -0,0 +1,13 @@ +--- +title: MDN 內容與風格指南 +slug: MDN/Guidelines +tags: + - Documentation + - Landing + - MDC Project + - MDN +translation_of: MDN/Guidelines +--- +
{{MDNSidebar}}

這些指南說明 MDN 文件該如何撰寫及格式化,及我們的範例程式與其他內容該如何呈現。 跟著這些指南進行,你就可以確保你的產出既乾淨又便於使用。

+ +

{{LandingPageListSubpages}}

diff --git a/files/zh-tw/mdn/guidelines/writing_style_guide/index.html b/files/zh-tw/mdn/guidelines/writing_style_guide/index.html new file mode 100644 index 0000000000..39d4d22e9a --- /dev/null +++ b/files/zh-tw/mdn/guidelines/writing_style_guide/index.html @@ -0,0 +1,567 @@ +--- +title: MDN 風格指南 +slug: MDN/Guidelines/Writing_style_guide +translation_of: MDN/Guidelines/Writing_style_guide +--- +
{{MDNSidebar}}
+ +

為了讓文檔更加組織化、標準化而易於閱讀,MDN 風格指南描述了文本的組織方式、拼寫和格式等問題。這些規則只是指導方針而非強制規定。與格式相比,我們對內容更感興趣,因此在你做貢獻之前,大可不必因為沒有學習本指南而感到驚訝或沮喪,只管放手去做便是。勤勞的志願者們會編輯你的工作以符合本指南。

+ +

如果你在尋找頁面應當如何結構化的具體方式,參見 MDN 頁面配置指南

+ +

在語言方面,本指南主要適用於英語文檔,其它語言可擁有(且歡迎創建)自己的風格指南。它們應作為當地語系化團隊頁面的子頁面發佈。

+ +

有關 MDN 以外網站內容的風格標準,請參考 Mozilla 風格指南

+ +

基礎

+ +

維持整份文件的一致性是各大文件發表風格指南的基礎。以下段落將會列出這些基礎概念來協助您。

+ +

頁面標題

+ +

頁面標題會展示於搜索結果中,也可用於在頂部的麵包屑導航列中的層次結構以建構頁面。頁面標題可以與頁面“縮略名”不同。縮略名會出現在“<locale>/docs/”後,是頁面URL的一部分。

+ +

標題與頁首的大小寫

+ +

頁面標題與章節標題應使用一般句子的大小寫形式(只大寫句首字母和專有名詞), 而非新聞式標題。

+ + + +

有些舊的頁面編寫於本樣式規則定版之前。若你願意,可隨時更新它們。我們會逐漸完善它們。

+ +

選擇標題與簡述

+ +

頁面縮略名應保持簡短;當創建新的層級時, 該層次的縮略名通常應只由一兩個單詞組成。

+ +

至於頁面標題,只要在合理範圍內,長度可以隨意,不過它應當是描述性的。

+ +

創建新子樹

+ +

當你需要添加關於某個主題或主題範圍的文章時,一般可以創建一個登陸頁面,然後為這些文章分別添加子頁面。登陸頁面應當以一兩段對該主題或技術的描述開頭,接著提供一個子頁面的清單,並對每個子頁面做簡短的描述。你可以用一些我們創建的巨集來將頁面自動插入到該清單中。

+ +

JavaScript 指南為例,它的結構如下:

+ + + +

請儘量避免將你的文章放在頂層,不然會拖慢網站的下載速度,降低網站導航和搜索的效率。

+ +

章節、段落與換行

+ +

請按照遞增順序使用標題級別:首先是 {{HTMLElement("h2")}},其次是{{HTMLElement("h3")}},接著是 {{HTMLElement("h4")}},不要跳過級別。H2 是允許的最高級別,因為 H1 要留給頁面標題。若你需要超過四、五個級別的標題,請考慮將該文章拆分為幾篇更小的文章並創建登陸頁面,然後用巨集 {{TemplateLink("Next")}}、{{TemplateLink("Previous")}} 和 {{TemplateLink("PreviousNext")}} 將他們連結起來。

+ +

在你鍵盤上的 Enter (或 return) 鍵會開一個新的段落。如果希望插入新的一行中間沒有空白,就同時按下 Shift 和 Enter 鍵。

+ +

Don't create single subsections -- you don't subdivide a topic into one. It's either two subheadings or more or none at all. 

+ +

Don't have bumping heads, which are headings followed immediately by headings. Aside from looking horrible, it's helpful to readers if every heading has at least a brief intro after it to introduce the subsections beneath.

+ +

文本格式與樣式

+ +

請使用“樣式”下拉清單來為選中的內容應用預定義的樣式。

+ +
注意: “注意” 樣式用於重要的注意事項,就像這樣。
+ +
警告:同樣,“警告”樣式用於創建警告框,就像這樣。
+ +

除非有明確指令,否則請勿使用 HTML 的 style 屬性來手動更改內容的風格。如果你無法使用預先定義的 class 來達成目的,就將他丟到 {{IRCLink("mdn")}} 以尋求協助。

+ +

範例程式的樣式與格式

+ +

縮排與換行

+ +

所有的程式碼範例,一個縮排使用兩個空白鍵。程式碼縮排要整潔、左大括號( { )和開展一段區域的宣稱同行。例如:

+ +
if (condition) {
+  /* handle the condition */
+} else {
+  /* handle the "else" case */
+}
+
+ +

一行不能長到要橫向滾動才能閱讀,應當於自然斷點處換行。例如:

+ +
if (class.CONDITION || class.OTHER_CONDITION || class.SOME_OTHER_CONDITION
+       || class.YET_ANOTHER_CONDITION ) {
+  /* something */
+}
+
+var toolkitProfileService = Components.classes["@mozilla.org/toolkit/profile-service;1"]
+                           .createInstance(Components.interfaces.nsIToolkitProfileService);
+
+ +

行內程式碼樣式

+ +

按下 Code 按鈕(標示為一對尖括號 <> )套用到函式、變數、以及方法名稱的行內程式碼(這用到了 {{HTMLElement("code")}} 元素),例如 frenchText() 函式。

+ +

方法名稱要跟著一對小括號:doSomethingUseful(),這能讓該方法與其他程式碼術語做出辨別。

+ +

語法高亮

+ +

Screenshot of the "syntax highlighting" menu.Entire lines (or multiple lines) of code should be formatted using syntax highlighting rather than the {{HTMLElement("code")}} element. Click the "pre" button in the toolbar to create the preformatted content box in which you'll then write your code. Then, with the text entry cursor inside the code box, select the appropriate language from the language list button to the right of the "pre" button, as seen in the screenshot to the right. The following example shows text with JavaScript formatting:

+ +
+
for (var i = 0, j = 9; i <= 9; i++, j--)
+  document.writeln("a[" + i + "][" + j + "]= " + a[i][j]);
+
+ +

If no appropriate transformation is available, use the pre tag without specifying a language ("No Highlight" in the language menu).

+ +
x = 42;
+ +

HTML 元素風格參考

+ +

There are various specific rules to follow when writing about HTML elements, in order to consistently describe the various components of elements, and to ensure that they're properly linked to detailed documentation.

+ +
+
元素名
+
請使用 {{TemplateLink("HTMLElement")}} macro,它可以導向該元素的網頁連結。例如說,寫 \{{HTMLElement("title")}} 就會產生 {{HTMLElement("title")}}。如果不想要有連結,使用尖括號把名字包起來 ,然後套用 Code (inline) 樣式(例如 <title>)。
+
屬性名
+
請使用 粗體
+
屬性定義
+
針對 definition term,請使用 {{TemplateLink("htmlattrdef")}} macro(例如 \{{htmlattrdef("type")}})so that it can be linked to from other pages, then use the {{TemplateLink("htmlattrxref")}} macro (e.g., \{{htmlattrxref("attr","element")}}) to reference attribute definitions.
+
屬性值
+
Use "Code (inline)" style, and do not use quotation marks around strings, unless needed by the syntax of a code sample. E.g.: When the type attribute of an <input> element is set to email or tel ...
+
Labeling attributes
+
Use labels like {{HTMLVersionInline(5)}} thoughtfully. For example, use them next to the bold attribute name but not for every occurrence in your body text.
+
+ +

拉丁語縮寫

+ +

在注記與括弧中

+ + + +

在行文中

+ + + +

與拉丁文意義相同的中/英文

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
縮寫拉丁文英文中文
cf.confercompare對比,比較
e.g.exempli gratiafor example例如
et al.et aliiand others什麼的,以及其他
etc.et ceteraand so forth, and so on等等,諸如此類
i.e.id estthat is, in other words即,換言之
N.B.nota benenote well注意
P.S.post scriptumpostscript注,附言
+ +
+

注意:永遠考慮使用拉丁語縮寫的收益。有些縮寫很少用到、多數讀者並不明白其意義,或常常與其他縮寫搞混。如果你要用,也請確定用對了,像常見的錯誤是把「e.g.」與「i.e.」搞混。

+
+ +

縮寫與簡稱

+ +

大小寫與點號

+ +

所有的縮寫與簡稱都要大寫、並把半形句點刪除,就算是「US」與「UN」之類的組織也一樣。

+ + + +

全名

+ +

On the first mention of a term on a page, expand acronyms likely to be unfamiliar to users. When in doubt, expand it, or, better, link it to the article or glossary entry describing the technology.

+ + + +

縮寫與簡寫的複數形式

+ +

For plurals of acronyms or abbreviations, add s. Don't use an apostrophe. Ever. Please.

+ + + +

大小寫

+ +

Use standard English capitalization rules in body text, and capitalize "World Wide Web" and "Web".

+ +

Keyboard keys should use sentence-style capitalization, not all-caps capitalization. For example, "Enter" not "ENTER."

+ +

縮寫

+ +

Use contractions (e.g. "don't", "can't", "shouldn't") if you prefer. We're not that formal!

+ +

複數形式

+ +

Use English-style plurals, not the Latin- or Greek-influenced forms.

+ + + +

連字號

+ +

Hyphenate compounds when the last letter of the prefix is a vowel and is the same as the first letter of the root.

+ + + +

性別中立的用語

+ +

It is a good idea to use gender-neutral language in any kind of writing where gender is irrelevant to the subject matter, to make the text as inclusive as possible. So for example, if you are talking about the actions of a specific man, usage of he/his would be fine, but if the subject is a person of either gender, he/his isn't really appropriate.
+
+ Let's take the following example:

+ +
+

A confirmation dialog appears, asking the user if he allows the web page to make use of his web cam.

+
+ +
+

A confirmation dialog appears, asking the user if she allows the web page to make use of her web cam.

+
+ +

Both versions in this case are gender-specific. This could be fixed by using gender-neutral pronouns:

+ +
+

A confirmation dialog appears, asking the user if they allow the web page to make use of their web cam.

+
+ +
+

Note: MDN allows the use of this very common syntax (which is controversial among usage authorities), in order to make up for the lack of a neutral gender in English. The use of the third-person plural as a neutral gender pronoun (that is, using "they," them", "their," and "theirs") is an accepted practice, commonly known as "singular 'they.'"

+
+ +

You can use both genders:

+ +
+

A confirmation dialog appears, asking the user if he or she allows the web page to make use of his/her web cam.

+
+ +

making the users plural:

+ +
+

A confirmation dialog appears, asking the users if they allow the web page to make use of their web cams.

+
+ +

The best solution, of course, is to rewrite and eliminate the pronouns completely:

+ +
+

A confirmation dialog appears, requesting the user's permission for web cam access.

+
+ +
+

A confirmation dialog box appears, which asks the user for permission to use the web cam.

+
+ +

The last way of dealing with the problem is arguably better, as it is not only grammatically more correct but removes some of the complexity associated with dealing with genders across different languages that may have wildly varying gender rules. This can make translation easier, both for readers reading English, then translating it into their own language as they read, and for localizers translating articles into their own language.

+ +

數字與數詞

+ +

日期

+ +

For dates (not including dates in code samples) use the format "January 1, 1990".

+ + + +

Alternately, you can use the YYYY/MM/DD format.

+ + + +

年代

+ +

For decades, use the format "1990s". Don't use an apostrophe.

+ + + +

數詞的複數

+ +

For plurals of numerals add "s". Don't use an apostrophe.

+ + + +

逗號

+ +

In running text, use commas only in five-digit and larger numbers.

+ + + +

標點符號

+ +

連續逗號

+ +

Use the serial comma. The serial (also known as "Oxford") comma is the comma that appears before the conjunction in a series of three or more items.

+ + + +
+

Note: This is in contrast to the One Mozilla style guide, which specifies that the serial comma is not to be used. MDN is an exception to this rule.

+
+ +

拼字

+ +

For words with variant spellings, always use the first entry at Answers.com. Do not use variant spellings.

+ + + +

術語

+ +

棄用 vs. 過時

+ +

It's important to be clear on the difference between the terms obsolete and deprecated.

+ +
+
棄用:
+
On MDN, the term obsolete marks an API or technology that is not only no longer recommended, but also no longer implemented in the browser. For Mozilla-specific technologies, the API is no longer implemented in Mozilla code; for Web standard technology, the API or feature is no longer supported by current, commonly-used browsers.
+
過時:
+
On MDN, the term deprecated marks an API or technology that is no longer recommended, but is still implemented and may still work. These technologies will in theory eventually become obsolete and be removed, so you should stop using them. For Mozilla-specific technologies, the API is still supported in Mozilla code; for Web standard technology, the API or feature has been removed or replaced in a recent version of the defining standard.
+
+ +

HTML 元素

+ +

Use "elements" to refer to HTML and XML elements, rather than "tags". In addition, they should almost always be wrapped in "<>", and should be in the {{HTMLElement("code")}} style. Also, at least the first time you reference a given element in a section should use the {{TemplateLink("HTMLElement")}} macro, to create a link to the documentation for the element (unless you're writing within that element's reference document page).

+ + + +

使用者介面動作

+ +

In task sequences, describe user interface actions using the imperative mood. Identify the user interface element by its label and type.

+ + + +

語態

+ +

While the active voice is generally preferred, the passive voice is also acceptable, given the informal feel of our content. Try to be consistent, though.

+ +

Wiki 語法與用處

+ +

外部連結

+ +

To automatically create a link to a Bugzilla bug, use this template:

+ +
\{{Bug(322603)}}
+
+ +

This results in:

+ +

{{Bug(322603)}}

+ +

For WebKit bugs, you can use this template:

+ +
\{{Webkitbug("322603")}}
+
+ +

This results in:

+ +

{{Webkitbug("322603")}}

+ +

頁面標籤

+ +

Tags provide meta information about a page and/or indicate that a page has specific improvements needed to its content. Every page in the wiki should have tags. You can find details on tagging in our How to properly tag pages guide.

+ +

The tagging interface lives at the bottom of a page while you're in edit mode, and looks something like this:

+ +

Screenshot of the UX for adding and removing tags on MDN

+ +

To add a tag, click in the edit box at the end of the tag list and type the tag name you wish to add. Tags will autocomplete as you type. Press enter (or return) to submit the new tag. Each article may have as many tags as needed. For example, an article about using JavaScript in AJAX programming might have both "JavaScript" and "AJAX" as tags.

+ +

To remove a tag, simply click the little "X" icon in the tag.

+ +

標記需要加工的頁面

+ +

In addition to using tags to track information about the documentation's quality and content, we also use them to mark articles as needing specific types of work.

+ +

標記棄用的頁面

+ +

Use the following tags for pages that are not current:

+ + + +

SEO 摘要

+ +

The SEO summary is a very short summary of the page. It will be reported as a summary of the article to robots crawling the site, and will then appear in search results for the page. It is also used by macros that automate the construction of landing pages inside MDN itself.

+ +

By default, the first pagragraph of the page is used as the SEO summary. However you can override this behavior by marking a section with the "SEO summary" style in the WYSIWYG editor.

+ +

導航頁面

+ +

Landing pages are pages at the root of a topic area of the site, such as the main CSS or HTML pages. They have a standard format that consists of three areas:

+ +
    +
  1. A brief (typically one paragraph) overview of what the technology is and what it's used for. See {{anch("Writing a landing page overview")}} for tips.
  2. +
  3. A two-column list of links with appropriate headings. See {{anch("Creating a page link list")}} for guidelines.
  4. +
  5. An optional "Browser compatibility" section at the bottom of the page.
  6. +
+ +

創建頁面連結清單

+ +

The link list section of an MDN landing page consists of two columns. These are created using the following HTML:

+ +
<div class="row topicpage-table">
+  <div class="section">
+    ... left column contents ...
+  </div>
+  <div class="section">
+    ... right column contents ...
+  </div>
+</div>
+ +

The left-hand column should be a list of articles, with an <h2> header at the top of the left column explaining that it's a list of articles about the topic (for example "Documentation and tutorials about foo"); this header should use the CSS class "Documentation". Below that is a <dl> list of articles, with each article's link in a <dt> block and a brief one-or-two sentence summary of the article in the corresponding <dd> block.

+ +

The right-hand column should contain one or more of the following sections, in order:

+ +
+
從社群尋求協助
+
This should provide information on Matrix rooms and mailing lists available about the topic. The heading should use the class "Community".
+
工具
+
A list of tools the user can look at to help with the use of the technology described in this section of MDN. The heading should use the class "Tools".
+
相關主題
+
A list of links to landing pages for other, related, technologies of relevance. The heading should use the class "Related_Topics".
+
+ +

<<<finish this once we finalize the landing page standards>>>

+ +

插入、使用圖片

+ +

It's sometimes helpful to provide an image in an article you create or modify, especially if the article is very technical. To include an image:

+ +
    +
  1. Attach the desired image file to the article (at the bottom of every article in edit mode)
  2. +
  3. Create an image in the WYSIWYG editor
  4. +
  5. In the WYSIWYG editor in the drop-down list listing attachments, select the newly created attachment which is your image
  6. +
  7. Press OK.
  8. +
+ +

其它參考

+ +

首選風格指南

+ +

If you have questions about usage and style not covered here, we recommend referring to the Economist style guide or, failing that, the Chicago Manual of Style.

+ +

首選詞典

+ +

For questions of spelling, please refer to Answers.com. The spell-checker for this site uses American English. Please do not use variant spellings (e.g., use honor rather than honour).

+ +

We will be expanding the guide over time, so if you have specific questions that aren't covered in this document, please send them to the MDC mailing list or project lead so we know what should be added.

+ +

MDN 特定資訊

+ + + +

語言、文法和拼字

+ +

If you're interested in improving your writing and editing skills, you may find the following resources to be helpful.

+ + diff --git a/files/zh-tw/mdn/index.html b/files/zh-tw/mdn/index.html new file mode 100644 index 0000000000..c335002f11 --- /dev/null +++ b/files/zh-tw/mdn/index.html @@ -0,0 +1,32 @@ +--- +title: MDN 專案 +slug: MDN +tags: + - Documentation + - MDN +translation_of: MDN +--- +
{{MDNSidebar}}
+ +

MDN Web Docs 是我們為開放網路、Mozilla 技術、Firefox 與其他開發者相關專題建立文件的 Wiki 系統。歡迎任何人新增與編輯內容。你不需要是程式設計師或非常了解技術;這邊有各種需要協助的工作,從最簡單(閱讀文件、改錯字)到最複雜(撰寫 API 文件)都有。

+ +
+

MDN Web Docs 的使命是提供開發者網站平台輕鬆建立專案所需的資訊。歡迎加入!

+
+ +

我們歡迎你的直接協助,非常容易!也不需要擔心「要不要獲得許可」之類的問題。在此同時,請試著了解並融入 MDN 社群;我們都在這裡協助你!以下文件能作為起步的指引。

+ + + + diff --git a/files/zh-tw/mdn/kuma/index.html b/files/zh-tw/mdn/kuma/index.html new file mode 100644 index 0000000000..1a4263acad --- /dev/null +++ b/files/zh-tw/mdn/kuma/index.html @@ -0,0 +1,26 @@ +--- +title: 'Kuma: MDN 的維基平台' +slug: MDN/Kuma +tags: + - Kuma + - Landing + - MDN Meta +translation_of: MDN/Kuma +--- +
{{MDNSidebar}}
+ +
{{IncludeSubnav("/zh-TW/docs/MDN")}}
+ +

Kuma 是由 MDN Web Docs 維護的 Django 程式碼。

+ +

{{SubpagesWithSummaries}}

+ +

參與 Kuma

+ +

要參與 Kuma:

+ + diff --git a/files/zh-tw/mdn/tools/index.html b/files/zh-tw/mdn/tools/index.html new file mode 100644 index 0000000000..a7ac474b98 --- /dev/null +++ b/files/zh-tw/mdn/tools/index.html @@ -0,0 +1,15 @@ +--- +title: MDN tools +slug: MDN/Tools +tags: + - Landing + - MDN Meta +translation_of: MDN/Tools +--- +
{{MDNSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/MDN")}}
+ +

MDN 提供了許多功能來簡化追蹤進度、管理內容,並跟上網站最新的修改。

+ +

{{LandingPageListSubpages}}

diff --git a/files/zh-tw/mdn/tools/kumascript/index.html b/files/zh-tw/mdn/tools/kumascript/index.html new file mode 100644 index 0000000000..9404ced57b --- /dev/null +++ b/files/zh-tw/mdn/tools/kumascript/index.html @@ -0,0 +1,490 @@ +--- +title: KumaScript +slug: MDN/Tools/KumaScript +translation_of: MDN/Tools/KumaScript +--- +
{{MDNSidebar}}

概要

+ +

On the Kuma platform that powers MDN, the template system for automating aspects of content on the wiki is called KumaScript. KumaScript is powered by server-side JavaScript, implemented using Node.js. This article provides basic information on how to use KumaScript.

+ +

For a detailed overview and Q&A of KumaScript, watch the MDN dev team's KumaScript Fireside Chat (the meeting starts at 10 minutes into the video). KumaScript replaced DekiScript, which was the template language for MindTouch, the previous platform used by MDN.

+ +

What is KumaScript?

+ + + +

What KumaScript is not

+ + + +

基礎

+ +

KumaScript is used on MDN in embedded JavaScript templates. These templates can be invoked in document content by any MDN author, through the use of macros.

+ +

A script in KumaScript is a template, and each template is a file in the macros directory of the KumaScript repository on Github. A  template looks like this:

+ +
<% for (var i = 0; i < $0; i++) { %>
+Hello #<%= i %>
+<% } %>
+ +

Invoking a template is done with a macro, which can be used anywhere in any wiki content. A macro looks like this:

+ +
\{{ hello("3") }}
+ +

The output of the macro looks like this:

+ +
Hello #0
+Hello #1
+Hello #2
+ +

Macro syntax

+ +

KumaScript templates are invoked in document content with macros, like this:

+ +
\{{ templateName("arg0", "arg1", ..., "argN") }}
+
+ +

Macro syntax consists of these rules:

+ + + +

Using JSON as a macro parameter

+ +

As a semi-experimental feature (not guaranteed to work), you can supply a JSON object for the first and only parameter, like so:

+ +
\{{ templateName({ "Alpha":"one", "Beta":["a","b","c"], "Foo":"http:\/\/mozilla.org\/" }) }}
+
+ +

The data from this macro is available in template code as an object in the $0 argument (e.g., $0.Alpha, $0.Beta, $0.Foo). This also allows you to express complex data structures in macro parameters that are hard or impossible to do with a simple list of parameters.

+ +

Note that this parameter style is very picky — it must adhere to JSON syntax exactly, which has some requirements about escaping characters that are easy to miss (e.g., all forward slashes are escaped). When in doubt, try running your JSON through a validator.

+ +

How to write "\{{" in text

+ +

Since the character sequence "\{{" is used to indicate the start of a macro, this can be troublesome if you actually just want to use "\{{" and "}}" in a page. It will probably produce DocumentParsingError messages.

+ +

In this case, you can escape the first brace with a backslash, like so: \\{

+ +

Template syntax

+ +

Each KumaScript template is a file under the macros directory of KumaScript. You create and edit these files as you would the files of any open-source project on GitHub (see the KumaScript README for more information).

+ +

KumaScript templates are processed by an embedded JavaScript template engine with a few simple rules:

+ + + +

Tips

+ +

You can see a list of macros and how they are used on MDN on the macros dashboard.

+ +

進階功能

+ +

Beyond the basics, the KumaScript system offers some advanced features.

+ +

Environment variables

+ +

When the wiki makes a call to the KumaScript service, it passes along some context on the current document that KumaScript makes available to templates as variables:

+ +
+
env.path
+
The path to the current wiki document
+
env.url
+
The full URL to the current wiki document
+
env.id
+
A short, unique ID for the current wiki document
+
env.files
+
An array of the files attached to the current wiki document; each object in the array is as described under {{ anch("File objects") }} below
+
env.review_tags
+
An array of the review tags on the article ("technical", "editorial", etc.)
+
env.locale
+
The locale of the current wiki document
+
env.title
+
The title of the current wiki document
+
env.slug
+
The URL slug of the current wiki document
+
env.tags
+
An array list of tag names for the current wiki document
+
env.modified
+
Last modified timestamp for the current wiki document
+
env.cache_control
+
Cache-Control header sent in the request for the current wiki document, useful in deciding whether to invalidate caches
+
+ +

File objects

+ +

Each file object has the following fields:

+ +
+
title
+
The attachment's title
+
description
+
A textual description of the current revision of the file
+
filename
+
The file's name
+
size
+
The size of the file in bytes
+
author
+
The username of the person who uploaded the file
+
mime
+
The MIME type of the file
+
url
+
The URL at which the file can be found
+
+ +

Working with tag lists

+ +

The env.tags and env.review_tags variables return arrays of tags. You can work with these in many ways, of course, but here are a couple of suggestions.

+ +
Looking to see if a specific tag is set
+ +

You can look to see if a specific tag exists on a page like this:

+ +
if (env.tags.indexOf("tag") != −1) {
+  // The page has the tag "tag"
+}
+
+ +
Iterating over all the tags on a page
+ +

You can also iterate over all the tags on a page, like this:

+ +
env.tag.forEach(function(tag) {
+  // do whatever you need to do, such as:
+  if (tag.indexOf("a") == 0) {
+    // this tag starts with "a" - woohoo!
+  }
+});
+ +

APIs and Modules

+ +

KumaScript offers some built-in methods and APIs for KumaScript macros.  Macros can also use module.exports to export new API methods.

+ +

API changes require updating the KumaScript engine or macros via a pull request to the KumaScript repository.

+ +

Built-in methods

+ +

This manually-maintained documentation is likely to fall out of date with the code. With that in mind, you can always check out the latest state of built-in APIs in the KumaScript source. But here is a selection of useful methods exposed to templates:

+ +
+
md5(string)
+
Returns an MD5 hex digest of the given string.
+
template("name", ["arg0", "arg1", ..., "argN"])
+
Executes and returns the result of the named template with the given list of parameters.
+
Example: <%- template("warning", ["foo", "bar", "baz"]) %>.
+
Example using the domxref macro: <%- template("domxref", ["Event.bubbles", "bubbles"]) %>.
+
This is a JavaScript function. So, if one of the parameters is an arg variable like $2, do not put it in quotes. Like this: <%- template("warning", [$1, $2, "baz"]) %>. If you need to call another template from within a block of code, do not use <% ... %>. Example: myvar = "<li>" + template("LXRSearch", ["ident", "i", $1]) + "</li>";
+
require(name)
+
Loads another template as a module; any output is ignored. Anything assigned to module.exports in the template is returned.
+
Used in templates like so: <% var my_module = require('MyModule'); %>.
+
cacheFn(key, timeout, function_to_cache)
+
Using the given key and cache entry lifetime, cache the results of the given function. Honors the value of env.cache_control to invalidate cache on no-cache, which can be sent by a logged-in user hitting shift-refresh.
+
request
+
Access to mikeal/request, a library for making HTTP requests. Using this module in KumaScript templates is not yet very friendly, so you may want to wrap usage in module APIs that simplify things.
+
log.debug(string)
+
Outputs a debug message into the script log on the page (i.e. the big red box that usually displays errors).
+
+ +

Built-in API modules

+ +

There's only one API built in at the moment, in the kuma namespace. You can see the most up to date list of methods under kuma from the KumaScript source code, but here are a few:

+ +
+
kuma.inspect(object)
+
Renders any JS object as a string, handy for use with log.debug(). See also: node.js util.inspect().
+
+ +
+
kuma.htmlEscape(string)
+
Escapes the characters &, <, >, " to &amp, &lt;, &gt;, &quot;, respectively.
+
kuma.url
+
See also: node.js url module.
+
kuma.fetchFeed(url)
+
Fetch an RSS feed and parse it into a JS object. See also: InsertFeedLinkList
+
+ +

Creating modules

+ +

Using the built-in require() method, you can load a template as a module to share common variables and methods between templates. A module can be defined in a template like this:

+ +
<%
+module.exports = {
+    add: function (a, b) {
+        return a + b;
+    }
+}
+%>
+
+ +

Assuming this template is saved under https://github.com/mdn/kumascript/tree/master/macros as MathLib.ejs, you can use it in another template like so:

+ +
<%
+var math_lib = require("MathLib");
+%>
+The result of 2 + 2 = <%= math_lib.add(2, 2) %>
+
+ +

And, the output of this template will be:

+ +
The result of 2 + 2 = 4
+
+ +

Auto-loaded modules

+ +

There are a set of modules editable as wiki templates that are automatically loaded and made available to every template. This set is defined in the configuration file for the KumaScript service - any changes to this requires an IT bug to edit configuration and a restart of the service.

+ +

For the most part, these attempt to provide stand-ins for legacy DekiScript features to ease template migration. But, going forward, these can be used to share common variables and methods between templates:

+ + + +

Note: You might notice that the DekiScript modules use a built-in method named buildAPI(), like so:

+ +
<% module.exports = buildAPI({
+    StartsWith: function (str, sub_str) {
+        return (''+str).indexOf(sub_str) === 0;
+    }
+}); %>
+
+ +

The reason for this is because DekiScript is case-insensitive when it comes to references to API methods, whereas JavaScript is strict about uppercase and lowercase in references. So, buildAPI() is a hack to try to cover common case variations in DekiScript calls found in legacy templates.

+ +
+

With that in mind, please do not use buildAPI() in new modules.

+
+ +

Tips and caveats

+ +

Debugging

+ +

A useful tip when debugging. You can use the log.debug() method to output text to the scripting messages area at the top of the page that's running your template. Note that you need to be really sure to remove these when you're done debugging, as they're visible to all users! To use it, just do something like this:

+ +
<%- log.debug("Some text goes here"); %>
+
+ +

You can, of course, create more complex output using script code if it's helpful.

+ +

Caching

+ +

KumaScript templates are heavily cached to improve performance. For the most part, this works great to serve up content that doesn't change very often. But, as a logged-in user, you have two options to force a page to be regenerated, in case you notice issues with scripting:

+ + + +

Using search keywords to open template pages

+ +

When using templates, it's common to open the template's code in a browser window to review the comments at the top, which are used to document the template, its parameters, and how to use it properly. To quickly access templates, you can create a Firefox search keyword, which gives you a shortcut you can type in the URL box to get to a template more easily.

+ +

To create a search keyword, open the bookmarks window by choosing "Show all bookmarks" in the Bookmarks menu, or by pressing Control-Shift-B (Command-Shift-B on Mac). Then from the utility ("Gear") menu in the Library window that appears, choose "New Bookmark...".

+ +

This causes the bookmark editing dialog to appear. Fill that out as follows:

+ +
+
Name
+
A suitable name for your search keyword; "Open MDN Template" is a good one.
+
Location
+
https://github.com/mdn/kumascript/blob/master/macros/%s
+
Tags {{optional_inline}}
+
A list of tags used to organize your bookmarks; these are entirely optional and what (if any) tags you use is up to you.
+
Keyword
+
The shortcut text you wish to use to access the template. Ideally, this should be something short and quick to type, such as simply "t" or "mdnt".
+
Description {{optional_inline}}
+
A suitable description explaining what the search keyword does.
+
+ +

The resulting dialog looks something like this:

+ +

+ +

Then click the "Add" button to save your new search keyword. From then on, typing your keyword, then a space, then the name of a macro will open that macro in your current tab. So if you used "t" as the keyword, typing t ListSubpages will show you the page at {{TemplateLink("ListSubpages")}}.

+ +

Cookbook

+ +

This section will list examples of common patterns for templates used on MDN, including samples of legacy DekiScript templates and their new KumaScript equivalents.

+ +

Force templates used on a page to be reloaded

+ +

It bears repeating: To force templates used on a page to be reloaded after editing, hit Shift-Reload. Just using Reload by itself will cause the page contents to be regenerated, but using cached templates and included content. A Shift-Reload is necessary to invalidate caches beyond just the content of the page itself.

+ +

Recovering from "Unknown Error"

+ +

Sometimes, you'll see a scripting message like this when you load a page:

+ +
Kumascript service failed unexpectedly: <class 'httplib.BadStatusLine'>
+ +

This is probably a temporary failure of the KumaScript service. If you Refresh the page, the error may disappear. If that doesn't work, try a Shift-Refresh. If, after a few tries, the error persists - file an IT bug for Mozilla Developer Network to ask for an investigation.

+ +

Broken wiki.languages() macros

+ +

On some pages, you'll see a scripting error like this:

+ +
Syntax error at line 436, column 461: Expected valid JSON object as the parameter of the preceding macro but...
+
+ +

If you edit the page, you'll probably see a macro like this at the bottom of the page:

+ +
\{{ wiki.languages({ "zh-tw": "zh_tw/Core_JavaScript_1.5_教學/JavaScript_概要", ... }) }}
+
+ +

To fix the problem, just delete the macro. Or, replace the curly braces on either side with HTML comments <!-- --> to preserve the information, like so:

+ +
<!-- wiki.languages({ "zh-tw": "zh_tw/Core_JavaScript_1.5_教學/JavaScript_概要", ... }) -->
+
+ +

Because Kuma supports localization differently, these macros aren't actually needed any more. But, they've been left intact in case we need to revisit the relationships between localized pages. Unfortunately, it seems like migration has failed to convert some of them properly.

+ +

Finding the Current Page's Language

+ +

In KumaScript, the locale of the current document is exposed as an environment variable:

+ +
var lang = env.locale;
+
+ +

The env.locale variable should be reliable and defined for every document.

+ +

Reading the contents of a page attachment

+ +

You can read the contents of an attached file by using the mdn.getFileContent() function, like this:

+ +
<%
+  var contents = mdn.getFileContent(fileUrl);
+  ... do stuff with the contents ...
+%>
+
+ +

or

+ +
<%-mdn.getFileContent(fileObject)%>
+
+ +

In other words, you may specify either the URL of the file to read or as a file object. The file objects for a page can be accessed through the array env.files. So, for example, to embed the contents of the first file attached to the article, you can do this:

+ +
<%-mdn.getFileContent(env.files[0])%>
+
+ +
Note: You probably don't want to try to embed the contents of a non-text file this way, as the raw contents would be injected as text. This is meant to let you access the contents of text attachments.
+ +

If the file isn't found, an empty string is returned. There is currently no way to tell the difference between an empty file and a nonexistent one. But if you're putting empty files on the wiki, you're doing it wrong.

+ +

Localizing template content

+ +

Templates are not translated like wiki pages, rather any single template might be used for any number of locales.

+ +

So the main way to output content tailored to the current document locale is to pivot on the value of env.locale. There are many ways to do this, but a few patterns are common in the conversion of legacy DekiScript templates:

+ +

If/else blocks in KumaScript

+ +

The KumaScript equivalent of this can be achieved with simple if/else blocks, like so:

+ +
<% if ("fr" == env.locale) { %>
+<%- template("CSSRef") %> « <a title="Référence_CSS/Extensions_Mozilla" href="/fr/docs/Référence_CSS/Extensions_Mozilla">Référence CSS:Extensions Mozilla</a>
+<% } else if ("ja" == env.locale) { %>
+<%- template("CSSRef") %> « <a title="CSS_Reference/Mozilla_Extensions" href="/ja/docs/CSS_Reference/Mozilla_Extensions">CSS リファレンス:Mozilla 拡張仕様</a>
+<% } else if ("pl" == env.locale) { %>
+<%- template("CSSRef") %> « <a title="Dokumentacja_CSS/Rozszerzenia_Mozilli" href="/pl/docs/Dokumentacja_CSS/Rozszerzenia_Mozilli">Dokumentacja CSS:Rozszerzenia Mozilli</a>
+<% } else if ("de" == env.locale) { %>
+<%- template("CSSRef") %> « <a title="CSS_Referenz/Mozilla_CSS_Erweiterungen" href="/de/docs/CSS_Referenz/Mozilla_CSS_Erweiterungen">CSS Referenz: Mozilla Erweiterungen</a>
+<% } else { %>
+<%- template("CSSRef") %> « <a title="CSS_Reference/Mozilla_Extensions" href="/en-US/docs/CSS_Reference/Mozilla_Extensions">CSS Reference:Mozilla Extensions</a>
+<% } %>
+
+ +

Depending on what text editor is your favorite, you may be able to copy & paste from the browser-based editor and attack this pattern with a series of search/replace regexes to get you most of the way there.

+ +

My favorite editor is MacVim, and a series of regexes like this does the bulk of the work with just a little manual clean up following:

+ +
%s#<span#^M<span#g
+%s#<span lang="\(.*\)" .*>#<% } else if ("\1" == env.locale) { %>#g
+%s#<span class="script">template.Cssxref(#<%- template("Cssxref", [#
+%s#)</span> </span>#]) %>
+
+ +

Your mileage may vary, and patterns change slightly from template to template. That's why the migration script was unable to just handle this automatically, after all.

+ +

String variables and switch

+ +

Rather than switch between full chunks of markup, you can define a set of strings, switch them based on locale, and then use them to fill in placeholders in a single chunk of markup:

+ +
<%
+var s_title = 'Firefox for Developers';
+switch (env.locale) {
+    case 'de':
+        s_title = "Firefox für Entwickler";
+        break;
+    case 'fr':
+        s_title = "Firefox pour les développeurs";
+        break;
+    case 'es':
+        s_title = "Firefox para desarrolladores";
+        break;
+};
+%>
+<span class="title"><%= s_title %></span>
+
+ +

Use mdn.localString()

+ +

A recent addition to the MDN:Common module is mdn.localString(), used like this:

+ +
<%
+var s_title = mdn.localString({
+  "en-US": "Firefox for Developers",
+  "de": "Firefox für Entwickler",
+  "es": "Firefox para desarrolladores"
+});
+%>
+<span class="title"><%= s_title %></span>
+
+ +

This is more concise than the switch statement, and may be a better choice where a single string is concerned. However, if many strings need to be translated (e.g., as in CSSRef), a switch statement might help keep all the strings grouped by locale and more easily translated that way.

+ +

When the object does not have the appropriate locale, the value of "en-US" is used as the initial value.

+ +

參見

+ + diff --git a/files/zh-tw/mdn/tools/kumascript/troubleshooting/index.html b/files/zh-tw/mdn/tools/kumascript/troubleshooting/index.html new file mode 100644 index 0000000000..e3dcd998d5 --- /dev/null +++ b/files/zh-tw/mdn/tools/kumascript/troubleshooting/index.html @@ -0,0 +1,63 @@ +--- +title: 修復 KumaScript 錯誤 +slug: MDN/Tools/KumaScript/Troubleshooting +translation_of: MDN/Tools/KumaScript/Troubleshooting +--- +
{{MDNSidebar}}
+

網頁上出現一塊又大又醜的 KumaScript 錯誤會惹惱讀者,好險任何擁有 MDN 帳號的人,可以編輯文件來修復錯誤。當一個頁面出現錯誤的時候,該面會被列在有錯誤的文件裡面。網站編輯者會透過這份清單,找出並修復錯誤。這篇文章列出 KumaScript 錯誤的四種類型,還有解決他們的步驟。

+
+ +

文件解析錯誤

+ +

DocumentParsingError errors appear when KumaScript has trouble understanding something in the document itself. The most common cause is a syntax error in a macro.

+ +

Check for:

+ +
+
Use of curly braces without intending to call a macro.
+
If you need to write  \{ in a document without calling a macro you can escape it with a \ like this: \\{
+
Use of a special character in a macro parameter.
+
If you need to use a " or a \  inside of a macro parameter they can be escaped with a \ like this: \\ or \"
+
Missing commas between macro parameters.
+
Macro parameters need to be delimited by a comma (,) but not at the end of the list of parameters; for example \{\{anch("top", "Back to top")}}.
+
HTML tags appearing inside a macro call
+
If you apply styling to a macro, it will often break because, for example, a </code> tag may have appeared inside the macro code in the source code. Check the source view to see what's there, and remove any unnecessary styling.
+
+ + + +

TemplateLoadingError

+ +

TemplateLoadingError errors appear when KumaScript has trouble finding which macro to include on a page.

+ +

Check for:

+ +
+
Misspelling of macro names or renamed macros.
+
You can try visiting the template page for the macro to see if it's named correctly. The URL for the template page can be constructed by adding the template name to the end of the URL https://developer.mozilla.org/en-US/docs/Template: — for example the template page for \{\{anch("top", "Back to top")}}  is https://developer.mozilla.org/en-US/docs/Template:anch.
+
+ There is a partial list of macros for the MDN, which may include the existing macro you are looking at, or its correct/new spelling.
+
+ +
+

Tip: You can make it quick and easy to jump to a specific macro by adding a search keyword to Firefox. <<<MORE SOON>>

+
+ +

TemplateExecutionError

+ +

TemplateExecutionError errors appear when KumaScript encounters an error in the macro. These errors can only be fixed by admin users and need to be reported as bugs.

+ +

Before reporting an error check to see that it hasn't already been fixed. You can do this by forcing KumaScript to give you a fresh copy of the page by holding down Shift while you refresh the page (Shift + Ctrl + R on Windows/Linux, Shift + Cmd + R on Mac).

+ +

If the error persists, report a bug, including the URL of the page and the text of the error.

+ +

未知和錯誤

+ +

如果錯誤並不屬於上述任何一項時,將被歸類為未知.

+ +

Check for fixes and report persistent bugs like described under TemplateExecutionError.

+ +

 

+ +

 

diff --git a/files/zh-tw/mdn_at_ten/index.html b/files/zh-tw/mdn_at_ten/index.html new file mode 100644 index 0000000000..039fa64ed8 --- /dev/null +++ b/files/zh-tw/mdn_at_ten/index.html @@ -0,0 +1,37 @@ +--- +title: MDN 10 週年 +slug: MDN_at_ten +translation_of: MDN_at_ten +--- +
慶祝文件化網頁10年.
+ +
+
+

MDN 的歷史

+ +

在 2005 早期, 一個小團隊開始創見一個新穎, 免費的網路社群資源給所有的網路開發者. 他們的才華和不一樣的想法成為了今天的 Mozilla 開發者網路平台(Mozilla Developer Network)—所有開放網路技術的主要資源. 十年後, 我們全球的社群比以往都來的大, 而且我們也持續為開放網路科技創建文件, 提供範例程式碼和學習資源, 包含 CSS, HTML, JavaScript 及其他.

+ +

了解更多 about the history

+ + +

協助 MDN

+ +

十年來, MDN 社群紀錄開放網路. 從修改錯別字到撰寫整個 API 文件, 每個人不分多少都有貢獻. 我們擁有超過 90,000 頁的資料內容已經被我們傑出的成員(Mozillians)翻譯或編寫. 你也可以成為其中的一員.

+ +

了解更多 about contributing

+ +

 

+ +

 

+
+ +
{{TenthCampaignQuote}}
+ + + +
    +
  1. MDN 10 週年
  2. +
  3. MDN 的歷史
  4. +
  5. 協助 MDN
  6. +
+
diff --git a/files/zh-tw/mercurial/index.html b/files/zh-tw/mercurial/index.html new file mode 100644 index 0000000000..1a375a0643 --- /dev/null +++ b/files/zh-tw/mercurial/index.html @@ -0,0 +1,22 @@ +--- +title: Mercurial +slug: Mercurial +translation_of: Mozilla/Mercurial +--- +

Mercurial (also known as "hg"), is the distributed version control software used for the development of Firefox, Thunderbird, and the shared Gecko core. It replaced CVS after Mozilla 1.9 was branched.

+

hg is the Mercurial command-line tool, Hg being the chemical symbol for the element mercury.

+

Learning to use Mercurial

+

First, read every word of Mercurial basics, before you do anything else.

+

Then, the Mercurial FAQ is a decent place to start.

+

See Getting Mozilla Source Code Using Mercurial for getting a tree to build.

+

See Mercurial Queues for managing queues of patches, and how to integrate Mercurial with Bugzilla.

+

Further reading

+

The hg book is the definitive Mercurial user guide.

+

The Mercurial tag lists the Mercurial-related articles on MDC.

+

And on wiki.mozilla.org, these helpful pages:

+ +

{{ languages( { "es": "es/Mercurial", "fr": "fr/Mercurial", "ja": "ja/Mercurial" } ) }}

diff --git a/files/zh-tw/mozilla/add-ons/add-on_debugger/index.html b/files/zh-tw/mozilla/add-ons/add-on_debugger/index.html new file mode 100644 index 0000000000..2b3106d6af --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/add-on_debugger/index.html @@ -0,0 +1,78 @@ +--- +title: 附加元件除錯工具箱 +slug: Mozilla/Add-ons/Add-on_Debugger +translation_of: 'https://extensionworkshop.com/documentation/develop/debugging/' +--- +

{{AddonSidebar}}

+ +

附加元件除錯工具箱提供 Firefox 工具箱中的部分工具,能在附加元件的作用範圍中除錯:

+ + + +

需要重新啟動瀏覽器的 XUL overlay 附加元件無法使用附加元件除錯工具箱,這類的元件請使用瀏覽器工具箱

+ +

請看這段影片,快速認識附加元件除錯工具箱:

+ +

{{EmbedYouTube("KU3Xsck7qy0")}}

+ +

啟用附加元件除錯工具箱

+ +
+

如欲啟用附加元件除錯工具箱,您必須啟用 Firefox 裡的「啟用瀏覽器 chrome 與附加元件除錯工具箱」及「啟用遠端除錯」兩項設定。您可開啟網頁工具箱裡的設定,而後在「進階設定」一區中啟用上述選項。

+
+ +

開啟附加元件除錯工具箱

+ +

註:如前所述,附加元件除錯工具是專供不需重新啟動、以 SDK 製作的附加元件使用。若想為其他類型的附加元件除錯,請使用瀏覽器工具箱裡的工具。

+ +

Now open the Add-on Manager. Next to the entry for your add-on you will see a button labeled "Debug". Click this button to launch the debugger.

+ +

Next you'll see a dialog asking you to accept an incoming connection. Click "OK", and the debugger will start in a separate window. Note that sometimes the debugger window is hidden by the main Firefox window.

+ +

{{EmbedYouTube("DvNpUVJcG_E")}}

+ +

使用附加元件除錯工具

+ +

The Add-on Debugger looks and behaves very much like the Browser Toolbox, except that while the scope of the Browser Toolbox is the whole browser, the Add-on Debugger is focused on the specific add-on for which you launched it. Like the Browser Toolbox, a toolbar along the top lets you switch between a number of different tools. In Firefox 31 there's only one such tool, the JavaScript Debugger, but with Firefox 32 you also get the Console and Scratchpad.

+ +

JavaScript 除錯器

+ +

This behaves just like the normal JavaScript Debugger, except its scope is the add-on rather than a web page. On the left-hand side it lists JavaScript sources:

+ + + +

Content scripts

+ +

Content scripts are only listed if and when they are loaded. So, if your Add-on loads a content script with contentScriptFile, the file will not appear in the debugger sources until you go to a page that loads the content script.

+ +

If you set a breakpoint in a content script, it will not be active for instances of the content script which are loaded after the breakpoint is set.

+ +

For example, suppose you have an add-on that attaches a content script to every tab the user loads. The content script adds a click handler to the page. As soon as you open a tab, this content script will be listed in the debugger. If you then set a breakpoint in the content script's click handler, then execution will pause whenever you click the page. But if you open a new tab, there are now two instances of the content script, and the breakpoint will not be enabled for the second instance You'll need to set a new breakpoint now if you want to it work for the second instance.

+ +

We're investigating improvements to this in bug 1016046.

+ +

主控台

+ +

The Console behaves just like the Web Console, but its scope is the add-on rather than the web page.

+ +

However, note that it actually runs in the context of the add-on's bootstrap.js, which may not be what you expect if your add-on uses the SDK: you won't see any objects defined in your add-on's main.js, and you won't see require() either. This issue is being tracked as bug 1005193.

+ +

You can execute Console statements in the context of main.js while execution is paused inside main.js.

+ +

程式碼速記本

+ +

The Scratchpad behaves just like the normal Scratchpad, but its scope is the add-on rather than the web page.

+ +

Like the Console, the add-on Scratchpad runs in the context of the add-on's bootstrap.js even if the add-on uses the SDK, and as with the Console you can execute Scratchpad code in the context of main.js while execution is paused inside main.js.

+ +

為 chrome: 或 about: 頁面除錯

+ +

從 Firefox 37 起,一般的除錯工具已經可以用來為 chrome: 及 about: 兩類頁面除錯,使用方法同一般網頁除錯。

diff --git a/files/zh-tw/mozilla/add-ons/add-on_guidelines/index.html b/files/zh-tw/mozilla/add-ons/add-on_guidelines/index.html new file mode 100644 index 0000000000..fe05866a87 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/add-on_guidelines/index.html @@ -0,0 +1,117 @@ +--- +title: Add-on guidelines +slug: Mozilla/Add-ons/Add-on_guidelines +translation_of: 'https://extensionworkshop.com/documentation/publish/add-on-policies/' +--- +

These add-on guidelines were created to foster an open and diverse add-on developer community while ensuring an excellent user experience. They apply to all add-ons and add-on updates regardless of where they are hosted, and also apply to customizations performed by installers that configure Firefox without using an add-on. Add-ons hosted on AMO are subject to additional policies.

+

Be Transparent

+ +

Be Respectful to Users

+ +

Be Safe

+ +

Be Stable

+ +

Exceptions

+ +

Other exceptions may apply.

+

Enforcement

+

Add-ons that do not follow these guidelines may qualify for blocklisting, depending on the extent of the violations. Guidelines qualified with the word + + must + are especially important, and violations thereof will most likely result in a blocklisting nomination.

+

The Add-ons Team will do their best to contact the add-on's developers and provide a reasonable time frame for the problems to be corrected before a block is put in place. If an add-on is considered malicious or its developers have proven unreachable or unresponsive, or in case of repeat violations, blocklisting may be immediate.

+

Guideline violations should be reported via Bugzilla, under Tech Evangelism > Add-ons. Questions can be posted in the #addons IRC channel.

+

These guidelines may change in the future. All updates will be announced in the Add-ons Blog.

diff --git a/files/zh-tw/mozilla/add-ons/amo/index.html b/files/zh-tw/mozilla/add-ons/amo/index.html new file mode 100644 index 0000000000..3857ed65ca --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/amo/index.html @@ -0,0 +1,9 @@ +--- +title: AMO +slug: Mozilla/Add-ons/AMO +tags: + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Add-ons/AMO +--- +

Content to be added.

diff --git a/files/zh-tw/mozilla/add-ons/amo/policy/index.html b/files/zh-tw/mozilla/add-ons/amo/policy/index.html new file mode 100644 index 0000000000..8ac1738387 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/amo/policy/index.html @@ -0,0 +1,21 @@ +--- +title: AMO 政策 +slug: Mozilla/Add-ons/AMO/Policy +tags: + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Add-ons/AMO/Policy +--- +

{{AddonSidebar}}

+ +

Mozilla 致力於確保套件的用戶與開發者,都有著良好的體驗。提交套件以前,請閱讀以下政策。

+ +
+
Developer Agreement
+
Effective January 5, 2016
Review Process
+
Add-ons extend the core capabilities of Firefox, allowing users to modify and personalize their Web experience. A healthy add-on ecosystem, built on trust, is vital for developers to be successful and users to feel safe making Firefox their own. For these reasons, Mozilla requires all add-ons to comply with the following set of policies on acceptable practices. The below is not intended to serve as legal advice, nor is it intended to serve as a comprehensive list of terms to include in your add-on’s privacy policy.
Featured Add-ons
+
How up-and-coming add-ons become featured and what's involved in the process.
聯絡我們 + +

如何就這些套件的政策,與我們取得聯繫

+ +
diff --git "a/files/zh-tw/mozilla/add-ons/amo/policy/\350\201\257\347\265\241\350\263\207\350\250\212/index.html" "b/files/zh-tw/mozilla/add-ons/amo/policy/\350\201\257\347\265\241\350\263\207\350\250\212/index.html" new file mode 100644 index 0000000000..7358e5f642 --- /dev/null +++ "b/files/zh-tw/mozilla/add-ons/amo/policy/\350\201\257\347\265\241\350\263\207\350\250\212/index.html" @@ -0,0 +1,24 @@ +--- +title: 附加元件聯絡資訊 +slug: Mozilla/Add-ons/AMO/Policy/聯絡資訊 +translation_of: Mozilla/Add-ons#Contact_us +--- +

誠摯的感謝您連絡 Mozilla 附加元件團隊,淺請先閱讀本頁說明以確保您的訊息被正確的遞送。

+ +

附加元件支援服務

+ +

若你需要特定附加元件的支援訊息,比如說 "我該如何使用這個附加元件?" 或 "它怎麼不能...?",請透過列於附加元建列表中的聯絡方式,聯絡該附加元件的開發者。

+ +

附加元件編輯者審閱

+ +

若你有任何關於某個附加元件的編輯者審閱(Editor's review)的疑問,或想回報政策違反,請 E-mail 至 amo-editors@mozilla.orgAlmost all add-on reports fall under this category. Please be sure to include a link to the add-on in question and a detailed description of your question or comment.

+ +

Add-on Security Vulnerabilities

+ +

If you have discovered a security vulnerability in an add-on, even if it is not hosted here, Mozilla is very interested in your discovery and will work with the add-on developer to correct the issue as soon as possible. Add-on security issues can be reported confidentially in Bugzilla or by emailing amo-admins@mozilla.org.

+ +

Website Functionality & Development

+ +

If you've found a problem with the site, we'd love to fix it. Please file a bug report in Bugzilla, including the location of the problem and how you encountered it.

+ +

How to get in touch with us regarding these policies or your add-on.

diff --git a/files/zh-tw/mozilla/add-ons/firefox_for_android/api/index.html b/files/zh-tw/mozilla/add-ons/firefox_for_android/api/index.html new file mode 100644 index 0000000000..a8e6ebf9e0 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/firefox_for_android/api/index.html @@ -0,0 +1,30 @@ +--- +title: API +slug: Mozilla/Add-ons/Firefox_for_Android/API +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive/Add-ons/Legacy_Firefox_for_Android/API +--- +

There are a couple of differences between desktop Firefox and Firefox for Android that are particularly relevant to add-on developers:

+ + + +

Instead, Firefox for Android provides its own APIs:

+ + + +

In these pages we've documented the main functions and properties exposed by these objects. To see all the details, refer to the code at browser.js.

diff --git a/files/zh-tw/mozilla/add-ons/firefox_for_android/index.html b/files/zh-tw/mozilla/add-ons/firefox_for_android/index.html new file mode 100644 index 0000000000..8ade48ff37 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/firefox_for_android/index.html @@ -0,0 +1,70 @@ +--- +title: Extensions for Firefox for Android +slug: Mozilla/Add-ons/Firefox_for_Android +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive/Add-ons/Legacy_Firefox_for_Android +--- +

Firefox for Android supports add-ons using the same extension system used by all other Gecko-based applications. You can use the Add-on SDK or build manually bootstrapped restartless add-ons. You can even develop traditional restart-required add-ons, although the other two approaches are preferable.

+ +

Add-ons that work with desktop Firefox do not automatically work in Firefox for Android:

+ + + +

The following articles provide help with developing extensions for Firefox on Android. In addition, please refer to the general extension documentation that applies to all Mozilla applications.

+ +
+
+

Tutorials

+ +
+
Walkthrough
+
Developing, packaging and installing a simple add-on for Firefox for Android.
+
Firefox Hub Walkthrough
+
How to develop a Firefox Hub add-on to add content to the Firefox for Android home page.
+
Add-on SDK
+
How to develop Firefox for Android add-ons using the Add-on SDK.
+
+ +

Sample code

+ +
+
Code Snippets
+
Code samples for common tasks.
+
Initialization and Cleanup
+
How to initialize your add-on when it is started and clean up when it is shut down.
+
Firefox for Android Add-ons Github Repo
+
A collection of JS modules, sample code, and boilerplate repos to help you build add-ons for Firefox for Android.
+
+
+ +
+

API reference

+ +
+
NativeWindow
+
Create native Android UI widgets.
+
BrowserApp
+
Access browser tabs and the web content they host.
+
Prompt.jsm
+
Show native Android dialogs.
+
HelperApps.jsm
+
Query and launch native apps installed on the system.
+
Notifications.jsm
+
Use extended properties for Android system notifications.
+
Home.jsm
+
Customize the home page.
+
HomeProvider.jsm
+
Store data to display on the home page.
+
 
+
+
+
+ +

 

diff --git a/files/zh-tw/mozilla/add-ons/index.html b/files/zh-tw/mozilla/add-ons/index.html new file mode 100644 index 0000000000..6d2945ed44 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/index.html @@ -0,0 +1,89 @@ +--- +title: 附加元件 +slug: Mozilla/Add-ons +translation_of: Mozilla/Add-ons +--- +
{{AddonSidebar}}
+ +

附加元件允許開發者擴充並訂製 Firefox 的功能。它們使用標準的 Web 技術--JavaScript、HTML、CSS、還有一些專門的 JavaScript API--寫成。另外,附加元件還能:

+ + + +

開發附加元件

+ +

目前有許多開發 Firefox 附加元件的工具,但 WebExtensions 會在 2017 年末成為標準。其他的工具如傳統附加元件、免重啟附加元件、附加元件 SDK 等,屆時皆預期棄用。

+ +

深入理解 WebExtensions

+ +

如果要寫新的附加元件,推薦使用 WebExtension 撰寫。

+ +

WebExtensions 是被設計為跨瀏覽器通用的:為 Firefox 撰寫的 WebExtensions 通常只要在一點點的改變下,就能在 Chrome、Edge、Opera 運行。它們也能與多行程 Firefox 完全相容。

+ +

請參見目前在 Firefox 和其他瀏覽器所支援的 API。我們正持續設計與導入新的 API,以回應開發者所需。

+ +

多數 WebExtensions API 也能在 Firefox for Android 運行。

+ +

與現有附加元件合併

+ +

如果你正在維護過時的附加元件如 XUL overlay、bootstrapped、附加元件 SDK 等,我們建議把它移植到 WebExtension。MDN 有一些移植指引

+ +

我們在 wiki page 上收集了一些資源以助開發者完成移植。要開始的話,請使用 Lookup Tool 來檢查你的附加元件有無受影響。

+ +

發佈附加元件

+ +

Addons.mozilla.org,也俗稱「AMO」,是 Mozilla 給開發者們陳列附加元件的官方網站,用戶們也可以在那邊找到所需。當你把附加元件上傳到 AMO 時,你可以參與我們的用戶和創作者社區、並找到你附加元件的擁躉們。

+ +

你不用把附加元件上傳到 AMO,但你的附加元件需要給 Mozilla 簽署。否則,用戶將無法安裝。

+ +

要找到發佈附加元件的過程概觀,請參見簽署並發布你的附加元件

+ +

其他種類的附加元件

+ +

通常,當大家在講「附加元件」時候,他們是指套件(extension)。但也有其他類型的附加元件,允許用戶訂製 Firefox。包含:

+ + + +
+

聯絡我們

+ +

你可以透過以下連結取得協助、獲取附加元件的新聞、還有得到回饋。

+ +

附加元件論壇

+ +

使用附加元件討論論壇討論附加元件方面的開發並取得協助。

+ +

電郵群組

+ +

請使用 dev-addons 群組討論附加元件開發生態圈,包含 WebExtension 系統開發與 AMO:

+ + + +

請使用 webextensions-support list 以取得移植到 WebExtension 的協助:

+ + + +

IRC

+ +

如果你喜歡用 IRC,你可以在這裡聯繫:

+ + diff --git a/files/zh-tw/mozilla/add-ons/sdk/builder/index.html b/files/zh-tw/mozilla/add-ons/sdk/builder/index.html new file mode 100644 index 0000000000..f7dc93a009 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/sdk/builder/index.html @@ -0,0 +1,13 @@ +--- +title: Builder +slug: Mozilla/Add-ons/SDK/Builder +translation_of: Archive/Add-ons/Add-on_SDK/Builder +--- +

Add-on Builder 是 Web-based 的開發環境,讓開發者能以 SDK API 來開發附加元件,而不必使用 cfx 命令列工具。Add-on Builder 已經於 2014 年 4 月 1 日下架,而原本的網址「builder.addons.mozilla.org」則轉至此頁。
+
+ 若您過去使用 Builder 來開發採用 SDK 的附加元件,便已獲得絕大部分以 SDK 直接開發的必備知識。Builder 中的 high-levellow-level API,就跟 SDK 裡的一模一樣。改用 SDK 很簡單:

+ diff --git a/files/zh-tw/mozilla/add-ons/sdk/guides/index.html b/files/zh-tw/mozilla/add-ons/sdk/guides/index.html new file mode 100644 index 0000000000..f4e37d9e10 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/sdk/guides/index.html @@ -0,0 +1,115 @@ +--- +title: Guides +slug: Mozilla/Add-ons/SDK/Guides +translation_of: Archive/Add-ons/Add-on_SDK/Guides +--- +

This page lists more theoretical in-depth articles about the SDK.

+
+

Contributor's guide

+
+
+
+
+ Getting Started
+
+ Learn how to contribute to the SDK: getting the code, opening/taking a bug, filing a patch, getting reviews, and getting help.
+
+ Modules
+
+ Learn about the module system used by the SDK (which is based on the CommonJS specification), how sandboxes and compartments can be used to improve security, and about the built-in SDK module loader, known as Cuddlefish.
+
+ Classes and Inheritance
+
+ Learn how classes and inheritance can be implemented in JavaScript, using constructors and prototypes, and about the helper functions provided by the SDK to simplify this.
+
+
+
+
+
+ Private Properties
+
+ Learn how private properties can be implemented in JavaScript using prefixes, closures, and WeakMaps, and how the SDK supports private properties by using namespaces (which are a generalization of WeakMaps).
+
+ Content Processes
+
+ The SDK was designed to work in an environment where the code to manipulate web content runs in a different process from the main add-on code. This article highlights the main features of that design.
+
+
+
+
+

SDK infrastructure

+
+
+
+
+ Module structure of the SDK
+
+ The SDK, and add-ons built using it, are of composed from reusable JavaScript modules. This explains what these modules are, how to load modules, and how the SDK's module tree is structured.
+
+ SDK API lifecycle
+
+ Definition of the lifecycle for the SDK's APIs, including the stability ratings for APIs.
+
+
+
+
+
+ Program ID
+
+ The Program ID is a unique identifier for your add-on. This guide explains how it's created, what it's used for and how to define your own.
+
+ Firefox compatibility
+
+ Working out which Firefox releases a given SDK release is compatible with, and dealing with compatibility problems.
+
+
+
+
+

SDK idioms

+
+
+
+
+ Working With Events
+
+ Write event-driven code using the the SDK's event emitting framework.
+
+ Content scripts guide
+
+ An overview of content scripts, including: what they are, what they can do, how to load them, how to communicate with them.
+
+
+
+
+
+ Two Types of Scripts
+
+ This article explains the differences between the APIs available to your main add-on code and those available to content scripts.
+
+
+
+
+

XUL migration

+
+
+
+
+ XUL Migration Guide
+
+ Techniques to help port a XUL add-on to the SDK.
+
+ XUL versus the SDK
+
+ A comparison of the strengths and weaknesses of the SDK, compared to traditional XUL-based add-ons.
+
+
+
+
+
+ Porting Example
+
+ A walkthrough of porting a relatively simple XUL-based add-on to the SDK.
+
+
+
+

 

diff --git a/files/zh-tw/mozilla/add-ons/sdk/high-level_apis/context-menu/index.html b/files/zh-tw/mozilla/add-ons/sdk/high-level_apis/context-menu/index.html new file mode 100644 index 0000000000..42c5e0ca85 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/sdk/high-level_apis/context-menu/index.html @@ -0,0 +1,588 @@ +--- +title: context-menu +slug: Mozilla/Add-ons/SDK/High-Level_APIs/context-menu +translation_of: Archive/Add-ons/Add-on_SDK/High-Level_APIs/context-menu +--- +
+

Stable

+
+

加入選單項目、子選單、選單分隔線到頁面右鍵選單。

+

用法

+

Instead of manually adding items when particular contexts occur and then removing them when those contexts go away, you bind items to contexts, and the adding and removing is automatically handled for you. Items are bound to contexts in much the same way that event listeners are bound to events. When the user invokes the context menu, all of the items bound to the current context are automatically added to the menu. If no items are bound, none are added. Likewise, any items that were previously in the menu but are not bound to the current context are automatically removed from the menu. You never need to manually remove your items from the menu unless you want them to never appear again.

+

For example, if your add-on needs to add a context menu item whenever the user visits a certain page, don't create the item when that page loads, and don't remove it when the page unloads. Rather, create your item only once and supply a context that matches the target URL.

+

Context menu items are displayed in the order created or in the case of sub menus the order added to the sub menu. Menu items for each add-on will be grouped together automatically. If the total number of menu items in the main context menu from all add-ons exceeds a certain number (normally 10 but configurable with the extensions.addon-sdk.context-menu.overflowThreshold preference) all of the menu items will instead appear in an overflow menu to avoid making the context menu too large.

+

Specifying Contexts

+

As its name implies, the context menu should be reserved for the occurrence of specific contexts. Contexts can be related to page content or the page itself, but they should never be external to the page.

+

For example, a good use of the menu would be to show an "Edit Image" item when the user right-clicks an image in the page. A bad use would be to show a submenu that listed all the user's tabs, since tabs aren't related to the page or the node the user clicked to open the menu.

+

The Page Context

+

First of all, you may not need to specify a context at all. When a top-level item does not specify a context, the page context applies. An item that is in a submenu is visible unless you specify a context.

+

The page context occurs when the user invokes the context menu on a non-interactive portion of the page. Try right-clicking a blank spot in this page, or on text. Make sure that no text is selected. The menu that appears should contain the items "Back", "Forward", "Reload", "Stop", and so on. This is the page context.

+

The page context is appropriate when your item acts on the page as a whole. It does not occur when the user invokes the context menu on a link, image, or other non-text node, or while a selection exists.

+

宣告式場景條件(Declarative Contexts)

+

當你藉由設定 context 屬性(該屬性為: 傳給 constructor 的選項物件之屬性)來新增選單項目時,你可以指定一些簡單的宣告式場景條件, 如下:

+
var cm = require("sdk/context-menu");
+cm.Item({
+  label: "My Menu Item",
+  context: cm.URLContext("*.mozilla.org")
+});
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Constructor選單項目出現的條件
PageContext() 當場景為網頁時.
SelectionContext() 當使用者在網頁上選取項目時.
SelectorContext(selector) 當選單在符合下述條件之一的節點上顯示: selector匹配, CSS 選擇器, 或 其祖先節點匹配選擇器. selector可以有多個(以逗點分隔), 例如, "a[href], img".
URLContext(matchPattern) 特定網址的網頁. matchPattern is a match pattern string or an array of match pattern strings. 當 matchPattern 是陣列, 網址符合任何陣列元素之一時. These are the same match pattern strings that you use with the page-mod include property. Read more about patterns.
PredicateContext(predicateFunction)當選單被觸發時,predicateFunction 函數被呼叫,若函數傳回值為真值,則選單項目顯示。這函數傳入一物件,物件有著描述選單觸發場景條件的屬性.
arrayAn array of any of the other types. This context occurs when all contexts in the array occur.
+

選單項目也有 context 屬性,可以用在新增或移除宣告式場景條件,當建構後. 例如:

+
var context = require("sdk/context-menu").SelectorContext("img");
+myMenuItem.context.add(context);
+myMenuItem.context.remove(context);
+

當選單項目被指定了多個場景條件, 選單項目顯示於所有場景條件皆成立時.

+

In Content Scripts

+

宣告式場景條件很容易使用,但功能不強. 舉例來說, 你希望選單項目出現的條件為:「有著至少一張圖片的頁面」, 但宣告式場景條件並不能達成這一點.

+

當你需要對選單項目的出現時機有著更多的控制, 你可以使用 content scripts. 如同 SDK 的其他 APIs 一樣, context-menu API 使用 content scripts 以讓你的附加元件與瀏覽器中的頁面互動. 在最上層選單的每一個選單項目可以使用 content script.

+

每當選單即將顯示時,一個特殊事件,其名為 "context" ,觸發於你的 content scripts. 如果你為這個事件註冊了偵聽(listener)函數,當函數傳回真值時, 與偵聽函數關聯的選單項目會被顯示於選單中.

+

下例中, 當選單觸發於「有著至少一張圖片的頁面」時,顯示選單項目.

+
require("sdk/context-menu").Item({
+  label: "This Page Has Images",
+  contentScript: 'self.on("context", function (node) {' +
+                 '  return !!document.querySelector("img");' +
+                 '});'
+});
+

需要注意的是偵聽函數有一個參數叫 node. 這個 node 指的是使用者在頁面上按右鍵來觸發選單的頁面觸發節點. 你可以使用它來決定是否要顯示選單項目.

+

你可以在 content script 中,同時指定宣告式場景條件和 context 偵聽函數. 在這種情況下, 先評估宣告式場景條件, 然後你的選單項目顯示條件為:所有宣告式場景條件成立,並且你的 context 偵聽函數傳回真值.

+

如果任一宣告式場景條件未成立, 那麼你的 context 偵聽函數不會被呼叫. 下面的例子利用了這點. 確保了偵聽函數只在 image node 上觸發選單時,才會被呼叫:

+
var cm = require("sdk/context-menu");
+cm.Item({
+  label: "A Mozilla Image",
+  context: cm.SelectorContext("img"),
+  contentScript: 'self.on("context", function (node) {' +
+                 '  return /mozilla/.test(node.src);' +
+                 '});'
+});
+

However, if you do combine SelectorContext and the "context" event, be aware that the node argument passed to the "context" event will not always match the type specified in SelectorContext.

+

SelectorContext will match if the menu is invoked on the node specified or any descendant of that node, but the "context" event handler is passed the actual node on which the menu was invoked. 上個例子有作用,是因為 <IMG> 元素內不能包含其他元素, 但底下的例子裡, node.nodeName 不能保證是 "P" - 例如說, 當使用者在一個段落(<P>)的連結(<A>)上點右鍵時,它不會是 "P" :

+
var cm = require("sdk/context-menu");
+cm.Item({
+  label: "A Paragraph",
+  context: cm.SelectorContext("p"),
+  contentScript: 'self.on("context", function (node) {' +
+                 '  console.log(node.nodeName);' +
+                 '  return true;' +
+                 '});'
+});
+

The content script is executed for every page that a context menu is shown for. It will be executed the first time it is needed (i.e. 當右鍵選單第一次顯示,並且選單項目的所有宣告式場景條件皆成立時) ,接著處於作用中,直到你銷毀你的選單項目或者關閉頁面.

+

處理選單項目上的點擊

+

content script 除了上述所說的功能(用來偵聽 "context" 事件)以外,你可以使用 content script 來處理選單項目上的點擊. 當使用者點擊選單項目時,一個名為 "click" 的事件在選單項目的 content script 內被觸發.

+

因此, 欲處理選單項目上的點擊, 可以藉由偵聽選單項目 content script 內的 "click" 事件, 如下:

+
require("sdk/context-menu").Item({
+  label: "My Item",
+  contentScript: 'self.on("click", function (node, data) {' +
+                 '  console.log("Item clicked!");' +
+                 '});'
+});
+

注意:偵聽函數有兩參數 nodedata.

+

"node" 參數

+

node 是使用者右鍵點擊所觸發選單的節點.

+ +

例如, 假設你的附加元件看起來像這樣:

+
var script = "self.on('click', function (node, data) {" +
+             "  console.log('clicked: ' + node.nodeName);" +
+             "});";
+
+var cm = require("sdk/context-menu");
+
+cm.Item({
+  label: "body context",
+  context: cm.SelectorContext("body"),
+  contentScript: script
+});
+

這個附加元件建立了一個右鍵選單項目,該項目使用 SelectorContext 來顯示項目,顯示時機為:右鍵選單觸發於 <BODY> 元素的任何後代元素之上時. 點擊時, 項目記錄了 nodeName 屬性(觸發選單的節點名稱)傳給點擊事件處理器.

+

如果你執行這個附加元件,你將看到它總是記錄 "BODY", 即使你點擊的是頁面上的段落元素<P>:

+
info: contextmenu-example: clicked: BODY
+

與上面對比, 底下的附加元件使用了 PageContext:

+
var script = "self.on('click', function (node, data) {" +
+             "  console.log('clicked: ' + node.nodeName);" +
+             "});";
+
+var cm = require("sdk/context-menu");
+
+cm.Item({
+  label: "body context",
+  context: cm.PageContext(),
+  contentScript: script
+});
+

它將記錄實際點擊的節點名稱:

+
info: contextmenu-example: clicked: P
+

"data" 參數

+

data 是使用者所點擊選單項目的 data屬性. 注意: 當你有一個多層的選單(項目)時,點擊事件會被傳給被點擊的項目的所有祖先(項目),所以一定要驗證 data 值傳給你所期待的項目. 你可以使用 "data" 參數來簡化點擊事件處理 by providing just a single click listener on a Menu that reacts to clicks for any child items.:

+
var cm = require("sdk/context-menu");
+cm.Menu({
+  label: "My Menu",
+  contentScript: 'self.on("click", function (node, data) {' +
+                 '  console.log("You clicked " + data);' +
+                 '});',
+  items: [
+    cm.Item({ label: "Item 1", data: "item1" }),
+    cm.Item({ label: "Item 2", data: "item2" }),
+    cm.Item({ label: "Item 3", data: "item3" })
+  ]
+});
+
+

和附加元件通訊

+

時常,你需要收集一些訊息,在點擊偵聽函數內和執行一個無關於頁面動作. 為了與關聯於 content script 的選單項目通訊, content script 可以呼叫附屬於全域 self 物件的 postMessage 函數, 傳給它一些 JSON-able 資料. 選單項目的 "message" 事件偵聽函數將被呼叫(前述的 JSON-able 資料作為參數傳入).

+
var cm = require("sdk/context-menu");
+cm.Item({
+  label: "Edit Image",
+  context: cm.SelectorContext("img"),
+  contentScript: 'self.on("click", function (node, data) {' +
+                 '  self.postMessage(node.src);' +
+                 '});',
+  onMessage: function (imgSrc) {
+    openImageEditor(imgSrc);
+  }
+});
+

更新選單項目的文字標籤

+

Each menu item must be created with a label, but you can change its label later using a couple of methods.

+

最簡單的方法是設定選單項目的 label 屬性. 下面的例子更新選單項目的文字標籤為它被點擊的次數:

+
var numClicks = 0;
+var myItem = require("sdk/context-menu").Item({
+  label: "Click Me: " + numClicks,
+  contentScript: 'self.on("click", self.postMessage);',
+  onMessage: function () {
+    numClicks++;
+    this.label = "Click Me: " + numClicks;
+    // Setting myItem.label is equivalent.
+  }
+});
+

Sometimes you might want to update the label based on the context. For instance, if your item performs a search with the user's selected text, it would be nice to display the text in the item to provide feedback to the user. 在這些情況下,你可以使用第二種方法 . 回想一下,你的 content scripts 可以偵聽 "context" 事件,如果你的偵聽函數傳回真值, 與 content scripts 關聯的選單項目會顯示在選單中. 除了傳回真值, 你的 "context" 偵聽函數也可以傳回字串. 當 "context" 偵聽函數傳回字串, 字串成為選單項目的新文字標籤.

+

This item implements the aforementioned search example:

+
var cm = require("sdk/context-menu");
+cm.Item({
+  label: "Search Google",
+  context: cm.SelectionContext(),
+  contentScript: 'self.on("context", function () {' +
+                 '  var text = window.getSelection().toString();' +
+                 '  if (text.length > 20)' +             // 若太長
+                 '    text = text.substr(0, 20) + "...";' + // 則截短
+                 '  return "Search Google for " + text;' +  // 後綴到固定字串上傳回
+                 '});'
+});
+

"context" 偵聽函數取得使用者所選取的文字, 如果字串太長則截短它, 並後綴到固定字串上傳回. 當選單項目顯示, 它的文字標籤將是 "Search Google for text", 此處的 text 是被截短的 使用者所選取的文字.

+

隱私視窗

+

If your add-on has not opted into private browsing, then any menus or menu items that you add will not appear in context menus belonging to private browser windows.

+

To learn more about private windows, how to opt into private browsing, and how to support private browsing, refer to the documentation for the private-browsing module.

+

更多例子

+

For conciseness, these examples create their content scripts as strings and use the contentScript property. In your own add-on, you will probably want to create your content scripts in separate files and pass their URLs using the contentScriptFile property. See Working with Content Scripts for more information.

+
+

Unless your content script is extremely simple and consists only of a static string, don't use contentScript: if you do, you may have problems getting your add-on approved on AMO.

+

Instead, keep the script in a separate file and load it using contentScriptFile. This makes your code easier to maintain, secure, debug and review.

+
+

Show an "Edit Page Source" item when the user right-clicks a non-interactive part of the page:

+
require("sdk/context-menu").Item({
+  label: "Edit Page Source",
+  contentScript: 'self.on("click", function (node, data) {' +
+                 '  self.postMessage(document.URL);' +
+                 '});',
+  onMessage: function (pageURL) {
+    editSource(pageURL);
+  }
+});
+

Show an "Edit Image" item when the menu is invoked on an image:

+
var cm = require("sdk/context-menu");
+cm.Item({
+  label: "Edit Image",
+  context: cm.SelectorContext("img"),
+  contentScript: 'self.on("click", function (node, data) {' +
+                 '  self.postMessage(node.src);' +
+                 '});',
+  onMessage: function (imgSrc) {
+    openImageEditor(imgSrc);
+  }
+});
+

Show an "Edit Mozilla Image" item when the menu is invoked on an image in a mozilla.org or mozilla.com page:

+
var cm = require("sdk/context-menu");
+cm.Item({
+  label: "Edit Mozilla Image",
+  context: [
+    cm.URLContext(["*.mozilla.org", "*.mozilla.com"]),
+    cm.SelectorContext("img")
+  ],
+  contentScript: 'self.on("click", function (node, data) {' +
+                 '  self.postMessage(node.src);' +
+                 '});',
+  onMessage: function (imgSrc) {
+    openImageEditor(imgSrc);
+  }
+});
+

Show an "Edit Page Images" item when the page contains at least one image:

+
var cm = require("sdk/context-menu");
+cm.Item({
+  label: "Edit Page Images",
+  // This ensures the item only appears during the page context.
+  context: cm.PageContext(),
+  contentScript: 'self.on("context", function (node) {' +
+                 '  var pageHasImgs = !!document.querySelector("img");' +
+                 '  return pageHasImgs;' +
+                 '});' +
+                 'self.on("click", function (node, data) {' +
+                 '  var imgs = document.querySelectorAll("img");' +
+                 '  var imgSrcs = [];' +
+                 '  for (var i = 0 ; i < imgs.length; i++)' +
+                 '    imgSrcs.push(imgs[i].src);' +
+                 '  self.postMessage(imgSrcs);' +
+                 '});',
+  onMessage: function (imgSrcs) {
+    openImageEditor(imgSrcs);
+  }
+});
+

Show a "Search With" menu when the user right-clicks an anchor that searches Google or Wikipedia with the text contained in the anchor:

+
var cm = require("sdk/context-menu");
+var googleItem = cm.Item({
+  label: "Google",
+  data: "http://www.google.com/search?q="
+});
+var wikipediaItem = cm.Item({
+  label: "Wikipedia",
+  data: "http://en.wikipedia.org/wiki/Special:Search?search="
+});
+var searchMenu = cm.Menu({
+  label: "Search With",
+  context: cm.SelectorContext("a[href]"),
+  contentScript: 'self.on("click", function (node, data) {' +
+                 '  var searchURL = data + node.textContent;' +
+                 '  window.location.href = searchURL;' +
+                 '});',
+  items: [googleItem, wikipediaItem]
+});
+

Globals

+

Constructors

+

Item(options)

+

建立一個有文字標籤的選單項目,當點擊它時,可以執行一些動作.

+
參數
+

options : 物件
+ options 物件的必要屬性:

+ + + + + + + + + + + + + + + +
名稱型別 
label字串 +

選單項目的文字標籤. It must either be a string or an object that implements toString().

+
+

options 物件的可選屬性:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
名稱型別 
image字串 +

選單項目的圖示, a string URL. The URL can be remote, a reference to an image in the add-on's data directory, or a data URI.

+
data字串 +

An optional arbitrary value to associate with the item. It must be either a string or an object that implements toString(). It will be passed to click listeners.

+
accessKey只有單一字元的字串 +
+

New in Firefox 35.

+
+

選單項目的快捷鍵. Pressing this key selects the item when the context menu is open.

+
contextvalue +

If the item is contained in the top-level context menu, this declaratively specifies the context under which the item will appear; see Specifying Contexts above.

+
contentScript字串, 陣列 +

If the item is contained in the top-level context menu, this is the content script or an array of content scripts that the item can use to interact with the page.

+
contentScriptFile字串, 陣列 +

If the item is contained in the top-level context menu, this is the local file URL of the content script or an array of such URLs that the item can use to interact with the page.

+
onMessage函數 +

If the item is contained in the top-level context menu, this function will be called when the content script calls self.postMessage. It will be passed the data that was passed to postMessage.

+
+ +

建立一個有文字標籤的選單項目,用以展開子選單.

+
參數
+

options : 物件
+ options 物件的必要屬性:

+ + + + + + + + + + + + + + + + + + + + +
名稱型別 
label字串 +

選單項目的文字標籤. It must either be a string or an object that implements toString().

+
items陣列 +

選單項目構成的陣列,這些選單項目會被子選單所包含. 陣列中的元素須為 Item, Menu, 或 Separator.

+
+

options 物件的可選屬性:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
名稱型別 
image字串 +

The menu's icon, a string URL. The URL can be remote, a reference to an image in the add-on's data directory, or a data URI.

+
contextvalue +

If the menu is contained in the top-level context menu, this declaratively specifies the context under which the menu will appear; see Specifying Contexts above.

+
contentScript字串, 陣列 +

If the menu is contained in the top-level context menu, this is the content script or an array of content scripts that the menu can use to interact with the page.

+
contentScriptFile字串, 陣列 +

If the menu is contained in the top-level context menu, this is the local file URL of the content script or an array of such URLs that the menu can use to interact with the page.

+
onMessage函數 +

If the menu is contained in the top-level context menu, this function will be called when the content script calls self.postMessage. It will be passed the data that was passed to postMessage.

+
+

Separator()

+

Creates a menu separator.

+

PageContext()

+

Creates a page context. See Specifying Contexts above.

+

SelectionContext()

+

Creates a context that occurs when a page contains a selection. See Specifying Contexts above.

+

SelectorContext(selector)

+

Creates a context that matches a given CSS selector. See Specifying Contexts above.

+
Parameters
+

selector : string
+ A CSS selector.

+

URLContext(matchPattern)

+

Creates a context that matches pages with particular URLs. See Specifying Contexts above.

+
Parameters
+

matchPattern : string,array
+ A match pattern string, regexp or an array of match pattern strings or regexps.

+

PredicateContext(predicateFunction)

+
+

New in Firefox 29

+
+

Creates a context that occurs when predicateFunction returns a true value. See Specifying Contexts above.

+
Parameters
+

predicateFunction : function(context)
+ A function which will be called with an object argument that provide information about the invocation context. context object properties:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyDescription
documentTypeThe MIME type of the document the menu was invoked in. E.g. text/html for HTML pages, application/xhtml+xml for XHTML, or image/jpeg if viewing an image directly.
documentURLThe URL of the document the menu was invoked in.
targetNameThe name of the DOM element that the menu was invoked on, in lower-case.
targetIDThe id attribute of the element that the menu was invoked on, or null if not set.
isEditabletrue if the menu was invoked in an editable element, and that element isn't disabled or read-only.  This includes non-input elements with the contenteditable attribute set to true.
selectionTextThe current selection as a text string, or null. If the menu was invoked in an input text box or area, this is the selection of that element, otherwise the selection in the contents of the window.
srcURLThe src URL of the element that the menu was invoked on, or null if it doesn't have one.
linkURLThe href URL of the element that the menu was invoked on, or null if it doesn't have one.
valueThe current contents of a input text box or area if the menu was invoked in one, null otherwise.
+

Item

+

A labeled menu item that can perform an action when clicked.

+

Methods

+

destroy()

+

Permanently removes the item from its parent menu and frees its resources. The item must not be used afterward. If you need to remove the item from its parent menu but use it afterward, call removeItem() on the parent menu instead.

+

Properties

+

label

+

The menu item's label. You can set this after creating the item to update its label later.

+

image

+

The item's icon, a string URL. The URL can be remote, a reference to an image in the add-on's data directory, or a data URI. You can set this after creating the item to update its image later. To remove the item's image, set it to null.

+

data

+

An optional arbitrary value to associate with the item. It must be either a string or an object that implements toString(). It will be passed to click listeners. You can set this after creating the item to update its data later.

+

context

+

A list of declarative contexts for which the menu item will appear in the context menu. Contexts can be added by calling context.add() and removed by called context.remove().

+

parentMenu

+

The item's parent Menu, or null if the item is contained in the top-level context menu. This property is read-only. To add the item to a new menu, call that menu's addItem() method.

+

contentScript

+

The content script or the array of content scripts associated with the menu item during creation.

+

contentScriptFile

+

The URL of a content script or the array of such URLs associated with the menu item during creation.

+

Events

+

message

+

If you listen to this event you can receive message events from content scripts associated with this menu item. When a content script posts a message using self.postMessage(), the message is delivered to the add-on code in the menu item's message event.

+
Arguments
+

value : Listeners are passed a single argument which is the message posted from the content script. The message can be any JSON-serializable value.

+ +

A labeled menu item that expands into a submenu.

+

Methods

+

addItem(item)

+

Appends a menu item to the end of the menu. If the item is already contained in another menu or in the top-level context menu, it's automatically removed first. If the item is already contained in this menu it will just be moved to the end of the menu.

+
Parameters
+

item : Item,Menu,Separator
+ The Item, Menu, or Separator to add to the menu.

+

removeItem(item)

+

Removes the given menu item from the menu. If the menu does not contain the item, this method does nothing.

+
Parameters
+

item : Item,Menu,Separator
+ The menu item to remove from the menu.

+

destroy()

+

Permanently removes the menu from its parent menu and frees its resources. The menu must not be used afterward. If you need to remove the menu from its parent menu but use it afterward, call removeItem() on the parent menu instead.

+

Properties

+

label

+

The menu's label. You can set this after creating the menu to update its label later.

+

items

+

An array containing the items in the menu. The array is read-only, meaning that modifications to it will not affect the menu. However, setting this property to a new array will replace all the items currently in the menu with the items in the new array.

+

image

+

The menu's icon, a string URL. The URL can be remote, a reference to an image in the add-on's data directory, or a data URI. You can set this after creating the menu to update its image later. To remove the menu's image, set it to null.

+

context

+

A list of declarative contexts for which the menu will appear in the context menu. Contexts can be added by calling context.add() and removed by called context.remove().

+

parentMenu

+

The menu's parent Menu, or null if the menu is contained in the top-level context menu. This property is read-only. To add the menu to a new menu, call that menu's addItem() method.

+

contentScript

+

The content script or the array of content scripts associated with the menu during creation.

+

contentScriptFile

+

The URL of a content script or the array of such URLs associated with the menu during creation.

+

Events

+

message

+

If you listen to this event you can receive message events from content scripts associated with this menu item. When a content script posts a message using self.postMessage(), the message is delivered to the add-on code in the menu item's message event.

+
Arguments
+

value : Listeners are passed a single argument which is the message posted from the content script. The message can be any JSON-serializable value.

+

Separator

+

A menu separator. Separators can be contained only in Menus, not in the top-level context menu.

+

Methods

+

destroy()

+

Permanently removes the separator from its parent menu and frees its resources. The separator must not be used afterward. If you need to remove the separator from its parent menu but use it afterward, call removeItem() on the parent menu instead.

+

Properties

+

parentMenu

+

The separator's parent Menu. This property is read-only. To add the separator to a new menu, call that menu's addItem() method.

diff --git a/files/zh-tw/mozilla/add-ons/sdk/high-level_apis/index.html b/files/zh-tw/mozilla/add-ons/sdk/high-level_apis/index.html new file mode 100644 index 0000000000..32b39d045b --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/sdk/high-level_apis/index.html @@ -0,0 +1,10 @@ +--- +title: High-Level APIs +slug: Mozilla/Add-ons/SDK/High-Level_APIs +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive/Add-ons/Add-on_SDK/High-Level_APIs +--- +

Modules listed on this page implement high-level APIs for building add-ons: creating user interfaces, interacting with the web, and interacting with the browser.

+

Unless the documentation explicitly says otherwise, all these modules are "Stable": we'll avoid making incompatible changes to them. {{ LandingPageListSubpages ("/en-US/Add-ons/SDK/High-Level_APIs", 5) }}

diff --git a/files/zh-tw/mozilla/add-ons/sdk/index.html b/files/zh-tw/mozilla/add-ons/sdk/index.html new file mode 100644 index 0000000000..2937b883d7 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/sdk/index.html @@ -0,0 +1,82 @@ +--- +title: Add-on SDK +slug: Mozilla/Add-ons/SDK +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive/Add-ons/Add-on_SDK +--- +

有了附加元件開發套件(Add-on SDK),您可以使用標準的JavaScript、HTML、CSS等語法來建立Firefox的附加元件。SDK包含用來製作附加元件的JavaScript API,及建立、測試、運行或包裝附加元件的相關工具。

+ +
+

入門

+ +
+
+
+
從此開始
+
如何安裝 SDK 使用 cfx tool 來建立、測試或包裝附加元件。
+
和瀏覽器互動
+
開啟網頁監測頁面載入以及列出已開啟頁面
+
開發技巧
+
學習常用開發技術,如單元測試紀錄建立可重用模組在地化流動裝置
+
+
+ +
+
+
建立使用者介面的元件
+
工具列按鈕內文選單選單項目對話框等等。
+
修改網頁
+
修改符合網址模式的頁面或動態修改特定分頁
+
整合各項
+
以 Annotator(一個顯示註解的附加元件)為例顯示製作流程。
+
+
+
+ +
+

指引

+ +
+ + + +
+ +
+

參考資料

+ +
+
+
+
高階 API
+
高階 SDK API 的參考文件。
+
工具參考
+
Reference documentation for the cfx tool used to develop, test, and package add-ons, the console global used for logging, and the package.json file.
+
+
+ +
+
+
低階 API
+
低階 SDK API 的參考文件。
+
+
+
diff --git a/files/zh-tw/mozilla/add-ons/sdk/low-level_apis/index.html b/files/zh-tw/mozilla/add-ons/sdk/low-level_apis/index.html new file mode 100644 index 0000000000..2108d30783 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/sdk/low-level_apis/index.html @@ -0,0 +1,20 @@ +--- +title: Low-Level APIs +slug: Mozilla/Add-ons/SDK/Low-Level_APIs +translation_of: Archive/Add-ons/Add-on_SDK/Low-Level_APIs +--- +

Modules in this section implement low-level APIs. These modules fall roughly into three categories:

+ +

These modules are still in active development, and we expect to make incompatible changes to them in future releases.

+

{{ LandingPageListSubpages ("/en-US/Add-ons/SDK/Low-Level_APIs", 5) }}

+

 

diff --git a/files/zh-tw/mozilla/add-ons/themes/obsolete/index.html b/files/zh-tw/mozilla/add-ons/themes/obsolete/index.html new file mode 100644 index 0000000000..d420b6ebf0 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/themes/obsolete/index.html @@ -0,0 +1,10 @@ +--- +title: Obsolete +slug: Mozilla/Add-ons/Themes/Obsolete +tags: + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Add-ons/Themes/Obsolete +--- +

This page collects theme docs that we don't expect will ever be updated, but which we're keeping for the time being as potential source material for updated docs.

+

{{ ListSubPages ("/en-US/Add-ons/Themes/Obsolete", 5) }}

diff --git a/files/zh-tw/mozilla/add-ons/webextensions/anatomy_of_a_webextension/index.html b/files/zh-tw/mozilla/add-ons/webextensions/anatomy_of_a_webextension/index.html new file mode 100644 index 0000000000..505642ac10 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/anatomy_of_a_webextension/index.html @@ -0,0 +1,139 @@ +--- +title: Anatomy of an extension +slug: Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension +translation_of: Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension +--- +
{{AddonSidebar}}
+ +

附加元件是一群檔案的集合,基於發布及安裝的目的而包裝成一個檔案。在這個章節,我們將快速地瀏覽這些可能會放在附加元件中的檔案。

+ +

manifest.json

+ +

這是每個附加元件中,唯一一個必要放置的檔案。它包含了附加元件的名稱、版本、及需要的權限等資訊,同時也提供了附加元件中其他檔案的路徑指標。

+ +

這份manifest也可以包含幾項其他種類檔案的指標路徑:

+ + + +

+ +

參考 manifest.json 參考頁取得全部的明細。

+ +

除了那些參考自manifest之外,附加元件可以包含額外支援的檔案作為 Extension pages

+ +

Background scripts 後台腳本

+ +

擴展套件通常需要保持長期狀態或長時間執行操作,而生命週期不依賴於任何特定網頁或瀏覽器視窗。這是後台腳本的用途。

+ +

後台腳本會在擴充套件讀取時立即執行且會持續執行直到擴充套件被禁用或是解除安裝。你可以在腳本裡使用任何WebExtension APIs, 只要你已經申請了必要的權限。

+ +

Specifying background scripts 載入後台腳本

+ +

你可以在"manifest.json"裡使用background關鍵字用來包含後台腳本。

+ +
// manifest.json
+
+"background": {
+  "scripts": ["background-script.js"]
+}
+ +

你可以同時載入後台腳本,而他們會運行於相同的環境中,就像是在一個網頁中同時載入一樣。

+ +

然而,你也可以先載入一個後台頁面,然後在後台頁面中載入腳本。這樣的做法能為後台腳本提供 ES 6 模組的支援,算是一个優點。

+ +

manifest.json

+ +
// manifest.json
+
+"background": {
+  "page": "background-page.html"
+}
+ +

background-page.html

+ +
<!DOCTYPE html>
+<html lang="zh-tw">
+  <head>
+    <meta charset="utf-8">
+    <script type="module" src="background-script.js"></script>
+  </head>
+</html>
+ +

Background script environment 後台腳本環境

+ +

DOM APIs

+ +

後台腳本運行在一個特殊的網頁中,我們稱之為後台頁面(background pages) 。這個頁面會給予他們一個全域的變數window,並且提供腳本使用所有的標準DOM API。

+ +

WebExtension APIs

+ +

只要你請求了必要的權限後,後台腳本可以使用任何的WebExtension APIs

+ +

Cross-origin access 跨域請求

+ +

當後台腳本擁有host permissions 時,便能像任何主機發送 XHR 請求。

+ +

Web content 網頁內容

+ +

後台腳本沒辦法直接的存取前端的網頁。然而,你可以載入 content scripts 到前端網頁後,透過message-passing API 來與 content scripts 進行通訊

+ +

Content security policy 內容安全策略

+ +

依據内容安全策略(Content Security Policy),後台腳本不能執行一些可能有危險的操作,例如使用 eval()。 詳情请参考内容安全策略

+ + + +

Your extension can include various user interface components whose content is defined using an HTML document:

+ + + +

For each of these components, you create an HTML file and point to it using a specific property in manifest.json. The HTML file can include CSS and JavaScript files, just like a normal web page.

+ +

All of these are a type of Extension pages, and unlike a normal web page, your JavaScript can use all the same privileged WebExtension APIs as your background script. They can even directly access variables in the background page using {{WebExtAPIRef("runtime.getBackgroundPage()")}}.

+ +

Extension pages擴充頁面

+ +

You can also include HTML documents in your extension which are not attached to some predefined user interface component. Unlike the documents you might provide for sidebars, popups, or options pages, these don't have an entry in manifest.json. However, they do also get access to all the same privileged WebExtension APIs as your background script.

+ +

You'd typically load a page like this using {{WebExtAPIRef("windows.create()")}} or {{WebExtAPIRef("tabs.create()")}}.

+ +

See Extension pages to learn more.

+ +

Content scripts

+ +

Use content scripts to access and manipulate web pages. Content scripts are loaded into web pages and run in the context of that particular page.

+ +

Content scripts are extension-provided scripts which run in the context of a web page; this differs from scripts which are loaded by the page itself, including those which are provided in {{HTMLElement("script")}} elements within the page.

+ +

Content scripts can see and manipulate the page's DOM, just like normal scripts loaded by the page.

+ +

Unlike normal page scripts, they can:

+ + + +

Content scripts cannot directly access normal page scripts but can exchange messages with them using the standard window.postMessage() API.

+ +

Usually, when we talk about content scripts, we are referring to JavaScript, but you can inject CSS into web pages using the same mechanism.

+ +

See the content scripts article to learn more.

+ +

Web accessible resources 網頁無障礙資源

+ +

Web accessible resources are resources such as images, HTML, CSS, and JavaScript that you include in the extension and want to make accessible to content scripts and page scripts. Resources which are made web-accessible can be referenced by page scripts and content scripts using a special URI scheme.

+ +

For example, if a content script wants to insert some images into web pages, you could include them in the extension and make them web accessible. Then the content script could create and append img tags which reference the images via the src attribute.

+ +

To learn more, see the documentation for the web_accessible_resources manifest.json key.

diff --git a/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/cookiestore/index.html b/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/cookiestore/index.html new file mode 100644 index 0000000000..b8ab73dc3f --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/cookiestore/index.html @@ -0,0 +1,80 @@ +--- +title: cookies.CookieStore +slug: Mozilla/Add-ons/WebExtensions/API/cookies/CookieStore +translation_of: Mozilla/Add-ons/WebExtensions/API/cookies/CookieStore +--- +
{{AddonSidebar()}}
+ +

{{WebExtAPIRef("cookies")}} API 的 CookieStore 型別代表瀏覽器中的 cookie 存放空間。

+ +

不同瀏覽模式(browsing mode)的視窗,有不同的 cookie 存放空間:例如隱私/隱身模式的視窗,會使用來自非隱私/隱身模式視窗的個別 cookie 存放空間。

+ +

型別

+ +

此型別的值都是物件,並包含以下屬性:

+ +
+
id
+
string,代表 cookie 存放空間內的唯一識別號(identifier)。
+
tabIds
+
integersarray,識別所有分享此 cookie 存放空間的瀏覽頁籤。
+
+ +

瀏覽器相容性

+ + + +

{{Compat("webextensions.api.cookies.CookieStore")}}

+ +

示例

+ +

在以下程式碼片段內,{{WebExtAPIRef("cookies.getAllCookieStores()")}} 用來查找瀏覽器內,所有目前能用 cookie 存放空間,並列出每個 cookie 存放空間的 ID、還有分享此 cookie 存放空間的頁籤。

+ +
function logStores(cookieStores) {
+  for(store of cookieStores) {
+    console.log(`Cookie store: ${store.id}\n Tab IDs: ${store.tabIds}`);
+  }
+}
+
+var getting = browser.cookies.getAllCookieStores();
+getting.then(logStores);
+ +

{{WebExtExamples}}

+ +
致謝 + +

此 API 基於 Chromium 的 chrome.cookies API 而來,文件改作自 Chromium 程式碼裡的 cookies.json

+ +

Microsoft Edge 的相容資訊來自微軟公司,原文以創用 CC 姓名標示 3.0 美國版條款授權大眾使用。

+
+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/index.html b/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/index.html new file mode 100644 index 0000000000..34da08932c --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/index.html @@ -0,0 +1,163 @@ +--- +title: cookies +slug: Mozilla/Add-ons/WebExtensions/API/cookies +tags: + - API + - Add-ons + - Cookies + - Extensions + - Interface + - Non-standard + - Reference + - WebExtensions + - 介面 + - 參考文件 + - 擴充套件 + - 附加元件 + - 非標準 +translation_of: Mozilla/Add-ons/WebExtensions/API/cookies +--- +
{{AddonSidebar}}
+ +
讓擴充套件可以取得、設定 cookies 資訊,並監控其變動。
+ +
 
+ +

使用此 API 前,必須先在 manifest.json 檔案中加入「cookies」這項 API 權限宣告,也必須以 host 權限宣告將要存取 Cookies 的網站列入。參見 Cookie 權限一節。

+ +

型別

+ +
+
{{WebExtAPIRef("cookies.Cookie")}}
+
代表一個 HTTP cookie 的相關資訊。
+
{{WebExtAPIRef("cookies.CookieStore")}}
+
代表瀏覽器中的 cookie 存放空間。
+
{{WebExtAPIRef("cookies.OnChangedCause")}}
+
代表觸發 cookie 資料變動的原因。
+
+ +

方法

+ +
+
{{WebExtAPIRef("cookies.get()")}}
+
取回單一 cookie 的相關資訊。
+
{{WebExtAPIRef("cookies.getAll()")}}
+
取回符合設定條件的所有 cookies 資訊。
+
{{WebExtAPIRef("cookies.set()")}}
+
為 cookie 設定資料。如果目前已有相同的 cookies,則會覆寫原本的 cookie 資料。
+
{{WebExtAPIRef("cookies.remove()")}}
+
刪除某特定名稱的 cookie。
+
{{WebExtAPIRef("cookies.getAllCookieStores()")}}
+
列出目前所有的 cookie 存放空間。
+
+ +

事件處理程序

+ +
+
{{WebExtAPIRef("cookies.onChanged")}}
+
當 cookie 設定或刪除時觸發。
+
+ +

權限

+ +

使用此 API 前,擴充套件應於 manifest.json 設定檔中指明需要「cookies」API 權限,亦須以 host 權限宣告指明需要存取 cookies 的網站清單。此後,符合 host 權限宣告的 URL 所能讀寫的任何 cookies,該擴充套件即可讀取。比方說:

+ +
+
http://*.example.com/
+
+

若套件有這樣的 host 權限宣告,即可:

+ +
    +
  • 讀取 www.example.com 任何路徑下的非安全 cookie。
  • +
  • 寫入 www.example.com 任何路徑下的安全或非安全 cookie。
  • +
+ +

不能

+ +
    +
  • 讀取 www.example.com 下的安全 cookie。
  • +
+
+
http://www.example.com/
+
+

若套件有這樣的 host 權限宣告,即可:

+ +
    +
  • 讀取 www.example.com 任何路徑下的非安全 cookie。
  • +
  • 讀取 .example.com 任何路徑下的非安全 cookie。
  • +
  • 寫入 www.example.com 任何路徑下的安全或非安全 cookie。
  • +
  • 寫入 .example.com 任何路徑下的安全或非安全 cookie。
  • +
+ +

不能

+ +
    +
  • 寫入 foo.example.com 的 cookie。
  • +
  • 寫入 foo.www.example.com 的 cookie。
  • +
+
+
*://*.example.com/
+
+

若套件有這樣的 host 權限宣告,即可:

+ +
    +
  • 讀、寫 www.example.com 任何路徑下的安全或非安全 cookie。
  • +
+
+
+ +

瀏覽器相容性

+ +

{{Compat("webextensions.api.cookies")}}

+ + + +

Edge 不相容資訊

+ +

Edge 不支援 promises,請使用回呼(callback)函式處理。

+ +

 {{WebExtExamples("h2")}}

+ +
致謝 + +

此 API 基於 Chromium 的 chrome.cookies API 而來,文件改作自 Chromium 程式碼裡的 cookies.json

+ +

Microsoft Edge 的相容資訊來自微軟公司,原文以創用 CC 姓名標示 3.0 美國版條款授權大眾使用。

+
+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/onchanged/index.html b/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/onchanged/index.html new file mode 100644 index 0000000000..7558105bcc --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/onchanged/index.html @@ -0,0 +1,118 @@ +--- +title: cookies.onChanged +slug: Mozilla/Add-ons/WebExtensions/API/cookies/onChanged +translation_of: Mozilla/Add-ons/WebExtensions/API/cookies/onChanged +--- +
{{AddonSidebar()}}
+ +

{{WebExtAPIRef("cookies")}} API 的 onChanged 事件會在 cookie 設定或刪除時觸發。

+ +

請注意,更新 cookie 的屬性要透過以下兩個步驟實做:

+ +
    +
  1. 首先,要更新的 cookie 會先被刪掉,並產生一個 overwrite 的 {{WebExtAPIRef("cookies.OnChangedCause")}} 提醒。
  2. +
  3. 接著,帶著更新數值的新 cookie 會被寫進去,並產生第二個 explicit 的 {{WebExtAPIRef("cookies.OnChangedCause")}} 提醒。
  4. +
+ +

語法

+ +
browser.cookies.onChanged.addListener(listener)
+browser.cookies.onChanged.removeListener(listener)
+browser.cookies.onChanged.hasListener(listener)
+
+ +

此 API 也能以 browser.cookies.onChanged.* 運行。

+ +

此事件有以下函式:

+ +
+
addListener(callback)
+
給此事件添加監聽器(listener)。
+
removeListener(listener)
+
停止監聽此事件。listener 參數是要移除的監聽器。
+
hasListener(listener)
+
檢查此事件的 listener 是否被監聽了。若有監聽,回傳 true,否則回傳 false
+
+ +

addListener 語法

+ +

參數

+ +
+
callback
+
+

能被呼叫的 callback 函式會在此事件發生的時候觸發。函式會 passed 以下參數:

+ +
+
changeInfo
+
一個含有觸發事件資訊的 object。它有兩個屬性:
+
+
+
removed
+
一個 boolean。如果 cookie 被刪除則為 true,否則為 false
+
cookie
+
一個 {{WebExtAPIRef('cookies.Cookie')}} 物件。含有被設定、或被刪除的 cookie 資訊。
+
cause
+
一個 {{WebExtAPIRef('cookies.OnChangedCause')}} 數值。含有 cookie被改變的潛在原因。
+
+
+
+
+
+ +

瀏覽器相容性

+ + + +

{{Compat("webextensions.api.cookies.onChanged")}}

+ +

示例

+ +

本範例監聽 onChanged 事件並紀錄由 changeInfo 參數傳來的資訊:

+ +
browser.cookies.onChanged.addListener(function(changeInfo) {
+  console.log('Cookie changed: ' +
+              '\n * Cookie: ' + JSON.stringify(changeInfo.cookie) +
+              '\n * Cause: ' + changeInfo.cause +
+              '\n * Removed: ' + changeInfo.removed);
+});
+ +

{{WebExtExamples}}

+ +
致謝 + +

此 API 基於 Chromium 的 chrome.cookies API 而來,文件改作自 Chromium 程式碼裡的 cookies.json

+ +

Microsoft Edge 的相容資訊來自微軟公司,原文以創用 CC 姓名標示 3.0 美國版條款授權大眾使用。

+
+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/onchangedcause/index.html b/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/onchangedcause/index.html new file mode 100644 index 0000000000..592aaf7d6d --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/api/cookies/onchangedcause/index.html @@ -0,0 +1,82 @@ +--- +title: cookies.OnChangedCause +slug: Mozilla/Add-ons/WebExtensions/API/cookies/OnChangedCause +translation_of: Mozilla/Add-ons/WebExtensions/API/cookies/OnChangedCause +--- +
{{AddonSidebar()}}
+ +

{{WebExtAPIRef("cookies")}} API 的 OnChangedCause 型別,代表觸發 cookie 資料變動的原因。

+ +

型別

+ +

此型別的所有值都是字串(string)。可用值包括:

+ +
+
evicted
+
由於垃圾回收(garbage collection)而被刪除的 cookie。
+
expired
+
由於過期而被刪除的 cookie。
+
explicit
+
透過顯式呼叫(explicit call){{WebExtAPIRef("cookies.remove()")}} 而被插入或刪除的 cookie。
+
expired_overwrite
+
被已過期(already-expired expiration date)cookie 所覆寫的 cookie。
+
overwrite
+
A call to {{WebExtAPIRef("cookies.set()")}} overwrote this cookie with a different one.
+
+ +

瀏覽器相容性

+ + + +

{{Compat("webextensions.api.cookies.OnChangedCause")}}

+ +

示例

+ +

你可以在 cookie 變更的時候監聽被通知的 {{WebExtAPIRef("cookies.onChanged")}} 事件。此監聽器 passed 含有 cause 屬性,值為 OnChangeCaused 字串的 changeInfo 物件:

+ +
browser.cookies.onChanged.addListener(function(changeInfo) {
+  console.log('Cookie changed: ' +
+              '\n * Cookie: ' + JSON.stringify(changeInfo.cookie) +
+              '\n * Cause: ' + changeInfo.cause +
+              '\n * Removed: ' + changeInfo.removed);
+});
+ +

{{WebExtExamples}}

+ +
致謝 + +

此 API 基於 Chromium 的 chrome.cookies API 而來,文件改作自 Chromium 程式碼裡的 cookies.json

+ +

Microsoft Edge 的相容資訊來自微軟公司,原文以創用 CC 姓名標示 3.0 美國版條款授權大眾使用。

+
+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/api/index.html b/files/zh-tw/mozilla/add-ons/webextensions/api/index.html new file mode 100644 index 0000000000..955086de10 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/api/index.html @@ -0,0 +1,53 @@ +--- +title: JavaScript APIs +slug: Mozilla/Add-ons/WebExtensions/API +tags: + - NeedsTranslation + - TopicStub + - WebExtensions +translation_of: Mozilla/Add-ons/WebExtensions/API +--- +
{{AddonSidebar}}
+ +
+

JavaScript APIs for WebExtensions can be used inside the extension's background scripts and in any other documents bundled with the extension, including browser action or page action popups, sidebars, options pages, or new tab pages. A few of these APIs can also be accessed by an extension's content scripts (see the list in the content script guide).

+ +

To use the more powerful APIs you need to request permission in your extension's manifest.json.

+ +

You can access the APIs using the browser namespace:

+ +
function logTabs(tabs) {
+  console.log(tabs);
+}
+
+browser.tabs.query({currentWindow: true}, logTabs);
+
+ +
+

Many of the APIs are asynchronous, returning a Promise:

+ +
function logCookie(c) {
+  console.log(c);
+}
+
+function logError(e) {
+  console.error(e);
+}
+
+var setCookie = browser.cookies.set(
+  {url: "https://developer.mozilla.org/"}
+);
+setCookie.then(logCookie, logError);
+
+ +
+

Note that this is different from Google Chrome's extension system, which uses the chrome namespace instead of browser, and which uses callbacks instead of promises for asynchronous functions. As a porting aid, the Firefox implementation of WebExtensions APIs supports chrome and callbacks as well as browser and promises. Mozilla has also written a polyfill which enables code that uses browser and promises to work unchanged in Chrome: https://github.com/mozilla/webextension-polyfill.

+ +

Firefox also implements these APIs under the chrome namespace using callbacks. This allows code written for Chrome to run largely unchanged in Firefox for the APIs documented here.

+ +

Microsoft Edge uses the browser namespace, but doesn't yet support promise-based asynchronous APIs. In Edge, for the time being, asynchronous APIs must use callbacks.

+ +

Not all browsers support all the APIs: for the details, see Browser support for JavaScript APIs.

+
+ +
{{SubpagesWithSummaries}}
diff --git a/files/zh-tw/mozilla/add-ons/webextensions/api/storage/index.html b/files/zh-tw/mozilla/add-ons/webextensions/api/storage/index.html new file mode 100644 index 0000000000..8e1d68894d --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/api/storage/index.html @@ -0,0 +1,103 @@ +--- +title: storage +slug: Mozilla/Add-ons/WebExtensions/API/storage +tags: + - API + - 擴充套件 +translation_of: Mozilla/Add-ons/WebExtensions/API/storage +--- +
+
{{AddonSidebar}}
+ +

讓套件可以存讀資料以及監聽儲存項目的更動。

+ +

儲存系統基於 Web Storage API,有一些不同,包括:

+ + + +

要使用這個 API 你必須在 manifest.json 裡面加入 "storage" 的權限

+ +

每個套件都有自己的儲存空間,它們可以被切分爲不同種類的儲存。

+ +

雖然這個 API 與{{domxref("Window.localStorage")}}很相似,建議你不要在套件裡使用 Window.localStorage 儲存套件相關資料。Firefox 在用戶由於隱私問題清除歷史記錄與資料時會清除 localStorage API 儲存的資料,而 storage.local API 儲存的則會留著。

+ +
儲存空間不會被加密,所以你不應該把它們用來儲存用戶的機密資料。
+ +

型別

+ +
+
{{WebExtAPIRef("storage.StorageArea")}}
+
表示儲存空間的物件。
+
{{WebExtAPIRef("storage.StorageChange")}}
+
表示儲存空間變化的物件。
+
+ +

屬性

+ +

storage 有三個屬性,各自表示不同種類的儲存空間。

+ +
+
{{WebExtAPIRef("storage.sync")}}
+
表示 sync 儲存空間。sync 儲存空間裡的項目會被瀏覽器同步,所以可以跨裝置在所有已登入瀏覽器實例裡面使用。
+
{{WebExtAPIRef("storage.local")}}
+
表示 local 儲存空間。local 儲存空間裡的項目會被侷限在安裝套件的機器上。
+
{{WebExtAPIRef("storage.managed")}}
+
表示 managed 儲存空間。managed 儲存空間的項目由網域管理者設置而且對套件唯讀,修改這項會導致錯誤。
+
+ +

事件

+ +
+
{{WebExtAPIRef("storage.onChanged")}}
+
當儲存空間裡的一個或更多項目被修改時觸發。
+
+ +

瀏覽器兼容性

+
+ +

{{Compat("webextensions.api.storage")}}

+ +

{{WebExtExamples("h2")}}

+ +
Acknowledgements + +

This API is based on Chromium's chrome.storage API. This documentation is derived from storage.json in the Chromium code.

+ +

Microsoft Edge compatibility data is supplied by Microsoft Corporation and is included here under the Creative Commons Attribution 3.0 United States License.

+
+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/api/storage/local/index.html b/files/zh-tw/mozilla/add-ons/webextensions/api/storage/local/index.html new file mode 100644 index 0000000000..3cdc3ab140 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/api/storage/local/index.html @@ -0,0 +1,84 @@ +--- +title: storage.local +slug: Mozilla/Add-ons/WebExtensions/API/storage/local +translation_of: Mozilla/Add-ons/WebExtensions/API/storage/local +--- +
{{AddonSidebar()}}
+ +

代表 local 儲存空間。通常 local 裡面的東西,會放在套件安裝的地方。

+ +

瀏覽器可能會限制套件本地可儲存的資料數量:

+ + + +

如果套件被移除、相關的儲存資料也會一併移除。

+ +

在 Firefox 內,你可以透過 about:config 內設定 keepUuidOnUninstall 與 keepStorageOnUninstall 為 true 以避免瀏覽器在移除套件時,一併移除相關的儲存資料。這個功能是為了方便開發者除錯,套件本身無法改變這個設定。

+ +

雖然這 API 與 {{domxref("Window.localStorage")}} 相似,但不建議在套件內使用 Window.localStorage。在某些情況下,用戶會出於隱私上的理由,要求 Firefox 清理瀏覽紀錄與資料,這其中就包含使用 localStorage API 的資料。另一方面,storage.local API 的資料,在這種情況下會予以保留。

+ +

方法

+ +

local 物件實做了定義於 {{WebExtAPIRef("storage.StorageArea")}} 類別的方法:

+ +
+
{{WebExtAPIRef("storage.StorageArea.get()")}}
+
取得一個或多個源自儲存空間的項目。
+
{{WebExtAPIRef("storage.StorageArea.getBytesInUse()")}}
+
取得儲存空間內,一個或多個已為項目所使用的容量。單位為 byte。
+
{{WebExtAPIRef("storage.StorageArea.set()")}}
+
Stores one or more items in the storage area. If the item already exists, its value will be updated. When you set a value, the {{WebExtAPIRef("storage.onChanged")}} event will fire.
+
{{WebExtAPIRef("storage.StorageArea.remove()")}}
+
刪除一個或多個儲存空間內的項目。
+
{{WebExtAPIRef("storage.StorageArea.clear()")}}
+
刪除所有儲存空間內的項目。
+
+ +

瀏覽器相容性

+ + + +

{{Compat("webextensions.api.storage.local")}}

+ +

{{WebExtExamples}}

+ +
致謝 + +

This API is based on Chromium's chrome.storage API. This documentation is derived from storage.json in the Chromium code.

+ +

Microsoft Edge compatibility data is supplied by Microsoft Corporation and is included here under the Creative Commons Attribution 3.0 United States License.

+
+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/api/storage/storagearea/get/index.html b/files/zh-tw/mozilla/add-ons/webextensions/api/storage/storagearea/get/index.html new file mode 100644 index 0000000000..744cc6ed8b --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/api/storage/storagearea/get/index.html @@ -0,0 +1,122 @@ +--- +title: StorageArea.get() +slug: Mozilla/Add-ons/WebExtensions/API/storage/StorageArea/get +translation_of: Mozilla/Add-ons/WebExtensions/API/storage/StorageArea/get +--- +
{{AddonSidebar()}}
+ +

從儲存空間內檢查一個或多個單元(item)。

+ +

這個非同步函式會回傳 Promise

+ +

語法

+ +
let gettingItem = browser.storage.<storageType>.get(
+  keys    // null, string, object or array of strings
+)
+
+ +

<storageType> 會是以下可覆寫的儲存類型之一:{{WebExtAPIRef("storage.sync")}} 或 {{WebExtAPIRef("storage.local")}}。

+ +

參數

+ +
+
keys
+
用來識別要檢查單元的 key(單個為字串;多個為陣列、或指定預設值的物件)。如果把這裡留空(空字串、空陣列、空物件都可以),就會取得空物件。如果是 null 或 undefined,則會取得所有儲存的內容。
+
+ +

回傳值

+ +

Promise that will be fulfilled with a results object containing every object in keys that was found in the storage area. If the operation failed, the promise will be rejected with an error message.

+ +
+

When used within a content script in Firefox versions prior to 52, the Promise returned by browser.storage.local.get() is fulfilled with an Array containing one Object. The Object in the Array contains the keys found in the storage area, as described above. The Promise is correctly fulfilled with an Object when used in the background context (background scripts, popups, options pages, etc.). When this API is used as chrome.storage.local.get(), it correctly passes an Object to the callback function.

+
+ +

瀏覽器相容性

+ +

{{Compat("webextensions.api.storage.StorageArea.get")}}

+ +

示例

+ +

假設儲存空間有以下單元:

+ +
// 兩個單元:「kitten」與「monster」
+browser.storage.local.set({
+  kitten:  {name:"Mog", eats:"mice"},
+  monster: {name:"Kraken", eats:"people"}
+});
+ +

Define success and failure handlers for the promise:

+ +
function onGot(item) {
+  console.log(item);
+}
+
+function onError(error) {
+  console.log(`Error: ${error}`);
+}
+ +

With no keys argument, retrieve everything:

+ +
let gettingItem = browser.storage.local.get();
+gettingItem.then(onGot, onError);
+
+// -> Object { kitten: Object, monster: Object }
+ +

With an empty keys argument, return nothing:

+ +
// with an empty array, retrieve nothing
+let gettingItem = browser.storage.local.get([]);
+gettingItem.then(onGot, onError);
+
+// -> Object { }
+ +

With the name of an object, retrieve the match:

+ +
let gettingItem = browser.storage.local.get("kitten");
+gettingItem.then(onGot, onError);
+
+// -> Object { kitten: Object }
+ +

With an array of object names, retrieve all matches:

+ +
let gettingItem = browser.storage.local.get(["kitten", "monster", "grapefruit"]);
+gettingItem.then(onGot, onError);
+
+// -> Object { kitten: Object, monster: Object } 
+ +

With an object with object names as keys and the default value as value:

+ +
let gettingItem = browser.storage.local.get({
+  kitten: "no kitten",
+  monster: "no monster",
+  grapefruit: {
+    name: "Grape Fruit",
+    eats: "Water"
+  }
+});
+
+// -> Object { kitten: Object, monster: Object, grapefruit: Object }
+
+ +

{{WebExtExamples}}

+ +

Chrome 示例

+ +
chrome.storage.local.get("kitten", function(items){
+  console.log(items.kitten);  // -> {name:"Mog", eats:"mice"}
+});
+ +

Or with an arrow function

+ +
chrome.storage.local.get("kitten", items=>{
+  console.log(items.kitten); // -> {name:"Mog", eats:"mice"}
+});
+ +
致謝 + +

This API is based on Chromium's chrome.storage API. This documentation is derived from storage.json in the Chromium code.

+ +

Microsoft Edge compatibility data is supplied by Microsoft Corporation and is included here under the Creative Commons Attribution 3.0 United States License.

+
diff --git a/files/zh-tw/mozilla/add-ons/webextensions/api/storage/storagearea/index.html b/files/zh-tw/mozilla/add-ons/webextensions/api/storage/storagearea/index.html new file mode 100644 index 0000000000..088e8b5a79 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/api/storage/storagearea/index.html @@ -0,0 +1,85 @@ +--- +title: storage.StorageArea +slug: Mozilla/Add-ons/WebExtensions/API/storage/StorageArea +tags: + - API + - Add-ons + - Extensions + - NeedsTranslation + - Non-standard + - Reference + - Storage + - StorageArea + - TopicStub + - Type + - WebExtensions +translation_of: Mozilla/Add-ons/WebExtensions/API/storage/StorageArea +--- +
{{AddonSidebar()}}
+ +

StorageArea is an object representing a storage area.

+ +

Type

+ +

Values of this type are objects.

+ +

Methods

+ +
+
{{WebExtAPIRef("storage.StorageArea.get()")}}
+
Retrieves one or more items from the storage area.
+
{{WebExtAPIRef("storage.StorageArea.getBytesInUse()")}}
+
Gets the amount of storage space (in bytes) used one or more items being stored in the storage area.
+
{{WebExtAPIRef("storage.StorageArea.set()")}}
+
Stores one or more items in the storage area. If an item already exists, its value will be updated.
+
{{WebExtAPIRef("storage.StorageArea.remove()")}}
+
Removes one or more items from the storage area.
+
{{WebExtAPIRef("storage.StorageArea.clear()")}}
+
Removes all items from the storage area.
+
+ +

Browser compatibility

+ + + +

{{Compat("webextensions.api.storage.StorageArea")}}

+ +

{{WebExtExamples}}

+ +
Acknowledgements + +

This API is based on Chromium's chrome.storage API. This documentation is derived from storage.json in the Chromium code.

+ +

Microsoft Edge compatibility data is supplied by Microsoft Corporation and is included here under the Creative Commons Attribution 3.0 United States License.

+
+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/content_scripts/index.html b/files/zh-tw/mozilla/add-ons/webextensions/content_scripts/index.html new file mode 100644 index 0000000000..e767b3ef89 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/content_scripts/index.html @@ -0,0 +1,444 @@ +--- +title: 內容腳本 +slug: Mozilla/Add-ons/WebExtensions/Content_scripts +tags: + - 擴充套件 +translation_of: Mozilla/Add-ons/WebExtensions/Content_scripts +--- +
{{AddonSidebar}}
+ +
內容腳本(content script)是擴充套件的一部分,它會在在特定的網頁執行(與之相對的則是同樣屬於套件
+ +
的後端腳本(background scripts)或者網站本身的腳本,像是那些那些透過 {{HTMLElement("script")}} 標籤讀取的內
+ +
容)
+ +
 
+ +

後端腳本可以使用所有的 擴充套件JavaScript APIs,但它們無法直接使用網頁中的內容。所以如果你的套件必須要透過 content scripts 才能使用它們。

+ +

就像一般網頁裡的 scripts 一樣,content scripts 可以透過 standard DOM APIs 存取並修改頁面內容。

+ +

Content scripts 只能使用can only access 一小部分的擴充套件APIs,但它們可以透過一個訊息系統來與後端腳本溝通,從而間接地使用擴充套件APIs。

+ +
+

留意到 content scripts 目前會在 addons.mozilla.org 和 testpilot.firefox.com 中被阻擋。如果你嘗試在這些網域下的頁面注入一段 content script 會失敗並且在日誌裡記下一個 CSP 錯誤。

+
+ +
+

由於錯誤 1408996,透過 var foo or window.foo = "bar" 加入 content script 的 global 作用域的值可能會消失。

+
+ +

讀入內容腳本

+ +

你可以透過下列三種方式將內容腳本讀入頁面:

+ +
    +
  1. 在安裝時讀入至符合URL模式的頁面:透過你的 manifest.json 中的 content_scripts 鍵,你可以要求瀏覽器在每次讀取URL符合給定模式的頁面時讀入內容腳本。
  2. +
  3. 在執行時讀入至符合URL模式的頁面:透過 content_scripts API,你可以要求瀏覽器在每次讀取URL符合給定模式的頁面時讀入內容腳本。這就像第一種方法,不同的是你可以在執行時增加或移除內容腳本。
  4. +
  5. 在執行時讀入至特定的頁籤:透過 tabs.executeScript() API,你可以在任何時候將內容腳本讀入特定的頁籤:舉例來說可以在使用者點擊工具列按鈕時給予回應。
  6. +
+ +

每個套件的每個架構裡都只有一個全局作用域,所以一個內容腳本的變數可以直接被其他內容腳本使用,不管那個內容腳本是怎麼被讀入的。

+ +

透過方法(1)和方法(2)你只能把內容腳本讀入至URL可以用匹配模式來呈現的頁面中。而透過方法3可以把腳本讀入與套件打包在一起的頁面之中,但是你不能在像是 "about:debugging" 或 "about:addons" 這類特別的瀏覽器頁面讀入腳本。

+ +

內容腳本環境

+ +

使用 DOM

+ +

內容腳本可以像一般頁面的腳本一樣使用並修改頁面的DOM。它們也可以偵測到所有頁面script 對 DOM 做的更動。

+ +

然而,內容腳本看到的是「乾淨的DOM」。這表示:

+ + + +

在 Gecko 裡,這種行爲稱爲 X光視野

+ +

舉例來說,有這樣一個網頁:

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+  </head>
+
+  <body>
+    <script src="page-scripts/page-script.js"></script>
+  </body>
+</html>
+ +

"page-script.js" 做了這件事:

+ +
// page-script.js
+
+// 替DOM新增一個元素
+var p = document.createElement("p");
+p.textContent = "This paragraph was added by a page script.";
+p.setAttribute("id", "page-script-para");
+document.body.appendChild(p);
+
+// 替 window 定義一個新的屬性
+window.foo = "This global variable was added by a page script";
+
+// 重新定義內建的 window.confirm 函數
+window.confirm = function() {
+  alert("The page script has also redefined 'confirm'");
+}
+ +

接著、一個套件把 content script 插入頁面:

+ +
// content-script.js
+
+// 可以使用與修改DOM
+var pageScriptPara = document.getElementById("page-script-para");
+pageScriptPara.style.backgroundColor = "blue";
+
+// 看不見 page-script 增加的屬性
+console.log(window.foo);  // undefined
+
+// 看見的是原有的形式
+window.confirm("Are you sure?"); // 呼叫原本的 window.confirm()
+ +

反過來也是一樣,頁面腳本無法看到內容腳本增加的 Javascript 屬性。

+ +

這表示我們可以預期內容腳本依賴著DOM屬性,不需要擔心它的變數與頁面腳本中所定義的變數衝突。

+ +

這實際的影響就是內容腳本無法使用所有頁面腳本讀入的函式庫。所以,舉例來說,如果頁面包含了 JQuery,內容腳本將無法看到它。

+ +

如果內容腳本真的想要使用 javascript 函式庫,那麼函式庫本身必須要與要使用它的內容腳本一同插入:

+ +
"content_scripts": [
+  {
+    "matches": ["*://*.mozilla.org/*"],
+    "js": ["jquery.js", "content-script.js"]
+  }
+]
+ +

注意到 Firefox 提供了一些API來使用被頁面腳本產生的 Javascript 物件以及對頁面腳本公開自己的 Javascript 物件。詳閱與頁面腳本共用物件

+ +

擴充套件APIs

+ +

除標準DOM APIs之外,內容腳本可以使用下列 擴充套件APIs:

+ +

來自 extension:

+ + + +

來自 runtime:

+ + + +

來自 i18n:

+ + + +

來自 storage 的全部。

+ +

XHR 與 Fetch

+ +

內容腳本可以透過一般的 window.XMLHttpRequestwindow.fetch() APIs 來發出請求。

+ +

內容腳本跟套件的其他部分擁有相同的跨網域權限: 所以如果套件在 manifest.json 中透過 permissions 鍵要求了某一網域的使用,那麼它的內容腳本也能使用同樣的網域。

+ +

這是透過公開更多內容腳本中授權的XHR以及fetch實例來達成的。這件事情會導致標頭中不會設置 OriginReferer的副作用,就像頁面請求自己一樣,一般會避免請求將跨來源泄露出去。從58版本號以後套件要傳送一些彷彿是頁面內容自己傳送的請求時可以改用 content.XMLHttpRequestcontent.fetch()。對跨瀏覽器套件來說,這些事情的存在必須要能被做特徵檢測。

+ +

與後端腳本溝通

+ +

雖然內容腳本不能直接使用大部分的 擴充套件APIs,但是透過使用訊息APIs與後端腳本溝通,它們能夠間接地使用與後端腳本一樣的 APIs。

+ +

後端腳本與內容腳本的溝通模式有兩種: 你可以傳送選擇性夾帶回應的一次性訊息,也可以在兩者之間建立一個長存的連線來交換訊息。

+ +

一次性訊息

+ +

要傳送選擇性夾帶回應的一次性訊息,你可以使用下列APIs:

+ + + + + + + + + + + + + + + + + + + + + +
 在內容腳本處在後端腳本處
傳訊息browser.runtime.sendMessage()browser.tabs.sendMessage()
收訊息browser.runtime.onMessagebrowser.runtime.onMessage
+ +

舉例來說,有個監聽著頁面點擊事件的內容腳本。如果點擊對象是連結,它會傳送目標的URL給後端腳本:

+ +
// content-script.js
+
+window.addEventListener("click", notifyExtension);
+
+function notifyExtension(e) {
+  if (e.target.tagName != "A") {
+    return;
+  }
+  browser.runtime.sendMessage({"url": e.target.href});
+}
+ +

後端腳本監聽這些訊息並且透過 notifications API 顯示通知:

+ +
// background-script.js
+
+browser.runtime.onMessage.addListener(notify);
+
+function notify(message) {
+  browser.notifications.create({
+    "type": "basic",
+    "iconUrl": browser.extension.getURL("link.png"),
+    "title": "你點了個按鈕喲!",
+    "message": message.url
+  });
+}
+
+ +

這個範例來自 GitHub上的 notify-link-clicks-i18n ,稍微經過修改。

+ +

基於連線的訊息

+ +

當你在後端腳本與內容腳本間交換大量訊息時,使用一次性連線顯得沒效率。所以另一個替代方案是是在兩者間建立一個長存的連線,透過這個連線交換訊息。

+ +

兩邊都有一個 runtime.Port 物件可以用來交換訊息。

+ +

建立連線你需要:

+ + + +

當兩邊都有端口後,可以透過 runtime.Port.postMessage() 來傳送訊息,用 runtime.Port.onMessage 接收訊息。

+ +

舉例來說,當這讀取完成,這個內容腳本會:

+ + + +
// content-script.js
+
+var myPort = browser.runtime.connect({name:"port-from-cs"});
+myPort.postMessage({greeting: "內容腳本傳喜訊"});
+
+myPort.onMessage.addListener(function(m) {
+  console.log("內容腳本收到來自後端腳本的訊息: ");
+  console.log(m.greeting);
+});
+
+document.body.addEventListener("click", function() {
+  myPort.postMessage({greeting: "它們點了網頁!"});
+});
+ +

同樣地,後端腳本會:

+ + + +
// background-script.js
+
+var portFromCS;
+
+function connected(p) {
+  portFromCS = p;
+  portFromCS.postMessage({greeting: "嘿!內容腳本!"});
+  portFromCS.onMessage.addListener(function(m) {
+    console.log("後端腳本收到來自內容腳本的訊息:")
+    console.log(m.greeting);
+  });
+}
+
+browser.runtime.onConnect.addListener(connected);
+
+browser.browserAction.onClicked.addListener(function() {
+  portFromCS.postMessage({greeting: "它們按了按鈕!"});
+});
+
+ +

複數內容腳本

+ +

如果你有多個內容腳本同時在溝通,你可能會想把這些連線儲存在陣列裡面。

+ +

 

+ + + +
// background-script.js
+
+var ports = []
+
+function connected(p) {
+  ports[p.sender.tab.id]    = p
+  //...
+}
+
+browser.runtime.onConnect.addListener(connected)
+
+browser.browserAction.onClicked.addListener(function() {
+  ports.forEach(p => {
+        p.postMessage({greeting: "它們按了按鈕!"})
+    })
+});
+ +

 

+ + + +

與網頁溝通

+ +

雖說內容腳本預設不能存取頁面腳本產生的物件,但它們可以透過DOM window.postMessage 和 window.addEventListener APIs與頁面腳本溝通。

+ +

例如:

+ +
// page-script.js
+
+var messenger = document.getElementById("from-page-script");
+
+messenger.addEventListener("click", messageContentScript);
+
+function messageContentScript() {
+  window.postMessage({
+    direction: "from-page-script",
+    message: "Message from the page"
+  }, "*");
+ +
// content-script.js
+
+window.addEventListener("message", function(event) {
+  if (event.source == window &&
+      event.data &&
+      event.data.direction == "from-page-script") {
+    alert("內容腳本收到訊息: \"" + event.data.message + "\"");
+  }
+});
+ +

完全版的範例請查看GitHub上的示範頁面並按照教學做。

+ +
+

注意到當你透過這個方式跟不被信任的內容腳本互動時要非常小心。套件有很強的權限,惡意網頁可以輕易地騙出這些權限。

+ +

舉個簡單的例子,假設一接收訊息的內容腳本長這樣:

+ +
// content-script.js
+
+window.addEventListener("message", function(event) {
+  if (event.source == window &&
+      event.data.direction &&
+      event.data.direction == "from-page-script") {
+    eval(event.data.message);
+  }
+});
+ +

如此一來頁面腳本可以使用包含內容腳本全部權限的程式碼。

+
+ +

在內容腳本中使用 eval()

+ +

在 Chrome 裡, eval() 只會在內容腳本而不會在頁面腳本裡執行。

+ +

在 Firefox 裡:

+ + + +

例如,試想有一個內容腳本長這樣:

+ +
// content-script.js
+
+window.eval('window.x = 1;');
+eval('window.y = 2');
+
+console.log(`In content script, window.x: ${window.x}`);
+console.log(`In content script, window.y: ${window.y}`);
+
+window.postMessage({
+  message: "check"
+}, "*");
+ +

這段程式碼透過 window.eval() 和 eval() 建立了些變數 x 和 y 、記錄下它們的值並且傳訊息給頁面。

+ +

接收訊息這邊,頁面腳本記錄下一樣的值:

+ +
window.addEventListener("message", function(event) {
+  if (event.source === window && event.data && event.data.message === "check") {
+    console.log(`In page script, window.x: ${window.x}`);
+    console.log(`In page script, window.y: ${window.y}`);
+  }
+});
+ +

在 Chrome 裡,這會產出這樣的結果:

+ +
In content script, window.x: 1
+In content script, window.y: 2
+In page script, window.x: undefined
+In page script, window.y: undefined
+ +

而在 Firefox 裡會產生這些:

+ +
In content script, window.x: undefined
+In content script, window.y: 2
+In page script, window.x: 1
+In page script, window.y: undefined
+ +

這些也適用於 setTimeout()setInterval()、與 Function()

+ +

當在頁面執行程式碼時一定要小一萬個心,頁面的環境有可能被惡意的網頁所控制,它們可以重新定義與你互動的物件來作出一些出乎意料的行爲:

+ +
// page.js 重新定義 console.log
+
+var original = console.log;
+
+console.log = function() {
+  original(true);
+}
+
+ +
// content-script.js 呼叫被重新定義的版本
+
+window.eval('console.log(false)');
+
diff --git a/files/zh-tw/mozilla/add-ons/webextensions/index.html b/files/zh-tw/mozilla/add-ons/webextensions/index.html new file mode 100644 index 0000000000..bf6499baac --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/index.html @@ -0,0 +1,115 @@ +--- +title: 瀏覽器擴充功能 +slug: Mozilla/Add-ons/WebExtensions +tags: + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Add-ons/WebExtensions +--- +
{{AddonSidebar}}
+ +

擴充功能(extension)可以擴展和修改瀏覽器的功能。Firefox 的擴充功能是使用 WebExtension API 建立而成,這是一個開發跨瀏覽器擴充功能的系統。這個系統的大部分相容於 Google Chrome 和 Opera 的 擴充功能 APIW3C Draft Community Group。這些瀏覽器的擴充功能在大多數的情況下,只需要一點改變就可以在 Firefox 或 Microsoft Edge 中執行。這個 API 也和多處理程序的 Firefox 完全相容。

+ +

如果你有任何新點子、問題,或是需要使用 WebExtension API 來移植舊的擴充功能,你可以在 dev-addons 郵件群組IRC 上的 #extdev 找到我們。

+ +
+ + +
+

參考資料

+ +

JavaScript APIs

+ + + +
{{ ListSubpages ("/zh-TW/Add-ons/WebExtensions/API") }}
+ +

Manifest keys

+ + + +
{{ ListSubpages ("/zh-TW/Add-ons/WebExtensions/manifest.json") }}
+
+
diff --git a/files/zh-tw/mozilla/add-ons/webextensions/internationalization/index.html b/files/zh-tw/mozilla/add-ons/webextensions/internationalization/index.html new file mode 100644 index 0000000000..7c521177a3 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/internationalization/index.html @@ -0,0 +1,400 @@ +--- +title: Internationalization +slug: Mozilla/Add-ons/WebExtensions/Internationalization +translation_of: Mozilla/Add-ons/WebExtensions/Internationalization +--- +
{{AddonSidebar}}
+ +

WebExtension API 有個相當方便、能用於國際化的模組:i18n。我們將在這篇文章內探索本功能,並提供實際做動的範例。專供 extensions 組建所使用的 i18n 系統 API,用法與坊間諸如 i18n.js 的函式庫相似。

+ +
+

本例所使用的套件:notify-link-clicks-i18n 能在 GitHub 找到。看各章節時,請配著原始碼觀看。

+
+ +

剖析國際化的套件

+ +

國際化套件能包含與其他套件相同的功能:background scriptscontent scripts……等。但它也擁有一些能允許在語言間切換的部份。目錄樹大概是這樣:

+ + + +

我們將逐一探索各大新特性:章節的每個部份,都是要國際化套件時,所需遵循的步驟。

+ +

在 _locales 提供本地化的字串

+ +
+
You can look up language subtags using the Find tool on the Language subtag lookup page. Note that you need to search for the English name of the language.
+
+ +

Every i18n system requires the provision of strings translated into all the different locales you want to support. In extensions, these are contained within a directory called _locales, placed inside the extension root. Each individual locale has its strings (referred to as messages) contained within a file called messages.json, which is placed inside a subdirectory of _locales, named using the language subtag for that locale's language.

+ +

Note that if the subtag includes a basic language plus a regional variant, then the language and variant are conventionally separated using a hyphen: for example, "en-US". However, in the directories under _locales, the separator must be an underscore: "en_US".

+ +

So for example, in our sample app we have directories for "en" (English), "de" (German), "nl" (Dutch), and "ja" (Japanese). Each one of these has a messages.json file inside it.

+ +

Let's now look at the structure of one of these files (_locales/en/messages.json):

+ +
{
+  "extensionName": {
+    "message": "Notify link clicks i18n",
+    "description": "Name of the extension."
+  },
+
+  "extensionDescription": {
+    "message": "Shows a notification when the user clicks on links.",
+    "description": "Description of the extension."
+  },
+
+  "notificationTitle": {
+    "message": "Click notification",
+    "description": "Title of the click notification."
+  },
+
+  "notificationContent": {
+    "message": "You clicked $URL$.",
+    "description": "Tells the user which link they clicked.",
+    "placeholders": {
+      "url" : {
+        "content" : "$1",
+        "example" : "https://developer.mozilla.org"
+      }
+    }
+  }
+}
+ +

This file is standard JSON — each one of its members is an object with a name, which contains a message and a description. All of these items are strings; $URL$ is a placeholder, which is replaced with a substring at the time the notificationContent member is called by the extension. You'll learn how to do this in the {{anch("Retrieving message strings from JavaScript")}} section.

+ +
+

Note: You can find much more information about the contents of messages.json files in our Locale-Specific Message reference.

+
+ +

Internationalizing manifest.json

+ +

There are a couple of different tasks to carry out to internationalize your manifest.json.

+ +

Retrieving localized strings in manifests

+ +

Your manifest.json includes strings that are displayed to the user, such as the extension's name and description. If you internationalize these strings and put the appropriate translations of them in messages.json, then the correct translation of the string will be displayed to the user, based on the current locale, like so.

+ +

To internationalize strings, specify them like this:

+ +
"name": "__MSG_extensionName__",
+"description": "__MSG_extensionDescription__",
+ +

Here, we are retrieving message strings dependant on the browser's locale, rather than just including static strings.

+ +

To call a message string like this, you need to specify it like this:

+ +
    +
  1. Two underscores, followed by
  2. +
  3. The string "MSG", followed by
  4. +
  5. One underscore, followed by
  6. +
  7. The name of the message you want to call as defined in messages.json, followed by
  8. +
  9. Two underscores
  10. +
+ +
__MSG_ + messageName + __
+ +

Specifying a default locale

+ +

Another field you should specify in your manifest.json is default_locale:

+ +
"default_locale": "en"
+ +

This specifies a default locale to use if the extension doesn't include a localized string for the browser's current locale. Any message strings that are not available in the browser locale are taken from the default locale instead. There are some more details to be aware of in terms of how the browser selects strings — see {{anch("Localized string selection")}}.

+ +

Locale-dependent CSS

+ +

Note that you can also retrieve localized strings from CSS files in the extension. For example, you might want to construct a locale-dependent CSS rule, like this:

+ +
header {
+  background-image: url(../images/__MSG_extensionName__/header.png);
+}
+ +

This is useful, although you might be better off handling such a situation using {{anch("Predefined messages")}}.

+ +

Retrieving message strings from JavaScript

+ +

So, you've got your message strings set up, and your manifest. Now you just need to start calling your message strings from JavaScript so your extension can talk the right language as much as possible. The actual i18n API is pretty simple, containing just four main methods:

+ + + +

In our notify-link-clicks-i18n example, the background script contains the following lines:

+ +
var title = browser.i18n.getMessage("notificationTitle");
+var content = browser.i18n.getMessage("notificationContent", message.url);
+ +

The first one just retrieves the notificationTitle message field from the available messages.json file most appropriate for the browser's current locale. The second one is similar, but it is being passed a URL as a second parameter. What gives? This is how you specify the content to replace the $URL$ placeholder we see in the notificationContent message field:

+ +
"notificationContent": {
+  "message": "You clicked $URL$.",
+  "description": "Tells the user which link they clicked.",
+  "placeholders": {
+    "url" : {
+      "content" : "$1",
+      "example" : "https://developer.mozilla.org"
+    }
+  }
+}
+
+ +

The "placeholders" member defines all the placeholders, and where they are retrieved from. The "url" placeholder specifies that its content is taken from $1, which is the first value given inside the second parameter of getMessage(). Since the placeholder is called "url", we use $URL$ to call it inside the actual message string (so for "name" you'd use $NAME$, etc.) If you have multiple placeholders, you can provide them inside an array that is given to {{WebExtAPIRef("i18n.getMessage()")}} as the second parameter — [a, b, c] will be available as $1, $2, and $3, and so on, inside messages.json.

+ +

Let's run through an example: the original notificationContent message string in the en/messages.json file is

+ +
You clicked $URL$.
+ +

Let's say the link clicked on points to https://developer.mozilla.org. After the {{WebExtAPIRef("i18n.getMessage()")}} call, the contents of the second parameter are made available in messages.json as $1, which replaces the $URL$ placeholder as defined in the "url" placeholder. So the final message string is

+ +
You clicked https://developer.mozilla.org.
+ +

Direct placeholder usage

+ +

It is possible to insert your variables ($1, $2, $3, etc.) directly into the message strings, for example we could rewrite the above "notificationContent" member like this:

+ +
"notificationContent": {
+  "message": "You clicked $1.",
+  "description": "Tells the user which link they clicked."
+}
+ +

This may seem quicker and less complex, but the other way (using "placeholders") is seen as best practice. This is because having the placeholder name (e.g. "url") and example helps you to remember what the placeholder is for — a week after you write your code, you'll probably forget what $1$8 refer to, but you'll be more likely to know what your placeholder names refer to.

+ +

Hardcoded substitution

+ +

It is also possible to include hardcoded strings in placeholders, so that the same value is used every time, instead of getting the value from a variable in your code. For example:

+ +
"mdn_banner": {
+  "message": "For more information on web technologies, go to $MDN$.",
+  "description": "Tell the user about MDN",
+  "placeholders": {
+    "mdn": {
+      "content": "https://developer.mozilla.org/"
+    }
+  }
+}
+ +

In this case we are just hardcoding the placeholder content, rather than getting it from a variable value like $1. This can sometimes be useful when your message file is very complex, and you want to split up different values to make the strings more readable in the file, plus then these values could be accessed programmatically.

+ +

In addition, you can use such substitutions to specify parts of the string that you don't want to be translated, such as person or business names.

+ +

Localized string selection

+ +

Locales can be specified using only a language code, like fr or en, or they may be further qualified with a region code, like en_US or en_GB, which describes a regional variant of the same basic language. When you ask the i18n system for a string, it will select a string using the following algorithm:

+ +
    +
  1. if there is a messages.json file for the exact current locale, and it contains the string, return it.
  2. +
  3. Otherwise, if the current locale is qualified with a region (e.g. en_US) and there is a messages.json file for the regionless version of that locale (e.g. en), and that file contains the string, return it.
  4. +
  5. Otherwise, if there is a messages.json file for the default_locale defined in the manifest.json, and it contains the string, return it.
  6. +
  7. Otherwise return an empty string.
  8. +
+ +

Take the following example:

+ + + +

Suppose the default_locale is set to fr, and the browser's current locale is en_GB:

+ + + +

Predefined messages

+ +

The i18n module provides us with some predefined messages, which we can call in the same way as we saw earlier in {{anch("Calling message strings from manifests and extension CSS")}}. For example:

+ +
__MSG_extensionName__
+ +

Predefined messages use exactly the same syntax, except with @@ before the message name, for example

+ +
__MSG_@@ui_locale__
+ +

The following table shows the different available predefined messages:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Message nameDescription
@@extension_id +

The extension's internally-generated UUID. You might use this string to construct URLs for resources inside the extension. Even unlocalized extensions can use this message.

+ +

You can't use this message in a manifest file.

+ +

Also note that this ID is not the add-on ID returned by {{WebExtAPIRef("runtime.id")}}, and that can be set using the applications key in manifest.json. It's the generated UUID that appears in the add-on's URL. This means that you can't use this value as the extensionId parameter to {{WebExtAPIRef("runtime.sendMessage()")}}, and can't use it to check against the id property of a {{WebExtAPIRef("runtime.MessageSender")}} object.

+
@@ui_localeThe current locale; you might use this string to construct locale-specific URLs.
@@bidi_dirThe text direction for the current locale, either "ltr" for left-to-right languages such as English or "rtl" for right-to-left languages such as Arabic.
@@bidi_reversed_dirIf the @@bidi_dir is "ltr", then this is "rtl"; otherwise, it's "ltr".
@@bidi_start_edgeIf the @@bidi_dir is "ltr", then this is "left"; otherwise, it's "right".
@@bidi_end_edgeIf the @@bidi_dir is "ltr", then this is "right"; otherwise, it's "left".
+ +

Going back to our earlier example, it would make more sense to write it like this:

+ +
header {
+  background-image: url(../images/__MSG_@@ui_locale__/header.png);
+}
+ +

Now we can just store our local specific images in directories that match the different locales we are supporting — en, de, etc. — which makes a lot more sense.

+ +

Let's look at an example of using @@bidi_* messages in a CSS file:

+ +
body {
+  direction: __MSG_@@bidi_dir__;
+}
+
+div#header {
+  margin-bottom: 1.05em;
+  overflow: hidden;
+  padding-bottom: 1.5em;
+  padding-__MSG_@@bidi_start_edge__: 0;
+  padding-__MSG_@@bidi_end_edge__: 1.5em;
+  position: relative;
+}
+ +

For left-to-right languages such as English, the CSS declarations involving the predefined messages above would translate to the following final code lines:

+ +
direction: ltr;
+padding-left: 0;
+padding-right: 1.5em;
+
+ +

For a right-to-left language like Arabic, you'd get:

+ +
direction: rtl;
+padding-right: 0;
+padding-left: 1.5em;
+ +

Testing out your extension

+ +

Starting in Firefox 45, you can install extensions temporarily from disk — see Loading from disk. Do this, and then try testing out our notify-link-clicks-i18n extension. Go to one of your favourite websites and click a link to see if a notification appears reporting the URL of the clicked link.

+ +

Next, change Firefox's locale to one supported in the extension that you want to test.

+ +
    +
  1. Open "about:config" in Firefox, and search for the general.useragent.locale preference.
  2. +
  3. Double click on the preference (or press Return/Enter) to select it, enter the language code for the locale you want to test, then click "OK" (or press Return/Enter). For example in our example extension, "en" (English), "de" (German), "nl" (Dutch), and "ja" (Japanese) are supported.
  4. +
  5. Search for intl.locale.matchOS and double click the preference so that it is set to false.
  6. +
  7. Restart your browser to complete the change.
  8. +
+ +
+

Note: This works to change the browser's locale, even if you haven't got the language pack installed for that language. You'll just get the browser UI in your default language if this is the case.

+
+ +
    +
+ +

Load the extension temporarily from disk again, then test your new locale:

+ + + +

{{EmbedYouTube("R7--fp5pPGg")}}

diff --git a/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/author/index.html b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/author/index.html new file mode 100644 index 0000000000..a99d8438e8 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/author/index.html @@ -0,0 +1,44 @@ +--- +title: 作者 +slug: Mozilla/Add-ons/WebExtensions/manifest.json/author +translation_of: Mozilla/Add-ons/WebExtensions/manifest.json/author +--- +
+
{{AddonSidebar}}
+ + + + + + + + + + + + + + + + +
型別String
強制No
範例 +
+"author": "cool puppy"
+
+ +

套件作者,用來顯示在瀏覽器的用戶介面中。如果有提供 developer 鍵而且裡面包含 "name" 屬性,那會覆蓋author鍵。不能指定多個作者。

+ +

這是一個可侷限的屬性

+
+ +

 

+ +

範例

+ +
"author": "cool puppy"
+ +

瀏覽器兼容

+ + + +

{{Compat("webextensions.manifest.author")}}

diff --git a/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/background/index.html b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/background/index.html new file mode 100644 index 0000000000..d02b6eb600 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/background/index.html @@ -0,0 +1,93 @@ +--- +title: background +slug: Mozilla/Add-ons/WebExtensions/manifest.json/background +tags: + - 擴充套件 +translation_of: Mozilla/Add-ons/WebExtensions/manifest.json/background +--- +
+
{{AddonSidebar}}
+ + + + + + + + + + + + + + + + +
型別Object
強制No
範例 +
+"background": {
+  "scripts": ["background.js"]
+}
+
+ +

background 鍵來引入一個或多個後端腳本,還有一個選擇性的套件後端頁面。

+ +

後端腳本是用來放置一些需要維護長期狀態或是進行長期操作的程式碼,它麼的生命週期跟任何網頁或瀏覽器視窗是獨立的。

+ +

後端腳本會在套件一被讀取就被讀入,一直到套件被禁用或移除才會卸載。只要你有請求對應的權限你可以在這個腳本裡使用任何擴充套件 APIs。

+ +

更多細節,查看套件解析的"後端頁面"章節。

+ +

background 鍵是一個物件,可能包含下列二屬性其中之一,兩者都是選擇性的:

+ + + + + + + + + + + + +
"scripts" +

一個字串組成的陣列,每個都是 JavaScript 原始碼的路徑。路徑是 manifest.json 檔案自身的相對路徑。這些是會被套件讀取的後端腳本。

+ +

腳本共用全局 window

+ +

腳本根據陣列裡的順序讀入。

+ +

註:Firefox 版本50以前有一個錯誤 當 Firefox 除錯器開啓時,腳本並不總是按照陣列裡的順序讀入。要解決這個錯誤,你可以用 "page" 屬性並且在頁面中透過 <script> 標籤讀入後端腳本。這個錯誤在 Firefox 50 被修正,從那開始腳本總是會依照陣列中的順序讀入。

+ +
+

註: 如果你想要用<script>標籤從遠端取得一個腳本(例如 <script src = "https://code.jquery.com/jquery-1.7.1.min.js">),你必須要修改套件 manifest.json 中的 content_security_policy 鍵。

+
+
"page" +

如果你指定 "scripts",那麼爲了讓你的腳本執行一個空白頁面會被建立。

+ +

如果頁面中需要某些內容,你可以用 "page" 選項定義自己的頁面。

+ +

如果你用了這個屬性,你就不能透過 "scripts" 來指定後端腳本。但是你可以像一般的網頁一樣在頁面中引入你自己的腳本。

+
+ +

範例

+ +
  "background": {
+    "scripts": ["jquery.js", "my-background.js"]
+  }
+ +

讀取兩個後端腳本。

+ +
"background": {
+    "page": "my-background.html"
+  }
+ +

讀取一個自訂的後端頁面。

+ +

瀏覽器兼容

+
+ + + +

{{Compat("webextensions.manifest.background", 10)}}

diff --git a/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/browser_specific_settings/index.html b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/browser_specific_settings/index.html new file mode 100644 index 0000000000..7a96adfecc --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/browser_specific_settings/index.html @@ -0,0 +1,88 @@ +--- +title: applications +slug: Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings +tags: + - 擴充套件 +translation_of: Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings +--- +
+
{{AddonSidebar}}
+ + + + + + + + + + + + + + + + +
型別Object
強制通常是不強制(請看你什麼時候會需要 Add-on ID?)。在 Firefox 48(桌面)前以及Android版Firefox 是強制的。
範例 +
+"applications": {
+  "gecko": {
+    "id": "addon@example.com",
+    "strict_min_version": "42.0"
+  }
+}
+
+ +

敘述

+ +

applications 鍵包含了詳細描述特定應用的鍵。

+ +

目前這只包含了一個鍵,gecko,它包含4個string參數:

+ + + +

查看可用Gecko版本

+ +

套件ID格式

+ +

套件ID格式必須是下列其中一種:

+ + + +

後者比較容易產生與操作。小心,在這裡使用真實信箱地址可能會引來垃圾信件。

+ +

例如:

+ +
"id": "extensionname@example.org",
+
+"id": "{daf44bf7-a45e-4450-979c-91cf07434c3d}"
+ +

 

+ +

範例

+ +

包含所有可用鍵的範例。註:大多數套件會忽略 strict_max_versionupdate_url

+ +
"applications": {
+  "gecko": {
+    "id": "addon@example.com",
+    "strict_min_version": "42.0",
+    "strict_max_version": "50.*",
+    "update_url": "https://example.com/updates.json"
+  }
+}
+ +

瀏覽器兼容

+
+ + + +

{{Compat("webextensions.manifest.browser_specific_settings")}}

diff --git a/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/homepage_url/index.html b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/homepage_url/index.html new file mode 100644 index 0000000000..4a9b065496 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/homepage_url/index.html @@ -0,0 +1,46 @@ +--- +title: homepage_url +slug: Mozilla/Add-ons/WebExtensions/manifest.json/homepage_url +tags: + - 擴充套件 +translation_of: Mozilla/Add-ons/WebExtensions/manifest.json/homepage_url +--- +
+
{{AddonSidebar}}
+ + + + + + + + + + + + + + + + +
型別String
強制No
範例 +
+"homepage_url": "https://example.org/my-addon"
+
+ +

套件首頁的URL。

+ +

如果有 developer 鍵且它包含 "url" 屬性,這會覆蓋 homepage_url 鍵。

+ +

這是一個可侷限的屬性

+ +

範例

+ +
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/beastify"
+ +

瀏覽器兼容性

+
+ + + +

{{Compat("webextensions.manifest.homepage_url")}}

diff --git a/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/index.html b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/index.html new file mode 100644 index 0000000000..23eda6a41c --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/index.html @@ -0,0 +1,113 @@ +--- +title: manifest.json +slug: Mozilla/Add-ons/WebExtensions/manifest.json +tags: + - Add-ons + - Extensions + - NeedsTranslation + - TopicStub + - WebExtensions +translation_of: Mozilla/Add-ons/WebExtensions/manifest.json +--- +
{{AddonSidebar}}
+ +

manifest.json 是所有採用 WebExtension API 的擴充功能中、唯一一個必須包含的檔案。

+ +

你可透過 manifest.json 為擴充功能指定名稱(name)、版本(version)這類的基本元資料(metadata),也可指定擴充功能的一些相關功能,例如像是背景腳本(background scripts)、內容腳本(content scripts)、瀏覽器動作(browser actions)等等。

+ +

這是個採用 JSON 格式的檔案,但有個例外:它可接受含有 "//" 這種格式的註解文字。

+ +

manifest.json 可採用的鍵值如下所列:

+ +
{{ ListSubpages ("/en-US/Add-ons/WebExtensions/manifest.json") }}
+ +
 
+ +

"manifest_version""version" 和 "name" 是一定要設定的鍵值。另外,如果有設定 "_locales" directory ,就一定要設定 "default_locale" ,否則就是這兩個鍵值都不做設定。 Google Chrome, 並不支援 "applications" ,但針對 Firefox 48 之前及 Android 的版本,則必須設置這個鍵值。

+ +

你可透過擴充功能中的 JavaScript,藉由 {{WebExtAPIRef("runtime.getManifest()")}} 這個函式來存取擴充功能裡的 manifest :

+ +
browser.runtime.getManifest().version;
+ +

範例

+ +

以下程式碼顯示的是一般 manifest 鍵值的基本語法。請注意,這個範例並不是讓你用來直接複製貼上的,你必須根據所開發的擴充功能,填入相應的鍵值、關於擴充功能的完整範例,請參見 擴充功能範例

+ +
{
+  "applications": {
+    "gecko": {
+      "id": "addon@example.com",
+      "strict_min_version": "42.0"
+    }
+  },
+
+  "background": {
+    "scripts": ["jquery.js", "my-background.js"],
+    "page": "my-background.html"
+  },
+
+  "browser_action": {
+    "default_icon": {
+      "19": "button/geo-19.png",
+      "38": "button/geo-38.png"
+    },
+    "default_title": "Whereami?",
+    "default_popup": "popup/geo.html"
+  },
+
+  "commands": {
+    "toggle-feature": {
+      "suggested_key": {
+        "default": "Ctrl+Shift+Y",
+        "linux": "Ctrl+Shift+U"
+      },
+      "description": "Send a 'toggle-feature' event"
+    }
+  },
+
+  "content_security_policy": "script-src 'self' https://example.com; object-src 'self'",
+
+  "content_scripts": [
+    {
+      "exclude_matches": ["*://developer.mozilla.org/*"],
+      "matches": ["*://*.mozilla.org/*"],
+      "js": ["borderify.js"]
+    }
+  ],
+
+  "default_locale": "en",
+
+  "description": "...",
+
+  "icons": {
+    "48": "icon.png",
+    "96": "icon@2x.png"
+  },
+
+  "manifest_version": 2,
+
+  "name": "...",
+
+  "page_action": {
+    "default_icon": {
+      "19": "button/geo-19.png",
+      "38": "button/geo-38.png"
+    },
+    "default_title": "Whereami?",
+    "default_popup": "popup/geo.html"
+  },
+
+  "permissions": ["webNavigation"],
+
+  "version": "0.1",
+
+  "web_accessible_resources": ["images/my-image.png"]
+}
+ +

瀏覽器相容性

+ +

若想對所有的 manifest 鍵值及其子健有個完整的概念,可參見 完整 manifest.json 瀏覽器相容表

+ + + +

{{Compat("webextensions.manifest")}}

diff --git a/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/options_ui/index.html b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/options_ui/index.html new file mode 100644 index 0000000000..7a376817f1 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/manifest.json/options_ui/index.html @@ -0,0 +1,110 @@ +--- +title: options_ui +slug: Mozilla/Add-ons/WebExtensions/manifest.json/options_ui +tags: + - 擴充套件 +translation_of: Mozilla/Add-ons/WebExtensions/manifest.json/options_ui +--- +
+
{{AddonSidebar}}
+ + + + + + + + + + + + + + + + +
型別Object
強制No
範例 +
+"options_ui": {
+  "page": "options/options.html"
+}
+
+ +

options_ui 鍵來定義套件的選項頁面

+ +

選項頁面包含了套件的設定。用戶可以從套件管理員進入這個畫面,而你可以用{{WebExtAPIRef("runtime.openOptionsPage()")}}打開它。

+ +

指定 options_ui 爲一個與套件打包在一起的HTML檔案路徑。就像一般的網頁一樣,HTML檔案可包含CSS與JavaScript檔案。跟普通頁面不同的是,它可以使用所有被授權套件APIs。 不過,它執行的作用域不同於你的後端腳本。

+ +

如果你想在選項頁面後端腳本的JavaScript裡共用資料或函數,你可以透過用{{WebExtAPIRef("extension.getBackgroundPage()")}}與後端腳本的 Window 關聯、用{{WebExtAPIRef("extension.getViews()")}}與任何套件內腳本的{{domxref("Window")}}關聯來實現。你也可以透過 runtime.sendMessage()runtime.onMessage,跟(或)runtime.connect()在選項頁面與後端的頁面的JavaScript之間溝通。
+ 後者(或是runtime.Port)也可以用來在後端腳本內容腳本之間共用選項。

+ +

一般要儲存選項頁面的選項變動時,你要可能會用 storage APIstorage.sync(如果你想要在所有用戶登入的瀏覽器實例之間同步設定的話),或者透過 storage.local (如果設定是針對目前身份或機器)。而如果你希望你的後端腳本(或內容腳本)監聽該變化,你可以加上 storage.onChanged 監聽器。

+ +

語法

+ +

options_ui 鍵是一個包含了下列內容的物件:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
browser_styleBoolean +

可選,預設爲 true

+ +

用這個來替你的頁面引入一個樣式表,使你的頁面與瀏覽器UI以及其他用 browser_style 的套件看起來一致。雖然它預設是true還是建議你加入這個屬性。

+ +

在 Firefox 裡,樣式表可以在 chrome://browser/content/extension.css 或 chrome://browser/content/extension-mac.css(OS X)查看。設定尺寸的時候注意到這個樣式表目前會做這個設定box-sizing: border-box (查看 box-sizing)。

+ +

Firefox風格指南寫到一些你可以應用到彈出視窗裡面的元素上來變成特定樣式的class。

+
open_in_tabBoolean +

可選,預設爲 false

+ +

如果設爲 true,選項頁面會在普通的瀏覽器頁籤開啓而不是整合在瀏覽器的套件管理員裡。

+
pageString +

強制。

+ +

包含選項頁面細項的HTML檔案路徑。

+ +

這個路徑是 manifest.json 的相對路徑。

+
+ +

範例

+ +
  "options_ui": {
+    "page": "options/options.html"
+  }
+ +

瀏覽器兼容性

+
+ + + +

{{Compat("webextensions.manifest.options_ui")}}

+ +

See also

+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/user_interface/browser_action/index.html b/files/zh-tw/mozilla/add-ons/webextensions/user_interface/browser_action/index.html new file mode 100644 index 0000000000..afdf61f340 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/user_interface/browser_action/index.html @@ -0,0 +1,50 @@ +--- +title: 工具列按鈕 +slug: Mozilla/Add-ons/WebExtensions/user_interface/Browser_action +tags: + - 擴充套件 +translation_of: Mozilla/Add-ons/WebExtensions/user_interface/Browser_action +--- +
{{AddonSidebar}}
+ +

根據工具列按鈕,這個用戶介面是一個加到瀏覽器工具列的按鈕。用戶透過點擊按鈕來與你的套件互動。
+

+ +

工具列按鈕與網址列按鈕非常相似。關於差別以及何時該使用的指引,詳閱工具列按鈕。

+ +

詳細指定工具列按鈕

+ +

透過在 manifest.json 中使用 browser_action 鍵來定義工具列按鈕的屬性:

+ +
"browser_action": {
+  "default_icon": {
+    "19": "button/geo-19.png",
+    "38": "button/geo-38.png"
+  },
+  "default_title": "我在哪?"
+}
+ +

唯一一個強制的鍵只有 default_icon

+ +

指定工具列按鈕的方式有兩種: 有彈出視窗跟沒有彈出視窗。如果你不指定彈出視窗,當用戶點擊按鈕事件會被傳送到套件,而套件透過 browserAction.onClicked 監聽:

+ +
browser.browserAction.onClicked.addListener(handleClick);
+ +

如果你指定彈出視窗,點擊事件不會被傳送,取而代之當用戶點擊按鈕時彈出視窗會被展開。用戶可以跟彈出視窗互動且當用戶點擊了彈出視窗外側它會自動關閉。更多建立與管理彈出視窗的細節請查看彈出視窗文章。

+ +

註: 你的套件只能有一個工具列按鈕。

+ +

你可以透過 browserAction API 程式化地更改任何工具列按鈕的屬性。

+ +

圖示

+ +

更多關於建立工具列按鈕使用的圖示,請查看文件光子設計系統裡的圖示學

+ +

範例

+ +

GitHub上的擴充套件範例程式庫包含兩個建立工具列按鈕的範例:

+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/user_interface/context_menu_items/index.html b/files/zh-tw/mozilla/add-ons/webextensions/user_interface/context_menu_items/index.html new file mode 100644 index 0000000000..949ec58b74 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/user_interface/context_menu_items/index.html @@ -0,0 +1,54 @@ +--- +title: 快捷選單項 +slug: Mozilla/Add-ons/WebExtensions/user_interface/Context_menu_items +tags: + - 擴充套件 +translation_of: Mozilla/Add-ons/WebExtensions/user_interface/Context_menu_items +--- +
{{AddonSidebar}}
+ +
+

這個用戶介面添加一個或多個項目到瀏覽器的快捷選單。這是用戶在網頁上點擊右鍵時出現的選單。頁籤也可以透過 browser.menus API 使用快捷選單。

+ +

Example of content menu items added by a WebExtension, from the context-menu-demo example

+ +

你可以用這個介面來顯示一些跟特定瀏覽器或網頁內容相關的功能。舉例來說,當用戶在圖片上按右鍵時提供圖片編輯器的功能或者在反白內容上按右鍵時提供儲存頁面內容的功能。你可以對選單添加普通的選單項目、核取方塊、單選按鈕組以及分隔線。選單項目透過{{WebExtAPIRef("contextMenus.create")}}添加後透過它會顯示在所有瀏覽器頁籤,但是你可以透過{{WebExtAPIRef("contextMenus.remove")}}來移除它。

+ +

指定快捷選單項目

+ +

透過{{WebExtAPIRef("contextMenus")}} API可以程式化地管理快捷選單項目。然而,你必須請求 contextMenus 的權限才能使用這些API的好處。

+ +
"permissions": ["contextMenus"]
+ +

現在你可以在你套件的後端腳本處添加(修改/刪除)選單項目。建立一個選單項目你要指定 id,標題以及它應該隸屬於哪個選單:

+ +
browser.contextMenus.create({
+  id: "log-selection",
+  title: browser.i18n.getMessage("contextMenuItemSelectionLogger"),
+  contexts: ["selection"]
+}, onCreated);
+ +

接著你的套件會監聽選單項目的點擊。送出有關項目點擊、點擊環境以及發生點擊頁籤的資訊可以用來使用恰當的套件功能。

+ +
browser.contextMenus.onClicked.addListener(function(info, tab) {
+  switch (info.menuItemId) {
+    case "log-selection":
+      console.log(info.selectionText);
+      break;
+    ...
+  }
+})
+ +

圖示

+ +

更多關於建立快捷選單圖示的細節請查看文件光子設計系統圖示學

+ +

範例

+ +

GitHub上的webextensions-examples 程式庫包含了兩個建立快捷選單的範例:

+ + +
diff --git a/files/zh-tw/mozilla/add-ons/webextensions/user_interface/devtools_panels/index.html b/files/zh-tw/mozilla/add-ons/webextensions/user_interface/devtools_panels/index.html new file mode 100644 index 0000000000..fddea1b0e0 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/user_interface/devtools_panels/index.html @@ -0,0 +1,66 @@ +--- +title: 開發工具面板 +slug: Mozilla/Add-ons/WebExtensions/user_interface/devtools_panels +tags: + - 初學者 + - 擴充套件 + - 教學 + - 用戶介面 +translation_of: Mozilla/Add-ons/WebExtensions/user_interface/devtools_panels +--- +
{{AddonSidebar}}
+ +
+

Firefox 54 以後可以使用這個功能。

+
+ +

當套件提供開發者使用的工具時,可以以一個瀏覽器開發工具的新面板的形式在開發者工具裡添加一個UI。

+ +

Simple example showing the addition of "My panel" to the Developer Tools tabs.

+ +

指定開發工具面板

+ +

開發工具面板可以透過 devtools.panels API 添加,因此這必須在特別的開發工具頁面執行。

+ +

透過在套件的 manifest.json 添加 devtools_page 鍵並提供HTML檔案來添加開發工具頁面:

+ +
"devtools_page": "devtools-page.html"
+ +

在開發工具頁面,呼叫腳本會添加開發工具面板:

+ +
<body>
+  <script src="devtools.js"></script>
+</body>
+ +

在腳本裡,藉由指定面板標題、圖示、HTML檔案來建立開發工具:

+ +
function handleShown() {
+  console.log("panel is being shown");
+}
+
+function handleHidden() {
+  console.log("panel is being hidden");
+}
+
+browser.devtools.panels.create(
+  "My Panel",           // title
+  "icons/star.png",           // icon
+  "devtools/panel/panel.html"          // content
+).then((newPanel) => {
+  newPanel.onShown.addListener(handleShown);
+  newPanel.onHidden.addListener(handleHidden);
+});
+ +

套件現在可以在檢測器視窗透過 devtools.inspectedWindow.eval() 或透過後端腳本傳送訊息來插入內容腳本兩種方式執行。你可以在擴充開發者工具找到更多相關訊息。

+ +

開發面板設計

+ +

更多關於如何設計符合 Firefox 風格的開發者面板,請查看文件光子設計系統

+ +

圖示

+ +

更多關於建立開發者工具面板圖示的細節,請查看文件光子設計系統圖示學

+ +

範例

+ +

GitHub上的 webextensions-examples 程式庫包含了建立開發工具面板的 devtools-panels 範例。

diff --git a/files/zh-tw/mozilla/add-ons/webextensions/user_interface/index.html b/files/zh-tw/mozilla/add-ons/webextensions/user_interface/index.html new file mode 100644 index 0000000000..5c8e40bcdd --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/user_interface/index.html @@ -0,0 +1,94 @@ +--- +title: 用戶介面 +slug: Mozilla/Add-ons/WebExtensions/user_interface +tags: + - 擴充套件 + - 用戶介面 +translation_of: Mozilla/Add-ons/WebExtensions/user_interface +--- +
{{AddonSidebar}}
+ +

套件APIs 提供了幾種介面來完成對用戶的功能。下方是那些介面的概述,每種用戶介面都有更詳細的資訊可以查閱。

+ +
+

爲了使用這些UI元件在套件裡提供優秀的用戶體驗,建議閱讀用戶體驗最佳實踐文章。

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

可用介面

+
敘述範例
工具列按鈕一個瀏覽器工具列上的按鈕,被點擊時會送出事件給套件。預設的情況下在所有頁籤都能看到此按鈕。Example showing a toolbar button (browser action).
附帶彈出視窗的工具列按鈕一個按鈕上的彈出視窗,當按鈕被點擊時展開。彈出視窗被一個HTML文件來定義。Example of the pop-up on a toolbar button
網址列按鈕一個網址列上的按鈕,點擊時傳送事件給套件。預設的情況下,在所有的頁籤中此按鈕都會被隱藏。Example showing an address bar button (page action)
附帶彈出視窗的網址列按鈕網址列按鈕上的一個按鈕,當按鈕被點擊時展開,彈出視窗被一個HTML文件來定義。Example of a popup on the address bar button
快捷選單在一個或多個瀏覽器快捷選單中的選單項目、核取方塊、選項按鈕。另外,選單可以透過增加分隔線來組成。當選單項目被點擊時傳送一個事件給套件。Example of content menu items added by a WebExtension, from the context-menu-demo example
側邊欄 +

一個顯示在網頁旁邊的HTML文件,每頁可以顯示獨立的內容。側邊欄會在用戶安裝套件時打開,然後根據用戶對側邊欄的可視選項開關。側邊欄裡的用戶互動由它的HTML文件來控制。

+
Example of a sidebar
選項頁面一個使你可以定義用戶能修改的偏好設定的頁面。用戶可以透過瀏覽器的套件管理畫面進到這裡。Example showing the options page content added in the favorite colors example.
套件頁面透過套件裡的網頁來在視窗或頁籤內提供表單、幫助訊息或任何需要的內容。Example of a simple bundled page displayed as a detached panel.
通知透過作業系統的機制顯示的短暫的通知。當用戶點擊通知或通知關閉時(不論自動關閉或用戶手動關閉)時傳送事件給套件。Example of an extension triggered system notification
網址列建議當用戶輸入關鍵字時提供自訂的網址列建議。Example showing the result of the firefox_code_search WebExtension's customization of the address bar suggestions.
開發者工具面板一個包含相關HTML文件的頁籤顯示在瀏覽器的開發者工具裡。Example showing the result of the firefox_code_search WebExtension's customization of the address bar suggestions.
+ +

下面是一些關於建立這些用戶介面的詳細教學:

+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/user_interface/sidebars/index.html b/files/zh-tw/mozilla/add-ons/webextensions/user_interface/sidebars/index.html new file mode 100644 index 0000000000..923cd9d14f --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/user_interface/sidebars/index.html @@ -0,0 +1,55 @@ +--- +title: 側邊欄 +slug: Mozilla/Add-ons/WebExtensions/user_interface/Sidebars +tags: + - 擴充套件 +translation_of: Mozilla/Add-ons/WebExtensions/user_interface/Sidebars +--- +
{{AddonSidebar}}
+ +
+

側邊欄是一個顯示在瀏覽器視窗上、網頁旁邊的面板。瀏覽器提供能讓用戶看見目前可用的側邊欄並且擇一顯示的UI。例如,Firefox 有一個 "檢視 > 側邊欄" 的選單。一次只能有一個側邊欄顯示,而那個側邊欄會顯示在所有的頁籤以及瀏覽器視窗。

+ +

瀏覽器可能包含了一些內建的側邊欄。例如,Firefox 包含了一個可以跟書籤互動的側邊欄:

+ +

在 manifest.json 裡用 sidebar_action 鍵可以替瀏覽器添加側邊欄。它會被列在內建的側邊欄旁邊,而用戶可以透過與內建側邊欄一模一樣的機制來打開它。

+ +

就像工具列按鈕一樣,你藉由HTML文件指定側邊欄的內容。當用戶打開側邊欄,側邊欄的文件會被讀取到每個開著的瀏覽器視窗。每個視窗都各自獲取文件的實例,當新的視窗被開啓,他們也會獲取自己的側邊欄實例。

+ +

你可以用{{WebExtAPIRef("sidebarAction.setPanel()")}}函數設置某個頁籤專屬的文件。側邊欄會透過{{WebExtAPIRef("windows.getCurrent()")}} API找出它隸屬的視窗 :

+ +
// sidebar.js
+browser.windows.getCurrent({populate: true}).then((windowInfo) => {
+  myWindowId = windowInfo.id;
+});
+ +

如果側邊欄要在不同的視窗顯示不同內容這會很有用。範例請看 "annotate-page" 範例

+ +

側邊欄文件與後端腳本以及彈出視窗享有一樣的權限。他們可以透過{{WebExtAPIRef("runtime.getBackgroundPage()")}}直接讀取後端頁面(只要側邊欄隸屬於隱私模式的視窗),並且可以透過一些 messaging APIs 與內容腳本或原生應用互動,像是{{WebExtAPIRef("tabs.sendMessage()")}}與{{WebExtAPIRef("runtime.sendNativeMessage()")}}。

+ +

側邊欄文件會在瀏覽器視窗關閉或用戶關閉側邊欄時被卸載。這代表不像後端腳本,側邊欄文件並不總是保持讀入的狀態。但是不像工具列按鈕,他們可以在用戶與網頁互動時保持讀入。

+ +

當定義著側邊欄的套件被首次安裝時,側邊欄2會自動開啓。這是爲了幫助用戶瞭解這個套件包含了一個側邊欄。註:套件無法程式化地開啓側邊欄,側邊欄只能由用戶開啓。

+ +

指定側邊欄

+ +

要指定側邊欄,在 manifest.json 裡透過 sidebar_action 鍵定義文件、標題以及圖示:

+ +
"sidebar_action": {
+  "default_title": "My sidebar",
+  "default_panel": "sidebar.html",
+  "default_icon": "sidebar_icon.png"
+}
+ +

你可以透過{{WebExtAPIRef("sidebarAction")}} API程式化地更改標題、面板以及圖示。

+ +

標題與圖示會在任一個瀏覽器提供的UI中顯示,像是 Firefox 裡的 "檢視 > 側邊欄" 選單。

+ +

側邊欄設計

+ +

更多如何設計符合 Firefox 風格的側邊欄網頁細節,請查看文件光子設計系統

+ +

範例

+ +

GitHub上的 webextensions-examples 程式庫包含了建立側邊欄的 annotate-page 範例。

+
diff --git a/files/zh-tw/mozilla/add-ons/webextensions/what_are_webextensions/index.html b/files/zh-tw/mozilla/add-ons/webextensions/what_are_webextensions/index.html new file mode 100644 index 0000000000..6494e50a5f --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/what_are_webextensions/index.html @@ -0,0 +1,26 @@ +--- +title: 何謂附加元件? +slug: Mozilla/Add-ons/WebExtensions/What_are_WebExtensions +translation_of: Mozilla/Add-ons/WebExtensions/What_are_WebExtensions +--- +
{{AddonSidebar}}
+ +
 
+ +

附加元件(Add-ons)擴展並修改了瀏覽器的功能。他們使用標準的網路技術──JavaScript、HTML、以及 CSS、還有一些專用的 JavaScript API──寫成。除此之外,附加元件可以給瀏覽器添加新功能、或是改變特定網站的外觀或內容。

+ +

Firefox的附加元件開發基於能跨瀏覽器的 WebExtensions APIs ,在很大的程度上相容於和 Google Chrome 與 Opera 瀏覽器所支持的 extension API  。大多數情況下,針對這些瀏覽器所撰寫的 Extension 只要些許修改就能在 Firefox 或是 Microsoft Edge 執行,也與 multiprocess Firefox 完全相容。

+ +

在過去,你可以使用三種系統開發 Firefox 附加元件: XUL/XPCOM overlaysbootstrapped extensions、或是 Add-on SDK。但2017年11月底之後,WebExtensions 將成為唯一開發 Firefox 附加元件的方式,而其他方式會被廢棄。

+ +

如果你有任何想法或問題,甚至是需要協助轉換舊附加元件到新系統,你可以在 dev-addons mailing listIRC#webextensions 找到我們。

+ +

 

+ +

接下來呢?

+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/your_first_webextension/index.html b/files/zh-tw/mozilla/add-ons/webextensions/your_first_webextension/index.html new file mode 100644 index 0000000000..7e4f37423e --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/your_first_webextension/index.html @@ -0,0 +1,150 @@ +--- +title: 你的第一個 WebExtension +slug: Mozilla/Add-ons/WebExtensions/Your_first_WebExtension +translation_of: Mozilla/Add-ons/WebExtensions/Your_first_WebExtension +--- +
{{AddonSidebar}}
+ +

我們會在這篇文章詳細講解 Firefox 的 WebExtension 的製作。這支附加元件會在 "mozilla.org" 網域底下的所有網頁,增加紅色外框。

+ +

範例的原始碼也放在 GitHub 喔:https://github.com/mdn/webextensions-examples/tree/master/borderify

+ +

首先勒,你需要 Firefox 45.0 或以上的版本。

+ +

撰寫 WebExtension

+ +

新增一個資料夾,然後進到裡面:

+ +
mkdir borderify
+cd borderify
+ +

manifest.json

+ +

現在新增一個檔案 "manifest.json",直接放在 "borderify" 目錄底下就行,然後把下面的程式碼塞進去:

+ +
{
+
+  "manifest_version": 2,
+  "name": "Borderify",
+  "version": "1.0",
+
+  "description": "Adds a red border to all webpages matching mozilla.org.",
+
+  "icons": {
+    "48": "icons/border-48.png"
+  },
+
+  "content_scripts": [
+    {
+      "matches": ["*://*.mozilla.org/*"],
+      "js": ["borderify.js"]
+    }
+  ]
+
+}
+ + + +

這裡最有趣的 key 是 content_scripts:它告訴 Firefox 說:符合特定型態的 URL 會載入網頁的腳本。在此我們告訴 Firefox 說:所有由 "mozilla.org" 或其子域名服務的 HTTP 或 HTTPS 頁面,都要載入 "borderify.js"。

+ + + +
+

某些情況下,你需要給附加元件指定 ID。如果需要指定附加元件 ID,請在 manifest.json 引入 applications key,並設定 gecko.id 屬性:

+ +
"applications": {
+  "gecko": {
+    "id": "borderify@example.com"
+  }
+}
+
+ +

icons/border-48.png

+ +

附加元件要有一個圖標。它會在附加元件管理員的附加元件清單旁邊列出來。我們的 manifest.json 已經說好了,要在 "icons/border-48.png" 那邊會有個圖標。

+ +

在 "borderify" 目錄下直接建立 "icons" 目錄,並儲存一個叫 "border-48.png" 的圖標檔。你可以用範例的這張圖標,它是從 Google Material Design 圖標集抓下來的,並使用創用 CC:姓名標示-相同方式分享授權。

+ +

如果你要用自己的圖標,它應該是 48x48 像素。你也可以針對高解析度提供 96x96 像素的圖標,這樣的話它在 manifest.json 會被指定為 icons 物件內的 96 property:

+ +
"icons": {
+  "48": "icons/border-48.png",
+  "96": "icons/border-96.png"
+}
+ +

要不然,你也能提供 SVG 檔,它就會等比縮放。

+ + + +

borderify.js

+ +

最後,新增一個檔案叫 "borderify.js",直接放在 "borderify" 目錄底下即可,然後一樣把下面的 code 塞進去:

+ +
document.body.style.border = "5px solid red";
+ +

一旦網址符合 manifest.json 中 content_scripts 所設定的模式,這段 script 就會載入,並且就像該頁自己讀入的程式碼一樣、能夠直接存取該頁上的東西。

+ + + +

測試看看

+ +

首先,仔細檢查這些檔案是否在正確的位置:

+ +
borderify/
+    icons/
+        border-48.png
+    borderify.js
+    manifest.json
+ +

安裝

+ +

在 Firefox 打開 about:debugging,點選 Load Temporary Add-on 然後選擇你的 manifest.json 檔案:

+ +

{{EmbedYouTube("cer9EUKegG4")}}

+ +

現在這個附加元件就要安裝起來,但它要在你重新啟動 Firefox 後才開始。

+ +

又或者,你可以從命令列利用 web-ext 工具執行 WebExtension。

+ +

測試

+ +

現在去看一下 mozilla.org 還有它下面的所有網頁。你應該會看到有個紅色外框圍繞著網頁。

+ +

{{EmbedYouTube("rxBQl2Z9IBQ")}}

+ +
+

不過,別把這招用在 addons.mozilla.org 上,該網域目前會阻擋 content scripts。

+
+ +

再做點小實驗吧。改一下腳本讓外框顏色改變,或是做其他更動。接著存檔,並按下 about:debugging 的 Reload 鍵重啟附加元件。現在你能看到更動了:

+ +

{{EmbedYouTube("NuajE60jfGY")}}

+ + + +

打包並發送

+ +

想讓別人用你的附加元件,就要把元件遞交給 Mozilla 簽署之。想獲得更多資訊,請參見 發布你的 WebExtension

+ +

接下來咧?

+ +

現在你針對 Firefox 的 WebExtension 開發有點子的話,來看看:

+ + diff --git a/files/zh-tw/mozilla/add-ons/webextensions/your_second_webextension/index.html b/files/zh-tw/mozilla/add-ons/webextensions/your_second_webextension/index.html new file mode 100644 index 0000000000..403eff4aa7 --- /dev/null +++ b/files/zh-tw/mozilla/add-ons/webextensions/your_second_webextension/index.html @@ -0,0 +1,368 @@ +--- +title: 你的第二個 WebExtension +slug: Mozilla/Add-ons/WebExtensions/Your_second_WebExtension +translation_of: Mozilla/Add-ons/WebExtensions/Your_second_WebExtension +--- +

{{AddonSidebar}}

+ +

假如你已經讀過了 你的第一個 WebExtension,你也已經知道該如何寫一個 extension(外掛),在這篇文章中我們將會教你寫一個稍微複雜一點的 extension,來 demo 一些 API 的使用。

+ +

在這個 extension 中,將會新增一個按鈕到 Firefox 的工具列上,當使用者按下按鈕後,將會顯示一個彈出視窗 (pop-up) 並可選擇一個動物。當使用者選擇了一個動物後,將會在當前的網頁中顯示使用者所選的動物圖片。

+ +

為了實作這個,我們將需要:

+ + + +

下面是這次 extension 的流程圖:

+ +

+ +

這個一個簡單的 extension,但是會教你許多基本的 WebExtensions API 的概念:

+ + + +

也可以在 GitHub 上找到範例的原始碼: https://github.com/mdn/webextensions-examples/tree/master/beastify

+ +

實作這個 extension 前,請先確認你的 Firefox 有 45.0 或更新的版本。

+ +

實作 extension

+ +

新增一個資料夾,然後進去:

+ +
mkdir beastify
+cd beastify
+ +

manifest.json

+ +

在資料夾 "beastify" 下新增一個檔案,並命名為 "manifest.json",然後撰寫以下程式碼。

+ +
{
+
+  "manifest_version": 2,
+  "name": "Beastify",
+  "version": "1.0",
+
+  "description": "Adds a browser action icon to the toolbar. Click the button to choose a beast. The active tab's body content is then replaced with a picture of the chosen beast. See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Examples#beastify",
+  "homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/beastify",
+  "icons": {
+    "48": "icons/beasts-48.png"
+  },
+
+  "permissions": [
+    "activeTab"
+  ],
+
+  "browser_action": {
+    "default_icon": "icons/beasts-32.png",
+    "default_title": "Beastify",
+    "default_popup": "popup/choose_beast.html"
+  },
+
+  "web_accessible_resources": [
+    "beasts/frog.jpg",
+    "beasts/turtle.jpg",
+    "beasts/snake.jpg"
+  ]
+
+}
+
+ + + +

所有的路徑都會關連到 manifest.json 。

+ +

The icon

+ +

一個 extension 應該要有一個 icon。icon 將會顯示在 Add-ons Manager 的 extension 列表中。(在 Firefox 網址列輸入 "about:addons" 開啟 Add-ons Manager)。

+ +

在 beastify 下建立一個名為 "icons" 的資料夾,並準備一個命名為 "beasts-48.png" 的 icon並存在 "beastify/icons" 的資料夾中(可以使用我們的範例圖檔,圖檔來源:Free Retina Icon Set,遵照使用條款來使用)。並在 manifest.json 裡告訴他要使用 "icons/beasts-48.png" 路徑下的 icon。

+ +

如果你想要使用自己的 icon,icon 大小必須是  48x48 pixels,另外也可使用 96x96 pixel 來支援較高解析度的顯示。

+ +
"icons": {
+  "48": "icons/beasts-48.png",
+  "96": "icons/beasts-96.png"
+}
+ +

工具列按鈕(The toolbar button)

+ +

工具列按鈕也需要一個 icon,在 manifest.json 裡 "browser_action" 物件中的 "default_icon" 中告訴他要使用 "icons/beasts-32.png" 路徑下的 icon。。

+ +

準備一個命名為 "beasts-32.png" 的 icon,並存在 "beastify/icons" 資料夾中(你可以使用範例圖檔,圖檔來源:IconBeast Lite icon set,遵守使用條款來使用)。 

+ +

假設你不使用 pop-up,當按下按鈕的時候就會觸發事件。假如使用 pop-up ,當按下按鈕時並不會觸發事件,取而代之會打開 pop-up。不過這邊我們想要用 pop-up,所以接來下會教你如何新增他。

+ +

The popup

+ +

pop-up 的方法主要是讓使用者可以選擇三個動物中的其中一個。

+ +

在 beastify 下 新增一個名為 "popup" 的資料夾,該資料夾中會包含以下三個檔案:

+ + + +
mkdir popup
+cd popup
+touch choose_beast.html choose_beast.css choose_beast.js
+ +

choose_beast.html

+ +

HTML 內容長得像這樣:

+ +
<!DOCTYPE html>
+
+<html>
+  <head>
+    <meta charset="utf-8">
+    <link rel="stylesheet" href="choose_beast.css"/>
+  </head>
+
+<body>
+  <div id="popup-content">
+    <div class="button beast">Frog</div>
+    <div class="button beast">Turtle</div>
+    <div class="button beast">Snake</div>
+    <div class="button reset">Reset</div>
+  </div>
+  <div id="error-content" class="hidden">
+    <p>Can't beastify this web page.</p><p>Try a different page.</p>
+  </div>
+  <script src="choose_beast.js"></script>
+</body>
+
+</html>
+ +

我們在 ID 為 "popup-content"  的 <div>  元件裡建立了一個包含每種動物選項的元件。當載入 popup 發生問題時,用另外一個 ID 為 "error-content" 且類別定義為 "hidden"<div>  元件來處理。

+ +

值得注意的是我們在這個檔案裡引用了 CSS 與 JS 檔案,就如同一般網頁。

+ +

choose_beast.css

+ +

CSS 定義了 pop-up 的大小,並確保三個選項有填滿整個 pop-up,並給他們幾個基本的 style:

+ +
html, body {
+  width: 100px;
+}
+
+.button {
+  margin: 3% auto;
+  padding: 4px;
+  text-align: center;
+  font-size: 1.5em;
+  cursor: pointer;
+}
+
+.beast:hover {
+  background-color: #CFF2F2;
+}
+
+.beast {
+ background-color: #E5F2F2;
+}
+
+.clear {
+ background-color: #FBFBC9;
+}
+
+.clear:hover {
+ background-color: #EAEAC9;
+}
+
+ +

choose_beast.js

+ +

在 pop-up 的 JavaScript 中,我們監控著 click 事件。當按下其中一個選項後,將會讀取 js 檔到當前的瀏覽器分頁(active_tab)中,當內容腳本被讀取後,將會發送一個訊息告訴他該選擇哪一張圖片。

+ +
/*
+Given the name of a beast, get the URL to the corresponding image.
+*/
+function beastNameToURL(beastName) {
+  switch (beastName) {
+    case "Frog":
+      return browser.extension.getURL("beasts/frog.jpg");
+    case "Snake":
+      return browser.extension.getURL("beasts/snake.jpg");
+    case "Turtle":
+      return browser.extension.getURL("beasts/turtle.jpg");
+  }
+}
+
+/*
+Listen for clicks in the popup.
+
+If the click is on one of the beasts:
+  Inject the "beastify.js" content script in the active tab.
+
+  Then get the active tab and send "beastify.js" a message
+  containing the URL to the chosen beast's image.
+
+If it's on a button which contains class "clear":
+  Reload the page.
+  Close the popup. This is needed, as the content script malfunctions after page reloads.
+*/
+
+document.addEventListener("click", (e) => {
+  if (e.target.classList.contains("beast")) {
+    var chosenBeast = e.target.textContent;
+    var chosenBeastURL = beastNameToURL(chosenBeast);
+
+    browser.tabs.executeScript(null, {
+      file: "/content_scripts/beastify.js"
+    });
+
+    var gettingActiveTab = browser.tabs.query({active: true, currentWindow: true});
+    gettingActiveTab.then((tabs) => {
+      browser.tabs.sendMessage(tabs[0].id, {beastURL: chosenBeastURL});
+    });
+  }
+  else if (e.target.classList.contains("clear")) {
+    browser.tabs.reload();
+    window.close();
+  }
+});
+
+ +

這邊使用了三個 WebExtensions API 的方法:

+ + + +

內容腳本(The content script)

+ +

在 beastify 下建立一個名為 "content_scripts" 的資料夾,並新增一個命名為 "beastify.js" 的檔案,檔案裡的內容:

+ +
/*
+beastify():
+* removes every node in the document.body,
+* then inserts the chosen beast
+* then removes itself as a listener
+*/
+function beastify(request, sender, sendResponse) {
+  removeEverything();
+  insertBeast(request.beastURL);
+  browser.runtime.onMessage.removeListener(beastify);
+}
+
+/*
+Remove every node under document.body
+*/
+function removeEverything() {
+  while (document.body.firstChild) {
+    document.body.firstChild.remove();
+  }
+}
+
+/*
+Given a URL to a beast image, create and style an IMG node pointing to
+that image, then insert the node into the document.
+*/
+function insertBeast(beastURL) {
+  var beastImage = document.createElement("img");
+  beastImage.setAttribute("src", beastURL);
+  beastImage.setAttribute("style", "width: 100vw");
+  beastImage.setAttribute("style", "height: 100vh");
+  document.body.appendChild(beastImage);
+}
+
+/*
+Assign beastify() as a listener for messages from the extension.
+*/
+browser.runtime.onMessage.addListener(beastify);
+
+ +

內容腳本中新增了一個 listener ,使其從 extension 可傳送訊息。(具體來說是從 "choose_beast.js" 這邊) ,在 listener 中做了:

+ + + +

The beasts

+ +

最後,我們需要將動物的照片放進來

+ +

新增一個名為 "beasts" 的資料夾,並把三張動物的圖片放進此資料夾中,請取相對應的檔名。可以使用範例圖片 ,或從這邊下載:

+ +

+ +

Testing it out

+ +

首先,請再三的確認檔案有放到相對應的資料夾中:

+ +
beastify/
+
+    beasts/
+        frog.jpg
+        snake.jpg
+        turtle.jpg
+
+    content_scripts/
+        beastify.js
+
+    icons/
+        beasts-32.png
+        beasts-48.png
+
+    popup/
+        choose_beast.css
+        choose_beast.html
+        choose_beast.js
+
+    manifest.json
+ +

開啟 Firefox 45.0,並安裝本地的 extensive 到瀏覽器裡。

+ +

在 Firefox 網址列輸入 "about:debugging" ,點選 "Load Temporary Add-on",然後選擇你的 "manifest.json" 檔案。然後應該就會看到 extensive 的 icon 出現在工具列上了:

+ +

{{EmbedYouTube("sAM78GU4P34")}}

+ +

打開一個網頁,點選 icon,選擇一個動物的名字,將會看到網頁內容被動物的圖片取代了:

+ +

{{EmbedYouTube("YMQXyAQSiE8")}}

+ +

透過命令行佈署

+ +

你可以利用web-ext自動化暫時載入。
+ 試試看:

+ +
cd beastify
+web-ext run
diff --git a/files/zh-tw/mozilla/adding_phishing_protection_data_providers/index.html b/files/zh-tw/mozilla/adding_phishing_protection_data_providers/index.html new file mode 100644 index 0000000000..14b56484b5 --- /dev/null +++ b/files/zh-tw/mozilla/adding_phishing_protection_data_providers/index.html @@ -0,0 +1,66 @@ +--- +title: 新增偽造網站清單來源 +slug: Mozilla/Adding_phishing_protection_data_providers +tags: + - 待翻譯 +translation_of: Mozilla/Adding_phishing_protection_data_providers +--- +

詐騙網站偵測技術讓 Firefox 能將當前網頁與黑名單兩相比對,藉此得知此網站是否為詐騙網站,並於確認後提醒使用者。

+ +

安裝新資料來源

+ +

要安裝詐騙網站清單的資料來源,必須調整一些相關設定,以便提供資料來源的細節。

+ +

每個資料來源都有其獨一無二的 ID 號碼,而 ID 號碼為 0 者即是 Firefox 出廠時的預設資料來源。當安裝新的資料來源時,你應該指定另一個未使用的號碼。

+ +

要知道哪些號碼能用,必須以迴圈循序取出設定值,例如先是 browser.safebrowsing.provider.0.name、而後為browser.safebrowsing.provider.1.name,以此類推。當取值時無傳回內容,代表這個數字可以用。

+ +

你可以從為擴充套件新增偏好設定文章中找到讀寫設定值的相關範例。

+ +

必備設定

+ +
+
browser.safebrowsing.provider.idnum.name
+
資料來源的名稱,讓使用者方便識別。
+
+ +
+
browser.safebrowsing.provider.idnum.keyURL
+
用來為其他要求編碼的私鑰 URL。
+
+ +
+
browser.safebrowsing.provider.idnum.lookupURL
+
The URL to use to look up URLs to see if they're blacklisted. This request must be encrypted using the private key returned by the keyURL request.
+
+ +

選用設定

+ +
+
browser.safebrowsing.provider.idnum.reportURL
+
An URL used for reporting when users visit phishing pages and whether or not they decided to heed the warning or to ignore it.
+
+ +
+
browser.safebrowsing.provider.idnum.updateURL
+
An URL used to request an updated list of phishing sites. The server either provides a full list or incremental updates in order to bring the client's tables up to date.
+
+ +
+
browser.safebrowsing.provider.idnum.reportGenericURL
+
Not currently used; intended for use in reporting other issues with the phishing protection service.
+
+ +
+
browser.safebrowsing.provider.idnum.reportErrorURL
+
An URL to which the user is directed in order to report a safe page that is incorrectly being reported as a phishing site.
+
+ +
+
browser.safebrowsing.provider.idnum.reportPhishURL
+
An URL to which the user is directed in order to report a phishing site that isn't detected by the phishing protection system.
+
+ +

Determining the currently-selected data provider

+ +

If you need to determine the ID number of the currently selected anti-phishing data provider, you can look at the current value of the preference browser.safebrowsing.dataProvider.

diff --git a/files/zh-tw/mozilla/chrome_registration/index.html b/files/zh-tw/mozilla/chrome_registration/index.html new file mode 100644 index 0000000000..f2cde3f964 --- /dev/null +++ b/files/zh-tw/mozilla/chrome_registration/index.html @@ -0,0 +1,348 @@ +--- +title: Chrome registration +slug: Mozilla/Chrome_Registration +translation_of: Mozilla/Chrome_Registration +--- +

馬桶裡有個 chrome?

+ +

Chrome 是一拖拉庫在文件 window 範圍之外 AP 視窗的 UI 元件。 管它 Toolbars 、 menu bars、progress bars 還是 window title bars 基本上都是 chrome 的一部份。

+ +
+

Mozilla 會尋找並讀取主題佈景和附加元件根目錄的 chrome.manifest 檔。

+
+ +
+

古早的 Gecko 1.9.2 (及更古早版本),Mozilla 是從 AP 讀取chrome/*.manifest 檔。 從 Gecko 2.0 {{ geckoRelease("2.0") }} 開始,就只剩根目錄的 chrome.manifest 還有再用;若要增加更多的內容,就在其中利用 manifest 指令來擴充。

+
+ +

Chrome providers

+ +

基於某種 window type (例如針對 browser window) 提供 chrome 者稱為 chrome provider。所有的 provider 同心協力針對特定的 window 提供整套的 chrome,從工具列上的圖案到文字或內容描述檔,以及 window 本身的外觀。

+ +

以下是三種基本的 chrome provider :

+ +
+
Content
+
視窗描述主要是來自於 content provider,格式可以是任何一種 Mozilla 看得懂的類型。通常會是個  XUL file,因為它本來就是專門設計來描述 window 和 dialog 的。用來定義 UI 的 JavaScript 檔也會跟在這包,多數的 XBL binding files 也是。
+
Locale
+
多語系的應用程式會將語系資訊交給 locale providers。醬子譯者就可以翻譯並插進一個另外的 chrome package 而不去更動其它的程式。Java-style properties 檔和 DTD 檔是兩種主要的多語系檔案類型。
+
Skin
+
Skin provider 就負責 chrome 整套外觀的描述檔,通常是 CSS 和圖形。
+
+ +
+

註: 從 skin packages 載入的 scripts (包括 XBL 裡的) 並不會執行喔。

+
+ +

Chrome 登錄 (chrome registry)

+ +

Gecko runtime 會保持一份稱為 chrome registry 的記錄,用來對登錄 chrome package 名稱和實際檔案路徑。

+ +

Chrome registry 可以設定並且會保存;且有賴於 xpinstall 和 extension manager,這樣 user 就可以很多套 chrome provider 然後選擇喜歡的語系和外觀。

+ +

XULRunner application、主題布景或附加元件要讓 chrome registry 知道有這麼一個 chrome,那就要在自己的根目錄下放一個 純文字格式的 manifest,也就是 `chrome.manifest`。

+ +

這個純文字的 manifests 是簡單的逐行格式,會被一行一行地解析。 chrome registry 看懂一行就處理一行,看不懂就跳過;當然,有問題的會 log 在 console 中。

+ +
locale packagename localename path/to/files
+skin packagename skinname path/to/files
+
+ +

Firefox 2 、 Thunderbird 2 和 SeaMonkey 1.1 無法辨識大小寫夾雜的 packagename 。 要是把範例中的 packagename 改成 CamelCasePackage 就會跑出類似 "No chrome registered for chrome://camelcasepackage/path/to/files" 的訊息。 Firefox 3 、 Thunderbird 3 還有 SeaMonkey 2 已經支援這個功能。Bug resolved 於 Mozilla 1.9; see {{bug(132183)}}.

+ +

Manifest 指令

+ +

comments

+ +

如果一行的開頭是 '#' 那這整行就變成註解。

+ +
# this line is a comment - you can put whatever you want here
+
+ +

manifest

+ +

{{ gecko_minversion_inline("2.0b4") }}

+ +
manifest subdirectory/foo.manifest [flags]
+
+ +

這行會載入另一份 manifest 檔。這在拆分元件、chrome 登錄項或是各平台相依登錄資料時尤其有用。

+ +

binary-component

+ +

{{ gecko_minversion_inline("2.0b2") }}

+ +
binary-component components/mycomponent.dll [flags]
+
+ +

叫 Mozilla 登錄並應用 binary component,由於 binary components 為 ABI-specific,應與 abi flag 並用。 在 Firefox 4 之前 ,components 資料夾裡的檔案會自動被登錄。

+ +

interfaces

+ +

{{ gecko_minversion_inline("2.0b2") }}

+ +
interfaces component/mycomponent.xpt [flags]
+
+ +

叫 Mozilla 從經由 XPIDL 產生的 typelib 檔載入 interface 資訊。在 Firefox 4 之前,components 資料夾裡的檔案會自動被登錄。

+ +

component

+ +

{{ gecko_minversion_inline("2.0b2") }}

+ +
component {00000000-0000-0000-0000-000000000000} components/mycomponent.js [flags]
+
+ +

告訴 Mozilla 一個由 XPCOM 元件以 JavaScript (或是其它可接受的 scripting language) 實作之元件的 CID。ClassID {0000 ...} 一定要和該元件所實現的 ClassID 相同。可利用程式或線上 UUID 產生器產生唯一的 ClassID。

+ +

contract

+ +

{{ gecko_minversion_inline("2.0b2") }}

+ +
contract @foobar/mycontract;1 {00000000-0000-0000-0000-000000000000} [flags]
+
+ +

將特定實作的 contract ID (一個語意化字串) 對應到 ClassID。通常 contract ID 就和它頂頭所列的 component entry 一組。
+  

+ +

category

+ +

{{ gecko_minversion_inline("2.0b2") }}

+ +
category category entry-name value [flags]
+
+ +

登錄在 category manager ,至於項目的格式和用意就要看它是哪個 category 了。

+ +

content

+ +

下面這行登錄一個 content package :

+ +
content packagename uri/to/files/ [flags]
+
+ +

這會將 package 登錄在一個像 `chrome://packagename/content/..` 的位置,也就是之後它被存取的位置。這個 URI 可以是絕對位置或是相對於 manifest file 的位置,但要注意結尾的 '/' 不可省略。

+ +

locale

+ +

下面這行登錄一個 locale package :

+ +
locale packagename localename uri/to/files/ [flags]
+
+ +

這會將 locale package 登錄在解析 `chrome://packagename/locale/..` 所用的位置。 localename 通常直接用語系名稱像是 "zh" 或有時候用 語系-地區 像 "zh-TW"。如果同一 package 有多個語系 chrome registry 會根據使用者偏好中的設定值選擇最接近的語系。

+ +

skin

+ +

下面這行登錄一個 skin package :

+ +
skin packagename skinname uri/to/files/ [flags]
+
+ +

這會將 skin package 登錄在 chrome://packagename/skin/.. , skinname is 是用來識別所安裝 skin 的一個非透明化字串。同樣地,若同一 package 登記了多個 skin , chrome registry 會根據使用者偏好中的設定值選擇最合適的。

+ +

style

+ +

Style overlay (套用在chrome page上的自訂 CSS) 以下列語法登錄:

+ +
style chrome://URI-to-style chrome://stylesheet-URI [flags]
+
+ +
注意: 只有位於 chrome URI 的 stylesheet 可以這樣用。
+ +

override

+ +

chrome 登錄 manifest 允許 override 指令以便讓某些 extension 或其它嵌入物件可以改寫 XULRunner 或 AP 預設的 chrome file 設定。

+ +
override chrome://package/type/original-uri.whatever new-resolved-URI [flags]
+
+ +

注意:override 路徑不會遞迴 (所以將 chrome://foo/content/bar/ override 為 file:///home/john/blah/ 之後,其行為通常不會是預期的那樣)。而且 override 之後路徑是相對於被重寫掉的路徑而不是用來重寫的路徑 (從 CSS 的角度來說,這搞不好是個偏門也搞不好使人抓狂) 。

+ +
+

在 Gecko 1.8.1.5 (Firefox 2.0.0.5) 和較早的版本中有個 new-resolved-URI 參數 只能用絕對路徑而不能用相對路徑的 bug。詳見: {{ Bug(323455) }}.

+
+ +

resource

+ +

{{ Fx_minversion_inline("3") }}

+ +

在 extension 和 AP 中使用 Components.utils.import 來載入 JavaScript code modules 時,建立 resource protocol 別名 (aliases) 有時是必須的。請使用 resource 指令來建立別名:

+ +
resource aliasname uri/to/files/ [flags]
+
+ +

這會將目的路徑對映到 resource://<aliasname>/.. 。

+ +
+

沒有安全性限制防止網頁內容 include 以 resource: 開頭的 URI,故請留意此處所開啟的能見度

+
+ +

Manifest 旗號

+ +

Manifest 指令行允許多個以空白分隔的旗號附加於行尾。這些旗號將會設定 package 中 chrome 的特殊屬性,或限制這些指令行本身於什麼條件下作用。

+ +

application

+ +

Extension 可以安裝於多個應用程式,而有些 chrome registration 可能只需作用於特定的應用程式。以下旗號

+ +
application=app-ID
+
+ +

代表這個指令只應在 extension 安裝於符合 app-ID 的應用程式時作用。同一行可以指定多個應用程式,此時只要其中一項符合即會作用。

+ +

以下示範如何為多個應用程是分別指定 overlay :

+ +
overlay chrome://browser/content/browser.xul chrome://myaddon/content/ffOverlay.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+overlay chrome://messenger/content/mailWindowOverlay.xul chrome://myaddon/content/tbOverlay.xul application={3550f703-e582-4d05-9a08-453d09bdfdc6}
+overlay chrome://songbird/content/xul/layoutBaseOverlay.xul chrome://myaddon/content/sbOverlay.xul application=songbird@songbirdnest.com
+
+ +

appversion

+ +

Extension 可以安裝於同一應用程式的多個不同版本,而有些 chrome registration 可能只需作用於特定的版本。以下旗號

+ +
appversion=version
+appversion<version
+appversion<=version
+appversion>version
+appversion>=version
+
+ +

代表這個指令只應在 extension 安裝於符合特定版本的應用程式時作用。同一行可以指定多個 appversion ,此時只要其中一項符合即會作用。版本字串應遵循 Toolkit version format

+ +
+

Gecko 在 1.8.0.13 之前以及版本 1.8.1.5 有一個 bug , 就是本字串必須超過一個字元(也就是最少兩個) 才能使用 < 、 > 及 =,否則會在 console 中收到 appversion flag was not recognized 的錯誤訊息。參見: {{ Bug(380398) }} 。

+
+ +

platformversion

+ +

{{ gecko_minversion_inline("8.0") }} 當附加元件尤其是 binary components支援一種以上的應用程式時,若能指定所相容的 Gecko 版本將為其帶來更多的方便性。若某些 chrome registration 只作用於定特定 Gecko 版本,以下旗號

+ +
platformversion=version
+platformversion<version
+platformversion<=version
+platformversion>version
+platformversion>=version
+
+ +

代表這個指令只應在 extension 安裝於符合特定 Gecko 版本的應用程式時作用。同一行可以指定多個 platformversion,此時只要其中一項符合即會作用。

+ +

contentaccessible

+ +

{{ Fx_minversion_inline("3") }} Chrome resources 已不能被非信任來源內容中的 <img>、<script> 及其他包含或添加的 elements 所參照。 這個限制不僅適用於非信任來源中所定義的 elements , 同時也適用於受信任的附加元件中所定義的 elements。若參照需要明確地被允許,請將 contentaccessible 旗號設定為 yes 來達到如舊版 Firefox 中的行為。 See {{ bug("4369")}}

+ +

contentaccessible 只能用於 content package ,言下之意,它不會被 locale 或 skin registration 所識別。好在於 content package 所對應到的 locale 和 skin packages 對 content 而言是可見的。

+ +

注意:由於舊版的 Firefox 根本看不懂 contentaccessible flag , 若要讓附加元件同時支援 Firefox 3 及古董版的話就得來個倒退嚕,您倒是看看:

+ +
content packagename chrome/path/
+content packagename chrome/path/ contentaccessible=yes
+
+ +

os

+ +

{{ Fx_minversion_inline("3") }} Extensions (or themes) may offer different features depending on the operating system on which Firefox is running. The value is compared to the value of OS_TARGET for the platform.

+ +
os=WINNT
+os=Darwin
+
+ +

See OS_TARGET for a more complete list of os names. The os name is case insensitive.

+ +

osversion

+ +

{{ Fx_minversion_inline("3") }} An extension or theme may need to operate differently depending on which version of an operating system is running. For example, a theme may wish to adopt a different look on Mac OS X 10.5 than 10.4:

+ +
osversion>=10.5
+
+ +

abi

+ +

{{ Fx_minversion_inline("4") }} If a component is only compatible with a particular ABI, it can specify which ABI/OS by using this directive. The value is taken from the nsIXULRuntime OS and XPCOMABI values (concatenated with an underscore). For example:

+ +
binary-component component/myLib.dll abi=WINNT_x86-MSVC
+binary-component component/myLib.so abi=Linux_x86-gcc3 
+
+ +

See XPCOM ABI for more details.

+ +

platform (Platform-specific packages)

+ +

Some packages are marked with a special flag indicating that they are platform specific. Some parts of content, skin, and locales may be different based on the platform being run. These packages contain three different sets of files, for Windows and OS/2, Macintosh, and Unix-like platforms. For example, the order of the "OK" and "Cancel" buttons in a dialog is different, as well as the names of some items.

+ +

The "platform" modifier is only parsed for content registration; it is not recognized for locale or skin registration. However, it applies to content, locale, and skin parts of the package, when specified.

+ +

To indicate that a package is platform-specific, add the "platform" modifier to the "content" line after the path, for example:

+ +
content global-platform jar:toolkit.jar!/toolkit/content/global-platform/ platform
+
+ +

Once that is specified in your manifest you then ensure that under the directory global-platform are subdirectories win (Windows/OS2), mac (OS9/OSX), or unix (Everything Else). Anything residing outside of these subdirectories will be ignored.

+ +

xpcnativewrappers

+ +

Chrome packages can decide whether to use the XPCNativeWrapper security mechanism to automatically protect their code against malicious content that they might access. See Safely accessing content DOM from chrome for details.

+ +

This flag is enabled by default since Firefox 1.5. Disabling it manually was possible by specifying xpcnativewrappers=no until Firefox 4.

+ +
+

{{ gecko_callout_heading("2.0") }}

+ +

Support for this flag has been removed in Gecko 2.0 {{ geckoRelease("2.0") }}. You can no longer disable XPCNativeWrappers. To update your add-on to work without this flag:

+ + +
+ +

The xpcnativewrappers flag applies only to content packages; it is not recognized for locale or skin registration.

+ +

Example chrome manifest

+ +
content       necko                   jar:comm.jar!/content/necko/
+locale        necko       en-US       jar:en-US.jar!/locale/en-US/necko/
+content       xbl-marquee             jar:comm.jar!/content/xbl-marquee/
+content       pipnss                  jar:pipnss.jar!/content/pipnss/
+locale        pipnss      en-US       jar:en-US.jar!/locale/en-US/pipnss/
+# Firefox-only
+overlay chrome://browser/content/pageInfo.xul           chrome://pippki/content/PageInfoOverlay.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+# SeaMonkey-only
+overlay chrome://navigator/content/pageInfo.xul         chrome://pippki/content/PageInfoOverlay.xul application={92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}
+overlay chrome://communicator/content/pref/preftree.xul chrome://pippki/content/PrefOverlay.xul
+content       pippki                  jar:pippki.jar!/content/pippki/
+locale        pippki      en-US       jar:en-US.jar!/locale/en-US/pippki/
+content       global-platform         jar:toolkit.jar!/content/global-platform/ platform
+skin          global      classic/1.0 jar:classic.jar!/skin/classic/global/
+override chrome://global/content/netError.xhtml jar:embedder.jar!/global/content/netError.xhtml
+content       inspector               jar:inspector.jar!/content/inspector/
+
+ +

Instructions supported in bootstrapped add-ons

+ +

The following instructions are supported in Bootstrapped extensions:

+ + + +

Debugging a chrome manifest file

+ +

The Chrome List extension (for Firefox 3.6 and older) shows all registered chrome. This is very helpful when trying to write a chrome.manifest file as you can inspect where the files are being mapped from (jar files, local directory, etc.)

+ +

Old-style contents.rdf manifests

+ +

Before the plaintext manifests were introduced (which happened in Firefox 1.5, Toolkit 1.8), RDF manifests named "contents.rdf" were used to register chrome. This format is deprecated; however, SeaMonkey versions before version 2 do not support the plaintext manifest format yet, so contents.rdf manifests are required for extensions that wish to maintain backwards compatibility with Firefox 1.0 or the suite.

+ +

{{ gecko_minversion_note("1.9.2", "The contents.rdf manifest format is no longer supported at all starting with Gecko 1.9.2; add-ons already installed using this format will continue to work but can no longer be installed. Be sure to remove your add-on and reinstall it to ensure that it installs correctly after updating it to use a plaintext manifest.") }}

+ +

Official references for Toolkit API

+ +

{{ page("en-US/docs/Toolkit_API/Official_References") }}

+ +

{{ languages( { "fr": "fr/Enregistrement_chrome", "ja": "ja/Chrome_Registration", "pl": "pl/Rejestracja_Chrome" ,"zh-cn":"zh-cn/Chrome_Registration"} ) }}

diff --git a/files/zh-tw/mozilla/connect/index.html b/files/zh-tw/mozilla/connect/index.html new file mode 100644 index 0000000000..2e7b782447 --- /dev/null +++ b/files/zh-tw/mozilla/connect/index.html @@ -0,0 +1,126 @@ +--- +title: Connect with Mozilla +slug: Mozilla/Connect +tags: + - 繁體中文TW +translation_of: Mozilla/Connect +--- +
+

Enable, inspire and collaborate to make the Web the primary platform used to create experiences across all connected devices.

+
+ +
+
+
+ +
+ +
+ +
+ +
+ +
+
+ +
+

與 Mozilla 連結

+ +

Developers are creating the future by building services and apps for people all over the world. The goal of Mozilla Developer Relations is to help developers to use open and standardized web technologies to succeed in achieving their goals. In addition to the documentation here on MDN, we offer help and other resources towards this goal, through various channels. We invite you to connect, learn, and share your own knowledge.

+ +

We are offering help through Q&A on Stack Overflow, to solve specific technical issues and challenges you might have. We also have a newsletter keeping you informed on the latest happenings in the web scene around web apps and more. Subscribe to the Apps & Hacks newsletter.

+ +

If you share Mozilla's mission and principles, and want to help spread them to more developers, check out the ways you can get involved with technical evangelism, and join our evangelism discussion group.

+ +

We have a lot of plans and ideas for iteratively expanding our Developer Relations offerings, and we want you involved as we do so! So, follow the tags on Stack Overflow, subscribe to the Hacks blog, subscribe to the newsletter, and sign up for an account!

+ +

加入 Mozilla

+ +

If you want to go beyond connecting with Mozilla, you can join Mozilla and help realize Mozilla's mission of building a better Internet. As a developer, you have skills to contribute in many areas, as well as the opportunity to enhance your skills. Mozilla is an open source project, so we "default to open." You can "view source" and contribute to our software development projects, like the Firefox browser for desktop and Android, Firefox OS, and Mozilla's own websites. You can become part of an international community and get recognition for your efforts. Here are some of the advantages of contributing to the Mozilla project.

+ +

學習新東西的機會

+ +
+

In writing code for an open source project, you may face problems you have not encountered before, which present learning opportunities for you. You can try out new tools and techniques in an open source project. For example, if you've never done any unit testing, and cannot get permission from your boss to do so in your regular job, writing some code for an open source project would be an excellent place to try it out. Contributing to open source gives you the opportunity to collaborate with and get to know many people around the world who have similar interests. Moreover, an open source organization like Mozilla has many contributors who can help you in solving problems you encounter. If you're just getting started contributing, you can look for "mentored" bugs, where an experienced contributor has offered to help a newcomer fix them.

+ +

我可以從貢獻中得到什麼?

+ +

Exploring many things and getting recognition in the community -- these are the intangible benefits of contributing to Mozilla. While we can't guarantee specific tangible benefits, many valued contributors receive free Mozilla gear and invitations to Mozilla-related events, and are first in line to be considered for internships. Moreover, your experience in contributing to an open source project might help you find a job. More and more employers of developers are looking at open source contributions. They like to see that you're blogging and contributing to mailing lists, and they really like to see you listed as a committer on an open source project. It can also help with the work experience section of your resume.

+ +

我可以如何貢獻 Mozilla?

+ +

There are many project area for which you can contribute to Mozilla. You can find a current, complete list on the main Mozilla Get Involved page. Some areas that may interest you as a developer include:

+ + +
+
+ +
+
+

Stack Overflow 上的問與答 查看所有 Q&A…

+ +

We have Q&A to discuss challenges and issues when developing, in particular for Firefox OS and the Open Web on mobile. It's available on Stack Overflow under the easy URL http://stackoverflow.com/r/mozilla.

+ +
Stack form
+ +

最新 Q&A 主題

+
+ +
 
+
+ +

Developers at a Firefox OS workshop in Madrid.

+ +
+
+

Mozilla 在哪裡? 在活動頁面上查看訪客與詳細說明…

+ +

Here is a listing of events where Mozilla representatives will be speaking. Make sure to talk to them!

+
+ + +
+
diff --git a/files/zh-tw/mozilla/creating_mozsearch_plugins/index.html b/files/zh-tw/mozilla/creating_mozsearch_plugins/index.html new file mode 100644 index 0000000000..d41978c6ee --- /dev/null +++ b/files/zh-tw/mozilla/creating_mozsearch_plugins/index.html @@ -0,0 +1,56 @@ +--- +title: 製作 MozSearch 搜尋模組 +slug: Mozilla/Creating_MozSearch_plugins +tags: + - 搜尋模組 +translation_of: Mozilla/Creating_MozSearch_plugins +--- +

Firefox 2 使用簡化的 OpenSearch 格式儲存搜尋模組,而 MozSearch 搜尋模組則是描述搜尋引擎、URL 及相關參數的 XML 檔。 +

+
警告:MozSearch 並非標準格式,也只應於 Mozilla 專案內部使用。除非要包裝在 Firefox 擴充套件中或直接與 Firefox 安裝檔一起發佈,否則不該使用這種格式。要製作能由網頁安裝的搜尋模組,請參考製作 OpenSearch 搜尋模組
+

搜尋模組檔

+

MozSearch 格式檔與 OpenSearch 格式很像,只是根元素及 XML 名稱空間不同。 +

+

範例:Yahoo! 搜尋

+

下列 XML 是內建於英文版 Firefox 2 的 Yahoo! 搜尋模組: +

+
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>Yahoo</ShortName>
+<Description>Yahoo Search</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Image width="16" height="16">data:image/x-icon;base64,R0lGODlhEAAQAJECAP8AAAAAAP///wAAACH5BAEAAAIALAAAAAAQABAAAAIplI+py+0NogQuyBDEnEd2kHkfFWUamEzmpZSfmaIHPHrRguUm/fT+UwAAOw==</Image>
+<Url type="application/x-suggestions+json" method="GET"
+     template="http://ff.search.yahoo.com/gossip?output=fxjson&amp;command={searchTerms}" />
+<Url type="text/html" method="GET" template="http://search.yahoo.com/search">
+  <Param name="p" value="{searchTerms}"/>
+  <Param name="ei" value="UTF-8"/>
+
+  <MozParam name="fr" condition="pref" pref="yahoo-fr" />
+</Url>
+<SearchForm>http://search.yahoo.com/</SearchForm>
+</SearchPlugin>
+
+

假設使用者選擇 Yahoo! 搜尋模組,然後在搜尋欄內輸入「mozilla」後按下 Enter 鍵。接著 Firefox 會依據上面的搜尋模組敘述前往這個搜尋 URL: +

+
http://search.yahoo.com/search?p=mozilla&ei=UTF-8&fr=moz2
+
+

若使用者只單純按下搜尋欄的放大鏡圖示,或者在搜尋欄隱藏時點選「工具>網路搜尋」,則瀏覽器會前往 <SearchForm> 指定的 <tt>http://search.yahoo.com/</tt>。 +

+

範例:搜尋 MDC

+

此搜尋模組能協助你輕鬆搜尋 Mozilla 開發者中心英文版的文件: +

+
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>MDC</ShortName>
+<Description>Mozilla Developer Center search</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Image width="16" height="16">data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAABGdBTUEAAK%2FINwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz%2F%2Fz8DJQAggJiQOe%2Ffv2fv7Oz8rays%2FN%2BVkfG%2FiYnJfyD%2F1%2BrVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw%2F8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi%2FG%2BQKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo%2BMXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia%2BCuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq%2FvLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg%2FkdypqCg4H8lUIACnQ%2FSOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD%2BaDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg%3D%3D</Image>
+<Url type="text/html" method="GET" template="http://developer.mozilla.org/en/docs/Special:Search?search={searchTerms}"/>
+<SearchForm>http://developer.mozilla.org/en/docs/Special:Search</SearchForm>
+</SearchPlugin>
+
+

這個範例中單純將參數加到 URL 中,而不是使用 <Param> 指定參數。這也是使用 GET 時的建議做法,而 <Param> 應於以 POST 方式傳送表單時才使用。 +

+

延伸閱讀

+ +{{ languages( { "ca": "ca/Creaci\u00f3_de_connectors_MozSearch", "en": "en/Creating_MozSearch_plugins", "es": "es/Creaci\u00f3n_de_plugins_MozSearch", "fr": "fr/Cr\u00e9ation_de_plugins_MozSearch", "ja": "ja/Creating_MozSearch_plugins", "it": "it/Creare_Plugin_MozSearch", "pl": "pl/Tworzenie_wtyczek_MozSearch" } ) }} diff --git a/files/zh-tw/mozilla/developer_guide/index.html b/files/zh-tw/mozilla/developer_guide/index.html new file mode 100644 index 0000000000..ea630bbd6b --- /dev/null +++ b/files/zh-tw/mozilla/developer_guide/index.html @@ -0,0 +1,92 @@ +--- +title: 開發者指南 +slug: Mozilla/Developer_guide +tags: + - Developing Mozilla + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Developer_guide +--- +

不管你是老手或新手,你會發現這個頁面的文章都能在你著手進行Mozilla開發時給你幫助

+ +

首次使用?

+ +
+
準備開始
+
一步一步引領你進入Mozilla的新手指南。
+
+ + + + + + + + +
+

文件主題

+ +
+
使用Mozilla原始碼
+
程式概要,如何取得程式碼以及編程風格指南。
+
建構說明
+
如何建立 Firefox, Thunderbird, SeaMonkey, 或其他 Mozilla 應用程式.
+
開發過程概要
+
Mozilla 開發過程概要.
+
管理數個文件
+
作業於 Firefox 先行釋出的版本時,通常有數個Firefox文件是有幫助的,例如每個通道配置一個文件,或者針對不同的測試有不同的文件。
+
Automated Testing
+
How to run Mozilla's automated tests, and how to write new tests.
+
How to submit a patch
+
After getting your patch written, you need to get it checked into the tree. This article explains the review process and how to get your patch approved.
+
Getting documentation updated
+
How to ensure that documentation is kept up to date as you develop.
+
Mozilla modules and module ownership
+
This article provides information about Mozilla's modules, what the role of a module owner is, and how module owners are selected.
+
Code snippets
+
Useful code samples for a wide variety of things you might need to figure out how to do.
+
Mozilla development strategies
+
Tips for how to make the most of your time working on the Mozilla project.
+
Debugging
+
Find helpful tips and guides for debugging Mozilla code.
+
Performance
+
Performance guides and utilities to help you make your code perform well (and to play nicely with others).
+
The Mozilla platform
+
Information about the workings of the Mozilla platform.
+
Adding APIs to the navigator object {{ gecko_minversion_inline("9.0") }}
+
How to augment the {{ domxref("window.navigator") }} object with additional APIs.
+
Interface Compatibility
+
Guidelines for modifying scriptable and binary APIs in Mozilla.
+
Customizing Firefox
+
Information about creating customized versions of Firefox.
+
Virtual ARM Linux environment
+
How to set up an ARM emulator running Linux for testing ARM-specific, but not necessarily platform-specific, code. Useful for mobile developers.
+
+
+

Tools

+ +
+
Bugzilla
+
The Bugzilla database used to track issues for Mozilla projects.
+
MXR
+
Browse and search the Mozilla source code repository on the Web.
+
Bonsai
+
The Bonsai tool lets you find out who changed what file in the repository, and when they did it.
+
Mercurial
+
The distributed version-control system used to manage Mozilla's source code.
+
Tinderbox
+
Tinderbox shows the status of the tree (whether or not it currently builds successfully).  Check this before checking in and out, to be sure you're working with a working tree.
+
Crash tracking
+
Information about the Socorro and Talkback crash reporting systems.
+
Performance tracking
+
See performance information for Mozilla projects.
+
Callgraph
+
A tool to help perform static analysis of the Mozilla code by generating callgraphs automatically.
+
Developer forums
+
A topic-specific list of discussion forums where you can talk about Mozilla development issues.
+
Mozilla Platform Development Cheat Sheet
+
Brian Bondy's list of frequently referenced information for platform developers.
+
+
+ +

 

diff --git a/files/zh-tw/mozilla/developer_guide/source_code/cvs/index.html b/files/zh-tw/mozilla/developer_guide/source_code/cvs/index.html new file mode 100644 index 0000000000..385662f39f --- /dev/null +++ b/files/zh-tw/mozilla/developer_guide/source_code/cvs/index.html @@ -0,0 +1,182 @@ +--- +title: 使用CVS獲取Mozilla源代碼 +slug: Mozilla/Developer_guide/Source_Code/CVS +translation_of: Mozilla/Developer_guide/Source_Code/CVS +--- +
Tips: This document descibes how to get source code for older versions of the code, Gecko 1.9.0, Firefox 3 or earlier, and older versions of NSS and NSPR. Development for Gecko 1.9.1/Firefox 3.5 and beyond, and recent versions of NSS and NSPR, uses the Mercurial source code control system.
+ +
+

到 七月 2015, 在Mozilla 上CVS 服務不會有長時間的操作.為訪問CVS 存檔, 請看 the blog post 宣告改變.

+
+ +

那些正在進行積極開發的人可以使用 CVS 查看最新的源代碼。如果您計劃提供補丁並修復錯誤,這是最好的方法,因為它可以讓您獲得最新的更新並將它們與您自己的更改合併。

+ +

如果要編譯產品以供發布,通常下載 Mozilla 源代碼 tarball

+ +

開始

+ +

CVS 表示 “並發版本控制系統”。要了解有關 CVS 的更多信息,請訪問

+ +

支持文檔

+ +

所有人可以檢查 (也被認爲是 "拉" 或是 "下載") 通過 CVS, 但只有一個確定的人擁有能力記錄 (創建改變, 也被認爲是 "提交"). 那些人是模塊所有人以及他們的代表. 閲讀我們的檔案在 hacking mozilla 去找到怎樣獲得能力記錄. 你也許也想閲讀關於 通過SSH連接CVS.

+ +

必選

+ +

檢查原始碼需要運行 CVS 1.11 及其更新版本. CVS伺服器不適用于1.12.13 以及懸挂的替代結果, 雖然 1.12.9 知道如何工作. 而且, 你必須利用 GNU make 檢查以及構建 Mozilla. 沒有其他的 “make” 程式是可接受的. 在 Windows, mac 以及合格的 GNU 系統 (比如 GNU/Linux), 使用 "make" 運行 GNU make; 在許多的 非 GNU unixes (比如 Solaris, etc.), 使用 "gmake".

+ +

CVS 用戶端設置

+ +

"cvsroot" (倉庫驗証字符串) 用於匿名訪問 Mozilla CVS 是

+ +
:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
+
+ +

如果你使用圖形化 CVS 用戶界面, 使用後面的服務器數據:

+ + + +

選擇一個項目 Pull

+ +

由於幾個不同的應用程式是從一個相同的基礎源代碼構建而成, 你必須選擇哪一個程式在命令行上使用 MOZ_CO_PROJECT 變量來檢查. 當他將要檢查實際源代碼時, 信息需要支持。 (見適當的checkout section 之下, 你應該根據分支進行檢查). 可能性選項包括以下内容:

+ +

     检查以上所有项目的源代码,以及一些附加的实用程序代码

+ +
+
browser 
+
獨立的 ”Firefox" 瀏覽器
+
mail 
+
獨立的 “Thunderbird” 郵件/新聞 客戶端
+
suite 
+
傳統的 ”Mozilla“ SeaMonkey 瀏覽器套裝, 郵件/新聞, composer, 與其他應用程式.
+
minimo 
+
獨立的小設備瀏覽器.
+
composer 
+
獨立的 HTML composer.
+
calendar 
+
獨立的 "Sunbird" 日曆 應用.
+
xulrunner 
+
下一代 XUL 應用啓動器.
+
camino 
+
“Camino” Macintosh 本地瀏覽器
+
all 
+
+ +

Multiple projects can be specified with commas: MOZ_CO_PROJECT=suite,browser,xulrunner.

+ +

Note that if you are using a custom .mozconfig file, you can also specify MOZ_CO_PROJECT there, instead of including it on the command line.

+ +

Checking Out a New Source Tree

+ +

Check Tinderbox

+ +

Before pulling a tree, you should always check the appropriate Tinderbox to make sure that the codebase is not broken. If there are red tinderboxes, it is usually advisable to wait until they are green before pulling a tree.

+ +

Branch HEAD

+ +

To check out a new source tree from scratch, get the client.mk file which contains makefile instructions which are used to pull the rest of the tree:

+ +
$ cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co mozilla/client.mk
+
+ +

Note: if you have already set up a .mozconfig file, you may also need to check out the following files:

+ +
+
Firefox 
+
+
cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co mozilla/browser/config/mozconfig
+
+
Thunderbird 
+
+
cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co mozilla/mail/config/mozconfig
+
+
+ +

{{ Note("The last version of Thunderbird on the HEAD was a post-3.0a2 nightly build. The last version of SeaMonkey on the HEAD was a 2.0a1pre nightly build. No further development of Thunderbird or SeaMonkey is taking place on the HEAD of CVS") }}

+ +

Specific Branch

+ +

If you want to check out the source code of a specific CVS branch, use

+ +
$ cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co -r BRANCH mozilla/client.mk
+
+ +

instead. To, for example, pull the Firefox 2.0/Thunderbird 2.0/SeaMonkey 1.1 development branch, replace BRANCH above with MOZILLA_1_8_BRANCH. For available branch tags in Mozilla, see CVS Tags.

+ +

The information on pulling project specific .mozconfig files as listed in the previous section apply to other branches than HEAD as well of course.

+ +

Checkout

+ +

After having chosen the correct branch, run:

+ +
$ cd mozilla
+$ make -f client.mk checkout MOZ_CO_PROJECT=option,option
+
+ +

As mentioned above, if you are using a custom .mozconfig file where you have already specified the MOZ_CO_PROJECT variable, you do not need to repeat it here on command line.

+ +
Always use client.mk to checkout the Mozilla sources: do not check out the mozilla/ module directly. Various subprojects such as NSS, NSPR, and LDAP C SDK are pulled from stable release tags, even when regular mozilla development occurs on the trunk.
+ +

Specific Time

+ +

If you want to check out the source code as it was at a specific time you can use the MOZ_CO_DATE variable. For example MOZ_CO_DATE="20 Oct 2006 17:00 PDT".

+ +

This can either be added to your .mozconfig file, or specified on the command line, such as

+ +
$ cd mozilla
+$ make -f client.mk checkout MOZ_CO_DATE="20 Oct 2006 17:00 PDT" MOZ_CO_PROJECT=option,option
+
+ +

Changing the Source Tree to a Different Branch

+ +

Branch HEAD

+ +

In order to update a source tree (be it branch HEAD or a specific branch) to latest branch HEAD, first run:

+ +
$ cd mozilla
+$ cvs up -A client.mk
+
+ +

The -A option removes any "sticky branch" information, which leads to the effect that the tree is updated to HEAD.

+ +

Specific Branch

+ +

To update a source tree which was pulled from a specific branch, start with

+ +
$ cd mozilla
+$ cvs up -r BRANCH client.mk
+
+ +

instead. Replace BRANCH by the tag of the branch you want to update.

+ +

Updating a Source Tree

+ +

To update your source tree simply do the following:

+ +
$ make -f client.mk checkout MOZ_CO_PROJECT=option,option
+
+ +

As always, if you use a custom .mozconfig file where MOZ_CO_PROJECT is already defined, you do not need to repeat it on command line.

+ +

Creating a Diff File

+ +

In order to create a diff of a single local file against the current file in the repository, use:

+ +
$ cvs diff -u8p FILENAME
+
+ +

See Creating a patch for more information.

+ +

Converting a Downloaded Source Tree

+ +

Downloaded source trees from mozilla.org (source tarballs) are already set up with CVS information, like a normal checkout. You can update these trees like normal trees to the latest code, without special action. See previous section on how to update a source tree.

+ +

interwiki link

+ +

 

diff --git a/files/zh-tw/mozilla/developer_guide/source_code/index.html b/files/zh-tw/mozilla/developer_guide/source_code/index.html new file mode 100644 index 0000000000..6bfc3bcd9a --- /dev/null +++ b/files/zh-tw/mozilla/developer_guide/source_code/index.html @@ -0,0 +1,44 @@ +--- +title: 與 Mozilla 原始碼共事 +slug: Mozilla/Developer_guide/Source_Code +translation_of: Mozilla/Developer_guide/Source_Code +--- +

以下文章將幫你掌握 Mozilla 原始碼、了解怎麼閱讀程式碼、並把建議的變更放到代碼樹裡面。

+ +
+
+
+
Getting the code from the Mercurial repository
+
If you plan to contribute to the Mozilla project, the best way to get the code is to check it out from the version control repository. Learn how to do that here.
+
Getting a pre-configured Mozilla build system virtual machine
+
This is the easiest way to get started: use a VirtualBox virtual machine which is already configured with a complete build environment for you to use. Just boot the VM and build!
+
Downloading the code using HTTP or FTP
+
If you want to fetch the code for a specific release of a particular Mozilla product, you may prefer to download a source code archive.
+
Viewing and searching Mozilla source code online
+
Learn how to use MXR, Mozilla's online search and browsing tool for accessing the source code. This isn't a good way to download the code, but is a great way to search it.
+
Navigating the Mozilla source code
+
Learn about the various folders in the Mozilla source tree, and how to find what you're looking for.
+
Bugs for newcomers
+
If you are new to the project and want something to work on, look here.
+
+
+ +
+
+
Mozilla Coding Style Guide
+
The code style guide provides information about how you should format your source code to ensure that you don't get mocked by the reviewers.
+
Interface development guide
+
Guidelines and documentation for how to create and update XPCOM interfaces.
+
SVG Cleanup Guide
+
Guidelines and best practices for shipping new SVGs.
+
Try Servers
+
Mozilla products build on at least three platforms. If you don't have access to them all, you can use the try servers to test your patches and make sure the tests pass.
+
Creating a patch
+
Once you've made a change to the Mozilla code, the next step (after making sure it works) is to create a patch and submit it for review. This article needs to be updated fully for Mercurial.
+
Getting commit access to the source code
+
Feel ready to join the few, the proud, the committers? Find out how to get check-in access to the Mozilla code.
+
Getting older Mozilla code from CVS
+
Older versions of the Mozilla source code, as well as the current versions of NSS and NSPR, are kept in a CVS repository. Learn about that in this article.
+
+
+
diff --git a/files/zh-tw/mozilla/firefox/developer_edition/index.html b/files/zh-tw/mozilla/firefox/developer_edition/index.html new file mode 100644 index 0000000000..d912a36470 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/developer_edition/index.html @@ -0,0 +1,56 @@ +--- +title: Firefox 開發者版本 +slug: Mozilla/Firefox/Developer_Edition +tags: + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Firefox/Developer_Edition +--- +
{{FirefoxSidebar}}

一個專為 Web 開發者量身定做的 Firefox 版本。

+ +

下載 Firefox 開發者版本

+ +
+
+
+

最新的 Firefox 功能

+ +

Firefox Developer Edition 取代了 Firefox 釋出流程中的 Aurora 頻道。如同 Aurora,各功能會在 Nightly builds 中穩定下來後,每隔六週下放到 Developer Edition 裡面。

+ +

透過 Developer Edition,您可以在至少 12 週前接觸到 Firefox 正式釋出的工具及平台功能。

+ +

來看看 Developer Edition 有哪些新功能

+
+ +
+

清晰的界面

+ +

更快找到開發者工具。

+ +

實驗性的開發者工具

+ +

我們加入了尚未準備好正式釋出的實驗性工具。

+ +

例如,Developer Edition 加入了 Valence 附加元件,一個可以讓您透過 Firefox 開發者工具連到其他瀏覽器,像是 Android 上面的 Chrome 及 iOS 上面的 Safari。

+
+
+ +
+
+

獨立的設定檔

+ +

Firefox Developer Edition 使用一個獨立於其他已經安裝在您電腦上 Firefox 版本的設定檔。這意味著您可以簡單的在執行 Developer Edition 的同時使用正式或測試版的 Firefox。

+ +
+

註:這表示在您第一次啟動  Developer Edition 後,將會看到一個完全沒有自訂外觀﹑沒有擴充套件、沒有書籤、也沒有歷史紀錄的瀏覽器。若您想讓您的  Developer Edition 跟您其他版本的  Firefox 使用一樣的設定,您可以使用  Firefox Sync 來達成同步。

+
+
+ +
+

針對 Web 開發者的設置

+ +

我們針對 Web 開發者的需求調整了預設的設定值。例如,chrome 及遠端除錯功能預設為開啟。

+
+
+ +

 

diff --git a/files/zh-tw/mozilla/firefox/developer_edition/reverting/index.html b/files/zh-tw/mozilla/firefox/developer_edition/reverting/index.html new file mode 100644 index 0000000000..0a83335196 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/developer_edition/reverting/index.html @@ -0,0 +1,25 @@ +--- +title: 回到過去 +slug: Mozilla/Firefox/Developer_Edition/Reverting +translation_of: Mozilla/Firefox/Developer_Edition/Reverting +--- +
{{FirefoxSidebar}}

換掉 Developer Edition 佈景主題

+ +


+ 如果您想繼續使用 Developer Edition, 可是比較喜歡目前套用在 Firefox 及 Firefox Beta 的 Australis 界面,您可以切換到一般的 Firefox 佈景主題:只要打開「自訂模式」面板並點擊「使用 Firefox Developer Edition 佈景主題」按鈕即可。

+ +

{{EmbedYouTube("OvJwofTjsNg")}}

+ +

注意,目前 Developer Edition 佈景主題尚未與個性面板相容。所以如果您想套用個性面板,您必須先切回 Australis 界面。

+ +

回到 Firefox Aurora

+ +


+ 如果您想保留所有 Firefox Developer Edition 的前期測試功能,但是又不想要有其他的改變,您可以回復到看起來就像是以前的 Firefox Aurora。請依序執行下面兩步驟:

+ +
    +
  1. 開啟 Developer Edition 的選項頁面,並將「允許 Firefox Developer Edition 與 Firefox 同時執行」選項的勾選取消掉。您將會收到重新啟動瀏覽器的提示。
  2. +
  3. 瀏覽器重新啟動後,您可以打開「自訂模式」面板並點擊「使用 Firefox Developer Edition 佈景主題」按鈕來關閉 Developer Edition 佈景主題。
  4. +
+ +

{{EmbedYouTube("0Ofq-vlw8Qw")}}

diff --git a/files/zh-tw/mozilla/firefox/index.html b/files/zh-tw/mozilla/firefox/index.html new file mode 100644 index 0000000000..55827cdf75 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/index.html @@ -0,0 +1,62 @@ +--- +title: Firefox +slug: Mozilla/Firefox +tags: + - Firefox + - Mozilla + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Firefox +--- +
{{FirefoxSidebar}}
+ +

Firefox 是 Mozilla 基金會最受歡迎的網頁瀏覽程式,在眾多平台包含 Windows、Mac OS X、桌面版 Linux 及 Android 行動裝置上發行。 具有廣大相容性,整合最新的 Web 技術和強大的開發工具。不管你是一般使用者還是開發者,Firefox 都是您的最佳選擇。

+ +

Firefox 是一項開源專案;大多數的程式碼都是由我們廣大的社群志工們所貢獻。在這裡您將會學會如何為 Firefox 專案做出貢獻,並找到一些關於打造 Firefox 擴充套件、在 Firefox 底下使用開發者工具,以及其他任務的資訊鍊結。

+ +
+

學習如何打造 Firefox 的擴充套件、如何自己開發及編譯 Firefox,以及 Firefox 的內部及子項目是如何運作的。

+
+ + + +

Firefox 更新頻道

+ +

Firefox 釋出被分成四個 更新頻道

+ +

Firefox 每日更新頻道

+ +

每個晚上我們會建置 Firefox 在 mozilla-central 中最新的程式碼。這些版本是為了開發者,或是那些想測試還在研發中的尖端科技的嘗鮮者而建置的。

+ +

下載 Firefox 每日版

+ +

Firefox 開發者版本

+ +

這個 Firefox 是為了開發者量身訂製的版本。每六個禮拜,我們會將 Firefox 每日版中已經夠穩定的功能加入,並釋出新版本的 Firefox 開發者版本。 我們也會將一些為了開發者設計的額外功能加入其中,而那些功能只會在這個頻道出現

+ +

了解更多關於 Firefox 開發者版本的資訊

+ +

下載 Firefox 開發者版本

+ +

Firefox Beta 測試版

+ +

在 Firefox 開發者版本花費六個禮拜後,我們會將那些夠穩定的功能加入並釋出新版本的 Firefox Beta 版。Firefox Beta 版是為了那些 Firefox 愛好者測試那些確定會在下個版本釋出的功能。

+ +

下載 Firefox Beta 版

+ +

Firefox

+ +

在確認 Firefox Beta 版穩定的另外六個禮拜,我們已經準備好將新功能以最新版本 Firefox 的姿態推出給全球的使用者。

+ +

下載 Firefox

diff --git a/files/zh-tw/mozilla/firefox/multiprocess_firefox/index.html b/files/zh-tw/mozilla/firefox/multiprocess_firefox/index.html new file mode 100644 index 0000000000..6afe2dd67d --- /dev/null +++ b/files/zh-tw/mozilla/firefox/multiprocess_firefox/index.html @@ -0,0 +1,80 @@ +--- +title: 多處理程序的 Firefox +slug: Mozilla/Firefox/Multiprocess_Firefox +tags: + - Elecrolysis + - Firefox + - Multiprocess + - e10s +translation_of: Mozilla/Firefox/Multiprocess_Firefox +--- +
{{FirefoxSidebar}}

在舊的 Firefox 桌面版本中,整個瀏覽器都是執行在單一的作業系統處理程序裡。特別是用來執行瀏覽器使用者介面(又稱為「chrome code」)的 JavaScript 和網頁裡的程式碼(又稱為「內容」或「網頁內容」)都在同一個處理程序中。
+
+最新版的 Firefox 會分別在單獨的處理程序中執行瀏覽器的介面和網頁內容。在這個架構的第一個版本中,所有瀏覽器分頁在同一個處理程序中執行,而瀏覽器介面則在另外的一個處理程序中。在未來幾個版本後,我們希望能有不只一個處理程序。這個提供多處理程序 Firefox 的專案稱為 Electrolysis,有時候會縮寫成 e10s。

+ +

多處理程序的 Firefox 不會影響一般的網頁。只有 Firefox 本身和附加元件的開發者們需要直接存取網頁內容時才會受到影響。

+ +

使用者介面的 chrome JavaScript 必須使用 message manager 來間接存取網頁內容。為了緩解過渡期的影響,我們已經實作了 Cross Process Object Wrappers 和一些給附加元件開發者的相容替代方案。如果你是附加元件的開發者,想知道這會不會影響到你,請參閱多處理程序 Firefox 的工作指南

+ +
+
+
+
+
技術總覽
+
非常高階的多處理程序 Firefox 實作解釋。
+
網頁內容相容性指南
+
過渡期可能出現的潛在網站相容性問題的指南和細節。提示:不是很多!
+
用語表
+
多處理程序 Firefox 的術語參考。
+
Message manager
+
溝通介面與內容的元件完整指南。
+
基於 SDK 的附加元件
+
如何移植使用 Add-on SDK 開發的附加元件。
+
各種 URIs 在哪裡載入
+
URIs(chrome:, about:, file:, resource:)在哪個處理程序中載入的快速指南。
+
+
+ +
+
+
動機
+
為什麼我們要實作多處理程序的 Firefox:效能、安全和穩定。
+
附加元件移植指南
+
如果你是附加元件的開發者,來這裡看看你要如何處理程式碼。
+
跨處理程序元件包裝(Cross Process Object Wrappers)
+
Cross Process Object Wrappers 是一個移植工具,讓 chrome code 可以同步存取內容。
+
內容處理程序的除錯
+
如何在內容處理程序、包含框架和處理程序腳本中進行除錯。
+
多處理程序 Firefox 的分頁處理
+
在多處理程序的 Firefox 中分頁是如何切換的。
+
+
+
+ +
+
+
+
+
Chrome 程式碼的限制
+
不再有用的 Chrome 程式碼,以及如何修正。
+
+
+ +
+
+
框架程式碼的限制
+
不再有用的框架程式碼,以及如何替代。
+
+
+
+ +
+

聯絡我們

+ +

了解更多關於項目、參與、或者來問問題。

+ + diff --git a/files/zh-tw/mozilla/firefox/privacy/index.html b/files/zh-tw/mozilla/firefox/privacy/index.html new file mode 100644 index 0000000000..1f42ab5be0 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/privacy/index.html @@ -0,0 +1,9 @@ +--- +title: 隱私 +slug: Mozilla/Firefox/Privacy +tags: + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Firefox/Privacy +--- +
{{FirefoxSidebar}}

{{ ListSubpages () }}

diff --git a/files/zh-tw/mozilla/firefox/privacy/tracking_protection/index.html b/files/zh-tw/mozilla/firefox/privacy/tracking_protection/index.html new file mode 100644 index 0000000000..a52f8b815d --- /dev/null +++ b/files/zh-tw/mozilla/firefox/privacy/tracking_protection/index.html @@ -0,0 +1,74 @@ +--- +title: 追蹤保護 +slug: Mozilla/Firefox/Privacy/Tracking_Protection +translation_of: Mozilla/Firefox/Privacy/Tracking_Protection +--- +
{{FirefoxSidebar}}

追蹤保護是什麼?

+ +

在第 42 版後,Firefox Desktop 與 Firefox for Android 導入了追蹤保護。在隱私視窗(Firefox for Android 則是隱私標籤)內,Firefox 會封鎖從其他用戶追蹤網站載入的內容。

+ +

有些被封鎖的內容,屬於頁面排版的一部分。如果 Firefox 因為封鎖了這些內容而造成跑版,用戶很可能會注意到。但如果針對遭封鎖的元素,以其他元素填充的話,用戶也可能完全不會注意到。

+ +

當 Firefox 封鎖內容的時候,網頁主控台的訊息會跳出如下面般的紀錄:

+ +
因為啟用了追蹤保護,位於「http://some/url」的資源已被封鎖。
+ +

請記得在使用 Firefox for Android 的時候,你可以透過遠端除錯訪問主控台。

+ +

Firefox UI 會在封鎖內容的時候告訴用戶,並同時告知用戶可以在此次瀏覽階段解除封鎖。用戶也可以選擇完全停用追蹤保護。

+ +

Firefox 如何決定封鎖什麼?

+ +

載入內容的封鎖與否,取決於該內容來自哪個網域。

+ +

Firefox 會傳送一個確定參與用戶追蹤的網域列表。當追蹤保護啟動的時候,Firefox 會封鎖來自列表網站的內容。

+ +

追蹤用戶的網站通常來自第三方廣告網站與分析網站。

+ +

這對我的網站有什麼意義?

+ +

當追蹤保護啟用時,最明顯的意義是:

+ + + +

更值得注意的是,如果你的網站有部分依賴於追蹤器的運作程式碼,那這些追蹤程式碼將會被封鎖和禁止並可能導致你的網站失去正常運作當追蹤保護被啟用。例如,當你的網站包含程式碼,那些程式碼依賴於追蹤網站所提供的程式碼的功能,那麼這些追蹤網站的程式碼的功能將會失敗,不會運作,停止呼叫程式碼,失去網站的運作功能。

+ +

像是說,不要這樣用 Google Analytics:

+ +
<a href="http://www.example.com" onclick="trackLink('http://www.example.com', event);">Visit example.com</a>
+<script>
+function trackLink(url,event) {
+    event.preventDefault();
+    ga('send', 'event', 'outbound', 'click', url, {
+     'transport': 'beacon',
+     'hitCallback': function() {
+       document.location = url;
+     }
+   });
+}
+</script>
+ +

而是要在使用物件以前偵測該物件是否存在或被停用,防止程式運作的失敗。像是:

+ +
<a href="http://www.example.com" onclick="trackLink('http://www.example.com', event);">Visit example.com</a>
+<script>
+function trackLink(url,event) {
+    event.preventDefault();
+    if (window.ga && ga.loaded) {
+         ga('send', 'event', 'outbound', 'click', url, {
+         'transport': 'beacon',
+         'hitCallback': function() { document.location = url; }
+       });
+    } else {
+        document.location = url;
+    }
+}
+</script>
+
+ +

關於此技術的詳細資訊可參見 Google Analytics, Privacy, and Event Tracking.

+ +

取決於那些第三方網站程式的程式碼寫法和運作方式,這樣的程式碼寫法不會是適合和適用於你的網站的程式碼。所以說,你的網站將會失敗停止運作如果這些第三方外掛程式碼回應過慢或不可用或追蹤程式碼被外掛程式停用。

diff --git a/files/zh-tw/mozilla/firefox/releases/1.5/index.html b/files/zh-tw/mozilla/firefox/releases/1.5/index.html new file mode 100644 index 0000000000..01321916f6 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/1.5/index.html @@ -0,0 +1,103 @@ +--- +title: Firefox 1.5 技術文件 +slug: Mozilla/Firefox/Releases/1.5 +translation_of: Mozilla/Firefox/Releases/1.5 +--- +
{{FirefoxSidebar}}

Based on the Gecko 1.8 engine, Firefox 1.5 improved its already best in class standards support, and provided new capabilities to enable the next generation of web applications. Firefox 1.5 features improved support for CSS2 and CSS3, APIs for scriptable and programmable 2D graphics through SVG 1.1 and <canvas>, XForms and XML events, as well as many DHTML, JavaScript, and DOM enhancements.

+

Developer Tools

+

Several tools and browser extensions are available to help developers support Firefox 1.5.

+ +

Note: Some extensions do not currently support Firefox 1.5, and will be automatically disabled.

+

Overview

+

Some of the new features in Firefox 1.5:

+

Web site and application developers

+
+
+ SVG In XHTML Introduction
+
+ Learn how to use SVG in XHTML pages and how to use JavaScript and CSS to manipulate the picture in the same way you would script regular XHTML. See also SVG in Firefox to learn about the status and known problems of SVG implementation in Firefox.
+
+ Drawing Graphics with Canvas
+
+ Learn about the new <canvas> tag and how to draw graphs and other objects in Firefox.
+
+ CSS3 Columns
+
+ Learn about the new support for automatic multi-column text layout as proposed for CSS3.
+
+ Using Firefox 1.5 caching
+
+ Learn about bfcache and how it speeds up back and forward navigation.
+
+

XUL and Extension Developers

+
+
+ Building an Extension
+
+ This tutorial will take you through the steps required to build a very basic extension for Firefox. Also see another tutorial on MozillaZine knowledge base, which demonstrates the new features of the Extension Manager in 1.5 that make creating a new extension even easier.
+
+ XPCNativeWrapper
+
+ XPCNativeWrapper is a way to wrap up an object so that it's safe to access from privileged code. It can be used in all Firefox versions, though the behavior changed somewhat starting with Firefox 1.5 (Gecko 1.8).
+
+ Preferences System
+
+ Learn about the new widgets that allow you to create Options windows easier using less JavaScript code.
+
+ International characters in XUL JavaScript
+
+ XUL JavaScript files can now contain non-ASCII characters.
+
+ Tree API changes
+
+ The interfaces for accessing XUL <tree> elements have changed.
+
+ XUL Changes for Firefox 1.5
+
+ Summary of XUL changes. See also Adapting XUL Applications for Firefox 1.5.
+
+ + +

New End user Features

+

User Experience

+ +

Security and Privacy

+ +

Support for open Web standards

+

Firefox support for Web standards continues to lead the industry with consistent cross-platform implementations for:

+ +

Firefox 1.5 supports the following data transport protocols (HTTP, FTP, SSL, TLS, and others), multilingual character data (Unicode), graphics (GIF, JPEG, PNG, SVG, and others) and the latest version of the world's most popular scripting language, JavaScript 1.6.

+

Changes since Firefox 1.0

+

Many changes have been introduced into Firefox since it was first released on November 9, 2004. Firefox has progressed with many new features and bug fixes. A detailed list of changes is available from squarefree.com.

diff --git a/files/zh-tw/mozilla/firefox/releases/10/index.html b/files/zh-tw/mozilla/firefox/releases/10/index.html new file mode 100644 index 0000000000..1226e5de82 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/10/index.html @@ -0,0 +1,209 @@ +--- +title: Firefox 10 技術文件 +slug: Mozilla/Firefox/Releases/10 +translation_of: Mozilla/Firefox/Releases/10 +--- +
{{FirefoxSidebar}}
+ +

Firefox 10 shipped on January 31, 2012. This article provides information about the new features and key bugs fixed in this release, as well as links to more detailed documentation for both web developers and add-on developers.

+ +

This documentation is not yet complete. Want to help document Firefox 10? See the list of bugs that need to be written about and pitch in!

+ +
Important note: Firefox 10 is the first release of this browser with two digits. This may lead to problem with some UA-sniffing scripts. Be sure to check them, and those contained in 3rd-party software you embed in your pages, like libraries. For more information about this, look at the Firefox goes 2-digit article on hack.mozilla.org.
+ +

Changes for Web developers

+ +

HTML

+ + + +

JavaScript

+ + + +

DOM

+ +

DOM3 Events

+ + + +

DOM4

+ + + +

Page Visibility API

+ + + +

Full Screen API

+ + + +

Battery API

+ + + +

Canvas

+ + + +

WebGL

+ + + +

Web Workers

+ + + +

IndexedDB

+ +

Great progress has been made to update IndexedDB to the latest draft specification. This effort will continue in Firefox 11.

+ + + +

Other

+ + + +

CSS

+ + + +

SVG

+ + + +

Networking

+ + + +

Developer tools

+ + + +

Changes for Mozilla and add-on developers

+ +

For an overview of likely issues that may arise when updating your add-ons to support Firefox 10, see Updating add-ons for Firefox 10.

+ +
Note: The old PRBool data type has been retired! Anywhere in the documentation that refers to it now uses the standard C++ bool type instead. Documentation will be updated in the future, but for now, just keep this in mind.
+ +

Manifests

+ + + +

XUL

+ + + +

XPConnect

+ + + +

Interface changes

+ + + +

Plug-in changes

+ + + +

Build system changes

+ + + +

See also

+ + + +

{{ languages( { "ja": "ja/Firefox_10_for_developers" } ) }}

diff --git a/files/zh-tw/mozilla/firefox/releases/11/index.html b/files/zh-tw/mozilla/firefox/releases/11/index.html new file mode 100644 index 0000000000..cd5895fe6d --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/11/index.html @@ -0,0 +1,111 @@ +--- +title: Firefox 11 技術文件 +slug: Mozilla/Firefox/Releases/11 +translation_of: Mozilla/Firefox/Releases/11 +--- +
{{FirefoxSidebar}}

Firefox 11 shipped on March 13, 2012. This article provides information about the new features and key bugs fixed in this release, as well as links to more detailed documentation for both web developers and add-on developers.

+

Changes for Web developers

+

HTML

+ +

DOM

+ +

CSS

+ +

JavaScript

+

No change.

+

SVG

+ +

WebSocket

+ +

IndexedDB

+ +

Network

+ +

Developer tools

+ +

Changes for Mozilla and add-on developers

+

JavaScript code modules

+

NetUtil.jsm

+ +

New JavaScript code modules

+
+
+ source-editor.jsm
+
+ Provides a convenient, easy-to-use source code editor that you can use in your add-ons. This is the same editor used by Scratchpad and other developer tools integrated into Firefox.
+
+

Interface changes

+ +

Removed interfaces

+

The following interfaces were implementation details that are no longer needed:

+ + + +

Preference changes

+
+
+ {{Pref("ui.tooltipDelay")}}
+
+ Specifies the delay, in milliseconds, between the mouse cursor beginning to hover and the display of a tooltip.
+
+

Build system changes

+ +

Other changes

+ +

See also

+
+ {{Firefox_for_developers('10')}}
diff --git a/files/zh-tw/mozilla/firefox/releases/2/adding_feed_readers_to_firefox/index.html b/files/zh-tw/mozilla/firefox/releases/2/adding_feed_readers_to_firefox/index.html new file mode 100644 index 0000000000..79a12bae1d --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/2/adding_feed_readers_to_firefox/index.html @@ -0,0 +1,36 @@ +--- +title: 新增消息來源閱讀工具 +slug: Mozilla/Firefox/Releases/2/Adding_feed_readers_to_Firefox +translation_of: Mozilla/Firefox/Releases/2/Adding_feed_readers_to_Firefox +--- +
{{FirefoxSidebar}}

從 Firefox 2 起,消息來源(feed)可選用不同的 RSS 或 Atom 閱讀工具訂閱。這份文件提供新增其他閱讀程式支援的方法。 +

+

新增 Web 版閱讀工具

+

新增 Web 版閱讀工具需要三個設定: +

+
browser.contentHandlers.types.number.title +
閱讀程式的名稱。 +
browser.contentHandlers.types.number.type +
這部份必須設定為「application/vnd.mozilla.maybe.feed」。 +
browser.contentHandlers.types.number.uri +
閱讀程式的 URI。其中以「%s」標示消息來源 URL 必須插入的地方。 +
+

number 應該替換成尚未使用的最小自然數。舉例來說,如果要新增一個名為「Easy Reader」的閱讀工具、且目前 0 到 4 皆已使用,則應將 number 設定為 5,如下: +

+ +

你可以用 <tt>about:config</tt> 手動加入這些設定,如果擴充套件要新增閱讀工具則亦可寫程式修改之。 +

+

從 Web 應用程式新增閱讀工具

+

使用 JavaScript 也可輕易新增消息來源的閱讀工具,只要用 navigator.registerContentHandler() 函式即可,如下: +

+
navigator.registerContentHandler("application/vnd.mozilla.maybe.feed",
+                                 "http://www.theeasyreaderurl.com?feed=%s",
+                                 "Easy Reader");
+
+

新增本機閱讀程式

+

新增本機閱讀程式時,最簡單的方式便是使用「選項」(或「偏好設定」,名稱視作業系統而定)的「消息來源」面板直接添加。 +

當然也可以用擴充套件,改以程式方式新增閱讀程式。只要將browser.feeds.handlers.application 設定為閱讀程式的路徑即可。 +

{{ languages( { "en": "en/Adding_feed_readers_to_Firefox", "es": "es/A\u00f1adir_lectores_de_canales_a_Firefox", "ja": "ja/Adding_feed_readers_to_Firefox" } ) }} diff --git a/files/zh-tw/mozilla/firefox/releases/2/index.html b/files/zh-tw/mozilla/firefox/releases/2/index.html new file mode 100644 index 0000000000..a68f4fcbac --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/2/index.html @@ -0,0 +1,89 @@ +--- +title: Firefox 2 技術文件 +slug: Mozilla/Firefox/Releases/2 +translation_of: Mozilla/Firefox/Releases/2 +--- +
{{FirefoxSidebar}}

Firefox 2 的開發相關特色

+

Firefox 2 有許多新的特色及功能,本文提供各項新特色的相關文章連結。 +

+

給網頁設計師及開發者

+
即時摘要 +
即時摘要能定期顯示網頁中的關鍵訊息。網站或其他第三方開發者都能提供即時摘要來源,而後使用者能選擇在書籤上顯示即時摘要或網頁標題。 +
+
製作即時摘要 +
即時摘要來源的製作教學。 +
+
即時摘要 XML 語法參考 +
即時摘要來源之 XML 語法參考指南。 +
+
製作 OpenSearch 搜尋模組 +
Firefox 2 支援 OpenSearch 搜尋模組格式。 +
+
製作 MozSearch 搜尋模組 +
Firefox 2 支援擴充版的 OpenSearch 格式,名為 MozSearch。但此非標準,故僅建議用於程式內部。 +
+
讓搜尋模組支援搜尋建議 +
讓你的 MozSearch 模組支援搜尋建議功能,此功能將於搜尋欄中以下拉選單顯示建議關鍵字。 +
+
JavaScript 1.7 新功能 +
Firefox 2 支援 JavaScript 1.7,包含新的 let 表達式、跨結構指定(destructuring assignment)、產生器 (generators)、迴圈器 (iterators) 和陣列簡約式 (array comprehensions)。 +
+
WHATWG 於用戶端儲存工作階段資料 +
於用戶端儲存工作階段資料技術可讓網路應用程式於用戶端儲存結構化資料。 +
+
Firefox 中的 SVG +
Firefox 2 提升支援 Scalable Vector Graphics (SVG) 的程度,實作了 <textPath> 元素、也開始支援某些從前無法妥善處理的屬性。 +
+
控制 HTML 表單中的拼字檢查功能 +
Firefox 2 支援文字輸入區的即時拼字檢查,本文描述撰寫 HTML 表單元素時啟用或停用此功能的方法。 +
+
Firefox 2 的安全功能 +
某些與安全相關之協定的預設啟用情形,在 Firefox 2 有了更動。 +
+

給 XUL 與擴充套件開發者

+
讓擴充套件升級至 Firefox 2 +
描述讓現有擴充套件升級以便支援 Firefox 2 的方法。 +
+
跨連線儲存 (Session store) API +
Firefox 現在支援跨連線 (Session) 儲存或復原資料。 +
+
消息來源內容存取 API +
讓開發者存取、解析 RSS 或 Atom 消息來源的 API。 +
+
SAX 支援 +
事件驅動式的 XML 解析 API。 +
+
自網頁添加搜尋引擎 +
Firefox 能以 JavaScript 新增搜尋引擎模組,模組可為 OpenSearch 或 Sherlock 格式。 +
+
於 XUL 中使用拼字檢查 +
如何使用拼字檢查功能及怎樣取得建議拼字清單的程式碼。 +
+
新增偽造網站清單來源 +
Firefox 可以新增額外的詐騙網站資料來源,藉此提升偵測偽造網站的能力。 +
+
新增消息來源閱讀工具 +
你可以用網頁或程式新增 Firefox 的消息來源閱讀工具。 +
+
Storage +
Firefox 2 新增 mozStorage 功能,為基於 sqlite 的資料庫結構。 +
+
Firefox 2 佈景主題之更動 +
討論現有佈景主題更新以便支援 Firefox 2 的方法。 +
+

給廣大使用者的新功能

+

Firefox 2 提供比上個版本更簡潔的操作介面,強化的安全隱私保護,讓您上網更安全方便。 +

+

使用操作體驗

+ +

安全隱私保護

+ +{{ languages( { "ca": "ca/Firefox_2_per_a_desenvolupadors", "es": "es/Firefox_2_para_desarrolladores", "en": "en/Firefox_2_for_developers", "fr": "fr/Firefox_2_pour_les_d\u00e9veloppeurs", "it": "it/Firefox_2.0_per_Sviluppatori", "ja": "ja/Firefox_2_for_developers", "ko": "ko/Firefox_2_for_developers", "pl": "pl/Firefox_2_dla_programist\u00f3w", "pt": "pt/Firefox_2_para_desenvolvedores" } ) }} diff --git a/files/zh-tw/mozilla/firefox/releases/2/security_changes/index.html b/files/zh-tw/mozilla/firefox/releases/2/security_changes/index.html new file mode 100644 index 0000000000..d0a4b7ad5a --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/2/security_changes/index.html @@ -0,0 +1,29 @@ +--- +title: Firefox 2 的安全功能 +slug: Mozilla/Firefox/Releases/2/Security_changes +tags: + - 安全性 + - 待翻譯 +translation_of: Mozilla/Firefox/Releases/2/Security_changes +--- +
{{FirefoxSidebar}}

本文探討 Firefox 2 與安全性相關的變動。

+ +

不夠安全的編碼方式皆預設關閉

+ +

Firefox 2 預設停用 SSLv2 及不夠安全的「export」編碼方式(金鑰長度小於 64 位元),改以 SSLv3 替代,這樣可以提高安全性。

+ +

偏好的編碼方式為 TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHATLS_RSA_WITH_3DES_EDE_CBC_SHA。有些伺服器則稱為 SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHASSL_RSA_WITH_3DES_EDE_CBC_SHA

+ +

若 SSLv2 必須開啟,則可以將各項以 security.ssl2.* 開頭的使用偏好設定為 true

+ +

新特色

+ + + +

開啟與關閉編碼方式

+ +

透過在 URL 上打上 about:config,並且篩選 "ssl" 或 "tls",你可以得知 Firefox 2 支援哪些加密編碼,並且開啟或關閉這些加密方式。

diff --git a/files/zh-tw/mozilla/firefox/releases/3.6/index.html b/files/zh-tw/mozilla/firefox/releases/3.6/index.html new file mode 100644 index 0000000000..f053267778 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/3.6/index.html @@ -0,0 +1,301 @@ +--- +title: Firefox 3.6 技術文件 +slug: Mozilla/Firefox/Releases/3.6 +translation_of: Mozilla/Firefox/Releases/3.6 +--- +

Firefox 3.6 offers support for new and developing web standards, increased performance, and an overall better experience for web users and developers. This page provides links to articles covering the new capabilities of Firefox 3.6.

+ +

For web site and application developers

+ +

CSS

+ +
+
Using gradients
+
Firefox 3.6 adds support for the proposed -moz-linear-gradient and -moz-radial-gradient properties for background.
+
Multiple backgrounds
+
The background property (as well as background-color, background-image, background-position, background-repeat, and background-attachment) now supports multiple backgrounds. This lets you specify multiple backgrounds that are rendered atop one another in layers.
+
Mozilla-specific media features
+
Media features have been added for Mozilla-specific system metrics, so that media queries can be used to more safely check on the availability of features such as touch support.
+
Scaling background images
+
The background-size property from the CSS 3 Backgrounds and Borders draft is now supported under the name -moz-background-size.
+
WOFF font support
+
@font-face now supports the WOFF downloadable font file format.
+
Pointer events
+
The pointer-events property lets content specify whether or not an element may be the target of mouse pointer events.
+
+ +

Miscellaneous CSS changes

+ + + +

HTML

+ +
+
Using files from web applications
+
Support for the new HTML5 File API has been added to Gecko, making it possible for web applications to access local files selected by the user. This includes support for selecting multiple files using the input type="file" HTML element's new multiple attribute.
+
HTML5 video supports poster frames
+
The poster attribute is now supported for the video element, allowing content to specify a poster frame to be displayed until the video begins to play.
+
Checkboxes and radio buttons support the indeterminate property
+
HTML input elements of types checkbox and radio now support the indeterminate property, which allows a third, "indeterminate" state.
+
Canvas image smoothing can be controlled
+
The new mozImageSmoothingEnabled property can be used to turn on and off image smoothing when scaling in canvas elements.
+
Asynchronous script execution
+
By setting the async attribute on a script element, the script will not block loading or display of the rest of the page. Instead the script executes as soon as it is downloaded.
+
+ +

JavaScript

+ +

Gecko 1.9.2 introduces JavaScript 1.8.2, which adds a number of language features from the ECMAScript 5 standard:

+ + + +
+
+ +

DOM

+ +
+
Web workers can now self-terminate
+
Workers now support the nsIWorkerScope.close() method, which allows them to terminate themselves.
+
Drag and drop now supports files
+
The DataTransfer object provided to drag listeners now includes a list of files that were dragged.
+
Checking to see if an element matches a specified CSS selector
+
The new element.mozMatchesSelector method lets you determine whether or not an element matches a specified CSS selector. See bug 518003.
+
Detecting device orientation
+
Content can now detect the orientation of the device if it has a supported accelerometer, using the MozOrientation event. Firefox 3.6 supports the accelerometer in Mac laptops.
+
Detecting document width and height changes
+
The new MozScrollAreaChanged event is dispatched whenever the document's scrollWidth and/or scrollHeight properties change.
+
+ +

Miscellaneous DOM changes

+ + + +

XPath

+ +
+
The choose() XPath method is now supported
+
The choose() method is now supported by our implementation of XPath.
+
+ +

For XUL and add-on developers

+ +

If you're an extension developer, you should start by reading Updating extensions for Firefox 3.6, which offers a helpful overview of what changes may affect your extension. Plug-in developers should read Updating plug-ins for Firefox 3.6.

+ +

New features

+ +
+
Detecting device orientation
+
Content can now detect the orientation of the device if it has a supported accelerometer, using the MozOrientation event. Firefox 3.6 supports the accelerometer in Mac laptops.
+
Monitoring HTTP activity
+
You can now monitor HTTP transactions to observe requests and responses in real time.
+
Working with the Windows taskbar
+
It's now possible to customize the appearance of windows in the taskbar in Windows 7 or later. This has been disabled by default in Firefox 3.6.
+
+ +

Places

+ + + +

Storage

+ +
+
Locale-aware collation of data is now supported by the Storage API
+
Gecko 1.9.2 added several new collation methods to provide optimized collation (sorting) of results using locale-aware techniques.
+
Properties on a statement can now be enumerated
+
You can now use a for..in enumeration to enumerate all the properties on a statement.
+
mozIStorageStatement's getParameterIndex changed behavior between 3.5 and 3.6.
+
See bug 528166 for details.
+
Asynchronously bind multiple sets of parameters and execute a statement.
+
See bug 490085 for details. Documentation coming soon.
+
+ +

Preferences

+ + + +

Themes

+ +

See Updating themes for Firefox 3.6 for a list of changes related to themes.

+ +
+
Lightweight themes
+
Firefox 3.6 supports lightweight themes; these are easy-to-create themes that simply apply a background to the top (URL bar and button bar) and bottom (status bar) of browser windows. This is an integration of the existing Personas theme architecture into Firefox.
+
+ +

Miscellaneous

+ + + +

For Firefox/Gecko developers

+ +

Certain changes are only really interesting if you work on the internals of Firefox itself.

+ +

Interfaces merged

+ +

The following interfaces have been combined together:

+ + + +

Interfaces removed

+ +

The following interfaces have been removed entirely because they were unused, unimplemented, or obsolete:

+ + + +

Interfaces moved

+ +

The following interfaces have been relocated from their previous IDL files into new ones:

+ + + +

A large number of interfaces have been moved. See Interfaces moved in Firefox 3.6 for a complete list.

+ +

Other interface changes

+ +

The following assorted changes have been made:

+ + + +

Changes in accessibility code

+ + + +

See also

+ +
diff --git a/files/zh-tw/mozilla/firefox/releases/3/dom_improvements/index.html b/files/zh-tw/mozilla/firefox/releases/3/dom_improvements/index.html new file mode 100644 index 0000000000..315cc39037 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/3/dom_improvements/index.html @@ -0,0 +1,26 @@ +--- +title: Firefox 3 Dom Improvements +slug: Mozilla/Firefox/Releases/3/DOM_improvements +translation_of: Mozilla/Firefox/Releases/3/DOM_improvements +--- +
{{FirefoxSidebar}}

Firefox 3 對 DOM 的改善

+

Firefox 3 對 DOM 做了一些改善,改善重點之一就是加強對於「其他瀏覽器對 DOM 所增加的延伸規格」的支援。

+ +

參考資料

+ +

延伸閱讀

+ diff --git a/files/zh-tw/mozilla/firefox/releases/3/firefox_3_css_improvement/index.html b/files/zh-tw/mozilla/firefox/releases/3/firefox_3_css_improvement/index.html new file mode 100644 index 0000000000..bbad0696a8 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/3/firefox_3_css_improvement/index.html @@ -0,0 +1,30 @@ +--- +title: Firefox 3 CSS Improvement +slug: Mozilla/Firefox/Releases/3/Firefox_3_CSS_Improvement +translation_of: Mozilla/Firefox/releases/3/CSS_improvements +--- +
{{FirefoxSidebar}}

Firefox 3 CSS 的改善

+ +

參考資訊

+ +

延伸閱讀

+ diff --git a/files/zh-tw/mozilla/firefox/releases/3/index.html b/files/zh-tw/mozilla/firefox/releases/3/index.html new file mode 100644 index 0000000000..a6663801f8 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/3/index.html @@ -0,0 +1,93 @@ +--- +title: Firefox 3 技術文件 +slug: Mozilla/Firefox/Releases/3 +translation_of: Mozilla/Firefox/Releases/3 +--- +
{{FirefoxSidebar}}

Firefox 3 網站開發須知

+

 

+
+
+ Web application 需要更新的地方
+
+ 提供一些應用 Firefox 3 的新功能在 web applications 時可能需要注意的地方。
+
+ Online / Offline 事件
+
+ Firefox 3 支援 WHATWG 的 online/offline event,讓 applications/extensions 可以偵測目前是否有 active 的網際網路連線、目前是在線上還是斷線中。
+
+ Cross-site XMLHttpRequest
+
+ Firefox 3 支援了 W3C Access Control working draft,這讓你可以對其他網站作 XMLHttpRequests 以取得其他網站的資料,並加以管理,這讓你可以在自己建立的網站中,混入來自多個其他網站的內容。
+
+ Alternate style sheet
+
+ Firefox 3 支援 CSS object model alternate style sheet API。(見 Bug 200930)
+
+ Web-based protocol handlers
+
+ 在 Firefox 3,我們可以使用 navigator.registerProtocolHandler() 的方式把 web application 註冊為 protocal handler。
+
+ 使用 Canvas 來「畫」字
+
+ Firefox 3 支援用 mozilla 專用的非標準、實驗中的 API (mozXXX) 來處理 <canvas>
+
+ 支援在 Canvas 使用 transform
+
+ Firefox 3 支援在 <canvas> 上使用 transform() 與 setTransform()
+
+ 使用 microformat
+
+ Firefox 3 現在有 APIs 可以處理 microformat
+
+ Drag / drop 事件
+
+ Firefox 3 支援兩個新的 events,在「拖放」開始與結束的時候,可以傳給「拖放操作」的 source node。
+
+ HTML 5 的 focus 相關屬性
+
+ Firefox 3 支援 HTML 5 新增給 DOM 的兩個屬性 activeElementhasFocus
+
+ Offline resources on Firefox
+
+ Firefox 3 現在支援讓 web application 可以要求將 resources 存入快取,以便我們離線時可以執行 web applications。
+
+ CSS 的改善
+
+ Firefox 3 改善了對於 CSS 的支援。
+
+ DOM 的改善
+
+ Firefox 3 的 DOM implimentation 有一些新功能,其中包括:支援了 IE 對 DOM 作的某些 extensions。
+
+ Javascript 1.8 的支援
+
+ Firefox 3 現在支援 Javascript 1.8。(見 Bug 380236)
+
+ EXSLT 的支援
+
+ Firefox 3 支援了 a substantial subset of the EXSLT extensions to XSLT。
+
+ SVG 的改善
+
+ Firefox 3 大大提高了對 SVG 的支援,其中包括:支援了超過兩打的新 filters、好幾個新元素、新屬性,以及其他的改善。
+
+ Animated PNG 的支援
+
+ Firefox 3 現在支援動態 PNG 格式 (Animated PNG image format)
+
+ <a ping> 的支援
+
+ Firefox 3 現在支援用 <a ping> 去 ping URL,並且預設是 enable 的。
+
+

參考資料

+

Firefox 3 for developers

+

延伸閱讀

+ +
+  
+

{{ languages( { "en": "en/Firefox_3_for_developers", "es": "es/Firefox_3_para_desarrolladores", "fr": "fr/Firefox_3_pour_les_d\u00e9veloppeurs", "ja": "ja/Firefox_3_for_developers", "ko": "ko/Firefox_3_for_developers", "pl": "pl/Firefox_3_dla_programist\u00f3w", "pt": "pt/Firefox_3_para_desenvolvedores" } ) }}

diff --git a/files/zh-tw/mozilla/firefox/releases/35/index.html b/files/zh-tw/mozilla/firefox/releases/35/index.html new file mode 100644 index 0000000000..d15394097d --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/35/index.html @@ -0,0 +1,130 @@ +--- +title: Firefox 35 技術文件 +slug: Mozilla/Firefox/Releases/35 +translation_of: Mozilla/Firefox/Releases/35 +--- +
+ {{ ReleaseChannelInfo("35", "35", "January 2015", "Aurora") }}
+

Want to help document Firefox 35? See the list of bugs that need to be written about and pitch in!

+

Changes for Web developers

+

Developer Tools

+

Highlights:

+ +

All devtools bugs fixed between Firefox 34 and Firefox 35.

+

CSS

+ +

HTML

+ +

JavaScript

+ +

Interfaces/APIs/DOM

+ +

MathML

+ +

SVG

+

No change.

+

Audio/Video

+

No change.

+

Security

+ +

Changes for add-on and Mozilla developers

+

XUL

+ +

Older versions

+
+ +
diff --git "a/files/zh-tw/mozilla/firefox/releases/4/firefox_4_\351\226\213\347\231\274\350\200\205\346\226\260\345\212\237\350\203\275\346\246\202\350\246\275/index.html" "b/files/zh-tw/mozilla/firefox/releases/4/firefox_4_\351\226\213\347\231\274\350\200\205\346\226\260\345\212\237\350\203\275\346\246\202\350\246\275/index.html" new file mode 100644 index 0000000000..c36dad8487 --- /dev/null +++ "b/files/zh-tw/mozilla/firefox/releases/4/firefox_4_\351\226\213\347\231\274\350\200\205\346\226\260\345\212\237\350\203\275\346\246\202\350\246\275/index.html" @@ -0,0 +1,228 @@ +--- +title: Firefox 4 for developers +slug: Mozilla/Firefox/Releases/4/Firefox_4_開發者新功能概覽 +--- +
{{FirefoxSidebar}}

2010 年六月起進入 Beta 測試期的 Firefox 4,增進了效能、加強針對 HTML 5 及其他創新網際科技的支援程度,也更加安全。本文為網頁、附加元件、Gecko 平台開發者們提供這一版的簡要技術相關資訊。

+ +
+

{{ gecko_callout_heading("2") }}

+ +

Gecko 1.9.3 即將更名為 Gecko 2,但許多文件還沒有針對此點更新,在接下來的幾個星期中才會有所更動。

+
+ +

以下大部分的功能都已經可以在 逐日建置版中試用。

+ +
註:本文、以及本文所連結的其他文件仍持續編修中,很多文件的名稱只是暫定、有些主題的文件也可能會拆成幾份子文件以方便閱讀。中文團隊的目標將僅翻譯這份概覽,其他子文件則有待大家的幫忙。
+ +

Features for web developers

+ +

Gecko now uses the HTML5 parser, which fixes bugs, improves interoperability, and improves performance. It also lets content embed SVG and MathML directly in the HTML markup.

+ +

HTML

+ +
+
Introduction to the HTML5 parser
+
A look at what the HTML5 parser means to you, and how to embed SVG and MathML into your content inline.
+
Forms in HTML5
+
A look at improvements to web forms in HTML5.
+
HTML5 Sections
+
Gecko now supports the new HTML5 elements related to sections in a document: {{ HTMLElement("article") }}, {{ HTMLElement("section") }}, {{ HTMLElement("nav") }}, {{ HTMLElement("aside") }}, {{ HTMLElement("hgroup") }}, {{ HTMLElement("header") }} and {{ HTMLElement("footer") }}.
+
Other HTML5 elements
+
Gecko now also supports the following new HTML5 elements: {{ HTMLElement("mark") }}, {{ HTMLElement("figure") }} and  {{ HTMLElement("figcaption") }}.
+
WebSockets
+
A guide to using the new WebSockets API for real-time communication between a web application and a server.
+
+ +

Miscellaneous HTML changes

+ + + +

CSS

+ +
+
CSS transitions
+
New CSS transitions support is available in Firefox 4.
+
Computed values in CSS
+
Support for calc() to compute values in CSS is in progress. See {{ bug(363249) }}.
+
Selector grouping
+
Support for {{ cssxref(":-moz-any") }} to group selectors and factorize combinators.
+
Background image subrectangle support
+
The {{ cssxref("-moz-image-rect") }} property makes it possible to use subrectangles of images as a background image.
+
CSS touch properties
+
Support for touch properties is added. Details, and real article names, to come later.
+
Privacy and the :visited selector
+
Changes have been made to what information can be obtained about the style of visited links using CSS selectors. This may affect some web applications.
+
+ +

Miscellaneous CSS changes

+ + + +

Graphics and video

+ +
+
 
+
WebGL
+
The developing WebGL standard is now supported by Firefox.
+
Optimizing graphics performance
+
Tips and tricks for getting the most out of graphics and video performance in Firefox 4.
+
Support for WebM video
+
The new open WebM video format is supported by Gecko 1.9.3; support is included in nightlies as of 9 June.
+
Full screen API
+
Details coming soon.
+
SMIL animation
+
Support for SMIL animation of SVG is now available. See {{ bug(482402) }}.
+
Using SVG as images and as CSS backgrounds
+
You can now use SVG with the {{ htmlelement("img") }} element, as well as the background image in CSS. See {{ bug(272288) }}, {{ bug(276431) }} and {{ bug(231179) }}.
+
+ +

DOM

+ +
+
Obtaining boundary rectangles for ranges
+
The Range object now has getClientRects() and getBoundingClientRect() methods. See {{ bug(396392) }}.
+
Capturing mouse events on arbitrary elements
+
Support for the Internet Explorer-originated setCapture() and releaseCapture() APIs has been added. See {{ bug(503943) }}.
+
Manipulating the browser history
+
The existing document history object, available through the {{ domxref("window.history") }} object, now supports the new HTML5 pushState() and replaceState() methods.
+
Touch and multi-touch events
+
Support has been added for touch and multi-touch events.
+
IndexedDB
+
The proposed IndexedDB standard, which provides a local database store for web applications, will be supported by Firefox 4.
+
+ +

Miscellaneous DOM changes

+ + + +

Security

+ +
+
Introducing Content Security Policy
+
Content Security Policy (CSP) is a Mozilla proposal designed to help web designers and server administrators specify how content on their web sites interacts. The goal is to help detect and mitigate attacks including cross-site scripting and data injection attacks.
+
ForceTLS
+
Details soon.
+
The Account Manager
+
Details soon.
+
+ +

JavaScript

+ +

For an overview of the changes implemented in JavaScript 1.8.5, see New in JavaScript 1.8.5. JavaScript in Firefox 4 will have additional adherence to the ECMAScript 5 standard.

+ +

Changes for Mozilla and add-on developers

+ +

For helpful tips on updating existing extensions for Firefox 4, see Updating extensions for Firefox 4.

+ +

JavaScript code modules

+ +
+
Services.jsm
+
The Services.jsm code module provides getters that make it easy to obtain references to commonly-used services, such as the preferences service or the window mediator, among others.
+
+ +
+
JS-ctypes API
+
The JS-ctypes API makes it possible to call C-compatible foreign library functions without using XPCOM.
+
Add-ons Manager
+
The new Add-ons Manager provides information about installed add-ons, support for managing them, and provides ways to install and remove add-ons.
+
Loading code modules from chrome: URLs
+
You can now load JavaScript code modules using chrome: URLs, even inside JAR files.
+
+ +

DOM changes

+ +
+
{{ domxref("ChromeWorker") }}
+
A new type of worker for privileged code; this lets you use things like js-ctypes from workers in extensions and application code.
+
+ +

XUL

+ +

tabbrowser (gBrowser) changes

+ +

Several changes were made to the {{ XULElem("tabbrowser") }} element that impact extensions that interact with tabs.

+ + + +

Miscellaneous XUL changes

+ + + +

Storage

+ +

Miscellaneous storage API changes

+ + + +

XPCOM

+ +
+
XPCOM changes in Gecko 1.9.3
+
Details about changes to XPCOM that impact compatibility in Firefox 4.
+
Components.utils.getGlobalForObject()
+
This new method returns the global object with which an object is associated; this replaces a common use case of the now-removed __parent__.
+
+ +

Memory management

+ +
+
Infallible memory allocation
+
Mozilla now provides infallible memory allocators that are guaranteed not to return null. You should read this article to learn how they work and how to explicitly request fallible versus infallible memory allocation.
+
+ +

Other changes

+ +
+
Gopher support removed
+
The Gopher protocol is no longer supported natively. Continued support is available via the OverbiteFF extension.
+
Default plugin removed
+
The default plugin has been removed. The application plugins folder has also been removed by default, however support for installing plugins via this folder still exists. See bug 533891.
+
Extension Manager replaced with AddonManager
+
nsIExtensionManager has been replaced by AddonManager. Since there is apparently no way at present to obtain the install location from a given extension ID, the closest workaround is to use the directory service to find the profile directory and append "extensions" to it (though this approach will not catch extensions outside of the profile directory or those which are aliased to another location).
+
+ +

參考

+ + diff --git a/files/zh-tw/mozilla/firefox/releases/4/index.html b/files/zh-tw/mozilla/firefox/releases/4/index.html new file mode 100644 index 0000000000..394f07815e --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/4/index.html @@ -0,0 +1,231 @@ +--- +title: Firefox 4 技術文件 +slug: Mozilla/Firefox/Releases/4 +translation_of: Mozilla/Firefox/Releases/4 +--- +
{{FirefoxSidebar}}

2010 年六月起進入 Beta 測試期的 Firefox 4,增進了效能、加強針對 HTML 5 及其他創新網際科技的支援程度,也更加安全。本文為網頁、附加元件、Gecko 平台開發者們提供這一版的簡要技術相關資訊。

+ +
+

{{ gecko_callout_heading("2") }}

+ +

Gecko 1.9.3 即將更名為 Gecko 2,但許多文件還沒有針對此點更新,在接下來的幾個星期中才會有所更動。

+
+ +

以下大部分的功能都已經可以在 逐日建置版中試用。

+ +
註:本文、以及本文所連結的其他文件仍持續編修中,很多文件的名稱只是暫定、有些主題的文件也可能會拆成幾份子文件以方便閱讀。中文團隊的目標將僅翻譯這份概覽,其他子文件則有待大家的幫忙。
+ +

Features for web developers

+ +

Gecko now uses the HTML5 parser, which fixes bugs, improves interoperability, and improves performance. It also lets content embed SVG and MathML directly in the HTML markup.

+ +

HTML

+ +
+
Introduction to the HTML5 parser
+
A look at what the HTML5 parser means to you, and how to embed SVG and MathML into your content inline.
+
Forms in HTML5
+
A look at improvements to web forms in HTML5.
+
HTML5 Sections
+
Gecko now supports the new HTML5 elements related to sections in a document: {{ HTMLElement("article") }}, {{ HTMLElement("section") }}, {{ HTMLElement("nav") }}, {{ HTMLElement("aside") }}, {{ HTMLElement("hgroup") }}, {{ HTMLElement("header") }} and {{ HTMLElement("footer") }}.
+
Other HTML5 elements
+
Gecko now also supports the following new HTML5 elements: {{ HTMLElement("mark") }}, {{ HTMLElement("figure") }} and  {{ HTMLElement("figcaption") }}.
+
WebSockets
+
A guide to using the new WebSockets API for real-time communication between a web application and a server.
+
+ +

Miscellaneous HTML changes

+ + + +

CSS

+ +
+
CSS transitions
+
New CSS transitions support is available in Firefox 4.
+
Computed values in CSS
+
Support for calc() to compute values in CSS is in progress. See {{ bug(363249) }}.
+
Selector grouping
+
Support for {{ cssxref(":-moz-any") }} to group selectors and factorize combinators.
+
Background image subrectangle support
+
The {{ cssxref("-moz-image-rect") }} property makes it possible to use subrectangles of images as a background image.
+
CSS touch properties
+
Support for touch properties is added. Details, and real article names, to come later.
+
Privacy and the :visited selector
+
Changes have been made to what information can be obtained about the style of visited links using CSS selectors. This may affect some web applications.
+
+ +

Miscellaneous CSS changes

+ + + +

Graphics and video

+ +
+
 
+
WebGL
+
The developing WebGL standard is now supported by Firefox.
+
Optimizing graphics performance
+
Tips and tricks for getting the most out of graphics and video performance in Firefox 4.
+
Support for WebM video
+
The new open WebM video format is supported by Gecko 1.9.3; support is included in nightlies as of 9 June.
+
Full screen API
+
Details coming soon.
+
SMIL animation
+
Support for SMIL animation of SVG is now available. See {{ bug(482402) }}.
+
Using SVG as images and as CSS backgrounds
+
You can now use SVG with the {{ htmlelement("img") }} element, as well as the background image in CSS. See {{ bug(272288) }}, {{ bug(276431) }} and {{ bug(231179) }}.
+
+ +

DOM

+ +
+
Obtaining boundary rectangles for ranges
+
The Range object now has getClientRects() and getBoundingClientRect() methods. See {{ bug(396392) }}.
+
Capturing mouse events on arbitrary elements
+
Support for the Internet Explorer-originated setCapture() and releaseCapture() APIs has been added. See {{ bug(503943) }}.
+
Manipulating the browser history
+
The existing document history object, available through the {{ domxref("window.history") }} object, now supports the new HTML5 pushState() and replaceState() methods.
+
Touch and multi-touch events
+
Support has been added for touch and multi-touch events.
+
IndexedDB
+
The proposed IndexedDB standard, which provides a local database store for web applications, will be supported by Firefox 4.
+
+ +

Miscellaneous DOM changes

+ + + +

Security

+ +
+
Introducing Content Security Policy
+
Content Security Policy (CSP) is a Mozilla proposal designed to help web designers and server administrators specify how content on their web sites interacts. The goal is to help detect and mitigate attacks including cross-site scripting and data injection attacks.
+
ForceTLS
+
Details soon.
+
The Account Manager
+
Details soon.
+
+ +

JavaScript

+ +

For an overview of the changes implemented in JavaScript 1.8.5, see New in JavaScript 1.8.5. JavaScript in Firefox 4 will have additional adherence to the ECMAScript 5 standard.

+ +

Changes for Mozilla and add-on developers

+ +

For helpful tips on updating existing extensions for Firefox 4, see Updating extensions for Firefox 4.

+ +

JavaScript code modules

+ +
+
Services.jsm
+
The Services.jsm code module provides getters that make it easy to obtain references to commonly-used services, such as the preferences service or the window mediator, among others.
+
+ +
+
JS-ctypes API
+
The JS-ctypes API makes it possible to call C-compatible foreign library functions without using XPCOM.
+
Add-ons Manager
+
The new Add-ons Manager provides information about installed add-ons, support for managing them, and provides ways to install and remove add-ons.
+
Loading code modules from chrome: URLs
+
You can now load JavaScript code modules using chrome: URLs, even inside JAR files.
+
+ +

DOM changes

+ +
+
{{ domxref("ChromeWorker") }}
+
A new type of worker for privileged code; this lets you use things like js-ctypes from workers in extensions and application code.
+
+ +

XUL

+ +

tabbrowser (gBrowser) changes

+ +

Several changes were made to the {{ XULElem("tabbrowser") }} element that impact extensions that interact with tabs.

+ + + +

Miscellaneous XUL changes

+ + + +

Storage

+ +

Miscellaneous storage API changes

+ + + +

XPCOM

+ +
+
XPCOM changes in Gecko 1.9.3
+
Details about changes to XPCOM that impact compatibility in Firefox 4.
+
Components.utils.getGlobalForObject()
+
This new method returns the global object with which an object is associated; this replaces a common use case of the now-removed __parent__.
+
+ +

Memory management

+ +
+
Infallible memory allocation
+
Mozilla now provides infallible memory allocators that are guaranteed not to return null. You should read this article to learn how they work and how to explicitly request fallible versus infallible memory allocation.
+
+ +

Other changes

+ +
+
Gopher support removed
+
The Gopher protocol is no longer supported natively. Continued support is available via the OverbiteFF extension.
+
Default plugin removed
+
The default plugin has been removed. The application plugins folder has also been removed by default, however support for installing plugins via this folder still exists. See bug 533891.
+
Extension Manager replaced with AddonManager
+
nsIExtensionManager has been replaced by AddonManager. Since there is apparently no way at present to obtain the install location from a given extension ID, the closest workaround is to use the directory service to find the profile directory and append "extensions" to it (though this approach will not catch extensions outside of the profile directory or those which are aliased to another location).
+
+ +

參考

+ + + +

{{ languages( { "en": "en/Firefox_4_for_developers", "de": "de/Firefox_4_fur_Entwickler", "ja": "ja/Firefox_4_for_developers"} ) }}

diff --git a/files/zh-tw/mozilla/firefox/releases/5/index.html b/files/zh-tw/mozilla/firefox/releases/5/index.html new file mode 100644 index 0000000000..cba3c4563b --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/5/index.html @@ -0,0 +1,165 @@ +--- +title: Firefox 5 技術文件 +slug: Mozilla/Firefox/Releases/5 +translation_of: Mozilla/Firefox/Releases/5 +--- +
{{FirefoxSidebar}}
+ +

Firefox 5,基於 Gecko 5.0,在 2011 年六月21日發行。本文將提供這次發行會對開發者所生影響之資訊。

+ +

網路開發者的改變

+ +

HTML

+ + + +

Canvas improvements

+ + + +

CSS

+ +
+
CSS animations
+
Support for CSS animations has been added, using the -moz- prefix for now.
+
+ +

DOM

+ + + +

JavaScript

+ + + +

SVG

+ + + +

HTTP

+ + + +

MathML

+ + + +

Developer tools

+ + + +

Changes for Mozilla and add-on developers

+ +

For a guide to updating your add-on for Firefox 5, please see Updating add-ons for Firefox 5.

+ +
Note: Firefox 5 requires that binary components be recompiled, as do all major releases of Firefox. See Binary Interfaces for details.
+ +

Changes to JavaScript code modules

+ +

New JavaScript code modules

+ + + +

NetUtil.jsm

+ + + +

Interface changes

+ + + +

New interfaces

+ + + +

Removed interfaces

+ +

The following interfaces were implementation details that are no longer needed:

+ + + +

Debugging aids

+ + + +

JavaScript API (SpiderMonkey)

+ + + +

Build system changes

+ + + +

See also

+ +
{{Firefox_for_developers('4')}}
diff --git a/files/zh-tw/mozilla/firefox/releases/6/index.html b/files/zh-tw/mozilla/firefox/releases/6/index.html new file mode 100644 index 0000000000..bd3141a249 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/6/index.html @@ -0,0 +1,291 @@ +--- +title: Firefox 6 技術文件 +slug: Mozilla/Firefox/Releases/6 +translation_of: Mozilla/Firefox/Releases/6 +--- +

Firefox 6, based on Gecko 6.0, was released on August 16, 2011. This article provides links to information about the changes that affect developers in this release.

+

Changes for web developers

+

HTML

+
+
+ +

CSS

+
+
+ -moz-text-decoration-color
+
+ This new property lets you set the color used by text decorations, such as underlines, overlines, and strikethroughs.
+
+ -moz-text-decoration-line
+
+ This new property lets you set the kind of text decorations added to an element.
+
+ -moz-text-decoration-style
+
+ This new property lets you set the style of text decorations, such as underlines, overlines, and strikethroughs. Styles include single-strokes, double strokes, wavy lines, dotted lines, and so forth.
+
+ -moz-hyphens
+
+ This new property lets you control how hyphenation of words during line wrapping is handled.
+
+ -moz-orient
+
+ A new (currently Mozilla-specific) property which lets you control the vertical or horizontal orientation of certain elements (particularly <progress>).
+
+ ::-moz-progress-bar
+
+ A Mozilla-specific pseudo-element that lets you style the area of an <progress> element representing the completed portion of a task.
+
+

Other changes

+ +

DOM

+
+
+ Using media queries from code
+
+ You can now test the result of a media query string programmatically using the window.matchMedia() method and the MediaQueryList interface.
+
+ Touch events
+
+ Firefox 6 adds support for W3C standard touch events; these make it easy to interpret one or more touches at a time on touch-sensitive surfaces such as touch screens and trackpads.
+
+ Server-sent events
+
+ Server-sent events make it possible for a web application to ask a server to send events just like any locally-created DOM event.
+
+ +

JavaScript

+ +

SVG

+ +

MathML

+ +

Accessibility (ARIA)

+ +

Networking

+
+
+ WebSockets
+
+ WebSockets was updated to protocol version 07 for Firefox 6. In addition, the global WebSocket object has been renamed to MozWebSocket to prevent it from incorrectly being used to detect the availability of unprefixed WebSockets.
+
+ +

Other changes

+ +

Changes for Mozilla and add-on developers

+

For an overview of the changes you may need to make in order to make your add-on compatible with Firefox 6, see Updating add-ons for Firefox 6.

+
+ Note: Firefox 6 requires that binary components be recompiled, as do all major releases of Firefox. See Binary Interfaces for details.
+

JavaScript code modules

+

FileUtils.jsm

+ +

XPCOMUtils.jsm

+ +

XPCOM

+ +

Using the DOM from chrome

+
+
+ Using the DOM File API in chrome code
+
+ Although you've always been able to use the DOM File API from chrome code, the File constructor now supports specifying a local pathname string when used from chrome. In addition, you can also specify the file to access using the DOM File API using an nsIFile object.
+
+

Interface changes

+ +

New interfaces

+
+
+ mozIAsyncFavicons
+
+ A new service that lets you access the favicon service asynchronously.
+
+ nsIEventSource
+
+ Details forthcoming.
+
+ nsIGSettingsCollection
+
+ Details forthcoming.
+
+ nsIGSettingsService
+
+ Details forthcoming.
+
+ nsIHttpUpgradeListener
+
+ The callback interface for handling HTTP upgrade requests via the nsIHttpChannelInternal.HTTPUpgrade() method.
+
+ nsIStructuredCloneContainer
+
+ A container for objects that have been serialized using the structured clone algorithm.
+
+ nsITelemetry
+
+ Implements telemetry support to allow recording of telemetry data to be used to present histograms for performance tracking purposes. See bug 649502 and bug 585196.
+
+ nsITimedChannel
+
+ See bug 576006.
+
+ nsIWebSocketListener
+
+ See bug 640003.
+
+ nsIWebSocketProtocol
+
+ See bug 640003.
+
+

Removed interfaces

+

The following interfaces were implementation details that are no longer needed:

+ +

Other changes

+
+
+ Using preferences from application code
+
+ A new static API is available for easily accessing preferences; this is only available to application code and can't be used by add-ons.
+
+

See also

+
+
diff --git a/files/zh-tw/mozilla/firefox/releases/61/index.html b/files/zh-tw/mozilla/firefox/releases/61/index.html new file mode 100644 index 0000000000..e0b9d26ae6 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/61/index.html @@ -0,0 +1,139 @@ +--- +title: Firefox 61 技術變動摘要 +slug: Mozilla/Firefox/Releases/61 +translation_of: Mozilla/Firefox/Releases/61 +--- +
{{FirefoxSidebar}}
{{draft}}
+ +

此文章提供 Firefox 61 中與開發者較為相關之變動資訊。Firefox 61 預定於 2018 年 6 月 26 日正式發表

+ +

Web 開發相關變動

+ +

開發者工具

+ +

無變動。

+ +

HTML

+ +

無變動。

+ +

CSS

+ +

無變動。

+ +

SVG

+ + + +

JavaScript

+ + + +

API

+ +

新 API

+ +

無變動。

+ +

DOM

+ + + +

DOM 事件

+ +

無變動。

+ +

Service workers

+ +

無變動。

+ +

Media 及 WebRTC

+ +

{{domxref("AudioContext.AudioContext", "AudioContext()")}} 建構式現在可以選擇性傳入一個 {{domxref("AudioContextOptions")}} 型態的 options 參數,用以調整新的 AudioContext 下偏好的延遲時間及取樣率。

+ +

Canvas 及 WebGL

+ +

無變動。

+ +

CSSOM

+ +

無變動。

+ +

HTTP

+ + + +

安全性

+ +

無變動。

+ +

外掛程式

+ +

無變動。

+ +

其他

+ +

無變動。

+ +

Web 平台中移除的項目

+ +

HTML

+ +

無變動。

+ +

CSS

+ +

無變動。

+ +

APIs

+ +

無變動。

+ +

SVG

+ + + +

其他

+ +

無變動。

+ +

附加元件及 Mozilla 軟體開發相關變動

+ +

WebExtensions

+ +

無變動。

+ +

請參見

+ + + +

舊版資訊

+ +

{{Firefox_for_developers(60)}}

+ +

 

diff --git a/files/zh-tw/mozilla/firefox/releases/68/index.html b/files/zh-tw/mozilla/firefox/releases/68/index.html new file mode 100644 index 0000000000..bd6a7e5008 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/68/index.html @@ -0,0 +1,240 @@ +--- +title: Firefox 68 for developers +slug: Mozilla/Firefox/Releases/68 +translation_of: Mozilla/Firefox/Releases/68 +--- +

{{FirefoxSidebar}}

+ +

This article provides information about the changes in Firefox 68 that will affect developers. Firefox 68 was released on July 9, 2019.

+ +

Changes for web developers

+ +

Developer tools

+ +

Browser/web console

+ + + +

JavaScript debugger

+ + + +

Network monitor

+ + + +

Page inspector

+ + + +

Storage inspector

+ + + +

Other

+ + + +

Removals

+ + + +

HTML

+ + + +

 Removals

+ + + +

CSS

+ + + +

Removals

+ + + +

SVG

+ +

No changes.

+ +

JavaScript

+ + + +

APIs

+ +

CSS Object Model (CSSOM)

+ + + +

DOM

+ + + +

DOM events

+ + + +

Media, Web Audio, and WebRTC

+ + + +

Removals

+ + + +

HTTP

+ + + +

Removals

+ + + +

Security

+ + + +

WebDriver conformance (Marionette)

+ +

Bug fixes

+ + + +

Other

+ + + +

Plugins

+ +

No changes.

+ +

Changes for add-on developers

+ +

API changes

+ + + +

Manifest changes

+ +

No changes.

+ +

See also

+ + + +

Older versions

+ +

{{Firefox_for_developers(67)}}

diff --git a/files/zh-tw/mozilla/firefox/releases/7/index.html b/files/zh-tw/mozilla/firefox/releases/7/index.html new file mode 100644 index 0000000000..3faf9bd904 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/7/index.html @@ -0,0 +1,189 @@ +--- +title: Firefox 7 技術文件 +slug: Mozilla/Firefox/Releases/7 +translation_of: Mozilla/Firefox/Releases/7 +--- +
{{FirefoxSidebar}}

Firefox 7 shipped on September 27, 2011. This article provides information about the changes that affect developers -- both of web content and of Firefox add-ons.

+

Changes for web developers

+

HTML

+ +

Canvas

+ +

CSS

+ +

MathML

+ +

DOM

+ +

JavaScript

+ +

WebSockets

+ +

console API

+ +
+

Web timing

+ +

XML

+ +
+

Changes for Mozilla and add-on developers

+

These changes affect add-on developers as well as developers working on or with Mozilla code itself. Add-on developers should see Updating extensions for Firefox 7 for additional information.

+
+ Note: Firefox 7 requires that binary components be recompiled, as do all major releases of Firefox. See Binary Interfaces for details.
+

JavaScript code modules

+

FileUtils.jsm

+ +

AddonManager.jsm

+ +

XUL

+ +

XPCOM

+ +

Memory reporters

+

Support has been added for multi-reporters; that is, memory reporters that gather data on request and call a callback for each generated result. See {{ interface("nsIMemoryMultiReporter") }} and {{ interface("nsIMemoryMultiReporterCallback") }} for the relevant interfaces, as well as the {{ ifmethod("nsIMemoryReporterManager", "registerMultiReporter") }} and {{ ifmethod("nsIMemoryReporterManager", "unregisterMultiReporter") }} methods.

+

User experience changes

+ +

Changes to the build system

+ +

Interface changes

+ +

New interfaces

+
+
+ {{ interface("nsIDOMFontFace") }}
+
+ Describes a single font face.
+
+ {{ interface("nsIDOMFontFaceList") }}
+
+ Describes a list of font faces, each represented by {{ interface("nsIDOMFontFace") }}.
+
+

Removed interfaces

+

The following interfaces were implementation details that are no longer needed:

+ +

The following interfaces were removed as part of the removal of the ActiveX embedding API:

+ +

Other Changes

+ +

See also

+
+ {{Firefox_for_developers('6')}}
diff --git a/files/zh-tw/mozilla/firefox/releases/8/index.html b/files/zh-tw/mozilla/firefox/releases/8/index.html new file mode 100644 index 0000000000..51ca78d6e7 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/8/index.html @@ -0,0 +1,259 @@ +--- +title: Firefox 8 技術文件 +slug: Mozilla/Firefox/Releases/8 +translation_of: Mozilla/Firefox/Releases/8 +--- +

Firefox 8 was released on November 8, 2011. This article provides information both for web developers and for add-on and Mozilla project developers to help take full advantage of the features of this release.

+ +

Changes for web developers

+ +

HTML

+ + + +

DOM

+ + + +

JavaScript

+ + + +

CSS

+ + + +

Network

+ + + +

WebSockets

+ + + +

WebGL

+ + + +

MathML

+ + + +

Developer tools

+ + + +

Changes for Mozilla and add-on developers

+ +

See Updating add-ons for Firefox 8 for a guide to changes you're likely to have to make to make your add-ons compatible with Firefox 8.

+ +
Note: Firefox 8 requires that binary components be recompiled, as do all major releases of Firefox. See Binary Interfaces for details.
+ +

XPCOM

+ +
+
Components.utils
+
The new methods Components.utils.createObjectIn() and Components.utils.makeObjectPropsNormal() have been created to make it easier to create objects in specific compartments.
+
+ + + + + +

Workers

+ +

It is no longer possible to access XPCOM objects from ChromeWorkers. XPConnect has been disabled in worker contexts as of bug 649537.

+ +

XUL

+ + + +

Changes to the build system

+ + + +

Chrome registration

+ + + +

Interface changes

+ + + +

Removed interfaces

+ +

The following interfaces were implementation details that are no longer needed:

+ + + +

The nsIWorkerFactory interface has been removed as well. Workers can still be created using the Worker and ChromeWorker constructors.

+ +

Other changes

+ + + +

See also

+ + diff --git a/files/zh-tw/mozilla/firefox/releases/9/index.html b/files/zh-tw/mozilla/firefox/releases/9/index.html new file mode 100644 index 0000000000..39e727c628 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/9/index.html @@ -0,0 +1,231 @@ +--- +title: Firefox 9 技術文件 +slug: Mozilla/Firefox/Releases/9 +translation_of: Mozilla/Firefox/Releases/9 +--- +
+ +

Firefox 9 was released for Windows on December 20, 2011. Mac and Linux version 9.0.1, which fixed a crashing bug discovered at the last minute, were released on December 21, 2011.

+ +

Changes for web developers

+ +

HTML

+ + + +

CSS

+ + + +

JavaScript

+ +

No change.

+ +

DOM

+ +
+
Using full-screen mode
+
The new full-screen API provides a way to present content using the entire screen, with no browser interface. This is great for video and games. This API is currently experimental and prefixed.
+
+ + + +

Workers

+ + + +

WebGL

+ + + +

MathML

+ + + +

Networking

+ + + +

Developer tools

+ + + +

Changes for Mozilla and add-on developers

+ +

See Updating add-ons for Firefox 9 for an overview of the changes you may need to make to get your add-ons working in Firefox 9.

+ +

XUL

+ + + +

JavaScript code module changes

+ + + +

Service changes

+ + + +

NSPR

+ + + +

Interface changes

+ +

Removed interfaces

+ + + +

Miscellaneous interface changes

+ + + +

IDL parser

+ +

The IDL parser no longer includes support for the never fully-implemented notion of unique pointers.

+ +

Build system changes

+ + + +

Other changes

+ + + +

See also

+ +
diff --git a/files/zh-tw/mozilla/firefox/releases/index.html b/files/zh-tw/mozilla/firefox/releases/index.html new file mode 100644 index 0000000000..6ef85761f2 --- /dev/null +++ b/files/zh-tw/mozilla/firefox/releases/index.html @@ -0,0 +1,12 @@ +--- +title: Firefox 各版本技術文件 +slug: Mozilla/Firefox/Releases +tags: + - Firefox + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Firefox/Releases +--- +
{{FirefoxSidebar}}

這個頁面整合了 Firefox 每次釋出時的技術文件。這些文件讓您能夠清楚知道各個 Firefox 版本釋出時新增了哪些新功能及修正了哪些錯誤。

+
+ {{ListSubpages("",1,0,1)}}
diff --git a/files/zh-tw/mozilla/gecko/chrome/api/browser_api/index.html b/files/zh-tw/mozilla/gecko/chrome/api/browser_api/index.html new file mode 100644 index 0000000000..faa28e0f03 --- /dev/null +++ b/files/zh-tw/mozilla/gecko/chrome/api/browser_api/index.html @@ -0,0 +1,158 @@ +--- +title: Browser API +slug: Mozilla/Gecko/Chrome/API/Browser_API +translation_of: Mozilla/Gecko/Chrome/API/Browser_API/Using +--- +

{{ non-standard_header() }}

+

{{ B2GOnlyHeader2('privileged') }}

+

摘要

+

HTML Browser API 其實是 HTML <iframe> 元素的延伸,可讓 Web Apps 建構瀏覽器或類似瀏覽器的 Apps。主要可分為 2 大項:

+ +

另在「嵌入式內容就是 1 個 Open Web App」的情況下,將於合適的 Apps 環境 (如權限) 中載入該內容。

+

用途

+

設定了 mozbrowser 屬性之後,即可將 <iframe> 轉為瀏覽器框架:

+
<iframe src="http://hostname.tld" mozbrowser>
+

如果要嵌入 Open Web Apps,就必須提供 mozapp 屬性,且導向 Apps 的 manifest 檔案之路徑應為:

+
<iframe src="http://hostname.tld" mozapp='http://path/to/manifest.webapp' mozbrowser>
+

最後透過 remote 屬性,<iframe> 內容可載入至本身的子處理程序 (Child process) 中,藉以分離出「嵌入此 <iframe> 頁面」的處理程序。

+
<iframe src="http://hostname.tld" mozbrowser remote>
+
+

警告:因應安全考量,若要從未知/未經信任的來源下載內容,則必備最後一項屬性。若要略過此屬性,則 Apps 可能受到惡意網站的危害。

+
+

權限

+

任何 Apps 若要嵌入瀏覽器框架,則其 app manifest 檔案中必備 browser 權限。

+
{
+  "permissions": {
+    "browser": {}
+  }
+}
+

此外,若要嵌入 Open Web Apps,則該 App 亦需具備 embed-apps 權限。

+
{
+  "permissions": {
+    "browser": {},
+    "embed-apps": {}
+  }
+}
+

其他函式

+

為因應瀏覽器 <iframe> 的需求,Firefox OS 另擴充了 HTMLIFrameElement DOM 介面。下列新函式將為 <iframe> 提供更多功能:

+

存取 (Navigation) 函式

+

這些函式可存取 <iframe> 的瀏覽記錄,為建構「停止」、「上一頁」、「下一頁」、「重新載入」等按鈕所必備。

+ +

效能函式

+

這些函式可管理瀏覽器 <iframe> 所使用的資源。特別適於建構分頁式瀏覽器的應用。

+ +

事件函式

+

為了管理瀏覽器 <iframe> 的內容,另新增了許多新事件 (如下所示)。下列函式即用以處理這些事件:

+ +

其他函式

+

這些函式適於使用瀏覽器 <iframe> 的 Apps。

+ +

事件

+

若要讓 Apps 管理瀏覽器 <iframe>,則該 Apps 將監聽瀏覽器 <iframe> 中發生的新事件。監聽的新事件如下:

+ +

範例

+

此範例可建構最基本的瀏覽器 Apps。

+

HTML

+

在 HTML 中,我們只要新增 1 組 URL 位址列、1個「Go」與「Stop」按鈕、1 組瀏覽器 <iframe>

+
<header>
+  <input id="url">
+  <button id="go">Go</button>
+  <button id="stop">Stop</button>
+</header>
+
+<iframe src="about:blank" mozbrowser remote></iframe>
+
+

CSS

+

變個小小的 CSS 戲法,即可切換按鈕為「Go」與「Stop」。

+
button:disabled {
+  display: none;
+}
+

JavaScript

+

現在可加進必要的功能:

+
document.addEventListener("DOMContentLoaded", function () {
+  var url  = document.getElementById("url");
+  var go   = document.getElementById("go");
+  var stop = document.getElementById("stop");
+
+  var browser = document.getElementsByTagName("iframe")[0];
+
+  // This function is used to switch the Go and Stop button
+  // If the browser is loading content, "Go" is disabled and "Stop" is enabled
+  // Otherwise, "Go" is enabled and "Stop" is disabled
+  function uiLoading(isLoading) {
+      go.disabled =  isLoading;
+    stop.disabled = !isLoading;
+  }
+
+  go.addEventListener("touchend", function () {
+    browser.setAttribute("src", url.value);
+  });
+
+  stop.addEventListener("touchend", function () {
+    browser.stop();
+  });
+
+  // When the browser starts loading content, we switch the "Go" and "Stop" buttons
+  browser.addEventListener('mozbrowserloadstart', function () {
+    uiLoading(true);
+  });
+
+  // When the browser finishes loading content, we switch back the "Go" and "Stop" buttons
+  browser.addEventListener('mozbrowserloadend', function () {
+    uiLoading(false);
+  });
+
+  // In case of error, we also switch back the "Go" and "Stop" buttons
+  browser.addEventListener('mozbrowsererror', function (event) {
+    uiLoading(false);
+    alert("Loading error: " + event.detail);
+  });
+
+  // When a user follows a link, we make sure the new location is displayed in the address bar
+  browser.addEventListener('mozbrowserlocationchange', function (event) {
+    url.value = event.detail;
+  });
+});
+

另可參閱

+ diff --git a/files/zh-tw/mozilla/gecko/chrome/api/index.html b/files/zh-tw/mozilla/gecko/chrome/api/index.html new file mode 100644 index 0000000000..7c32384981 --- /dev/null +++ b/files/zh-tw/mozilla/gecko/chrome/api/index.html @@ -0,0 +1,14 @@ +--- +title: Chrome-only API reference +slug: Mozilla/Gecko/Chrome/API +translation_of: Mozilla/Gecko/Chrome/API +--- +
{{FirefoxSidebar}}
+ +

此頁面列出了僅能在 Gecko Chrome 中執行的 APIs(and sometimes in other privileged circumstances.)。

+ +
+

Note: Most of the APIs exposed to the Web in general are also usable in Chrome code: see Web APIs for a list of these.

+
+ +

{{SubpagesWithSummaries}}

diff --git a/files/zh-tw/mozilla/gecko/chrome/index.html b/files/zh-tw/mozilla/gecko/chrome/index.html new file mode 100644 index 0000000000..5701f56b12 --- /dev/null +++ b/files/zh-tw/mozilla/gecko/chrome/index.html @@ -0,0 +1,15 @@ +--- +title: Gecko Chrome +slug: Mozilla/Gecko/Chrome +tags: + - Chrome + - Gecko + - Mozilla + - Overview +translation_of: Mozilla/Gecko/Chrome +--- +
{{FirefoxSidebar}}
+ +

此頁面包含了於 Gecko 中執行 Chrome 程式碼的相關資訊。

+ +

{{SubpagesWithSummaries}}

diff --git a/files/zh-tw/mozilla/gecko/index.html b/files/zh-tw/mozilla/gecko/index.html new file mode 100644 index 0000000000..ce55ea402f --- /dev/null +++ b/files/zh-tw/mozilla/gecko/index.html @@ -0,0 +1,65 @@ +--- +title: Gecko +slug: Mozilla/Gecko +translation_of: Mozilla/Gecko +--- +
+

Gecko是一個排版引擎,一開始叫做NGLayout,屬於Mozilla專案。Gecko的功能就是讀取網頁內容,如 HTML, CSS, XUL, JavaScript,然後解析將內容顯示在螢幕上或印出來,在以XUL為基礎的應用程式中,Gecko也是用來解析生成應用程式的UI介面。

+
+ +

許多應用程式中都有使用到Gecko,包括一些瀏覽器,如Firefox, SeaMonkey等等 (完整列表請參考維基百科Gecko的文章.) 。使用相同版本Gecko的程式對於標準都有著相同的支援。

+ + + + + + + + +
+

文件

+ +
+
Chrome
+
+

這個頁面包含 Gecko 運行 Chrome 專有程式碼的訊息。

+
+
+ +
+
Gecko FAQ
+
常見問題
+
Gecko DOM 參考
+
DOM參考文件
+
Gecko 事件參考
+
Gecko和Mozilla程式內各項事件的參考文件;對於網頁標準的DOM事件,請參考 DOM event reference.
+
Gecko 版本和對應的應用程式
+
Geck版本和各應用程式所用的Gecko版本列表
+
Mozilla 的排版介紹
+
排版相關的技術探討
+
應用 Mozilla
+
在你自己的應用程式中使用Gecko
+
Gecko支援的字符集
+
Gecko支援的字符集列表
+
HTML 解析器運作
+
HTML解析器相關的執行緒探討
+
{{interwiki('wikimo', 'Gecko:Home_Page', 'Gecko Homepage on MozillaWiki')}}
+
使用者、產品規劃圖和最新資源的入口首頁
+
+ +

全部...

+
+

社群

+ +
    +
  • View Mozilla forums... {{DiscussionList("dev-tech-layout", "mozilla.dev.tech.layout")}}
  • +
+ + + +
+
Web Standards, XUL, Embedding Mozilla, Developing Mozilla
+
+
+ +

 

diff --git a/files/zh-tw/mozilla/index.html b/files/zh-tw/mozilla/index.html new file mode 100644 index 0000000000..3d0e3b309f --- /dev/null +++ b/files/zh-tw/mozilla/index.html @@ -0,0 +1,11 @@ +--- +title: Mozilla +slug: Mozilla +tags: + - NeedsTranslation + - TopicStub +translation_of: Mozilla +--- +

以下文章內容,與如何下載與組建 Mozilla 的程式碼有關。此外,也會收錄一些有助於理解程式碼如何運作、如何組建 Mozilla 程式的附加元件之類的文章。

+ +

{{LandingPageListSubpages}}

diff --git a/files/zh-tw/mozilla/infallible_memory_allocation/index.html b/files/zh-tw/mozilla/infallible_memory_allocation/index.html new file mode 100644 index 0000000000..06844eedd5 --- /dev/null +++ b/files/zh-tw/mozilla/infallible_memory_allocation/index.html @@ -0,0 +1,84 @@ +--- +title: 絕對可靠的記憶體配置 +slug: Mozilla/Infallible_memory_allocation +tags: + - 分配 + - 記憶體 +translation_of: Mozilla/Infallible_memory_allocation +--- +
{{gecko_minversion_header("2.0")}}
+ +

There's ongoing work to implement infallible memory allocators. These are memory allocation routines that never return null; that is, they always successfully return the requested block of memory. This is in contrast to a traditional, fallible memory allocator that can return null indicating that the request failed.

+ +

Currently, while code is transitioned to be compatible with infallible memory allocators, you have to explicitly decide whether to use infallible allocation or not. Eventually, however, the generic memory allocators (malloc() and realloc()) will become infallible.

+ +

記憶體配置要怎樣才能萬無一失?

+ +

「萬無一失」這個詞代表了配置記憶體時絕對會成功:你的程式碼永遠不會看到請求失敗,也就無須對失敗的情況做出處置。

+ +

平常在配置記憶體時,情況則不太一樣。在有限記憶體的狀況下,記憶體配置是有可能失敗的。然而,在平常配置失敗的程序中程式將不會返回到你的程式碼中,而是直接停止程式。不過這情況可能有點少見,因為記憶體管理系統通常都會為你要求的記憶體想盡辦法找到空間。

+ +

選擇記憶體分配器

+ +

當你在寫需要配置記憶體的程式時,可能需要遵守幾個規則以便幫助你決定是否在分配器使用萬無一失的策略:

+ + + +

明示的萬無一失記憶體分配器

+ +

下面的記憶體分配器都明確地標示出他們是萬無一失的,並且會一直保持下去。他們保證會回傳可用的記憶體指標:

+ +
p = moz_xmalloc();
+p = moz_xrealloc();
+
+ +
f = new Foo();
+fArray = new Foo[];
+
+ +
n = ::operator new(...);
+nArray = ::operator new[](...);
+
+ +

Explicitly fallible memory allocators

+ +

These memory allocators are explicitly fallible, and will remain so. When using these, you must check to ensure the resulting value isn't null before attempting to use the returned memory.

+ +
p = moz_malloc();
+p = moz_realloc();
+
+ +
namespace mozilla {
+  f = new (fallible) Foo();
+  fArray = new (fallible) Foo[];
+}
+
+ +
namespace mozilla {
+  n = ::operator new(..., fallible);
+  nArray = ::operator new[](..., fallible);
+}
+
+ +

最終萬無一失分配器

+ +

下面的記憶體目前是可能出錯的,但在未來將會變成萬無一失的:

+ +
p = malloc();
+p = realloc();
+
+ +

你也可以參看

+ + diff --git a/files/zh-tw/mozilla/introduction_to_layout_in_mozilla/index.html b/files/zh-tw/mozilla/introduction_to_layout_in_mozilla/index.html new file mode 100644 index 0000000000..0c0c5388db --- /dev/null +++ b/files/zh-tw/mozilla/introduction_to_layout_in_mozilla/index.html @@ -0,0 +1,358 @@ +--- +title: Introduction to Layout in Mozilla +slug: Mozilla/Introduction_to_Layout_in_Mozilla +translation_of: Mozilla/Introduction_to_Layout_in_Mozilla +--- +

概要

+ + + +

基本數據流

+ + + +

+ +

關鍵數據結構

+ +

+ + + +

+ +

關鍵數據結構

+ + + +

詳細執行步驟

+ + + +

設置

+ + + +

+ +

內容模型的構建

+ + + +

+ +

框架 Frame 的構建

+ + + +

+ +

Style 選定

+ + + +

回流

+ + + +

回流

+ + + +

增量回流

+ +

+ + + +

增量回流

+ +

+ + + +

增量回流

+ +

+ + + +

增量回流

+ +

+ + + +

繪畫

+ + + +

漸進

+ + + +

+ +

未來(?)技術講座

+ + + +

結論

+ + + +
+

原始文檔信息

+ + +
diff --git a/files/zh-tw/mozilla/javascript_code_modules/index.html b/files/zh-tw/mozilla/javascript_code_modules/index.html new file mode 100644 index 0000000000..72f737df9e --- /dev/null +++ b/files/zh-tw/mozilla/javascript_code_modules/index.html @@ -0,0 +1,102 @@ +--- +title: JavaScript code modules +slug: Mozilla/JavaScript_code_modules +tags: + - Add-ons + - Extensions + - JavaScript + - Landing + - Modules + - NeedsTranslation + - TopicStub + - XPCOM +translation_of: Mozilla/JavaScript_code_modules +--- +
{{gecko_minversion_header("1.9")}}
+ +

JavaScript code modules let multiple privileged JavaScript scopes share code. For example, a module could be used by Firefox itself as well as by extensions, in order to avoid code duplication.

+ +

General topics

+ +
+
Using JavaScript code modules
+
An introduction to how to use JavaScript code modules.
+
Components.utils.import
+
How to import a JavaScript code module.
+
Components.utils.unload {{gecko_minversion_inline("7.0")}}
+
How to unload a JavaScript code module.
+
Code snippets: Modules
+
Examples of how to use code modules.
+
Mozilla Labs JS Modules
+
This page features a list of JS modules, along with download links and documentation, that extension developers can use in their code.
+
+ +
+
+ +

Standard code modules

+ +
+
AddonManager.jsm {{gecko_minversion_inline("2.0")}}
+
Interface to install, manage, and uninstall add-ons.
+
AddonRepository.jsm {{gecko_minversion_inline("2.0")}}
+
Allows searching of the add-ons repository.
+
Assert.jsm {{gecko_minversion_inline("28.0")}}
+
Implements the CommonJS Unit Testing specification version 1.1, which provides a basic, standardized interface for performing in-code logical assertions with optional, customizable error reporting.
+
ctypes.jsm {{fx_minversion_inline("3.6")}}
+
Provides an interface that allows JavaScript code to call native libraries without requiring the development of an XPCOM component.
+
CustomizableUI.jsm {{fx_minversion_inline("29")}}
+
Allows you to interact with customizable buttons and items in Firefox's main window UI.
+
DeferredTask.jsm {{gecko_minversion_inline("18.0")}}
+
Run a task after a delay.
+
Dict.jsm {{gecko_minversion_inline("5.0")}}
+
Provides an API for key/value pair dictionaries.
+
DownloadLastDir.jsm {{gecko_minversion_inline("2.0")}}
+
Provides the path to the directory into which the last download occurred.
+
Downloads.jsm {{gecko_minversion_inline("23.0")}}
+
Provides a single entry point to interact with the downloading capabilities of the platform.
+
FileUtils.jsm {{gecko_minversion_inline("1.9.2")}}
+
Provides helpers for dealing with files.
+
Geometry.jsm {{gecko_minversion_inline("2.0")}}
+
Provides routines for performing basic geometric operations on points and rectangles.
+
HTTP.jsm {{gecko_minversion_inline("25.0")}}
+
A wrapper for XMLHttpRequest that provides convenient and simplified API for dealing with HTTP requests.
+
JNI.jsm {{fx_minversion_inline("17.0")}}
+
Abstracts the js-ctypes to provide an interface that allows JavaScript code to call code running in native JVMs.
+
ISO8601DateUtils.jsm
+
Provides routines to convert between JavaScript Date objects and ISO 8601 date strings.
+
Log.jsm (formerly log4moz) {{gecko_minversion_inline("27.0")}}
+
Provides a log4j style API for logging log messages to various endpoints, such as the Browser Console or a file on disk. This module was formerly
+
NetUtil.jsm
+
Provides helpful networking utility functions, including the ability to easily copy data from an input stream to an output stream asynchronously.
+
openLocationLastURL.jsm {{gecko_minversion_inline("1.9.1.4")}}
+
Provides access to the last URL opened using the "Open Location" option in the File menu.
+
OSFile.jsm {{gecko_minversion_inline("16.0")}}
+
Provides routines to access files. Read, write, rename, create directories, ...
+
PerfMeasurement.jsm {{fx_minversion_inline("4.0")}}
+
Provides access to low-level hardware and OS performance measurement tools.
+
PluralForm.jsm
+
Provides an easy way to get the correct plural forms for the current locale, as well as ways to localize to a specific plural rule.
+
PopupNotifications.jsm {{gecko_minversion_inline("2.0")}}
+
Provides an easy way to present non-modal notifications to users.
+
Promise.jsm {{gecko_minversion_inline("25.0")}}
+
Implements the Promises/A+ proposal as known in April 2013.
+
PromiseWorker.jsm {{gecko_minversion_inline("20.0")}}
+
A version of {{domxref("ChromeWorker")}} which uses promises to return the worker's result instead of using an event to do so.
+
Services.jsm {{gecko_minversion_inline("2.0")}}
+
Provides getters for conveniently obtaining access to commonly-used services.
+
source-editor.jsm {{fx_minversion_inline("11.0")}}
+
The Source Editor is used by developer tools such as the Style Editor; this interface implements the editor and lets you interact with it.
+
Sqlite.jsm {{gecko_minversion_inline("20.0")}}
+
A Promise-based API to {{ interface("mozIStorage") }}/SQLite.
+
Task.jsm {{gecko_minversion_inline("17.0")}}
+
Implements a subset of Task.js to make sequential, asynchronous operations simple, using the power of JavaScript's yield operator.
+
Timer.jsm {{gecko_minversion_inline("22.0")}}
+
A pure JS implementation of window.setTimeout.
+
Webapps.jsm {{gecko_minversion_inline("??.0")}}
+
Provides an interface to manager Open Web Apps.
+
WebRequest.jsm {{gecko_minversion_inline("41.0")}}
+
Provides an API to add event listeners for the various stages of making an HTTP request. The event listener receives detailed information about the request, and can modify or cancel the request.
+
XPCOMUtils.jsm
+
Contains utilities for JavaScript components loaded by the JS component loader.
+
diff --git a/files/zh-tw/mozilla/javascript_code_modules/promise.jsm/index.html b/files/zh-tw/mozilla/javascript_code_modules/promise.jsm/index.html new file mode 100644 index 0000000000..fc54b6e846 --- /dev/null +++ b/files/zh-tw/mozilla/javascript_code_modules/promise.jsm/index.html @@ -0,0 +1,144 @@ +--- +title: Promise.jsm +slug: Mozilla/JavaScript_code_modules/Promise.jsm +tags: + - NeedsTranslation + - TopicStub +translation_of: Mozilla/JavaScript_code_modules/Promise.jsm +--- +

{{ gecko_minversion_header("25") }}

+ +

The Promise.jsm JavaScript code module implements the Promises/A+ proposal as known in April 2013.

+ +
+

This module was used before DOM Promises were made globally available in Gecko 29. Its usage is not suggested for new code.

+ +

If you just need a Promise, consider using a DOM Promise instead.

+ +

If you need a Deferred, because you want to create a Promise and manually resolve or reject it, consider using PromiseUtils.jsm instead.

+
+ +

To use it, you first need to import the code module into your JavaScript scope:

+ +
Components.utils.import("resource://gre/modules/Promise.jsm");
+
+ +
+

Note: A preliminary promise module is also available starting from Gecko 17, though it didn't conform to the Promises/A+ proposal until Gecko 25:

+ +
Components.utils.import("resource://gre/modules/commonjs/promise/core.js");     // Gecko 17 to 20
+Components.utils.import("resource://gre/modules/commonjs/sdk/core/promise.js"); // Gecko 21 to 24
+
+ +

This implementation also includes helper functions that are specific to the Add-on SDK. While you may still import this module from the above paths, the recommended way for loading it is through the Add-on SDK loader.

+
+ +

Introduction

+ +

For an introduction to promises, you may start from the Add-on SDK documentation, keeping in mind that only the core subset is implemented in this module.

+ +

A promise is an object representing a value that may not be available yet. Internally, a promise can be in one of three states:

+ + + +

A reference to an existing promise may be received by different means, for example as the return value of a call into an asynchronous API. In this case, the state of the promise can be observed but not directly controlled.

+ +

To observe the state of a promise, its then method must be used. This method registers callback functions that are called as soon as the promise is either fulfilled or rejected. The method returns a new promise, that in turn is fulfilled or rejected depending on the state of the original promise and on the behavior of the callbacks. For example, unhandled exceptions in the callbacks cause the new promise to be rejected, even if the original promise is fulfilled. See the documentation of the then method for details.

+ +

Promises may also be created using the new Promise() constructor.

+ +

Method overview

+ + + + + + + + + + + + + +
Deferred defer(); {{ obsolete_inline("30") }}
Promise resolve([optional] aValue);
Promise reject([optional] aReason);
+ +

Methods

+ +

defer()

+ +

Creates a new pending promise and provides methods to resolve or reject it.

+ +
Deferred defer(); {{ obsolete_inline("30") }}
+
+ +
Parameters
+ +

None.

+ +
Return value
+ +

A new object, containing the new promise in the promise property, and the methods to change its state in the resolve and reject properties. See the Deferred documentation for details.

+ +

resolve()

+ +

Creates a new promise fulfilled with the specified value, or propagates the state of an existing promise.

+ +
Promise resolve(
+  aValue
+);
+
+ +
Parameters
+ +
+
aValue {{ optional_inline() }}
+
If this value is not a promise, including undefined, it becomes the fulfillment value of the returned promise. If this value is a promise, then the returned promise will be resolved with the value, i.e. it will eventually assume the same state as the provided promise.
+
+ +
Return value
+ +

A promise that can be pending, fulfilled, or rejected.

+ +

reject()

+ +

Creates a new promise rejected with the specified reason.

+ +
Promise reject(
+  aReason
+);
+
+ +
Parameters
+ +
+
aReason {{ optional_inline() }}
+
+

The rejection reason for the returned promise. Although the reason can be undefined, it is generally an Error object, like in exception handling.

+ +
Note: This argument should not be a promise. Specifying a rejected promise would make the rejection reason equal to the rejected promise itself, and not its rejection reason.
+
+
+ +
Return value
+ +

A rejected promise.

+ +

Examples

+ +

See the examples page.

+ +

See also

+ + diff --git a/files/zh-tw/mozilla/javascript_code_modules/promise.jsm/promise/index.html b/files/zh-tw/mozilla/javascript_code_modules/promise.jsm/promise/index.html new file mode 100644 index 0000000000..44c0b22181 --- /dev/null +++ b/files/zh-tw/mozilla/javascript_code_modules/promise.jsm/promise/index.html @@ -0,0 +1,215 @@ +--- +title: Promise +slug: Mozilla/JavaScript_code_modules/Promise.jsm/Promise +tags: + - JavaScript + - Promise.jsm +translation_of: Mozilla/JavaScript_code_modules/Promise.jsm/Promise +--- +

一個 Promise 物件代表一個可能還不能使用的值。

+ +

可以用不同的方式接收一個 promise 的參照,比如作為一個異步 API 的回傳值。一但你有了 promise 的參照,你就可以呼叫它的 then() 方法來在它的值準備好後,或是,當錯誤發生時執行一些動作。

+ +

Promises 物件也可以透過 new Promise() 建構子來創建。當你使用一個 Promise 物件的參照時,並不需要額外引入 Promise.jsm 模組 。

+ +

一個 promise 可以處於三種內部狀態:

+ + + +
+

註: 你永遠應該處理、轉送或是回報錯誤(或是拒絕的原因)。如果你看到 "A promise chain failed to handle a rejection",那很有可能是程式碼中有東西需要修正。請參考 handling errors and common pitfalls 。

+
+ +

文件規範

+ +

在說明文件中,完成值的型別通常被定義在角括號中。舉例來說,OS.File.exists 方法回傳的 promise 最終將會履行一個 boolean。

+ +
Promise<boolean> exists(string path);
+
+ +

拒絕原因通常可以分別在方法的文件中定義,而且當沒有特別說明時它將被當作是一個 Error 物件。

+ +

方法總覽

+ + + + + + + + + + +
Promise then([optional] Function onFulfill, [optional] Function onReject);
Promise catch([optional] Function onReject);
+ +

建構子

+ +

創建一個新的 promise ,初始化等待狀態,並提供一些 resolving 方法的參照,這些方法將可以用來改變它的狀態。

+ +
new Promise(executor);
+
+ +

參數

+ +
+
executor
+
+

這個方法將立刻被呼叫,伴隨著兩個 resolving 方法作為其參數:

+ +
executor(resolve, reject);
+
+ +

建構子在 executor 結束之前不會結束。那些 resolving 方法可以在任何時候被使用,包含 executor 完成前和完成後,用來控制 promise 的最終狀態。如果 executor 拋出了例外,例外的值將被當作參數傳入 reject 方法。

+
+
+ +

Resolving 方法

+ +

resolve()

+ +

執行將特定值連結到 promise 的工作,或是傳遞狀態到一個已存在的 promise。如果被連結的 promise 已經處於被解決的狀態,無論是被連結到值、拒絕原因、或另外一個 promise,這個方法將不會做任何事。

+ +
註: 用一個等待中的 promise 當作此方法的 aValue 參數,並在這個 promise 被解決或被拒絕前再次呼叫此方法,第二次的呼叫並不會有任何效果,因為原本的 promise 已經被連結到這個等待中的 promise。
+ +
void resolve(
+  aValue
+);
+
+ +
參數
+ +
+
aValue Optional
+
如果這個值不是一個 promise,包含 undefined,它將成為被連結 promise 的完成值。如果這個值是一個 promise,則被連結的 promise 將會連結到這個傳入的 promise,並和它保持一樣的狀態(包含任何未來的轉變)。
+
+ +

reject()

+ +

用指定的原因拒絕被連結的 promise。如果該 promise 已經被解決,無論是連結到值、拒絕原因、或另外一個 promise,這個方法將不會做任何事。

+ +
void reject(
+  aReason
+);
+
+ +
參數
+ +
+
aReason Optional
+
+

被連結 promise 的拒絕原因。雖然原因可以是 undefined,它通常會是一個 Error 物件對象,就像例外處理那樣。

+ +
註: 這個參數不應該是一個 promise。指定一個拒絕 promise 作為拒絕原因會讓拒絕原因等於這個拒絕 promise 物件本身,而不是該 promise 的拒絕原因。
+
+
+ +

方法

+ +

then()

+ +

在 promise 被完成或是被拒絕後立刻呼叫提供的方法。一個新的 promise 將被回傳,新 promise 的狀態改變將基於此 promise 和提供的 callback 方法。

+ +

一個適當的 callback 總是在這個方法回傳後調用,無論此 promise 是否已經被完成或是被拒絕。你也可以在同一個 promise 上多次呼叫 then 方法,callback 們將被依照它們的註冊順序依序被調用。

+ +
+

警告: 如果 onFulfill callback 拋出例外, onReject callback 並不會被調用,錯誤也不會顯示在 console(你將會看到 promise 鍊失敗錯誤)。作為替代方法,你可以在你準備回傳的 promise 上註冊一個拒絕 callback 方法(使用 catch() 或是 then()),用於處理任何此 promise 上註冊的 callback 中拋出的例外。

+
+ +
註: 當你在同一個 promise 上呼叫多次 then 方法時,註冊的 callback 們將被獨立的調用。舉例來說,如果任何例外發生在其中一個 callback 中,它將不會影響其餘 callback 的執行。callback 的行為只會影響它註冊的 then 方法回傳的 promise。實際上,每次調用 then 方法將回傳完全不同的 promise。
+ +
Promise then(
+  Function onFulfill,
+  Function onReject
+);
+
+ +
參數
+ +
+
onFulfill Optional
+
如果 promise 被完成,這個方法將被調用,完成值將作為它的唯一參數,此方法的回傳值將決定 then 方法回傳的新 promise 的狀態。若此參數不是一個方法(通常為null),then 方法回傳的新 promise 將被用和原本 promise 相同的完成值完成。
+
onReject Optional
+
+

如果 promise 被拒絕,這個方法將被調用,拒絕原因將作為它的唯一參數,此方法的回傳值將決定 then 方法回傳的新 promise 的狀態。若此參數不是一個方法(通常為null),then 方法回傳的新 promise 將被用和原本 promise 相同的拒絕原因拒絕。

+
+
+ +
回傳值
+ +

一個預設等待的 promise ,接著可以假設其狀態基於 callback 方法的結果:

+ + + +

catch()

+ +

相當於呼叫 then() ,並使用 undefined 作為 onFulfill 參數的值。如果你串接 then(onFulfile).catch(onReject)onFulfill 拋出的例外將會被攔截並傳入 onReject ,這和直接將 onReject 傳入 then() 中不同。

+ +
Promise catch(
+  Function onReject
+);
+
+ +

因此以下的呼叫是等價的:

+ +
p.then(undefined, logError);
+p.catch(logError);
+
+ +

除錯

+ +

基於 promise 的設計, promise 對象的狀態和值無法在不調用 then() 的前提下同步地檢視。

+ +

為了幫助除錯,只有在手動檢視 promise 對象時,才能看到更多資訊,這些資訊是代碼無法訪問的特殊屬性(目前,這是透過隨機化屬性名稱來實現的,因為缺少更複雜的語言或調適器的支持)。

+ +

這些代碼無法訪問,可檢視的屬性為:

+ + + +

Promise properties are visible in the debugger.Promise handlers can be watched from the Console.

+ +

範例

+ +

參見 examples.

+ +

錯誤處理和常見的陷阱

+ +

你應該回報沒有被處理的錯誤,除非你將 promise 移交給調用者或是交給其他的代碼來處理這些錯誤。

+ +
// ###### WRONG: Silently drops any rejection notified by "OS.File.Exists".
+OS.File.exists(path).then(exists => { if (exists) myRead(path); });
+
+// ###### WRONG: Silently drops any exception raised by "myRead".
+OS.File.exists(path).then(exists => { if (exists) myRead(path); }, Components.utils.reportError);
+
+// CORRECT (for example, might report the exception "myRead is not defined")
+OS.File.exists(path).then(exists => { if (exists) myRead(path); })
+                    .catch(Components.utils.reportError);
+
+// CORRECT (the function returns a promise, and the caller will handle the rejection)
+function myReadIfExists(path)
+{
+  return OS.File.exists(path).then(exists => { if (exists) myRead(path); });
+}
+ +

參見

+ + diff --git a/files/zh-tw/mozilla/js-ctypes/index.html b/files/zh-tw/mozilla/js-ctypes/index.html new file mode 100644 index 0000000000..a49961f677 --- /dev/null +++ b/files/zh-tw/mozilla/js-ctypes/index.html @@ -0,0 +1,97 @@ +--- +title: js-ctypes +slug: Mozilla/js-ctypes +translation_of: Mozilla/js-ctypes +--- +

{{jsctypesSidebar("Introduction")}}

+ +

js-ctypes allows application and extension code to call back and forth to native code written in C. C++ support is possible through vtable pointers see 使用 COM. For a discussion on extended C++ support see {{bug("505907")}}. Unlike binary XPCOM components, It allows developers to ship a single binary for use with multiple versions of Firefox.

+ +
Note: js-ctypes 只能使用在 chrome 的應用程式和擴展裡,
+ + + + + + + + +
+

文件

+ +
+
使用 JS-Ctypes
+
+ +
+
JS-ctypes 參考
+
參考 js-ctypes API. + +
+
+ +

View All...

+ +

範例

+ +
+
Add to iPhoto
+
A Firefox extension that uses js-ctypes to call Carbon and Core Foundation framework routines on Mac OS X to implement an "Add image to iPhoto" feature in Firefox.
+
使用 C 結構和指針
+
 
+
使用 COM
+
 
+
使用 Objective-C
+
+ +

使用 JNI/Java

+ +
+
Github :: ochameau / jscpptypes
+
A mangling library to use C++ from js-ctypes
+
+
+

社群

+ + + + + + +
+ +

 

diff --git a/files/zh-tw/mozilla/localization/index.html b/files/zh-tw/mozilla/localization/index.html new file mode 100644 index 0000000000..eee1265f5f --- /dev/null +++ b/files/zh-tw/mozilla/localization/index.html @@ -0,0 +1,25 @@ +--- +title: Mozilla 在地化 +slug: Mozilla/Localization +tags: + - Landing + - Localization + - Mozilla + - NeedsTranslation + - TopicStub + - Translation + - l10n +translation_of: Mozilla/Localization +--- +

在地化(Localization、L10n)指的是翻譯軟體的使用者介面,從一個語言到另一個語言,並調整到適合該語言的文化。這些資源提供給所有對於在地化的技術層面感興趣的人。像是開發者和貢獻者。

+ +

延伸閱讀

+ +
+
Localizing MDN
+
這些資源涵蓋了 MDN 文件的在地化。
+
App localization
+
這一系列文件特別用於在地化應用程式,包含 Firefox OS 應用程式。
+
L10n
+
Mozilla 用於在地化 Firefox OS 的 L10n API 參考文件。
+
diff --git a/files/zh-tw/mozilla/localization/localizing_with_pontoon/index.html b/files/zh-tw/mozilla/localization/localizing_with_pontoon/index.html new file mode 100644 index 0000000000..08461fecd6 --- /dev/null +++ b/files/zh-tw/mozilla/localization/localizing_with_pontoon/index.html @@ -0,0 +1,135 @@ +--- +title: 使用 Pontoon 來在地化 +slug: Mozilla/Localization/Localizing_with_Pontoon +translation_of: Mozilla/Localization/Localizing_with_Pontoon +--- +

Pontoon 是一個基於web網頁的、所見即所得(WYSIWYG)的在地化(l10n即localization)工具。在Mozilla基金會,我們使用Pontoon本地化Mozilla網站和Firefox OS(火狐移動操作系統)的應用層(app)接口,就是Gaia。 Pontoon是一個非常簡單和直觀的,僅需要很少甚至沒有技術背景,就能在l10n本地化工作流程中,學會使用的工具。以下,我們將討論如何在本地化項目中使用Pontoon,從最初的註冊登錄到最終面對你的貢獻者(參與該項目的志願者或工作人員)。在這個過程中,我們將挑出Pontoon的一些貼心特性,那將使你十分有效率,並將使l10n本地化共享項目變得更容易。

+ +
+

你是位開發者嗎? 閱讀 在你的網站上使用 Pontoon 或學習如何在 GitHub 上使用。

+
+ +

第一步

+ +

Pontoon 的首頁 is very easy to use. To begin localizing the project, click on the Persona icon and sign in. Next, simply select the project you want to work on and your locale from the dropdown menus. Pontoon will automatically open that locale's project for you to get started. Note that for our purposes here, we'll be using Firefox Affiliates website to demo Pontoon's functionality and workflow. And there it is, opened inside Pontoon:

+ +

Browser app and workspace

+ +

主要工具列

+ +

如你所見,most of the interface is taken by the website being translated. Only the toolbar on top belongs to Pontoon, containing the following items (from left to right):

+ +

Main toolbar

+ +

字串列表

+ +

Opens a sidebar with a list of all strings to localize.

+ +

Project selector (Affiliates)

+ +

Switches between projects to localize.

+ +

Resource selector (Homepage)

+ +

Switches between project resources to localize, like subpages or localization files. Hidden if no resources available for project.

+ +

+ +
+
+ +

Locale selector (Slovenian)

+ +

Switches between languages to localize.

+ +

Go

+ +

Opens project-resource-locale selection.

+ +

Progress indicator

+ +

Displays your progress on the resource being localized. More details are available in the popup.

+ +
+
+ +

使用者清單

+ +

Allows for user-specific tasks, like commiting to repository, downloading files and signing out.

+ +

資訊清單

+ +

Gives important information, like the anticipated project timeline and a list of keyboard shortcuts.

+ +
+
+ +

好了,我們現在是不是該來翻譯啦~

+ +
+
+ +

翻譯字串

+ +

當使用 Pontoon 來在地化時,你有多種選擇來翻譯你的字串,你可以直接修改內容、在內容外或是兩種混和。We'll start with looking at in-context translation.

+ +

內容中

+ +

Pontoon's in-context translation mode is what puts it above others. It opens a web page (or web app) and enables real-time editing of that page. Here's how you translate your first string:

+ +

In-context localization

+ +
    +
  1. Hover over the text you want to translate with your mouse.
  2. +
  3. An edit button appears over that text. Click on it to enable the translate mode.
  4. +
  5. Replace the original text with its translation into your language.
  6. +
  7. Click the save button to save your translation.
  8. +
+ +
+

內容外

+ +

Some strings are impossible to translate in-context, e.g. the contents of the <title> tag in websites and strings with placeables or different plural forms. By clicking on the hamburger icon in the main toolbar, a list of all strings and available translations will open in the sidebar. You can also use the sidebar for out-of-context localization:

+ +

Out-of-context localization: list Out-of-context localization: translate

+ +
    +
  1. 點擊你想要翻譯的字串。
  2. +
  3. Translation panel with original string and its details (e.g. comments) opens.
  4. +
  5. Translate the string in the translation area below.
  6. +
  7. 按下儲存按鈕來儲存你的翻譯。
  8. +
+ +

當你在內容外翻譯,成果將會直接在內容上呈現,if they could also be translated in-context.

+ +

翻譯小助手

+
+ +

如你所見,suggestions from history, translation memory, machine translation and other locales are also available in the out-of-context translation panel. We call all of these translation helpers and here's how each of them will help you as you translate strings:

+ +

Translation helpers: History Translation helpers: Machinery Translation helpers: Other locales Translation helpers: Search

+ +

歷史紀錄

+ +

Displays previously suggested translations, including from other users.

+ +

Machinery

+ +

Displays matches from various services: internal translation memory, Mozilla Transvision, open source translation memory, Microsoft terminology and machine translation.

+ +

其他語言

+ +

Displays matching translations from other locales.

+ +

搜尋

+ +

Almost like machinery, but takes provided keyword as input parameter instead of the original string.

+ +

By clicking a suggestion, it gets copied into translation area.

+ +
+
+ +

發布你的在地化

+ +

Suppose you now want to publish your l10n work by committing it to a repo. Pontoon lets you do that too! Actually, it does that for you by automatically syncing with repositories on hourly basis. You can now pat yourself on the back, do a little dance, go to sleep or do something else to celebrate your work!

diff --git a/files/zh-tw/mozilla/mathml_project/index.html b/files/zh-tw/mozilla/mathml_project/index.html new file mode 100644 index 0000000000..dea19cfe6f --- /dev/null +++ b/files/zh-tw/mozilla/mathml_project/index.html @@ -0,0 +1,60 @@ +--- +title: Mozilla MathML Project +slug: Mozilla/MathML_Project +tags: + - MathML + - MathML Project + - NeedsTranslation + - TopicStub +translation_of: Mozilla/MathML_Project +--- +

The Mozilla MathML project is Mozilla's project to build and enhance MathML support within Firefox and other Mozilla-based applications. For a quick overview, see the slides for the innovation fairs at Mozilla Summit 2013.

+

Updates

+

Mathzilla

+ +

Community

+ + + +

Sample MathML Documents

+ +

Create MathML Documents

+ +
+

Original Document Information

+ +
+

 

diff --git a/files/zh-tw/mozilla/mathml_project/screenshots/index.html b/files/zh-tw/mozilla/mathml_project/screenshots/index.html new file mode 100644 index 0000000000..880c0ddd35 --- /dev/null +++ b/files/zh-tw/mozilla/mathml_project/screenshots/index.html @@ -0,0 +1,14 @@ +--- +title: MathML 快照 +slug: Mozilla/MathML_Project/Screenshots +translation_of: Mozilla/MathML_Project/Screenshots +--- + diff --git "a/files/zh-tw/mozilla/mathml_project/\351\226\213\351\240\255/index.html" "b/files/zh-tw/mozilla/mathml_project/\351\226\213\351\240\255/index.html" new file mode 100644 index 0000000000..6572d9e913 --- /dev/null +++ "b/files/zh-tw/mozilla/mathml_project/\351\226\213\351\240\255/index.html" @@ -0,0 +1,91 @@ +--- +title: 使用 MathML +slug: Mozilla/MathML_Project/開頭 +tags: + - MathML +translation_of: Mozilla/MathML_Project/Start +--- +

使用 MathML

+

你有看到這頁面理那些精巧的數學算式嗎? 沒有嗎? 太糟糕了, 來這邊看一下你錯過了什麼東西吧。 並快下載支援這個功能的 Mozilla 板本來補救這哀傷的場面!

+

還是你發現你看到的畫面根螢幕截圖不一樣呢? 這牆況通常是因為你少了某些關鍵的 MathML 字型

+

現在準備萬全了, 你應該看得到這個行內等式的尖角符號: x ^ + xy ^ + xyz ^ .  旁邊這個則是小小的公式, det | a c b d | = a d - b c , 也可以被設定成這樣的顯示方式: det | a b c d | = a d - b c .

+

數學的排版非常的挑剔。 MathML in Mozilla 正是著眼於實踐 MathML 標準 + + + 以能達到 所標記即所得 、或者說 所製即所得 + + + ,簡短點就是所謂的 "WYSIWYM"。 而這兩者的差異可以在下面的兩行算式表現出來!( ... ( ( a 0 + a 1 ) n 1 + a 2 ) n 2 + ... + a p ) n p ( ... ( ( a 0 + a 1 ) n 1 + a 2 ) n 2 + ... + a p ) n p

+

而這粗體等式的根 y 3 + p y + q = 0  也用粗體呈現 y = - q 2 + q 2 4 + p 3 27 2 3 + - q 2 - q 2 4 + p 3 27 2 3 .

+

而等式 a x 2 + b x + c = 0 ,  的根 在下面的黃色區域內點可以縮放它

+
+

Zoomable Math

+

HTML Content

+
    <p>
+      <math display="block">
+        <mstyle id="zoomableMath" mathbackground="yellow">
+          <mrow>
+            <mi>x</mi>
+            <mo>=</mo>
+            <mfrac>
+              <mrow>
+                <mrow>
+                  <mo>-</mo>
+                  <mi>b</mi>
+                </mrow>
+                <mo>&#xB1;</mo>
+                <msqrt>
+                  <mrow>
+                    <msup>
+                      <mi>b</mi>
+                      <mn>2</mn>
+                    </msup>
+                    <mo>-</mo>
+                    <mrow>
+                      <mn>4</mn>
+                      <mi>a</mi>
+                      <mi>c</mi>
+                    </mrow>
+                  </mrow>
+                </msqrt>
+              </mrow>
+              <mrow>
+                <mn>2</mn>
+                <mi>a</mi>
+              </mrow>
+            </mfrac>
+          </mrow>
+        </mstyle>
+      </math>
+    </p>
+
+
+

JavaScript Content

+
      function zoomToggle()
+      {
+      if (this.hasAttribute("mathsize")) {
+      this.removeAttribute("mathsize");
+      } else {
+      this.setAttribute("mathsize", "200%");
+      }
+      }
+
+      function load()
+      {
+      document.getElementById("zoomableMath").
+      addEventListener("click", zoomToggle, false);
+      }
+
+      window.addEventListener("load", load, false);
+
+

{{ EmbedLiveSample('Zoomable_Math') }}

+

還這邊這個有趣的筆記 { u t + f ( u ) x = 0 u ( 0 , x ) = { u - if  x < 0 u + if  x > 0

+

或是這個複雜的筆記 Ell ^ Y ( Z ; z , τ ) := Y ( l ( y l 2 π i ) θ ( y l 2 π i - z ) θ ( 0 ) θ ( - z ) θ ( y l 2 π i ) ) × ( k θ ( e k 2 π i - ( α k + 1 ) z ) θ ( - z ) θ ( e k 2 π i - z ) θ ( - ( α k + 1 ) z ) ) π ( n ) = m = 2 n ( k = 1 m - 1 ( m / k ) / m / k ) - 1 ϕ W s k ( Ω g ) ( | α | k α ϕ ξ α L s ( Ω g ) s ) 1 / s

+

想要看更多的範例你可以點 MathML Project 頁面的任一連結; 如果你有在編譯自己的版本,可以看一下這個資料夾 + + mozilla/layout/mathml/tests + 。

+

所以你可以做些什麼呢? 你在 Mozilla 上使用時有沒有遇到任何 MathML 標準是沒正常運作的? 或者是一些煩人的東西你覺得需要改進? 或是你之前做的某些東西沒辦法正常運作了(像是 迴歸 )? 如果有遇到這些狀況,快去 BugZilla 回報這些異常吧。BugZilla 世有辦法收錄這些東西的。而且,如果你遇到問題不回報,我們也沒辦法去修正啊?!

+

如果你想要讓 Gecko 成為一個更精巧更完善的 MathML 繪製引擎,加入我們。 你的回應可以以 網站上的 MathML 內容呈現、或者去 BugZilla 回報錯誤。或者,如果你能在在程式碼方面提供協助, 來 檢查或改進目前的程式碼 , 或者是處理我們待處理清單的項目。

+
+  
diff --git a/files/zh-tw/mozilla/performance/about_colon_memory/index.html b/files/zh-tw/mozilla/performance/about_colon_memory/index.html new file mode 100644 index 0000000000..f9895899dd --- /dev/null +++ b/files/zh-tw/mozilla/performance/about_colon_memory/index.html @@ -0,0 +1,188 @@ +--- +title: 'about:memory' +slug: 'Mozilla/Performance/about:memory' +translation_of: 'Mozilla/Performance/about:memory' +--- +

about:memory 在Firefox 裡是個特別分頁可讓你你看、存、讀、Firefox 的記憶體處理詳細測量出的差異。 此頁也讓你進行其他記憶體相關的操作例如觸發垃圾回收 (GC) 和循環回收 (CC)、轉存 GC & CC 紀錄和轉存無效堆疊偵測 ( DMD) 報告。 此頁出現在所有版本且不須任何準備即可用它。

+ +

如何產生記憶體報告

+ +

讓我們假設你想去量測 Firefox 的記憶體使用量。 或許你想自己去調查它、也或許某人要球你使用 about:memory 去產生"記憶體報告"以讓他們可以研究你碰到的問題。 跟著下列步驟走:

+ + + +

注意在兩個例子中產生的資料含有私人敏感的細節例如你開在其他分頁的完整清單。如果你不想分享這些訊息,你可以選擇 "anonymize" 核取格,在按下 "Measure and save..." 或 "Measure..."之前。 這將造成私人敏感資料被剝掉,但也可能會造成其他人難以去研究記憶體用量。

+ +

從檔案讀取記憶體報告

+ +

最簡單的方法從檔案讀取記憶體報告就是用 "Load..." 按鈕。 你也可以用 "Load and diff..." 按鈕去獲得在兩個記憶體報告檔中的差異。

+ +

單一記憶體報告檔也可以自動被讀取,當附加一個檔案查詢字串,例如:

+ +
about:memory?file=/home/username/reports.json.gz
+
+ +

這是從其他Firefox裝置系統讀取記憶體報告檔最有用的。

+ +

記憶體報告被儲存到壓縮的格式 (gzipped JSON)。 這些檔案可以被直接讀或解壓縮後讀入。

+ +

解釋記憶體報告

+ +

幾乎在 about:memory 中你看到東西都有工具提示的解釋。停留在任何按鈕將看到它作用的描述。停留在任何文字量測值上將看到它意義的描述。

+ +

量測基本

+ +

大多數量測使用位元組為他們的單位,但某些是百分比計算。

+ +

多數量測值表示在樹狀目錄結構中。例如:

+ +
 585 (100.0%) -- preference-service
+ └──585 (100.0%) -- referent
+    ├──493 (84.27%) ── strong
+    └───92 (15.73%) -- weak
+        ├──92 (15.73%) ── alive
+        └───0 (00.00%) ── dead
+
+ +

枝葉節點表示實際量測值:每個內部節點值是子節點的總和。

+ +

樹狀目錄的使用允許量測值分成進一步的目錄、次目錄、次次目錄…….如果需要可到任意深度。一個目錄中所有的量測值不會重疊。

+ +

樹狀可以用斜線 '/' 作為分隔符號被描寫。 例如, preference/referent/weak/dead 表示上列中到最後枝葉節點的路徑。

+ +

次目錄按它可以被縮起或展開。如果你發現任何特別的樹狀目錄,這可以幫你馬上縮起主根下所有分枝,然後慢慢展開感興趣的。

+ +

報告區間 Sections

+ +

記憶體報告依照每個預處理原則、每個區間一個程序被顯示,在每個程序的量測值中,還有更多小區間。

+ +

Explicit Allocations

+ +

這個區間包含一個單一樹狀目錄,叫做 "explicit",量測所有經由表層呼叫(explicit calls)去堆疊配置函數和非堆疊配置函數(例如 mmap and VirtualAlloc)的記憶體。

+ +

這裡是瀏覽器區間的例子,分頁打開了 cnn.com、 techcrunch.com、 和 arstechnica.com。不同的次目錄被展開,其他的因展示緣故被縮起。

+ +
191.89 MB (100.0%) -- explicit
+├───63.15 MB (32.91%) -- window-objects
+│   ├──24.57 MB (12.80%) -- top(http://edition.cnn.com/, id=8)
+│   │  ├──20.18 MB (10.52%) -- active
+│   │  │  ├──10.57 MB (05.51%) -- window(http://edition.cnn.com/)
+│   │  │  │  ├───4.55 MB (02.37%) ++ js-compartment(http://edition.cnn.com/)
+│   │  │  │  ├───2.60 MB (01.36%) ++ layout
+│   │  │  │  ├───1.94 MB (01.01%) ── style-sheets
+│   │  │  │  └───1.48 MB (00.77%) -- (2 tiny)
+│   │  │  │      ├──1.43 MB (00.75%) ++ dom
+│   │  │  │      └──0.05 MB (00.02%) ── property-tables
+│   │  │  └───9.61 MB (05.01%) ++ (18 tiny)
+│   │  └───4.39 MB (02.29%) -- js-zone(0x7f69425b5800)
+│   ├──15.75 MB (08.21%) ++ top(http://techcrunch.com/, id=20)
+│   ├──12.85 MB (06.69%) ++ top(http://arstechnica.com/, id=14)
+│   ├───6.40 MB (03.33%) ++ top(chrome://browser/content/browser.xul, id=3)
+│   └───3.59 MB (01.87%) ++ (4 tiny)
+├───45.74 MB (23.84%) ++ js-non-window
+├───33.73 MB (17.58%) ── heap-unclassified
+├───22.51 MB (11.73%) ++ heap-overhead
+├────6.62 MB (03.45%) ++ images
+├────5.82 MB (03.03%) ++ workers/workers(chrome)
+├────5.36 MB (02.80%) ++ (16 tiny)
+├────4.07 MB (02.12%) ++ storage
+├────2.74 MB (01.43%) ++ startup-cache
+└────2.16 MB (01.12%) ++ xpconnect
+ +

某些專家才需要瞭解這裡所有的細節,但有很多東西值得解釋。

+ + + +

某些附加元件 add-ons 的記憶體用量有識別性, 像下列例子所示:

+ +
├───40,214,384 B (04.17%) -- add-ons
+│   ├──21,184,320 B (02.20%) ++ {d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}/js-non-window/zones/zone(0x100496800)/compartment([System Principal], jar:file:///Users/njn/Library/Application%20Support/Firefox/Profiles/puna0zr8.new/extensions/%7Bd10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d%7D.xpi!/bootstrap.js (from: resource://gre/modules/addons/XPIProvider.jsm:4307))
+│   ├──11,583,312 B (01.20%) ++ jid1-xUfzOsOFlzSOXg@jetpack/js-non-window/zones/zone(0x100496800)
+│   ├───5,574,608 B (00.58%) -- {59c81df5-4b7a-477b-912d-4e0fdf64e5f2}
+│   │   ├──5,529,280 B (00.57%) -- window-objects
+│   │   │  ├──4,175,584 B (00.43%) ++ top(chrome://chatzilla/content/chatzilla.xul, id=4293)
+│   │   │  └──1,353,696 B (00.14%) ++ top(chrome://chatzilla/content/output-window.html, id=4298)
+│   │   └─────45,328 B (00.00%) ++ js-non-window/zones/zone(0x100496800)/compartment([System Principal], file:///Users/njn/Library/Application%20Support/Firefox/Profiles/puna0zr8.new/extensions/%7B59c81df5-4b7a-477b-912d-4e0fdf64e5f2%7D/components/chatzilla-service.js)
+│   └───1,872,144 B (00.19%) ++ treestyletab@piro.sakura.ne.jp/js-non-window/zones/zone(0x100496800)
+ +

更多細節值得解釋如下:

+ + + +

其他量測值

+ +

這個區間包含多目錄,包括許多在 "explicit" 目錄中橫跨的量測值。 例如, 在 "explicit"目錄所有的 DOM 和 layout 量測值是被打散成一個又一個視窗, 但在 "Other Measurements" 這些量測值是整合為由整個瀏覽器來的總和, 如下例所示:

+ +
26.77 MB (100.0%) -- window-objects
+├──14.59 MB (54.52%) -- layout
+│  ├───6.22 MB (23.24%) ── style-sets
+│  ├───4.00 MB (14.95%) ── pres-shell
+│  ├───1.79 MB (06.68%) ── frames
+│  ├───0.89 MB (03.33%) ── style-contexts
+│  ├───0.62 MB (02.33%) ── rule-nodes
+│  ├───0.56 MB (02.10%) ── pres-contexts
+│  ├───0.47 MB (01.75%) ── line-boxes
+│  └───0.04 MB (00.14%) ── text-runs
+├───6.53 MB (24.39%) ── style-sheets
+├───5.59 MB (20.89%) -- dom
+│   ├──3.39 MB (12.66%) ── element-nodes
+│   ├──1.56 MB (05.84%) ── text-nodes
+│   ├──0.54 MB (02.03%) ── other
+│   └──0.10 MB (00.36%) ++ (4 tiny)
+└───0.06 MB (00.21%) ── property-tables
+ +

在這區間的某些目錄量測那些在 "explicit" 目錄中不是橫跨目錄的量測值,例如在上上個例子中的這個 "preference-service" 。

+ +

最後, 在這區間結尾是獨立的量測值, 如下例所示:

+ +
    0.00 MB ── canvas-2d-pixels
+    5.38 MB ── gfx-surface-xlib
+    0.00 MB ── gfx-textures
+    0.00 MB ── gfx-tiles-waste
+          0 ── ghost-windows
+  109.22 MB ── heap-allocated
+        164 ── heap-chunks
+    1.00 MB ── heap-chunksize
+  114.51 MB ── heap-committed
+  164.00 MB ── heap-mapped
+      4.84% ── heap-overhead-ratio
+          1 ── host-object-urls
+    0.00 MB ── imagelib-surface-cache
+    5.27 MB ── js-main-runtime-temporary-peak
+          0 ── page-faults-hard
+    203,349 ── page-faults-soft
+  274.99 MB ── resident
+  251.47 MB ── resident-unique
+1,103.64 MB ── vsize
+ +

某些量測值標示如下:

+ + + +

系統 System

+ +

這區間只顯示在Firefox OS。 它包含全裝置從操作系統所測得值。在其之中, 這些區間有助於精確瞭解裝置的記憶體如何被使用。

+ +

......翻譯完雖然瞭解不少,卻僅知哪些資訊可以給改善者參考,要解決使用者記憶體的問題,還是建議各位設計師可以整合One Tab之類的軟體,限制記憶體使用例如最大800MB,如果超過了,依使用者習慣分為100個分頁中有20個維持開啟活動、剩下的逐步變成例如完整保存的網頁檔之類,平時留個分頁籤名字只是看看而已,點到了才載入,就不會讓人難忍受了,也不會吃太多記憶體就依照個人使用狀況自行分配就好,畢竟閒置的除了影像外,很多只是在播放廣告,一點感想。

diff --git a/files/zh-tw/mozilla/performance/index.html b/files/zh-tw/mozilla/performance/index.html new file mode 100644 index 0000000000..f8261ab133 --- /dev/null +++ b/files/zh-tw/mozilla/performance/index.html @@ -0,0 +1,130 @@ +--- +title: Performance +slug: Mozilla/Performance +tags: + - NeedsTranslation + - Performance + - TopicStub +translation_of: Mozilla/Performance +--- +

被連接到此的這篇文章將幫助你改進效能,不論你是開發 Mozilla 核心碼或附加元件。

+ + + + + + + + +
+

Documentation

+ +
+
回報性能問題 Rorting a Performance Problem
+
對使用者友善的指導以報告性能問題。不需要開發環境。
+
性能最好的實踐在擴充元件中
+
給擴充元件開發者性能"最好的實踐"指引。
+
測量附加元件啟動效能
+
給附加元件開發者指引如何設定測試環境。
+
XUL School: 附加元件效能
+
給附加元件開發者提示去幫他們避免損害應用效能。
+
GPU 效能
+
當使用GPU時給研究和改進效能的可靠建議
+
+ +

查看所有頁面以 "Performance" 標籤的...

+ +

記憶體研究和漏洞偵測工具

+ +
+
about:memory
+
about:memory 是最輕巧使用工具給量測記憶體用量使用在 Mozilla 程式碼,且是最好出發地。它也讓你進行其他記憶體相關的操作像觸發垃圾回收 (GC) 和循環回收 (CC)、轉存 GC & CC 紀錄和轉存無效堆疊偵測 ( DMD) 報告。 about:memory 是建立在 Firefox's memory reporting 構造上.
+
DMD
+
無效堆疊偵測 (DMD) 是個可識別在about:memory中的量測值問題點,而且可以作各式各樣的一般堆疊研究。
+
areweslimyet.com
+
areweslimyet.com (又名 AWSY) 是記憶體用和回歸偵測系統。
+
BloatView
+
BloatView 在配置和引用計數時列印按類別統計資料,且依類別提供記憶體中洩漏的分解總數目。它常用為 Mozilla持續整合測試的一部分。
+
引用計數追蹤與平衡
+
引用計數追蹤與平衡是個手段要追蹤由引用計數不正確的使用造成的洩漏。 他們遲緩又不那麼容易使用,且因此大多數適合專家級開發者使用。
+
GC and CC logs
+
觸發垃圾回收 (GC) 和循環回收 (CC)紀錄可被產生與分析以不同方式。特別是,他們能幫助瞭解為何特定勿建一直保持存在記憶體。
+
Valgrind
+
Valgrind 是個即時偵測種種記憶體相關的問題含洩漏的工具。 Valgrind 常作為Mozilla's持續整合測試的 部份  ,雖然Valgrind的遲緩讓應用範圍受限。
+
LeakSanitizer
+
LeakSanitizer (又叫 LSAN) 相似於 Valgrind。 但它跑得快一些因為它使用靜態來源碼架構。LSAN常作為Mozilla's持續整合測試的一部分,雖然多數測試執行時它也是 AddressSanitizer (又叫 ASAN) 測試工作的一部分。
+
Apple tools
+
Apple provides some tools for Mac OS X that report similar problems to those reported by LSAN and Valgrind. The "leaks" tool is not recommended for use with SpiderMonkey or Firefox, because it gets confused by tagged pointers and thinks objects have leaked when they have not (see bug 390944).
+
Leak Gauge
+
Leak Gauge is a tool that can be used to detect certain kinds of leaks in Gecko, including those involving documents, window objects, and docshells.
+
LogAlloc
+
LogAlloc is a tool that dumps a log of memory allocations in Gecko. That log can then be replayed against Firefox's default memory allocator independently or through another replace-malloc library, allowing the testing of other allocators under the exact same workload.
+
Memory Profiler
+
The memory profiler samples allocation events and provides different views to analyze the allocation characteristic.
+
+ +

See also the documentation on Leak-hunting strategies and tips.

+
+

Profiling and performance tools

+ +
+
Profiling with the Developer Tools Profiler
+
The profiler built into the developer tools has a high-level waterfall, detailed call tree, allocations and GC profiling, and flame graphs. It is available on all platforms and release channels, and also supports remote profiling b2g and Fennec.
+
+ +
+
Profiling with the Gecko Profiler Addon {{ gecko_minversion_inline("16.0") }}
+
The Gecko Profiler Addon is a good tool to start with.
+
Profiling with Instruments
+
How to use Apple's Instruments tool to profile Mozilla code.
+
Profiling with Xperf
+
How to use Microsoft's Xperf tool to profile Mozilla code.
+
Profiling with Concurrency Visualizer
+
How to use Visual Studio's Concurrency Visualizer tool to profile Mozilla code.
+
Profiling with Zoom
+
Zoom is a profiler for Linux done by the people who made Shark
+
Measuring performance using the PerfMeasurement.jsm code module {{ gecko_minversion_inline("2.0") }}
+
Using PerfMeasurement.jsm to measure performance data in your JavaScript code.
+
Adding a new Telemetry probe
+
Information on how to add a new measurement to the Telemetry performance-reporting system
+
Profiling JavaScript with Shark {{ gecko_minversion_inline("1.9") }}
+
How to use the Mac OS X Shark profiler to profile JavaScript code in Firefox 3.5 or later.
+
Profiling with Shark
+
How to use Apple's Shark tool to profile Mozilla code.
+
Investigating CSS Performance
+
How to figure out why restyle is taking so long
+
+ +

Power profiling

+ +
+
Power profiling overview
+
This page provides an overview of relevant information, including details about hardware, what can be measured, and recommended approaches. It should be the starting point for anybody new to power profiling.
+
tools/power/rapl (Mac, Linux)
+
tools/power/rapl is a command-line utility in the Mozilla codebase that uses the Intel RAPL interface to gather direct power estimates for the package, cores, GPU and memory.
+
powermetrics (Mac-only)
+
powermetrics is a command-line utility that gathers and displays a wide range of global and per-process measurements, including CPU usage, GPU usage, and various wakeups frequencies.
+
TimerFirings logging (All platforms)
+
TimerFirings logging is a built-in logging mechanism that prints data on every time fired.
+
dtrace (Mac-only)
+
dtrace is a powerful kernel instrumentation tool. One of its many features is the ability to instrument wakeups in a high-context fashion.
+
Activity Monitor, Battery Status Menu and top (Mac-only)
+
The battery status menu, Activity Monitor and top are three related Mac tools that have major flaws but often consulted by users, and so are worth understanding.
+
Intel Power Gadget (Windows, Mac, Linux)
+
Intel Power Gadget provides real-time graphs for package and processor RAPL estimates. It also provides an API through which those estimates can be obtained.
+
perf (Linux-only)
+
perf is a powerful command-line utility that can measure many different things, including energy estimates and high-context measurements of things such as wakeups.
+
turbostat (Linux-only)
+
turbostat is a command-line utility that gathers and displays various power-related measurements, with a focus on per-CPU measurements such as frequencies and C-states.
+
powertop (Linux-only)
+
powertop is an interactive command-line utility that gathers and displays various power-related measurements.
+
+ + + +
+
JavaScript, XPCOM, Developing Mozilla, Extensions, Addons
+
+
+ +

 

diff --git a/files/zh-tw/mozilla/preferences/index.html b/files/zh-tw/mozilla/preferences/index.html new file mode 100644 index 0000000000..1169ecabf1 --- /dev/null +++ b/files/zh-tw/mozilla/preferences/index.html @@ -0,0 +1,48 @@ +--- +title: Preferences +slug: Mozilla/Preferences +tags: + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Preferences +--- +

The preference system makes it possible to store data for Mozilla applications using a key/value pairing system. These articles provide information about how to use the preference system.

+ + + + + + + +
+

Documentation

+
+
Preferences system
+
An introduction to using the preference system in Mozilla.
+
XUL School: Handling preferences
+
The XUL School tutorial chapter on preferences.
+
Mozilla preference reference
+
A reference guide to all Mozilla preferences; currently a work in progress.
+
A brief guide to Mozilla preferences
+
An introductory guide to where preferences are stored and other useful information about the core preference system.
+
Using preferences from application code {{gecko_minversion_inline("6.0")}}
+
Firefox 6 introduced static functions for accessing preferences efficiently from within application code. This API is not available for add-ons, but if you're working on a Gecko application, this API is the preferred way to access preferences.
+
Mozilla networking preferences
+
A guide to key networking-related preferences.
+
Mozilla preferences for uber-geeks
+
A guide to preferences that only truly elite geeks should play with.
+
+

View all pages tagged with "Preferences"...

+
+

Examples

+
+
Code snippets
+
Preference-related code snippets.
+
Adding preferences to an extension
+
How to add preferences to an existing extension.
+
+ + +
diff --git a/files/zh-tw/mozilla/preferences/preferences_system/index.html b/files/zh-tw/mozilla/preferences/preferences_system/index.html new file mode 100644 index 0000000000..965cd97480 --- /dev/null +++ b/files/zh-tw/mozilla/preferences/preferences_system/index.html @@ -0,0 +1,40 @@ +--- +title: Preferences system +slug: Mozilla/Preferences/Preferences_system +tags: + - NeedsTranslation + - Preferences system + - TopicStub + - XUL +translation_of: Mozilla/Preferences/Preferences_system +--- +

This document describes Toolkit's preferences system. Using this system it is possible to create preferences windows that display and operate appropriately on various platforms (Windows, MacOS X and GNOME).

+ +

The system is implemented through a few XUL elements and attributes. Reference information about them is available below:

+

Preferences System documentation:

+

Use

+

Code for a typical preferences window may look like this:

+
<prefwindow id="appPreferences"
+            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <prefpane id="pane1" label="&pane1.title;">
+    <preferences>
+      <preference id="pref1" name="pref.name" type="bool"/>
+    </preferences>
+
+   .. UI elements that refer to the preferences above, e.g.:
+    <checkbox id="check1" preference="pref1"
+              label="&check1.label;" accesskey="&check1.accesskey;"/>
+  </prefpane>
+
+  <prefpane id="pane2" label="&pane2.title;" src="chrome://uri/to/pane.xul"/>
+</prefwindow>
+
+

Pane content can be specified inline or an external chrome URI supplied for pane content to be loaded in via a dynamic overlay. You should be careful to read the HIGs for the platforms you are targeting and use the XUL preprocessor if necessary to set different window titles as appropriate. You should also be careful to specify the width of the window (in em) as appropriate using the preprocessor for each targeted platform, as well as the height (in em) for platforms where the window size does not change as the selected panel is changed (e.g. Windows).

+

Usage in XULRunner applications

+

When calling openDialog() to open a preferences dialog, "toolbar" should be included in the features string.  Not using "toolbar" will cause the preferences dialog to only display one preference pane.

+

Example:

+
var features = "chrome,titlebar,toolbar,centerscreen,modal";
+window.openDialog(url, "Preferences", features);
+
+

Bugzilla

+

The component for bugs in the Preferences bindings (but not in Firefox/Thunderbird Options UI) is Toolkit:Preferences (file a bug list open bugs)

diff --git a/files/zh-tw/mozilla/preferences/preferences_system/new_attributes/index.html b/files/zh-tw/mozilla/preferences/preferences_system/new_attributes/index.html new file mode 100644 index 0000000000..f583b29b26 --- /dev/null +++ b/files/zh-tw/mozilla/preferences/preferences_system/new_attributes/index.html @@ -0,0 +1,55 @@ +--- +title: Preference XUL Attributes +slug: Mozilla/Preferences/Preferences_system/New_attributes +translation_of: Mozilla/Preferences/Preferences_system/New_attributes +--- +

 

+

<prefwindow> 裡的 Widgets 可能有下述屬性 (除此以外,尚有標準屬性).

+

preference

+

Specifies id of the linked <preference> element. preference 和 widget 兩者的 value 將保持同步.

+

如下例,當 pane 被載入時, textbox 從名稱 extensions.example.mypref 的 preference 來自動初始化它的 value ;反過來說,當使用者改變 textbox 的 value 時,<preference>元素的 value 會同步更新,並將在適當的時候儲存至 preferences system.

+
<preference id="my_pref" name="extensions.example.mypref" type="unichar"/>
+<textbox preference="my_pref"/>
+
+

preference-editable

+

By default, the <preference> element will automatically modify the value of a few standard widgets: checkbox, colorpicker, radiogroup, textbox, listitem, listbox, and menulist.

+

If you wish it to update the value of an element with different local name, for example your own XBL widget, you need to set the preference-editable="true" attribute on it.

+

For your widget to modify the <preference>'s value, you need to make sure a change, command, or input event is fired after the widget's value changes.

+

bug # or any testcases ? Note: this does not currently work on the tree widget. It may not work on anything so far (the API says it is to be available in version 1.8).

+

onsyncfrompreference/onsynctopreference

+

Often you will have UI whose construction does not map easily to a given preference type. 例如,你可能有一個 checkbox,當一個整數值是 3 時它被打勾,是 2 時不被打勾。為了初始化這個 UI 元素,你不能依賴預設的 initialization routine,因為這兩個數值對 checkbox 元素來說是無意義的. 你需要寫轉換函數來轉換 preference value 成 UI 元素可用的初始值,並且也轉換 UI 元素的 value 成某些格式來儲存至 preferences file. 這就是 onsyncfrompreference/onsynctopreference 的作用.

+

onsyncfrompreference 被呼叫,當一個元素從 preferences 被初始化。 明確地說, 當一個 preference 元素的 value 被載入, 所有使用那個 preference 的元素將使他們的 onsyncfrompreference handler 被呼叫.

+
+ Be careful when writing onsyncfrompreference handlers.  <preference> elements defined after the preference element  being dealt with will not yet have their value set, so referring to them from the handler will lead to a null result. Reorder the <preference> elements or directly fetch the preference value via Services.prefs
+

If you supply an implementation of this event, your implementation will be invoked during initialization and you can return the value with which to initialize the UI element with, or undefined to tell the preferences system to initialize the UI element with the default value (i.e. to attempt to initialize with the preference value). In the above example, you might write the checkbox like this:

+
<checkbox preference="foo.bar" onsyncfrompreference="return onsyncfrompreference();"/>
+
+.. script:
+function onsyncfrompreference()
+{
+  var preference = document.getElementById("foo.bar");
+  // .value === undefined means the preference is set to the default value
+  var actualValue = preference.value !== undefined ?
+                      preference.value : preference.defaultValue;
+  // actualValue may be |null| here if the pref didn't have the default value.
+  return preference.value == 3;
+
+  // If foo.bar was boolean and we wanted to use its value to initialize
+  // the checkbox, we could still implement this method if we wanted to
+  // perform any other initialization actions at this time.
+}
+
+

onsynctopreference is called when preferences are being written - the preferences system asks each element to translate its current state into a value suitable for writing to the specified preference. You can return a special value or undefined to tell the preferences system to use its standard means for obtaining the value. In the above example:

+
<checkbox preference="foo.bar" onsynctopreference="return onsynctopreference();"/>
+.. script:
+function onsynctopreference()
+{
+  var checkbox = document.getElementById("checkbox");
+  return checkbox.checked ? 3 : 2;
+}
+
+// If foo.bar was boolean and we wanted to use its value to write to
+// preferences, we could still implement this method if we wanted to
+// perform any other initialization actions at this time.
+
+

Preferences System documentation:

diff --git a/files/zh-tw/mozilla/projects/index.html b/files/zh-tw/mozilla/projects/index.html new file mode 100644 index 0000000000..7e832a9616 --- /dev/null +++ b/files/zh-tw/mozilla/projects/index.html @@ -0,0 +1,14 @@ +--- +title: Projects +slug: Mozilla/Projects +tags: + - Landing + - Mozilla + - NeedsContent + - NeedsTranslation + - Projects + - TopicStub +translation_of: Mozilla/Projects +--- +

Below you'll find links to documentation about various Mozilla projects; these are often parts of Firefox or other products, but may also be used in other projects as well.

+

{{ LandingPageListSubpages() }}

diff --git a/files/zh-tw/mozilla/projects/nss/getting_started_with_nss/index.html b/files/zh-tw/mozilla/projects/nss/getting_started_with_nss/index.html new file mode 100644 index 0000000000..83eb55baba --- /dev/null +++ b/files/zh-tw/mozilla/projects/nss/getting_started_with_nss/index.html @@ -0,0 +1,58 @@ +--- +title: Getting Started With NSS +slug: Mozilla/Projects/NSS/Getting_started_with_NSS +translation_of: Mozilla/Projects/NSS/Getting_started_with_NSS +--- +

如何參與NSS

+ +

網絡安全服務(NSS)是Mozilla軟件使用的加密算法和安全網絡協議的基礎庫。
+
+ 您想參與並幫助我們改善Mozilla Firefox和其他使用NSS的應用程序的核心安全性嗎?我們期待著您的貢獻!
+
+ 我們有大量任務等待您關注,我們很樂意協助您確定與您的興趣或技能相匹配的領域。您可以在Mozilla IRC#nss頻道中找到我們,也可以在mozilla.dev.tech.crypto新聞組中提問。

+ +

NSS庫及其支持的命令行工具使用C編程語言編寫。它的構建系統和自動化測試基於makefile和bash腳本。

+ +

隨著時間的流逝,已經產生了許多描述NSS各個方面的文檔。您可以從以下內容開始:

+ + + +

(不幸的是,NSS項目目前沒有技術撰稿人,因此我們的文檔沒有我們想要的那樣井井有條。您可以通過更好的組織方式來做出貢獻。)

+ +

NSS示例代碼

+ +

由NSS開發人員維護的命令行工具是開始學習如何編寫NSS應用程序的好地方。您可以在子目錄mozilla / security / nss / cmd中找到它們

+ +

或看看一些基本的NSS示例代碼

+ +

目前正在開發和審查一組新的樣本,請參閱創建新的NSS樣本

+ +

歡迎您通過以下方式下載示例:hg clone https://hg.mozilla.org/projects/nss; cd nss; hg更新SAMPLES_BRANCH

+ +

如何貢獻

+ +

...(此部分仍在建設中,但是有很多貢獻的機會)

+ +

如果您沒有,請先在bugzilla.mozilla.org上打開一個bugzilla帳戶。

+ +

NSS ::庫組件可解決您要處理的問題。我們維護了一個標記為“ good-first-bug”NSS錯誤列表,您可以查看這些錯誤

+ +

創建補丁

+ +

請參閱有關NSS來源,構建和測試的部分,以開始製作補丁。當您對此感到滿意時,就需要進行代碼審查。

+ +

代碼審查

+ +

http://phabricator.services.mozilla.com/是我們的代碼審查工具,它使用您的Bugzilla帳戶。使用我們的Phabricator用戶說明上傳補丁進行審核

+ +

Github上的清單形式列出了一些在代碼審查期間將要評估的項目

+ +

通過審查後,您的補丁程序可以由NSS小組的成員登陸。您可以在Mozilla IRC#nss頻道中找到我們。

+ +

請注意,我們不會發布未經審查和測試的代碼。代碼僅在具有測試的情況下才有效,而測試僅在它們屬於自動化的一部分時才有效。

diff --git a/files/zh-tw/mozilla/projects/nss/index.html b/files/zh-tw/mozilla/projects/nss/index.html new file mode 100644 index 0000000000..186df02c73 --- /dev/null +++ b/files/zh-tw/mozilla/projects/nss/index.html @@ -0,0 +1,180 @@ +--- +title: Network Security Services +slug: Mozilla/Projects/NSS +tags: + - JSS + - NSS + - NeedsMigration + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Projects/NSS +--- +

Network Security Services (NSS) is a set of libraries designed to support cross-platform development of security-enabled client and server applications. Applications built with NSS can support SSL v3, TLS, PKCS #5, PKCS #7, PKCS #11, PKCS #12, S/MIME, X.509 v3 certificates, and other security standards.

+ +

For detailed information on standards supported, see Overview of NSS. For a list of frequently asked questions, see the FAQ.

+ +

NSS is available under the Mozilla Public License. For information on downloading NSS releases as tar files, see Download PKI Source.

+ +

If you're a developer and would like to contribute to NSS, you might want to read the documents highlevel overview of internal details of NSS and getting started with NSS.

+ + + + + + + + +
+

Documentation

+ +

Background Information

+ +
+
Overview of NSS
+
Provides a brief summary of NSS and its capabilities.
+
NSS FAQ
+
Answers basic questions about NSS.
+
Introduction to Public-Key Cryptography
+
Explains the basic concepts of public-key cryptography that underlie NSS.
+
Introduction to SSL
+
Introduces the SSL protocol, including information about cryptographic ciphers supported by SSL and the steps involved in the SSL handshake.
+
+ +

Getting Started

+ +
+
NSS Releases
+
This page contains information about the current and past releases of NSS.
+
Get the source code and Build it
+
Instructions on how to build NSS on the different supported platforms.
+
Get Mozilla Source Code Using Mercurial
+
Information about with working with Mercurial.
+
Get Mozilla Source Code Using CVS (deprecated)
+
Old deprecated CVS documentation.
+
+ +

NSS APIs

+ +
+
Introduction to Network Security Services
+
Provides an overview of the NSS libraries and what you need to know to use them.
+
NSS SSL Public Functions
+
Summarizes the SSL APIs exported by the NSS shared libraries.
+
NSS SSL Reference
+
API used to invoke SSL operations.
+
NSS API Guidelines
+
Explains how the libraries and code are organized, and guidelines for developing code (naming conventions, error handling, thread safety, etc.)
+
NSS Technical Notes
+
Links to NSS technical notes, which provide latest information about new NSS features and supplementary documentation for advanced topics in programming with NSS.
+
+ +

Tools, testing, and other technical details

+ +
+
Build Instructions for NSS
+
Describe how to check out and build NSS releases.
+
+ +
+
NSS Developer Tutorial
+
How to make changes in NSS. Coding style, maintaining ABI compatibility.
+
+ +
+
NSS Tools
+
Tools for developing, debugging, and managing applications that use NSS.
+
Sample Code
+
Demonstrates how NSS can be used for cryptographic operations, certificate handling, SSL, etc.
+
Third-Party Code
+
A list of third-party code included in the NSS library.
+
NSS 3.2 Test Suite
+
Archived version. Describes how to run the standard NSS tests.
+
NSS Performance Reports
+
Archived version. Links to performance reports for NSS 3.2 and later releases.
+
Encryption Technologies Available in NSS 3.11
+
Archived version. Lists the cryptographic algorithms used by NSS 3.11.
+
NSS 3.1 Loadable Root Certificates
+
Archived version. Describes the scheme for loading root CA certificates.
+
cert7.db
+
Archived version. General format of the cert7.db database.
+
+ +

PKCS #11 information

+ + + +
+
+ +

CA certificates pre-loaded into NSS

+ + + +
+
+ +

NSS is built on top of Netscape Portable Runtime (NSPR)

+ +
+
Netscape Portable Runtime
+
NSPR project page.
+
NSPR Reference
+
NSPR API documentation.
+
+ +

Additional Information

+ + + +

Planning

+ +

Information on NSS planning can be found at wiki.mozilla.org, including:

+ + +
+

Community

+ +
    +
  • View Mozilla Security forums...
  • +
+ +

{{ DiscussionList("dev-security", "mozilla.dev.security") }}

+ +
    +
  • View Mozilla Cryptography forums...
  • +
+ +

{{ DiscussionList("dev-tech-crypto", "mozilla.dev.tech.crypto") }}

+ + + + +
diff --git a/files/zh-tw/mozilla/projects/rhino/index.html b/files/zh-tw/mozilla/projects/rhino/index.html new file mode 100644 index 0000000000..9167cbfaac --- /dev/null +++ b/files/zh-tw/mozilla/projects/rhino/index.html @@ -0,0 +1,27 @@ +--- +title: Rhino +slug: Mozilla/Projects/Rhino +tags: + - JavaScript + - Mozilla + - NeedsTranslation + - NeedsUpdate + - Rhino + - TopicStub +translation_of: Mozilla/Projects/Rhino +--- +

Image:rhino.jpg

+ +

Rhino is an open-source implementation of JavaScript written entirely in Java. It is typically embedded into Java applications to provide scripting to end users. It is embedded in J2SE 6 as the default Java scripting engine.

+ +

Rhino downloads

+ +

How to get source and binaries

+ +

Rhino documentation

+ +

Information on Rhino for script writers and embedders.

+ +

Rhino help

+ +

Some resources if you get stuck.

diff --git a/files/zh-tw/mozilla/projects/rhino/license/index.html b/files/zh-tw/mozilla/projects/rhino/license/index.html new file mode 100644 index 0000000000..951430039e --- /dev/null +++ b/files/zh-tw/mozilla/projects/rhino/license/index.html @@ -0,0 +1,47 @@ +--- +title: Rhino license +slug: Mozilla/Projects/Rhino/License +translation_of: Mozilla/Projects/Rhino/License +--- +

Rhino可在開源許可下使用。

+ +

MPL / GPL許可

+ +

Rhino的大部分源代碼都是在MPL 1.1 / GPL 2.0許可下提供的。

+ +

部分Rhino調試器的許可證

+ +

此外,一些文件(目前是toolsrc / org / mozilla / javascript / tools / debugger / treetable /的內容)在以下許可下可用:

+ +
 *版權所有1997,1998 Sun Microsystems,Inc。保留所有權利。
+ *
+ *重新分發和使用源和二進制形式,有或沒有
+ *修改,如果滿足以下條件,則允許
+ *符合:
+ *
+ *  - 源代碼的重新分發必須保留上述版權
+ *通知,此條件清單和以下免責聲明。
+ *
+ *  - 二進制形式的再分發必須複製上述版權
+ *通知,此條件清單和以下免責聲明
+ *隨分發提供的文件和/或其他材料。
+ *
+ *  -  Sun Microsystems的名稱和名稱
+ *貢獻者可用於支持或推廣衍生產品
+ *未經事先書面許可,不得使用本軟件。
+ *
+ *本軟件由版權所有者和貢獻者“提供
+ *“是”以及任何明示或暗示的擔保,包括但不限於,
+ *對適銷性和特定適用性的暗示保證
+ *目的不承擔任何責任。在任何情況下都不應該是版權所有者或
+ *貢獻者對任何直接,間接,偶然,特殊的,
+ *示範性或後續性損害(包括但不限於,
+ *購買替代商品或服務; 丟失使用,數據或
+ *利潤; 或商業中斷)然而,導致和任何理論
+ *責任,無論是合同,嚴格責任還是侵權(包括
+ *疏忽或以其他方式)以任何方式使用此產品
+ *軟件,即使被告知此類損害的可能性。
+
+ +
+

Norrisboyd 2008年4月14日06:16(PDT)

diff --git a/files/zh-tw/mozilla/qa/bug_writing_guidelines/index.html b/files/zh-tw/mozilla/qa/bug_writing_guidelines/index.html new file mode 100644 index 0000000000..57d1cc41db --- /dev/null +++ b/files/zh-tw/mozilla/qa/bug_writing_guidelines/index.html @@ -0,0 +1,246 @@ +--- +title: Bug writing guidelines +slug: Mozilla/QA/Bug_writing_guidelines +tags: + - 錯誤回報 +translation_of: Mozilla/QA/Bug_writing_guidelines +--- +
+

If you need help with Mozilla software (for example with Firefox, Seamonkey or Thunderbird), use one of the available support options. Do not edit this page!

+
+ +

This page assumes you'd like to contribute to the Mozilla project by collecting enough information to enter a useful bug report in Bugzilla, the Mozilla bug tracking system. Thank you!

+ +

If you're new to reporting bugs, you may want to try getting help from the more experienced contributors. See the Community section on the QA page for pointers. If you're going to report a Firefox bug, you can also get assistance in the #firefox channel on irc.mozilla.org. For other projects (e.g., Thunderbird, SeaMonkey)  you can find the appropriate channel on IRC.

+ +

如何回報錯誤

+ +

每次回報一個錯誤

+ +

如此一來能夠有效率地處理每個錯誤。

+ +

其他需要您注意的事項

+ +
    +
  1. 釐清如何 重現您遇到的錯誤: + +
      +
    • 如果能夠 完整描述重現錯誤過程 —太棒了! — 您將提供有收穫的錯誤回報。
    • +
    • 有時能夠重現問題,但不確定是用什麼特定的方法,則您需要提供有幫助的額外資訊。
    • +
    • 如果無法重現問題,回報該問題可能沒有太大的幫助,除非在發現錯誤時,您有獨特的發現。
    • +
    +
  2. +
  3. 檢查軟體是否已更新至最新版本。建議先測試開發中版本來確認錯誤是不是早就修正(例如:Firefox Beta, Aurora, 或是走在科技前端的 Nightly
  4. +
  5. When reporting a Firefox bug, first check if you can reproduce the bug in a new Firefox profile. If the bug only happens in your existing profile, try to figure out what settings, extensions, or files in your profile are needed to reproduce the bug. +
      +
    • If the bug seems egregious (i.e. obviously affecting a large portion of users), there's probably something unusual about your setup that's a necessary part of the steps to reproduce the bug. You have much better chances of figuring it out than a developer who does not have access to your system.
    • +
    • If the bug falls into one of specific types of bugs listed in a section below, it may still be useful even if you can't reproduce it in a new Firefox profile.
    • +
    +
  6. +
  7. Open the Enter a new bug form, which will guide you through most of the bug reporting process: +
      +
    • Create a Bugzilla account if you don't have one already, select the product having the bug.
    • +
    • Enter a clear unique summary as described below; check if the bug has already been reported (if you want to be more thorough, there's an advanced guide on screening duplicate bugs).
    • +
    • Provide precise steps to reproduce, expected results and actual results as described in the following section.
    • +
    • Provide additional information (also described below), especially if you can't reproduce the bug in a new profile; and/or by reporting a crash, memory usage, performance, regression bug; or if the problem is with a specific web site.
    • +
    +
  8. +
  9. 如果遇到多個錯誤時,請分開一個一個回報。
  10. +
+ +

簡短明確描述問題

+ +

您會怎麼用大概十幾個字描述問題? 開發者會先看到這一部分文字。

+ +

好的錯誤回報會快速且清楚說明錯誤。這是用來解釋問題的來龍去脈,請不要給予針對問題的建議。

+ + + + + +

描述可以重現問題的詳細的步驟

+ +

How can a developer reproduce the bug on his or her own computer?

+ +

Steps to reproduce are the most important part of any bug report. If a developer is able to reproduce the bug, the bug is very likely to be fixed. If the steps are unclear, it might not even be possible to know whether the bug has been fixed.

+ + + + + + + + + + + + + + + + + + + + + + + + +
在問題回報裡應該寫些什麼 ?好的例子(描述細節) +

不好的例子(敘述籠統)

+
+

說說你能不能控制卡 bug 的時機。

+ +

可以故意卡、偶爾遇到、不能控制。

+
照著下面的步驟做問題就出現了: 
+

描述如何命令 Firefox 做你想做的事。

+
+

1. 點桌面捷徑打開 Firefox
+ 2. 按下 Cmd+N (Windows 系統按 Ctrl+N )來打開新的視窗。

+ +

3. 把 https://mail.google.com/ 複製貼上到網址列然後按Enter。

+
在新視窗打開Gmail
+

照著步驟做後,清楚地描述你看到的 (實際) 結果預期結果。 請將這兩項分開來寫。

+
預期結果: 我的收件匣正常顯示。
+ 實際結果: 我的收件匣顯示 '您的瀏覽器不支援 Cookies (錯誤 -91)'。
+

 

+ +

"網頁跑不出來"

+
+ +

提供額外的資訊

+ +

The following information is requested for most bug reports. You can save time by providing this information below the Expected results. If you need to attach multiple files, you can do so after submitting the report.

+ +

For specific types of bugs

+ +

If you are reporting a crash bug, please include a Breakpad ID or attach stack trace, and include the crash signature in the bug summary as well as in the Crash Signature field.

+ +

If you are reporting a memory use or leak bug, please attach the output of about:memory. Ideally, find steps to reproduce an increase in what is shown in about:memory (even after clicking the "Minimize memory usage" button at the bottom). If you have trouble finding steps to reproduce, try the Firefox Support page titled Firefox Uses Too Much Memory (Ram) - How to Fix. If you are a C++ developer, more precise tools are available.

+ +

If you are reporting a bug about slowness or high CPU usage, please provide a link to the performance profile in the bug.

+ +

If you are reporting a hang (beachball on OS X or "not responding" on Windows), please follow the instructions in How to Report a Hung Firefox.

+ +

If you are reporting a bug involving a Flash hang, please visit https://wiki.mozilla.org/Flash/Hang_Debugging to learn how to provide useful information for developers.

+ +

If you are reporting a bug involving a specific web page, please try to make a reduced testcase and attach it to the bug report. If you don't have time or expertise, please report the issue to webcompat.com instead, where our volunteers will do this for you.

+ +

If the bug was recently introduced, finding a regression window can help identify the cause of the bug.

+ +

What if my bug seems "random" or "intermittent"?

+ +

For most Firefox bugs

+ +

You should provide the following information for most Firefox bugs.

+ + + + + + + + + + + + + + + + + + + + +
What should you include in a bug report?Example
Indicate if the problem can be reproduced using a new Firefox profile and any changes you need to make in order to reproduce.The problem can be reproduced in a new profile, but only if Preferences -> Privacy & Security -> Tracking Protection is selected.
If you can only reproduce with an existing profile try to figure out what settings, extensions, or files in your profile are needed to reproduce the bug. If you skip the step, save the troubleshooting information from about:support to a file and attach it to the bug report.I can't reproduce in a new profile, about:support information from the offending profile is attached.
+

Indicate if the problem can be reproduced using the latest Nightly build. Include the Build ID from about:support.

+ +

If possible, test using the new Firefox profile you created. If you need to test the Nightly build with your regular profile, you might want to back up the profile first, since the pre-release build may corrupt your data.

+
The problem can be reproduced on the latest Nightly (Build ID 20170416100136).
+ +

 

+ +
+

Original document information

+ + +
+ +

 

+ +
+

Advanced

+ +

Finding the correct product and component

+ +

You will be asked to categorize your bug into a "product" and a "component" within that product, in order to direct your report to the correct developers.

+ +

If you're using Firefox, the bug is most likely in "Firefox", "Toolkit", or "Core".

+ + + +

When in doubt, search for similar bugs and see which component they are in.

+ +

If none of the components seem appropriate, look for a "General" component in the most appropriate product.

+ +

General Outline of a Bug Report

+ +
+

Most of the following article has been merged into this page from QMO: How to write a proper bug

+
+ + + +

 

+ +
+

Original document information

+ + +
diff --git a/files/zh-tw/mozilla/qa/index.html b/files/zh-tw/mozilla/qa/index.html new file mode 100644 index 0000000000..99a8a38dd2 --- /dev/null +++ b/files/zh-tw/mozilla/qa/index.html @@ -0,0 +1,251 @@ +--- +title: 'QA: Quality assurance at Mozilla' +slug: Mozilla/QA +tags: + - Landing + - NeedsTranslation + - QA + - Testing + - TopicStub +translation_of: Mozilla/QA +--- +

The Mozilla Quality Assurance (QA) team drives software quality assurance activities across Mozilla and plays a key role in releasing a diverse range of software products on schedule. Within each project in Mozilla, we work to explore new features, write and execute tests, uncover and file bugs, build and maintain tools, collect and analyze metrics, and support the release world-class products that promote the open Web.

+ +

Here you'll find articles and tools to help you gear up to join the QA team testing Firefox to ensure that each release is as good as it can be.

+ +

Get started

+ + + +

Bugs

+ +
+
+

Reporting bugs

+ +
+
Bugzilla
+
All Mozilla projects use Bugzilla to track bugs. You will need to create an account with Bugzilla in order to report bugs and triage them.
+
Bug writing guidelines
+
The more effectively a bug is reported, the more likely that an engineer will actually fix it. By following these guidelines, you can help ensure that your bugs stay at the top of the Mozilla engineers' heap, and get fixed.
+
A Bug's Life
+
This tutorial will give an overview of what happens in the states that a bug will go through as well as how it will go from one to the next within its total life. It also explains the meaning of flags/keywords used in QA.
+
Filing Crash Bugs
+
This document lists guidelines and tips on how to file bug reports for crashes in a way that helps in debugging and fixing the reported issue.
+
+
+ +
+

Triaging bugs

+ +
+
Confirming unconfirmed bugs
+
Identify useful bug reports and close the rest.
+
Triaging Bugs for Firefox
+
Information about the entire bug triaging process – from processing incoming bugs to narrowing down the steps to reproducing bugs.
+
Screening duplicate bugs
+
Help get bugs fixed faster by screening incoming reports for duplicates.
+
General Guidelines
+
What to do and what not to do in Bugzilla.
+
+
+
+ +
+

Manual testing

+ +
+
+
+
Manual Test Case Writing Primer
+
How to write proper manual test cases
+
+
+ +
+
+
TestRail
+
Mozilla QA's manual test cases reside in TestRail. You will need an LDAP account in order to login and execute test cases. Learn more on the TestRail wiki page.
+
+
+
+ +
+

Automated testing

+ +
+
+
+
Automated testing at Mozilla
+
Documentation about creating and using automated tests for Mozilla code.
+
Running automated tests
+
+

This page lists the steps required to run Mozilla's automated test suites.

+
+
Developing tests
+
Ensure that future changes to Mozilla don't break things that currently work correctly.
+
Avoiding intermittent test failures
+
Suggestions for ways to make your tests more reliable, thereby helping to avoid random, intermittent test failures.
+
Test Verification
+
When a changeset adds a new test, or modifies an existing test, the test verification (TV) test suite performs additional testing to help find intermittent failures in the modified test as quickly as possible.
+
Mozharness FAQ
+
Answers to common questions about Mozharness.
+
+
+ +
+
+
Robocop
+
Robocop is the automated testing system used for Firefox for Android. Learn its code style guidelines
+
Marionette
+
Get started with Marionette UI testing.
+
web-platform-tests
+
Learn how to use the industry standard, cross-browser, cross-platform Web runtime testing system from the W3C used by Mozilla and others to ensure browser interoperability.
+
External Media Tests
+
Get started testing HTML5-based video elements using VideoPuppeteer, a Marionette- -based test suite used to test sites like YouTube and Netflix.
+
Chrome tests
+
A chrome test is basically a Mochitest running with chrome privileges.
+
+
+
+ +
+

Firefox QE

+ +
+
+
+
Triaging Bugs for Firefox
+
Information about the entire bug triaging process – from processing incoming bugs to narrowing down the steps to reproduce a bug.
+
+ +
+
Tips and Tricks
+
These tips and tricks will make your life easier when you are testing.
+
+Downloading Nightly or Trunk Builds + +
+
Every 24 hours, a "nightly" build is created that testers all over the world download and test, reporting as they go along on any bugs that hit them.
+
+
+ +
+
+
Command Line Options
+
Command line options are used to specify various startup options for Firefox.
+
Reporting a Performance Problem
+
This article will guide you in reporting a performance problem using the Gecko Profiler extension.
+
Crash reporting
+
Firefox ships with an open-source crash reporting system.
+
+
+
+ +
+

Firefox for Android

+ +
+
+
+
Mobile Firefox
+
Firefox for Android is the mobile version of Firefox with a native Android look and feel.
+
Compatibility Testing
+
Help us identify websites that do not work well in Firefox by reporting the specific issues that you find in your investigation.
+
+
+ +
+
+
Logging with the Android Debug Bridge and Logcat
+
This article will provide a walkthrough in downloading and setting up an environment to which one can gain access to and view Android system logs.
+
Enabling the Error Console
+
See the Mozilla Hacks article on Remote Debugging on Firefox for Android for web content. If you need to debug the Firefox browser itself use Android's adb logcat.
+
+
+
+ +
+

Firefox OS

+ +
+
+

Manual testing

+ +
+
Simulator vs Emulator vs Device
+
These are three basic options when it comes to getting a Firefox OS environment in order to work on, or developing for, Firefox OS.
+
Debugging
+
Discover the different tools at your disposal to debug your Firefox OS code.
+
Reporting Bugs
+
This article provides a guide to filing bugs against the Firefox OS project, including Gaia and B2G.
+
+
+ +
+

Platform (Gecko)

+ +
+
Automated Testing
+
Learn various aspects of testing Firefox OS, including running different tests, automation, and result reporting and tracking.
+
Gaia Performance Tests
+
This article provides information about running performance tests on Gaia, as well as how to create new tests.
+
Feature Support Chart
+
There are several different builds of Firefox OS you can download or build for yourself, and there are some differences between the types of features available on each device.
+
+
+
+ +
+

Web QA

+ +
+
+
+
Reducing testcases
+
Improve bug reports by turning broken web pages into simple testcases, which can help developers understand the bug and can also be used for creating automated tests.
+
Managing XFails
+
One of the ongoing tasks of the Web QA department is managing xfails. This document will explain what xfails are, and describe the steps one can take to investigate and update them.
+
+
+ +
+
+
Running Automated Tests
+
So you’re interested in contributing to Mozilla Web QA automation projects but don’t know where to start? This doc will help you get up and running a set of tests locally.
+
+
+
+ +
+

Glossary

+ +
+
+
Smoke Test
+
+
+
+ +

See also

+ + diff --git a/files/zh-tw/mozilla/rust/index.html b/files/zh-tw/mozilla/rust/index.html new file mode 100644 index 0000000000..28f46deb33 --- /dev/null +++ b/files/zh-tw/mozilla/rust/index.html @@ -0,0 +1,40 @@ +--- +title: Rust 程式語言 +slug: Mozilla/Rust +translation_of: Mozilla/Rust +--- +

Rust logoRust 是個由 Mozilla 及社區志願者所建立的開源系統程式語言,旨在幫助開發者建立快速安全,並充分使用當代多核心處理器強大功能的程式。它會阻止記憶體區段錯誤(segmentation fault)並確保執行緒(thread)安全、並使用簡單明瞭的語法。

+ +

另外,Rust 提供了 zero-cost abstractions, move semantics, guaranteed memory safety, threads with no data races, trait-based generics, pattern matching, type inference, and efficient C bindings, with a minimum runtime size.

+ +

要學習 Rust,可以透過:

+ + + +

Rust and the future of systems programming

+ +

{{EmbedYouTube("8EPsnf_ZYU0")}}

+ +

Unlocking the power of parallelism with Rust

+ +

{{EmbedYouTube("cNeIOt8ZdAY")}}

+ +

Rust for web developers

+ +

{{EmbedYouTube("FfoXFnzZbBM")}}

+ +

Safe systems programming with Rust

+ +

{{EmbedYouTube("P3sfNGtpuxc")}}

+ +

Growing the Rust community

+ +

{{EmbedYouTube("duv0tuPAnO0")}}

+ +

Putting Rust into production at Mozilla

+ +

{{EmbedYouTube("2RhbYpgVpg0")}}

diff --git a/files/zh-tw/mozilla/tech/index.html b/files/zh-tw/mozilla/tech/index.html new file mode 100644 index 0000000000..f9682e62e1 --- /dev/null +++ b/files/zh-tw/mozilla/tech/index.html @@ -0,0 +1,14 @@ +--- +title: Mozilla technologies +slug: Mozilla/Tech +tags: + - Landing + - Mozilla + - NeedsTranslation + - Reference + - TopicStub + - XUL +translation_of: Mozilla/Tech +--- +

Mozilla has several technologies used as components of its projects. These are documented here. (flesh out this text).

+

{{LandingPageListSubpages}}

diff --git a/files/zh-tw/mozilla/tech/xpcom/reference/index.html b/files/zh-tw/mozilla/tech/xpcom/reference/index.html new file mode 100644 index 0000000000..29d07953d6 --- /dev/null +++ b/files/zh-tw/mozilla/tech/xpcom/reference/index.html @@ -0,0 +1,27 @@ +--- +title: XPCOM reference +slug: Mozilla/Tech/XPCOM/Reference +tags: + - Add-ons + - Extensions + - Landing + - Mozilla + - NeedsTranslation + - Reference + - TopicStub + - XPCOM +translation_of: Mozilla/Tech/XPCOM/Reference +--- +

This reference describes the interfaces and functions provided by the XPCOM library. In addition, it details the various helper classes and functions, as well as the components, provided by the XPCOM glue library. The contents herein are oriented primarily toward extension developers and people embedding XPCOM in other projects.

+ +
+

WebExtensions are becoming the new standard for creating add-ons. Eventually support for XPCOM add-ons will be deprecated, so you should begin to investigate porting your add-ons to use the WebExtensions API, and report any missing functionality so we can be sure to address your concerns. Work is ongoing on WebExtension capabilities, so your input will help prioritize and plan the work. To learn more about the kinds of changes that will be needed, see Comparison with XUL/XPCOM extensions. In addition, any binaries you use will then need to be converted for use with the WebExtensions native messaging API, or compiled using WebAssembly or Emscripten.

+
+ +
+

If you're working on a module in the Mozilla codebase that's compiled with the MOZILLA_INTERNAL_API flag set, some of these APIs -- the string functions and classes in particular -- are not the ones you should be using. See the XPCOM internal string guide for documentation of the internal string API used within the Mozilla codebase.

+
+ +

{{LandingPageListSubpages}}

+ +

Many XPCOM pages return an nsresult. Prior to Gecko 19 {{geckoRelease(19)}}, this was an integer that simply returned an error code. It is now a strongly typed enum when XPCOM is built using a C++11 compiler. This causes compile-time errors to occur when improper values are returned as nsresult values, thereby making it easier to catch many bugs.

diff --git a/files/zh-tw/mozilla/tech/xpcom/reference/interface/index.html b/files/zh-tw/mozilla/tech/xpcom/reference/interface/index.html new file mode 100644 index 0000000000..d098cf8402 --- /dev/null +++ b/files/zh-tw/mozilla/tech/xpcom/reference/interface/index.html @@ -0,0 +1,19 @@ +--- +title: XPCOM Interface Reference +slug: Mozilla/Tech/XPCOM/Reference/Interface +tags: + - NeedsTranslation + - TopicStub + - XPCOM + - XPCOM Interface Reference +translation_of: Mozilla/Tech/XPCOM/Reference/Interface +--- +

This is a reference to the XPCOM interfaces provided by the Mozilla platform.

+ +
{{tree('','1')}}
+ +

See also

+ + diff --git a/files/zh-tw/mozilla/tech/xpcom/reference/interface/nsicontentpolicy/index.html b/files/zh-tw/mozilla/tech/xpcom/reference/interface/nsicontentpolicy/index.html new file mode 100644 index 0000000000..6ed47b6c80 --- /dev/null +++ b/files/zh-tw/mozilla/tech/xpcom/reference/interface/nsicontentpolicy/index.html @@ -0,0 +1,491 @@ +--- +title: nsIContentPolicy +slug: Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy +translation_of: Archive/Mozilla/nsIContentPolicy +--- +

{{IFSummaryStart(“DOM /鹼/ nsIContentPolicy.idl”,“編寫腳本”)}}接口用於實現內容策略的機制。這個接口的實現可以被用來控制各種類型的外的線的內容,或者某些類型的內聯內容的處理的負荷。{{IFSummaryEnd(“nsIContentPolicyBase”,42,“1.0”)}}

+ +

可以觀察到,正在通過實施{{接口(“nsIContentPolicy”)}}加載到瀏覽器中的內容。如果你正在開發一個內容感知的插件(攔截廣告或改變內容的外觀,例如)該接口是非常有用的,或者如果你想停止或允許用戶瀏覽的網址。

+ +

{{WarningStart()}}不要阻塞調用者在你的實施方式{{manch(“shouldLoad”)}}或{{manch(“為ShouldProcess”)}}(例如,通過啟動一個對話框,以提示用戶東西)。“){{WarningEnd()}}

+ +
+

注:在現實中,很多這種接口在{{接口(“nsIContentPolicyBase”)}}接口定義,但現在,直到有人有時間來拆東西記錄在這裡。

+
+ +

方法概述

+ + + + + + + + + + +
short shouldLoad(in unsigned long aContentType, in nsIURI aContentLocation, in nsIURI aRequestOrigin, in nsISupports aContext, in ACString aMimeTypeGuess, in nsISupports aExtra, in nsIPrincipal aRequestPrincipal);
short shouldProcess(in unsigned long aContentType, in nsIURI aContentLocation, in nsIURI aRequestOrigin, in nsISupports aContext, in ACString aMimeType, in nsISupports aExtra, in nsIPrincipal aRequestPrincipal);
+ +

常量

+ +

內容類型

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
不變描述
TYPE_OTHER1指示內容,其類型是未知的,或者是不感興趣的一個有限的使用情況之外。在一般情況下,你應該盡量不要使用這種類型的,除非沒有其他人是合適的。{{gecko_minversion_inline(“1.8”)}}
TYPE_SCRIPT2表示的可執行script(例如JavaScript)。{{gecko_minversion_inline(“1.8”)}}
TYPE_IMAGE3指示image(例如,{{HTMLElement的(“IMG”)}}的元素)。{{gecko_minversion_inline(“1.8”)}}
TYPE_STYLESHEET4指示stylesheet(例如,{{HTMLElement的(“風格”)}}的元素)。{{gecko_minversion_inline(“1.8”)}}
TYPE_OBJECT5代表一個普通object(插件,處理內容通常這一類下降)。{{gecko_minversion_inline(“1.8”)}}
TYPE_DOCUMENT6表示DOM {{domxref(“文件”)}}在頂層(即,直接在瀏覽器標籤)。{{gecko_minversion_inline(“1.8”)}}
TYPE_SUBDOCUMENT7 +

表示包含在另一個一{{domxref(“文件”)}} document例如,{{HTMLElement的(“IFRAME”)}}和{{HTMLElement的(“幀”)}}的元素)。{{gecko_minversion_inline(“1.8”)}}

+ +
+

注:壁虎使用TYPE_INTERNAL_FRAME,並TYPE_INTERNAL_IFRAME以內部辨別其差異。這些類型映射到TYPE_SUBDOCUMENT被傳遞到內容政策實施前,不應外壁虎代碼中使用。{{gecko_minversion_inline(41)}}

+
+
TYPE_REFRESH8 +

指示定時刷新。

+ +

{{manch(“shouldLoad”)}}將永遠不會得到這個,因為它並不代表內容被加載(通過刷新觸發的實際負載將通過{{manch(“shouldLoad”)}}如預期)。

+ {{manch(“為ShouldProcess”)}}將收到此為,例如{{HTMLElement的(“元”)}}刷新元件和HTTP刷新頭。{{gecko_minversion_inline(“1.8”)}}
TYPE_XBL9指示XBL綁定請求,觸發或者通過{{cssxref(“ - MOZ結合”)}} CSS屬性或{{domxref(“Document.addBinding()”)}}方法。{{gecko_minversion_inline(“1.8”)}}
TYPE_PING10表示通過在{{HTML元素(“A”)}}使用元素{{htmlattrxref(“平”,“一”)}}屬性的點擊觸發的平。{{gecko_minversion_inline(“1.9”)}}
TYPE_XMLHTTPREQUEST11表示{{domxref(“XMLHttpRequest的”)}}。也用於{{domxref(“Document.load()”)}} {{gecko_minversion_inline(“1.9”)}}
TYPE_OBJECT_SUBREQUEST12表示由一個插件的請求。{{gecko_minversion_inline(“1.9”)}}
TYPE_DTD13表示通過XML加載的DTD document{{gecko_minversion_inline(“1.9”)}}
TYPE_FONT14指示經由{{cssxref(“@字體面”)}}規則加載的字體。{{gecko_minversion_inline(“1.9.1”)}}
TYPE_MEDIA15表示視頻或音頻負載。{{gecko_minversion_inline(“1.9.1”)}}
TYPE_WEBSOCKET16表示的WebSocket的負荷。{{gecko_minversion_inline(“11”)}}
TYPE_CSP_REPORT17表示一個內容安全策略報告。{{gecko_minversion_inline(“20”)}}
TYPE_XSLT18表示一個樣式表轉換。{{gecko_minversion_inline(“27”)}}
TYPE_BEACON19表示信標後。{{gecko_minversion_inline(“30”)}}
TYPE_FETCH20指示通過發起的負載的{{domxref(“GlobalFetch.fetch()”)}}方法,其可作為在全球都{{domxref(“窗口”)}}和{{domxref(“工人”)} }上下文。{{gecko_minversion_inline(36)}}
TYPE_IMAGESET21指示要加載的{{HTML元素(“IMG”)}}(與該{{htmlattrxref(“srcset”,“IMG”)}}屬性或{{HTMLElement的(“圖片”)}}。{{gecko_minversion_inline(請求36)}}
TYPE_WEB_MANIFEST22指示要加載一個Web清單的請求。{{gecko_minversion_inline(41)}}
TYPE_INTERNAL_SCRIPT23 +

用於表示使用{{HTMLElement的(“腳本”)}}元素加載的腳本的內部常數。{{gecko_minversion_inline(41)}}

+ +
+

重要說明:此類型映射到TYPE_SCRIPT傳遞給內容政策實施之前,不宜在室外的Gecko內核代碼中使用。

+
+
TYPE_INTERNAL_WORKER24 +

用於表示通過專用工人加載的腳本的內部常數。{{gecko_minversion_inline(41)}}

+ +
+

重要說明:此類型映射到TYPE_SCRIPT傳遞給內容政策實施之前,不宜在室外的Gecko內核代碼中使用。

+
+
TYPE_INTERNAL_SHARED_WORKER25 +

用於表示通過共享工人加載的腳本的內部常數。{{gecko_minversion_inline(41)}}

+ +
+

重要說明:此類型映射到TYPE_SCRIPT傳遞給內容政策實施之前,不宜在室外的Gecko內核代碼中使用。

+
+
TYPE_INTERNAL_EMBED26 +

內部常量用於表示從{{HTML元素(“嵌入”)}}元素加載的內容。{{gecko_minversion_inline(41)}}

+ +
+

重要說明:此類型映射到TYPE_OBJECT傳遞給內容政策實施之前,不宜在室外的Gecko內核代碼中使用。

+
+
TYPE_INTERNAL_OBJECT27 +

內部常量用於表示從{{HTMLElement的(“對象”)}}元素加載的內容。{{gecko_minversion_inline(41)}}

+ +
+

重要說明:此類型映射到TYPE_OBJECT傳遞給內容政策實施之前,不宜在室外的Gecko內核代碼中使用。

+
+
TYPE_INTERNAL_FRAME28 +

內部常量用於表示從{{HTML元素(“幀”)}}元素加載的內容。{{gecko_minversion_inline(41)}}

+ +
+

重要說明:此類型映射到TYPE_SUBDOCUMENT傳遞給內容政策實施之前,不宜在室外的Gecko內核代碼中使用。

+
+
TYPE_INTERNAL_IFRAME29 +

內部常量用於表示從{{HTML元素(“IFRAME”)}}元素加載的內容。{{gecko_minversion_inline(41)}}

+ +
+

重要說明:此類型映射到TYPE_SUBDOCUMENT傳遞給內容政策實施之前,不宜在室外的Gecko內核代碼中使用。

+
+
TYPE_INTERNAL_AUDIO30 +

內部常量用於表示從{{HTML元素(“音頻”)}}元素加載的內容。{{gecko_minversion_inline(41)}}

+ +
+

重要說明:此類型映射到TYPE_MEDIA傳遞給內容政策實施之前,不宜在室外的Gecko內核代碼中使用。

+
+
TYPE_INTERNAL_VIDEO31 +

內部常量用於表示從{{HTML元素(“視頻”)}}元素加載的內容。{{gecko_minversion_inline(41)}}

+ +
+

重要說明:此類型映射到TYPE_MEDIA傳遞給內容政策實施之前,不宜在室外的Gecko內核代碼中使用。

+
+
TYPE_INTERNAL_TRACK32 +

內部常量用於表示從{{HTML元素(“軌道”)}}元素加載的內容。{{gecko_minversion_inline(41)}}

+ +
+

重要說明:此類型映射到TYPE_MEDIA傳遞給內容政策實施之前,不宜在室外的Gecko內核代碼中使用。

+
+
REJECT_REQUEST-1從{{manch(“shouldLoad”)}}或{{manch(“為ShouldProcess”)}}返回如果負載或處理請求是基於所述請求的細節拒絕。{{gecko_minversion_inline(“1.8”)}}
REJECT_TYPE-2 +

從{{manch(“shouldLoad”)}}或{{manch(“為ShouldProcess”)}}返回如果負載/過程僅僅基於(上述標誌)它的類型拒絕。

+ {{注(“這甩只適用於該服務器上的當前請求,而不是同一類型的未來需求。”)}} {{gecko_minversion_inline(“1.8”)}}
REJECT_SERVER-3 +

從{{manch(“shouldLoad”)}}或{{manch(“為ShouldProcess”)}}如果負載/過程是基於在服務器上拒絕它託管在或從請求(返回aContentLocationaRequestOrigin),例如,如果塊的IMAGE,因為它是從goatse.cx服務(即使你不一定阻止other從該服務器/域類型)。

+ {{注(“這甩只適用於該服務器上的當前請求,而不是同一類型的未來需求。”)}} {{gecko_minversion_inline(“1.8”)}}
REJECT_OTHER-4 +

從{{manch(“shouldLoad”)}}或返回{{manch(“為ShouldProcess”)}}如果負載/過程是基於一些拒絕other標準。Mozilla的呼叫者會處理這個喜歡REJECT_REQUEST; 第三方實現者,例如,用這個來指導自己的來電諮詢額外參數的更多細節。{{gecko_minversion_inline(“1.8”)}}

+ +

{{注(“這甩只適用於該服務器上的當前請求,而不是同一類型的未來需求。”)}}

+
ACCEPT1從{{manch(“shouldLoad”)}}或{{manch(“為ShouldProcess”)}}如果負載或處理請求不被拒絕返回。{{gecko_minversion_inline(“1.8”)}}
OTHER0{{obsolete_inline(“1.8”)}}
SCRIPT1{{obsolete_inline(“1.8”)}}
IMAGE2{{obsolete_inline(“1.8”)}}
STYLESHEET3{{obsolete_inline(“1.8”)}}
OBJECT4{{obsolete_inline(“1.8”)}}
SUBDOCUMENT5{{obsolete_inline(“1.8”)}}
CONTROL_TAG6{{obsolete_inline(“1.8”)}}
RAW_URL7{{obsolete_inline(“1.8”)}}
DOCUMENT8{{obsolete_inline(“1.8”)}}
+ +

方法

+ +

shouldLoad()

+ +

打電話讓自己的內容政策的執行決定在給定位置的資源是否應該被加載。這種方法是通過加載指定aContentLocation的資源,以確定是否要開始加載所請求的資源之前調用。

+ +

shouldLoad()可以稱為同時所涉及的文檔的DOM和佈局是不一致的狀態。這意味著,該方法的實施者不得做任何以下內容:

+ +
    +
  1. 以任何方式修改DOM中(例如,設置屬性是一個沒有沒有)。
  2. +
  3. 查詢依賴於佈局(例如,任何DOM屬性offset*屬性)。
  4. +
  5. 查詢依賴於任何風格的DOM屬性(例如,計算方式)。
  6. +
  7. 查詢依賴於DOM的當前狀態的“上下文”節點(例如,節點列表的長度)之外的任何DOM屬性。
  8. +
  9. [JavaScript實現僅]不使用XPCNativeWrapper(顯式或隱式地)的任何對象上的任何類型的訪問屬性。由於各種DOM0的事情,這會導致項目4。
  10. +
+ +

如果你在做這些事情shouldLoad()的實現,期望不可預知的行為,可能包括死機,沒有顯示出來的內容,內容顯示了一倍,等等。如果你不需要做任何的事情上面,做他們關閉超時或事件。

+ +
:當多個內容策略用於(例如,通過幾個擴展),如果其中一人拒絕的請求,該政策的其餘部分不叫。參考:http://mxr.mozilla.org/mozilla-central/source/content/base/src/nsContentPolicy.cpp#146
+ +
:內容政策在上述情況下的順序取決於安裝的優先級。
+ +
短shouldLoad(
+  在無符號長aContentType,
+  在nsIURI aContentLocation,
+  在nsIURI aRequestOrigin,
+  在nsISupports aContext,
+  在ACString aMimeTypeGuess,
+  在nsISupports aExtra,
+  在nsIPrincipal aRequestPrincipal
+);
+
+ +
參數
+ +
+
aContentType
+
的類型的內容進行測試。這將是一個一個{{ANCH(“內容類型”)}}在上面列出。
+
aContentLocation
+
的內容的URI被檢查; 一定不能null
+
aRequestOrigin {optional_inline}}
+
啟動此加載請求的資源的位置; null如果不適用。
+
aContext {optional_inline}}
+
的{{接口(“nsIDOMNode”)}}或{{接口(“nsIDOMWindow”)}}發起請求,或一些可以QueryInterface()向其中的一個; null如果不適用。
+
{{音符(“aContext是當用戶使用的上下文菜單中的新選項卡/窗口或CMD / CTRL +打開鏈接的新選項卡/窗口點擊鏈接(即,aContext不是該鏈路是在拉片在這些情況下)。“)}}
+
 
+
 
+
aMimeTypeGuess
+
可選的。用於所請求的內容的MIME類型猜測,基於可用於請求發起(例如,信息OBJECT的類型屬性); 不能可靠地反映實際的MIME類型所請求的內容。
+
aExtra
+
一個可選的參數,直通非壁虎呼叫者額外的數據傳遞給被調用者。
+
+ +
+
aRequestPrincipal
+
可選的。定義了導致負載的主體。這僅適用於可選的非壁虎代碼:所有的壁虎代碼應該設置此參數。對於導航事件,這是導致該加載頁面的主體。
+
+ +
返回值
+ +

ACCEPT 要么 REJECT_*

+ +

為ShouldProcess()

+ +

如果資源被處理?{{manch(“為ShouldProcess”)}}將被調用一次傳遞給它的所有資料已被確定有關資源,資源的一部分已經被加載後一般。“處理”是指通過處理應用程序。例如,為ShouldProcess可以用來允許來自服務器的響應根據MIME類型的響應的處理或忽略。

+ +

{{NoteStart()}} {{manch(“為ShouldProcess”)}}可以被稱為當DOM和佈局document涉及處於不一致的狀態。查看{{manch(“shouldLoad”)}}筆記,看看這是什麼意思了這種方法的實現者。{{NoteEnd()}}

+ +
短為ShouldProcess(
+  在無符號長aContentType,
+  在nsIURI aContentLocation,
+  在nsIURI aRequestOrigin,
+  在nsISupports aContext,
+  在ACString aMimeType,
+  在nsISupports aExtra,
+  在nsIPrincipal aRequestPrincipal
+);
+
+ +
參數
+ +
+
aContentType
+
的類型的內容進行測試。這將是TYPE_ *常量之一。
+
aContentLocation
+
可選的。被請求的資源的位置:可能是,例如,一個重定向後的URI資源。
+
aRequestOrigin
+
可選的。啟動此加載請求的資源的位置; null如果不適用。
+
aContext
+
可選的。的{{接口(“nsIDOMNode”)}}或發起請求{{接口(“nsIDOMWindow”)}},或一些可以查詢接口的那些中的一個; null如果不適用。
+
aMimeType
+
MIME類型所請求的資源(例如,圖像/ PNG)的,所報告的網絡庫,如果可用的話(可以是空的,如果不適合的類型,例如,TYPE_REFRESH)。
+
aExtra
+
一個可選的參數,直通非壁虎呼叫者額外的數據傳遞給被調用者。
+
+ +
+
aRequestPrincipal
+
可選的。提出請求的主體。
+
+ +
返回值
+ +

ACCEPT 要么 REJECT_*

+ +

+ +

您可以通過包括容易實現這個接口nsIContentPolicy.h的頭文件和實現public nsIContentPolicy到類,如下所示:

+ +
//將這個變成你的頭文件
+
+#包括“_path_to_sdk /包括/內容/ nsIContentPolicy.h”
+
+MyClass類:公共nsISupports,公共nsIContentPolicy {
+  ...
+  NS_DECL_NSICONTENTPOLICY
+  ...
+}
+
+//這到您的實現文件 
+NS_IMPL_ISUPPORTSn(MyClass的,nsISupports,nsIContentPolicy,...)
+
+ +

{{NoteStart()}}之前,你能接受的通知,你必須註冊你的插件{{接口(“nsICategoryManager”)}}。見下面的例子。{{NoteEnd()}}

+ +
字符*以前= nsnull; 
+
+nsCOMPtr的的<nsICategoryManager> catman; 
+
+servman-> GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID,
+NS_GET_IID(nsICategoryManager)
+getter_AddRefs(catman)); 
+
+RV = catman-> AddCategoryEntry(“內容的策略”,
+COMPONENT_CLASSNAME,
+COMPONENT_CONTRACTID,
+PR_TRUE,   
+PR_TRUE,
+以前);
+ +

JavaScript開發人員也可以實現XPCOM組件擴展nsIContentPolicy

diff --git a/files/zh-tw/mozilla/thunderbird/autoconfiguration/fileformat/howto/index.html b/files/zh-tw/mozilla/thunderbird/autoconfiguration/fileformat/howto/index.html new file mode 100644 index 0000000000..fafd0dffa0 --- /dev/null +++ b/files/zh-tw/mozilla/thunderbird/autoconfiguration/fileformat/howto/index.html @@ -0,0 +1,199 @@ +--- +title: 'Autoconfig: How to create a configuration file' +slug: Mozilla/Thunderbird/Autoconfiguration/FileFormat/HowTo +translation_of: Mozilla/Thunderbird/Autoconfiguration/FileFormat/HowTo +--- +

Definition

+

Authoritative definition

+

Example

+

Real-world example

+

 

+

<?xml version="1.0" encoding="UTF-8"?>

+

<clientConfig version="1.1">
+   <emailProvider id="freenet.de">
+     <domain>freenet.de</domain>
+     <displayName>Freenet Mail</displayName>
+     <displayShortName>Freenet</displayShortName>
+     <incomingServer type="imap">
+       <hostname>imap.freenet.de</hostname>
+       <port>993</port>
+       <socketType>SSL</socketType>
+       <authentication>password-encrypted</authentication>
+       <username>%EMAILADDRESS%</username>
+     </incomingServer>
+     <incomingServer type="imap">
+       <hostname>imap.freenet.de</hostname>
+       <port>143</port>
+       <socketType>STARTTLS</socketType>
+       <authentication>password-encrypted</authentication>
+       <username>%EMAILADDRESS%</username>
+     </incomingServer>
+     <incomingServer type="pop3">
+       <hostname>pop.freenet.de</hostname>
+       <port>995</port>
+       <socketType>SSL</socketType>
+       <authentication>password-cleartext</authentication>
+       <username>%EMAILADDRESS%</username>
+     </incomingServer>
+     <incomingServer type="pop3">
+       <hostname>pop.freenet.de</hostname>
+       <port>110</port>
+       <socketType>STARTTLS</socketType>
+       <authentication>password-cleartext</authentication>
+       <username>%EMAILADDRESS%</username>
+     </incomingServer>
+     <outgoingServer type="smtp">
+       <hostname>smtp.freenet.de</hostname>
+       <port>465</port>
+       <socketType>SSL</socketType>
+       <authentication>password-encrypted</authentication>
+       <username>%EMAILADDRESS%</username>
+     </outgoingServer>
+     <outgoingServer type="smtp">
+       <hostname>smtp.freenet.de</hostname>
+       <port>587</port>
+       <socketType>STARTTLS</socketType>
+       <authentication>password-encrypted</authentication>
+       <username>%EMAILADDRESS%</username>
+     </outgoingServer>
+     <documentation url="http://kundenservice.freenet.de/hilfe/email/programme/config/index.html">
+       <descr lang="de">Allgemeine Beschreibung der Einstellungen</descr>
+       <descr lang="en">Generic settings page</descr>
+     </documentation>
+     <documentation url="http://kundenservice.freenet.de/hilfe/email/programme/config/thunderbird/imap-thunderbird/imap/index.html">
+       <descr lang="de">TB 2.0 IMAP-Einstellungen</descr>
+       <descr lang="en">TB 2.0 IMAP settings</descr>
+     </documentation>
+   </emailProvider>
+ </clientConfig>

+

How to probe mail servers

+

To determine a server's capabilities, you can contact the server directly and talk the POP/IMAP/SMTP protocol manually (assuming you already know the hostname).
+ For non-SSL, use netcat -v hostname port (preferred) or telnet hostname port as "client".

+ +

In all cases, the server should respond with a list of capabilities.

+

SSL / STARTTLS

+

There are 2 SSL variants: normal SSL and STARTTLS.

+

Normal SSL

+

The old-style SSL (including TLS, which is just the new name for SSL) has a special port:

+ +

On Linux, you can contact the server via

+

+

openssl s_client -connect hostname:port

+

You should see output about the SSL handshake and the certificate. Important is what is listed as "CN=". This must be the same as the hostname that you contacted, otherwise the certificate is not valid (or you need to use another hostname).
+ If you see nothing, then probably the server does not support SSL.
+ After that, you can have the same protocol exchange as with netcat on standard ports, as listed above.

+

STARTTLS

+

STARTTLS is a special, new form of SSL, which works on the standard ports (e.g. port 143 for IMAP). You can contact the server via netcat as mentioned above. If you see "STARTTLS" (for IMAP, SMTP) or "STLS" (for POP) listed as one of the capabilities, the server should support STARTTLS.
+ To try it out, on Linux, you can contact the server via

+

 

+

openssl s_client -connect hostname:port -starttls proto

+

...where "proto" is imap, pop3 or smtp. For example:

+

+

openssl s_client -connect imap.example.com:143 -starttls imap

+

You should get the same response as described above for openssl.

+

Configuration file format

+

Add the appropriate port and socket type for each server, depending on protocol and SSL support. For example,
+ for IMAP with SSL:

+

 

+

<port>993<port>

+

<socketType>SSL</socketType>

+

for IMAP with STARTTLS:

+

 

+

<port>143<port>
+ <socketType>STARTTLS</socketType>

+

for IMAP without any SSL (deprecated!):

+

 

+

<port>143<port>

+

<socketType>plain</socketType>

+

Use SSL

+

Please do not submit or serve any configurations without SSL! There's no reason in 2010 why users still need to read mail entirely unprotected.
+ If you are an ISP and think the server load is too high, try adding an SSL accelerator. They are cheap and widely used. In fact, even most freemail (!) providers these days support SSL, so if users pay you money for ISP service, that's all the more reason to give them proper service. But first simply try to enable software SSL - small servers may be fine with SSL and without any additional installations.

+

Valid certificate

+

Either way, be sure to use a valid certificate:

+ +

Authentication

+

Probe the mail server, as explained above for STARTTLS. If you see CRAM-MD5 or APOP in the response, the server should support encrypted passwords. If you only see AUTH LOGIN and/or PLAIN, or no AUTH at all, the server probably does not support secure authentication. In the former case, select "Encrypted passwords" as "Authentication method" (in Thunderbird Account Settings UI, incoming server and SMTP server), and test whether you can actually log in with a real account (because some servers are unfortunately broken with regards to authentication, often due to a wrong or misconfigured SASL installation).

+

Configuration file format

+

In the configuration file, for each IMAP, POP and SMTP server, you need to specify the authentication method.
+
+ For plaintext passwords:

+

 

+

<authentication>password-cleartext</authentication>

+

For CRAM-MD5:

+

 

+

<authentication>password-encrypted</authentication>

+


+ Discouraged settings (SMTP only):
+ If the SMTP server can only be used after checking incoming mail, please use

+

 

+

<authentication>smtp-after-pop</authentication>

+

Note that RFC 4409 disallows that and requires the customer-facing SMTP server to support proper authentication via AUTH.
+ If the SMTP server can only be used within the ISP's network, and requires no authentication, use:

+

 

+

<authentication>client-IP-address</authentication>

+

or, if it requires authentication in addition to the user being in the ISP network, use e.g.:

+

 

+

<authentication>password-cleartext</authentication>

+

<restriction>client-IP-address</restriction>

+

However, that means that users on the road or in the office are unable to send mail, which is a real problem for many of our users. This violates RFC 4409 as well and is an outdated configuration. Please try find a configuration that works in all cases, for the sake of the users.

+

Please support MD5 passwords

+

Please support authentication with CRAM-MD5. It is simple to implement, and to set up, and you can still use RADIUS or a database that stores passwords in plaintext, so you don't need to make changes to your mail server or authentication infrastructure apart from installing some software and configuring it correctly. CRAM-MD5 is particularly important when no SSL is used: Never make users send their passwords in plaintext over the network! (Not even in your ISP network.) We warn users in the Mail Account Creation dialog about such insecure configurations, and we reserve the right to block them in the future.
+
+ As an ISP, you should ideally store passwords in encrypted format, which removes the risk of mass password theft (and possibly reuse on other sites) if somebody hacks your servers. You can still support plaintext passwords in this case, and encrypt passwords on the fly before comparing. (Users who use plaintext passwords would still be somewhat exposed, but at least you don't have the risk of the whole plaintext password database being stolen.) You can use both plaintext and encrypted authentication transmission with plaintext or encrypted password databases - the two issues are independent.

+

Username

+

If the user's IMAP login name is the same as his email address (for example, if "fred@example.com" is the login name), add:

+

 

+

<username>%EMAILADDRESS%</username>

+

Note: Use %EMAILADDRESS% as literal. Thunderbird will replace it with the email address that the user entered. Same for %EMAILLOCALPART% and other placeholders.

+

If the login name is the same as the first segment before the @ of the email address (for example, "fred" for "fred@example.com"), use:

+

 

+

<username>%EMAILLOCALPART%</username>

+

Aliases, or username not part of email address

+

Note that the above must be true for any email address that the user would set up - even for aliases.
+
+ You can ignore aliases like info@, if that's an alias for fred@ (or both fred@ and wilma@) and Fred would set up fred@example.com in Thunderbird, not info@.
+
+ If, however, Fred can set up hero@example.com as alias for fred@example.com, and neither "hero" nor "hero@example.com" would work as login name on your IMAP server, you need to set up a lookup of alias -> username on your autoconfig server. So, if you get a request for <http://autoconfig.example.com/mail/c...ro@example.com>, your autconfig server must have a script which responds to /mail/config-v1.1.xml and returns the concrete username, for example:

+

 

+

<username>fred</username>

+

... (or <username>fred@example.com</username>, as appropriate) for hero@example.com. This is the only way to enable automatic configuration without users having to remember what their primary login name was, which is a serious problem in practical experience. Even if you have told them all the necessary information in your welcome letter, they usually cannot find the letter. That's exactly where autoconfiguration tries to help.

+

Enable visiturl

+

Some providers do not provide IMAP or POP service by default, but require it to be enabled via a web UI. If that is the case, add the URL that a logged-in user would use into this field, and the application can prompt the user to visit it.

+

This is not yet supported by Thunderbird 3.1, but should be in the future, so please add this critical information where it applies.

+

If you are an ISP, please by all means avoid this. It's one of those "walls" against which users run the hard way.

+

Documentation URL

+

If the configuration is (partially) based on a help webpage of the ISP that describes the configuration that end users should use, you can record its URL here. You may add several of them, as several elements. It is for informational purposes only and mainly for the maintenance of the config file, the client currently does not use them at all.

+

If your URL contains ampersands (&), please remember to replace them with HTML entities (&amp;). For example:

+

 

+

<documentation url="http://example.com/help.php?client=thunderbird&amp;lang=en"/>

+

Otherwise your XML file will be incorrect and Thunderbird will neither be able to parse it, nor to return any error message.

diff --git a/files/zh-tw/mozilla/thunderbird/autoconfiguration/fileformat/index.html b/files/zh-tw/mozilla/thunderbird/autoconfiguration/fileformat/index.html new file mode 100644 index 0000000000..76a90f2777 --- /dev/null +++ b/files/zh-tw/mozilla/thunderbird/autoconfiguration/fileformat/index.html @@ -0,0 +1,10 @@ +--- +title: Autoconfig file format +slug: Mozilla/Thunderbird/Autoconfiguration/FileFormat +tags: + - NeedsTranslation + - TopicStub +translation_of: Mozilla/Thunderbird/Autoconfiguration/FileFormat +--- + diff --git a/files/zh-tw/mozilla/thunderbird/autoconfiguration/index.html b/files/zh-tw/mozilla/thunderbird/autoconfiguration/index.html new file mode 100644 index 0000000000..84cc17039c --- /dev/null +++ b/files/zh-tw/mozilla/thunderbird/autoconfiguration/index.html @@ -0,0 +1,113 @@ +--- +title: Autoconfiguration in Thunderbird +slug: Mozilla/Thunderbird/Autoconfiguration +tags: + - Administration + - NeedsTranslation + - TopicStub + - enterprise +translation_of: Mozilla/Thunderbird/Autoconfiguration +--- +

Author: Ben Bucksch
+ Please do not change this document without consulting the author

+

Thunderbird 3.1 and later (and 3.0 to some degree) includes mail account autoconfiguration functionality. The goal of autoconfiguration is to make it very easy for users to configure the connection of Thunderbird to their email servers. In many cases, people should be able to download and install Thunderbird, enter their real name, email address and password in the Account Setup Wizard and have a fully functioning mail client and get and send their mail as securely as possible.

+

See also:

+ +

This document describes how Autoconfiguration in Thunderbird works, and what to do to allow mail servers to be autoconfigured.

+

Mechanisms

+

Thunderbird gets the server settings via different means, each of which is intended for different cases:

+ +

All the lookup mechanisms use the email address domain as base for the lookup. For example, for the email address fred@example.com , the lookup is performed as (in this order):

+
    +
  1. tb-install-dir/isp/example.com.xml on the harddisk
  2. +
  3. check for autoconfig.example.com
  4. +
  5. look up of "example.com" in the ISPDB
  6. +
  7. look up "MX example.com" in DNS, and for mx1.mail.hoster.com, look up "hoster.com" in the ISPDB
  8. +
  9. try to guess (imap.example.com, smtp.example.com etc.)
  10. +
+

We may in the future add DNS SRV records as supported mechanism in the future, but we currently do not.

+

How to add support for your domain

+

Classification

+

If you are a big ISP (> 100,000 users) providing email addresses solely under a few domains like "example.com" and "example.de", you may either submit the configuration to the ISPDB or set up a configuration server.
+
+ If you support email aliases and the user's login name is not part of the email address (for example, users may have "hero@example.com" as email address, but the IMAP/POP/SMTP login name is neither "hero" nor "hero@example.com", but "u67578"), you need to set up a configuration server, which does the email address -> login name lookup.
+
+ If you host customer domains, i.e. you are "hoster.com", but your customers have "fred@flintstone.com" and "louis@kent.com" as domains, with only a few users per domain, you need to set up a configuration server (or rely on DNS MX).
+
+ If you are a small company installing Thunderbird on your employees' desktops, you can place a configuration file in the Thunderbird installation folder.

+

ISPDB

+

Database URL is <https://live.mozillamessaging.com/autoconfig/v1.1/>, append domain name, e.g. <https://live.mozillamessaging.com/autoconfig/v1.1/freenet.de>.
+
+ Current process: File a bug in Bugzilla, Product "Webtools", Component "ISPDB Database Entries", with a configuration file that matches the requirements described below. Request review from bwinton, gozer or ben.bucksch.
+
+ Future: add the configuration to the ISPDB server app.

+

Configuration server at ISP

+

Given the email address "fred@example.com", Thunderbird first checks <http://autoconfig.example.com/mail/config-v1.1.xml?emailaddress=fred@example.com> and then <http://example.com/.well-known/autoconfig/mail/config-v1.1.xml>.

+

Small company

+

If you are a small company, you can put the XML configuration file on your web server, at URL <http://example.com/.well-known/autoconfig/mail/config-v1.1.xml>. (This is not yet finalized and subject to change.)

+

Domain hoster

+

If you are an ISP that hosts domains for your customers - for example, you are hoster.com and your customer registers fancy.com or example.com, and your servers accept and serve the mail for example.com -, you should set up an autoconfig server.

+

DNS

+

For each customer domain, you add a DNS record (in addition to the existing MX, A www etc. DNS records):
+ autoconfig IN A 10.2.3.4
+ or
+ autoconfig IN CNAME autoconfig.hoster.com.
+ ... where 10.2.3.4 and autoconfig.hoster.com are IP addresses / hostnames you own.
+ This allows Thunderbird to find you as hoster.

+

To make the Version without an autoconfig DNS Entry work you have to make sure that example.com points to the Webserver you will place the config-v1.1.xml on.

+

Example: example.com A 10.2.3.4

+

Web server

+

You set up a web server bound to a physical IP address. This may be on the same machine as other web servers, but the web server must be configured to the content to any requested domain.
+
+ You must use an virtual host that match all autoconfig.* domains of your customers. In Apache terms, you can use a "ip-based virtual host". In the Apache configuration files, that means something like: Listen 10.2.3.4:80 (of course, you use a public IP address that you own)

+
<VirtualHost 10.2.3.4:80> #Must be the first and only virtual host with this ip!
+    DocumentRoot /var/www/autoconfig/
+    ServerName autoconfig.hoster.com
+    <Directory /var/www/autoconfig>
+	Order allow,deny
+	allow from all
+    </Directory>
+</VirtualHost>
+

Place the configuration file at the URL /mail/config-v1.1.xml on that host.

+

All config files must be served as Content-Type: text/xml (or application/xml), otherwise the file will be ignored. Also, they must use charset UTF-8 (esp. if there are any non-ASCII-characters).

+

If you like to use name-based virtual hosts. You probably don't want to setup the autoconfig subdomain for every domain of your customers.
+ You can add a Rewriterule in the default virtual host (on debian /etc/apache2/sites-enabled/000-default)  to match all autoconfig.* subdomains:

+
<VirtualHost *:80> #Must be the first Virtual host
+	ServerAdmin webmaster@hoster.com
+	ServerName www
+	DocumentRoot /var/www
+	RewriteEngine On
+	RewriteCond %{HTTP_HOST} ^autoconfig\. [NC]
+	RewriteRule ^/(.*)	http://autoconfig.hoster.com/$1 [L,R=301,NE]
+        #...
+</VirtualHost>
+<VirtualHost *:80>
+    DocumentRoot /var/www/autoconfig/
+    ServerName autoconfig.hoster.com
+    <Directory /var/www/autoconfig>
+ 	Order allow,deny
+	allow from all
+    </Directory>
+</VirtualHost>
+
+

 

+

 

+

Configuration file

+

This is described at How to create a configuration file and defined on the sub-pages.

+

{{ languages( { "ja": "ja/Thunderbird/Autoconfiguration" } ) }}

diff --git a/files/zh-tw/mozilla/thunderbird/deploying_thunderbird_in_the_enterprise/index.html b/files/zh-tw/mozilla/thunderbird/deploying_thunderbird_in_the_enterprise/index.html new file mode 100644 index 0000000000..0873a7d1f2 --- /dev/null +++ b/files/zh-tw/mozilla/thunderbird/deploying_thunderbird_in_the_enterprise/index.html @@ -0,0 +1,26 @@ +--- +title: Deploying Thunderbird in the Enterprise +slug: Mozilla/Thunderbird/Deploying_Thunderbird_in_the_Enterprise +tags: + - Corporate + - Corporation + - NeedsTranslation + - Thunderbird 3 + - TopicStub + - enterprise + - thunderbird +translation_of: Mozilla/Thunderbird/Deploying_Thunderbird_in_the_Enterprise +--- +

These documents and references are provided to help those involved in deploying Thunderbird in large institutions. 

+

The documents are maintained primarily by volunteers and are a work in progress.  In other words, there are improvements and additions still be made, and you can help make those changes.  If you have skills, experience or information that will make these items better in small ways or large, please edit the documents directly, after creating an MDN account or registering with mozilla wiki if you don't already have an account.  You may also comment on the Talk page to note items that may be missing or inaccurate.

+

References

+ +

Related information

+ +

{{ languages( { "ja": "ja/Thunderbird/Deploying_Thunderbird_in_the_Enterprise" } ) }}

diff --git a/files/zh-tw/mozilla/thunderbird/deploying_thunderbird_in_the_enterprise/upgrading_thunderbird_in_the_enterprise/index.html b/files/zh-tw/mozilla/thunderbird/deploying_thunderbird_in_the_enterprise/upgrading_thunderbird_in_the_enterprise/index.html new file mode 100644 index 0000000000..b067ae50fd --- /dev/null +++ b/files/zh-tw/mozilla/thunderbird/deploying_thunderbird_in_the_enterprise/upgrading_thunderbird_in_the_enterprise/index.html @@ -0,0 +1,260 @@ +--- +title: 於企業內升級 Thunderbird +slug: >- + Mozilla/Thunderbird/Deploying_Thunderbird_in_the_Enterprise/Upgrading_Thunderbird_in_the_Enterprise +translation_of: >- + Mozilla/Thunderbird/Deploying_Thunderbird_in_the_Enterprise/Upgrading_Thunderbird_in_the_Enterprise +--- +
{{ draft }}
+ +

這是一篇關於幫助大型組織使用 Thunderbird 升級到 3 版的升級手冊 (也可稱之為 "企業")。 這份初步草稿是從草稿作者知識庫摘要 auto-sync / offline settings (bug 562589) 與 Thunderbird 3 與管理者相關的搬遷問題 (bug 562589#c7) (如同 2010/05/06).

+ +

背景

+ +

此份搬遷手冊針對典型的企業環境做出一些假設:

+ + + +

(The above requirements may not be compatible with the fact that the new global search (Gloda) is enabled by default on upgrade and IMAP folder automatic synchronization is enabled by default on upgrade. This is discussed further below.)

+ +

企業環境通常需要執行大規模軟件升級,而不是為個人用戶升級軟件,此升級目標也許會是:

+ + + +

相關資訊:

+ + + +

遷移指南 (Thunderbird 2 升級到 Thunderbird 3.0)

+ +

The major changes in Thunderbird 3.0 that are relevant to enterprise administrators include:

+ + + +

For more detailed information about the changes between Thunderbird 2 and Thunderbird 3, see:

+ + + +

As a general rule, administrators should deal with the process of upgrading Thunderbird and enabling new features separately. That is, they should try to keep the user setup as similar as possible between Thunderbird 2 and 3 and wait until the Thunderbird 3 upgrade is complete and stable before enabling Thunderbird 3 features.

+ +

在遷移前,停用附加元件以進行安全升級

+ +

Problems due to add-on are known. For example;

+ + + +

To avoid such unwanted problems due to add-ons, next upgrade procedure is recommended for safe migration.

+ +
    +
  1. Start Tb 2 with -safe-mode to make all add-ons disabled before upgrade.
  2. +
  3. Keep backup of profile directory before upgrade.
  4. +
  5. If possible, do uninstall of Thunderbird 2 and clean install of Thunderbird 3, instead of upgrade by software update by Thunderbird 2, for both safe migration and reducing of network traffic.
  6. +
+ +

停用遷移幫手

+ +

Enterprise sites that perform mass upgrades generally want to prevent users from performing Thunderbird upgrades on their own. An upgrade dialogue in the Thunderbird Migration Assistant should be disabled.

+ +
lockPref("mail.ui.show.migration.on.upgrade",false);
+ +

停用全域 (全域搜索與索引) 以避免遷移後的索引

+ +

Initail purpose of Gloda was solution of of problem like Bug 383895 (slowness in body text search of local mail data). With enhancements and many improvements by Thuderbird 3 on auto-sync of IMAP folder, Gloda can be used also for IMAP folders very easily. So, gloda is very useful for everyday usage even for IMAP users: It can search messages very fast, much faster than an IMAP server can, and so notably increase productivity. Also, it will in the future have increased functionality in other areas.

+ +

However, the new Thunderbird 3 search and index functionality initially impacts performance. (The indexer runs when Thunderbird 3 is first started and will continue to work until all the user's email is indexed. The more messages a user has, the longer the indexer will run.) Also, it uses diskspace on the client (about 1/2 (?) of mailbox size), which is a problem for roaming profiles.

+ +

Gloda can be enabled by only single action after upgrade - check an option at Tools/Options/Advanced/General tab. So, to minimize user support workload after migration, we  recommend you to disable automatic enabling of Gloda durng migration by Thunderbird 3.

+ +
怎麼會? 可能嗎? 需要加強?
+ +

停用自動同步,保持每個資料夾 "離線使用" 設定,以避免遷移後每個巨大的 IMAP 資料夾下載所有郵件

+ +

Auto-sync of IMAP folders is enabled by default for all IMAP accounts. The per folder "offline use" setting of all IMAP folders is changed to "offline use=On" when Thunderbird 3 is launched the first time. To keep same settings as Thunderbird 2, disable the auto-sync and offline-use settings upon upgrade.

+ +

完全停用自動同步 (auto-sync):

+ +
lockPref("mail.server.default.autosync_offline_stores", false);
+lockPref("mail.server." + serverFromAccount + ".autosync_offline_stores", false);
+
+ +

停用每個資料夾 "離線使用 (offline use)" 設定在遷移時設定變更 (Tb 3.0.5 到 Tb 3.1rc1):

+ +
lockPref("mail.server." + serverFromAccount + ".offline_download", false);
+
+ +

To disable per folder "offline use" setting change upon migration (Tb 3.1rc2 or later):

+ +
lockPref("mailnews.ui.show.migration.on.upgrade",false);
+
+ +

注意:

+ + + +

在遷移後,如何啟用自動同步

+ +

Account Settings/Synchronization & Disk Space

+ + + +

Current behavior of UI for auto-sync setting.

+ + + +

Note: There is a request for a design change in bug 537943.

+ +

Gloda and auto-sync/offline-use are possibly independent, although relevant.

+ + + +

修改資料夾面板檢視從 "聰明資料夾 " 為 "所有資料夾"

+ +

By default, Thunderbird 3 displays "Smart Folders" in the folder pane. (Smart Folders combine the messages in similarly named folders in multiple accounts, for example grouping Inbox messages from all accounts into a single Inbox on the Smart Folder pane.) If you want to preserve the default Thunderbird 2 behavior of showing "All Folders", advice users to select View | Folders | All from the menu.

+ +

Can "forcing Smart Folders view" upon migration be stopped? How? Is it possible? Enhancement is needed?

+ +

Note: "Smart Folders" is renamed to "Unified Folders" by Tb 3.1, and Tb 3.1 won't force it upon migration from Tb2 any more.

+ +

注意事項

+ +

由自動配置 (autoconfig) 帳戶定義

+ +

When new accounts are created, the new "autoconfig" functionality is automatically invoked. Unless users have the correct account definition parameters, it may be confusing for them to configure their own accounts (if this is permitted).

+ +

IMAP 資料夾檔案的位置

+ +

By default, the IMAP folder file is located in each user's profile directory. If the user is storing a lot of messages for off-line access, this can result in too much data for a roaming profile. Regardless of whether or not there is a roaming profile, there may be if the profile is located on a network resource or if Microsoft Window's Offline File (CSC) is used for the offline storage file.

+ +

If that is the case, you have two options:

+ +

If the Gloda search and index is mandatory for IMAP mail data:

+ +
    +
  1. Locate mail directory for IMAP account at location with which remote/network access won't happen(e.g. "Local Settings" of MS Win)
  2. +
  3. Enable auto-sync, and set offline use=on of IMAP folders.
  4. +
  5. Accept download of all mails to any PC which uses the IMAP account.
  6. +
  7. Accept per PC thread pane column setting of the IMAP accout. +
      +
    • +
      +
       
      +
      + +
      +
      As thread pane column setting is currently saved in .msf file, and as you selected folder location other than profile directory, data in .msf can not be shared among PCs, even when you use Roaming Profile.
      +
      +
    • +
    +
  8. +
+ +

When Gloda is not needed for IMAP mail data:

+ +
    +
  1. Locate IMAP folder file at any place you want.
  2. +
  3. Disable auto-sync, and/or set offline use=off of all IMAP folders. +
      +
    • +
      +
       
      +
      + +
      +
      As new feature of "Disk Cache for mail in IMAP folder of offline-use=off" is added to Tb 3, mail data of viewed mail is held in far larger Disk Cache than very small memory cache of Thunderbird 2. So, frequency of problem like "repeatedly downloaded big attachment data" is reduced very much compared to Thunderbird 2.
      +
      +
    • +
    +
  4. +
+ +

As Gloda is first solution of problem of Bug 383895 (slowness in body text search of local mail data), and as many IMAP servers have excellent body text search functionality, consider utilizing of online search first for IMAP mail data. If online search is usable, enabling of auto-sync/offline-use merely for Gloda can be avoided.

+ +

線上搜尋 IMAP 資料夾

+ +

There is known with regards to online search (documented in Bug 546925 "Run search on server" of Edit/Find/Search Messages doesn't work). For now, users must use Quick Search or Virtual Folder (Saved Search folder) for online searches.

+ +

搜尋、自動同步、離線使用與 "聰明資料夾"

+ +

If IMAP folder of offline-use=off, full text search by Gloda won't work because of offline-use=off.

+ +

And, if not all mails of IMAP folder of offline-use=on is downloaded into local offline-store file because of your setting for offline-store file size limitation, Gloda can't find not-downloaded mails of the IMAP folder.

+ +

And, as "Smart Folder" is internally Virtual Folder(Saved Search Folder), a "Smart Folder" can be Virtual Folder with multiple search target folders in mixture of local mail folders, IMAP folders of offline-use=on(all mails are sync'ed), IMAP folders of offline-use=on(not all mails are sync'ed), and IMAP folders of offline-use=off.

+ +

Never open bug at bugzilla.mozilla.org for "Search can't find my mail!" without sufficient checking of "what mail at what kind of folder is not hit by what kind of search at where", please.

+ +

遷移手冊 (Thunderbird 2 到 Thunderbird 3.1)

+ +

(content needed)

+ +

遷移手冊 (Thunderbird 3.0 到 Thunderbird 3.1)

+ +

(content needed)

diff --git a/files/zh-tw/mozilla/thunderbird/index.html b/files/zh-tw/mozilla/thunderbird/index.html new file mode 100644 index 0000000000..f0a48a2be0 --- /dev/null +++ b/files/zh-tw/mozilla/thunderbird/index.html @@ -0,0 +1,79 @@ +--- +title: Thunderbird +slug: Mozilla/Thunderbird +tags: + - NeedsTranslation + - TopicStub + - thunderbird +translation_of: Mozilla/Thunderbird +--- +

Thunderbird is Mozilla's mail/messaging application. These pages document Thunderbird and also provide links to documentation about the MailNews backend which is also used in other projects such as Eudora/Penelope, Seamonkey, Correo, etc.

+

Thunderbird is Firefox's kid sibling, and is built on the same technical platform as the web browser. In development for many years, and currently one of the most popular open source email clients, it is used by millions of people around the world to bring together all their email accounts, newsgroup and feed reading in a familiar high-productivity environment.  (From early 2007 to early 2011 Thunderbird was developed by Mozilla Messaging, a subsidiary that was owned by Mozilla.)

+ + + + + + + +
+

Documentation

+
+
+ Building Thunderbird
+
+ Information about building Thunderbird with the comm-central repository. There's also information about how comm-central works, how the review process works and how to use the Mozilla symbol server to help with debugging.
+
+ MailNews Protocols
+
+ Rough documentation about mail protocols..
+
+ Database views
+
+ Backend information about {{ Interface("nsIMsgDBView") }} and related interfaces..
+
+ Thunderbird API documentation
+
+ Thunderbird API documentation
+
+ Extension documentation
+
+ Tutorials and tips for building Thunderbird extensions
+
+ Automated Testing
+
+ Details of Thunderbird's automated testing facilities
+
+ Thunderbird in the Enterprise
+
+ Help with deploying Thunderbird in large organizations
+
+

View All...

+
+

Community

+ +

Tools

+ + + +
+

 

diff --git a/files/zh-tw/mozilla/thunderbird/thunderbird_extensions/index.html b/files/zh-tw/mozilla/thunderbird/thunderbird_extensions/index.html new file mode 100644 index 0000000000..4ce42f41a7 --- /dev/null +++ b/files/zh-tw/mozilla/thunderbird/thunderbird_extensions/index.html @@ -0,0 +1,135 @@ +--- +title: Thunderbird extensions +slug: Mozilla/Thunderbird/Thunderbird_extensions +tags: + - Add-ons + - Extensions + - NeedsTranslation + - TopicStub + - thunderbird +translation_of: Mozilla/Thunderbird/Thunderbird_extensions +--- +
Building a Thunderbird extension
+Step-by-step explanation on how to build an extension for Thunderbird.
+ +
+

{{AddonSidebar}}

+The following documentation provides help for creating extensions for Mozilla's Thunderbird email client. Although there are many similarities with Firefox extensions there are also some differences that may confound the starting developer.
+ +

+Please help! You can add a how-to (a question or an answer or a code snippet), summarize and link to a relevant newsgroup discussion, or create a tutorial. Need help? Contact jenzed.
+ + + + + + + + +
+

Documentation

+ +

Getting started with Thunderbird

+ +

A brave, young developer wants to develop an add-on for Thunderbird. Here's a few links to help them through this journey.

+ +
    +
  • Start by reading the tutorial and learn how to build a Thunderbird extension (Outdated, still talks about overlays and the add-on builder is no longer available but the tutorial has not been updated.)
  • +
  • Read about the main windows so that you know what one means when they say « thread pane », « preview pane », and « folder pane ».
  • + +
  • Want to do some real stuff? See how to inspect a message (demo add-on included!)
  • +
  • Play with our other demo add-on that exercises some more advanced Thunderbird-specific features
  • +
  • Want to do even more stuff? Don't reinvent the wheel: steal functions from the thunderbird-stdlib project (doc here). Functions for dealing with messages (delete them, archive them, change their tags, etc.) are included.
  • +
  • Haven't found what you're looking for? Read the Thunderbird how-tos; they contain a lot of recipes for things extensions want to do.
  • +
  • Still haven't managed to do what you wanted? See the list of all Thunderbird communication channels so that you know where to ask when you get stuck :-).
  • +
  • Feeling really brave? Read the source using a fancy interface; you can often find tests that demonstrate how to do what you're trying to achieve.
  • +
+ +

The Gloda database

+ +

Thunderbird has a subsystem called Gloda. Gloda stands for « Global Database », and creates Thunderbird-wide relations between objects. Gloda provides concepts such as Conversations, Messages, Identities, Contacts. All these concepts are related together: a Conversation contains Messages which are linked to Identities (from field, to field) which are themselves part of a Contact: indeed, a contact has multiple identities.

+ +

Typical use cases for Gloda: find all messages whose subject matches [search term], find all messages from [person], find all messages in the same thread as [a given message], find all messages involving [person], etc. etc.

+ +

Gloda is extremely powerful and is used heavily by add-ons such as Thunderbird Conversations. Learn more about Gloda:

+ + + + + +

Some of these links may be wildly out of date, but they still provide valuable information on the codebase.

+ + + + + + +
+

Community

+ + + +

{{ DiscussionList("dev-extensions", "mozilla.dev.extensions") }}

+ + + +

Tools

+ + + +

... more tools ...

+ +

View All...

+ + + +
+
XUL, JavaScript, XPCOM, Themes, Developing Mozilla
+
+
+ +

Categories

+ +

{{ languages( { "ja": "ja/Extensions/Thunderbird" } ) }}

diff --git a/files/zh-tw/mozilla/thunderbird/thunderbird_extensions/theme_packaging/index.html b/files/zh-tw/mozilla/thunderbird/thunderbird_extensions/theme_packaging/index.html new file mode 100644 index 0000000000..9aeb61d94f --- /dev/null +++ b/files/zh-tw/mozilla/thunderbird/thunderbird_extensions/theme_packaging/index.html @@ -0,0 +1,105 @@ +--- +title: 包裝佈景主題 +slug: Mozilla/Thunderbird/Thunderbird_extensions/Theme_Packaging +tags: + - Toolkit API + - 佈景主題 +translation_of: Mozilla/Thunderbird/Thunderbird_extensions/Theme_Packaging +--- +

本文描述包裝 Firefox 及 Thunderbird 之佈景主題的方法。

+

需求

+

製作 Firefox 或 Thunderbird 的佈景主題需要懂層疊樣式表(CSS)、會一點 XBL、還要有美術繪圖設計等能力(不過也不見得一定要)。本文只說明包裝佈景主題以便顯示於 Firefox 佈景主題視窗的方法。

+

佈景主題檔案架構

+

Firefox 及 Thunderbird 的佈景主題是一個將資料以下列結構包裝的 JAR 檔案:

+
theme.jar:
+  install.rdf
+  contents.rdf
+  preview.png
+  icon.png
+  browser/一堆檔案
+  global/一堆檔案
+  mozapps/一堆檔案
+  communicator/一堆檔案
+  ...
+
+
+ +

install.rdf

+

install.rdf 清單長得像這樣:

+
<?xml version="1.0"?>
+
+ <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+   <Description about="urn:mozilla:install-manifest">
+     <em:type>4</em:type>
+     ''其他特性''
+   </Description>
+ </RDF>
+
+

必備特性

+

install.rdf 檔中必須含有下列特性:

+ +

詳細資訊請見 install.rdf 參考

+

選用特性

+ +

如果你想將佈景主題送上 addons.mozilla.org,則 updateURL 就是必備的特性。

+

範例

+
<?xml version="1.0"?>
+
+ <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+   <Description about="urn:mozilla:install-manifest">
+     <em:id>{18b64b56-d42f-428d-a88c-baa413bc413f}</em:id>
+     <em:version>1.0</em:version>
+     <em:type>4</em:type>
+
+     <!-- 擴充套件的適用軟體,含最低需求及上限版本資訊。 -->
+     <em:targetApplication>
+       <Description>
+         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+         <em:minVersion>0.8</em:minVersion>
+         <em:maxVersion>0.9</em:maxVersion>
+       </Description>
+     </em:targetApplication>
+
+     <!-- 使用者會看到的資訊 -->
+     <em:name>New Theme 1</em:name>
+     <em:description>A test theme for Firefox</em:description>
+     <em:creator>Ben Goodger</em:creator>
+     <em:contributor>John Doe</em:contributor>
+     <em:homepageURL>http://www.bengoodger.com/</em:homepageURL>
+
+     <!-- 佈景主題管理員內部所用的識別名稱 -->
+     <em:internalName>newtheme1</em:internalName>
+   </Description>
+ </RDF>
+
+

以下是幾個 targetApplication 特性常用的應用程式 GUID:

+
Firefox      {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+Thunderbird  {3550f703-e582-4d05-9a08-453d09bdfdc6}
+Sunbird      {718e30fb-e89b-41dd-9da7-e25a45638b28}
+
+

Toolkit API 官方參考文件

+
+ {{page("/zh-TW/docs/Toolkit_API/Official_References")}}
+
+  
diff --git a/files/zh-tw/prism/index.html b/files/zh-tw/prism/index.html new file mode 100644 index 0000000000..30d3f7d7db --- /dev/null +++ b/files/zh-tw/prism/index.html @@ -0,0 +1,89 @@ +--- +title: Prism +slug: Prism +tags: + - prism +translation_of: Archive/Mozilla/Prism +--- +

Prism 是以 XULRunner 為基礎的極簡化瀏覽器,可以讓網際應用程式不必透過一般瀏覽器介面就能直接執行。Prism 的主要概念是「特定網站專用瀏覽器」,就好比為某個網際應用程式量身訂做的瀏覽器一樣,無需選單、工具列及其他傳統瀏覽器的元件。這類專屬瀏覽器能為其網際應用程式提供與作業系統更緊密的整合,所以能同時擁有一般單機程式與網際應用程式雙方面的好處。

+

好處

+ +

架構概觀

+

Prism 是個 XULRunner 軟體,其中除了 XULRunner 內建的瀏覽器引擎外還包括:

+ + + + + + + + +
+

文件

+
+
+ 常見問題集
+
+  
+
+ 軟體包
+
+ 將網際應用程式的設定、圖示及其他專屬自訂檔「包」在 ZIP 壓縮檔內方便使用。
+
+ 設定
+
+ A webapp bundle should contain a webapp.ini configuration file. The configuration file is a simple, INI-style text file that specifies some parameters about a web application.
+
+ 樣式
+
+ One of Prism's goals is to make web applications feel more like desktop applications. One way to make the illusion seem more real is to use styling (or theming). Prism supports a simple styling system that allows the user to add CSS files to the webapp bundle.
+
+ 主視窗
+
+ Prism provides a simple, scaled down browser window for running web applications. Using configuration files and webapp scripting, the host window can be modified.
+
+ 安裝程式
+
+ 安裝 Prism。
+
+

全部列出…

+
+

社群

+ +

其他東西

+ +

一起搞吧!

+ +

相關主題

+
+
+ XULRunner
+
+
+

 

+

 

+
+  
+

{{ languages( { "en": "en/Prism", "fr": "fr/Prism" } ) }}

diff --git "a/files/zh-tw/prism/\344\270\273\350\246\226\347\252\227/index.html" "b/files/zh-tw/prism/\344\270\273\350\246\226\347\252\227/index.html" new file mode 100644 index 0000000000..d8e06c3a60 --- /dev/null +++ "b/files/zh-tw/prism/\344\270\273\350\246\226\347\252\227/index.html" @@ -0,0 +1,21 @@ +--- +title: 主視窗 +slug: Prism/主視窗 +tags: + - prism +translation_of: Archive/Mozilla/Prism/HostWindow +--- +

Prism 執行網際應用程式時,是以非常簡單的視窗呈現。視窗上仍有一些介面組件(如圖所示),而Prism 可以設定某些介面組件的顯示與否。

+

Image:webrunner-ui.gif

+ +

註:

+ +

{{ languages( { "en": "en/Prism/HostWindow" } ) }}

diff --git "a/files/zh-tw/prism/\345\256\211\350\243\235\347\250\213\345\274\217/index.html" "b/files/zh-tw/prism/\345\256\211\350\243\235\347\250\213\345\274\217/index.html" new file mode 100644 index 0000000000..d3ab5e831a --- /dev/null +++ "b/files/zh-tw/prism/\345\256\211\350\243\235\347\250\213\345\274\217/index.html" @@ -0,0 +1,11 @@ +--- +title: 安裝程式 +slug: Prism/安裝程式 +tags: + - prism +translation_of: Archive/Mozilla/Prism/Installer +--- +

安裝程式需將 *.webapp 檔的關聯程式設定為 Prism,這麼一來雙點 *.webapp 檔時才會自動用 Prism 開啟網際應用程式。 +

目前 Windows 跟 Mac 的安裝程式都可以自動設定關聯。 +

這麼一來還有另一個好處:當點選網頁上的 .webapp 檔時也能自動以 Prism 開啟!不過在 Firefox 中這招只在伺服器將 .webapp 檔做為 application/x-webrunner 送出時才有用,而 IE 倒不會檢查這點。(參考這個例子) +

{{ languages( { "en": "en/Prism/Installer" } ) }} diff --git a/files/zh-tw/profile_manager/index.html b/files/zh-tw/profile_manager/index.html new file mode 100644 index 0000000000..a1f40c3a8d --- /dev/null +++ b/files/zh-tw/profile_manager/index.html @@ -0,0 +1,110 @@ +--- +title: Profile Manager +slug: Profile_Manager +translation_of: Mozilla/Profile_Manager +--- +

Firefox and other XULRunner applications store user settings and data in special folders, called profiles.    Firefox provides a built-in applet to manage these profiles, but it will eventually be going away (see bug 214675), so a new standalone Profile Manager application has been created, which works with any XULRunner application, and has many features not found in Firefox's built-in version.

+

Downloading

+

Binaries

+

You can download Profile Manager builds from ftp://ftp.mozilla.org/pub/mozilla.org/utilities/profilemanager/1.0/.  There is no installer; just extract the files from the archive. 

+

System requirements:

+ +

Source code

+

You can download the source as well:

+

hg clone http://hg.mozilla.org/automation/profilemanager/

+

Instructions for building can be found in BUILD.txt.

+

Reporting Bugs

+

Profile Manager bugs should be reported in Bugzilla, under Testing -> ProfileManager.

+

Starting Profile Manager

+

To start Profile Manager, just launch profilemanager.exe (on Windows) or profilemanager-bin (on Linux and Mac).  By default, Profile Manager will manage Firefox profiles, but you can also use it to work with profiles of other xulrunner apps, like Thunderbird or SeaMonkey.  To use Profile Manager with an application other than Firefox, you need to launch it using the application's name as an argument, for example:

+

+

profilemanager-bin seamonkey

+

Profiles and application versions

+

Profile Manager manages two different lists: one of user profiles, and the other of application versions that can be used with the profiles.  By default, this means it tracks a list of Firefox applications that are installed on your system, and a list of profiles for use by Firefox.

+

+

An individual profile can be linked to a specific installation of Firefox, so that version of Firefox will be launched when that profile is selected.  For example, ProfileA might be linked with a copy of Firefox 3.6.10, while ProfileB might be linked with a copy of Firefox 3.5.3.

+

When launched, Profile Manager will look in some default locations for installed versions of Firefox (or other application you're using Profile Manager with).  Additionally, you can manually add Firefox versions by clicking the "Manage Firefox versions..." button:

+

 

+

Each Firefox version in the list has the following properties:  path, version, and default.  The default property indicates that this version of Firefox will be used with profiles that don't have a specific application version associated with them.

+

 

+

Creating a profile

+

To create a new profile, just click the New button from Profile Manager's toolbar.  A dialog will appear that allows you to specify the profile's name, and optionally the profile's path, and the version of Firefox (or other application) that will be used with this profile:

+

+

+

 

+

Launching Firefox with a profile

+

To launch Firefox with a specific profile, select the profile in the main window, and hit the "Start Firefox" button:  Firefox will be launched with that profile, and Profile Manager will terminate.  The version of Firefox which will be launched is indicated in the "Firefox version" dropdown in the Launch Options box:

+

+

+

There are several additional launch options available for Firefox.  These cause Firefox to be launched with various command-line arguments.  See Command Line Options for a description of these.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Launch OptionCommand Line Argument
Run Firefox in offline mode-offline
Run Firefox in safe mode-safe-mode
Start Firefox with a console-console
Start new instance-no-remote
+

Note: It isn't possible to start a second instance of Firefox without passing it the -no-remote command line argument.  For this reason, if you attempt to launch Firefox using Profile Manager, and it detects that another instance of Firefox is already running, it will automatically add the -no-remote argument for you, regardless of whether this launch option was checked.

+

 

+

Locked profiles

+

Some profiles may be shown as locked in the main window.   Such profiles are currently being used by an instance of Firefox.  If you attempt to perform any operation on a locked profile, you'll get a warning; if you choose to continue despite the warning, you may encounter errors or corrupt a profile.

+

+

It's strongly recommended to avoid operations on locked profiles.  If you need to do something with a locked profile, close the instance of Firefox which is using the profile first.

+

 

+

Backing up and restoring profiles

+

Profile Manager offers two different mechanisms for backing up and restoring profiles.

+

+

Backup folder

+

Profile Manager has a local backup folder where it can manage profile backups.  This is the easiest way to backup and restore profiles. 

+

To backup a profile:  select the profile you want to backup, and choose "backup to->backup folder" from the toolbar's Backup menu.  The profile will be backed up, and the backup will appear under the backups column in the main display:

+

+

To restore a profile:  select the backup in the main display, open the context menu, and choose "restore".  When you restore a profile, the backup is retained, so you can restore from the same backup at a later date.

+

To delete a backup:  select the backup in the main display, open the context menu, and choose "delete".

+

Profile archives

+

Profile Manager can also backup to and restore from .zip archives.  Profile Manager does not track these backups in the UI, but using profile archives is an easy way to move profiles between machines.

+

To backup a profile to an archive:  select the profile you want to backup, and choose "backup to->archive" from the toolbar's backup menu.  You'll be prompted for a name and location for the archive.

+

To create a profile from a profile archive:  Select "restore from->archive" from the toolbar's backup menu.  You'll be prompted for the location of the archive, and then for the name of the profile you'd like to create from the archive.

+

 

+

Other Operations

+

Context-clicking any profile in the profile list will cause a popup menu to appear with the following commands:

+ +

 

+

Future Enhancements

+ +

 

+

{{ languages( {"es" : "es/Administrador_de_perfiles" ,"zh-cn" : "zh-cn/Profile_Manager" } ) }}

diff --git a/files/zh-tw/python/index.html b/files/zh-tw/python/index.html new file mode 100644 index 0000000000..62aae7de17 --- /dev/null +++ b/files/zh-tw/python/index.html @@ -0,0 +1,65 @@ +--- +title: Python +slug: Python +tags: + - Python +translation_of: Learn/Server-side/Django +--- +

Python 是一種直譯式的腳本語言,是一個跨平台的的語言,可以在各個平台上面使用,如:Linux、Mac OS X、以及Microsoft Windows.

+

學習 Python

+

免費的電子書

+

如果是初學 Python,可以考慮看 Dive Into Python,雖然他最後是更新的時間是2004年,但依然是一部免費而且很棒的教程。它含括了幾乎所有 Python 的基本元素,還有一些平常使用 Python 可以執行什麼任務,像是網頁的請求,檔案的處理。如果對於 Python 基礎已經基礎的概念,就可以參考 Text Processing In Python ,這本書將會對於 Python 有更進階的介紹。

+

其他相關的免費電子書或是線上資源 :

+ +

當了解基礎的 Python,Code Like a Pythonista: Idiomatic Python 將幫助你了解一些 Python 特別的地方,還有跟別的語言的差異。

+

Free Online Courses

+ +

Python in Mozilla-based applications

+

XPCOM in Mozilla is used to support inter-language communication. Out-of-box it only supports C++ <-> JavaScript communication. The Python XPCOM package (also called PyXPCOM) is the low-level glue that ties Python and Mozilla together, letting XPCOM components written in JavaScript or C++ to be used from Python and vice versa. PyXPCOM is not included in the default Firefox build, so you'll need to use a third-party build or build yourself to use it. The most known consumer of PyXPCOM is the Komodo family of products.

+

Starting with Mozilla 1.9, Python DOM (PyDOM) bindings are implemented. This lets chrome XUL and HTML authors use Python in their <script> tags (again, not in the official Firefox/Thunderbird builds).

+

Python-based tools for Mozilla development

+

Python is used by Mozillians for tools that do various things with Mozilla apps and infrastructure. It would be useful to have a document on Python Environment and Tools for Mozilla.

+

Tools are listed here: http://k0s.org/toolbox/?language=python

+

Use of Python at Mozilla

+

Mozilla has considerable infrastructure based on python:

+ +

Python packaging

+

Python uses setup.py files to record metadata and installation instructions for python packages. Running (e.g.) python setup.py install will install the package, making its modules available on python's import path. For python 2.x, several distribution/installation modules exist. distutils is the only distribution package available in python's standard library. distutils has ability to upload to the python package index and to install python packages. See the Python documentation on distutils for details.

+

While distutils is built in to python's standard library, setuptools is a third-party ad hoc standard for packaging and distribution. It is mostly compatible with distutils, but importantly adds the ability for packages to include dependencies that are installed as prerequisites at the time setup.py is invoked as well as the ability to install python packages in development mode. This allows the files to be edited in place via .pth files which is handy if you are actively working on a project. setuptools also provides an easy_install script for installing packages and their dependencies through the web from PyPI. For instance, in order to install the PyYAML package, just run

+
easy_install PyYAML
+
+

Since setuptools is not included with python, you will need to install it in order to use it. You may install it from the setuptools PyPI page by downloading, extracting, and running python setup.py install. Or you can use the ez_setup.py script. You can download and run it with python (with root/Administrator privileges), or if you're in a bash shell, you can run

+
sudo python <(curl http://peak.telecommunity.com/dist/ez_setup.py)
+
+

setuptools is also provided with instances of virtualenv, so if you use virtualenvs for developing you may not need to install setuptools globally. distribute is a fork of setuptools written by Mozilla's own Tarek Ziade. It is compatible with setuptools and fixes a few bugs there.

+
+ Note: It's highly recommended that you use virtualenv for development!
+

The Python Package Index (PyPI) is the standard distribution point for python packages. If you need some functionality in python, it is a good place to look!

+

See also: http://k0s.org/portfolio/packaging.html

+

See also

+ diff --git a/files/zh-tw/sandbox/index.html b/files/zh-tw/sandbox/index.html new file mode 100644 index 0000000000..ce4d515992 --- /dev/null +++ b/files/zh-tw/sandbox/index.html @@ -0,0 +1,180 @@ +--- +title: Sandbox 沙盒 +slug: Sandbox +translation_of: Sandbox +--- +

This is a page 這是一張紙

+ + + +

Test

+ +

如何插入程式碼區塊,並即時預覽:Toolbar 第三行,點擊「插入程式碼範例模板」按鈕

+ +

HTML

+ +
<p>hello sandbox</p>
+ +

CSS

+ +
p {
+  color: blue;
+}
+ +

JavaScript

+ +
var p = document.querySelector('p');
+p.addEventListener('mouseover', function(e) {
+  p.style.color = 'green';
+})
+p.addEventListener('mouseout', function(e) {
+  p.style.color = 'blue';
+})
+
+
+ +

結果

+ +

{{EmbedLiveSample('Test')}}

+ + + +

其他

+ +

CSS Content

+ +
@ Compteur de style fisheye {
+  système: cyclique;
+  symboles: ◉;
+
+ +
<h1>CSS font-family</h1>
+<p class="serif">This is a paragraph, shown in the Times New Roman font.</p>
+<p class="sansserif">This is a paragraph, shown in the Arial font.</p>
+ +

+}
+
+.liste {
+    list-style: fisheye, cercle;
+}
+ +

Hello World

+ +

HTML

+ +
<p>Hello World</p>
+ +

{{EmbedLiveSample ( 'Linux is life')}}

+ +

Linux logo

+ +

logo couleur MDN (bleu)

+ +

Des trucs

+ +
+

Une note 

+ +
+

Un avertissement dans une note

+ +
+

Une note dans un avertissement dans une note

+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+

une autre note

+ +
+

Une note dans une note

+
+ +

This is an example of how to use the MDN!

+
+ +

π×1=1×π=2π÷π=π\ Pi \ times 1 = 1 \ times \ pi = 2 \ pi \ div \ pi = \ pi

+ +

ππππππ\ Pi \ frac {\ pi} {\ pi} \ frac {\ frac {\ pi} {\ pi}} {\ pi}

+ +

ππππππ\ Pi \ frac {\ pi} {\ pi} \ frac {\ frac {\ pi} {\ pi}} {\ pi}

+ +

limjets13e3/XX2X\ Int \ limits_ {1} ^ {3} \ frac {e ^ 3 / x} {x ^ 2} \, dx

+ +

ln(x) dx = x[ln(x) - 1]l\ Int \ limits_ {1} ^ {3} \ frac {e ^ 3 / x} {x ^ 2} \, d+x

+ +

abcdefghijklmnopqrstuvwxyz\alphabet

+ +

πest un nombre irrationnel, et cela est le rapport entre la circonférence d'un cercle à son diamètre. Il est communément approchée comme 3,14159.\ pifacts {3}

+ +

contenu

+ +

Test live sample

+ +

HTML Content

+ +
<p>Hello World</p>
+ +

Result

+ +

{{ EmbedLiveSample('Test live sample') }}

+ +

+ +

Focus on a text field

+ +

HTML Content

+ +
<input type="text" id="myTextField" value="Text field.">
+<p></p>
+<button type="button" onclick="focusMethod()">Click me to focus on the text field!</button> 
+ +

CSS Content

+ +
/* Sample CSS Content */
+ +

JavaScript Content

+ +
focusMethod = function getFocus() {
+  document.getElementById("myTextField").focus();
+} 
+ +

Result

+ +

{{ EmbedLiveSample('Focus_on_a_text_field') }}

+ +

Focus on a button

+ +

HTML Content

+ +
<button type="button" id="myButton">Click Me!</button>
+<p></p>
+<button type="button" onclick="focusMethod()">Click me to focus on the button!</button> 
+ +

CSS Content

+ +
Sample CSS Content
+ +

JavaScript Content

+ +
focusMethod = function getFocus() {
+  document.getElementById("myButton").focus();
+} 
+ +

Result

+ +

{{ EmbedLiveSample('Focus_on_a_button') }}

diff --git a/files/zh-tw/svg/tutorial/basic_shapes/index.html b/files/zh-tw/svg/tutorial/basic_shapes/index.html new file mode 100644 index 0000000000..579f39bbe9 --- /dev/null +++ b/files/zh-tw/svg/tutorial/basic_shapes/index.html @@ -0,0 +1,150 @@ +--- +title: 基本形状 +slug: SVG/Tutorial/Basic_Shapes +translation_of: Web/SVG/Tutorial/Basic_Shapes +--- +
+ {{ PreviousNext("SVG/Tutorial/Positions", "SVG/Tutorial/Paths") }}
+

下面将介绍一些SVG绘图常用的形状命令,通过它们名字,你可以很轻易的看出它们可以画出什么。这里也会给出一些定义位置和尺寸的属性,但不会介绍如何将元素定义得更准确更完善。在这里我们只介绍必须的基本功能,因为它们会被广泛应用在SVG文件里。

+

基本形状

+

你需要在文档里创建一个元素,来新增相应的形状。不同的元素用来定义不同的形状,并采用不同的属性定义尺寸和位置。其中一些是可以被其他形状命令替代的,所以显得有点多余,但是它们的存在是有意义的,它们可以让你用起来更方便,并且保证你的SVG文档尽可能简洁易懂。所有的基本形状都在右边的图例里展示出来了,生成它们的代码如下:

+

+
+
<?xml version="1.0" standalone="no"?>
+<svg width="200" height="250" version="1.1" xmlns="http://www.w3.org/2000/svg">
+
+  <rect x="10" y="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
+  <rect x="60" y="10" rx="10" ry="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
+
+  <circle cx="25" cy="75" r="20" stroke="red" fill="transparent" stroke-width="5"/>
+  <ellipse cx="75" cy="75" rx="20" ry="5" stroke="red" fill="transparent" stroke-width="5"/>
+
+  <line x1="10" x2="50" y1="110" y2="150" stroke="orange" fill="transparent" stroke-width="5"/>
+  <polyline points="60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145"
+      stroke="orange" fill="transparent" stroke-width="5"/>
+
+  <polygon points="50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180"
+      stroke="green" fill="transparent" stroke-width="5"/>
+
+  <path d="M20,230 Q40,205 50,230 T90,230" fill="none" stroke="blue" stroke-width="5"/>
+</svg>
+
+
+注意: stroke, stroke-widthfill 等属性会在后面的章节里介绍。
+

矩形 rect

+

rect元素用来创建矩形,它有6个基本属性,用于设定它的位置以及样式。上面的图例里,最开始的两个图形都是矩形,右边的矩形设定了rx和ry属性,从而增加了圆角,如果不给它们赋值,其默认值为0,也就没有圆角。

+
<rect x="10" y="10" width="30" height="30"/>
+<rect x="60" y="10" rx="10" ry="10" width="30" height="30"/>
+
+
+ x
+
+ 矩形左上角的x轴坐标
+
+ y
+
+ 矩形左上角的y轴坐标
+
+ width
+
+ 矩形的宽
+
+ height
+
+ 矩形的高
+
+ rx
+
+ 圆角的x轴半径
+
+ ry
+
+ 圆角的y轴半径
+
+

圆形 circle

+

circle 元素用来创建圆形,这里给出了3个属性:

+
<circle cx="25" cy="75" r="20"/>
+
+
+ r
+
+ 半径
+
+ cx
+
+ 圆心的x轴坐标
+
+ cy
+
+ 圆心的y轴坐标
+
+

椭圆 ellipse

+

椭圆ellipse其实就是一种特殊的圆形,这里可以改变x和y轴的半径来区分它们(数学上称为长轴半径和短轴半径)。

+
<ellipse cx="75" cy="75" rx="20" ry="5"/>
+
+
+ rx
+
+ x轴半径
+
+ ry
+
+ y轴半径
+
+ cx
+
+ 圆心的x轴坐标
+
+ cy
+
+ 圆心的y轴坐标
+
+

线 line

+

line画的是线段,通过在属性中定义起点和终点的坐标,构成两点之间的线段。

+
<line x1="10" x2="50" y1="110" y2="150"/>
+
+
+ x1
+
+ 第一个点的x轴坐标
+
+ y1
+
+ 第一个点的y轴坐标
+
+ x2
+
+ 第二个点的x轴坐标
+
+ y2
+
+ 第二个点的y轴坐标
+
+

折线 polyline

+

折线polyline是一组连接起来的线段,折线上所有的点都放在一个属性里:

+
<polyline points="60 110, 65 120, 70 115, 75 130, 80 125, 85 140, 90 135, 95 150, 100 145"/>
+
+
+ points属性
+
+points属性是点的列表,每个数字用空格、逗号、换行或回车分隔开。每个点包括两个数字,一个x轴坐标一个y轴坐标,所以,(0,0)、(1,1)、(2,2)这三个点的列表应该写成“0 0, 1 1, 2 2”。
+
+

多边形 polygon

+

多边形polygon和折线很像,它们都是定义一组点,然后将点用线段连接起来,从而形成一个图形。不同的是,多边形的起点和终点会连起来,形成一个闭合的形状。需要注意的是,矩形也是一种多边形,如果需要的话,你也可以用多边形来创建一个矩形。

+
<polygon points="50 160, 55 180, 70 180, 60 190, 65 205, 50 195, 35 205, 40 190, 30 180, 45 180"/>
+
+
+ points属性
+
多边形的points属性也是点的列表,每个数字用空格、逗号、换行或回车分隔开。每个点包括两个数字,一个x轴坐标一个y轴坐标,所以,(0,0)、(1,1)、(2,2)这三个点的列表应该写成“0 0, 1 1, 2 2”。这些都和折线的points属性一样。不同的是,这里的最后一个点和第一个点会自动连接起来,形成闭合路径。
+
+

路径 path

+

路径path可能是SVG中最通用的一种形状,通过path元素,我们可以创建矩形(有没有圆角都行)、圆形、椭圆形、折线、多边形,以及其他一些形状,比如二次贝塞尔曲线、三次贝塞尔曲线,等等。因为path很强大也很复杂,所以会在下一章进行详细介绍。这里只介绍一个定义路径形状的属性。

+
<path d="M 20 230 Q 40 205, 50 230 T 90230"/>
+
+
+ d属性
+
+ d属性的值是由一些点的坐标,以及控制这些坐标的命令组成的,它们一起描述了路径的形状。具体内容在path章节里介绍。
+
+
+ {{ PreviousNext("SVG/Tutorial/Positions", "SVG/Tutorial/Paths") }}
diff --git a/files/zh-tw/tools/3d_view/index.html b/files/zh-tw/tools/3d_view/index.html new file mode 100644 index 0000000000..463946c4c7 --- /dev/null +++ b/files/zh-tw/tools/3d_view/index.html @@ -0,0 +1,102 @@ +--- +title: 3D view +slug: Tools/3D_View +translation_of: Tools/3D_View +--- +
+

自 Firefox 47 開始,3D View 不再可用

+ +

有個 Tilt 3D 套件提供相同功能。但是,請記得這和內建版本一樣,無法在 multiprocess Firefox 使用。

+
+ +

當您點擊 3D View 按鈕,頁面將進入 3D 檢視模式,在這模式之下,您將看到頁面以 HTML 標籤層次,形成從底部向外突起的 3D 模型。這功能讓您可用更簡單的方式檢視頁面結構。

+ +

+ +

經由點擊及拖曳,您可以旋轉、重新定位 3D 圖像,以看到不同角度來確定結構。原先於屏幕外的元素將變為可見,如此一來您將可看見他們和可見元素的關係。您可以點擊元素經由 HTML panel 或是 Style panel 查看 HTML。相反地,您也能點擊導航列去選擇選取 3D View 中的特定元素。

+ +

如果您在頁面檢測器沒看到 3D 按鈕,可能是您的顯示卡驅動需要更新。查看無法使用的清單以取得更多資訊

+ +

操作 3D View

+ +

該怎麼使用鍵盤快速鍵及滑鼠控制 3D View?

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能鍵盤按鍵滑鼠
縮放+ / -滾輪上下
左右旋轉a / d滑鼠左右
上下翻轉w / s滑鼠上下
左右平移← / →滑鼠左右
上下平移↑ / ↓滑鼠上下
重設縮放大小0重設縮放大小為預設值
聚焦於選擇的節點f請確定該節點可見 {{ fx_minversion_inline("13.0") }}
重設 3D Viewr將縮放、旋轉、位置重設為預設值 {{ fx_minversion_inline("12.0") }}
隱藏節點x +

隱藏選擇的節點,這在您需要找到被遮蓋的節點時很實用 {{ fx_minversion_inline("12.0") }}

+
+ +

3D view 的使用時機

+ +

下列時機中,3D View 很實用:

+ + + +

另見

+ + + +

{{ languages( { "ja": "ja/Tools/Page_Inspector/3D_view", "zh-cn": "zh-cn/Tools/Page_Inspector/3D_view"} ) }}

diff --git a/files/zh-tw/tools/browser_toolbox/index.html b/files/zh-tw/tools/browser_toolbox/index.html new file mode 100644 index 0000000000..686a7ed06d --- /dev/null +++ b/files/zh-tw/tools/browser_toolbox/index.html @@ -0,0 +1,41 @@ +--- +title: Browser Toolbox +slug: Tools/Browser_Toolbox +translation_of: Tools/Browser_Toolbox +--- +

瀏覽器工具箱有別於一般的工具箱,它可以讓您對附加元件以及瀏覽器本身的 JavaScript 程式碼除錯。瀏覽器工具箱所顯示的內容為整個瀏覽器而非僅有單一頁面的內容。h

+ +
+

註: 如果您要為無需新啟動或是基於 SDK 的附加元件除錯,請使用 Add-on Debugger

+
+ +

啟用瀏覽器工具箱

+ +

瀏覽器工具箱預設為關閉。要啟用瀏覽器工具箱,您必須要勾選「Enable chrome and addon debugging」與「Enable remote debugging」兩個選項。

+ + + +

Now you should see a new item in the Web Developer menu in Firefox labeled "Browser Toolbox".

+ +

Click the menu item and you'll be presented with a dialog like this:

+ +

Click OK, and the Browser Toolbox will open in its own window:

+ +

You'll see, and be able to debug, all the JavaScript files loaded by the browser itself and by any add-ons that are running. Altogether you will have access to the following developer tools:

+ + + +

 

+ +

 

diff --git a/files/zh-tw/tools/debugger/how_to/index.html b/files/zh-tw/tools/debugger/how_to/index.html new file mode 100644 index 0000000000..084f1717e5 --- /dev/null +++ b/files/zh-tw/tools/debugger/how_to/index.html @@ -0,0 +1,11 @@ +--- +title: How to +slug: Tools/Debugger/How_to +tags: + - NeedsTranslation + - TopicStub +translation_of: Tools/Debugger/How_to +--- +
{{ToolsSidebar}}

These articles describe how to use the debugger.

+ +

{{ ListSubpages () }}

diff --git a/files/zh-tw/tools/debugger/how_to/open_the_debugger/index.html b/files/zh-tw/tools/debugger/how_to/open_the_debugger/index.html new file mode 100644 index 0000000000..d630094589 --- /dev/null +++ b/files/zh-tw/tools/debugger/how_to/open_the_debugger/index.html @@ -0,0 +1,24 @@ +--- +title: Open the debugger +slug: Tools/Debugger/How_to/Open_the_debugger +translation_of: Tools/Debugger/How_to/Open_the_debugger +--- +
{{ToolsSidebar}}
+ +

有三種方式可以打開除錯器:

+ + + +

{{EmbedYouTube("yI5SlVQiZtI")}}

+ +
+
+
diff --git a/files/zh-tw/tools/debugger/how_to/set_a_breakpoint/index.html b/files/zh-tw/tools/debugger/how_to/set_a_breakpoint/index.html new file mode 100644 index 0000000000..04044571e5 --- /dev/null +++ b/files/zh-tw/tools/debugger/how_to/set_a_breakpoint/index.html @@ -0,0 +1,25 @@ +--- +title: Set a breakpoint +slug: Tools/Debugger/How_to/Set_a_breakpoint +translation_of: Tools/Debugger/How_to/Set_a_breakpoint +--- +
{{ToolsSidebar}}
+ +

你可以使用以下任一種方法來設置中斷點;

+ + + +

以下影片使用 context menu 來設置一個中斷點:

+ +

{{EmbedYouTube("P7b98lEijF0")}}

+ +

每個中斷點會在除錯器中的兩個地方顯示;

+ + diff --git a/files/zh-tw/tools/debugger/index.html b/files/zh-tw/tools/debugger/index.html new file mode 100644 index 0000000000..ca245fc16a --- /dev/null +++ b/files/zh-tw/tools/debugger/index.html @@ -0,0 +1,58 @@ +--- +title: 除錯器 +slug: Tools/Debugger +translation_of: Tools/Debugger +--- +
+

本頁在描述 Firefox Nightly 與 Firefox Developer Edition 第 52 版以後的 JavaScript 除錯器(Debugger)。

+ +

要找在此版本之前、或是位於 Beta 與 Release 通道的 Firefox,請參閱Firefox 52 之前的除錯器

+ +

如果你是這個版本的除錯器,但需要用舊版本的除錯器,你可以去 about:config 那裡,把「devtools.debugger.new-debugger-frontend」選為 false

+
+ +

{{EmbedYouTube("QK4hKWmJVLo")}}

+ +

JavaScript 除錯器可以讓 JavaScript 單步執行,並檢查或修改其狀態,以便查找錯誤。

+ +

你可以在本地或是在遠端除錯用 Firefox 除錯。一個遠端除錯的例子,就是在 Android 設備上執行 Firefox for Android。請參閱遠端除錯以理解如何把欲除錯的目標,連接到除錯器上。

+ +

The debugger ships inside Firefox, and these pages describe how to use the version that's embedded in Firefox. However, you can also run it as a standalone web application, and can then use it to debug code running in other browsers and in Node. For more details on that, see the project's GitHub repository.

+ +

新版除錯器尚未支援所有舊版除錯器的功能。請參閱新版除錯器的侷限

+ +
+

用戶介面導覽

+ +

如果要自己摸索除錯器,我們有UI 的快速導覽

+ +
+

如何

+ +

如果要知道除錯器可以做什麼,請看看以下的教學:

+ +
+ +
+ +
+

參閱

+ +
+ +
diff --git a/files/zh-tw/tools/firefox_os_1.1_simulator/index.html b/files/zh-tw/tools/firefox_os_1.1_simulator/index.html new file mode 100644 index 0000000000..08483cbb3f --- /dev/null +++ b/files/zh-tw/tools/firefox_os_1.1_simulator/index.html @@ -0,0 +1,240 @@ +--- +title: Firefox OS 1.1 Simulator +slug: Tools/Firefox_OS_1.1_Simulator +translation_of: Tools/Firefox_OS_1.1_Simulator +--- +
+
+
+

本頁將說明「舊版」的 Firefox OS 模擬器 (Firefox OS Simulator)。只有在開發 Firefox 1.1 所適用的 App 時,才使用 1.1 版模擬器。且本版模擬器僅能安裝於 Firefox 24 或 Firefox 25 之上。

+

如果要針對 Firefox OS 1.2 或更高版本開發 App,則必須使用「應用程式管理員 (App Manager)」

+

若需要任何協助,請透過 dev-developer-tools 郵件群組#devtools on irc.mozilla.org 發問。

+
+

Firefox OS 模擬器 (Firefox OS Simulator) 附加元件,可讓你在桌機上測試自己的 Firefox OS App。若與實際裝置相較,模擬器可協助開發者順利完成「撰寫─測試─除錯」的程序,而且你還不用真的弄到實際設備就能夠測試 App。

+

此附加元件基本上包含:

+
    +
  • 模擬器:其內有 Firefox OS Desktop Client,屬於 Firefox OS 較高層級的版本,可於桌機中執行。模擬器所具備的某些附加模擬功能,甚至是標準 Firefox OS 桌面版所沒有的。
  • +
  • Dashboard:此為 Firefox 瀏覽器所管理的工具,可用以啟動/停止模擬器,並可安裝、除錯、解除安裝模擬器所執行的 App。Dashboard 亦可協助將 App 送入實際裝置,針對常見問題而檢查 App 的 manifest 檔案。.
  • +
+

下方截圖則是以模擬器所進行的除錯作業。

+

「Dashboard」即於右上的 Firefox 分頁中執行。我們在這裡新增了「Where am I?」的封裝式 (Packaged) App。左上方就是模擬器正執行的 App。這裡同時也連上了除錯工具,就位在視窗底端。你也可以看到我們設定了 App 的中斷點。

+

+

本篇指南涵蓋下列主旨:

+ +
+ 若要用模擬器對實際的 Apps 進行除錯,請參閱《Firefox OS 模擬器簡易攻略》頁面。
+

安裝「Firefox OS Simulator」附加元件

+

此模擬器軟體已封裝並發佈為 Firefox 的附加元件。安裝步驟為:

+
    +
  1. 開啟 Firefox 並前往 addons.mozilla.org 上的 Simulator 頁面
  2. +
  3. 點選「Add to Firefox」。
  4. +
  5. 下載附加元件完畢,系統隨即提醒你安裝。點選「立刻安裝 (Install Now)」。
  6. +
+

由於附加元件的檔案大小有所不同,Firefox 可能於安裝期間暫停數秒,並可能顯示「注意:發現容易停止回應的程式碼 (Warning: Unresponsive script)」對話框。如果出現此對話框,就點選「繼續 (Continue)」等到安裝作業結束即可。自 Firefox 27 起應該就不會再出現此問題。
+
+ 一旦安裝模擬器附加元件完畢,Firefox 將定期檢查是否有更新版本,隨時保持最新版本。

+

模擬器安裝期間隨即自動開啟 Dashboard。另外只要點選「Firefox」選單 (若是 OS X 與 Linux,則為「工具」選單),再點選「網頁開發者 (Web Developer)」→「Firefox OS Simulator」,都可再開啟 Dashboard:

+


+ Dashboard 可讓你將 App 新增至模擬器內並執行之。看起來就像下圖:

+

新增、移除、重新整理 App

+

新增 App

+

如果要將封裝式 (Packaged) App 新增至模擬器中,則請開啟 Dashboard,點選「Add Directory」並找到 App 的 manifest 檔案
+
+ 若要新增托管式 (Hosted) App,則於「URL for page or manifest.webapp」的文字框中輸入網址,再點選「Add URL」。如果網址指向 manifest 檔案,就會使用該 manifest 檔案;反之,則 Dashboard 將針對該網址產生 manifest 檔案。所以只要輸入網站網址,都可新增該網站作為 App。
+
+ 在新增 App 時,Dashboard 將為 manifest 檔案執行一系列的測試,檢查是否有常見問題。可參閱下方 Manifest 檔案檢驗以了解測試細節。

+

除非 manifest 檔案檢驗程序真的發現了 App 的錯誤,否則 Dashboard 均將自動於模擬器中執行你的 App。

+

管理 App

+

一旦新增了 App,就會出現在管理程式的 App 清單中:
+
+ 各個項目均提供了 App 的相關資訊:

+
    +
  • App 的名稱 ─ 取自於 manifest 檔案
  • +
  • App 的類型 ─ 可能為「Packaged」、「Hosted」、「Generated」之一
  • +
  • 其 manifest 檔案的連結
  • +
  • manifest 檔案檢驗的結果
  • +
+

另外會提供 4 項指令:

+
    +
  • 「Refresh」:在變更過 App 之後,可透過此指令更新並重新載入模擬器中的 App。此指令亦可讓 Dashboard 再次檢驗 manifest 檔案。如果變更過 App 之後卻沒有自動反應在「installed app:」中,則必須重新整理才能套用變更。
  • +
  • 「Connect」:此指令可銜接開發工具與指定的 App。如果尚未執行 App 與模擬器,則 Dashboard 將啟動之。
  • +
  • 「Remove」(也就是「X」):此指令可為 Dashboard 與模擬器移除 App。只要開啟了 Dashboard 分頁,亦可取消此動作。
  • +
  • 「Receipt」:此指令可針對付費 App 測試收據的驗證作業。在選擇了所要測試的收據類型之後,將重新安裝該 App 並包含所選類型的測試收據。
  • +
+
+

從模擬器視窗重新整理 App:在 App 執行時,只要透過選單列與相關快捷鍵,即可從模擬器視窗直接更新並重新載入 App。

+
+

檢驗 Manifest 檔案

+

當提供 manifest 檔案時,管理程式將執行某些檢驗測試,所回報的問題可分為 3 大類:

+
    +
  • manifest 錯誤:這種問題將導致 App 無法執行。
  • +
  • manifest 警示:這種問題將導致 App 無法正確運作。
  • +
  • 模擬器特定警示:目前模擬器尚未支援此 App 所使用的功能。
  • +
+

管理程式將總結 App 所遇到的問題。可點選摘要以獲得更多詳情。

+

Manifest 檔案錯誤

+

下列狀態均將由 Dashboard 回報為錯誤。也就是說,你必須修復之後才能在模擬器中繼續執行 App:

+
    +
  • manifest 檔案沒有必要的「name」欄位。
  • +
  • manifest 檔案為無效 JSON。
  • +
  • 此 App 屬於托管式 App,但其 manifest 檔案中的類型 (type) 欄位為「Privileged」或「Certified」;而此 2 種類型僅限用於封裝式 App。
  • +
  • 常見的 appCache 錯誤 (封裝式 App 無法使用 appCache,對 manifest 網址的請求,回傳了 HTTP 重新導向狀態或 HTTP 錯誤狀態)
  • +
+

如果新增的 manifest 檔案缺少了「name」欄位,就會出現如下圖的結果:
+

+

Manifest 檔案警示

+

下列 manifest 檔案的問題,Dashboard 均將回報為警示:

+
    +
  • 缺少圖示。
  • +
  • 圖示低於 128 像素:提交至 Marketplace 的所有 App,其代表圖示均必須為至少 128 像素的方塊圖。
  • +
  • 無法辨別「type」欄位。
  • +
  • manifest 檔案所請求的「權限」無法辨別。
  • +
  • manifest 檔案所請求的「權限」遭拒。
  • +
  • manifest 檔案所請求的「權限」無法決定其存取作業。
  • +
+

模擬器特定警示

+

最後,針對 App 所要使用的 Firefox OS 功能,但模擬器卻尚未支援的情況,管理程式將送出警示:

+
    +
  • type」欄位屬於「Certified」,但模擬器尚未完整支援 Certified App。
  • +
  • manifest 檔案請求「權限」以使用 API,但模擬器尚未支援此 API。
  • +
+

執行模擬器

+

有 2 種方式可啟動模擬器:

+
    +
  • 如果要新增、更新、移除 App,或是按下 App 輸入項旁邊的「Run」按鈕,則 Dashboard 就會在模擬器中自動執行 App。
  • +
  • 如果按下 Dashboard 左側的「Stopped」按鈕,則模擬器將回到首頁畫面,讓你再瀏覽自己的 App。
  • +
+

不論哪種方法,只要模擬器處於執行狀態,則「Stopped」按鈕會轉成綠色,且按鈕文字也會轉成「Running」。如果要停下模擬器,再按下相同按鈕即可。
+
+ 模擬器將以獨立視窗顯示,而該模擬畫面將為 320x480 像素,且底部工具列 (Toolbar) 將提供某些額外功能

+

+

若要模擬觸控事件,只要點擊滑鼠不放再拖曳即可。所以如果在主畫面按下滑鼠並由右至左拖曳,就可以看到內建的 App 還有你自己新增的 App:

+

+

模擬器工具列

+

在模擬器視窗底部的工具列,由左至右分別為主畫面 (Home)、畫面旋轉 (Screen Rotation)、地理位置定位 (Geolocation) 共 3 個按鈕:

+
    +
  • 主畫面」可回到主畫面 (或長按不放則可進入工作清單)。
  • +
  • 畫面旋轉」可切換裝置的橫向、直向畫面;即產生 orientationchange 事件。
  • +
  • 地理位置定位」將觸發對話框,詢問使用者是否要分享自己的地理位置。這個功能可能會套用你目前的座標,或提供自訂座標。App 可搭配 Geolocation API 而提供此功能。
  • +
+

+

模擬器選單列 (Menubar)

+

在頂端的選單列上即提供多項有用的指令,讓你達到更高的開發效率:

+

+
    +
  • File -> Quit (Ctrl/Cmd - Q):關閉模擬器
  • +
  • App -> Refresh (Ctrl/Cmd - R):重新整理執行中的 App
  • +
+

若於鍵盤上使用「App Refresh」 指令快捷鍵,則開發 App 就更像是撰寫網頁一樣:

+
    +
  • 更改程式碼 (並依需要而重新執行自己的程式設計工具,如 volo / yeoman / grunt)
  • +
  • 按下快捷鍵,即可重新整理正於模擬器中執行的 App
  • +
+
+

「Refresh App and Clear Data」隱藏快捷鍵:針對模擬器為 Apps 所儲存的資料,有時若能清除相關資料更有利於開發作業。因此模擬器亦提供隱藏版的快捷鍵「Shift - Ctrl/Cmd - R」。在清除下列資料時,此快捷鍵亦可重新整理正執行中的 App:

+
    +
  • +

    localStorage / sessionStorage

    +
  • +
  • +

    cookies

    +
  • +
  • +

    indexedDB

    +
  • +
  • +

    appCache

    +
  • +
+
+

附掛開發者工具

+

使用者可為模擬器附掛開發工具,讓 App 的除錯作業更順利。目前僅能附掛JavaScript 除錯器 (JavaScript Debugger)網頁主控台 (Web Console)樣式編輯器 (Style Editor)效能分析器 (Profiler)網路監測器 (Network Monitor)。當然,我們仍將持續支援更多開發工具

+
+

某些工具僅能用於 Firefox 的 Beta、Aurora,或 Nightly 版本。

+
+

若要為模擬器附掛開發工具,則可按下任一 App 的「Connect」按鈕:

+

+

Dashboard 分頁下方隨即開啟開發者工具面板,並銜接 App:

+

+

網頁主控台 (Web Console)

+

如果勾選了「Stopped/Running」開關下方的「Console」方塊,則執行模擬器時會開啟錯誤主控台 (Error Console)。透過這個通用的主控台物件,你的 App 均將由主控台所記錄。

+

除錯器 (Debugger)

+

透過除錯器,可針對執行中的 App 逐行檢查其 JavaScript 程式碼、管理中斷點、監看表示式,以更迅速追蹤錯誤與問題。進一步了解除錯器

+

樣式編輯器 (Style Editor)

+

可檢查並編輯 App 中設定的 CSS 檔案。你所進行的變更亦將即時套用至 App;而不需再重新整理。進一步了解樣式編輯器

+

效能分析器 (Profiler)

+

若銜接 App 與效能分析器,即可找出 JavaScript 程式碼耗時過長的部分。效能分析器將對目前 JavaScript 的 Call stack 定期取樣,並編寫樣本的統計資料。進一步了解效能分析器

+

網路監測器 (Network Monitor)

+

新的網路監測器提供友善介面,可針對 App 所啟動的網路請求,分析其狀態、標頭、內容、時間點等資訊。進一步了解網路監測器

+

收據 (Receipt)

+

若你正開發付費 App,就應該在有效 (以加密方式簽署) 收據上,測試自己的收據驗證代碼 (此代碼將驗證使用者是否已購買了 App 或收到退款,接著通知使用者並鎖定/解鎖 App 的功能)。

+

模擬器的 Dashboard 對各個 App 均提供了「Receipts」選單,讓你可選擇「Valid」、「Invalid」、「Refunded」測試收據而安裝 App。只要選擇你想要測試的收據類型,則 Dashboard 就會從 Marketplace 收據服務中取得該類型的測試收據,並在模擬器中安裝 App:

+

+

直接傳輸 (Push to device)

+

如果你手上已經有 Firefox OS 裝置並連上了模擬器,就可以從 Dashboard 直接將 App 送進裝置。

+

連上裝置

+

根據指南中的說明,就可順利將 Firefox OS 裝置連上桌機。另請注意,模擬器附加元件已經包含了 ADB,所以你不需再次安裝。

+

將 App 送入裝置

+

設定完畢之後,就可透過 USB 銜接裝置與桌上型電腦。你可以看到 Dashboard 左邊出現「Device connected」的註記,而且各個 App 項目上都會出現新的「Push」指令:

+

+

按下「Push」就會把 App 安裝進 Firefox OS 裝置中。

+
+

手動步驟:

+
    +
  • +

    一旦將 App 送入裝置之後,就必須手動關閉並重新啟動,才能取得更新內容。

    +
  • +
  • +

    如果你更新了 manifest 檔案 (如 App 的名稱、方向、類型、權限),就必須重新啟動作業系統,才能讓變更生效。

    +
  • +
+
+

Firefox OS 裝置連線確認

+

每次只要重新啟動裝置,就必須確認裝置上的第一次「Push」請求:

+

+

Linux 上的疑難排除

+

如果建立 udev 規則之後還是無法銜接裝置,則請參閱這個問題

+

模擬器的限制

+

請注意,Firefox OS 模擬器仍無法提供完美的模擬作業。

+

硬體限制

+

模擬器除了螢幕尺寸的限制之外,也無法模擬 Firefox OS 裝置的硬體 (例如 CPU 速度或可用的記憶體容量)。

+

音訊/視訊編碼

+

下列編碼 (Codecs) 因硬體加速解碼而有所不同,因此尚未支援:

+
    +
  • MP3
  • +
  • AAC
  • +
  • H.264 (MP4)
  • +
  • WebM
  • +
+

也就是說,若 App 或網站 (如 Youtube) 使用這些編碼,則模擬器將無法測試其中的視訊回播功能。

+

尚未支援的 API

+

一般來說,因為桌上型電腦無法使用支援硬體,所以可於裝置上運作的特定 API,可能無法用於模擬器之上。我們另外針對某些 API (例如 Geolocation 地理位置定位) 建構了模擬功能,未來版本亦將新增更多模擬 API。但目前仍尚未支援下列 API。如果使用了這些 API,也只會得到錯誤的報告或結果:

+ +

獲得協助

+

如果你發現了任何錯誤,請到 GitHub 提交這些錯誤。如果有任何問題,也請透過 dev-developer-tools 郵件群組或到 #devtools on irc.mozilla.org 上發問。

+

啟動詳細資訊 (verbose) 記錄的方法

+

透過 about:config 即可建立 extensions.r2d2b2g@mozilla.org.sdk.console.logLevel,接著將之設定為整數值 0,並停用/重新啟用附加元件即可。有關模擬器作業的其他訊息,均將顯示於錯誤主控台 (Error Console) 中;或是較新版本 Firefox 的瀏覽器主控台 (Browser Console)。

+
+
+
+

 

+
+

 

diff --git a/files/zh-tw/tools/index.html b/files/zh-tw/tools/index.html new file mode 100644 index 0000000000..f61960184d --- /dev/null +++ b/files/zh-tw/tools/index.html @@ -0,0 +1,192 @@ +--- +title: Firefox 開發者工具 +slug: Tools +tags: + - Developing Mozilla + - NeedsMarkupWork + - NeedsTechnicalReview + - NeedsTranslation + - Tools + - TopicStub + - Web Development + - 'Web Development:Tools' +translation_of: Tools +--- +
{{ToolsSidebar}}

在桌機與手機上檢查、編輯、並處理 HTML、CSS 與 JavaScript 的錯誤。

+ +
+
+
+ +
+

+ +

要尋找最新的開發工具與功能,請試試 Firefox Developer Edition。

+ +

Download Firefox Developer Edition

+
+ +
+
+ +
+

核心工具

+ +
+
+

頁面檢測器

+ +

The all-new Inspector panel in Firefox 57.

+ +

檢視並編輯網頁的內容與版面。視覺化各種東西,包括盒子模型、動畫、格線版面。

+
+ +
+

網路主控台

+ +

The all-new Console in Firefox 57.

+ +

檢查網頁紀錄的訊息、並透過 JavaScript 與網頁互動。

+
+
+ +
+
+
+

JavaScript 除錯器

+ +

The all-new Firefox 57 Debugger.html

+ +

停步、逐步、試驗、修改網頁的 JavaScript。

+
+ +
+

網路監控

+ +

The Network panel in Firefox 57 DevTools.

+ +

看看網頁載入時發了什麼請求。

+
+
+ +
+
+
+

效能工具

+ +

+ +

分析網站的通常反應、JavaScript、還有布局效能。

+
+ +
+

適應性設計模式

+ +

Responsive Design mode in Firefox 57.

+ +

看看網站或 app 在不同的設備與網路狀況下表現如何。

+
+
+ +
+

更多工具

+ +

Firefox 也內建了這些開發者工具,但通常不會像「核心工具」那麼常用。

+ +
+
+
記憶體
+
找出哪個物件是用了記憶體哪個地方。
+
儲存空間
+
檢查頁面存了什麼 cookie、本機的東西、indexedDB、session。
+
DOM 屬性檢查器
+
檢查頁面的 DOM 屬性、函式之類的。
+
開發者工具列
+
開發者工具的命令行介面。
+
Eyedropper
+
選取網頁的顏色。
+
速記本
+
Firefox 裡面文字編輯器,讓你能撰寫並執行 JavaScript。
+
樣式編輯器
+
針對目前的頁面觀察與編輯 CSS 樣式。
+
Shader Editor
+
查看與編輯 WebGL 使用的 vertex 與 fragment shader。
+
Web Audio Editor
+
檢查音頻的節點圖形,並修改其參數。
+
擷取畫面
+
擷取整個網頁或是某個元素。
+
+
+ +
+

連接開發者工具

+ +

如果你透過鍵盤快捷鍵或等同的選單選項啟動了開發者工具,它的目標會針對目前頁籤的文件。不過,你也可以把工具連接到其他目標,不論是不是相同的瀏覽器、甚至是不是相同的設備。

+ +
+
+
about:debugging
+
針對附加元件、內容頁籤、還有瀏覽器運行的 worker。
+
連接到 Firefox for Android
+
連接開發者工具到在 Android 運行的 Firefox 實例。
+
連接到 iframes
+
把開發者工具連接到頁面內指定的 iframe。
+
連接到其他瀏覽器
+
把開發者工具連接到 Android 的 Chrome 與 iOS 的 Safari。
+
+
+ +
+

給瀏覽器除錯

+ +

開發者工具預設上是附加在網頁或網路 app 的。不過,你可以把它與瀏覽器作為一個整體連結起來。這在瀏覽器與附加元件開發方面會很有用。

+ +
+
+
瀏覽器控制台
+
看看瀏覽器附加元件紀錄的訊息,然後運行 JavaScript 程式碼。
+
瀏覽器工具箱
+
將開發者工具附加到瀏覽器本身。
+
+
+ +
+

擴展開發者工具

+ +

開發者工具都設計為易於擴展的。Firefox 附加元件可以取用開發者工具與其元件,擴展現有工具或加入新工具。使用遠端除錯協定,可以建立自己的除錯用戶端與伺服器,讓你可以使用自己的工具為網站除錯,或針對不同的目標平台應用 Firefox 工具。

+ +
+
+
開發用附加元件示例
+
透過實例理解如何作出一個開發用的附加元件。
+
給開發者工具加一個面板
+
給開發者工具寫一個添加新面板的附加元件。
+
遠端除錯協定
+
協定用於連接 Firefox 開發者工具到如 Firefox 或 Firefox OS 設備之類的除錯目標。
+
原始碼編輯器
+
Firefox 內建,能嵌入到附加元件的原始碼編輯器。
+
Debugger 介面
+
可以讓 JavaScript 程式碼觀察其他 JavaScript 程式碼的 API。Firefox 開發者工具利用該 API 實做了 JavaScript 程式碼除錯器。
+
自訂網頁主控台輸出
+
如何擴展與自訂 Web ConsoleBrowser Console 的輸出。
+
+
+ +
+

從 Firebug 遷移

+ +

Firebug 已經走到產品生命的盡頭(理由請參閱 Firebug lives on in Firefox DevTools),我們明白有些人要遷移到不太熟悉的 DevTools 產品線會有點困難。針對從 Firebug 遷移到 Firefox 開發者工具壓力的緩解,我們寫了個方便的指南:從 Firebug 遷移

+ +
+

貢獻

+ +

如果你想幫忙改進開發者工具,這些資源能幫助你。

+ +
+
+
Get Involved
+
告訴你如何參與其中的 Mozilla wiki 頁面。
+
firefox-dev.tools
+
能幫你找到目前在處理的錯誤。
+
+
diff --git a/files/zh-tw/tools/network_monitor/index.html b/files/zh-tw/tools/network_monitor/index.html new file mode 100644 index 0000000000..ee1a1d0624 --- /dev/null +++ b/files/zh-tw/tools/network_monitor/index.html @@ -0,0 +1,584 @@ +--- +title: Network Monitor +slug: Tools/Network_Monitor +translation_of: Tools/Network_Monitor +--- +

網路監視器提供檢視所有從 Firefox 送出的網路需求 (像是從瀏覽器開啟一個頁面,或是一個 XMLHttpRequests ),例如需求所花費的時間,以及其他更詳細的資訊。

+ +

Opening the Network Monitor

+ +

There are a few different ways to open the Network Monitor:

+ +
+

Please note the keyboard shortcut was changed in Firefox 55

+
+ + + +

The Network Monitor will appear at the bottom of the browser window. Reload the page to see the requests:

+ +

+ +

The Network Monitor records network requests any time the Toolbox is open, even if the Network Monitor itself is not selected. This means you can start debugging a page in, for example, the Web Console, then switch to the Network Monitor to see network activity without having to reload the page.

+ +

UI overview

+ +

The UI is divided into four main pieces:

+ + + +

+ + + +

Performance analysis view

+ +

Toolbar

+ +

From Firefox 47 onwards, the toolbar is at the top of the main window. In earlier versions of Firefox, it's at the bottom.

+ +

It provides:

+ + + +
+

Note: From Firefox 58 onwards, the "Flash" filter button is no longer available, and Flash requests are included in the "Others" filter ({{bug(1413540)}}).

+
+ +

Network request list

+ +

By default, the Network Monitor shows a list of all the network requests made in the course of loading the page. Each request is displayed in its own row:

+ +

By default, the Network Monitor is cleared each time you navigate to a new page or reload the current page. You can override this behavior by checking "Enable persistent logs" in the Settings.

+ +

Network request columns

+ +

From Firefox 55 onwards, you can toggle different columns by right-clicking on the table header and choosing the specific column from the context menu. A "Reset Columns" option is also available to reset the columns to their initial configuration. Here is a list of all available columns:

+ + + +

The toolbar at the top labels these columns, and clicking the label sorts all the requests by that column.

+ +

Image thumbnails

+ +

If the file is an image, the row includes a thumbnail of the image, and hovering over the filename shows a preview in a tooltip:

+ +

+ +

Security icons

+ +

The Network Monitor displays an icon in the Domain column:

+ +

+ +

This gives you extra information about the security status of the request:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IconMeaning
HTTPS
Weak HTTPS (for example, a weak cipher was used)
Failed HTTPS (for example, a certificate was invalid)
HTTP
Localhost
+ +

For weak and failed HTTPS requests, you'll see more details of the problem in the Security tab.

+ +

Cause column

+ +

The Cause column indicates what the cause of the request was. This is usually fairly obvious, and you can generally see the correlation between this and the Type column entry. The most common values are:

+ + + +
+

When a request was triggered by JavaScript, a small JS icon is shown to the left of the entry in the Cause column. Hovering over this displays a popup containing the stack trace for the request, to provide more clues as to why a request happened. Note that since Firefox 55, stack traces can be found in the Stack Trace tab of the {{anch("Network request details")}} panel instead.

+ +

+ +

You can then click on any of the entries in the popup to open up the relevant script in the Debugger pane.

+
+ +

Timeline

+ +

The request list also displays a timeline for the different parts of each request.

+ +

+ +

Each timeline is given a horizontal position in its row relative to the other network requests, so you can see the total time taken to load the page. For more details on the color-coding used here, see the section on the Timings page.

+ +

Starting in Firefox 45, the timeline also contains two vertical lines:

+ + + +

Filtering requests

+ +

You can filter requests by content type, by whether they are XMLHttpRequests or WebSocket requests, by URL, or by request properties.

+ +

Filtering by content type

+ +

To filter by content type, use the buttons in the toolbar.

+ +

Filtering XHR

+ +

To see only {{Glossary("XHR (XMLHttpRequest)", "XHR")}} requests, use the "XHR" button in the toolbar.

+ +

Filtering WebSockets

+ +
+

New in Firefox 48

+
+ +

To see only WebSocket connections, use the "WS" button in the toolbar.

+ +

To monitor the data exchanged in WebSocket connections, try the WebSocket Monitor add-on.

+ +

Filtering by URL

+ +

To filter by URL, use the search box in the toolbar. Click in the search box, or press Ctrl + F (or Cmd + F on a Mac), and start typing. The list of network requests will be filtered to include only requests that contain your filter string, in either the Domain or the File portions.

+ +

From Firefox 45,  you can filter requests that don't contain your filter string by prefixing your query with the "-" operator. For example, the query "-google.com" will show all requests that don't have "google.com" in their URL.

+ +

Filtering by properties

+ +
+

New in Firefox 55

+
+ +

To filter by specific request properties, use the search box in the toolbar. The search box recognizes specific keywords, which can be used to filter the requests by specific request properties. Those keywords are followed by a colon and a related filter value. The filter values are matched case insensitive. Prepending a minus (-) negates the filter. You can combine different filters together by seperating them with a space.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeywordMeaningExamples
status-codeShows resources that have the specific HTTP status code.status-code:304
methodShows resources that have were requested via the specific HTTP request method.method:post
domainShows resources coming from a specifc domain.domain:mozilla.org
remote-ipShows resources coming from a server with the specified IP.remote-ip:63.245.215.53
+ remote-ip:[2400:cb00:2048:1::6810:2802]
causeShows resources matching a specific cause type. The types can be found in the description of the cause column.cause:js
+ cause:stylesheet
+ cause:img
transferredShows resources having a specific transferred size or a transferred size close to the one specified.  k can be used as suffix for kilobytes and m for megabytes, e.g. the value 1k is equivalent to 1024.transferred:1k
sizeShows resources having a specific size (after decompression) or a size close to the one specified. k can be used as suffix for kilobytes and m for megabytes, e.g. the value 1k is equivalent to 1024.size:2m
larger-thanShows resources that are larger than the specified size in bytes. k can be used as suffix for kilobytes and m for megabytes, e.g. the value 1k is equivalent to 1024.larger-than:2000
+ -larger-than:4k
mime-typeShows resources that match the specified MIME type.mime-type:text/html
+ mime-type:image/png
+ mime-type:application/javascript
isis:cached and is:from-cache shows only resources coming from cache.
+ is:running shows only resources, which are currently being transferred.
is:cached
+ -is:running
schemeShows resources transferred via the given scheme.scheme:http
has-response-headerShows resources that contain the specified HTTP response header.has-response-header:cache-control
+ has-response-header:X-Firefox-Spdy
set-cookie-domainShows the resources that have a Set-Cookie header with a Domain attribute that matches the specified value.set-cookie-domain:.mozilla.org
set-cookie-nameShows the resources that have a Set-Cookie header with a name that matches the specified value.set-cookie-name:_ga
set-cookie-valueShows the resources that have a Set-Cookie header with a value that matches the specified value.set-cookie-value:true
regexpShows the resources having a URL that matches the given {{Glossary("regular expression")}}.regexp:\d{5}
+ regexp:mdn|mozilla
+ +

Context menu

+ +

Context-clicking on a row in the list displays a context menu with the following options:

+ + + +

Edit and Resend

+ +

This option opens an editor enabling you to edit the request's method, URL, parameters, and headers, and resend the request.

+ +

Open in New Tab

+ +

Resends the request in a new tab — very useful for debugging asynchronous requests.

+ +
+

Note: Since Firefox 59, POST requests are correctly resent as POST requests ({{bug(1220758)}}).

+
+ +

Copy as cURL

+ +

This option copies the network request to the clipboard as a cURL command, so you can execute it from a command line. The command may include the following options:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-X [METHOD]If the method is not GET or POST
--dataFor URL encoded request parameters
--data-binaryFor multipart request parameters
--http/VERSIONIf the HTTP version is not 1.1
-IIf the method is HEAD
-H +

One for each request header.

+ +

From Firefox 34, if the "Accept-Encoding" header is present, the cURL command will include --compressed instead of -H "Accept-Encoding: gzip, deflate". This means that the response will be automatically decompressed.

+
+ +

Copy/Save All As HAR

+ +
+

New in Firefox 41.

+
+ +

These options create an HTTP Archive (HAR) for all requests listed. The HAR format enables you to export detailed information about network requests. 'Copy All As HAR' copies the data to the clipboard, 'Save All As HAR' opens a dialog allowing you to save the archive to disk.

+ +

Network request details

+ +

Clicking on a row displays a new pane in the right-hand side of the network monitor, which provides more detailed information about the request.

+ +

+ +

The tabs at the top of this pane enable you to switch between the following pages:

+ + + +

Clicking the icon at the right-hand end of the toolbar closes the details pane and returns you to the list view.

+ +

Headers

+ +

This tab lists basic information about the request:

+ +

+ +

This includes:

+ + + +

You can filter the headers that are displayed:

+ +

+ +
+

New in Firefox 54

+
+ +

From Firefox 54 onwards, you will see a question mark icon next to each header in the Status code row — this is a link to more information about that particular status code, in the MDN documentation of the HTTP headers.

+ +

Cookies

+ +

This tab lists full details of any cookies sent with the request or response:

+ +

+ +

As with headers, you can filter the list of cookies displayed.

+ +

Params

+ +

This tab displays the GET parameters and POST data of a request:

+ +

+ +

Response

+ +

The complete content of the response. If the response is HTML, JS, or CSS, it will be shown as text:

+ +

+ +

If the response is JSON, it will be shown as an inspectable object.

+ +

If the response is an image, the tab displays a preview:

+ +

+ +

HTML preview

+ +

From Firefox 59 onwards, if the response is HTML, a preview of the rendered HTML appears inside the Response tab, above the response payload.

+ +

+ +

Timings

+ +

The Timings tab breaks a network request down into the following subset of the stages defined in the HTTP Archive specification:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
Blocked +

Time spent in a queue waiting for a network connection.

+ +

The browser imposes a limit on the number of simultaneous connections that can be made to a single server. In Firefox this defaults to 6, but can be changed using the network.http.max-persistent-connections-per-server preference. If all connections are in use, the browser can't download more resources until a connection is released.

+
DNS resolutionTime taken to resolve a host name.
ConnectingTime taken to create a TCP connection.
SendingTime taken to send the HTTP request to the server.
WaitingWaiting for a response from the server.
ReceivingTime taken to read the entire response from the server (or cache).
+ +

It presents a more detailed, annotated, view of the timeline bar for that request showing how the total wait time is split into the various stages:

+ +

+ +

Security

+ +

If the site is being served over HTTPS, you get an extra tab labeled "Security". This contains details about the secure connection used including the protocol, the cipher suite, and certificate details:

+ +

+ +

The Security tab shows a warning for security weaknesses. Currently it warns you about two weaknesses:

+ +
    +
  1. Using SSLv3 instead of TLS
  2. +
  3. Using the RC4 cipher
  4. +
+ +

+ +

Stack trace

+ +

Since Firefox 55, stack traces are shown in the Stack Trace tab, for responses that have a stack trace of course.

+ +

+ +

Pausing and resume network traffic recording

+ +

In Firefox 58 and above, the Network Monitor has a button that pauses and resumes recording of the current page's network traffic. This is useful in situations where, for example, you are trying to get a stable view of a page for debugging purposes, but under normal circumstances the view keeps evolving due to persistent network requests. The pause button allows you to look at a certain snapshot.

+ +

The button can be found at the far left of the main Network Monitor toolbar, and looks like a typical pause button — .

+ +

You can see it here in context:

+ +

+ +

Once pressed, the button changes to a play icon, and you can toggle network traffic recording back on by pressing it again.

+ +

Performance analysis

+ +

The Network Monitor includes a performance analysis tool, to help show you how long the browser takes to download the different parts of your site.
+
+ To run the performance analysis tool click the stopwatch icon in the toolbar.

+ +

(Alternatively, if you have only just opened the Network Monitor, so it's not yet populated with the list of requests, you'll get a stopwatch icon in the main window.)

+ +

The Network Monitor then loads the site twice: once with an empty browser cache, and once with a primed browser cache. This simulates the first time a user visits your site, and subsequent visits. It displays the results for each run side by side, or vertically if the browser window is narrow:

+ +

+ +

The results for each run are summarised in a table and a pie chart. The tables group resources by type, and show the total size of each resource and the total time it took to load them. The accompanying pie chart shows the relative size of each resource type.

+ +

To get back to the Network Monitor's list of network requests click the "Back" button on the left.

+ +

Clicking on a slice of the pie takes you to the Network Monitor for that run, with a filter automatically applied to see only that resource type.

diff --git a/files/zh-tw/tools/page_inspector/how_to/examine_grid_layouts/index.html b/files/zh-tw/tools/page_inspector/how_to/examine_grid_layouts/index.html new file mode 100644 index 0000000000..af308f0b0b --- /dev/null +++ b/files/zh-tw/tools/page_inspector/how_to/examine_grid_layouts/index.html @@ -0,0 +1,30 @@ +--- +title: CSS 格線檢測器:檢查格線布局 +slug: Tools/Page_Inspector/How_to/Examine_grid_layouts +translation_of: Tools/Page_Inspector/How_to/Examine_grid_layouts +--- +

在規則畫面的格線圖標

+ +
Firefox 52 新功能
+ +

自 Firefox 52 以後的開發者工具,可以針對格線布局,要求檢測器覆蓋上格線指示。

+ +

在擁有 display: grid 的元素內,規則畫面會出現格線圖標:。點選圖標以覆蓋顯示的格線,包括了線與軌道:

+ +

就算選擇其他元素,覆蓋還是會出現,因此你可以編輯 CSS 的格線單元、並檢查格線如何做動。

+ +

{{EmbedYouTube("lzjIe-8WhiQ")}}

+ +

格線布局面板

+ +
Firefox 56 新功能
+ +

Firefox 56 基於前述的格線功能,提供了嶄新的面板。充分的選項及資訊,有利於格線偵錯。你可以在 Powerful New Additions to the CSS Grid Inspector in Firefox Nightly 查看所有需要的資訊。

+ +

{{EmbedYouTube("dU7xtnzfqxQ")}}

+ +

參見

+ + diff --git a/files/zh-tw/tools/page_inspector/how_to/index.html b/files/zh-tw/tools/page_inspector/how_to/index.html new file mode 100644 index 0000000000..69184c59cc --- /dev/null +++ b/files/zh-tw/tools/page_inspector/how_to/index.html @@ -0,0 +1,11 @@ +--- +title: 如何…… +slug: Tools/Page_Inspector/How_to +tags: + - NeedsTranslation + - TopicStub +translation_of: Tools/Page_Inspector/How_to +--- +

這裡蒐集了針對各種「如何……」的文章連結。這些文章連結會連到詳述有關「如何……」所需的技術。

+ +

{{ ListSubpages () }}

diff --git a/files/zh-tw/tools/page_inspector/index.html b/files/zh-tw/tools/page_inspector/index.html new file mode 100644 index 0000000000..dea2fd5139 --- /dev/null +++ b/files/zh-tw/tools/page_inspector/index.html @@ -0,0 +1,50 @@ +--- +title: 頁面檢測器 +slug: Tools/Page_Inspector +translation_of: Tools/Page_Inspector +--- +

使用頁面檢測器檢測並修改網頁的 HTML 與 CSS。

+ +

You can examine pages loaded in the local copy of Firefox or in a remote target such as Firefox for Android. See remote debugging to learn how to connect the developer tools to a remote target.

+ +
+

用戶介面導覽

+ +

To find your way around the Inspector, here's a quick tour of the UI.

+ +
+

如何

+ +

想知道頁面檢測器可意做什麼,請參考以下教學:

+ +
+ +
+ +
+

參考

+ +
+ +
diff --git a/files/zh-tw/tools/performance/allocations/index.html b/files/zh-tw/tools/performance/allocations/index.html new file mode 100644 index 0000000000..e124139c49 --- /dev/null +++ b/files/zh-tw/tools/performance/allocations/index.html @@ -0,0 +1,86 @@ +--- +title: Allocations +slug: Tools/Performance/Allocations +translation_of: Tools/Performance/Allocations +--- +
+

The Allocations view in the Performance tool shows you which functions in your page are allocating the most memory over the course of the profile.

+ +

For performance this is important mostly because allocating a lot of memory, or making a lot of allocations, can trigger garbage collection. This in turn can hurt the responsiveness of a page.

+
+ +
+

The Allocations view is new in Firefox 46.

+
+ +

To enable the Allocations view, you must check "Record Allocations" in the Performance tool settings, before recording a profile. Then record a profile as usual, and you will see a new tab labeled "Allocations" in the toolbar:

+ +

{{EmbedYouTube("Le9tTo7bqts")}}

+ +

Anatomy of the allocations view

+ +

The allocations view looks something like this:

+ +

+ +

The allocations view periodically samples allocations that are made over the recording. Each row represents a function in which at least one allocation-sample was taken during the recording.

+ +

It includes the following columns:

+ + + +

Rows are sorted by the "Self Bytes" column.

+ +

So in the example above:

+ + + +

Next to each function name is a disclosure arrow. Click this to see the places this function was called from:

+ +

+ +

Here you can see that signalLater() was called from two places: removeInner() and setSelectionInner(). In this way you can walk back up the call stack, and understand better the context for these allocations.

+ +

Self Cost and Total Cost

+ + + +

You'll see that there are separate sets of columns for "Self" and for "Total". "Self" records samples taken only in this function. "Total" records samples taken in this function or in functions called by this function. At the top level, these are always the same, since the view presents "leaf" functions at the top level (that is, it presents an inverted view of the call stack). But if you start walking back up the call stack, you'll see the difference:

+ +

+ +

Here, 8904 samples were taken in signalLater(). But signalLater() was called from two places: removeInner() and setSelectionInner(). Both these functions have 0 in Self Count, meaning that no allocations were seen directly in these functions. However, removeInner() has 8901 in Total Count, while setSelectionInner() has just 3 in Total Count. This is telling us that, of the 8904 allocations seen in signalLater(), all but three came through the removeInner() branch.

+ +

Allocations and garbage collection

+ +

Of course, the memory allocated by a site is in itself useful information to know. But the main connection between the allocation profile of a site and its responsiveness is the cost of garbage collection (GC).

+ +

With a garbage-collected language, like JavaScript, the runtime periodically needs to walk the heap looking for objects that are no longer reachable, and then freeing the memory they occupy. While GC events like this are executing, the JavaScript engine must be paused, so your program is suspended and will be completely unresponsive.

+ +

To reduce the impact on responsiveness, SpiderMonkey (the JavaScript engine in Firefox) can perform GC in small increments, letting the program run in between. Sometimes, though, it needs to perform a full non-incremental collection, and the program has to wait for it to finish.

+ +

GC events are shown as red markers in the Waterfall view, and are a big red flag for responsiveness,  sometimes running for hundreds of milliseconds:

+ +

+ +

If you're seeing GC events in your site's performance profile, what can you do? SpiderMonkey uses a complex set of heuristics to decide when to do what sort of garbage collection.

+ +

In general, though: allocation pressure - allocating a lot of memory, or allocating memory at a high rate - makes SpiderMonkey more likely to run garbage collection, and more likely to run full, non-incremental garbage collection.

+ +

If a GC event was caused by allocation pressure, then the sidebar on the right of the marker in the Waterfall view contains a link labeled "Show allocation triggers". If you click this link, the devtools switches to the allocations view, and selects the region of time from the end of the last GC cycle to the start of the one you clicked on. This shows you all the allocations that collectively triggered this GC event:

+ +

{{EmbedYouTube("tO5ovD9Jw4k")}}

+ +

If you're seeing these problems, consider whether you can reduce the number or size of the allocations you're making here. For example:

+ + diff --git a/files/zh-tw/tools/performance/frame_rate/index.html b/files/zh-tw/tools/performance/frame_rate/index.html new file mode 100644 index 0000000000..3c2c61467a --- /dev/null +++ b/files/zh-tw/tools/performance/frame_rate/index.html @@ -0,0 +1,58 @@ +--- +title: Frame rate +slug: Tools/Performance/Frame_rate +translation_of: Tools/Performance/Frame_rate +--- +
+

幀速率是一個網站的響應的量度。低或不一致的幀速率可以使一個網站出現反應遲鈍或janky,鬧了不好的用戶體驗。

+ +

60fps的幀頻是平穩的性能目標,給你所有需要響應某些事件更新的16.7毫秒時間預算。

+ +

在性能工具的幀速率圖表顯示你的幀速率在錄音的過程中。它給你,你的網站可能是有問題,使您能夠使用其他工具進行更深入的分析的快速指示。

+
+ +

幀速率和響應

+ +

幀速率是指視頻設備可產生圖像(或幀)的速率。這是從電影和遊戲最熟悉的,但現在被廣泛用作網站和Web應用程序性能的措施。

+ +

在Web性能,幀封裝瀏覽器需要做的,以更新和重繪屏幕的工作。幀速率是最明顯適用於動畫:如果幀速率太低,動畫將具有生澀外觀,而更快的幀速率會更順暢。但幀速率也可用作站點的響應作為用戶的一般衡量與其交互。

+ +

例如,如果移動鼠標在某個頁面元素觸發一些JavaScript改變元素的外觀,並觸發回流和重繪,那麼所有這些工作需要在該框架完成。如果時間過長的瀏覽器來處理框架,那麼瀏覽器就會瞬間出現反應遲鈍(janky)。

+ +

同樣,如果通過網頁滾動涉及到很多複雜的頁面更新和瀏覽器無法跟上一個可接受的幀速率,滾動頁面會出現遲緩或偶爾會凍結。

+ +

在一般情況下,高和一致的幀速率將使用戶與網站的互動更愉快和吸引力。

+ +
+

60fps的幀頻被算為是平穩的性能目標,給你所有的需要在應對某些事件做出同步更新16.7毫秒的時間預算。

+ +

然而,一致性就顯得尤為重要:如果你不能提供60fps的,它是更好地實現較低的幀速率更穩定,並避免幀速率造成該網站凍結突然驟降。

+
+ +

幀速率圖

+ +

幀速率曲線圖中找到記錄概述性能工具的一部分。這需要當瀏覽器完成一幀的時間戳,並使用該跟踪幀速率的在記錄的過程中。

+ +

x軸是時間上的信息期間,和有三個註釋:最大幀速率,平均幀速率和最低幀速率。

+ +

使用幀速率圖

+ +

幀速率曲線的巨大價值在於,像Web控制台,它給你,你的網站可能是有問題,使您能夠使用其他工具進行更深入的分析的快速指示。例如,這裡有一個性能配置截圖:

+ +

+ +

你可以看到,平均幀速率是相當健康的,但有三個點,其中幀頻為倒塌數十毫秒。這肯定會導致明顯的口吃的,在網頁中播放任何動畫。

+ +

幀速率圖表相關聯的瀑布摘要直接上面,並且有我們可以看到,在第一兩滴在幀速率是相關的橙色酒吧,其中表示時間花費在執行的JavaScript。

+ +

如果我們選擇了記錄這些片段之一,主瀑布視圖下它被放大到它,我們可以看到這是造成問題的功能:

+ +

+ +

我們從一個點擊事件的阻止主線程170毫秒的JavaScript函數。

+ +

它的功能有關係嗎?切換到火焰圖表看到在那個點調用堆棧:

+ +

+ +

有問題的函數被調用doPointlessComputationsInMainThread() 並且它在“main.js”定義。為了解決這個問題,我們可能會考慮將其分割成塊,並運行裡面件requestAnimationFrame,甚至運行在一個全功能的工人密集的JavaScript本文介紹如何使用這樣的策略,以修復因長期運行的JavaScript同步響應的問題。

diff --git a/files/zh-tw/tools/performance/index.html b/files/zh-tw/tools/performance/index.html new file mode 100644 index 0000000000..23ee0e1b61 --- /dev/null +++ b/files/zh-tw/tools/performance/index.html @@ -0,0 +1,82 @@ +--- +title: 效能 +slug: Tools/Performance +tags: + - 效能 +translation_of: Tools/Performance +--- +

效能工具給你網站整體反應度、JavaScript 與版面效能的洞察資訊。你可以使用效能工具在一段時間中錄製、測試你的網站的效能。這個工具會顯示瀏覽器在繪製你的網站時的所作之事,其總覽以及對應之畫框率的圖表。

+ +

你可以在這三個子工具中,了解效能數據多方面的深入資訊:

+ + + +

{{EmbedYouTube("WBmttwfA_k8")}}

+ +
+

由此開始

+ +
+
+
+
UI Tour
+
+

從這裡開始探索效能工具,對介面的快速導覽。

+
+
+
+ +
+
+
How to
+
最基本的任務:開啟工具、建立、儲存、載入與設定錄製。
+
+
+
+ +
+

效能工具的元件

+ +
+
+
+
Frame rate
+
了解你網站的整體回應速度。
+
Call Tree
+
尋找你網站中的 JavaScript 瓶頸。
+
+
+ +
+
+
Waterfall
+
了解當用戶與你的網站互動時,瀏覽器在做些什麼。
+
Flame Chart
+
看看錄製過程中某個 JavaScript 函式在那時執行。
+
+
+
+ +
+

應用場景

+ +
+
+
+
Animating CSS properties
+
使用 Waterfall 了解瀏覽器如何更新頁面,各種不同的 CSS 屬性動畫如何影響效能。
+
 
+
+
+ +
+
+
Intensive JavaScript
+
使用格率與 Waterfall 工具,以調查長時間執行的 JavaScript 帶來的效能問題,並了解如何使用 worker 來幫助解決問題。
+
+
+
diff --git a/files/zh-tw/tools/remote_debugging/firefox_for_android/index.html b/files/zh-tw/tools/remote_debugging/firefox_for_android/index.html new file mode 100644 index 0000000000..c2cd1e5e72 --- /dev/null +++ b/files/zh-tw/tools/remote_debugging/firefox_for_android/index.html @@ -0,0 +1,77 @@ +--- +title: Remotely debugging Firefox for Android +slug: Tools/Remote_Debugging/Firefox_for_Android +translation_of: Tools/Remote_Debugging/Firefox_for_Android +--- +

This guide explains how to use remote debugging to inspect or debug code running in Firefox for Android over USB.

+

+

This guide's split into two parts: the first part, "Prerequisites" covers stuff you only need to do once, while the second part, "Connecting", covers stuff you need to do each time you connect the device. 

+

Prerequisites

+

First, you'll need:

+ +

ADB setup

+

Next, you'll need to get the desktop and the Android device talking to each other using the adb command-line tool.

+

On the Android device

+ +

On the desktop

+ +

To check it worked, open up a command shell on the desktop and type:

+
adb devices
+

You should see some output like:

+
List of devices attached
+51800F220F01564 device
+
+

(The long hex string will be different.)

+

If you do, then adb has found your device and you've successfully set up ADB.

+

Enable remote debugging

+

Next, you need to enable remote debugging on both the Android device and the desktop.

+

Firefox for Android 24 and earlier

+

To enable remote debugging on the device, you need to set the devtools.debugger.remote-enabled preference to true.

+

Go to about:config in Firefox for Android, type "devtools" into the search box and press the Search key. You'll see all the devtools preferences. Find the devtools.debugger.remote-enabled preference, and press "Toggle".

+

+

Firefox for Android 25 and later

+

On Firefox for Android 25 and later, there's a menu item to enable remote debugging. Open the menu, select "Settings", then "Developer tools" (on some Android devices you may need to select "More" to see the "Settings" option). Check the "Remote debugging" box:

+

+

The browser will display a notification reminding you to set up port forwarding, which we'll do later on.

+

On the desktop

+

On the desktop, remote debugging is enabled by a setting in the Toolbox. Open the Toolbox, click the "Settings" button in the toolbar, and check "Enable remote debugging" in the Settings tab:

+

+
+ If you're using a version of Firefox older than 27, you'll need to restart the browser for the setting to take effect.
+

You'll then see a new option in the Web Developer menu labeled "Connect...":

+

+

Connecting

+

Now you can connect the remote debugging tools to the device. First, attach the device to the desktop with a USB cable, if you haven't already.

+

On the desktop

+

Go to a command prompt, and type:

+
adb forward tcp:6000 tcp:6000
+

(If you've changed the value the Android device uses for a debugging port, you'll need to adjust this accordingly.)

+

For Firefox OS, type:

+
adb forward tcp:6000 localfilesystem:/data/local/debugger-socket
+

You'll need to reissue this command each time you physically attach desktop and device with the USB cable.

+

Then go to the Web Developer menu on Firefox, and select "Connect...". You'll see a page that looks like this:

+

Unless you've changed the port numbers, choose 6000 and press the "Connect" button.

+

On the Android device

+

Next you'll see a dialog on the Android device asking you to confirm the connection:

+

Press "OK". The desktop waits for a few seconds to give you time to acknowledge this dialog: if it times out, just press "Connect" in the desktop dialog again.

+

On the desktop

+

Next, the desktop shows you a dialog that looks something like this:

+

This is asking whether you want to debug web content running in a browser tab, or to debug the browser code itself.

+ +

Let's choose to attach to the mozilla.org website. The Toolbox will open in its own window, attached to the Firefox for Android tab that's currently hosting mozilla.org:

+

+

The Toolbox, and the tools it hosts, work in just the same way as they do when attached to local content.

diff --git a/files/zh-tw/tools/remote_debugging/index.html b/files/zh-tw/tools/remote_debugging/index.html new file mode 100644 index 0000000000..c7cad963ed --- /dev/null +++ b/files/zh-tw/tools/remote_debugging/index.html @@ -0,0 +1,22 @@ +--- +title: Remote Debugging +slug: Tools/Remote_Debugging +translation_of: Tools/Remote_Debugging +--- +

You can use the Firefox developer tools on your desktop to debug code running remotely: in a different process on the same device or on a completely different device. To do this you use Firefox to attach the Toolbox to the remote process, and the Toolbox is then launched in its own window. At the moment the following tools support remote debugging:

+ +

Firefox for Android

+

Remotely debugging Firefox for Android describes how to connect to Firefox on an Android device over USB.

+

Firefox for Metro

+

Remotely debugging Firefox for Metro describes how to use desktop Firefox to debug code running in Windows 8 (Metro-style) Firefox.

+

Firefox OS

+

Using the App Manager includes instructions for connecting the Firefox developer tools to the Firefox OS simulator or to a Firefox OS device.

+

Thunderbird

+

Remotely debugging Thunderbird explains how a combination of Firefox and Thunderbird can be used to debug code running in Thunderbird.

diff --git a/files/zh-tw/tools/responsive_design_mode/index.html b/files/zh-tw/tools/responsive_design_mode/index.html new file mode 100644 index 0000000000..fb931bd52f --- /dev/null +++ b/files/zh-tw/tools/responsive_design_mode/index.html @@ -0,0 +1,184 @@ +--- +title: 適應性設計模式 +slug: Tools/Responsive_Design_Mode +translation_of: Tools/Responsive_Design_Mode +--- +
+

本頁在講述 Firefox 52 及其後的適應性設計模式。要找之前的版本,請參閱適應性設計模式(Firefox 52 之前)。這個版本的適應性設計模式還要啟動 Firefox multi-process support (e10s)。如果沒有啟動的話,你還是會看到舊版的適應性設計模式。

+
+ +

適應性設計(響應式設計)是指能令大多數不同設備,能有著相似效果的網站設計實做。特別是指手機平板,也能有如同桌機筆電般的效果。

+ +

在此,最重要的影響因素是螢幕寬度。但也有其他諸如像素的密度、有沒有支援觸控之類的因素。適應性設計模式提供了這些因素的簡單模擬法、以觀察網站在不同的設備下,會是什麼樣子。

+ +

切換適應性設計模式

+ +

有三種方法能切換到適應性設計模式:

+ + + +

使用適應性設計模式

+ +

啟動適應性設計模式後,網頁的內容會縮成特定設備的尺寸。初始是 320 x 480 像素:

+ +

+ +

你可以獨立切換顯示開發者工具的位置:

+ +

當適應性設計模式啟動時,你可以在大小調整後的區域內,如同平常一般地瀏覽。

+ +

設備選擇

+ +

在視區上方你會看到「尚未選擇裝置」:點選此欄就能看到裝置清單。選一個裝置,適應性設計模式就會設定以模擬該裝置的這些屬性:

+ + + +

另外,Firefox 還會設定用戶代理的 HTTP 請求標頭,以標定自己為該裝置的預設瀏覽器。例如說,當你選了 iPhone,Firefox 就會把自己標為 Safari。navigator.userAgent 屬性也會成為該值。

+ +

{{EmbedYouTube("JNAyKemudv0")}}

+ +

選單所列出的裝置,只是選定裝置的子集。在該選單的底下有個「編輯清單…」的選項。選定以後就會看到所有選項,還能點選想要在選單出現的設備選項。設置的相關聯裝備與數值,是取自於 https://github.com/mozilla/simulated-devices

+ +

儲存自訂設備

+ +

54 版以後的 Firefox 允許你自訂設備。各設備都會有:

+ + + +

另外,你還能透過把滑鼠停在設備名,以瀏覽該設備的屬性資訊。他們會以快顯視窗的形式出現。

+ +

+ +

裝置控制

+ +

你也能給多數設備支援自訂屬性。

+ +

設定螢幕大小

+ +

要設定螢幕大小,請點擊視窗下面的數值並修改之:

+ +

+ +

你也可以點右下角的三角形後不放,以自行調整你需要的大小。

+ +

設定設備像素比例

+ +

要自訂備像素比例,請點擊「DPR」標籤並選定想要的值。

+ +

+ +

模擬觸控事件切換

+ +

要啟動或關閉觸控事件,請點選手指圖示的圖標:

+ +

在觸控事件啟動時,滑鼠事件會被轉為觸控事件

+ +

開啟觸控事件會強制頁面重啟,因為許多頁面會在載入的時候檢查觸控,若支持觸控事件的話,也將增加 event handler。

+ +

切換方向

+ +

要讓螢幕在直放與橫放間切換,請點選設備選擇器旁邊的圖標:

+ +

+ +

網路限速

+ +

若你只在網速很快的環境下測試,你網站可能會在網速慢的環境下碰上問題。在適應性設計模式裡面,你可以叫瀏覽器用大略的速度,模擬不同的上網方案。

+ +

這些方案會模擬:

+ + + +

下方表格列出了各網路方案的大略數值,但請不要用這個功能做精確的性能測量:此功能目的,是給出不同條件下的用戶體驗。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
選取下載速度上載速度最小延遲(毫秒)
GPRS50 KB/s20 KB/s500
Regular 2G250 KB/s50 KB/s300
Good 2G450 KB/s150 KB/s150
Regular 3G750 KB/s250 KB/s100
Good 3G1.5 MB/s750 KB/s40
Regular 4G/LTE4 MB/s3 MB/s20
DSL2 MB/s1 MB/s5
Wi-Fi30 MB/s15 MB/s2
+ +

要選擇網路的話,請點選標示著「不限速」的標籤:

+ +

+ +

擷圖

+ +

要擷取視口的螢幕畫面,請點擊相機圖示:

+ +

+ +

畫面會放在 Firefox 預設的下載目錄。

+ +

Firefox 53 以後,若你在設定頁面點選「將畫面擷圖拍到剪貼簿」,螢幕擷圖就會複製到作業系統的剪貼簿。

diff --git a/files/zh-tw/tools/scratchpad/index.html b/files/zh-tw/tools/scratchpad/index.html new file mode 100644 index 0000000000..880b0c13ee --- /dev/null +++ b/files/zh-tw/tools/scratchpad/index.html @@ -0,0 +1,109 @@ +--- +title: 程式碼速記本 +slug: Tools/Scratchpad +translation_of: Archive/Tools/Scratchpad +--- +

程式碼速記本(Scratchpad)提供使用 JavaScript 程式碼實驗的環境。您可以編寫,運行和檢查的程式碼與網頁互動的結果。

+ +

不同於網頁主控台,這是專為在同一時間解釋的一行程式碼,便簽讓您編輯較大的 JavaScript 程式碼塊,然後根據您希望如何使用輸出以各種方式執行。

+ +

{{EmbedYouTube("Pt7DZACyClM")}}

+ +

用法

+ +

打開程式碼速記本

+ +

要打開「程式碼速記本」窗口的話有很多辦法:

+ + + +

這將打開一個程式碼速記本窗口。

+ +

在工具箱開啟程式碼速記本

+ +
Firefox 47 引入。
+ +

From Firefox 47, you can open Scratchpad inside the Toolbox. First you need to check "Scratchpad" in the "Default Firefox Developer Tools" section of the Settings page.

+ +

Now Scratchpad will be available in the Toolbox, alongside other tools like the Page Inspector and the Web Console. This is especially useful in split Console mode: you can use Scratchpad for a persistent, multiline editor, and the Console to interact with the page.

+ +

編輯

+ +

程式碼速記本窗口看起來像這樣(在 macOS 選單列在螢幕的頂部):

+ +

便簽本的屏幕截圖

+ +

檔案選單提供選項來儲存和載入JavaScript程式碼片段,因此,如果你喜歡,你可以在以後重用程式碼。

+ +

程式碼補全

+ +

程式碼速記本整合了ternjs ( javascript程式碼分析引擎 ),並使用該提供自動補全提示與包含在當前的符號資訊的視窗。要列出自動補全提示,按 Ctrl+Space

+ +

例如,嘗試輸入d,然後按 Ctrl+Space 。你會看到自動補全的視窗盒,如下圖:

+ +

提示左邊的每個圖標為目前提示的類型,目前高亮的提示會自動彈出更多資訊。使用來循環高亮的提示,並使用EnterTab 來選擇目前高亮的提示。

+ +

內嵌說明

+ +

如果想看到內嵌說明視窗,可以在將滑鼠指標(cursor)0移到標識符的位置,並按下Ctrl + Shift + Space。例如:如果你先輸入document.addEventListener,然後再按下Ctrl + Shift + Space,你將會看到一個彈出視窗,顯示該函數的語法和使用說明。

+ +

在彈出視窗中的「[文件]」連結,點擊後,可直接連結到MDN對應符號的說明文件網頁。

+ +

執行

+ +

一旦你寫完你的代碼,選擇要運行的程式碼。如果不選擇任何內容,視窗中的所有程式碼將被執行。然後透過「執行」選單或右鍵選單,來選擇你想要的執行方式。程式碼在當前的分頁中執行。任何宣告在函式(function)之外的變數將被加入到當前分頁的全域物件。

+ +

選單中有四個執行選項可以選擇

+ +

執行

+ +

當你選取「執行」選項時, 被選取的程式碼將會被執行. 你會將此選項用於執行一個函式或一段操作頁面內容的程式碼,而不需要看到執行後的輸出。

+ +

檢測

+ +

「檢測」選項執行程式碼的方法就像執行選項; 然而,程式碼返回後,object inspector會打開讓你檢查返回值。

+ +

例如,如果你輸入代碼:

+ +
window
+
+ +

然後選擇「檢測」,object Inspector 看起來是這樣的:

+ +

在便簽中檢查對象

+ +

顯示

+ +

「顯示」選項執行所選取的程式碼,然後直接將結果插入到你的程式碼速記本編輯器視窗中,作為一個註解,所以你可以使用它作為一個REPL

+ +

重新載入並執行

+ +

重新載入和執行選項僅在執行選單中。它首先重新載入頁面,然後執行該程式碼時,頁面上的「load」事件觸發。這適用於在剛開始的環境來執行程式碼。

+ +

在瀏覽器環境中執行程式碼速記本

+ +

你可以在瀏覽器環境運行程式碼速記本,而不是在特定網頁的環境中。如果您正在使用火狐本身或開發附加元件,這非常有用。要做到這一點,要勾選「啟用瀏覽器chrome與附加元件除錯工具箱」設定在開發者工具設置中。完成勾選後,執行程式碼速記本中,「環境」選單會有「瀏覽器」選項; 選擇「瀏覽器」選項後,你的範圍會是整個瀏覽器,而不僅僅是網頁的內容,此時,你將可以檢測一些全域變數來看:

+ +
window
+/*
+[ChromeWindow]
+*/
+
+gBrowser
+/*
+[object XULElement]
+*/
+ +

當程式碼速記本含有下列程式碼在第一行時,程式碼速記本會將執行環境設為整個瀏覽器
+ // -sp-context: browser

+ +

鍵盤快捷鍵

+ +

{{ Page ("zh-TW/docs/tools/Keyboard_shortcuts", "scratchpad") }}

+ +

源始碼編輯器的快捷鍵

+ +

{{ Page ("zh-TW/docs/tools/Keyboard_shortcuts", "source-editor") }}

diff --git a/files/zh-tw/tools/settings/index.html b/files/zh-tw/tools/settings/index.html new file mode 100644 index 0000000000..efcc04ce25 --- /dev/null +++ b/files/zh-tw/tools/settings/index.html @@ -0,0 +1,185 @@ +--- +title: Settings +slug: Tools/Settings +translation_of: Tools/Settings +--- +

{{ToolsSidebar}}

+ + + +

Beginning with Firefox 62, the icon to open Developer Tools settings has been moved into a menu accessed by clicking/touching ... (the elipsis) on the right of the tab.

+ +

+ +

The menu includes settings to control the location of the Developer Tools. You can choose between the default setting at the bottom of the windows, or move the tools to the left or right side of the screen. These settings are particularly useful if you have a widescreen monitor. You can also choose to open the tools in a separate window.

+ +

Show split console adds a section at the bottom of the tools showing the console. It makes visible the command line and one or two lines of the console output.

+ +

+ +

The rest of the settings are on the Developer Tools Settings Pane. To see the settings, open any of the Developer Tools, and then:

+ + + +

The Settings pane looks something like this:

+ +

Depicts the Toolbox options

+ +

Categories

+ +

Default Firefox Developer Tools

+ +

This group of checkboxes determines which tools are enabled in the toolbox. New tools are often included in Firefox but not enabled by default.

+ +

Available Toolbox Buttons

+ +

This group of checkboxes determines which tools get an icon in the Toolbox's toolbar.

+ +

As of Firefox 62, if the option to "Select an iframe as the currently targeted document" is checked, the icon will appear in the toolbar while the Settings tab is displayed, even if the current page doesn't include any iframes.

+ +

Note that in Firefox 52 we removed the checkbox to toggle the "Select element" button. The "Select element" button is now always shown.

+ +

Themes

+ +

This enables you to choose one of two themes.

+ + + +

Common preferences

+ +

Settings that apply to more than one tool. There's just one of these:

+ +
+
Enable persistent logs
+
A setting to control whether or not the Web Console and Network Monitor clear their output when you navigate to a new page.
+
+ +
+

If Common Preferences is not included in the Settings,  Web Console logs can be persisted  by using the 'about:config'  url in browser address bar, searching for: 'devtools.webconsole.persistlog' then toggling this value to true

+
+ +

Inspector

+ +
+
Show browser styles
+
A setting to control whether styles applied by the browser (user-agent styles) should be displayed in the Inspector's Rules view. Note that this setting is independent of the "Browser styles" checkbox in the Inspector's Computed view.
+
Truncate DOM attributes
+
By default, the Inspector truncates DOM attributes that are more than 120 characters long. Uncheck this box to prevent this behavior. This setting works by toggling the about:config preference "devtools.markup.collapseAttributes". To change the threshold at which attributes are truncated, you can edit the about:config preference "devtools.markup.collapseAttributeLength".
+
Default color unit
+
A setting to control how colors are represented in the inspector: +
    +
  • Hex
  • +
  • HSL(A)
  • +
  • RGB(A)
  • +
  • color name
  • +
  • As authored.
  • +
+
+
Enable layout panel
+
Enable the experimental layout panel. This setting only exists in Firefox Nightly.
+
+ +

Web Console

+ +
+
Enable timestamps
+
Controls whether the Web Console displays timestamps. The Web Console defaults to hiding timestamps.
+
Enable new console frontend
+
Switch to the experimental new console. This setting only exists in Firefox Nightly.
+
+ +

Debugger

+ +
+
Enable Source Maps
+
Enable source map support in the debugger.
+
Enable new debugger frontend
+
Enable the new debugger. This setting only exists in Firefox Nightly.
+
+ +

Style Editor

+ +
+
Show original sources
+
When a CSS preprocessor supporting source maps is used, this enables the Style Editor to display the original, preprocessor, sources rather than the generated CSS. Learn more about Style Editor support for CSS source maps. With this setting checked, the Page Inspector Rules view will also provide links to the original sources.
+
Autocomplete CSS
+
Enable the Style Editor to offer autocomplete suggestions.
+
+ +

Screenshot Behavior

+ +
+
Screenshot to clipboard
+
When you click the icon for the Screenshot tool, copy the screenshot image to the clipboard (the image will still be saved to your Downloads directory). New in Firefox 53.
+
Play camera shutter sound
+
When you click the icon for the Screenshot tool, play a shutter sound. New in Firefox 53.
+
+ +

Editor Preferences

+ +

Preferences for the CodeMirror source editor, which is included in Firefox and used by several developer tools, including Scratchpad and the Style Editor.

+ +
+
Detect indentation
+
Auto-indent new lines based on the current indentation.
+
Autoclose brackets
+
Determines whether typing an opening character like [ or { will cause the editor to insert the matching closing character ] or } for you.
+
Indent using spaces
+
When checked, indentation will be performed using spaces, when off, the editor will use tabs instead.
+
Tab size
+
The frequency of tab stops in the editor. Select 2, 4, or 8.
+
Keybindings
+
Choose the default CodeMirror keybindings or keybindings from one of several popular editors: +
    +
  • Vim
  • +
  • Emacs
  • +
  • Sublime Text
  • +
+
+
+ +

Advanced settings

+ +
+
Show Gecko platform data
+
A setting to control whether or not profiles should include Gecko platform symbols.
+
+ +
+
Disable HTTP Cache
+
Disable the browser HTTP cache to simulate first-load performance in all tabs that have the Toolbox open. This setting persists, meaning that if it is set, caching will be disabled whenever you reopen the devtools. Caching is re-enabled when the devtools are closed. Note that service workers are not affected by this option. +
Note that this option was called "Disable Cache" in Firefox versions previous to 49, but it was renamed to make it clearer that this affects the HTTP cache, and not Service Workers/the Cache API.
+
+
Disable JavaScript
+
Reload the current tab with JavaScript disabled.
+
Enable Service Workers over HTTP
+
Enable Service Worker registrations from insecure websites.
+
Enable browser chrome and add-on debugging toolboxes
+
Enable you to use developer tools in the context of the browser itself, and not only web content.
+
Enable remote debugging
+
Enable the developer tools to debug remote Firefox instances.
+
Enable worker debugging
+
Enable a panel within the debugger to debug workers. +

Note: This option got removed from the UI in Firefox 56, because this version ships with a new Debugger UI, but it can still be enabled for the old UI by setting the preference devtools.debugger.workers to true.

+
+
diff --git a/files/zh-tw/tools/style_editor/index.html b/files/zh-tw/tools/style_editor/index.html new file mode 100644 index 0000000000..058bf07f22 --- /dev/null +++ b/files/zh-tw/tools/style_editor/index.html @@ -0,0 +1,103 @@ +--- +title: 樣式編輯器 +slug: Tools/Style_Editor +translation_of: Tools/Style_Editor +--- +

樣式編輯器使您能夠:

+ + + +

{{EmbedYouTube("7839qc55r7o")}}

+ +

要打開樣式編輯器,請從“ 網頁開發者”選單中選擇“樣式編輯器”選項。(這是Mac上“工具”選單中的子選單)。 工具箱將會顯示在瀏覽器的視窗底部,並顯示樣式編輯器:

+ +

+ +

樣式編輯器分為兩個主要部分:

+ + + +
+

從Firefox 33開始,樣式編輯器還有第三個組件: 媒體測攔

+
+ +

樣式列表

+ +

左側的樣式列表格列出了當前頁面正在使用的所有樣式表。 通過單擊工作表名稱左側的眼球圖標,可以快速打開和關閉樣式表的使用。 通過單擊列表中每個樣式表選項右下角的“儲存”按鈕,可以將對樣式表所做的任何更改保存到電腦硬碟裡。

+ +

樣式編輯器

+ +

中間是編輯器窗格。 您可以在此處閱讀和編輯所選樣式表的原始碼。 您所做的任何更改都會立即應用於頁面。 這使得嘗試,修改和測試更改變得容易。 對更改感到滿意後,可以單擊樣式列表窗格中工作表條目上的“儲存”按鈕,以在電腦上儲存副本。

+ +

The editor provides line numbers and syntax highlighting to help make it easier to read your CSS. It also supports a number of keyboard shortcuts.

+ +

The Style Editor automatically de-minimizes style sheets that it detects, without affecting the original. This makes it much easier to work on pages that have been optimized.

+ +

The Style Editor supports autocomplete. Just start typing, and it will offer you a list of suggestions.

+ +

You can switch autocomplete off in the Style Editor settings.

+ +

The media sidebar

+ +

From Firefox 33 onwards, the Style Editor displays a sidebar on the right-hand side whenever the current sheet contains any @media rules. The sidebar lists the rules and provides a link to the line of the sheet where the rule is defined. Click an item to jump to that rule in the sheet. The condition text of the rule is greyed-out if the media query doesn’t currently apply.

+ +

The media sidebar works especially well with Responsive Design View for creating and debugging responsive layouts:

+ +

{{EmbedYouTube("aVUXmvLSwoM")}}

+ +

Creating and importing style sheets

+ +

You can create a new style sheet by clicking the New button in the toolbar. Then you can just start entering CSS into the new editor and watch as the new styles apply in real time just like changes to the other sheets.

+ +

You can load a style sheet from disk and apply it to the page by clicking the Import button.

+ +

Source map support

+ +

{{EmbedYouTube("zu2eZbYtEUQ")}}

+ +

Web developers often create CSS files using a preprocessor like Sass, Less, or Stylus. These tools generate CSS files from a richer and more expressive syntax. If you do this, being able to see and edit the generated CSS is not so useful, because the code you maintain is the preprocessor syntax, not the generated CSS. So you'd need to edit the generated CSS, then manually work out how to reapply that to the original source.

+ +

Source maps enable the tools to map back from the generated CSS to the original syntax, so they can display, and allow you to edit, files in the original syntax. From Firefox 29 onwards, the Style Editor can understand CSS source maps.

+ +

This means that if you use, for example, Sass, then the Style Editor will show you, and allow you to edit, Sass files, rather than the CSS that is generated from them:

+ +

For this to work, you must:

+ + + +

Viewing original sources

+ +

Now, if you check "Show original sources" in the Style Editor settings, the links next to CSS rules in the Rules view will link to the original sources in the Style Editor.

+ +

From Firefox 35 onwards original sources are displayed by default.

+ +

Editing original sources

+ +

You can also edit the original sources in the Style Editor and see the results applied to the page immediately. To get this to work there are two extra steps.

+ +

First, set up your preprocessor so it watches the original source and automatically regenerates the CSS when the source changes. With Sass you can do this simply by passing the --watch option:

+ +
sass index.scss:index.css --sourcemap --watch
+ +

Next, save the original source in the Style Editor by clicking the "Save" button next to the file, and saving it over the original file.

+ +

Now when you make changes to the source file in the Style Editor the CSS is regenerated and you can see the changes right away.

+ +

Keyboard shortcuts

+ +

Source editor shortcuts

+ +

{{ Page ("en-US/docs/tools/Keyboard_shortcuts", "source-editor") }}

+ +

{{ languages( { "ja": "ja/Tools/Style_Editor"} ) }}

diff --git a/files/zh-tw/tools/web_audio_editor/index.html b/files/zh-tw/tools/web_audio_editor/index.html new file mode 100644 index 0000000000..77e3ee44ba --- /dev/null +++ b/files/zh-tw/tools/web_audio_editor/index.html @@ -0,0 +1,36 @@ +--- +title: Web Audio Editor +slug: Tools/Web_Audio_Editor +translation_of: Tools/Web_Audio_Editor +--- +
+

The Web Audio Editor is new in Firefox 32.

+
+

With the Web Audio API, developers create an {{domxref ("AudioContext", "audio context")}}. Within that context they then construct a number of {{domxref ("AudioNode", "audio nodes")}}, including:

+ +

Each node has zero or more {{domxref ("AudioParam")}} properties that configure its operation. For example, the {{domxref ("GainNode")}} has a single gain property, while the {{domxref ("OscillatorNode")}} has frequency and detune properties.

+

The developer connects the nodes in a graph, and the complete graph defines the behavior of the audio stream.

+

The Web Audio Editor examines an audio context constructed in the page and provides a visualization of its graph. This gives you a high-level view of its operation, and enables you to ensure that all the nodes are connected in the way you expect. You can then examine and edit the AudioParam properties for each node in the graph. Some non-AudioParam properties, like an OscillatorNode's type property, are displayed, and you can edit these as well.

+

This tool is still experimental. If you find bugs, we'd love it if you filed them in Bugzilla. If you have feedback or suggestions for new features, ffdevtools.uservoice.com or Twitter are great places to register them.

+

Opening the Web Audio Editor

+

The Web Audio Editor is not enabled by default in Firefox 32. To enable it, open the Developer Tool Settings and check "Web Audio". Now there should be an extra tab in the Toolbox toolbar labeled "Web Audio". Click the tab and load a page that constructs an audio context. Two good demos are:

+ +

Visualizing the graph

+

The Web Audio Editor will now display the graph for the loaded audio context. Here's the graph for the Violent Theremin demo:

+

You can see that it uses three nodes: an {{domxref ("OscillatorNode")}} as the source, a {{domxref ("GainNode")}} to control the volume, and an {{domxref ("GainNode")}} as the destination.

+

Connections to AudioParams

+
+

Displaying connections to AudioParams is new in Firefox 34.

+
+

Connections between nodes are displayed as solid lines. If, instead, you've connected a node to an AudioParam in another node, then the connection is shown as a dashed line between the nodes, and is labeled with the name of the AudioParam:

+

Inspecting and modifying AudioNodes

+

If you click on a node, it's highlighted and you get a node inspector on the right hand side. This list the values of that node's AudioParam properties. For example, here's what the OscillatorNode looks like:

+

With the Violent Theremin demo, the frequency parameter is modified as the user moves the mouse left and right, and you can see this reflected in the node inspector. However, the value isn't updated in real time: you have to click the node again to see the updated value.

+

If you click on a value in the node inspector you can modify it: press Enter or Tab and the new value takes effect immediately.

diff --git a/files/zh-tw/tools/web_console/console_messages/index.html b/files/zh-tw/tools/web_console/console_messages/index.html new file mode 100644 index 0000000000..47849a3dab --- /dev/null +++ b/files/zh-tw/tools/web_console/console_messages/index.html @@ -0,0 +1,389 @@ +--- +title: 主控台訊息 +slug: Tools/Web_Console/Console_messages +translation_of: Tools/Web_Console/Console_messages +--- +

訊息顯示窗格佔據了網頁主控台的大部分:

+ +

+ +

每個訊息都會以單獨的行顯示出來:

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Time(時間)訊息被紀錄的時間。預設情況並不顯示:你可以在工具箱內設定讓時間戳出現。
Category(類別) +

類別:它標示這訊息屬於什麼類別:

+ +
    +
  • 黑色:網路請求
  • +
  • 藍色:CSS 警告/錯誤/日誌
  • +
  • 橘色:JavaScript 警告/錯誤
  • +
  • 紅色:安全性警告/錯誤
  • +
  • 綠色:伺服器日誌
  • +
  • 淺灰色Console API 訊息
  • +
  • 暗灰色:與命令行解釋器互動的輸入/輸出
  • +
+
Type(種類)For all messages except network requests and interactive input/output an icon indicating whether it is an error(X), a warning(!) or an informational log message (i).
Message(訊息)訊息本身。
Number of occurrences(出現次數)若該行產生的警告或錯誤被執行一次以上,該行只會紀錄一次、並用計數器表明被執行多少次。
Filename and line number(文件名和行數) +

對 JavaScript、CSS 與主控台的 API 訊息而言,訊息可以追蹤到特定的程式碼行數。主控台接著會提供一個能鏈接到生成該訊息的文件名和行數。

+ +

從 Firefox 36 開始,還會提供訊息生成的列數。

+
+ +

By default, the console is cleared each time you navigate to a new page or reload the current page. To override this behavior, check "Enable persistent logs" in the Settings.

+ +

Message categories

+ +

Network

+ +
+

Network log messages are not shown by default. Use the filtering feature to show them.

+
+ +

Network requests are logged with a line that looks like this:

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + +
TimeThe time the message was recorded.
CategoryIndicates that the message is an HTTP request.
Method +

The specific HTTP request method.

+ +

If the request was made as an XMLHttpRequest, there's an additional note indicating this:

+ +

+
URIThe target URI.
SummaryThe HTTP version, status code, and time taken to complete.
+ +

Viewing network request details

+ +

If you click on the message, you'll be redirected to the Network panel where the request is selected and more request and response details are shown within the side panel at the right side. In versions prior to Firefox 43 this information was shown in a separate popup.

+ +

Starting in Firefox 48, you can access much of this detail inline, without leaving the Web Console. Network request entries get a disclosure arrow next to them. Click this to see:

+ + + +

{{EmbedYouTube("cFlcWzJ9j4I")}}

+ +

JS

+ +

JavaScript messages look like this:

+ +

+ + + +
New in Firefox 49
+ +

JavaScript errors contain a "Learn more" link that takes you to the JavaScript error reference containing additional advice for fixing issues:

+ +

{{EmbedYouTube("OabJc2QR6o0")}}

+ +

Source maps

+ +
New in Firefox 50 (but disabled by default)
+ +

From Firefox 50, the Web Console understands source maps. This means that if your JavaScript sources are compressed, you can supply a source map for them. Then any messages or errors your source generates will show up in the Web Console with a link back to the original source, not the compressed version.

+ +

At the moment source map support is disabled by default. To enable it, visit "about:config", find the preference "devtools.sourcemap.locations.enabled" and set it to true.

+ +

Be aware that support is still experimental. It may have bugs and may slow down console output. Bug 1289570 tracks any work that needs to be done before source map support can be enabled by default.

+ +

CSS

+ +
+

CSS warnings and reflow messages are not shown by default. Use the filtering feature to show them.

+
+ +

CSS messages look like this:

+ +

+ +

Reflow events

+ +

The Web Console also logs reflow events under the CSS category. A reflow is the name given to the operation in which the browser calculates the layout of all or part of the page. Reflows occur when a change has happened to a page that the browser thinks affects the layout. Many events can trigger reflows, including: resizing the browser window, activating pseudoclasses like :hover, or manipulating the DOM in JavaScript.

+ +

Because reflows can be computationally expensive and directly affect the user interface, they can have a big impact on the responsiveness of a website or web app. By logging reflow events the Web Console can give you insight into when reflow events are being triggered, how long they take to execute and, if the reflows are synchronous reflows triggered from JavaScript, which code triggered them.

+ +

Reflow events are logged as "Reflow" messages, as distinct from CSS errors or warnings. By default, they are disabled. You can enable them by clicking the "CSS" button in the toolbar and selecting "Reflows".

+ +

Each message is labeled "reflow" and shows the time taken to execute the reflow:

+ +

If the reflow is a synchronous reflow triggered from JavaScript, it also shows a link to the line of code that triggered the reflow:

+ +

Click the link to open the file in the Debugger.

+ +

Synchronous and asynchronous reflows

+ +

If a change is made that invalidates the current layout - for example, the browser window is resized or some JavaScript modifies an element's CSS - the layout is not recalculated immediately. Instead, the reflow happens asynchronously, the next time the browser decides it needs to be done (generally, the next time the browser repaints). In this way the browser can save up a collection of invalidating changes and recalculate their effect at once.

+ +

However, if some JavaScript code reads a style that has been modified, then the browser must perform a synchronous reflow in order to calculate the computed style to return. For example, code like this will cause an immediate, synchronous, reflow, when it calls window.getComputedStyle(thing).height:

+ +
var thing = document.getElementById("the-thing");
+thing.style.display = "inline-block";
+var thingHeight = window.getComputedStyle(thing).height;
+ +

Because of this, it's a good idea to avoid interleaving write and read calls to an element's styles when manipulating the DOM, because every time you read back a style that has been invalidated by a previous write call, you force a synchronous reflow.

+ +

Security

+ +

Security warnings and errors look like this:

+ +

The security messages shown in the Web Console help developers find potential or actual vulnerabilities in their sites. Additionally, many of these messages help educate developers because they end with a “Learn More” link that takes you to a page with background information and advice for mitigating the issue.

+ +

The complete list of security messages is as follows:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MessageDetails
Blocked loading mixed active contentThe page contained mixed active content: that is, the main page was served over HTTPS, but asked the browser to load "active content", such as scripts, over HTTP. The browser blocked this active content. See Mixed Content for more details.
Blocked loading mixed display contentThe page contained mixed display content: that is, the main page was served over HTTPS, but asked the browser to load "display content", such as images, over HTTP. The browser blocked this display content. See Mixed Content for more details.
Loading mixed (insecure) active content on a secure pageThe page contained mixed active content: that is, the main page was served over HTTPS, but asked the browser to load "active content", such as scripts, over HTTP. The browser loaded this active content. See Mixed Content for more details.
Loading mixed (insecure) display content on a secure pageThe page contained mixed display content: that is, the main page was served over HTTPS, but asked the browser to load "display content", such as images, over HTTP. The browser loaded this display content. See Mixed Content for more details.
This site specified both an X-Content-Security-Policy/Report-Only header and a Content-Security-Policy/Report-Only header. The X-Content-Security-Policy/Report-Only header(s) will be ignored.See Content Security Policy for more details.
The X-Content-Security-Policy and X-Content-Security-Report-Only headers will be deprecated in the future. Please use the Content-Security-Policy and Content-Security-Report-Only headers with CSP spec compliant syntax instead.See Content Security Policy for more details.
Password fields present on an insecure (http://) page. This is a security risk that allows user login credentials to be stolen.Pages containing login forms must be served over HTTPS, not HTTP.
Password fields present in a form with an insecure (http://) form action. This is a security risk that allows user login credentials to be stolen.Forms containing password fields must submit them over HTTPS, not HTTP.
Password fields present on an insecure (http://) iframe. This is a security risk that allows user login credentials to be stolen.iframes containing login forms must be served over HTTPS, not HTTP.
The site specified an invalid Strict-Transport-Security header.See HTTP Strict Transport Security for more details.
+

This site makes use of a SHA-1 Certificate; it's recommended you use certificates with signature algorithms that use hash functions stronger than SHA-1.

+
+

The site uses a certificate whose signature uses the SHA-1 hash algorithm.

+ +

SHA-1 is still still widely used in certificates, but it is starting to show its age. Web sites and Certification Authorities are encouraged to switch to stronger hash algorithms in future. See the Weak Signature Algorithm article for more details.

+ +

Note that the SHA-1 certificate may not be your site's own certificate, but may be the certificate belonging to a Certification Authority that was used to sign your site's certificate.

+
+ +

Bug 863874 is the meta-bug for logging relevant security messages to the Web Console. If you have more ideas for useful features like the ones discussed here, or are interested in contributing, check out the metabug and its dependencies.

+ +

Logging

+ +
+

Messages logged from Shared Workers, Service Workers, add-ons, and Chrome Workers are not shown by default. Use the filtering feature to show them.

+
+ +

The Logging category includes messages logged using the Console API.
+

+ +

The Web console supports the following Console API messages:

+ + + +

The console prints a stack trace for all error messages, like this:

+ +
function foo() {
+  console.error("it explodes");
+}
+
+function bar() {
+  foo();
+}
+
+function doStuff() {
+ bar();
+}
+
+doStuff();
+ +

+ +

Server

+ +
+

New in Firefox 43

+
+ +
+

Server-side log messages are not shown by default. Use the filtering feature to show them.

+
+ +

From Firefox 43, the Web Console can display messages sent from the server. This enables you to use the Web Console to debug server-side code.

+ +

It uses the Chrome Logger protocol. Briefly, the way it works is:

+ + + +

To find a suitable library for your server code, see the Chrome Logger documentation.

+ +

Command line input/output

+ +

Commands sent to the browser using the Web Console's command line, and the corresponding responses, are logged using lines like this:

+ +

The dark gray bar indicates that these are input/output messages, while the direction of the arrow discriminates between input and output.

+ +

Filtering and searching

+ +

Filtering by category

+ +

You can use the toolbar along the top to constrain the results displayed.

+ +

To see only messages of particular categories, click the button labeled with that category ("Net", "CSS", and so on). Clicking the main part of the button toggles that category on or off, while clicking the arrow on the right gives you more fine-grained filter options within that category:

+ + + +

用文字過濾

+ +

To see only messages that contain a specific string, type in the text box labeled "Filter output".

+ +

清除日誌

+ +

>最後,您可以使用工具欄清除日誌。在 Firefox 48 以前,可以按下右邊的「清除」按鈕。在 Firefox 48 以後,可以按下左邊的垃圾桶圖示。

diff --git a/files/zh-tw/tools/web_console/index.html b/files/zh-tw/tools/web_console/index.html new file mode 100644 index 0000000000..49678e6d99 --- /dev/null +++ b/files/zh-tw/tools/web_console/index.html @@ -0,0 +1,37 @@ +--- +title: 網頁主控台 +slug: Tools/Web_Console +translation_of: Tools/Web_Console +--- +

網頁主控台能:

+ +
    +
  1. 記錄網頁相關的資訊:網路請求、JavaScript、CSS、安全性相關的問題,警告和錯誤、以及頁面運行的 JavaScript 相關問題,警告,錯誤,和參考訊息。
  2. +
  3. 透過執行頁面文中的 JavaScript 表達式與網頁互動
  4. +
+ +

{{EmbedYouTube("C6Cyrpkb25k")}}

+ +
+
+
+
打開網頁主控台
+
如何開始使用網頁主控台。
+
命令行解釋器
+
如何用主控台與文件互動。
+
分割主控台
+
把主控台拉到其他工具旁邊。
+
+
+ +
+
+
主控台訊息
+
主控台相關的紀錄訊息。
+
豐富的輸出對象
+
透過主控台觀察並與紀錄的物件互動。
+
鍵盤快速鍵
+
鍵盤快速鍵參考。
+
+
+
diff --git a/files/zh-tw/tools/web_console/keyboard_shortcuts/index.html b/files/zh-tw/tools/web_console/keyboard_shortcuts/index.html new file mode 100644 index 0000000000..1d113d419c --- /dev/null +++ b/files/zh-tw/tools/web_console/keyboard_shortcuts/index.html @@ -0,0 +1,10 @@ +--- +title: 鍵盤快捷鍵 +slug: Tools/Web_Console/Keyboard_shortcuts +translation_of: Tools/Web_Console/Keyboard_shortcuts +--- +

{{ Page ("zh-TW/docs/tools/Keyboard_shortcuts", "web-console") }}

+ +

全域快捷鍵

+ +

{{ Page ("zh-TW/docs/tools/Keyboard_shortcuts", "all-toolbox-tools") }}

diff --git a/files/zh-tw/tools/web_console/opening_the_web_console/index.html b/files/zh-tw/tools/web_console/opening_the_web_console/index.html new file mode 100644 index 0000000000..85d89608b0 --- /dev/null +++ b/files/zh-tw/tools/web_console/opening_the_web_console/index.html @@ -0,0 +1,23 @@ +--- +title: 打開網頁主控台 +slug: Tools/Web_Console/Opening_the_Web_Console +translation_of: Tools/Web_Console/UI_Tour +--- +

要開啟網頁主控台:

+ + + +

網頁工具箱將出現在瀏覽器視窗底部,網頁主控台也會隨之啟動(網頁工具箱只會稱它為「主控台」):

+ +

網頁主控台

+ +

網頁主控台介面主要有三大部分:

+ + diff --git a/files/zh-tw/tools/web_console/rich_output/index.html b/files/zh-tw/tools/web_console/rich_output/index.html new file mode 100644 index 0000000000..d09757cfa2 --- /dev/null +++ b/files/zh-tw/tools/web_console/rich_output/index.html @@ -0,0 +1,75 @@ +--- +title: 豐富的輸出對象 +slug: Tools/Web_Console/Rich_output +translation_of: Tools/Web_Console/Rich_output +--- +

當網路主控台印出物件時,它不但會顯示物件名、還會包括該物件資訊的 richer set。尤其是它要:

+ + + +

特定類型的 rich output

+ +

網路主控台給許多物件類型提供了 rich output,包括:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Object
Array
Date
Promise +
+

New in Firefox 36

+
+

+
RegExp
Window
Document
Element
Event
+ +

檢查物件屬性

+ +

當控制台印出一個物件的時候,它會以斜體的樣式呈現。點擊它,你會看到一個有該物件詳細資訊的面板: +

+ +

要關閉此面板請按 Esc 鍵...

+ +

高亮顯示與 DOM 節點檢查

+ +

若你在控制台印出的 DOM 元素上懸停游標,頁面會高亮該元素:

+ +

In the screenshot above you'll also see a blue "target" icon next to the node in the console output: click it to switch to the Inspector with that node selected.

diff --git a/files/zh-tw/tools/web_console/split_console/index.html b/files/zh-tw/tools/web_console/split_console/index.html new file mode 100644 index 0000000000..398f771c79 --- /dev/null +++ b/files/zh-tw/tools/web_console/split_console/index.html @@ -0,0 +1,14 @@ +--- +title: 分割主控台 +slug: Tools/Web_Console/Split_console +translation_of: Tools/Web_Console/Split_console +--- +

您可以把主控台拉到其他工具旁邊。當你在工具箱中的另一種工具內,只要按下 Esc 或是在工具欄內的「切換分割主控台」按鈕。工具箱將會分割,上面是原有的工具、而下面會是網頁主控台。

+ +

{{EmbedYouTube("G2hyxhPHyXo")}}

+ +

如往常般,$0 在檢測器作為選中元素的速記:

+ +

當您使用含有除錯器的分割主控台,主控台的範圍,是當前執行的 stack frame。因此,若你在函數內選了一個斷點,範圍將是該函式的範圍。You'll get autocomplete for objects defined in the function, and can easily modify them on the fly:

+ +

diff --git a/files/zh-tw/tools/web_console/the_command_line_interpreter/index.html b/files/zh-tw/tools/web_console/the_command_line_interpreter/index.html new file mode 100644 index 0000000000..72d9eba4fc --- /dev/null +++ b/files/zh-tw/tools/web_console/the_command_line_interpreter/index.html @@ -0,0 +1,121 @@ +--- +title: 命令行解釋器 +slug: Tools/Web_Console/The_command_line_interpreter +translation_of: Tools/Web_Console/The_command_line_interpreter +--- +

You can interpret JavaScript expressions in real time using the command line provided by the Web Console.

+ +

+ +

Entering expressions

+ +

To enter expressions just type into the command line and press Enter. To enter multiline expressions, use Shift+Enter instead of Enter.

+ +

The expression you type is echoed in the message display window, followed by the result:

+ +

+ +
New in Firefox 47
+ +

From Firefox 47 onwards, if your input does not appear to be complete when you press Enter, then the Console treats this as Shift+Enter , enabling you to finish your input.

+ +

For example, if you type:

+ +
function foo() {
+ +

and then Enter, the Console will not immediately execute the input, but will behave as if you had pressed Shift+Enter , so you can finish entering the function definition.

+ +

Accessing variables

+ +

You can access variables defined in the page, both built-in variables like window and variables added by JavaScript like jQuery:

+ +

+ +

Autocomplete

+ +

The command line has autocomplete: enter the first few letters and a popup appears with possible completions:

+ +

Type Enter or Tab to accept the suggestion, use the up/down arrows to move to a different suggestion, or just keep typing if you don't like any of the suggestions.

+ +

The console suggests completions from the scope of the currently executing stack frame. This means that if you've hit a breakpoint in a function you get autocomplete for objects local to the function.

+ +

You get autocomplete suggestions for array elements, as well:

+ +

+ +

Defining variables

+ +

You can define your own variables, and then access them:

+ +

+ +

Command history

+ +

The command line remembers commands you've typed: to move back and forward through your history, use the up and down arrows.

+ +

From Firefox 39 onwards, this history is persisted across sessions. To clear the history, use the clearHistory() helper function.

+ +

Working with iframes

+ +

If a page contains embedded iframes, you can use the cd() command to change the console's scope to a specific iframe, and then you can execute functions defined in the document hosted by that iframe. There are three ways to select an iframe using cd():

+ +

You can pass the iframe DOM element:

+ +
var frame = document.getElementById("frame1");
+cd(frame);
+ +

You can pass a CSS selector that matches the iframe:

+ +
cd("#frame1");
+ +

You can pass the iframe's global window object:

+ +
var frame = document.getElementById("frame1");
+cd(frame.contentWindow);
+
+ +

To switch the context back to the top-level window, call cd() with no arguments:

+ +
cd();
+ +

For example, suppose we have a document that embeds an iframe:

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+  </head>
+  <body>
+    <iframe id="frame1" src="static/frame/my-frame1.html"></iframe>
+  </body>
+</html>
+ +

The iframe defines a new function:

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <script>
+      function whoAreYou() {
+        return "I'm frame1";
+      }
+   </script>
+  </head>
+  <body>
+  </body>
+</html>
+ +

You can switch context to the iframe like this:

+ +
cd("#frame1");
+ +

Now you'll see that the global window's document is the iframe:

+ +

And you can call the function defined in the iframe:

+ +

+ +

Helper commands

+ +

{{ page("/en/Using_the_Web_Console/Helpers", "The commands") }}

diff --git a/files/zh-tw/tools/webide/index.html b/files/zh-tw/tools/webide/index.html new file mode 100644 index 0000000000..7a2968a1ac --- /dev/null +++ b/files/zh-tw/tools/webide/index.html @@ -0,0 +1,290 @@ +--- +title: WebIDE +slug: Tools/WebIDE +tags: + - NeedsTranslation + - TopicStub +translation_of: Archive/WebIDE +--- +
+

從 Firefox 34 開始均可使用 WebIDE。

+ +

亦可於 Firefox 33 中變更偏好設定,以啟動 WebIDE。鍵入 about:config 並找到「devtools.webide.enabled 」,將之設定為「true」即可。

+
+ +
+

WebIDE 現已取代「應用程式管理員 (App Manager)」,且其功能一如應用程式管理員,並可透過 Firefox OS 模擬器 (Firefox OS Simulator) 或實體 Firefox OS 裝置,進而建構、編輯、執行、除錯 Web App。

+ +

不僅如此,WebIDE 亦可連接 Firefox 開發者工具與他款瀏覽器,包含 Firefox 行動版 (Firefox for Android)、Android 上的 Chrome、iOS 上的 Safari。可參閱遠端除錯頁面,以了解應如何連上特定瀏覽器。

+
+ +

{{EmbedYouTube("2xmj4W8O3E4")}}

+ +

你必須先在 WebIDE 中設定一個或多個執行環境 (Runtime)。Runtime 即是 App 的執行與除錯環境。不論是 Firefox OS 裝置透過 USB 連上桌機 (從 Firefox 39 或更高版本起,可透過 WiFi 連上桌機),或是桌面版 Firefox 上安裝 Firefox OS 模擬器,都可當做執行環境。

+ +

接著就可建立 App 或啟動現有的 App。如果你要建立全新的 App,內建範本將提供你所需的資料目錄架構與最簡單的樣板;或有更完整的範本提供 Privileged App 所需要的 API。WebIDE 將以樹狀圖顯示 App 的檔案,讓你只要透過內建的編輯器即可修改並儲存檔案。當然,你也能選用自己習慣的編輯器開發 App,只用 WebIDE 除錯亦可。

+ +

最後,你可將 App 安裝於執行環境之中並執行。也能透過常見的開發者工具,如檢測器 (Inspector)主控台 (Console)JavaScript 除錯器 (JavaScript Debigger) 等,檢查並修改 App。

+ +

系統需求

+ +

若要以 WebIDE 開發 App 並除錯,必須使用 Firefox 33 或更高版本。如果要在實際 Freifox OS 裝置上測試 App,則該款裝置需搭載 Firefox OS 1.2 或更高版本,並搭配 1 組 USB 連接線。

+ +

如果要針對 Firefox OS 1.2 或更高版本開發 App,則限用 WebIDE 進行開發。

+ +

啟動 WebIDE

+ +

進入「網頁開發者」選單,點擊「WebIDE」即可將之啟動。亦可按下鍵盤的「Shift + F8」快捷鍵:左邊的「開啟應用程式 (Open App)」下拉式選單中,你可啟動現有的 App 或建立新的 App。右邊的「選擇 Runtime (Select Runtime)」下拉式選單中,你可選擇執行環境或設立新的執行環境。

+ +

在選擇了執行環境並開啟 App 之後,才可以按中間的「Run」、「Stop」、「Debug」按鈕。

+ +

設定執行環境

+ +

「選擇 Runtime」選單內,共分為 3 種執行環境:

+ + + +

第一次點開下拉式選單,你不會看見任何的執行環境:

+ +

接下來會帶你新增執行環境。

+ +

連結 Firefox OS 裝置

+ +

在開始連結 Firefox OS 裝置之前,必須先完成下列設定:

+ + + +
+

Linux 版本:

+ + +
+ +
+

Windows 版本:

+ + +
+ +

如果有其他 Android 裝置已連上你的電腦,請先中斷連線。再透過 USB 銜接裝置與電腦。則你的裝置應該會出現在「USB 裝置」之下:

+ +

+ +

如果還是沒看到你的裝置,請詳見〈疑難雜症〉頁面。

+ +

新增模擬器

+ +

Firefox OS 模擬器架構在 Firefox OS 之上,可在桌機上模擬 Firefox OS 裝置。且其執行的視窗尺寸、使用者介面、內建的 App 也都和 Firefox OS 裝置相同,更能模擬 Firefox OS 裝置的 API。

+ +

如此在許多情況下,就算你沒有實際裝置,也能測試或除錯自己的 App。

+ +

整個模擬器大到不能內建在 Firefox 之中,所以包裝成 Firefox 的附加元件。當你在 Runtimes 下拉式選單中點選「Install Simulator」,將會帶領你到安裝不同版本 Firefox OS 模擬器的頁面。

+ +

你可以安裝所有需要的模擬器。因為模擬器容量頗大,所以請耐心下載。當你安裝模擬器完畢,就能關閉「Extra Components」視窗。已安裝的模擬器就會出現在「Runtimes」的下拉式選單裡面:

+ +

若要進一步了解模擬器,詳見該頁

+ +

自訂執行環境

+ +

透過可自訂的執行環境,你可用任意的 hostname 和埠 (port) 去連結遠端裝置。

+ +

Firefox OS 裝置與 Android 裝置,均是透過「Android Debug Bridge」這個程式 (也稱為 ADB) 連上桌機。WebIDE 已預設使用名為「ADB Helper」的附加元件。此簡單的附加元件可幫你安裝 ADB 並設定好「埠」的轉址,進而簡化相關程序。接著 Firefox 桌面版的工具就能和裝置交換訊息了。

+ +

上述功能在大部分情況下都很方便。但有時候你可能不想透過 WebIDE 使用 ADB (例如你想要直接用命令列來跑 ADB)。這時你可使用 adb forward 指令來使用特定的「主機 (Host)」與「埠」
+
+ 如果你也想用 WebIDE 及命令列使用 ADB,就要停用 ADB Helper 附加元件,並透過「自訂 (Custom)」選項、輸入你傳送給 adb forward 的「主機」與「埠」,即可連接 WebIDE。

+ +

ADB Helper 目前還不支援連結 Firefox for Android。如果你想透過 WebIDE 連上 Firefox for Android,就必須設定自己的埠轉址 (Port forwarding) 與自訂的執行環境。可進一步參閱 connecting to Firefox for Android using ADB

+ +

選擇執行環境

+ +

當你設定好執行環境之後,就能在「選擇 Runtime (Select Runtime)」中點選。

+ + + +

WebIDE 工具列中間的「play」按鈕這時已經可按。點下後就會執行所選的執行環境。 

+ +

執行環境的動作

+ +

選取執行環境之後,「Runtimes」下拉式選單會多出 3 個選項:

+ + + +

+ +

+ +

建立並開啟 App

+ +

在「開啟應用程式 (Open App)」選單之下共有 3 個選項:
+ 1). 新增應用程式... (New App...)
+ 2). 開啟封裝的應用程式... (Open Packaged App...)
+ 3). 開啟架設的應用程式... (Open Hosted App...)

+ +

+ +

建立新的 App

+ +

點選「新增應用程式」即可建立新 App。你會看到對話視窗內提供「Privileged Empty App」與「Privileged App」共  2 個範本。

+ +

+ +

此 2 個範本均來自於 Mozilla 的「app template collection」,以最基本的架構讓你輕鬆上手。「Privileged App」則會教你如何使用權限去取得跨領域 (cross-origin) 的內容。

+ +

在選擇範本之後,必須設定該 App 的名稱及其檔案儲存目錄,接著會在專案編輯器中開啟新 App。

+ +

開啟封裝式 App

+ +

點選「開啟封裝的應用程式...」即可開啟封裝式 (Packaged) App。你所選取的資料夾中必須具備 App 的 manifest 檔案,然後就會在專案編輯器中開啟 App。

+ +
+

注意:你會在「應用程式管理員 (App Manager)」中看到「manifest」中文翻譯為「安裝資訊檔」。

+
+ +

開啟托管/架設式 App

+ +

點選「開啟架設的應用程式...」開啟托管/架設式 (Hosted) App。你必須輸入 1 組網址指向該 App 的 manifest 檔案,然後就會在專案編輯器中開啟該 App。

+ +

編輯 App

+ +

專案編輯器可供編輯 App。左側邊欄是 App 所有檔案的樹狀結構,可透過右鍵選單來新增、刪除檔案。右邊一大塊就是檔案編輯面板。

+ +

App 總覽頁面

+ +

如果是第一次打開或新建 App 時,編輯面板會出現 App 總覽頁面:

+ +

+ +

你可隨時透過左側的檔案樹狀圖,回到 App 總覽頁面。

+ +

Manifest 檔案檢查

+ +

WebIDE 會自動檢查 manifest 檔案的常見問題。只要發現問題,就會在 App 總覽頁面中顯示並說明錯誤原因:

+ +

+ +

當然也可以在專案編輯器中,直接編輯 App 的 manifest.webapp 檔案。

+ +

原始碼編輯器

+ +

WebIDE 是使用 CodeMirror 原始碼編輯器。

+ +

原始碼編輯器快捷鍵

+ +

{{ Page ("en-US/docs/tools/Keyboard_shortcuts", "source-editor") }}

+ +

程式碼補齊

+ +

當編輯 CSS 和 JavaScript 時,編輯器會自動補齊建議字串。 CSS 自動補齊功能預設為開啟:

+ +

按「Control + Space」就可顯示 JavaScript 的自動補齊建議:

+ +

+ +

行內說明文件

+ +

編輯器也可顯示 JavaScript 的行內說明文件。只要按下「Shift + Space」,就會跳出目前滑鼠游標放置的條目之說明:

+ +

+ +

在提示視窗中點選 [docs] 連結,就會帶你到該條目所對應的 MDN 頁面。

+ +

儲存檔案

+ +

你必須儲存檔案之後,才能觀看檔案修改成果。如果是修改過但尚未儲存的檔案,則樹狀圖的檔名旁邊將顯示星號。你可透過選單或按下「Control+S」,即可儲存檔案 (Mac OS X 則為「Command+S」)。

+ +

移除專案

+ +

要從 WebIDE 移除 App,可在 App 總覽頁面點選「移除專案 (Remove Project)」。

+ +

執行並除錯 App

+ +

當準備好要執行 App 時,必須從「選擇 Runtime」下拉式選單中選取任一執行環境。如果沒有適合的執行環境,請參考設定執行環境

+ +

WebIDE 工具列中間的「Play」按鈕現已可點擊。點下之後就會在你所選的執行環境中安裝並執行 App:

+ +

這時按下「Pause」就會出現開發者工具的工具箱,以利你對已連結的 App 進行除錯:

+ +

這裡會根據所選的執行環境而提供除錯工具,且必定會提供如檢測器 (Inspector)主控台 (Console)JavaScript 除錯器樣式編輯器 (Style Editor)效能分析器 (Profiler)程式碼速記本 (Scratchpad) 等基本工具。就如同一般網頁,透過這些工具做出的修改,都可以即時在 App 中看到結果,但僅暫存。相反的,透過編輯面板修改的檔案,都會直接儲存到硬碟之中,但必須重新啟動 App 才能看到結果。

+ +

Certified App 的除錯

+ +

若是搭配模擬器,則只要已選擇了執行環境,再點擊 App 的下拉選單,則不僅僅是你的 App,只要是該執行環境正執行中的所有 App 都會列在上面,包含Certified App。這時即可除錯所你選擇的 App:

+ +

+ +


+ 不過,如果要在實際裝置除錯 Certified App 還需要:

+ + + +

如果要啟動 Certified App 除錯功能,就要先連接執行環境,然後在選單中找到 Runtime > Runtime Info。如果你在這裡看到「開發工具受限權限 (DevTools restricted privileges)」為「Yes」,就表示無法進行 Certified App 的除錯。根據你除錯對象的不同,後續步驟也有所差異:

+ + + +

現在 (或在重新啟動 B2G 桌機用戶端之後) 你應該可以到 WebIDE 看到裝置中的所有 Certified App 了。

+ +

監控效能

+ +

如果你想知道自己 App 的效能,也有幾種方法可於 WebIDE 的執行環境中測得:

+ + + +

疑難雜症 (Troubleshooting)

+ +

WebIDE 的其他使用問題,請參閱疑難雜症頁。

+ +

 

+ +

 

diff --git a/files/zh-tw/tools/webide/troubleshooting/index.html b/files/zh-tw/tools/webide/troubleshooting/index.html new file mode 100644 index 0000000000..cfdadf7a1b --- /dev/null +++ b/files/zh-tw/tools/webide/troubleshooting/index.html @@ -0,0 +1,46 @@ +--- +title: WebIDE 錯誤排除 +slug: Tools/WebIDE/Troubleshooting +translation_of: Archive/WebIDE/Troubleshooting +--- +

連接 Firefox OS 裝置

+ +

如果您連接了 Firefox OS 裝置,但該裝置沒有出現在 WebIDE 裡,有些事情您可以先試試:

+ + + +

為認證過的應用程式除錯

+ +

如果您想為認證過的應用程式(包括內建的應用程式)除錯,請參考 debugging certified apps 中的說明。

+ +

Enable logging

+ +

You can also enable verbose logging to gather diagnostics:

+ +
    +
  1. visit about:config, and add a new preference called .console.logLevel, with the string value all, and set extensions.adbhelper@mozilla.org.debug to true
  2. +
  3. In the Add-ons Manager, disable and then re-enable the ADB Helper add-on.
  4. +
  5. Open the Browser Console and you'll now see console messages prefixed with adb. If the messages don't mean anything to you, ask for help.
  6. +
+ +

尋求協助

+ +

請上 IRC 的 #devtools 頻道尋求協助。

diff --git a/files/zh-tw/web/accessibility/aria/aria_techniques/index.html b/files/zh-tw/web/accessibility/aria/aria_techniques/index.html new file mode 100644 index 0000000000..502a808e1d --- /dev/null +++ b/files/zh-tw/web/accessibility/aria/aria_techniques/index.html @@ -0,0 +1,164 @@ +--- +title: Using ARIA +slug: Web/Accessibility/ARIA/ARIA_Techniques +translation_of: Web/Accessibility/ARIA/ARIA_Techniques +--- +

 

+ +

Roles(角色)

+ +

 

+ +

Widget roles (局部組件)

+ +
+ +
+ +

Composite roles

+ +

下面的技術,描述了每個複合角色,以及他們的必要和可選的子角色。

+ +
+ +
+ +

Document structure roles

+ +
+ +
+ +

Landmark roles

+ +
+ +
+ +

States and properties

+ +

 

+ +

Widget attributes

+ +
+ +
+ +

Live region attributes

+ +
+ +
+ +

Drag & drop attributes

+ +
+ +
+ +

Relationship attributes

+ +
+ +
diff --git a/files/zh-tw/web/accessibility/aria/forms/basic_form_hints/index.html b/files/zh-tw/web/accessibility/aria/forms/basic_form_hints/index.html new file mode 100644 index 0000000000..532911294d --- /dev/null +++ b/files/zh-tw/web/accessibility/aria/forms/basic_form_hints/index.html @@ -0,0 +1,119 @@ +--- +title: 基本表單應用 +slug: Web/Accessibility/ARIA/forms/Basic_form_hints +tags: + - 待翻譯 +translation_of: Web/Accessibility/ARIA/forms/Basic_form_hints +--- +

表單的 label

+ +

當使用傳統的 HTML 表單元素建立表單時,提供控制用的標籤(label)以及將標籤與對應表單元素建立關聯是非常重要的。當 screen reader (例如瀏覽器、電子郵件……等等)瀏覽一個頁面時,screen reader 會顯示 form controls ,但若沒有標示 control 和 label 之間的關聯,  screen reader 沒法知道哪個 label 是對應哪個 control。

+ +

下面的範例顯示一個使用標籤的表單。注意每一個 {{ HTMLElement("input") }} 元件都有 id,每一個 {{ HTMLElement("label") }} 元件有 for 屬性,用來對應 {{ HTMLElement("input") }} 元素的 id 。

+ +

範例 1. 使用 label 的簡易表單

+ +
<form>
+  <ul>
+    <li>
+      <input id="wine-1" type="checkbox" value="riesling"/>
+      <label for="wine-1">Berg Rottland Riesling</label>
+    </li>
+    <li>
+      <input id="wine-2" type="checkbox" value="weissbergunder"/>
+      <label for="wine-2">Weissbergunder</label>
+    </li>
+    <li>
+      <input id="wine-3" type="checkbox" value="pinot-grigio"/>
+      <label for="wine-3">Pinot Grigio</label>
+    </li>
+    <li>
+      <input id="wine-4" type="checkbox" value="gewurztraminer"/>
+      <label for="wine-4">Berg Rottland Riesling</label>
+    </li>
+  </ul>
+</form>
+
+ +

使用 ARIA 標籤

+ +

HTML 的 {{ HTMLElement("label") }} 元素適用於表單相關元素 , 但是許多表單控件被實現為動態JavaScript小部件 , 使用 {{ HTMLElement("div") }} 或 {{ HTMLElement("span") }}。 WAI-ARIA , 來自 W3C 的網路無障礙計畫 ( Web Accessibility Initiative ) 的無障礙互聯網應用程序規範 ( Accessible Rich Internet Applications specification ) , 為這些情況提供了 aria-labelledby 屬性。

+ +

下面的範例顯示使用無序列表 ( unordered list ) 實現的單選按鈕組 ( radio button group )。注意程式碼第三行 , {{ HTMLElement("li") }} 元素將 aria-labelledby 屬性設置為 "rg1_label" , 在第一行中元素 {{ HTMLElement("h3") }} 的 id , 即單選按鈕組的標籤。

+ +

範例 2. 使用無序列表實現的單選按鈕組 ( 改編自 http://www.oaa-accessibility.org/examplep/radio1/)

+ +
<h3 id="rg1_label">Lunch Options</h3>
+
+<ul class="radiogroup" id="rg1"  role="radiogroup" aria-labelledby="rg1_label">
+  <li id="r1"  tabindex="-1" role="radio" aria-checked="false">
+    <img role="presentation" src="radio-unchecked.gif" /> Thai
+  </li>
+  <li id="r2"  tabindex="-1" role="radio"  aria-checked="false">
+    <img role="presentation" src="radio-unchecked.gif" /> Subway
+  </li>
+  <li id="r3"   tabindex="0" role="radio" aria-checked="true">
+    <img role="presentation" src="radio-checked.gif" /> Radio Maria
+  </li>
+</ul>
+
+ +

Describing with ARIA

+ +

Form controls sometimes have a description associated with them, in addition to the label. ARIA provides the aria-describedby attribute to directly associate the description with the control.

+ +

The example below shows a {{ HTMLElement("button") }} element that is described by a sentence in a separate {{ HTMLElement("div") }} element. The aria-describedby attribute on the {{ HTMLElement("button") }} references the id of the {{ HTMLElement("div") }}.

+ +

Example 3. A button described by a separate element.

+ +
<button aria-describedby="descriptionRevert">Revert</button>
+<div id="descriptionRevert">Reverting will undo any changes that have been made
+                            since the last save.</div>
+ +

(Note that the aria-describedby attribute is used for other purposes, in addition to form controls.)

+ +

Required and invalid fields

+ +

Web developers typically use presentational strategies to indicated required or invalid fields, but assistive technologies (ATs) cannot necessarily infer this information from the presentation. ARIA provides attributes for indicating that form controls are required or invalid:

+ + + +

The example below shows a simple form with three fields. On lines 4 and 12, the aria-required attributes are set to true (in addition to the asterisks next to the labels) indicating that the name and email fields are required. The second part of the example is a snippet of JavaScript that validates the email format and sets the aria-invalid attribute of the email field (line 12 of the HTML) according to the result (in addition to changing the presentation of the element).

+ +

Example 4a. A form with required fields.

+ +
<form>
+  <div>
+    <label for="name">* Name:</label>
+    <input type="text" value="name" id="name" aria-required="true"/>
+  </div>
+  <div>
+    <label for="phone">Phone:</label>
+    <input type="text" value="phone" id="phone" aria-required="false"/>
+  </div>
+  <div>
+    <label for="email">* E-mail:</label>
+    <input type="text" value="email" id="email" aria-required="true"/>
+  </div>
+</form>
+ +

Example 4b. Part of a script that validates the form entry.

+ +
var validate = function () {
+  var emailElement = document.getElementById(emailFieldId);
+  var valid = emailValid(formData.email); // returns true if valid, false otherwise
+
+  emailElement.setAttribute("aria-invalid", !valid);
+  setElementBorderColour(emailElement, valid); // sets the border to red if second arg is false
+};
+ +

提供有幫助的錯誤訊息

+ +

繼續閱讀了解如何使用 ARIA alerts to enhance forms.

+ +
TBD: we should either combine into one article or separate into techniques, or both. Also, is ARIA markup appropriate for error messages in a page loaded after server side validation?
+ +

參閱 WAI-ARIA Authoring Practices .

diff --git a/files/zh-tw/web/accessibility/aria/forms/index.html b/files/zh-tw/web/accessibility/aria/forms/index.html new file mode 100644 index 0000000000..ca529d1b1e --- /dev/null +++ b/files/zh-tw/web/accessibility/aria/forms/index.html @@ -0,0 +1,19 @@ +--- +title: Forms +slug: Web/Accessibility/ARIA/forms +tags: + - ARIA + - Accessibility + - NeedsTranslation + - TopicStub +translation_of: Web/Accessibility/ARIA/forms +--- +

下列連結提供多種技術的資訊來處進網頁表格的存取:

+ + + +

透過Yahoo! article on form validation and ARIA, 網頁的瀏覽可發現上面所列出的技術的實際應用.

diff --git a/files/zh-tw/web/accessibility/aria/index.html b/files/zh-tw/web/accessibility/aria/index.html new file mode 100644 index 0000000000..891695ab5a --- /dev/null +++ b/files/zh-tw/web/accessibility/aria/index.html @@ -0,0 +1,142 @@ +--- +title: ARIA +slug: Web/Accessibility/ARIA +tags: + - ARIA + - Accessibility + - NeedsTranslation + - TopicStub +translation_of: Web/Accessibility/ARIA +--- +

Accessible Rich Internet Applications (ARIA) defines ways to make Web content and Web applications (especially those developed with Ajax and JavaScript) more accessible to people with disabilities. For example, ARIA enables accessible navigation landmarks, JavaScript widgets, form hints and error messages, live content updates, and more.

+ +

ARIA is a set of special accessibility attributes which can be added to any markup, but is especially suited to HTML. The role attribute defines what the general type of object is (such as an article, alert, or slider). Additional ARIA attributes provide other useful properties, such as a description for a form or the current value of a progressbar.

+ +

ARIA is implemented in most popular browsers and screen readers. However, implementations vary and older technologies don't support it well (if at all). Use either "safe" ARIA that degrades gracefully, or ask users to upgrade to newer technology.

+ +
+

Note: Please contribute and make ARIA better for the next person! Not enough time? Send suggestions to Mozilla's accessibility mailing list, or #accessibility IRC channel.

+
+ + + + + + + + + + + + + +
+

Getting Started with ARIA

+ +
+
Introduction to ARIA
+
A quick introduction to making dynamic content accessible with ARIA. See also the classic ARIA intro by Gez Lemon, from 2008.
+
Web Applications and ARIA FAQ
+
Answers common questions about WAI-ARIA and why it's needed to make web applications accessible.
+
Videos of Screen Readers Using ARIA
+
See both real and simplfied examples from around the web, including "before" and "after" ARIA videos. 
+
Using ARIA in HTML
+
A practical guide for developers. It suggests what ARIA attributes to use on HTML elements. Suggestions are based on implementation realities.
+
+ +

Simple ARIA Enhancements

+ +
+
Enhancing Page Navigation with ARIA Landmarks
+
A nice intro to using ARIA landmarks to improve web page navigation for screen reader users. See also, ARIA landmark implementation notes and examples on real sites (updated as of July '11).
+
Improving Form Accessibility
+
ARIA is not just for dynamic content! Learn how to improve accessibility of HTML forms using additional ARIA attributes. 
+
Live regions (work-in-progress)
+
Live regions provide suggestions to screen readers about how to handle changes to the contents of a page.
+
Using ARIA Live Regions to Announce Content Changes
+
A quick summary of live regions, by the makers of JAWS screen reader software. Note that live regions are also supported by NVDA in Firefox, and VoiceOver with Safari (as of OS X Lion and iOS 5).
+
+ +

ARIA for Scripted Widgets

+ +
+
Keyboard Navigation and Focus for JavaScript Widgets
+
The first step in developing an accessible JavaScript widget is to make it keyboard navigable. This article steps through the process. The Yahoo! focus management article is a great resource as well.
+
Style Guide for Keyboard Navigation
+
A challenge with ARIA is getting developers to implement consistent behavior -- clearly best for users. This style guide describes the keyboard interface for common widgets.
+
+ +

ARIA Resources

+ +
+
Widget Techniques, Tutorials, and Examples
+
Need a slider, a menu, or another kind of widget? Find resources here.
+
ARIA-Enabled JavaScript UI Libraries
+
If you're starting a new project, choose a UI widget library with ARIA support already built-in. Warning: this is from 2009 -- content should be moved to an MDN page where it can be updated.
+
Accessibility of HTML5 and Rich Internet Applications - CSUN 2012 Workshop Materials
+
Includes slide presentations and examples.
+
+
+

Mailing List

+ +
+
Free ARIA Google Group
+
A place to ask questions about ARIA, as well as make suggestions for improving the ARIA documentation found on these pages.
+
+ +

Blogs

+ +

ARIA information on blogs tends to get out of date quickly. Still, there is some great info out there from other developers making ARIA work today.

+ +

Paciello Group

+ +

Accessible Culture

+ +

Filing Bugs

+ +

File ARIA bugs on browsers, screen readers, and JavaScript libraries.

+ +

Examples

+ +
+
ARIA Examples Library
+
A set of barebones example files which are easy to learn from.
+
Accessible JS Widget Library Demos
+
Dojo, jQueryFluid, YUI
+
+ +
+
Yahoo! Mail
+
Yahoo! puts it all together with Yahoo! Mail, a web app that almost looks like a native app. It works very well. As a review of Yahoo! Mail by screen reader Marco Zehe says, "Keep up the good work!".
+
+ +
+
Yahoo! Search
+
Yahoo! has done an amazing job of advancing ARIA here, by exercising ARIA's full capabilities and sharing their techniques. Yahoo! Search uses a combination of ARIA landmarks, live regions, and widgets.
+
+ +

Standardization Efforts

+ +
+
WAI-ARIA Activities Overview at W3C
+
Authoritative Overview of WAI-ARIA Standardization efforts by the Web Accessibility Initiative (WAI)
+
WAI-ARIA Specification
+
The W3C specification itself, useful as a reference. Note that, at this stage, it is important to test compatibility, as implementations are still inconsistent.
+
WAI-ARIA Authoring Practices
+
Like the W3C WAI-ARIA specification, the official best practices represents a future ideal -- a day when authors can rely on consistent ARIA support across browsers and screen readers. The W3C documents provide an in-depth view of ARIA.
+
+ For now, web developers implementing ARIA should maximize compatibility. Use best practices docs and examples based on current implementations.
+
Open AJAX Accessibility Task Force
+
The Open AJAX effort centers around developing tools, sample files, and automated tests for ARIA.
+
Under Construction: WCAG 2.0 ARIA Techniques
+
The community needs a complete set of WCAG techniques for WAI-ARIA + HTML, so that organizations can be comfortable claiming their ARIA-enabled content is WCAG compliant. This is mostly important when regulations or policies are based on WCAG.
+
+
+ + +
+
Accessibility, AJAX, JavaScript
+
+
+ +

 

diff --git a/files/zh-tw/web/accessibility/index.html b/files/zh-tw/web/accessibility/index.html new file mode 100644 index 0000000000..b8ed259ecf --- /dev/null +++ b/files/zh-tw/web/accessibility/index.html @@ -0,0 +1,61 @@ +--- +title: 無障礙網頁 +slug: Web/Accessibility +tags: + - Accessibility + - Advanced + - Landing + - NeedsTranslation + - TopicStub + - Web Development +translation_of: Web/Accessibility +--- +

網路開發中的無障礙網頁,意味著盡可能令所有人都能使用網站,就算是在某些感官方面受限的人也不例外。本頁面會提供一些關於無障礙網頁的資訊。

+ +

「理想的無障礙環境就是在各方面都營造一個無障礙的環境。在有形方面,所應該考量事情包括,生活上、行動上、教育上所可能遭受到的障礙,並提供其足以克服這些環境的需求,此等需求包括個體本身的配備,如點字機……以及周圍環境中的裝設,如扶手、導盲磚……」 中文維基百科的「無障礙環境」、「理想無障礙環境」章節

+ +

從根本上,網路是為了在所有人面前都能運行而設計的,無論他們使用的軟硬體、語言文化、地理位置、抑或身心功能如何。當聽覺、運動、視力或認知能力障礙的人,都能訪問網路的時候,這個目標才算達成。」W3C - Accessibility

+ +
+
+

重要概念

+ +

MDN Accessibility Learning Area 涵蓋了最新的無障礙網頁教學所需:

+ +
+
何謂無障礙網頁?
+
這篇文章針對何謂無障礙網頁,起了一個好開頭。這模塊包含了要考慮哪些族群以及理由、不同族群會用什麼工具和 Web 互動、還有怎麼把無障礙網頁導入 Web 開發工作流程。
+
HTML:無障礙網頁的好開始
+
只要確保在任何時候,正確的 HTML 元素都用於正確的目的,就能消除各種網頁的障礙。這篇文章詳述 HTML 如何確保網頁無障礙。
+
充分實踐 CSS 與 JavaScript 的無障礙
+
如果 CSS 與 JavaScript 使用得當,將可以為無障礙網頁提供助力……反過來的話,就會嚴重影響無障礙體驗。這篇文章詳述如何在內容複雜的情況下,確保能充分實踐 CSS 與 JavaScript 的無障礙。
+
WAI-ARIA 基礎
+
從之前的文章來看,有時製作要涉及到非語意的 HTML 還有動態 JavaScript 更新技術……等,會令複雜的 UI 控制變得很困難。WAI-ARIA 正是為了解決此一問題而生。它對瀏覽器和輔助技術添加進一步的語意,讓用戶能知道發生了什麼事。我們將介紹如何在基本層面使用此技術,以提昇無障礙。
+
無障礙多媒體
+
會導致無障礙網頁出問題的另一個根源是多媒體:影片、聲音、圖片等內容,需要有合適的文字替代,以便輔助技術和它的用戶能夠理解。我們將在這篇文章中闡明作法。
+
行動無障礙網頁
+
隨著行動設備訪問漸受歡迎、還有像是 iOS 與 Android 這般熱門平台,已經具備完善的輔助工具,考慮到如何在這些平台上實踐無障礙網頁,就變得十分重要。這篇文章將討論行動裝置特有的無障礙網頁相關議題。
+
+
+ +
+

其他文件

+ +
+
Understanding the Web Content Accessibility Guidelines
+
+

This set of articles provides quick explanations to help you understand the steps that need to be taken to conform to the recommendations outlined in the W3C Web Content Accessibility Guidelines 2.0 (WCAG 2.0 or just WCAG, for the purposes of this writing).

+
+
Keyboard-navigable JavaScript widgets
+
Until now, web developers who want to make their styled <div> and <span> based widgets have lacked the proper techniques. Keyboard accessibility is part of the minimum accessibility requirements which a developer should be aware of.
+
ARIA
+
A collection of articles to learn how to use ARIA to make your HTML documents more accessible.
+
Assistive technology (AT) development
+
A collection of articles intended for AT developers
+
Mobile accessibility checklist
+
This document provides a concise checklist of accessibility requirements for mobile app developers.
+
+ +

所有與無障礙網頁相關的文章……

+
+
diff --git a/files/zh-tw/web/accessibility/mobile_accessibility_checklist/index.html b/files/zh-tw/web/accessibility/mobile_accessibility_checklist/index.html new file mode 100644 index 0000000000..b05da206bc --- /dev/null +++ b/files/zh-tw/web/accessibility/mobile_accessibility_checklist/index.html @@ -0,0 +1,94 @@ +--- +title: 行動無障礙檢核清單 +slug: Web/Accessibility/Mobile_accessibility_checklist +translation_of: Web/Accessibility/Mobile_accessibility_checklist +--- +
+

本文提供行動應用程式開發者一個簡潔的無障礙必備要件檢核清單,本文將隨著更多模型產生而不斷地演進。

+
+ +

顏色

+ + + +
+

注意: Jon Snook已撰寫實用的 Colour Contrast Checker 能用於檢查背景與前景顏色的對比。同樣地,Tanaguru Contrast-Finder 也提供類似功能,而且建議相似且更好的對比顏色提供你考量使用。

+
+ +

可視性

+ + + +

焦點

+ + + +

文字相等意義

+ + + +

處理狀態

+ + + +

一般準則

+ + + +
+

注意: Tanaguru自動無障礙測試服務提供有用的方法去發現一些發生於網頁或安裝的網頁應用程式(如Firefox OS)無障礙錯誤。你可在tanaguru.org找到更多關於Tanaguru技術開發,以及貢獻該專案的資訊。

+
+ +
+

注意: 本文件原始版本Yura Zenevich撰寫。

+
+ +

 

diff --git a/files/zh-tw/web/api/abortcontroller/index.html b/files/zh-tw/web/api/abortcontroller/index.html new file mode 100644 index 0000000000..8caa750806 --- /dev/null +++ b/files/zh-tw/web/api/abortcontroller/index.html @@ -0,0 +1,97 @@ +--- +title: AbortController +slug: Web/API/AbortController +translation_of: Web/API/AbortController +--- +
{{APIRef("DOM")}}{{SeeCompatTable}}
+ +

AbortController 介面代表一個控制器物件,讓你可以在需要時中斷一個或多個 DOM 請求。

+ +

你可以使用 {{domxref("AbortController.AbortController()")}} 建立一個新的 AbortController 物件。與 DOM 請求溝通時則是使用 {{domxref("AbortSignal")}} 物件。

+ +

建構子

+ +
+
{{domxref("AbortController.AbortController()")}}
+
建立一個新的 AbortController 物件實體。
+
+ +

屬性

+ +
+
{{domxref("AbortController.signal")}} {{readonlyInline}}
+
回傳一個 {{domxref("AbortSignal")}} 物件實體,可以用來中斷一個 DOM 請求、或是與其溝通。
+
+ +

方法

+ +
+
{{domxref("AbortController.abort()")}}
+
在一個 DOM 請求完成前中斷他。這可以用來中斷 fetch 請求、對任何 Response {{domxref("Body")}} 的讀取、或是資料流。
+
+ +

範例

+ +

在下面的程式碼片段中,我們要用 Fetch API 來下載一部影片。

+ +

我們首先用 {{domxref("AbortController.AbortController","AbortController()")}} 建立一個控制器,然後透過 {{domxref("AbortController.signal")}} 屬性取得他的 {{domxref("AbortSignal")}} 物件。

+ +

在初始化 fetch 請求 的時候,我們把 AbortSignal 作為選項傳入該請求的選項物件中(參考下方的 {signal})。這樣會把剛才的中斷訊號與控制器跟 fetch 請求關聯起來,讓我們可以透過呼叫 {{domxref("AbortController.abort()")}} 來中斷該請求。請參考下方範例中第二個事件處理器。

+ +
var controller = new AbortController();
+var signal = controller.signal;
+
+var downloadBtn = document.querySelector('.download');
+var abortBtn = document.querySelector('.abort');
+
+downloadBtn.addEventListener('click', fetchVideo);
+
+abortBtn.addEventListener('click', function() {
+  controller.abort();
+  console.log('下載已中斷');
+});
+
+function fetchVideo() {
+  ...
+  fetch(url, {signal}).then(function(response) {
+    ...
+  }).catch(function(e) {
+    reports.textContent = '下載錯誤: ' + e.message;
+  })
+}
+ +
+

注意: 當 abort() 被呼叫的時候,fetch() 回傳的 Promise 會被以 AbortError 拒絕。

+
+ +

在 GitHub 有個完整的範例可供參考 — 請參見 abort-api或是也可以實際體驗看看)。

+ +

規格

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#interface-abortcontroller', 'AbortController')}}{{Spec2('DOM WHATWG')}}初始定義
+ +

瀏覽器相容性

+ + + +

{{Compat("api.AbortController")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/ambient_light_events/index.html b/files/zh-tw/web/api/ambient_light_events/index.html new file mode 100644 index 0000000000..06eadc5621 --- /dev/null +++ b/files/zh-tw/web/api/ambient_light_events/index.html @@ -0,0 +1,96 @@ +--- +title: 使用光線事件 +slug: Web/API/Ambient_Light_Events +translation_of: Web/API/Ambient_Light_Events +--- +

{{ SeeCompatTable }}

+

摘要

+

環境光源 (Ambient light) 事件,可告知 Apps 或網頁目前光線強度的變化,以利做出反應,例如改變使用者介面 (User Interface,UI) 的顏色對比,或在拍照時改變曝光程度

+

光源事件

+

只要裝置的光線感測器偵測到光線強度變化,隨即通知瀏覽器。一旦瀏覽器取得該通知,就會發出 DeviceLightEvent 事件而提供光線強度的確實資訊。

+

只要使用 addEventListener 函式 (使用 {{event("devicelight")}} 事件名稱),或將事件處理器 (Event Handler) 附加至 window.ondevicelight 屬性,均可於 window 物件擷取到此事件。

+

一旦擷取完畢,則事件物件將透過 DeviceLightEvent.value 屬性,存取光線強度值 (以 Lux 為單位)。

+

範例

+
window.addEventListener('devicelight', function(event) {
+  var html = document.getElementsByTagName('html')[0];
+
+  if (event.value < 50) {
+    html.classList.add('darklight');
+    html.classList.remove('brightlight');
+  } else {
+    html.classList.add('brightlight');
+    html.classList.remove('darklight');
+  }
+});
+

規格

+ + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('AmbientLight', '', 'Ambient Light Events') }}{{ Spec2('AmbientLight') }}Initial specification
+

瀏覽器相容性

+

{{ CompatibilityTable() }}

+
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
{{domxref("DeviceLightEvent")}}{{CompatNo()}}{{CompatGeckoDesktop("22.0")}} (Mac OS X only){{CompatNo()}}{{CompatNo()}}{{CompatNo()}}
+
+
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
{{domxref("DeviceLightEvent")}}{{CompatNo()}}{{CompatNo()}}{{CompatGeckoMobile("15.0")}}{{CompatNo()}}{{CompatNo()}}{{CompatNo()}}
+
+

Gecko 說明

+

已建構 {{event("devicelight")}} 事件,且在 Firefox Mobile for Android (15.0) 與 Firefox OS (B2G) 中均預設為開啟。從 Gecko 22.0 (Firefox 22.0 / Thunderbird 22.0 / SeaMonkey 2.19) 開始,亦提供 Mac OS X 的桌機支援。目前對 Windows 7 的支援功能仍開發中 (請見 bug 754199)。

+

另請參閱

+ diff --git a/files/zh-tw/web/api/analysernode/getbytefrequencydata/index.html b/files/zh-tw/web/api/analysernode/getbytefrequencydata/index.html new file mode 100644 index 0000000000..d6b226dd8f --- /dev/null +++ b/files/zh-tw/web/api/analysernode/getbytefrequencydata/index.html @@ -0,0 +1,149 @@ +--- +title: AnalyserNode.getByteFrequencyData() +slug: Web/API/AnalyserNode/getByteFrequencyData +translation_of: Web/API/AnalyserNode/getByteFrequencyData +--- +

{{ APIRef("Web Audio API") }}

+ +
+

{{ domxref("AnalyserNode") }} 介面的 getByteFrequencyData() 方法會將當前的頻率資料複製到 {{domxref("Uint8Array")}} (無號 byte 陣列)。

+ +

如果陣列的元素數目比 {{domxref("AnalyserNode.frequencyBinCount")}} 少的話,多餘的元素會被 drop 掉。如果比需要的少的話,多餘的元素會被忽略。

+
+ +

語法

+ +
var audioCtx = new AudioContext();
+var analyser = audioCtx.createAnalyser();
+var dataArray = new Uint8Array(analyser.frequencyBinCount); // Uint8Array 應該要和 frequencyBinCount 等長
+analyser.getByteFrequencyData(dataArray); // 將 getByteFrequencyData() 回傳的資料放進 Uint8Array
+
+ +

回傳值

+ +

{{domxref("Uint8Array")}}。

+ +

範例

+ +

下面的範例顯示出 {{domxref("AudioContext")}} 用於建立一個 AnalyserNode 的基本用法,然後 {{domxref("window.requestAnimationFrame()", "requestAnimationFrame")}} 以及 {{htmlelement("canvas")}} 用來重複收集當前聲音輸入的頻率資料並在 "winamp bargraph style" 畫出輸出。若要知道更完整的範例或是資訊,請參考 Voice-change-O-matic demo (看 app.js 第 128–205 行 會有相關的程式碼)。

+ +
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
+var analyser = audioCtx.createAnalyser();
+
+  ...
+
+analyser.fftSize = 256;
+var bufferLength = analyser.frequencyBinCount;
+console.log(bufferLength);
+var dataArray = new Uint8Array(bufferLength);
+
+canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
+
+function draw() {
+  drawVisual = requestAnimationFrame(draw);
+
+  analyser.getByteFrequencyData(dataArray);
+
+  canvasCtx.fillStyle = 'rgb(0, 0, 0)';
+  canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
+
+  var barWidth = (WIDTH / bufferLength) * 2.5;
+  var barHeight;
+  var x = 0;
+
+  for(var i = 0; i < bufferLength; i++) {
+    barHeight = dataArray[i];
+
+    canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ',50,50)';
+    canvasCtx.fillRect(x,HEIGHT-barHeight/2,barWidth,barHeight/2);
+
+    x += barWidth + 1;
+  }
+};
+
+draw();
+ +

參數

+ +
+
陣列
+
頻率定義域會被複製進去的 {{domxref("Uint8Array")}} 。
+
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態Comment
{{SpecName('Web Audio API', '#widl-AnalyserNode-getByteFrequencyData-void-Uint8Array-array', 'getByteFrequencyData()')}}{{Spec2('Web Audio API')}} 
+ +

瀏覽器支援度

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome(10.0)}}{{property_prefix("webkit")}}{{CompatGeckoDesktop(25.0)}} {{CompatNo}}15.0{{property_prefix("webkit")}}
+ 22 (unprefixed)
6.0{{property_prefix("webkit")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatUnknown}}26.01.2{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}33.0
+
+ +

參看

+ + diff --git a/files/zh-tw/web/api/analysernode/index.html b/files/zh-tw/web/api/analysernode/index.html new file mode 100644 index 0000000000..875993cea9 --- /dev/null +++ b/files/zh-tw/web/api/analysernode/index.html @@ -0,0 +1,226 @@ +--- +title: AnalyserNode +slug: Web/API/AnalyserNode +tags: + - API + - AnalyserNode + - Interface + - NeedsTranslation + - Reference + - TopicStub + - Web Audio API +translation_of: Web/API/AnalyserNode +--- +

{{APIRef("Web Audio API")}}

+ +

The AnalyserNode interface represents a node able to provide real-time frequency and time-domain analysis information. It is an {{domxref("AudioNode")}} that passes the audio stream unchanged from the input to the output, but allows you to take the generated data, process it, and create audio visualizations.

+ +

An AnalyzerNode has exactly one input and one output. The node works even if the output is not connected.

+ +

Without modifying the audio stream, the node allows to get the frequency and time-domain data associated to it, using a FFT.

+ + + + + + + + + + + + + + + + + + + + + + + + +
Number of inputs1
Number of outputs1 (but may be left unconnected)
Channel count mode"explicit"
Channel count1
Channel interpretation"speakers"
+ +

Inheritance

+ +

This interface inherits from the following parent interfaces:

+ +

{{InheritanceDiagram}}

+ +

Properties

+ +

Inherits properties from its parent, {{domxref("AudioNode")}}.

+ +
+
{{domxref("AnalyserNode.fftSize")}}
+
Is an unsigned long value representing the size of the FFT (Fast Fourier Transform) to be used to determine the frequency domain.
+
{{domxref("AnalyserNode.frequencyBinCount")}} {{readonlyInline}}
+
Is an unsigned long value half that of the FFT size. This generally equates to the number of data values you will have to play with for the visualization.
+
{{domxref("AnalyserNode.minDecibels")}}
+
Is a double value representing the minimum power value in the scaling range for the FFT analysis data, for conversion to unsigned byte values — basically, this specifies the minimum value for the range of results when using getByteFrequencyData().
+
{{domxref("AnalyserNode.maxDecibels")}}
+
Is a double value representing the maximum power value in the scaling range for the FFT analysis data, for conversion to unsigned byte values — basically, this specifies the maximum value for the range of results when using getByteFrequencyData().
+
{{domxref("AnalyserNode.smoothingTimeConstant")}}
+
Is a double value representing the averaging constant with the last analysis frame — basically, it makes the transition between values over time smoother.
+
+ +

Methods

+ +

Inherits methods from its parent, {{domxref("AudioNode")}}.

+ +
+
{{domxref("AnalyserNode.getFloatFrequencyData()")}}
+
Copies the current frequency data into a {{domxref("Float32Array")}} array passed into it.
+
+ +
+
{{domxref("AnalyserNode.getByteFrequencyData()")}}
+
Copies the current frequency data into a {{domxref("Uint8Array")}} (unsigned byte array) passed into it.
+
+ +
+
{{domxref("AnalyserNode.getFloatTimeDomainData()")}}
+
Copies the current waveform, or time-domain, data into a {{domxref("Float32Array")}} array passed into it.
+
{{domxref("AnalyserNode.getByteTimeDomainData()")}}
+
Copies the current waveform, or time-domain, data into a {{domxref("Uint8Array")}} (unsigned byte array) passed into it.
+
+ +

Examples

+ +
+

Note: See the guide Visualizations with Web Audio API for more information on creating audio visualizations.

+
+ +

Basic usage

+ +

The following example shows basic usage of an {{domxref("AudioContext")}} to create an AnalyserNode, then {{domxref("window.requestAnimationFrame()","requestAnimationFrame")}} and {{htmlelement("canvas")}} to collect time domain data repeatedly and draw an "oscilloscope style" output of the current audio input. For more complete applied examples/information, check out our Voice-change-O-matic demo (see app.js lines 128–205 for relevant code).

+ +
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
+var analyser = audioCtx.createAnalyser();
+
+  ...
+
+analyser.fftSize = 2048;
+var bufferLength = analyser.frequencyBinCount;
+var dataArray = new Uint8Array(bufferLength);
+analyser.getByteTimeDomainData(dataArray);
+
+// draw an oscilloscope of the current audio source
+
+function draw() {
+
+      drawVisual = requestAnimationFrame(draw);
+
+      analyser.getByteTimeDomainData(dataArray);
+
+      canvasCtx.fillStyle = 'rgb(200, 200, 200)';
+      canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
+
+      canvasCtx.lineWidth = 2;
+      canvasCtx.strokeStyle = 'rgb(0, 0, 0)';
+
+      canvasCtx.beginPath();
+
+      var sliceWidth = WIDTH * 1.0 / bufferLength;
+      var x = 0;
+
+      for(var i = 0; i < bufferLength; i++) {
+
+        var v = dataArray[i] / 128.0;
+        var y = v * HEIGHT/2;
+
+        if(i === 0) {
+          canvasCtx.moveTo(x, y);
+        } else {
+          canvasCtx.lineTo(x, y);
+        }
+
+        x += sliceWidth;
+      }
+
+      canvasCtx.lineTo(canvas.width, canvas.height/2);
+      canvasCtx.stroke();
+    };
+
+    draw();
+ +

Specifications

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Web Audio API', '#the-analysernode-interface', 'AnalyserNode')}}{{Spec2('Web Audio API')}} 
+ +

Browser compatibility

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome(10.0)}}{{property_prefix("webkit")}}{{CompatGeckoDesktop(25.0)}} {{CompatNo}}15.0 {{property_prefix("webkit")}}
+ 22
6.0{{property_prefix("webkit")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatUnknown}}26.01.2{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}33.0
+
+ +

See also

+ + diff --git a/files/zh-tw/web/api/animationevent/index.html b/files/zh-tw/web/api/animationevent/index.html new file mode 100644 index 0000000000..d4528894b5 --- /dev/null +++ b/files/zh-tw/web/api/animationevent/index.html @@ -0,0 +1,182 @@ +--- +title: AnimationEvent +slug: Web/API/AnimationEvent +tags: + - API + - CSS + - CSS Animations + - Experimental + - Interface + - NeedsTranslation + - Reference + - TopicStub +translation_of: Web/API/AnimationEvent +--- +

{{SeeCompatTable}}{{APIRef("Web Animations API")}}

+ +

摘要

+ +

AnimationEvent 介面表現提供動畫相關資訊的事件。

+ +

{{InheritanceDiagram}}

+ +

性能

+ +

另外從其父 {{domxref("Event")}} 繼承屬性

+ +
+
{{domxref("AnimationEvent.animationName")}} {{readonlyInline}}
+
是一個{{domxref("DOMString")}}包含的值 {{cssxref("animation-name")}} CSS屬性與過渡有關。
+
{{domxref("AnimationEvent.elapsedTime")}} {{readonlyInline}}
+
是一個float給予時間的動畫已經運行,以秒為單位,當該事件燒製,不含動畫被暫停的任何時間量。為一個"animationstart"事件,elapsedTime0.0,除非有一個負值{{cssxref("animation-delay")}},在這種情況下,該事件將與燒製elapsedTime含有 (-1 * delay)
+
{{domxref("AnimationEvent.pseudoElement")}} {{readonlyInline}}
+
是一個{{domxref("DOMString")}},從"::",包含的名字虛擬元素的動畫運行。如果動畫上不偽元素,但該元素,一個空字符串上運行:''。
+
+ +

構造函數

+ +
+
{{domxref("AnimationEvent.AnimationEvent","AnimationEvent()")}}
+
創建一個AnimationEvent事件具有給定參數。
+
+ +

方法

+ +

同時繼承其父{{domxref("事件")}}方法

+ +
+
{{domxref("AnimationEvent.initAnimationEvent()")}} {{non-standard_inline}}{{deprecated_inline}}
+
初始化AnimationEvent 使用過時的創建 {{domxref("Document.createEvent()", "Document.createEvent(\"AnimationEvent\")")}} 方法。
+
+ +

規範

+ + + + + + + + + + + + + + + + +
產品規格狀態註解
{{ SpecName('CSS3 Animations', '#AnimationEvent-interface', 'AnimationEvent') }}{{ Spec2('CSS3 Animations') }}初始定義。
+ +

瀏覽器兼容性

+ +

{{CompatibilityTable()}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
特點ChromeFirefox (Gecko)Internet ExplorerOperaSafari
基本支持1.0 {{ property_prefix("webkit") }}{{CompatGeckoDesktop("6.0")}}10.012 {{property_prefix("O")}}
+ 12.10
+ 15.0 {{ property_prefix("webkit") }}
4.0 {{ property_prefix("webkit") }}
AnimationEvent()構造函數{{CompatNo}}{{CompatGeckoDesktop("23.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
initAnimationEvent(){{non-standard_inline}} {{deprecated_inline}}1.0{{CompatGeckoDesktop("6.0")}}
+ 在{{CompatGeckoDesktop("23.0")}}刪除
10.0124
pseudoelement{{CompatNo}}{{CompatGeckoDesktop("23.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
特點AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
基本支持{{CompatVersionUnknown}}{{ property_prefix("webkit") }}{{ CompatGeckoMobile("6.0") }}10.012 {{ property_prefix("o") }}
+ 12.10
+ 15.0 {{ property_prefix("webkit") }}
{{CompatVersionUnknown}}{{ property_prefix("webkit") }}{{CompatChrome(43.0)}}
AnimationEvent()構造函數{{CompatNo}}{{CompatGeckoMobile("23.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
initAnimationEvent(){{non-standard_inline}} {{deprecated_inline}}{{CompatVersionUnknown}}{{CompatGeckoMobile("6.0")}}
+ 在{{CompatGeckoMobile("23.0")}}刪除
10.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
pseudoelement{{CompatNo}}{{CompatGeckoMobile("23.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

另請參見

+ + diff --git a/files/zh-tw/web/api/animationevent/initanimationevent/index.html b/files/zh-tw/web/api/animationevent/initanimationevent/index.html new file mode 100644 index 0000000000..de5c7efe15 --- /dev/null +++ b/files/zh-tw/web/api/animationevent/initanimationevent/index.html @@ -0,0 +1,129 @@ +--- +title: AnimationEvent.initAnimationEvent() +slug: Web/API/AnimationEvent/initAnimationEvent +tags: + - API + - AnimationEvent + - CSSOM + - Method + - Obsolete + - Web Animations +translation_of: Web/API/AnimationEvent/initAnimationEvent +--- +

{{obsolete_header}}{{non-standard_header}}{{ apiref("Web Animations API") }}

+ +

Summary

+ +

The AnimationEvent.initAnimationEvent() method Initializes an animation event created using the deprecated {{domxref("Document.createEvent()", "Document.createEvent(\"AnimationEvent\")")}} method.

+ +

AnimationEvent created this way are untrusted.

+ +
+

Note: During the standardization process, this method was removed from the specification. It has been deprecated and is in the progress of being removed from most implementations. Do not use this method; instead, use the standard constructor, {{domxref("AnimationEvent.AnimationEvent", "AnimationEvent()")}}, to create a synthetic {{domxref("AnimationEvent")}}.

+
+ +

Syntax

+ +
animationEvent.initAnimationEvent(typeArg, canBubbleArg, cancelableArg, animationNameArg, elapsedTimeArg);
+ +

Parameters

+ +
+
typeArg
+
A {{domxref("DOMString")}} identifying the specific type of animation event that occurred. The following values are allowed: + + + + + + + + + + + + + + + + + + + + + +
ValueMeaning
animationstartThe animation has started.
animationendThe animation completed.
animationiterationThe current iteration just completed.
+
+
canBubbleArg
+
A {{domxref("Boolean")}} flag indicating if the event can bubble (true) or not (false).
+
cancelableArg
+
A {{domxref("Boolean")}} flag indicating if the event associated action can be avoided (true) or not (false).
+
animationNameArg
+
A {{domxref("DOMString")}} containing the value of the {{cssxref("animation-name")}} CSS property associated with the transition.
+
elapsedTimeArg
+
A float indicating the amount of time the animation has been running, in seconds, as of the time the event was fired, excluding any time the animation was paused. For an "animationstart" event, elapsedTime is 0.0 unless there was a negative value for animation-delay, in which case the event will be fired with elapsedTime containing  (-1 * delay).
+
+ +

Specifications

+ +

This method is non-standard and not part of any specification, though it was present in early drafts of {{SpecName("CSS3 Animations")}}.

+ +

Browser compatibility

+ +

{{ CompatibilityTable }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{ CompatGeckoDesktop("6.0") }}
+ Removed in {{ CompatGeckoDesktop("23.0") }}
10.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{ CompatGeckoMobile("6.0") }}
+ Removed in {{ CompatGeckoMobile("23.0") }}
10.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

See also

+ + diff --git a/files/zh-tw/web/api/battery_status_api/index.html b/files/zh-tw/web/api/battery_status_api/index.html new file mode 100644 index 0000000000..cbf98d417d --- /dev/null +++ b/files/zh-tw/web/api/battery_status_api/index.html @@ -0,0 +1,38 @@ +--- +title: Battery Status API +slug: Web/API/Battery_Status_API +translation_of: Web/API/Battery_Status_API +--- +

Battery Status API 也就是所謂的 Battery API,將提供系統電池充電容量的資訊,並在電池容量變化時送出事件,以通知使用者。此 API 可調整 Apps 的資源耗用量,在電力偏低時縮減耗電量;或可在電力耗盡之前儲存檔案,避免資料遺失。

+

Battery Status API 是以 window.navigator.battery 屬性 (為 BatteryManager 物件) 而擴充了 window.navigator,並新增數項可讓使用者接收的新事件,以隨時監控電池狀態。

+

範例

+

在此範例中,我們將分別監聽 chargingchangelevelchange 事件,而看到充電狀態 (不論是否插電進行充電) 與電池容量的變化。

+
var battery = navigator.battery || navigator.mozBattery || navigator.webkitBattery;
+
+function updateBatteryStatus() {
+  console.log("Battery status: " + battery.level * 100 + " %");
+
+  if (battery.charging) {
+    console.log("Battery is charging");
+  }
+}
+
+battery.addEventListener("chargingchange", updateBatteryStatus);
+battery.addEventListener("levelchange", updateBatteryStatus);
+updateBatteryStatus();
+
+

另可參閱規格所提供之範例

+

規格

+

{{page("/en-US/docs/Web/API/BatteryManager","Specifications")}}

+

瀏覽器相容性

+

{{page("/en-US/docs/Web/API/BatteryManager","Browser_compatibility")}}

+

另請參閱

+ diff --git a/files/zh-tw/web/api/blob/blob/index.html b/files/zh-tw/web/api/blob/blob/index.html new file mode 100644 index 0000000000..26fb1e8ef7 --- /dev/null +++ b/files/zh-tw/web/api/blob/blob/index.html @@ -0,0 +1,125 @@ +--- +title: Blob() +slug: Web/API/Blob/Blob +translation_of: Web/API/Blob/Blob +--- +

{{APIRef("File API")}}

+ +

Blob() 建構式會回傳一個新建立的 {{domxref("Blob")}} 物件。新物件的內容是由 array 參數的成員值串連所構成。

+ +

語法

+ +
var aBlob = new Blob( array, options );
+
+ +

參數

+ + + +

範例

+ +
var aFileParts = ['<a id="a"><b id="b">hey!</b></a>']; // an array consisting of a single DOMString
+var oMyBlob = new Blob(aFileParts, {type : 'text/html'}); // the blob
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('File API', '#constructorBlob', 'Blob()')}}{{Spec2('File API')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能ChromeFirefox (Gecko)Internet ExplorerOperaSafari
+

基礎支援

+
20{{CompatGeckoDesktop("13.0")}} [1]1012.108
在 Workers 中{{CompatUnknown}}{{CompatGeckoDesktop("14.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
基礎支援{{CompatUnknown}}{{CompatGeckoMobile("13.0")}} [1]{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}
在 Workers 中{{CompatUnknown}}{{CompatGeckoMobile("14.0")}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] 在 Firefox 16 以前,第二個參數若被設為 nullundefined 會導致錯誤而不是當成一個空鍵值。

+ +

參見

+ + + +

 

diff --git a/files/zh-tw/web/api/blob/index.html b/files/zh-tw/web/api/blob/index.html new file mode 100644 index 0000000000..457628556c --- /dev/null +++ b/files/zh-tw/web/api/blob/index.html @@ -0,0 +1,116 @@ +--- +title: Blob +slug: Web/API/Blob +translation_of: Web/API/Blob +--- +

{{APIRef("File API")}}

+ +

Blob(Binary Large Object)物件代表了一個相當於檔案(原始資料)的不可變物件。Blob 中的資料並不一定是 JavaScript 原生的格式。{{domxref("File")}} 介面基於 Blob,繼承 blob 並擴充其功能以支援操作使用者系統上的檔案。

+ +

從其它非 Blob 物件或資料來建構 Blob 物件,可以使用 {{domxref("Blob.Blob", "Blob()")}} 建構式。要建立一個包含目前 blob 內容子集的 blob,可使用 {{domxref("Blob.slice()", "slice()")}} 方法。若要自使用者系統上的檔案取得 Blob 物件,請參考 {{domxref("File")}} 文件。

+ +

接受 Blob 物件的 API 可以在 {{domxref("File")}} 上找到。

+ +
+

註:早期 slice() 方法擁有第二個參數 length 以指定在建立新 Blob 物件時要複製的位元組(byte)數量。假如指定的 start + length 超出了來源 Blob 的大小,則回傳的 Blob 會包含自索引 start 至結尾的完整來源內容。

+
+ +
+

註:需注意在部分瀏覽器版本中,slice() 方法帶有前綴:Firefox 12 與之前的版本為 blob.mozSlice(),Safari 中是 blob.webkitSlice()。舊的、無前綴字版本的 slice() 方法則有不同的語意(semantics),但這是已淘汰的方法。瀏覽器對 blob.mozSlice() 的支援已在 Firefox 30 時中止。

+
+ +

建構式

+ +
+
{{domxref("Blob.Blob", "Blob(blobParts[, options])")}}
+
回傳新建立的 Blob 物件,包含了建構式參數傳入之陣列所串聯後的值。第二個參數為 BlobPropertyBag 物件,其擁有 type 和 endings 屬性
+
+ +

屬性

+ +
+
{{domxref("Blob.size")}} {{readonlyinline}}
+
以 byte 為單位的 Blob 物件大小。
+
{{domxref("Blob.type")}} {{readonlyinline}}
+
Blob 物件中資料的型態,以 MIME 類型的字串表示。若型態為未知,則為空字串。
+
+ +

方法

+ +
+
{{domxref("Blob.slice()", "Blob.slice([start[, end[, contentType]]])")}}
+
回傳一個包含當前 Blob 物件之指定資料範圍(byte)內容的新 Blob 物件。
+
+ +

範例

+ +

Blob 建構函數用法範例

+ +

{{domxref("Blob.Blob", "Blob() constructor")}} 建構式允許由其它物件建立 blob 物件。以下的範例演示了以字串來建構 blob 物件:

+ +
var debug = {hello: "world"};
+var blob = new Blob([JSON.stringify(debug, null, 2)], {type : 'application/json'});
+ +
+

在 Blob 建構式出現之前,可以透過 {{domxref("BlobBuilder")}} 來建立 blob 物件(目前已不建議使用):

+ +
var builder = new BlobBuilder();
+var fileParts = ['<a id="a"><b id="b">hey!</b></a>'];
+builder.append(fileParts[0]);
+var myBlob = builder.getBlob('text/xml');
+
+ +

藉型別陣列建構的 blob 來建立 URL

+ +

範例程式碼:

+ +
var typedArray = GetTheTypedArraySomehow();
+var blob = new Blob([typedArray], {type: 'application/octet-binary'}); // pass a useful mime type here
+var url = URL.createObjectURL(blob);
+// url will be something like: blob:d3958f5c-0777-0845-9dcf-2cb28783acaf
+// now you can use the url in any context that regular URLs can be used in, for example img.src, etc.
+
+ +

從 Blob 取出資料

+ +

從 Blob 讀取資料的唯一方式就是使用 {{domxref("FileReader")}}。以下範例展示了讀取 Blob 內容作為型別陣列:

+ +
var reader = new FileReader();
+reader.addEventListener("loadend", function() {
+   // reader.result contains the contents of blob as a typed array
+});
+reader.readAsArrayBuffer(blob);
+ +

藉由操作 {{domxref("FileReader")}} 的其他方法,將 Blob 讀取成字串或是 data URL 是有可能的。

+ +

規範

+ + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('File API','#blob','Blob')}}{{Spec2('File API')}}Initial definition.
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Blob")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/blob/size/index.html b/files/zh-tw/web/api/blob/size/index.html new file mode 100644 index 0000000000..0abccad27d --- /dev/null +++ b/files/zh-tw/web/api/blob/size/index.html @@ -0,0 +1,114 @@ +--- +title: Blob.size +slug: Web/API/Blob/size +tags: + - API + - Files + - Property + - Reference + - WebAPI + - 參考 + - 屬性 +translation_of: Web/API/Blob/size +--- +
{{APIRef("File API")}}
+ +

Blob.size 屬性回傳以 byte 為單位的 {{domxref("Blob")}} 或一個 {{domxref("File")}} 的大小。

+ +

語法

+ +
var sizeInBytes = blob.size
+
+ +

+ +

一個數字。

+ +

範例

+ +
// fileInput 是個 HTMLInputElement: <input type="file" multiple id="myfileinput">
+var fileInput = document.getElementById("myfileinput");
+
+// files 是個 FileList 物件 (類似 NodeList)
+var files = fileInput.files;
+
+for (var i = 0; i < files.length; i++) {
+  console.log(files[i].name + " has a size of " + files[i].size + " Bytes");
+}
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態附註
{{SpecName('File API', '#dfn-size', 'size')}}{{Spec2('File API')}}初定義
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
功能ChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
File.size5{{CompatVersionUnknown}}{{CompatGeckoDesktop("2")}}10.011.105.1
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
功能AndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
File.size{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/blob/type/index.html b/files/zh-tw/web/api/blob/type/index.html new file mode 100644 index 0000000000..ee2a231724 --- /dev/null +++ b/files/zh-tw/web/api/blob/type/index.html @@ -0,0 +1,114 @@ +--- +title: Blob.type +slug: Web/API/Blob/type +translation_of: Web/API/Blob/type +--- +
{{APIRef("File API")}}
+ +

Blob 物件的 type 屬性提供檔案的 MIME 類別。若無法辨明型別則回傳空字串。

+ +

語法

+ +
var mimetype = instanceOfFile.type
+ +

+ +

一個字串。

+ +

範例

+ +
var i, fileInput, files, allowedFileTypes;
+
+// fileInput 是個 HTMLInputElement: <input type="file" multiple id="myfileinput">
+fileInput = document.getElementById("myfileinput");
+
+// files 是個 FileList 物件 (類似 NodeList)
+files = fileInput.files;
+
+// 這範例接受 *.png, *.jpeg 和 *.gif 圖片。
+allowedFileTypes = ["image/png", "image/jpeg", "image/gif"];
+
+for (i = 0; i < files.length; i++) {
+  // 測試 file.type 是否是允許的類別。
+  if (allowedFileTypes.indexOf(files[i].type) > -1) {
+    // 若符合則執行這裡的程式碼。
+  }
+});
+
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態備註
{{SpecName('File API', '#dfn-type', 'type')}}{{Spec2('File API')}}初定義
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
功能ChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
File.type5{{CompatVersionUnknown}}{{CompatGeckoDesktop("2")}}10.011.105.1
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
功能AndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
File.type{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/body/index.html b/files/zh-tw/web/api/body/index.html new file mode 100644 index 0000000000..82ba54e53d --- /dev/null +++ b/files/zh-tw/web/api/body/index.html @@ -0,0 +1,99 @@ +--- +title: Body +slug: Web/API/Body +tags: + - API + - BODY + - Experimental + - Fetch + - Fetch API + - Interface + - NeedsTranslation + - Reference + - TopicStub + - request +translation_of: Web/API/Body +--- +
{{ APIRef("Fetch") }}
+ +

The Body {{glossary("mixin")}} of the Fetch API represents the body of the response/request, allowing you to declare what its content type is and how it should be handled.

+ +

Body is implemented by both {{domxref("Request")}} and {{domxref("Response")}}. This provides these objects with an associated body (a stream), a used flag (initially unset), and a MIME type (initially the empty byte sequence).

+ +

Properties

+ +
+
{{domxref("Body.body")}} {{readonlyInline}}
+
A simple getter used to expose a {{domxref("ReadableStream")}} of the body contents.
+
{{domxref("Body.bodyUsed")}} {{readonlyInline}}
+
A {{domxref("Boolean")}} that indicates whether the body has been read.
+
+ +

Methods

+ +
+
{{domxref("Body.arrayBuffer()")}}
+
Takes a {{domxref("Response")}} stream and reads it to completion. It returns a promise that resolves with an {{domxref("ArrayBuffer")}}.
+
{{domxref("Body.blob()")}}
+
Takes a {{domxref("Response")}} stream and reads it to completion. It returns a promise that resolves with a {{domxref("Blob")}}.
+
{{domxref("Body.formData()")}}
+
Takes a {{domxref("Response")}} stream and reads it to completion. It returns a promise that resolves with a {{domxref("FormData")}} object.
+
{{domxref("Body.json()")}}
+
Takes a {{domxref("Response")}} stream and reads it to completion. It returns a promise that resolves with the result of parsing the body text as {{jsxref("JSON")}}.
+
{{domxref("Body.text()")}}
+
Takes a {{domxref("Response")}} stream and reads it to completion. It returns a promise that resolves with a {{domxref("USVString")}} (text). The response is always decoded using UTF-8.
+
+ +

Examples

+ +

The example below uses a simple fetch call to grab an image and display it in an {{htmlelement("img")}} tag. You'll notice that since we are requesting an image, we need to run {{domxref("Body.blob","Body.blob()")}} ({{domxref("Response")}} implements body) to give the response its correct MIME type.

+ +

HTML Content

+ +
<img class="my-image" src="https://wikipedia.org/static/images/project-logos/frwiki-1.5x.png">
+
+ +

JS Content

+ +
var myImage = document.querySelector('.my-image');
+fetch('https://upload.wikimedia.org/wikipedia/commons/7/77/Delete_key1.jpg')
+	.then(res => res.blob())
+	.then(res => {
+		var objectURL = URL.createObjectURL(res);
+		myImage.src = objectURL;
+});
+ +

{{ EmbedLiveSample('Examples', '100%', '250px') }}

+ +

Specifications

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Fetch','#body-mixin','Body')}}{{Spec2('Fetch')}} 
+ +

Browser compatibility

+ + + +

{{Compat("api.Body")}}

+ +

See also

+ + + +

 

diff --git a/files/zh-tw/web/api/body/json/index.html b/files/zh-tw/web/api/body/json/index.html new file mode 100644 index 0000000000..70085afff7 --- /dev/null +++ b/files/zh-tw/web/api/body/json/index.html @@ -0,0 +1,73 @@ +--- +title: Body.json() +slug: Web/API/Body/json +translation_of: Web/API/Body/json +--- +
{{APIRef("Fetch")}}
+ +

{{domxref("Body")}} mixin 的 json() 會拿 {{domxref("Response")}} stream 並完整地讀取他。它會回傳一個能夠實現 (resolve) 把回傳的結果的 body text 解析成 {{jsxref("JSON")}} 型別的 Promise。

+ +

語法

+ +
response.json().then(function(data) {
+  // do something with your data
+});
+ +

參數

+ +

None.

+ +

回傳

+ +

一個能夠實現 (resolve) 把回傳的結果的 body text 解析成 JSON 型別的 Promise。這可以是任何能夠被 JSON 呈現的資料型別 — 物件 (object), 陣列 (array), 字串 (string), 數字 (number)...

+ +

範例

+ +

在我們的範例 fetch json example (run fetch json live) 中,我們用 constructor {{domxref("Request.Request")}} 產生一個新的請求,並且用它去取回 .json 檔案。 當成功取回 (fetch) 時,我們使用 json() 去讀取跟解析資料,然後依照我們期待的把回傳的結果物件 (resulting objects) 裡讀取到的數值存入 list 中藉以顯示我們的產品資料。

+ +
var myList = document.querySelector('ul');
+
+var myRequest = new Request('products.json');
+
+fetch(myRequest)
+  .then(function(response) { return response.json(); })
+  .then(function(data) {
+    for (var i = 0; i < data.products.length; i++) {
+      var listItem = document.createElement('li');
+      listItem.innerHTML = '<strong>' + data.products[i].Name + '</strong> can be found in ' +
+                           data.products[i].Location +
+                           '. Cost: <strong>£' + data.products[i].Price + '</strong>';
+      myList.appendChild(listItem);
+    }
+  });
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Fetch','#dom-body-json','json()')}}{{Spec2('Fetch')}}
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Body.json")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/canvas_api/drawing_graphics_with_canvas/index.html b/files/zh-tw/web/api/canvas_api/drawing_graphics_with_canvas/index.html new file mode 100644 index 0000000000..c93ad87e10 --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/drawing_graphics_with_canvas/index.html @@ -0,0 +1,161 @@ +--- +title: Drawing graphics with canvas +slug: Web/API/Canvas_API/Drawing_graphics_with_canvas +translation_of: Web/API/Canvas_API/Tutorial +--- +
+

Most of this content (but not the documentation on drawWindow) has been rolled into the more expansive Canvas tutorial, this page should probably be redirected there as it's now redundant but some information may still be relevant.

+
+

介紹

+

  在 Firefox 1.5, Firefox 引入了新的 HTML 元素 <canvas> 來繪製圖形。<canvas> 是基於 WHATWG canvas specification 的技術 (其發軔於蘋果公司在 Safari 上的實做)。 我們可以用它來在使用者端進行圖形和 UI 元件的渲染。

+

  <canvas> 創建了一個具有一致多個 rendering contexts 的區域。在本文中,我們著重於 2D rendering context 的部份。對於 3D 圖形,您可以參考 WebGL rendering context

+

2D Rendering Context

+

先來個簡單的範例

+

  以下的程式碼做了一個簡單的展示:繪製兩個部份交疊的矩形 (其中一個矩形有透明屬性) :

+
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  ctx.fillStyle = "rgb(200,0,0)";
+  ctx.fillRect (10, 10, 55, 50);
+
+  ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
+  ctx.fillRect (30, 30, 55, 50);
+}
+
+ +

{{EmbedLiveSample('A_Simple_Example','150','150','/@api/deki/files/602/=Canvas_ex1.png')}}

+

  這個名為 draw 的函式從 canvas element 取得 2d context。物件 ctx 可以被用來在 canvas 上頭繪製圖形。從程式碼可以看出,我們簡單的藉由設定 fillStyle 繪製了兩個顏色不同的矩形,並透過 fillRect 設定其位置。此外,第二個矩形透過 rgba() 配置了透明屬性。

+

  關於更複雜的圖形繪製,我們可以使用 fillRect, strokeRect 和 clearRect,他們分別可以畫出填滿的矩形, 僅有外框的矩形以及矩形區域清除。

+

路徑的使用

+

  beginPath 函式用來初始一段路徑的繪製,並且可以透過 moveTo, lineTo, arcTo, arc 以及相關的函式來描述路徑內容。要結束的時候呼叫 closePath 即可。一旦路徑描述完畢,就可以透過 fill 或 stroke 來渲染該路徑在 canvas 上。

+
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  ctx.fillStyle = "red";
+
+  ctx.beginPath();
+  ctx.moveTo(30, 30);
+  ctx.lineTo(150, 150);
+  // was: ctx.quadraticCurveTo(60, 70, 70, 150); which is wrong.
+  ctx.bezierCurveTo(60, 70, 60, 70, 70, 150); // <- this is right formula for the image on the right ->
+  ctx.lineTo(30, 30);
+  ctx.fill();
+}
+
+ +

{{EmbedLiveSample('Using_Paths','190','190','/@api/deki/files/603/=Canvas_ex2.png')}}

+

  呼叫 fill() 或 stroke() 代表該路徑已經被使用。若要重新進行填滿等動作,則需要重頭創造一次路徑。

+

圖像狀態

+

  fillStyle, strokeStyle, lineWidth 和 lineJoin 等屬性是 graphics state 的一部分。關於這些屬性的修改,您可以透過 save() 及 restore() 來進行操作。

+

一個更為複雜的範例

+

  接著我們來看一個稍微複雜一點的範例,它同時引入了路徑, 狀態的修改以及變換矩陣。

+
function drawBowtie(ctx, fillStyle) {
+
+  ctx.fillStyle = "rgba(200,200,200,0.3)";
+  ctx.fillRect(-30, -30, 60, 60);
+
+  ctx.fillStyle = fillStyle;
+  ctx.globalAlpha = 1.0;
+  ctx.beginPath();
+  ctx.moveTo(25, 25);
+  ctx.lineTo(-25, -25);
+  ctx.lineTo(25, -25);
+  ctx.lineTo(-25, 25);
+  ctx.closePath();
+  ctx.fill();
+}
+
+function dot(ctx) {
+  ctx.save();
+  ctx.fillStyle = "black";
+  ctx.fillRect(-2, -2, 4, 4);
+  ctx.restore();
+}
+
+function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // note that all other translates are relative to this one
+  ctx.translate(45, 45);
+
+  ctx.save();
+  //ctx.translate(0, 0); // unnecessary
+  drawBowtie(ctx, "red");
+  dot(ctx);
+  ctx.restore();
+
+  ctx.save();
+  ctx.translate(85, 0);
+  ctx.rotate(45 * Math.PI / 180);
+  drawBowtie(ctx, "green");
+  dot(ctx);
+  ctx.restore();
+
+  ctx.save();
+  ctx.translate(0, 85);
+  ctx.rotate(135 * Math.PI / 180);
+  drawBowtie(ctx, "blue");
+  dot(ctx);
+  ctx.restore();
+
+  ctx.save();
+  ctx.translate(85, 85);
+  ctx.rotate(90 * Math.PI / 180);
+  drawBowtie(ctx, "yellow");
+  dot(ctx);
+  ctx.restore();
+}
+
+ +

{{EmbedLiveSample('A_More_Complicated_Example','215','215','/@api/deki/files/604/=Canvas_ex3.png')}}

+

  我們自定義了兩個函式: drawBowtie 以及 dot,並且個別呼叫了四次。在呼叫他們之前,我們使用了 translate()rotate() 來設定接著要繪製圖形的 transformation matrix,這將改變最終 dot 和 bowtie 的位置。dot 繪製了一個以 (0, 0) 為中心的小黑正方形,而 drawBowtie 產生了一個填滿的蝴蝶結樣貌的圖形。

+

  save() 和 restore() 規範了一系列動作的初始和結尾。一個值得注意的地方是,旋轉的動作是基於該圖形當下所在的位置, 所以 translate() -> rotate() -> translate() 的結果會和 translate() -> translate() -> rotate() 不同。

+

和 Apple <canvas> 的相容性

+

For the most part, <canvas> is compatible with Apple's and other implementations. There are, however, a few issues to be aware of, described here.

+

</canvas> tag 是必要的

+

In the Apple Safari implementation, <canvas> is an element implemented in much the same way <img> is; it does not have an end tag. However, for <canvas> to have widespread use on the web, some facility for fallback content must be provided. Therefore, Mozilla's implementation has a required end tag.

+

If fallback content is not needed, a simple <canvas id="foo" ...></canvas> will be fully compatible with both Safari and Mozilla -- Safari will simply ignore the end tag.

+

If fallback content is desired, some CSS tricks must be employed to mask the fallback content from Safari (which should render just the canvas), and also to mask the CSS tricks themselves from IE (which should render the fallback content).

+
canvas {
+  font-size: 0.00001px !ie;
+}
+

其他特性

+

藉由 Canvas 渲染網頁內容

+
+ This feature is only available for code running with Chrome privileges. It is not allowed in normal HTML pages. Read why.
+

Mozilla's canvas is extended with the drawWindow() method. This method draws a snapshot of the contents of a DOM window into the canvas. For example,

+
ctx.drawWindow(window, 0, 0, 100, 200, "rgb(255,255,255)");
+
+

would draw the contents of the current window, in the rectangle (0,0,100,200) in pixels relative to the top-left of the viewport, on a white background, into the canvas. By specifying "rgba(255,255,255,0)" as the color, the contents would be drawn with a transparent background (which would be slower).

+

It is usually a bad idea to use any background other than pure white "rgb(255,255,255)" or transparent, as this is what all browsers do, and many websites expect that transparent parts of their interface will be drawn on white background.

+

With this method, it is possible to fill a hidden IFRAME with arbitrary content (e.g., CSS-styled HTML text, or SVG) and draw it into a canvas. It will be scaled, rotated and so on according to the current transformation.

+

Ted Mielczarek's tab preview extension uses this technique in chrome to provide thumbnails of web pages, and the source is available for reference.

+
+ Note: Using canvas.drawWindow() while handling a document's onload event doesn't work. In Firefox 3.5 or later, you can do this in a handler for the MozAfterPaint event to successfully draw HTML content into a canvas on page load.
+

更多資訊

+ diff --git a/files/zh-tw/web/api/canvas_api/index.html b/files/zh-tw/web/api/canvas_api/index.html new file mode 100644 index 0000000000..c07ec36738 --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/index.html @@ -0,0 +1,158 @@ +--- +title: Canvas API +slug: Web/API/Canvas_API +translation_of: Web/API/Canvas_API +--- +
{{CanvasSidebar}}
+ +

{{HTMLElement("canvas")}}HTML5 的新元素,可透過 Script(通常是 JavaScript)繪製圖形。例如,可以用來繪圖、合成圖照片、建立動畫、甚至處理即時的影片播放。

+ +

Mozilla 應用程式從 Gecko 1.8(也就是 Firefox 1.5)起開始支援 <canvas>。這個元素最初由蘋果 OS X Dashboard 和 Safari 引入。Internet Explorer 9 以上版本也有支援 <canvas>,但較舊的 IE 版本則須嵌入 Google Explorer Canvas 專案中的程式腳本,才能得到有效的支援。Opera 9 也支援 <canvas>

+ +

<canvas> 元素通常也被 WebGL 用來在網頁上顯示使用硬體加速繪製的 3D 圖形。

+ +

範例

+ +

這則簡單的範例使用了{{domxref("CanvasRenderingContext2D.fillRect()")}}這個方法。

+ +

HTML

+ +
<canvas id="canvas"></canvas>
+
+ +

JavaScript

+ +
var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+
+ctx.fillStyle = "green";
+ctx.fillRect(10, 10, 100, 100);
+
+ +

Edit the code below and see your changes update live in the canvas:

+ + + +

{{ EmbedLiveSample('Playable_code', 700, 360) }}

+ +

參考

+ +
+ +
+ +

這些與WebGLRenderingContext有關的標識,皆引用在WebGL

+ +

教程指南

+ +
+
Canvas tutorial
+
這個全部的課程包含 <canvas> 基礎的使用和高階的應用。
+
Code snippets: Canvas
+
一些延伸的開發功能,包含<canvas>
+
Demo: A basic ray-caster
+
使用<canvas>做的光線追蹤(ray-tracing )範例。
+
Drawing DOM objects into a canvas
+
如何在 DOM<canvas>之中,畫個物件。例如 HTML的元素。
+
Manipulating video using canvas
+
結合{{HTMLElement("video")}} 和 {{HTMLElement("canvas")}} 去控制影像資料的真實時間
+
+ +

資源

+ +

Generic

+ + + +

Libraries

+ + + +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', "the-canvas-element.html", "Canvas")}}{{Spec2('HTML WHATWG')}} 
+ +

參見

+ + diff --git a/files/zh-tw/web/api/canvas_api/tutorial/advanced_animations/index.html b/files/zh-tw/web/api/canvas_api/tutorial/advanced_animations/index.html new file mode 100644 index 0000000000..caacb185aa --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/advanced_animations/index.html @@ -0,0 +1,376 @@ +--- +title: Advanced animations +slug: Web/API/Canvas_API/Tutorial/Advanced_animations +translation_of: Web/API/Canvas_API/Tutorial/Advanced_animations +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}}
+ +
+

在上一章節,我們做了一些基礎動畫且知道它的移動方式。在這部分我們更仔細的介紹它的動畫效果且並增加一些特效,使它看起來更高級。

+
+ +

畫一顆球

+ +

在這次的動畫練習中使用球來練習。照著下面的步驟完成 canvas 設定。

+ +
<canvas id="canvas" width="600" height="300"></canvas>
+
+ +

照常理,先在canvas上需要先畫一顆球。創造一個 ball object,它包含的屬性和draw()的方法,使canvas可以在上面繪圖。

+ +
var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+var ball = {
+  x: 100,
+  y: 100,
+  radius: 25,
+  color: 'blue',
+  draw: function() {
+    ctx.beginPath();
+    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
+    ctx.closePath();
+    ctx.fillStyle = this.color;
+    ctx.fill();
+  }
+};
+
+ball.draw();
+ +

這裡沒什麼特別的,透過{{domxref("CanvasRenderingContext2D.arc()", "arc()")}}的方法,球事實上只是畫下簡單的圓。

+ +

添加速度

+ +

現在有了一顆球,準備添加基礎的動畫像我們從上章節學到的課程。再次使用{{domxref("window.requestAnimationFrame()")}}控制動畫。添加移動的向量速度使球移動到向量點。對於每個幀(frame),我們使用{{domxref("CanvasRenderingContext2D.clearRect", "clear", "", 1)}}來清除canvas舊的移動幀(frame)。

+ +
var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+var raf;
+
+var ball = {
+  x: 100,
+  y: 100,
+  vx: 5,
+  vy: 2,
+  radius: 25,
+  color: 'blue',
+  draw: function() {
+    ctx.beginPath();
+    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
+    ctx.closePath();
+    ctx.fillStyle = this.color;
+    ctx.fill();
+  }
+};
+
+function draw() {
+  ctx.clearRect(0,0, canvas.width, canvas.height);
+  ball.draw();
+  ball.x += ball.vx;
+  ball.y += ball.vy;
+  raf = window.requestAnimationFrame(draw);
+}
+
+canvas.addEventListener('mouseover', function(e) {
+  raf = window.requestAnimationFrame(draw);
+});
+
+canvas.addEventListener('mouseout', function(e) {
+  window.cancelAnimationFrame(raf);
+});
+
+ball.draw();
+
+ +

邊界

+ +

沒有任何邊界碰撞下,球很快就會跑出canvas。這時需要確認球的 x and y 是否超出 canvas 尺寸,若超出則將球的向量顛倒。所以,我們添加了確認條件在draw方法:

+ +
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
+  ball.vy = -ball.vy;
+}
+if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
+  ball.vx = -ball.vx;
+}
+ +

第一個示範

+ +

讓我們看看,看似很遠的行徑它如何行徑。移動你的滑鼠在canvas,使動畫開始。 

+ + + +

{{EmbedLiveSample("First_demo", "610", "310")}}

+ +

加速性能

+ +

為了使移動看起來更真實,你可以照著範例改變速度:

+ +
ball.vy *= .99;
+ball.vy += .25;
+ +

這個使每個幀(frame)的垂直向量減少,所以球將只會在地板彈跳直到結束。

+ + + +

{{EmbedLiveSample("Second_demo", "610", "310")}}

+ +

追蹤效果

+ +

直到現在我們已經使用{{domxref("CanvasRenderingContext2D.clearRect", "clearRect")}}方法清除之前的幀(frames)。如果使用重置半透明{{domxref("CanvasRenderingContext2D.fillRect", "fillRect")}}這個方法,可以更淺顯的看出創造追蹤效果。

+ +
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
+ctx.fillRect(0, 0, canvas.width, canvas.height);
+ + + +

{{EmbedLiveSample("Third_demo", "610", "310")}}

+ +

增加滑鼠控制

+ +

為了能控制球使它跟著滑鼠移動,在這個範例使用mousemove 效果。當 click 事件觸發了這顆球,它又會開始彈跳。

+ + + +
var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+var raf;
+var running = false;
+
+var ball = {
+  x: 100,
+  y: 100,
+  vx: 5,
+  vy: 1,
+  radius: 25,
+  color: 'blue',
+  draw: function() {
+    ctx.beginPath();
+    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
+    ctx.closePath();
+    ctx.fillStyle = this.color;
+    ctx.fill();
+  }
+};
+
+function clear() {
+  ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
+  ctx.fillRect(0,0,canvas.width,canvas.height);
+}
+
+function draw() {
+  clear();
+  ball.draw();
+  ball.x += ball.vx;
+  ball.y += ball.vy;
+
+  if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
+    ball.vy = -ball.vy;
+  }
+  if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
+    ball.vx = -ball.vx;
+  }
+
+  raf = window.requestAnimationFrame(draw);
+}
+
+canvas.addEventListener('mousemove', function(e) {
+  if (!running) {
+    clear();
+    ball.x = e.clientX;
+    ball.y = e.clientY;
+    ball.draw();
+  }
+});
+
+canvas.addEventListener('click', function(e) {
+  if (!running) {
+    raf = window.requestAnimationFrame(draw);
+    running = true;
+  }
+});
+
+canvas.addEventListener('mouseout', function(e) {
+  window.cancelAnimationFrame(raf);
+  running = false;
+});
+
+ball.draw();
+
+ +

用你的滑鼠移動這顆球且點擊鬆放它。

+ +

{{EmbedLiveSample("Adding_mouse_control", "610", "310")}}

+ +

突破性(遊戲)

+ +

這個小章節只有解釋一些創造高級動畫的技巧。這裡還有更多!如何增加槳,磚塊,到這個 到 Breakout game demo去看,有我們更多遊戲研發的文章! 

+ +

延伸閱讀

+ + + +

{{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}}

diff --git a/files/zh-tw/web/api/canvas_api/tutorial/applying_styles_and_colors/index.html b/files/zh-tw/web/api/canvas_api/tutorial/applying_styles_and_colors/index.html new file mode 100644 index 0000000000..86e41e3476 --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/applying_styles_and_colors/index.html @@ -0,0 +1,669 @@ +--- +title: 套用樣式與顏色 +slug: Web/API/Canvas_API/Tutorial/Applying_styles_and_colors +translation_of: Web/API/Canvas_API/Tutorial/Applying_styles_and_colors +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_shapes", "Web/API/Canvas_API/Tutorial/Drawing_text")}}
+ +

繪畫圖形章節中,我們只用了預設的線條與填滿樣式,而在本章,我們將進一步看看所有可用的樣式選項,畫出更吸引人的圖。

+ +

顏色

+ +

U截至目前為止我們只有看到繪圖環境的方法(methods),如果我們想要設定圖形的顏色,我們有兩個屬性能用: fillStylestorkeStyle.

+ +
+
fillStyle = color
+
設定填滿圖形時用的顏色.
+
strokeStyle = color
+
設定勾勒圖形時用的顏色.
+
+ +

其中color可以是CSS{{cssxref("<color>")}}表示字串、漸層色物件(gradient color)或是模式物件(pattern object),現在先看一下CSS{<color>}表示字串,稍後再看另外兩個項目.

+ +

預設上勾勒和填滿色是黑色(CSS顏色值為#000000).

+ +
+

Note: 一旦改變了strokeStyle的顏色值,那麼之後圖形勾勒顏色都會變成新顏色,同樣狀況一樣適用於fillStyle.

+
+ +

合格的顏色值請參照CSS3{{cssxref("<color>")}}規範,下面範例所標示的顏色都指向同一個顏色.

+ +
// these all set the fillStyle to 'orange'
+
+ctx.fillStyle = "orange";
+ctx.fillStyle = "#FFA500";
+ctx.fillStyle = "rgb(255,165,0)";
+ctx.fillStyle = "rgba(255,165,0,1)";
+
+ +
+

Note: 目前Gecko引擎並不支援CSS3全部的顏色值,例如hsl(100%,25%,0)和rgb(0,100%,0)就不被支援.

+
+ +

fillStyle範例

+ +

這裡我們利用兩個for迴圈來畫出一個矩形陣列,而且陣列中每一個矩形的顏色都不相同。下面程式碼透過改變i和j兩個變數來分別變換RGB中的紅色值和綠色值,然後為每一個矩形產生自己專屬的顏色值。透過改變RGB的各顏色值,我們可以產生各式各樣的調色盤,像是逐步調整顏色值,你也可以做出像Photoshop內建一樣的調色盤。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  for (var i=0;i<6;i++){
+    for (var j=0;j<6;j++){
+      ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
+                       Math.floor(255-42.5*j) + ',0)';
+      ctx.fillRect(j*25,i*25,25,25);
+    }
+  }
+}
+ + + +

結果如下:

+ +

{{EmbedLiveSample("A_fillStyle_example", 160, 160, "https://mdn.mozillademos.org/files/5417/Canvas_fillstyle.png")}}

+ +

strokeStyle範例

+ +

本例和前例相當類似,不同的是我們改用arc()方法畫圓形而不是矩形、改設定strokeStyle變換圖形輪廓顏色。

+ +
  function draw() {
+    var ctx = document.getElementById('canvas').getContext('2d');
+    for (var i=0;i<6;i++){
+      for (var j=0;j<6;j++){
+        ctx.strokeStyle = 'rgb(0,' + Math.floor(255-42.5*i) + ',' +
+                         Math.floor(255-42.5*j) + ')';
+        ctx.beginPath();
+        ctx.arc(12.5+j*25,12.5+i*25,10,0,Math.PI*2,true);
+        ctx.stroke();
+      }
+    }
+  }
+
+ + + +

結果如下:

+ +

{{EmbedLiveSample("A_strokeStyle_example", "180", "180", "https://mdn.mozillademos.org/files/253/Canvas_strokestyle.png")}}

+ +

透明度

+ +

透過設定globalAlpha屬性或是以半透明顏色值設定strokeStyle與fillStyle屬性,除了畫不透明的圖形,我們還可以畫半透明的圖形。

+ +
+
globalAlpha = transparencyValue
+
允許值介於0.0(全透明)到1.0(不透明)。一旦設定後,之後畫布上畫的所有圖形的不透明度都會套用此設定值。預設值為1.0。
+
+ +

當我們想畫一系列相同不透明度的圖,設定globalAlpha值是一個方便的作法。

+ +

由CSS3顏色值能夠指定不透明度,我們也可以如下面一般,設定strokeStyle以及fillStyle來變更不透明度。

+ +
// Assigning transparent colors to stroke and fill style
+
+ctx.strokeStyle = "rgba(255,0,0,0.5)";
+ctx.fillStyle = "rgba(255,0,0,0.5)";
+
+ +

rgba()函數比rgb()函數多出一個不透明度參數,允許值介於0.0(全透明)到1.0(不透明).

+ +

globalAlpha範例

+ +

下面我們將在四個方格色塊背景上畫一系列半透明圓形。對於所有圓形,我們藉由設置globalAlpha屬性值為0.2使得圓形變成半透明,然後for迴圈裡我們逐一增加圓形繪圖半徑,最終結果看起來便像是輻射狀漸層圖案,而且圓形相互疊加在彼此之上後,又加深了重疊區域的不透明度,只要我們不斷增加圓形數量,最後圖片中央將被完全遮蓋,看不到背後的背景。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  // draw background
+  ctx.fillStyle = '#FD0';
+  ctx.fillRect(0,0,75,75);
+  ctx.fillStyle = '#6C0';
+  ctx.fillRect(75,0,75,75);
+  ctx.fillStyle = '#09F';
+  ctx.fillRect(0,75,75,75);
+  ctx.fillStyle = '#F30';
+  ctx.fillRect(75,75,150,150);
+  ctx.fillStyle = '#FFF';
+
+  // set transparency value
+  ctx.globalAlpha = 0.2;
+
+  // Draw semi transparent circles
+  for (i=0;i<7;i++){
+    ctx.beginPath();
+    ctx.arc(75,75,10+10*i,0,Math.PI*2,true);
+    ctx.fill();
+  }
+}
+ + + +

{{EmbedLiveSample("A_globalAlpha_example", "180", "180", "https://mdn.mozillademos.org/files/232/Canvas_globalalpha.png")}}

+ +

rgba()使用範例

+ +

這個範例類似於上面的範例,但不同的是我們改畫半透明的矩形。rgba()在使用上會多一點彈性,因為我們可以分別設置勾勒和填滿圖形的不透明度。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // Draw background
+  ctx.fillStyle = 'rgb(255,221,0)';
+  ctx.fillRect(0,0,150,37.5);
+  ctx.fillStyle = 'rgb(102,204,0)';
+  ctx.fillRect(0,37.5,150,37.5);
+  ctx.fillStyle = 'rgb(0,153,255)';
+  ctx.fillRect(0,75,150,37.5);
+  ctx.fillStyle = 'rgb(255,51,0)';
+  ctx.fillRect(0,112.5,150,37.5);
+
+  // Draw semi transparent rectangles
+  for (var i=0;i<10;i++){
+    ctx.fillStyle = 'rgba(255,255,255,'+(i+1)/10+')';
+    for (var j=0;j<4;j++){
+      ctx.fillRect(5+i*14,5+j*37.5,14,27.5)
+    }
+  }
+}
+ + + +

{{EmbedLiveSample("An_example_using_rgba()", "180", "180", "https://mdn.mozillademos.org/files/246/Canvas_rgba.png")}}

+ +

線條樣式

+ +

有數種屬性可以讓我們設定線條樣式.

+ +
+
lineWidth = value
+
設定線條寬度。
+
lineCap = type
+
設定線條結尾的樣式。
+
lineJoin = type
+
設定線條和線條間接合處的樣式。
+
miterLimit = value
+
限制當兩條線相交時交接處最大長度;所謂交接處長度(miter length)是指線條交接處內角頂點到外角頂點的長度。
+
+ +

底下我們將一一示範這些屬性的用途。

+ +

lineWidth範例

+ +

此屬性決定線條寬度,必須為正數,預設值為1.0單位。

+ +

線條寬度的起算點是從繪圖路徑中央開始往兩旁各延伸一半設定寬度,由於畫布座標不直接對應到像素(pixel),所以要比較小心設定好取得清晰的直線。

+ +

由下方例子可以明顯看到,畫布上有10條直線,由左至右,從最小的1.0單位寬開始逐漸加寬,請注意奇數寬度直線會因為繪圖路徑位置關係而比較模糊。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  for (var i = 0; i < 10; i++){
+    ctx.lineWidth = 1+i;
+    ctx.beginPath();
+    ctx.moveTo(5+i*14,5);
+    ctx.lineTo(5+i*14,140);
+    ctx.stroke();
+  }
+}
+
+ + + +

{{EmbedLiveSample("A_lineWidth_example", "180", "180", "https://mdn.mozillademos.org/files/239/Canvas_linewidth.png")}}

+ +

為了畫出清晰的直線,我們需要了解繪圖路徑是如何產生;如下方圖示,網格代表畫布座標軸,網格所框出的方格則代表螢幕上的像素,第一張圖片填滿了座標(2,1)到(5,5)的紅色區域,而這個紅色區域的邊際正好符合像素間的邊際,所以會產生出清晰的影像。

+ +

+ +

第二張圖片中,有一條寬1.0單位的直線從座標(3,1)到(3,5)被畫在畫布上,不過由於線條寬度的起算點是從繪圖路徑中央開始往兩旁各延伸一半設定寬度,所以當勾勒線條時,繪圖路徑兩旁的像素格只有一半會被填滿暗藍色,至於另外一半則會經由計算填入近似色(淡藍色),結果就是整格像素並非全部填入相同的暗藍色,進而產生出邊緣較為模糊的線條,上面程式碼範例中的奇數寬度直線就是因此而產生不清晰的線條。

+ +

為了避免劃出邊緣模糊直線,我們必須精準設定繪圖路徑位置,就本範例而言,如果我們的直線繪圖路徑是從座標(3.5, 1)到(3.5, 5)的話(如第三張圖),那麼1.0單位寬的直線將剛好填滿像素格,所以我們將可以畫出清晰的直線。

+ +
+

Note: 請注意本範例的Y軸座標都是整數點,若非如此,一樣會導致線條端點的像素格無法剛好被填滿的現象,而且同時最後產生的結果也會被lineCap給影響;倘若lineCap值為預設butt時,我們會需要為奇數寬度直線計算一下非整數的座標點,倘若lineCap樣式為square,那麼線段端點的像素格將自動被完整填滿。

+ +

還有一點需要注意,只要繪圖路徑被closePath()函數閉合起來,這樣便沒有了線條端點,所有的線條端點都會依據lineJoin樣式全部前後互相連接起來,這會自動延伸端點邊緣到線段接合處,如果此時接合端點是水平或垂直的話,位於中央的像素格將會被完整填滿。後面的說明會介紹lineCap和lineJoin樣式。

+
+ +

至於本例中偶數寬度的直線,為了避免模糊,繪圖路徑最好是落在整數座標點上。

+ +

雖然處裡2D繪圖縮放有些麻煩,但只要仔細計算像素格和繪圖路徑位置,縱使進行圖像縮放或變形,圖像輸出還是可以保持正確。一條寬1.0單位的直線,只要位置計算正確,放大兩倍後會變成一條2個像素寬的清晰直線,而且還是會保持正確位置。

+ +

lineCap範例

+ +

這個屬性決定線條端點的樣式,總共有三種樣式可選:

+ +

+ +
+
butt
+
線條端點樣式為方形
+
round
+
線條端點樣式為圓形
+
square
+
增加寬同線條寬度、高線條寬度一半的的方塊於線條端點
+
+ +

下面程式碼會畫出三條線,每條線的lineCap值皆不同。然後為了看清差異點,我們加上了兩條淡藍色的輔助線,線條的繪圖起始點和終點都剛好落在輔助線上。

+ +

最左邊的線條其lineCap為butt,不難看出它完全介於輔助線之間;第二條線其lineCap為round,端點樣式為半徑等於線條寬度一半的半圓;最右邊的線條其lineCap為square,端點樣式為寬同線條寬度、高線條寬度一半的的方塊。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  var lineCap = ['butt','round','square'];
+
+  // Draw guides
+  ctx.strokeStyle = '#09f';
+  ctx.beginPath();
+  ctx.moveTo(10,10);
+  ctx.lineTo(140,10);
+  ctx.moveTo(10,140);
+  ctx.lineTo(140,140);
+  ctx.stroke();
+
+  // Draw lines
+  ctx.strokeStyle = 'black';
+  for (var i=0;i<lineCap.length;i++){
+    ctx.lineWidth = 15;
+    ctx.lineCap = lineCap[i];
+    ctx.beginPath();
+    ctx.moveTo(25+i*50,10);
+    ctx.lineTo(25+i*50,140);
+    ctx.stroke();
+  }
+}
+
+ + + +

{{EmbedLiveSample("A_lineCap_example", "180", "180", "https://mdn.mozillademos.org/files/236/Canvas_linecap.png")}}

+ +

lineJoin範例

+ +

lineJoin屬性決定兩個連接區端(如線條、弧形或曲線)如何連接(對於長度為零,亦即終點和控制點為同一點的圖形無效)。

+ +

lineJoin屬性共有三個屬性值如下,其中miter為預設值,請注意一點若是兩個連接區段的繪圖方向一致,那代表不會有連接處,所以測定是無效的。

+ +

+ +
+
round
+
代表圓弧型連接樣式。
+
bevel
+
代表斜面型連接樣式。在連接區段的共同終點處填滿一個三角形區域,將原本的外接角處形成一個切面。
+
miter
+
代表斜交型連接樣式。向外延伸連結區段外緣直到相交於一點,然後形成菱形區域,而miterLimit屬性會影響miter屬性。
+
+ +

下方程式碼和圖形輸出展示了lineJoin在不同屬性值下呈現的不同結果

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  var lineJoin = ['round','bevel','miter'];
+  ctx.lineWidth = 10;
+  for (var i=0;i<lineJoin.length;i++){
+    ctx.lineJoin = lineJoin[i];
+    ctx.beginPath();
+    ctx.moveTo(-5,5+i*40);
+    ctx.lineTo(35,45+i*40);
+    ctx.lineTo(75,5+i*40);
+    ctx.lineTo(115,45+i*40);
+    ctx.lineTo(155,5+i*40);
+    ctx.stroke();
+  }
+}
+
+ + + +

{{EmbedLiveSample("A_lineJoin_example", "180", "180", "https://mdn.mozillademos.org/files/237/Canvas_linejoin.png")}}

+ +

miterLimit屬性

+ +

前面範例顯示出,當lineJoin值為miter時,兩條線的外緣會延伸相交,所以,當這兩條相交線的相交角度越小的話,他們的延伸交會點就會越遠離內緣連接點,而且隨著角度變小,距離呈指數型增長。

+ +

miterLimit會限制延伸交會點最遠可以離內緣連接點到多遠,當延伸交會點的落點超出這個範圍,那麼便以斜面(bevel)作為交接樣式。請注意,最大miter長度為線寬乘於miterLimit值,所以miterLimit可以獨立於目前顯示縮放尺寸或其他變形設定。

+ +

miterLimit預設值為10.0。

+ +

更精確來說,miter限制是指延伸長度(在HTML畫布上,這個長度是外緣相交角到連接區段的共同繪圖路經終點)相對於一半線寬的最大允許比率;也等同於,外緣距內緣相交點之距離相對於線寬的的最大允許比率;相當於,連接區最小內緣角的一半角度的餘割(cosecant)值, 小於此值則便以斜面(bevel)作為交接樣式:

+ + + +

下面是一個範例,其中藍線標示出各個線條繪圖路徑的起始點與終點。

+ +

倘若設定範例程式碼中的miterLimit低於4.2,所有的miter交接都會被移除,取而代之的是出現在藍線附近的bevel交接;倘若設定miterLimit大於10,那麼大部分的miter交接都會出現,而且你會發現,由左到右,miter長度逐漸縮短,這是由於線條相交角度逐漸加大之故;倘若設定中間值,那麼左邊會出現bevel交接,右邊會出現miter交接。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // Clear canvas
+  ctx.clearRect(0,0,150,150);
+
+  // Draw guides
+  ctx.strokeStyle = '#09f';
+  ctx.lineWidth   = 2;
+  ctx.strokeRect(-5,50,160,50);
+
+  // Set line styles
+  ctx.strokeStyle = '#000';
+  ctx.lineWidth = 10;
+
+  // check input
+  if (document.getElementById('miterLimit').value.match(/\d+(\.\d+)?/)) {
+    ctx.miterLimit = parseFloat(document.getElementById('miterLimit').value);
+  } else {
+    alert('Value must be a positive number');
+  }
+
+  // Draw lines
+  ctx.beginPath();
+  ctx.moveTo(0,100);
+  for (i=0;i<24;i++){
+    var dy = i%2==0 ? 25 : -25 ;
+    ctx.lineTo(Math.pow(i,1.5)*2,75+dy);
+  }
+  ctx.stroke();
+  return false;
+}
+
+ + + +

{{EmbedLiveSample("A_demo_of_the_miterLimit_property", "400", "180", "https://mdn.mozillademos.org/files/240/Canvas_miterlimit.png")}}

+ +

漸層

+ +

如同其他繪圖軟體可以畫出線性和放射狀的漸層圖案,透過設定fillStyle和strokeStyle屬性為canvasGradient漸層物件,我們也可以在canvas上做到一樣的效果。要創造漸層物件,可以使用下面的方法:

+ +
+
createLinearGradient(x1, y1, x2, y2)
+
產生一個線性漸層物件,其漸層起始點為(x1, y1)、終點為(x2, y2)。
+
createRadialGradient(x1, y1, r1, x2, y2, r2)
+
產生一個放射狀漸層物件,第一個圓之圓心落在(x1, y1)、半徑為r1,第一個圓之圓心落在(x2, y2)、半徑為r2。
+
+ +

例如:

+ +
var lineargradient = ctx.createLinearGradient(0, 0, 150, 150);
+var radialgradient = ctx.createRadialGradient(75, 75, 0, 75, 75, 100);
+
+ +

一旦產生了canvasGradient漸層物件,我們用addColorStop()方法可以添加顏色上去。

+ +
+
gradient.addColorStop(position, color)
+
於gradient漸層物件建立一個顏色點,其中color是CSS{{cssxref("<color>")}}的字串表示,而position介於0.0到1.0之間,定義了該顏色在漸層中的相對位置。呼叫這個方法會指定當進行到設定的位置時,漸層需要完全轉變成設定的顏色。
+
+ +

我們可以按照需要設定無數個顏色點,下面是一個簡單的由白到黑的簡單漸層範例程式碼。

+ +
var lineargradient = ctx.createLinearGradient(0,0,150,150);
+lineargradient.addColorStop(0, 'white');
+lineargradient.addColorStop(1, 'black');
+
+ +

createLinearGradient範例

+ +

本範例中,我們將建立兩種漸層,如範例所示,strokeStyle和fillSyle屬性都可以接受canvasGradient物件作為屬性值。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // Create gradients
+  var lingrad = ctx.createLinearGradient(0,0,0,150);
+  lingrad.addColorStop(0, '#00ABEB');
+  lingrad.addColorStop(0.5, '#fff');
+  lingrad.addColorStop(0.5, '#26C000');
+  lingrad.addColorStop(1, '#fff');
+
+  var lingrad2 = ctx.createLinearGradient(0,50,0,95);
+  lingrad2.addColorStop(0.5, '#000');
+  lingrad2.addColorStop(1, 'rgba(0,0,0,0)');
+
+  // assign gradients to fill and stroke styles
+  ctx.fillStyle = lingrad;
+  ctx.strokeStyle = lingrad2;
+
+  // draw shapes
+  ctx.fillRect(10,10,130,130);
+  ctx.strokeRect(50,50,50,50);
+
+}
+
+ + + +

第一個漸層為背景漸層,範例中我們在一個位置上指定了兩種顏色(白色到綠色),這樣做會產生非常突然的顏色轉換,一般來說,不管如何設定顏色點順序都沒關係,然而就這個例子而言,這種作法太過強烈了,但是如果這是你想要的顏色漸層順序,那其實也是可以。

+ +

第二個漸層起始位置(position 0.0)的顏色並沒有被指定,所以下一個漸層顏色會自動被設為起始位置顏色,因此即使我們沒有指定漸層起始位置顏色也沒有關係,就像本範例自動會設定起始位置的顏色等於位置0.5的黑色。

+ +

{{EmbedLiveSample("A_createLinearGradient_example", "180", "180", "https://mdn.mozillademos.org/files/235/Canvas_lineargradient.png")}}

+ +

createRadialGradient範例

+ +

這邊我們定義了四種放射狀漸層,相較於一般在Photoshop看到的”經典”放射狀漸層圖案(漸層從一個圖案中心點向外呈圓心狀延伸),因為我們可以控制漸層起始和終止點,我們可以做到更好的效果。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // Create gradients
+  var radgrad = ctx.createRadialGradient(45,45,10,52,50,30);
+  radgrad.addColorStop(0, '#A7D30C');
+  radgrad.addColorStop(0.9, '#019F62');
+  radgrad.addColorStop(1, 'rgba(1,159,98,0)');
+
+  var radgrad2 = ctx.createRadialGradient(105,105,20,112,120,50);
+  radgrad2.addColorStop(0, '#FF5F98');
+  radgrad2.addColorStop(0.75, '#FF0188');
+  radgrad2.addColorStop(1, 'rgba(255,1,136,0)');
+
+  var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40);
+  radgrad3.addColorStop(0, '#00C9FF');
+  radgrad3.addColorStop(0.8, '#00B5E2');
+  radgrad3.addColorStop(1, 'rgba(0,201,255,0)');
+
+  var radgrad4 = ctx.createRadialGradient(0,150,50,0,140,90);
+  radgrad4.addColorStop(0, '#F4F201');
+  radgrad4.addColorStop(0.8, '#E4C700');
+  radgrad4.addColorStop(1, 'rgba(228,199,0,0)');
+
+  // draw shapes
+  ctx.fillStyle = radgrad4;
+  ctx.fillRect(0,0,150,150);
+  ctx.fillStyle = radgrad3;
+  ctx.fillRect(0,0,150,150);
+  ctx.fillStyle = radgrad2;
+  ctx.fillRect(0,0,150,150);
+  ctx.fillStyle = radgrad;
+  ctx.fillRect(0,0,150,150);
+}
+
+ + + +

程式碼範例中,為了營造出3D效果,我們讓起始點和終止點位於不同位置,請注意,最好不要讓內外圈相重疊,以避免難以預測的奇怪效果。

+ +

每一個漸層圖案最後一個漸層色都是全透明的,如果希望倒數第二個漸層色能夠平順地轉換到這個最後一個漸層色,那麼兩者應該設定一樣的顏色值,像是程式碼範例中的漸層色 #019F62 其實就等於 rgba(1,159,98,1)。

+ +

{{EmbedLiveSample("A_createRadialGradient_example", "180", "180", "https://mdn.mozillademos.org/files/244/Canvas_radialgradient.png")}}

+ +

樣式(Patterns)

+ +

先前的範例中,我們都是藉由迴圈來重複產生影像樣式,不過其實有一條更簡單的方法,那就是呼叫createPattern方法。

+ +
+
createPattern(image, type)
+
呼叫createPattern()會產一個畫布樣式物件,然後回傳出來。
+ 其中image是CanvasImageSource類別物件(像是{{domxref("HTMLImageElement")}},、<canvas>元素、{{HTMLElement("video")}} 元素等)
+
+ +

Type是一串字串,定義了如何產生樣式,允許的值有:

+ +
+
repeat
+
沿垂直與水平方向重複排列影像
+
repeat-x
+
只沿水平方向重複排列影像
+
repeat-y
+
只沿垂直方向重複排列影像
+
no-repeat
+
不重複排列影像,只使用一次
+
+ +
+

Note: Firefox現在只支援repeat,所以其他值都是無效的

+
+ +
Note: 傳入尺寸為0x0像素的畫布會引起錯誤
+ +

利用createPattern()的方法和前面利用漸層的方法十分類似,我們呼叫createPattern()產生{{domxref("CanvasPattern")}}物件,然後將{CanvasPattern}物件設成fillStyle或strokeStyle的屬性值,例如:

+ +
var img = new Image();
+img.src = 'someimage.png';
+var ptrn = ctx.createPattern(img,'repeat');
+
+ +
+

Note: 不像drawImage()方法,呼叫createPattern()方法前影像必須要先載入完成,否則可能圖像的程生會有問題。

+
+ +

createPattern範例

+ +

這個範例中我們把fillStyle屬性值存為樣式物件,比較值得注意的是影像onload事件處理器,這是為了確保影像載入完成後再進行。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // create new image object to use as pattern
+  var img = new Image();
+  img.src = '/files/222/Canvas_createpattern.png';
+  img.onload = function(){
+
+    // create pattern
+    var ptrn = ctx.createPattern(img,'repeat');
+    ctx.fillStyle = ptrn;
+    ctx.fillRect(0,0,150,150);
+
+  }
+}
+
+ + + +

{{EmbedLiveSample("A_createPattern_example", "180", "180", "https://mdn.mozillademos.org/files/222/Canvas_createpattern.png")}}

+ +

陰影

+ +

要產生陰影只需要四個屬性:

+ +
+
shadowOffsetX = float
+
代表陰影從物件延伸出來的水平距離,預設為0,不受變形矩陣影響。
+
shadowOffsetY = float
+
代表陰影從物件延伸出來的垂直距離,預設為0,不受變形矩陣影響。
+
shadowBlur = float
+
代表陰影模糊大小範圍,預設為0,不受變形矩陣影響,不等同於像素值。
+
shadowColor = {{cssxref("<color>")}}
+
CSS顏色值,代表陰影顏色,預設為全透明。
+
+ +

shadowOffsetX和shadowOffsetY會決定陰影延伸大小,若是為正值,則陰影會往右(沿X軸)和往下(沿Y軸)延伸,若是為負值,則會往正值相反方向延伸。

+ +
+

{{gecko_callout_heading("7.0")}}

+ +

Note: 基於HTML5提議規格變更,從{{Gecko("7.0")}}開始,陰影只會在source-over的構圖排列下產生

+
+ +

文字陰影範例

+ +

本程式碼範例會產生一串帶有陰影的文字。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  ctx.shadowOffsetX = 2;
+  ctx.shadowOffsetY = 2;
+  ctx.shadowBlur = 2;
+  ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
+
+  ctx.font = "20px Times New Roman";
+  ctx.fillStyle = "Black";
+  ctx.fillText("Sample String", 5, 30);
+}
+
+ + + +

{{EmbedLiveSample("A_shadowed_text_example", "180", "100", "https://mdn.mozillademos.org/files/2505/shadowed-string.png")}}

+ +

{{PreviousNext("Web/Guide/HTML/Canvas_tutorial/Using_images", "Web/Guide/HTML/Canvas_tutorial/Transformations")}}

+ +
 
diff --git a/files/zh-tw/web/api/canvas_api/tutorial/basic_animations/index.html b/files/zh-tw/web/api/canvas_api/tutorial/basic_animations/index.html new file mode 100644 index 0000000000..336fadbce0 --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/basic_animations/index.html @@ -0,0 +1,347 @@ +--- +title: 基礎動畫 +slug: Web/API/Canvas_API/Tutorial/Basic_animations +translation_of: Web/API/Canvas_API/Tutorial/Basic_animations +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Compositing", "Web/API/Canvas_API/Tutorial/Advanced_animations")}}
+ +

控制{{HTMLElement("canvas")}}元素來產生互動式動畫不是一件難事,當然,如果產生的動畫越複雜越需要多費一些力氣,未來如果有機會我們將說明這一塊。

+ +

由於圖形一但產生後便靜止不動,所以我們必須重新繪圖好移動圖案,產生動畫效果,所以如果繪圖越複雜,繪圖運算也需要消耗越多運算資源和時間,換句話說,電腦效能的好壞將大大影響動畫順暢度,或許這也是畫布動畫最大的限制。

+ +

動畫基本步驟

+ +

產生一個畫面基本上需要以下步驟 :

+ +
    +
  1. 清除畫布
    + 除了不變的背景畫面,所有先前畫的圖案都要先清除,這個步驟可以透過clearRect()方法達成。
  2. +
  3. 儲存畫布狀態
    + 若是想要每一次重新繪圖時畫布起始狀態都是原始狀態,那麼就需要先行儲存畫布原始狀態。
  4. +
  5. 畫出畫面
    + 畫出需要畫面。
  6. +
  7. 復原畫布狀態
    + 復原畫布狀態以備下次繪圖使用。
  8. +
+ +

控制動畫

+ +

一般來說當程式碼執行完畢後我們才會看到繪圖結果,所以說我們無法靠執行for迴圈來產生動畫,我們得靠每隔一段時間繪圖來產生動畫,下面將介紹兩種作法。

+ +

排程更新

+ +

第一種作法是利用{{domxref("window.setInterval()")}}與{{domxref("window.setTimeout()")}}方法。

+ +
+

Note: 針對新版瀏覽器建議採用{{domxref("window.requestAnimationFrame()")}}方法。

+
+ +
+
setInterval(function, delay)
+
每隔delay毫秒,執行輸入function(函數)
+
setTimeout(function, delay)
+
過delay毫秒後,執行輸入function(函數)
+
requestAnimationFrame(callback)
+
告訴瀏覽器你希望執行動畫的時候,要求瀏覽器在重繪下一張畫面之前,呼叫callback函數來更新動畫
+
+ +

如果希望不要有任何的使用者互動影響,請使用setInterval(),因為它會確實地每隔一段時間就執行程式碼。如果你想製作遊戲 , 我們能夠使用keyboard 或是 mouse event來控制動畫,並使用setTimeout()函數一起。藉由設定EventListeners,我們能夠捕捉任何使用者的動作,並執行我們的動畫函數。

+ +
+

在下面的範例,我們將使用window.requestAnimationFrame()方法來控制動畫,window.requestAnimationFrame()方法為動畫提供更順暢更有效率的方式來執行,當系統準備好繪製畫面時,藉由呼叫動畫andmation frame()的callback函數 。callback通常每秒鐘執行60次,當執行background tab時,執行次數會更低,想知道更多關於動畫迴圈(animation loop)的資訊,尤其是遊戲的應用,請查看我們在 Game development zone 的主題 Anatomy of a video game 。

+
+ +

從使用者輸入操作控制動畫

+ +

我們也可以從使用者輸入操作控制動畫,就像是電玩遊戲一般;像是在鍵盤上設置事件處理器{{domxref("EventListener")}}捕捉使用者輸入並執行對應動畫。

+ +

你可以利用我們的次要版主要版動畫框架

+ +
var myAnimation = new MiniDaemon(null, animateShape, 500, Infinity);
+ +

+ +
var myAnimation = new Daemon(null, animateShape, 500, Infinity);
+ +

在後面的範例我們主要將使用window.setInterval()方法控制動畫,然後於本頁底部是一些使用widnow.setTimeout()的範例連結。

+ +

太陽系動畫

+ +

本例會產生一個小型太陽系運行動畫。

+ +
var sun = new Image();
+var moon = new Image();
+var earth = new Image();
+function init(){
+  sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png';
+  moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png';
+  earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png';
+  setInterval(draw,100);
+}
+
+function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  ctx.globalCompositeOperation = 'destination-over';
+  ctx.clearRect(0,0,300,300); // clear canvas
+
+  ctx.fillStyle = 'rgba(0,0,0,0.4)';
+  ctx.strokeStyle = 'rgba(0,153,255,0.4)';
+  ctx.save();
+  ctx.translate(150,150);
+
+  // Earth
+  var time = new Date();
+  ctx.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() );
+  ctx.translate(105,0);
+  ctx.fillRect(0,-12,50,24); // Shadow
+  ctx.drawImage(earth,-12,-12);
+
+  // Moon
+  ctx.save();
+  ctx.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() );
+  ctx.translate(0,28.5);
+  ctx.drawImage(moon,-3.5,-3.5);
+  ctx.restore();
+
+  ctx.restore();
+
+  ctx.beginPath();
+  ctx.arc(150,150,105,0,Math.PI*2,false); // Earth orbit
+  ctx.stroke();
+
+  ctx.drawImage(sun,0,0,300,300);
+}
+
+ + + +

{{EmbedLiveSample("An_animated_solar_system", "310", "310", "https://mdn.mozillademos.org/files/202/Canvas_animation1.png")}}

+ +

時鐘動畫

+ +

本例會產生一個時鐘指向現在時間。

+ +
function init(){
+  clock();
+  setInterval(clock,1000);
+}
+
+function clock(){
+  var now = new Date();
+  var ctx = document.getElementById('canvas').getContext('2d');
+  ctx.save();
+  ctx.clearRect(0,0,150,150);
+  ctx.translate(75,75);
+  ctx.scale(0.4,0.4);
+  ctx.rotate(-Math.PI/2);
+  ctx.strokeStyle = "black";
+  ctx.fillStyle = "white";
+  ctx.lineWidth = 8;
+  ctx.lineCap = "round";
+
+  // Hour marks
+  ctx.save();
+  for (var i=0;i<12;i++){
+    ctx.beginPath();
+    ctx.rotate(Math.PI/6);
+    ctx.moveTo(100,0);
+    ctx.lineTo(120,0);
+    ctx.stroke();
+  }
+  ctx.restore();
+
+  // Minute marks
+  ctx.save();
+  ctx.lineWidth = 5;
+  for (i=0;i<60;i++){
+    if (i%5!=0) {
+      ctx.beginPath();
+      ctx.moveTo(117,0);
+      ctx.lineTo(120,0);
+      ctx.stroke();
+    }
+    ctx.rotate(Math.PI/30);
+  }
+  ctx.restore();
+
+  var sec = now.getSeconds();
+  var min = now.getMinutes();
+  var hr  = now.getHours();
+  hr = hr>=12 ? hr-12 : hr;
+
+  ctx.fillStyle = "black";
+
+  // write Hours
+  ctx.save();
+  ctx.rotate( hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec )
+  ctx.lineWidth = 14;
+  ctx.beginPath();
+  ctx.moveTo(-20,0);
+  ctx.lineTo(80,0);
+  ctx.stroke();
+  ctx.restore();
+
+  // write Minutes
+  ctx.save();
+  ctx.rotate( (Math.PI/30)*min + (Math.PI/1800)*sec )
+  ctx.lineWidth = 10;
+  ctx.beginPath();
+  ctx.moveTo(-28,0);
+  ctx.lineTo(112,0);
+  ctx.stroke();
+  ctx.restore();
+
+  // Write seconds
+  ctx.save();
+  ctx.rotate(sec * Math.PI/30);
+  ctx.strokeStyle = "#D40000";
+  ctx.fillStyle = "#D40000";
+  ctx.lineWidth = 6;
+  ctx.beginPath();
+  ctx.moveTo(-30,0);
+  ctx.lineTo(83,0);
+  ctx.stroke();
+  ctx.beginPath();
+  ctx.arc(0,0,10,0,Math.PI*2,true);
+  ctx.fill();
+  ctx.beginPath();
+  ctx.arc(95,0,10,0,Math.PI*2,true);
+  ctx.stroke();
+  ctx.fillStyle = "rgba(0,0,0,0)";
+  ctx.arc(0,0,3,0,Math.PI*2,true);
+  ctx.fill();
+  ctx.restore();
+
+  ctx.beginPath();
+  ctx.lineWidth = 14;
+  ctx.strokeStyle = '#325FA2';
+  ctx.arc(0,0,142,0,Math.PI*2,true);
+  ctx.stroke();
+
+  ctx.restore();
+}
+ + + +

{{EmbedLiveSample("An_animated_clock", "180", "180", "https://mdn.mozillademos.org/files/203/Canvas_animation2.png")}}

+ +

循環景色

+ +

本例會產一個由左到右循環捲動美國優勝美地國家公園景色,你也可以自行替換其他比畫布還大的圖片。

+ +
var img = new Image();
+
+// User Variables - customize these to change the image being scrolled, its
+// direction, and the speed.
+
+img.src = '/files/4553/Capitan_Meadows,_Yosemite_National_Park.jpg';
+var CanvasXSize = 800;
+var CanvasYSize = 200;
+var speed = 30; //lower is faster
+var scale = 1.05;
+var y = -4.5; //vertical offset
+
+// Main program
+
+var dx = 0.75;
+var imgW;
+var imgH;
+var x = 0;
+var clearX;
+var clearY;
+var ctx;
+
+img.onload = function() {
+    imgW = img.width*scale;
+    imgH = img.height*scale;
+    if (imgW > CanvasXSize) { x = CanvasXSize-imgW; } // image larger than canvas
+    if (imgW > CanvasXSize) { clearX = imgW; } // image larger than canvas
+    else { clearX = CanvasXSize; }
+    if (imgH > CanvasYSize) { clearY = imgH; } // image larger than canvas
+    else { clearY = CanvasYSize; }
+    //Get Canvas Element
+    ctx = document.getElementById('canvas').getContext('2d');
+    //Set Refresh Rate
+    return setInterval(draw, speed);
+}
+
+function draw() {
+    //Clear Canvas
+    ctx.clearRect(0,0,clearX,clearY);
+    //If image is <= Canvas Size
+    if (imgW <= CanvasXSize) {
+        //reset, start from beginning
+        if (x > (CanvasXSize)) { x = 0; }
+        //draw aditional image
+        if (x > (CanvasXSize-imgW)) { ctx.drawImage(img,x-CanvasXSize+1,y,imgW,imgH); }
+    }
+    //If image is > Canvas Size
+    else {
+        //reset, start from beginning
+        if (x > (CanvasXSize)) { x = CanvasXSize-imgW; }
+        //draw aditional image
+        if (x > (CanvasXSize-imgW)) { ctx.drawImage(img,x-imgW+1,y,imgW,imgH); }
+    }
+    //draw image
+    ctx.drawImage(img,x,y,imgW,imgH);
+    //amount to move
+    x += dx;
+}
+
+ +

循環景色就是在下方的{{HTMLElement("canvas")}}中捲動,請注意其中的width和height和程式碼中的CanvasXZSize與CanvasYSize一樣。

+ +
<canvas id="canvas" width="800" height="200"></canvas>
+ +

Live sample

+ +

{{EmbedLiveSample("A_looping_panorama", "830", "230")}}

+ +

其他範例

+ +
+
Gartic
+
+

多人繪圖遊戲

+
+
Canvascape
+
+

第一人稱3D冒險遊戲

+
+
A basic ray-caster
+
透過鍵盤控制動畫範例
+
canvas adventure
+
+

另一個透過鍵盤控制動畫範例

+
+
An interactive Blob
+
和Blob遊戲
+
Flying through a starfield
+
+

飛越星河

+
+
iGrapher
+
+

股票市場圖

+
+
+ +

See also

+ + + +

{{PreviousNext("Web/Guide/HTML/Canvas_tutorial/Compositing", "Web/Guide/HTML/Canvas_tutorial/Optimizing_canvas")}}

diff --git a/files/zh-tw/web/api/canvas_api/tutorial/basic_usage/index.html b/files/zh-tw/web/api/canvas_api/tutorial/basic_usage/index.html new file mode 100644 index 0000000000..9d39027c96 --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/basic_usage/index.html @@ -0,0 +1,158 @@ +--- +title: Canvas 基本用途 +slug: Web/API/Canvas_API/Tutorial/Basic_usage +translation_of: Web/API/Canvas_API/Tutorial/Basic_usage +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial", "Web/API/Canvas_API/Tutorial/Drawing_shapes")}}
+ +
+

Let's start this tutorial by looking at the {{HTMLElement("canvas")}} {{Glossary("HTML")}} element itself. At the end of this page, you will know how to set up a canvas 2D context and have drawn a first example in your browser.

+
+ +

<canvas> 元素

+ +
<canvas id="tutorial" width="150" height="150"></canvas>
+
+ +

首先,先來看看 {{HTMLElement("canvas")}},它看起來有點像 {{HTMLElement("img")}} 元素,其中的差異點在於 <canvas> 沒有 src alt 屬性,<canvas> 只有 {{htmlattrxref("width", "canvas")}} 與 {{htmlattrxref("height", "canvas")}} 這兩個屬性,這兩個屬性皆為非必須、能透過 DOM屬性設定;若是沒有設定 width 和 height 屬性,畫布寬預設值為 300 pixels、高預設值為 150 pixels,我們可以用 CSS 強制設定元素尺寸,但當渲染時,影像會縮放以符合元素的尺寸。

+ +
+

Note:如果繪圖結果看起來有些扭曲,可以改試著用<canvas>自身的widthheight屬性而不要用CSS來設定寬高。

+
+ +

幾乎所有HTML元素都有id屬性,<canvas>也不例外,為了方便於程式碼腳本找到需要的<canvas>,每次都設定id是一項不錯的作法。

+ +

如同一般的影像可以設定如邊界(margin)、邊框(border)、背景(background)等等,<canvas>元素一樣可以設定這些樣式,然而,這些樣式規則不會影響canvas實際繪圖,稍後我們會看到相關範例。當沒有套用樣式規定時,<canvas>會被初始成全透明。

+ +

 

+ +
+

錯誤替代內容(Fallback content)

+ +

因為舊版瀏覽器(特別是IE9之前的IE)不支援{<canvas>}元素,我們應該為這些瀏覽器準備錯誤替代內容。

+ +

當不支援<canvas>的瀏覽器看到不認識的<canvas>時會忽略<canvas>,而此時在<canvas>下瀏覽器認識的替代內容則會被瀏覽器解析顯示,至於支援<canvas>的瀏覽器則是會正常解析<canvas>,忽略替代內容。

+ +

例如,我們可以準備一段canvas內容的說明文字或canvas繪圖完成後的靜態圖片,如下所示:

+ +
<canvas id="stockGraph" width="150" height="150">
+  current stock price: $3.15 +0.15
+</canvas>
+
+<canvas id="clock" width="150" height="150">
+  <img src="images/clock.png" width="150" height="150" alt=""/>
+</canvas>
+
+ +
 
+ +

需要</canvas>標籤

+ +

不像{{HTMLElement("img")}}元素,{{HTMLElement("canvas")}}元素必須要有</canvas>結束標籤。

+ +

 

+ +
+

縱使早期AppleSafari瀏覽器不需要結束標籤,但是基於規範,這是必須的,所以,為了相容性考量,應該要有結束標籤。Safari 2.0以前的版本會同時解析canvas以及替代內容,除非我們用CSS去遮蓋內容,不過幸運的是,現在已經沒有甚麼人在用這些舊版Safari

+
+ +

如果不需要錯誤替代內容,簡單的<canvas id="foo" ...></canvas>便可以完全相容於所有支援的瀏覽器。

+ +

 

+ +

渲染環境(rendering context)

+ +

{{HTMLElement("canvas")}}產生一個固定大小的繪圖畫布,這個畫布上有一或多個渲染環境(rendering context),我們可以用渲染環境來產生或操作顯示內容的渲染環境(rendering context)不同環境(context)可能會提供不同型態的渲染方式,好比說WebGL使用OpenGL ES3D環境(context),而這裡我們主要將討論2D渲染環境(rendering context)

+ +

一開始canvas為空白,程式碼腳本需要先存取渲染環境,在上面繪圖,然後才會顯現影像。{{HTMLElement("canvas")}} 素有一個方法(method)getContext(),透過此方法可以取得渲染環境及其繪圖函數(function)getContext()輸入參數只有渲染環境類型一項,像本教學所討論的2D繪圖,就是輸入”2d”

+ +
var canvas = document.getElementById('tutorial');
+var ctx = canvas.getContext('2d');
+
+ +

上面第一行先呼叫{{domxref("document.getElementById()")}}來取得{{HTMLElement("canvas")}}元素,一旦取得元素後,便可以用其getContext()取得渲染環境。

+ +

 

+ +
+

支援性檢查

+ +

替代內容會被不支援{{HTMLElement("canvas")}}.的瀏覽器所顯示。程式碼腳本也可以利用檢查getContext()方法是否存在來檢查是否支援<canvas>,我們可以修改上面例子成如下:

+ +
var canvas = document.getElementById('tutorial');
+
+if (canvas.getContext){
+  var ctx = canvas.getContext('2d');
+  // drawing code here
+} else {
+  // canvas-unsupported code here
+}
+
+
+
+ +
 
+ +

一個範本

+ +

這裡是一個最簡單的範本,之後就是我們範例的起始點。

+ +
<html>
+  <head>
+    <title>Canvas tutorial</title>
+    <script type="text/javascript">
+      function draw(){
+        var canvas = document.getElementById('tutorial');
+        if (canvas.getContext){
+          var ctx = canvas.getContext('2d');
+        }
+      }
+    </script>
+    <style type="text/css">
+      canvas { border: 1px solid black; }
+    </style>
+  </head>
+  <body onload="draw();">
+    <canvas id="tutorial" width="150" height="150"></canvas>
+  </body>
+</html>
+
+ +

一旦網頁載入完成後,程式碼會呼叫draw()函數(這是利用document上的load事件完成),這類draw()函數也可以透過{{domxref("window.setTimeout()")}}, {{domxref("window.setInterval()")}}或其他事件處理函數來呼叫,只要呼叫的時間點是在網頁載入完後。

+ +

這是我們的範本實際看起來的樣子:

+ +

{{EmbedLiveSample("A_skeleton_template", 160, 160)}}

+ +

一個簡單的範例

+ +

首先,讓我們先來畫兩個相交的正方形,其中一個正方形有alpha透明值,之後我們會說明這是如何達成的。

+ +
<html>
+ <head>
+  <script type="application/javascript">
+    function draw() {
+      var canvas = document.getElementById("canvas");
+      if (canvas.getContext) {
+        var ctx = canvas.getContext("2d");
+
+        ctx.fillStyle = "rgb(200,0,0)";
+        ctx.fillRect (10, 10, 55, 50);
+
+        ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
+        ctx.fillRect (30, 30, 55, 50);
+      }
+    }
+  </script>
+ </head>
+ <body onload="draw();">
+   <canvas id="canvas" width="150" height="150"></canvas>
+ </body>
+</html>
+
+ +

本範例的結果如下:

+ +

{{EmbedLiveSample("A_simple_example", 160, 160, "https://mdn.mozillademos.org/files/228/canvas_ex1.png")}}

+ +

{{PreviousNext("Web/Guide/HTML/Canvas_tutorial", "Web/Guide/HTML/Canvas_tutorial/Drawing_shapes")}}

diff --git a/files/zh-tw/web/api/canvas_api/tutorial/compositing/index.html b/files/zh-tw/web/api/canvas_api/tutorial/compositing/index.html new file mode 100644 index 0000000000..e5453c93a5 --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/compositing/index.html @@ -0,0 +1,207 @@ +--- +title: 合成效果 +slug: Web/API/Canvas_API/Tutorial/Compositing +translation_of: Web/API/Canvas_API/Tutorial/Compositing +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Transformations", "Web/API/Canvas_API/Tutorial/Basic_animations")}}
+ +

在前述的範例中,新繪製的圖形總會覆蓋在之前的圖形上,對大多數情況來說這相當正常,不過它也限制了圖形繪製的順序。其實我們可以透過 globalCompositeOperation 屬性來改變這項預設行為。

+ +

globalCompositeOperation

+ +

利用 globalCompositeOperation,我們可以將新圖形繪製在舊圖形之下、遮蓋部分區域、清除畫布部分區域 (不同於 clearRect() 函式只能清除矩形區域)。

+ +
+
globalCompositeOperation = type
+
type 字串可指定為以下 12 種合成設定之一,每一種合成設定均將套用到新繪製的圖形上。
+
+ +
+

Note: 下列圖例的藍色矩形是舊圖形,紅色圓形是新圖形。

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

source-over 預設值。將新圖形畫在舊圖形之上。

+
+

Image:Canvas_composite_srcovr.png

+
+

destination-over
+ 將新圖形畫在舊圖形之下。

+
+

Image:Canvas_composite_destovr.png

+
+

source-in
+ 只保留新、舊圖形重疊的新圖形區域,其餘皆變為透明。

+
+

Image:Canvas_composite_srcin.png

+
+

destination-in
+ 只保留新、舊圖形重疊的舊圖形區域,其餘皆變為透明。

+
+

Image:Canvas_composite_destin.png

+
+

source-out
+ 只保留新、舊圖形非重疊的新圖形區域,其餘皆變為透明。

+
+

Image:Canvas_composite_srcout.png

+
+

destination-out
+ 只保留新、舊圖形非重疊的舊圖形區域,其餘皆變為透明。

+
+

Image:Canvas_composite_destout.png

+
+

source-atop
+ 新圖形只繪製在新、舊圖形重疊的新圖形區域,然後蓋在舊圖形之上。

+
+

Image:Canvas_composite_srcatop.png

+
+

destination-atop
+ 舊圖形只保留在新、舊圖形重疊的舊圖形區域,然後蓋在新圖形之上。

+
+

Image:Canvas_composite_destatop.png

+
+

lighter
+ 新舊圖形重疊區域的顏色,由新、舊圖形的顏色碼相加而得。

+
+

Image:Canvas_composite_lighten.png

+
+

darker {{obsolete_inline}}

+ +

新舊圖形重疊區域的顏色,由新、舊圖形的顏色碼相減而得。此屬性值已經從畫布規格中移除了,不再支援。

+
+

Image:Canvas_composite_darken.png

+
+

xor
+ 新舊圖形重疊區域設為透明。

+
+

Image:Canvas_composite_xor.png

+
+

copy
+ 移除其他圖形,只保留新圖形。

+
+

Image:Canvas_composite_copy.png

+
+ +

這裡有這些構圖組合的實際範例輸出結果在此。

+ +

裁剪路徑

+ +

裁剪路徑就像是一般畫布圖形繪圖,但就如同遮罩一樣,會蓋掉不需要的部分,如右圖所示。紅邊星星是我們的裁剪路徑,在路徑區域以外部分都不會出現在畫布上。

+ +

和上述 globalCompositeOperation 相比,可以發現 source-in 和 source-atop 這兩種構圖組合所達到的效果,和裁剪路徑類似,而其中最大差異在於裁剪路徑不需加入新圖形,消失的部分也不會出現在畫布上,所以,如果想要限定繪圖區域,裁剪路徑會是更理想的作法。

+ +

繪畫圖形一章中,我們只提到 stroke() 和 fill() 函式,但其實還有第三個函式,那就是 clip() 函式。

+ +
+
clip()
+
轉換目前繪圖路徑為裁剪路徑。
+
+ +

呼叫 clip() 除了會替代 closePath() 來關閉路徑之外,還會轉換目前填滿或勾勒繪圖路徑為裁剪路徑。

+ +

 {{HTMLElement("canvas")}} 畫布預設有一個等同於本身大小的裁剪路徑,等同於無裁剪效果。

+ +

clip 範例

+ +

本範例使用了圓形的裁剪路徑,來限定畫星星時的繪圖區域。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  ctx.fillRect(0,0,150,150);
+  ctx.translate(75,75);
+
+  // Create a circular clipping path
+  ctx.beginPath();
+  ctx.arc(0,0,60,0,Math.PI*2,true);
+  ctx.clip();
+
+  // draw background
+  var lingrad = ctx.createLinearGradient(0,-75,0,75);
+  lingrad.addColorStop(0, '#232256');
+  lingrad.addColorStop(1, '#143778');
+
+  ctx.fillStyle = lingrad;
+  ctx.fillRect(-75,-75,150,150);
+
+  // draw stars
+  for (var j=1;j<50;j++){
+    ctx.save();
+    ctx.fillStyle = '#fff';
+    ctx.translate(75-Math.floor(Math.random()*150),
+                  75-Math.floor(Math.random()*150));
+    drawStar(ctx,Math.floor(Math.random()*4)+2);
+    ctx.restore();
+  }
+
+}
+
+function drawStar(ctx,r){
+  ctx.save();
+  ctx.beginPath()
+  ctx.moveTo(r,0);
+  for (var i=0;i<9;i++){
+    ctx.rotate(Math.PI/5);
+    if(i%2 == 0) {
+      ctx.lineTo((r/0.525731)*0.200811,0);
+    } else {
+      ctx.lineTo(r,0);
+    }
+  }
+  ctx.closePath();
+  ctx.fill();
+  ctx.restore();
+}
+
+ + + +

一開始我們先畫了一個黑色矩形作為畫布背景,然後移動畫布原點到中央,接著我們繪製弧線並呼叫 clip(),藉以建立圓形的裁剪路徑。畫布儲存狀態亦可儲存裁剪路徑。若要保留原本的裁剪路徑,則可於繪製新的裁剪路徑之前,先行儲存畫布狀態。

+ +

繪製裁剪路徑之後,所產生的所有圖形都只會出現在路徑以內,從後來繪製的漸層背景中可看出此特性。我們用自訂的 drawStar() 函數產生 50 個隨機散佈、大小不一的星星。這些星星同樣只會出現在裁剪路徑的範圍之內。

+ +

{{EmbedLiveSample("A_clip_example", "180", "180", "https://mdn.mozillademos.org/files/208/Canvas_clip.png")}}

+ +

{{PreviousNext("Web/Guide/HTML/Canvas_tutorial/Transformations", "Web/Guide/HTML/Canvas_tutorial/Basic_animations")}}

diff --git a/files/zh-tw/web/api/canvas_api/tutorial/drawing_shapes/index.html b/files/zh-tw/web/api/canvas_api/tutorial/drawing_shapes/index.html new file mode 100644 index 0000000000..96fe2b9615 --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/drawing_shapes/index.html @@ -0,0 +1,551 @@ +--- +title: 繪製圖形 +slug: Web/API/Canvas_API/Tutorial/Drawing_shapes +translation_of: Web/API/Canvas_API/Tutorial/Drawing_shapes +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_usage", "Web/API/Canvas_API/Tutorial/Applying_styles_and_colors")}}
+ +

網格(Grid)

+ +

在開始繪圖前,我們必須先了解畫布 (canvas) 網格,或著是說座標空間。在前一頁教學中的 HTML 範本有一個寬150 pixels (像素)、高150 pixels 的畫布。如右圖,你在畫布預設網格上繪圖,網格上 1 單位相當於畫布上 1 pixel,網格的原點 (座標 (0, 0) ) 坐落於左上角,所有元素定位皆相對於此左上角原點,所以藍色方塊的位置為從左往右推 x pixels、從上往下推 y pixels (亦即座標 (x, y) )。現在我們先專注在預設設定上,之後我們會看到如何轉換原點位置、旋轉網格以及縮放網格。

+ +

 

+ +

 

+ +

 

+ +

畫矩形

+ +

不同於SVG,{{HTMLElement("canvas")}}只支援一種原始圖形,矩形。所有的圖形都必須由一或多個繪圖路徑構成,而我們正好有一些繪圖路徑函數可以讓我們畫出複雜的圖形。

+ +
+

首先來看看矩形,共有三個矩形繪圖函數:

+ +
+
fillRect(x, y, width, height)
+
畫出一個填滿的矩形。
+
strokeRect(x, y, width, height)
+
畫出一個矩形的邊框
+
clearRect(x, y, width, height)
+
清除指定矩形區域內的內容,使其變為全透明。
+
+ +

這三個函數都接受一樣的參數: x, y代表從原點出發的座標位置,width, height代表矩形的寬高。

+ +

矩形範例

+ + + +
function draw() {
+  var canvas = document.getElementById('canvas');
+  if (canvas.getContext) {
+    var ctx = canvas.getContext('2d');
+
+    ctx.fillRect(25,25,100,100);
+    ctx.clearRect(45,45,60,60);
+    ctx.strokeRect(50,50,50,50);
+  }
+}
+ +

本例結果如下:

+ +

{{EmbedLiveSample("Rectangular_shape_example", 160, 160, "https://mdn.mozillademos.org/files/245/Canvas_rect.png")}}

+ +

fillRect()函數畫出一個寬高都100 pixels的矩形,clearRect()函數清除中央60 x 60 pixels大的正方形區域,接著strokeRect()在被清除區域內畫上一個50 x 50 pixels的矩形邊框。

+ +

之後我們會看到另外兩種代替clearRect()的方法,還有如何改變圖形顏色與筆畫樣式。

+ +

不像之後會看到的路徑繪圖函數,這三個函數會立即在畫布上畫出矩形。

+ +

路徑繪製

+ +

使用路徑 (path) 來畫圖形需要多一點步驟,一開始先產生路徑,然後用繪圖指令畫出路徑,然後再結束路徑,一旦路徑產生後便可以用畫筆或填滿方式來渲染生成,這裡是一些可用函數:

+ +
+
{{domxref("CanvasRenderingContext2D.beginPath", "beginPath()")}}
+
產生一個新路徑,產生後再使用繪圖指令來設定路徑。
+
{{domxref("CanvasRenderingContext2D.closePath", "closePath()")}}
+
閉合路徑好讓新的繪圖指令來設定路徑。
+
路徑 API
+
路徑 API,這些 API 便是繪圖指令
+
+ +
+
{{domxref("CanvasRenderingContext2D.stroke", "stroke()")}}
+
畫出圖形的邊框。
+
{{domxref("CanvasRenderingContext2D.fill", "fill()")}}
+
填滿路徑內容區域來產生圖形。
+
+ +

第一步呼叫 beginPath() 產生一個路徑,表面下,路徑會被存在一個次路徑 (sub-path) 清單中,例如直線、曲線等,這些次路徑集合起來就形成一塊圖形。每一次呼叫這個方法,次路徑清單就會被重設,然後我們便能夠畫另一個新圖形。

+ +
Note: 當目前路徑為空(例如接著呼叫beginPath()完後)或是在一個新畫布上,不論為何,第一個路徑繪圖指令總是moveTo();因為每當重設路徑後,你幾乎都會需要設定繪圖起始點。
+ +

第二步是呼叫各式方法來實際設定繪圖路徑,稍後我們將會介紹這部分。

+ +

第三步,也是非必要的一步,就是呼叫closePath()。這個方法會在現在所在點到起始點間畫一條直線以閉合圖形,如果圖形已經閉合或是只含一個點,這個方法不會有任何效果。

+ +
Note: 當呼叫fill(),任何開放的圖形都會自動閉合,所以不需要再呼叫closePath(),但是stroke()並非如此。
+ +

畫一個三角形

+ +

這是一個畫出三角形的程式碼範例。

+ + + +
function draw() {
+  var canvas = document.getElementById('canvas');
+  if (canvas.getContext){
+    var ctx = canvas.getContext('2d');
+
+    ctx.beginPath();
+    ctx.moveTo(75,50);
+    ctx.lineTo(100,75);
+    ctx.lineTo(100,25);
+    ctx.fill();
+  }
+}
+
+ +

結果如下:

+ +

{{EmbedLiveSample("Drawing_a_triangle", 110, 110, "https://mdn.mozillademos.org/files/9847/triangle.png")}}

+ +

移動畫筆

+ +

moveTo()是一個很有用的函數,moveTo()不會畫任何圖形,但卻是上述路徑清單的一部分,這大概有點像是把筆從紙上一點提起來,然後放到另一個點。

+ +
+
{{domxref("CanvasRenderingContext2D.moveTo", "moveTo(x, y)")}}
+
移動畫筆到指定的(x, y)座標點
+
+ +

當初始化畫布或是呼叫beginPath(),通常會想要使用moveTo()來指定起始點,我們可以用moveTo()畫不連結的路徑,看一下笑臉圖範例,圖中紅線即為使用到moveTo()的位置。

+ +

你可以拿下面的程式碼,放進先前的draw()函數,自己試試看效果。

+ + + +
function draw() {
+  var canvas = document.getElementById('canvas');
+  if (canvas.getContext){
+    var ctx = canvas.getContext('2d');
+
+    ctx.beginPath();
+    ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle
+    ctx.moveTo(110,75);
+    ctx.arc(75,75,35,0,Math.PI,false);   // Mouth (clockwise)
+    ctx.moveTo(65,65);
+    ctx.arc(60,65,5,0,Math.PI*2,true);  // Left eye
+    ctx.moveTo(95,65);
+    ctx.arc(90,65,5,0,Math.PI*2,true);  // Right eye
+    ctx.stroke();
+  }
+}
+
+ +

結果如下:

+ +

{{EmbedLiveSample("Moving_the_pen", 160, 160, "https://mdn.mozillademos.org/files/252/Canvas_smiley.png")}}

+ +

移除moveTo()便可以看到線條連結起來。

+ +
+

Note: 有關arc(),請參照下方 {{anch("Arcs")}} .

+
+ +

線條

+ +

用lineTo()方法畫直線。

+ +
+
{{domxref("CanvasRenderingContext2D.lineTo", "lineTo(x, y)")}}
+
從目前繪圖點畫一條直線到指定的(x, y)座標點。
+
+ +

本方法接受x, y參數作為線條結束點的座標位置,至於起始點則視前一個繪圖路徑,由前一個繪圖路徑的結束點作為起始點,當然,起始點也可以用moveTo()方法來變更。

+ +

下面畫兩個三角形,一個填滿,一個空心。

+ + + +
function draw() {
+  var canvas = document.getElementById('canvas');
+  if (canvas.getContext){
+    var ctx = canvas.getContext('2d');
+
+    // Filled triangle
+    ctx.beginPath();
+    ctx.moveTo(25,25);
+    ctx.lineTo(105,25);
+    ctx.lineTo(25,105);
+    ctx.fill();
+
+    // Stroked triangle
+    ctx.beginPath();
+    ctx.moveTo(125,125);
+    ctx.lineTo(125,45);
+    ctx.lineTo(45,125);
+    ctx.closePath();
+    ctx.stroke();
+  }
+}
+
+ +

從呼叫beginPath()起始一個新圖形路徑,然後用moveTo()移到我們想要的起始點,然後再畫兩條線形成三角形的兩邊。

+ +

{{EmbedLiveSample("Lines", 160, 160, "https://mdn.mozillademos.org/files/238/Canvas_lineTo.png")}}

+ +

我們可以看到填滿(fill)三角形和勾勒(stroke)三角形的區別;當填滿時,圖形會自動閉合,不過勾勒則不會,所以如果沒有呼叫closePaht()的話,只會畫出兩條線而非三角形。

+ +

弧形

+ +

用arc()方法來畫弧形或圓形。雖然也可以用arcTo(),但這個方法比較不可靠,所以這裡我們不討論arcTo()。

+ +
+
{{domxref("CanvasRenderingContext2D.arc", "arc(x, y, radius, startAngle, endAngle, anticlockwise)")}}
+
畫一個弧形
+
+ +

本方法接受五個參數: x, y代表圓心座標點,radius代表半徑,startAngle, endAngle分別代表沿著弧形曲線上的起始點與結束點的弧度,弧度測量是相對於x軸,anticlockwise為true代表逆時針作圖、false代表順時針作圖。

+ +
+

Note: arc()方法用的是弧度(radians)而非角度(degrees),如果要在弧度與角度間換算,可以利用以下javascript程式碼: radians = (Math.PI/180) * degrees.

+
+ +

以下例子比較複雜,它會畫出12個不同的弧形。

+ +

兩個for迴圈走一遍弧形圖列的列跟行,每一個弧形由呼叫beginPath()開始新的繪圖路徑,為了清楚,我們在程式範例中用變數儲存參數,你不一定要這麼做。

+ +

x, y座標點的部分應該相當淺顯,radius和startAngle是定值,endAngle從180度(半圓)開始,然後每一行增加90度,最後一行便會形成一個完整的圓。

+ +

第1, 3列的anticlockwise 為false,所以會順時針作圖,2, 4列的anticlockwise 為true,所以會逆時針作圖。最後的if決定下半部是用填滿圖形,上半部是勾勒圖形。

+ + + +
function draw() {
+  var canvas = document.getElementById('canvas');
+  if (canvas.getContext){
+    var ctx = canvas.getContext('2d');
+
+    for(var i=0;i<4;i++){
+      for(var j=0;j<3;j++){
+        ctx.beginPath();
+        var x              = 25+j*50;               // x coordinate
+        var y              = 25+i*50;               // y coordinate
+        var radius         = 20;                    // Arc radius
+        var startAngle     = 0;                     // Starting point on circle
+        var endAngle       = Math.PI+(Math.PI*j)/2; // End point on circle
+        var anticlockwise  = i%2==0 ? false : true; // clockwise or anticlockwise
+
+        ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
+
+        if (i>1){
+          ctx.fill();
+        } else {
+          ctx.stroke();
+        }
+      }
+    }
+  }
+}
+
+{{EmbedLiveSample("Arcs", 160, 210, "https://mdn.mozillademos.org/files/204/Canvas_arc.png")}} + +

貝茲曲線(Bezier curve)與二次曲線(quadratic curve)

+ +

二次與三次貝茲曲線(Bézier curves)是另一種可用來構成複雜有機圖形的路徑。

+ +
+
{{domxref("CanvasRenderingContext2D.quadraticCurveTo", "quadraticCurveTo(cp1x, cp1y, x, y)")}}
+
從目前起始點畫一條二次貝茲曲線到x, y指定的終點,控制點由cp1x, cp1y指定。
+
{{domxref("CanvasRenderingContext2D.bezierCurveTo", "bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)")}}
+
從目前起始點畫一條三次貝茲曲線到x, y指定的終點,控制點由(cp1x, cp1y)和(cp2x, cp2y)指定。
+
+ +

二次和三次的差別可以從右圖看出;貝茲曲線的起始和終點以藍點標示,其中二次貝茲曲線只有一個控制點(如紅點標示)而三次貝茲曲線有兩個控制點。

+ +

二次和三次貝茲曲線都用x, y參數定義終點座標,然後用cp1x, xp1y定義第一個控制點座標、cp2x, xp2y定義第二個控制點座標。

+ +

用二次和三次貝茲曲線作圖相當具有挑戰性,因為不像使用 Adobe illustrator 的向量繪圖軟體,我們在繪圖時無法即時看到繪圖狀況,所以畫複雜的圖形十分困難。下面的範例我們畫了一些圖形,如果你有時間與耐心,可以畫出更複雜的圖形。

+ +

二次貝茲曲線

+ +

本例用了數個二次貝茲曲線畫了一個會話框。

+ + + +
function draw() {
+  var canvas = document.getElementById('canvas');
+  if (canvas.getContext) {
+    var ctx = canvas.getContext('2d');
+
+    // Quadratric curves example
+    ctx.beginPath();
+    ctx.moveTo(75,25);
+    ctx.quadraticCurveTo(25,25,25,62.5);
+    ctx.quadraticCurveTo(25,100,50,100);
+    ctx.quadraticCurveTo(50,120,30,125);
+    ctx.quadraticCurveTo(60,120,65,100);
+    ctx.quadraticCurveTo(125,100,125,62.5);
+    ctx.quadraticCurveTo(125,25,75,25);
+    ctx.stroke();
+  }
+}
+
+ +

{{EmbedLiveSample("Quadratic_Bezier_curves", 160, 160, "https://mdn.mozillademos.org/files/243/Canvas_quadratic.png")}}

+ +

三次貝茲曲線

+ +

這個範例畫了一個愛心。

+ + + +
function draw() {
+  var canvas = document.getElementById('canvas');
+  if (canvas.getContext){
+    var ctx = canvas.getContext('2d');
+
+    // Quadratric curves example
+    ctx.beginPath();
+    ctx.moveTo(75,40);
+    ctx.bezierCurveTo(75,37,70,25,50,25);
+    ctx.bezierCurveTo(20,25,20,62.5,20,62.5);
+    ctx.bezierCurveTo(20,80,40,102,75,120);
+    ctx.bezierCurveTo(110,102,130,80,130,62.5);
+    ctx.bezierCurveTo(130,62.5,130,25,100,25);
+    ctx.bezierCurveTo(85,25,75,37,75,40);
+    ctx.fill();
+  }
+}
+
+ +

{{EmbedLiveSample("Cubic_Bezier_curves", 160, 160, "https://mdn.mozillademos.org/files/207/Canvas_bezier.png")}}

+ +

矩形

+ +

除了在{畫矩形}段落中提到的三個方法,還有rect()方法能夠在畫布上畫矩形;rect()方法會在目前路徑下加入一個矩形繪圖路徑。

+ +
+
{{domxref("CanvasRenderingContext2D.bezierCurveTo", "rect(x, y, width, height)")}}
+
畫一個左上角位於(x, y)、寬width、高height的矩形。
+
+ +

呼叫這個方法,moveTo()方法會以(0, 0)參數被自動呼叫,所以目前的下筆點跟者自動被設為預設座標。

+ +

多樣組合

+ +

截至目前為止,我們都只用一種路徑函數在各個範例裡作圖,不過,其實繪圖時並沒有任何使用數量或種類上的路徑函數限制,所以最後我們來試著組合各樣路徑繪圖函數來畫一些十分有名的遊戲角色。

+ + + +
function draw() {
+  var canvas = document.getElementById('canvas');
+  if (canvas.getContext){
+    var ctx = canvas.getContext('2d');
+
+    roundedRect(ctx,12,12,150,150,15);
+    roundedRect(ctx,19,19,150,150,9);
+    roundedRect(ctx,53,53,49,33,10);
+    roundedRect(ctx,53,119,49,16,6);
+    roundedRect(ctx,135,53,49,33,10);
+    roundedRect(ctx,135,119,25,49,10);
+
+    ctx.beginPath();
+    ctx.arc(37,37,13,Math.PI/7,-Math.PI/7,false);
+    ctx.lineTo(31,37);
+    ctx.fill();
+
+    for(var i=0;i<8;i++){
+      ctx.fillRect(51+i*16,35,4,4);
+    }
+
+    for(i=0;i<6;i++){
+      ctx.fillRect(115,51+i*16,4,4);
+    }
+
+    for(i=0;i<8;i++){
+      ctx.fillRect(51+i*16,99,4,4);
+    }
+
+    ctx.beginPath();
+    ctx.moveTo(83,116);
+    ctx.lineTo(83,102);
+    ctx.bezierCurveTo(83,94,89,88,97,88);
+    ctx.bezierCurveTo(105,88,111,94,111,102);
+    ctx.lineTo(111,116);
+    ctx.lineTo(106.333,111.333);
+    ctx.lineTo(101.666,116);
+    ctx.lineTo(97,111.333);
+    ctx.lineTo(92.333,116);
+    ctx.lineTo(87.666,111.333);
+    ctx.lineTo(83,116);
+    ctx.fill();
+
+    ctx.fillStyle = "white";
+    ctx.beginPath();
+    ctx.moveTo(91,96);
+    ctx.bezierCurveTo(88,96,87,99,87,101);
+    ctx.bezierCurveTo(87,103,88,106,91,106);
+    ctx.bezierCurveTo(94,106,95,103,95,101);
+    ctx.bezierCurveTo(95,99,94,96,91,96);
+    ctx.moveTo(103,96);
+    ctx.bezierCurveTo(100,96,99,99,99,101);
+    ctx.bezierCurveTo(99,103,100,106,103,106);
+    ctx.bezierCurveTo(106,106,107,103,107,101);
+    ctx.bezierCurveTo(107,99,106,96,103,96);
+    ctx.fill();
+
+    ctx.fillStyle = "black";
+    ctx.beginPath();
+    ctx.arc(101,102,2,0,Math.PI*2,true);
+    ctx.fill();
+
+    ctx.beginPath();
+    ctx.arc(89,102,2,0,Math.PI*2,true);
+    ctx.fill();
+  }
+}
+
+// A utility function to draw a rectangle with rounded corners.
+
+function roundedRect(ctx,x,y,width,height,radius){
+  ctx.beginPath();
+  ctx.moveTo(x,y+radius);
+  ctx.lineTo(x,y+height-radius);
+  ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
+  ctx.lineTo(x+width-radius,y+height);
+  ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
+  ctx.lineTo(x+width,y+radius);
+  ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
+  ctx.lineTo(x+radius,y);
+  ctx.quadraticCurveTo(x,y,x,y+radius);
+  ctx.stroke();
+}
+
+ +
+

結果如下:

+ +

{{EmbedLiveSample("Making_combinations", 160, 160)}}

+ +

畫出這樣的圖其實沒有想像中的困難,所以我們就不再描述細節了,其中比較需要注意的是,我們在繪圖環境上用了fillStyle屬性以及一個自定義的效用函數(roundedRect()),利用效用函數來執行時常重複的繪圖工作可以幫忙減少程式碼數量與複雜度。

+ +

稍後我們會更進一步介紹fillStyle屬性,這個範例我們所做是的透過fillStyle屬性來改變路徑填滿色為白色,然後再改回預設黑色,來變換填滿顏色,。

+ +

{{PreviousNext("Web/Guide/HTML/Canvas_tutorial/Basic_usage", "Web/Guide/HTML/Canvas_tutorial/Using_images")}}

+
+
+ +

Path2D objects

+ +

如同前面的範例,canvas 上常常會畫上一連串的繪圖路徑,為了簡化程式碼還有改善效能,我們可以利用 {{domxref("Path2D")}} 物件 (目前在較先進的瀏覽器上已經有提供了)。Path2D 讓我們可以快取和記錄繪圖指令,方便快速重複地繪圖,底下我就來看看如何使用 Path2D :

+ +

{{domxref("Path2D.Path2D", "Path2D()")}}

+ +

    Path2D 的建構子,可接受的參數有無參數、另一個 Path2D 物件、 字元表式的 SVG path:

+ +
new Path2D();     // 不傳入參數會回傳一個空的 Path2D 物件
+new Path2D(path); // 複製傳入的 Path2D 物件,然後以之建立 Path2D 物件
+new Path2D(d);    // 以傳入的 SVG 路徑建立 Path2D 物件
+ +

所有已知的 路徑 API,如 rect, arc 等等,都可以在 Path2D 上找到。

+ +

Path2D 物件還可以加入其他 Path2D 物件,這讓我們可以很方便的組合多個物件使用。

+ +

{{domxref("Path2D.addPath", "Path2D.addPath(path [, transform])")}}

+ +

    addPath 增加一個 Path2D 物件,其中的非必要參數是變形矩陣。

+ +

Path2D example

+ +

這個例子用 Path2D 物件將矩形和圓形的繪圖路徑存起來,以供之後使用。而配合新的 Path2D API,有一些繪圖方法更接受傳入 Path2D 作為繪圖路徑使用,例如下方本例所用到的 stroke 和 fill。

+ +
function draw() {
+  var canvas = document.getElementById('canvas');
+  if (canvas.getContext){
+    var ctx = canvas.getContext('2d');
+
+    var rectangle = new Path2D();
+    rectangle.rect(10, 10, 50, 50);
+
+    var circle = new Path2D();
+    circle.moveTo(125, 35);
+    circle.arc(100, 35, 25, 0, 2 * Math.PI);
+
+    ctx.stroke(rectangle);
+    ctx.fill(circle);
+  }
+}
+ +

{{EmbedLiveSample("Path2D_example", 130, 110, "https://mdn.mozillademos.org/files/9851/path2d.png")}}

+ +

使用向量路徑 (SVG paths)

+ +

另一個強而有力的特色是在 SVG 和 Canvas 中我們都可以使用 SVG path。

+ +

下面的路徑會移到座標點 (10, 10) (M10, 10),然後水平右移 80 點 (h 80),垂至下移 80 點 (v 80) 水平左移 80 點 (h -80) 最後回到起始點 (z),請到Path2D 建構子頁面看繪圖範例結果。

+ +
var p = new Path2D("M10 10 h 80 v 80 h -80 Z");
+ +
{{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_usage", "Web/API/Canvas_API/Tutorial/Applying_styles_and_colors")}}
+ +

 

diff --git a/files/zh-tw/web/api/canvas_api/tutorial/drawing_text/index.html b/files/zh-tw/web/api/canvas_api/tutorial/drawing_text/index.html new file mode 100644 index 0000000000..cfafa8a5a8 --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/drawing_text/index.html @@ -0,0 +1,397 @@ +--- +title: 使用canvas繪製文字 +slug: Web/API/Canvas_API/Tutorial/Drawing_text +translation_of: Web/API/Canvas_API/Tutorial/Drawing_text +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Applying_styles_and_colors", "Web/API/Canvas_API/Tutorial/Using_images")}}
+ +

{{ gecko_minversion_header("1.9") }}

+ +

canvas元素支援在標準 HTML 5 特色以及少許實驗性的Mozilla方法和功能上繪製文字。

+ +

文字可以包括任何Unicode字元,即使用那些超出“基本多文種平面”的字元也可以。

+ +

{{ fx_minversion_note("3.5", '在Firefox 3.5或之後的版本,當繪圖時,任何對於 shadow effects(陰影效果)的處理可以使用在文字上。') }}

+ +

方法概述

+ + + + + + + + + + + + + + + + + + + + + + + + + +
void fillText(in DOMString text, in float x, in float y, [optional] in float maxWidth); {{ gecko_minversion_inline("1.9.1") }}
nsIDOMTextMetrics measureText(in DOMString textToMeasure); {{ gecko_minversion_inline("1.9.1") }}
void mozDrawText(in DOMString textToDraw); {{ deprecated_inline() }}
float mozMeasureText(in DOMString textToMeasure); {{ deprecated_inline() }}
void mozPathText(in DOMString textToPath);
void mozTextAlongPath(in DOMString textToDraw, in boolean stroke);
void strokeText(in DOMString text, in float x, in float y, [optional] in float maxWidth); {{ gecko_minversion_inline("1.9.1") }}
+ +

 

+ +

屬性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
屬性型別描述
font {{ gecko_minversion_inline("1.9.1") }}DOMString +

當前的文字樣式被用在繪製文字。該字串使用和 CSS font(樣式表字型)相同的語法。要改變繪製文字的樣式,只要簡單的改變它的屬性值即可,就像下面展示的,預設的字型是10px(像素) sans-serif(字型名稱)

+ +

例如:

+ +
+ctx.font = "20pt Arial";
+
mozTextStyle {{ deprecated_inline() }}DOMString +

由上面的Html5字型 屬性取代

+
textAlign {{ gecko_minversion_inline("1.9.1") }}DOMString +

當前繪製文字所使用的文字對齊方式。  可使用的值:

+ +
+
left
+
文字靠左對齊。
+
right
+
文字靠右對齊。
+
center
+
文字置中對齊。
+
start
+
文字依照行首對齊 (書寫習慣由左到右的地區就靠左對齊,書寫習慣由右到左的就靠右對齊。).
+
end
+
文字依照行尾對齊(書寫習慣由左到右的地區就靠右對齊,書寫習責由右到左的地區就靠左對齊。)
+
+ +

預設的值是 start.

+
textBaseline {{ gecko_minversion_inline("1.9.1") }}DOMString +

當前繪製文字的基線位置  可使用的值:

+ +
+
top
+
基線在字元區塊的頂部(圖中top of the squre位置)。
+
hanging(懸掛)
+
文字基線在拼音文字頂部的位置(圖中hanging baseline)  當前仍未支援;會顯示 alphabetic代替。
+
middle
+
文字基線在字元區塊的中間。
+
alphabetic(拼音文字)
+
這是一般拼音文字底線的位置。
+
ideographic(表意文字)
+
文字在表意文字(如漢字)底部的位置  當前仍未支援;會顯示alphabetic代替。
+
bottom
+
基線在拼音文字下伸部的位置 這與ideographic的基線位置不同,因為表意文字沒有下伸部
+
+ +

預設使用 alphabetic.

+
+ +

下圖展示了textBaseline屬性所支援的各種基線,感謝 WHATWG.

+ +

top of em squre(字元區塊頂部)大致在字型中所有字母的最頂部位置,hanging basline(懸掛基線)則是在一些特殊(較小的,像是“आ”)字母頂部,middle則是在top of em squre(字元區塊頂部和bottom of em squre(字元區塊底部)的中間,alphabetic(拼音文字)的基線位置則是在一般拼音字母如Á,ÿ,f,Ω的底線位置。ideographic(表意文字)的基線在字元的底部位置,bottom of em squre(字元區塊底部)則大致是字型中所有字母的最底部位置。而top and bottom of the bounding box(上下的區域範圍線)則比這些基線都來得更遠,基於字母的高度可能超過字元區塊頂部和底部的範圍。

+ +

方法

+ +

fillText()

+ +

繪製文字使用font屬性指定的文字樣式,對齊則使用textAlign屬性,而指定基線則使用textBaseline.  填充文字當前使用fillStyle,而strokeStyle則被忽略

+ +
注意:這個方法在 Gecko 1.9.1 (Firefox 3.5)時引進,且是HTML 5標準的一部分.
+ +
void fillText(
+   in DOMString textToDraw,
+   in float x,
+   in float y,
+   [optional] in float maxWidth
+);
+
+ +
參數
+ +
+
textToDraw
+
將文字繪製到文本中。
+
x
+
繪製位置的x座標。
+
y
+
繪製位置的y座標。
+
maxWidth
+
最大寬度,可選用的;繪製字串最大長度 如果指定此參數,當字串被計算出比這個值更寬,它會自動選擇水平方向更窄的字型(如果有可用的字型或是有可讀的字型可以嵌入當前字型之中),或者縮小字型。
+
+ +
範例
+ +
ctx.fillText("Sample String", 10, 50);
+
+ +

measureText()

+ +

測量文字。返回一個物件包含了寬度,像素值,所指定的文字會以當前的文字樣式繪製。

+ +
注意: 這個方法在 Gecko 1.9.1 (Firefox 3.5) 引進,且是HTML 5標準的一部分。
+ +
nsIDOMTextMetrics measureText(
+  in DOMString textToMeasure
+);
+
+ +
參數
+ +
+
textToMeasure
+
該字串的像素值。
+
+ +
返回值
+ +

nsIDOMTextMetrics物件的width屬性在繪製時會將數字設定給CSS 的像素值寬度。

+ +

mozDrawText()

+ +

{{ deprecated_header() }}

+ +

繪製文字使用由mozTextStyle屬性的文字樣式。文本當前的填充顏色被用來當做文字顏色。

+ +
注意:這個方法已經不被建議使用,請使用正式的HTML 5方法 fillText() and strokeText().
+ +
void mozDrawText(
+   in DOMString textToDraw
+);
+
+ +
參數
+ +
+
textToDraw
+
將文字繪製到文本。
+
+ +
範例
+ +
ctx.translate(10, 50);
+ctx.fillStyle = "Red";
+ctx.mozDrawText("Sample String");
+
+ +

這個範例將文字“Sample String”繪製到畫布(canvas)上。

+ +

mozMeasureText()

+ +

{{ deprecated_header() }}

+ +

返回寬度,像素值,指定文字

+ +
注意:這個方法已經已宣告棄用,請使用正式的HTML 5方法measureText().
+ +
float mozMeasureText(
+  in DOMString textToMeasure
+);
+
+ +
參數
+ +
+
textToMeasure
+
字串的寬度像素值
+
+ +
返回值
+ +

文字的寬度像素值

+ +
範例
+ +
var text = "Sample String";
+var width = ctx.canvas.width;
+var len = ctx.mozMeasureText(text);
+ctx.translate((width - len)/2, 0);
+ctx.mozDrawText(text);
+
+ +

這個範例測量了字串的寬度,接著使用這個資訊將它畫在畫布(canvas)的水平中心。

+ +

mozPathText()

+ +

給文字路徑加上外框線,如果你想要的話,它允許你替文字加上框線代替填充它。

+ +
void mozPathText(
+  in DOMString textToPath
+);
+
+ +
參數
+ +
+
textToPath
+
為當前的文字路徑加上框線
+
+ +
Example
+ +
ctx.fillStyle = "green";
+ctx.strokeStyle = "black";
+ctx.mozPathText("Sample String");
+ctx.fill()
+ctx.stroke()
+
+ +

這個範例繪出文字“Sample String”,填充顏色是綠色,外框顏色是黑色。

+ +

mozTextAlongPath()

+ +

Adds (or draws) the specified text along the current path.

+ +
void mozTextAlongPath(
+  in DOMString textToDraw,
+  in boolean stroke
+);
+
+ +
參數
+ +
+
textToDraw
+
沿著指定路徑繪出文字
+
stroke
+
如果參數是 true(真值),文字會沿著指定路徑繪製。如果 false(假值),這個文字則會加入到路徑之中,再沿著當前路徑繪製。
+
+ +
備註
+ +

字體不會沿著路徑曲線縮放或變形,反而在彎曲路徑下,字體每次計算都會當成是直線在處理。這可以用來建立一些特殊的效果。

+ +

strokeText()

+ +

繪製文字使用font屬性指定的文字樣式,對齊則使用textAlign屬性,而指定基線則使用textBaseline.  當前使用strokeStyle來建立文字外框。

+ +
注意: 這個方法在 Gecko 1.9.1 (Firefox 3.5)時引進,且是HTML 5標準的一部分。
+ +
void strokeText(
+   in DOMString textToDraw,
+   in float x,
+   in float y,
+   [optional] in float maxWidth
+);
+
+ +
參數
+ +
+
textToDraw
+
將文字繪製到文本中。
+
x
+
繪製位置的x座標。
+
y
+
繪製位置的y座標
+
maxWidth
+
最大寬度,可選用的;繪製字串最大長度 如果指定此參數,當字串被計算出比這個值更寬,它會自動選擇水平方向更窄的字型(如果有可用的字型或是有可讀的字型可以嵌入當前字型之中),或者縮小字型。
+
+ +
範例
+ +
ctx.strokeText("Sample String", 10, 50);
+
+ +

備註

+ + + +

其它範例

+ + + +

瀏覽器兼容性

+ +

{{ CompatibilityTable() }}

+ +
+
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1+3.5+9.010.54.0
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support2.1{{ CompatUnknown() }}9.011.03.2
+
+
+ +

 

diff --git a/files/zh-tw/web/api/canvas_api/tutorial/index.html b/files/zh-tw/web/api/canvas_api/tutorial/index.html new file mode 100644 index 0000000000..15280a881d --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/index.html @@ -0,0 +1,69 @@ +--- +title: Canvas 教學文件 +slug: Web/API/Canvas_API/Tutorial +translation_of: Web/API/Canvas_API/Tutorial +--- +
{{CanvasSidebar}}
+ +

+ +
+

<canvas> 是一個 HTML 元素,我們可以利用程式腳本在這個元素上繪圖(通常是用 JavaScript)。除了繪圖,我們還可以合成圖片或做一些簡單(或是不那麼簡單)的動畫。右方的影像便是一些運用 <canvas> 的例子,接下來我們將會在教學文件中一一說明

+
+ +

本教學從基礎知識開始,描述如何利用 <canvas> 進行 2D 繪圖。教學中的範例會讓各位清楚瞭解 <canvas> 該如何運用,另外也會提供程式碼範例,讓大家嘗試製作自己的內容。

+ +

<canvas> 最早是由 Apple 為 Mac OS X Dashboard 所提出,之後 Safari 和 Google Chrome 也都採用。Gecko 1.8 作基礎的瀏覽器,如 Firefox 1.5 也都提供了支援。<canvas> 元素是 WhatWG Web applications 1.0(也就是 HTML5)規範的一部分,目前所有主流的瀏覽器都已支援。

+ +

在開始之前

+ +

<canvas> 並不困難,但你需要了解基本的 HTMLJavaScript。部分舊版瀏覽器不支援 <canvas>,不過基本上現今所有主流的瀏覽器都有支援。預設的畫布大小是 300px * 150px(寬 * 高)。但你也可以透過 HTML 寬、高屬性({{Glossary("attribute")}})自訂。為了在畫布上作畫,我們使用了一個 JavaScript context 物件來即時繪製圖形。

+ +

教學文件

+ + + +

參見

+ + + +

致歉各位貢獻者

+ +

由於 2013/6/17 那一週的不幸技術錯誤,所有有關本教學的歷史紀錄,包括過去所有貢獻者的紀錄都遺失了,我們深感抱歉,希望各位可以原諒這一次不幸的意外。

+ +
{{ Next("Web/Guide/HTML/Canvas_tutorial/Basic_usage") }}
+ +
 
diff --git a/files/zh-tw/web/api/canvas_api/tutorial/optimizing_canvas/index.html b/files/zh-tw/web/api/canvas_api/tutorial/optimizing_canvas/index.html new file mode 100644 index 0000000000..7fb8b35666 --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/optimizing_canvas/index.html @@ -0,0 +1,26 @@ +--- +title: 最佳化canvas +slug: Web/API/Canvas_API/Tutorial/Optimizing_canvas +translation_of: Web/API/Canvas_API/Tutorial/Optimizing_canvas +--- +

{{HTMLElement("canvas")}}在網頁2D繪圖上被大量運用於遊戲和複雜視覺化效果上。隨著繪圖複雜度越來越高,效能問題也會逐一浮現,所以最後我們在這邊列出一些最佳化畫布的方法,避免一些效能問題:

+ +

{{PreviousNext("Web/Guide/HTML/Canvas_tutorial/Basic_animations")}}

diff --git a/files/zh-tw/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.html b/files/zh-tw/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.html new file mode 100644 index 0000000000..398ef70484 --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.html @@ -0,0 +1,265 @@ +--- +title: Pixel manipulation with canvas +slug: Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas +translation_of: Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Advanced_animations", "Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility")}}
+ +
+

直到目前為止,我們還沒真正了解 pixels 在 canvas上的運用。使用ImageData物件,可直接對pixel 裡的陣列資料讀(read)寫(write)。在接下的內容中,也可了解到如何使影像平滑化(反鋸齒)及如何將影像保存在canvas之中。

+
+ +

ImageData物件

+ +

{{domxref("ImageData")}} 物件代表canvas區中最基礎的像素。

+ +

包含它只可讀的屬性:

+ +
+
width
+
影像中的寬度,以pixels為單位
+
height
+
影像中的高度,以pixels為單位
+
data
+
{{jsxref("Uint8ClampedArray")}} 代表一維陣列包含RGBA 格式。整數值介於0到255之間(包含255)。
+
+ +

data 屬性返回一個{{jsxref("Uint8ClampedArray")}},它可被當作為pixel的初始資料。每個pixel用4個1byte值做代表分別為透明值(也就是RGBA格式)。每個顏色組成皆是介於整數值介於0到255之間。而每個組成在一個陣列中被分配為一個連續的索引。從左上角 pixel 的紅色組成中的陣列由索引 0 為始。Pixels 執行順序為從左到右,再由上到下,直到整個陣列。

+ +

{{jsxref("Uint8ClampedArray")}}  包含height × width× 4 bytes的資料,同索引值從0到 (height×width×4)-1

+ +

例如,讀取影像的藍色組成的值。從pixel 的第200欄、第50行,你可以照著下面的步驟:

+ +
blueComponent = imageData.data[((50 * (imageData.width * 4)) + (200 * 4)) + 2];
+ +

使用Uint8ClampedArray.length屬性來讀取影像pixel的陣列大小

+ +
var numBytes = imageData.data.length;
+
+ +

創造一個 ImageData物件

+ +

可以使用{{domxref("CanvasRenderingContext2D.createImageData", "createImageData()")}}方法創造一個全新空白的ImageData 物件。

+ +

這裡有兩種createImageData()的方法:

+ +
var myImageData = ctx.createImageData(width, height);
+ +

這個方法是有規定大小尺寸.所有pixels預設是透明的黑色。

+ +

下面的方法一樣是由anotherImageData參考尺寸大小,由ImageData 物件創造一個與新的一樣的大小。這些新的物件的pixel皆預設為透明的黑色。

+ +
var myImageData = ctx.createImageData(anotherImageData);
+ +

得到pixel資料的內容

+ +

可以使用getImageData()這個方法,去取得canvas內容中ImageData 物件的資料含pixel 數據(data) 

+ +
var myImageData = ctx.getImageData(left, top, width, height);
+ +

這個方法會返回ImageData物件,它代表著在這canvas區域之中pixel 的數據(data) 。從各角落的點代表著 (left,top), (left+width, top), (left, top+height), and (left+width, top+height)。這些作標被設定為canvas 的空間座標單位。

+ +
+

注釋: 在ImageData 物件中,任何超出canvas外的pixels皆會返回透明的黑色的形式。

+
+ +

這個方法也被展示在使用canvas操作影像之中。

+ +

調色盤

+ +

這個範例使用getImageData() 方法去顯示在鼠標下的顏色。

+ +

首先,需要一個正確的滑鼠點layerX​​​​​​​和 layerY。在從getImageData() 提供pixel 陣列中(array)該點的pixel 數據(data) 。最後,使用陣列數據(array data)在<div>中設置背景色和文字去顯示該色。

+ + + +
var img = new Image();
+img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+img.onload = function() {
+  ctx.drawImage(img, 0, 0);
+  img.style.display = 'none';
+};
+var color = document.getElementById('color');
+function pick(event) {
+  var x = event.layerX;
+  var y = event.layerY;
+  var pixel = ctx.getImageData(x, y, 1, 1);
+  var data = pixel.data;
+  var rgba = 'rgba(' + data[0] + ', ' + data[1] +
+             ', ' + data[2] + ', ' + (data[3] / 255) + ')';
+  color.style.background =  rgba;
+  color.textContent = rgba;
+}
+canvas.addEventListener('mousemove', pick);
+
+ +

{{ EmbedLiveSample('A_color_picker', 610, 240) }}

+ +

在內容中寫入pixel 資料

+ +

可以使用putImageData() 方法將自訂pixel 數據(data) 放入內容中:

+ +
ctx.putImageData(myImageData, dx, dy);
+
+ +

dx 和 dy參數表示填入你所希望的座標,將它代入內容中左上角的pixel 數據(data)。

+ +

For example, to paint the entire image represented by myImageData to the top left corner of the context, you can simply do the following:

+ +
ctx.putImageData(myImageData, 0, 0);
+
+ +

灰階和負片效果

+ +

In this example we iterate over all pixels to change their values, then we put the modified pixel array back to the canvas using putImageData(). The invert function simply subtracts each color from the max value 255. The grayscale function simply uses the average of red, green and blue. You can also use a weighted average, given by the formula x = 0.299r + 0.587g + 0.114b, for example. See Grayscale on Wikipedia for more information.

+ + + +
var img = new Image();
+img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
+img.onload = function() {
+  draw(this);
+};
+
+function draw(img) {
+  var canvas = document.getElementById('canvas');
+  var ctx = canvas.getContext('2d');
+  ctx.drawImage(img, 0, 0);
+  img.style.display = 'none';
+  var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+  var data = imageData.data;
+
+  var invert = function() {
+    for (var i = 0; i < data.length; i += 4) {
+      data[i]     = 255 - data[i];     // red
+      data[i + 1] = 255 - data[i + 1]; // green
+      data[i + 2] = 255 - data[i + 2]; // blue
+    }
+    ctx.putImageData(imageData, 0, 0);
+  };
+
+  var grayscale = function() {
+    for (var i = 0; i < data.length; i += 4) {
+      var avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
+      data[i]     = avg; // red
+      data[i + 1] = avg; // green
+      data[i + 2] = avg; // blue
+    }
+    ctx.putImageData(imageData, 0, 0);
+  };
+
+  var invertbtn = document.getElementById('invertbtn');
+  invertbtn.addEventListener('click', invert);
+  var grayscalebtn = document.getElementById('grayscalebtn');
+  grayscalebtn.addEventListener('click', grayscale);
+}
+
+ +

{{ EmbedLiveSample('Grayscaling_and_inverting_colors', 330, 270) }}

+ +

放大和平滑化(反鋸齒)

+ +

With the help of the {{domxref("CanvasRenderingContext2D.drawImage", "drawImage()")}} method, a second canvas and the {{domxref("CanvasRenderingContext2D.imageSmoothingEnabled", "imageSmoothingEnabled")}} property, we are able to zoom into our picture and see the details.

+ +

We get the position of the mouse and crop an image of 5 pixels left and above to 5 pixels right and below. Then we copy that one over to another canvas and resize the image to the size we want it to. In the zoom canvas we resize a 10×10 pixel crop of the original canvas to 200×200.

+ +
zoomctx.drawImage(canvas,
+                  Math.abs(x - 5), Math.abs(y - 5),
+                  10, 10, 0, 0, 200, 200);
+ +

Because anti-aliasing is enabled by default, we might want to disable the smoothing to see clear pixels. You can toggle the checkbox to see the effect of the imageSmoothingEnabled property (which needs prefixes for different browsers).

+ + + + + +
var img = new Image();
+img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
+img.onload = function() {
+  draw(this);
+};
+
+function draw(img) {
+  var canvas = document.getElementById('canvas');
+  var ctx = canvas.getContext('2d');
+  ctx.drawImage(img, 0, 0);
+  img.style.display = 'none';
+  var zoomctx = document.getElementById('zoom').getContext('2d');
+
+  var smoothbtn = document.getElementById('smoothbtn');
+  var toggleSmoothing = function(event) {
+    zoomctx.imageSmoothingEnabled = this.checked;
+    zoomctx.mozImageSmoothingEnabled = this.checked;
+    zoomctx.webkitImageSmoothingEnabled = this.checked;
+    zoomctx.msImageSmoothingEnabled = this.checked;
+  };
+  smoothbtn.addEventListener('change', toggleSmoothing);
+
+  var zoom = function(event) {
+    var x = event.layerX;
+    var y = event.layerY;
+    zoomctx.drawImage(canvas,
+                      Math.abs(x - 5),
+                      Math.abs(y - 5),
+                      10, 10,
+                      0, 0,
+                      200, 200);
+  };
+
+  canvas.addEventListener('mousemove', zoom);
+}
+ +

{{ EmbedLiveSample('Zoom_example', 620, 490) }}

+ +

儲存圖片

+ +

The {{domxref("HTMLCanvasElement")}} provides a toDataURL() method, which is useful when saving images. It returns a data URI containing a representation of the image in the format specified by the type parameter (defaults to PNG). The returned image is in a resolution of 96 dpi.

+ +
+
{{domxref("HTMLCanvasElement.toDataURL", "canvas.toDataURL('image/png')")}}
+
Default setting. Creates a PNG image.
+
{{domxref("HTMLCanvasElement.toDataURL", "canvas.toDataURL('image/jpeg', quality)")}}
+
Creates a JPG image. Optionally, you can provide a quality in the range from 0 to 1, with one being the best quality and with 0 almost not recognizable but small in file size.
+
+ +

Once you have generated a data URI from you canvas, you are able to use it as the source of any {{HTMLElement("image")}} or put it into a hyper link with a download attribute to save it to disc, for example.

+ +

You can also create a {{domxref("Blob")}} from the canvas.

+ +
+
{{domxref("HTMLCanvasElement.toBlob", "canvas.toBlob(callback, type, encoderOptions)")}}
+
Creates a Blob object representing the image contained in the canvas.
+
+ +

延伸閱讀

+ + + +

{{PreviousNext("Web/API/Canvas_API/Tutorial/Advanced_animations", "Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility")}}

diff --git a/files/zh-tw/web/api/canvas_api/tutorial/transformations/index.html b/files/zh-tw/web/api/canvas_api/tutorial/transformations/index.html new file mode 100644 index 0000000000..b25a2248dd --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/transformations/index.html @@ -0,0 +1,336 @@ +--- +title: 變形效果 +slug: Web/API/Canvas_API/Tutorial/Transformations +translation_of: Web/API/Canvas_API/Tutorial/Transformations +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Using_images", "Web/API/Canvas_API/Tutorial/Compositing")}}
+ +

畫布狀態儲存與復原

+ +

在使用變形效果等複雜繪圖方法之前,有兩個不可或缺的方法(method)必須要先了解一下:

+ +
+
save()
+
儲存現階段畫布完整狀態。
+
restore()
+
復原最近一次儲存的畫布狀態。
+
+ +

每一次呼叫save(),畫布狀態便會存進一個堆疊(stack)之中。畫布狀態包含了:

+ + + +

我們可以呼叫save()的次數不限,而每一次呼叫restore(),最近一次儲存的畫布狀態便會從堆疊中被取出,然後還原畫布到此畫布狀態。

+ +

畫布狀態儲存與復原範例

+ +

本例會畫一連串矩形圖案來說明畫布狀態堆疊是如何運作。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  ctx.fillRect(0,0,150,150);   // Draw a rectangle with default settings
+  ctx.save();                  // Save the default state
+
+  ctx.fillStyle = '#09F'       // Make changes to the settings
+  ctx.fillRect(15,15,120,120); // Draw a rectangle with new settings
+
+  ctx.save();                  // Save the current state
+  ctx.fillStyle = '#FFF'       // Make changes to the settings
+  ctx.globalAlpha = 0.5;
+  ctx.fillRect(30,30,90,90);   // Draw a rectangle with new settings
+
+  ctx.restore();               // Restore previous state
+  ctx.fillRect(45,45,60,60);   // Draw a rectangle with restored settings
+
+  ctx.restore();               // Restore original state
+  ctx.fillRect(60,60,30,30);   // Draw a rectangle with restored settings
+}
+ + + +

 

+ +

* 預設用黑色填滿這個矩形

+ +

* 每種狀態可以看成是一層層堆疊的步驟紀錄

+ +

第一步:畫出黑色矩形 接著把第一個狀態儲存下來(用黑色填滿)

+ +

第二步:畫出藍色矩形 接著把第二個狀態儲存下來(用藍色填滿)

+ +

第三步:畫出半透明矩形

+ +

第四步:再畫出矩形  這時候我們取用最新儲存過的藍色(第二狀態)

+ +

第五步:再畫一個矩形 我們再取出更早之前儲存的黑色(第一狀態)

+ +

{{EmbedLiveSample("A_save_and_restore_canvas_state_example", "180", "180", "https://mdn.mozillademos.org/files/249/Canvas_savestate.png")}}

+ +

移動畫布

+ +

第一個變形效果方法是translate()。translate()是用來移動畫布,如右圖,原先畫布的原點在網格(0, 0)位置,我們可以移動畫布,使其原點移到(x, y)位置。

+ +
+
translate(x, y)
+
移動網格上的畫布,其中x代表水平距離、y代表垂直距離。
+
+ +

最好在做任何變形效果前先儲存一下畫布狀態,如此當我們需要復原先前的狀態時,只需要呼叫一下restore()即可,而且有一種情況是當我們在迴圈中移動畫布,如果不記得儲存和回復畫布狀態,繪圖區域很容易最後就超出邊界,然後出現圖案不見的狀況。

+ +

移動畫布範例

+ +

下面程式碼示範了利用translate()畫圖的好處,裡面,我們用了drawSpirograph()函數畫萬花筒類的圖案,如果沒有移動畫布原點,那麼每個圖案只會有四分之一會落在可視範圍,藉由移動畫布原點我們便可以自由變換每個圖案的位置,使圖案完整出現,而且省去手動計算調整每個圖案的座標位置。

+ +

另外一個draw()函數透過兩個for迴圈移動畫布原點、呼叫drawSpirograph()函數、復歸畫布圓點位置共九次。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  ctx.fillRect(0,0,300,300);
+  for (var i=0;i<3;i++) {
+    for (var j=0;j<3;j++) {
+      ctx.save();
+      ctx.strokeStyle = "#9CFF00";
+      ctx.translate(50+j*100,50+i*100);
+      drawSpirograph(ctx,20*(j+2)/(j+1),-8*(i+3)/(i+1),10);
+      ctx.restore();
+    }
+  }
+}
+
+function drawSpirograph(ctx,R,r,O){
+  var x1 = R-O;
+  var y1 = 0;
+  var i  = 1;
+  ctx.beginPath();
+  ctx.moveTo(x1,y1);
+  do {
+    if (i>20000) break;
+    var x2 = (R+r)*Math.cos(i*Math.PI/72) - (r+O)*Math.cos(((R+r)/r)*(i*Math.PI/72))
+    var y2 = (R+r)*Math.sin(i*Math.PI/72) - (r+O)*Math.sin(((R+r)/r)*(i*Math.PI/72))
+    ctx.lineTo(x2,y2);
+    x1 = x2;
+    y1 = y2;
+    i++;
+  } while (x2 != R-O && y2 != 0 );
+  ctx.stroke();
+}
+
+ + + +

{{EmbedLiveSample("A_translate_example", "330", "330", "https://mdn.mozillademos.org/files/256/Canvas_translate.png")}}

+ +

旋轉

+ +

rotate()函數可以畫布原點作中心,旋轉畫布。

+ +
+
rotate(x)
+
以畫布原點為中心,順時針旋轉畫布x弧度(弧度 = Math.PI * 角度 / 180)。
+
+ +

我們可以呼叫translate()方法來移動旋轉中心(亦即畫布原點)。

+ +

旋轉範例

+ +

本範例我們呼叫rotate()方法來畫一系列環狀圖案。如果不用rotate(),同樣的效果也可以藉由個別計算x, y座標點(x = r*Math.cos(a); y = r*Math.sin(a))達成;呼叫rotate()和個別計算x, y座標點不同之處在於,個別計算x, y座標點只有旋轉圓形圓心,而圓形並沒有旋轉,呼叫rotate()則會旋轉圓形和圓心,不過因為我們的圖案是圓形,所以兩種作法產生的效果不會有差異。

+ +

我們執行了兩個迴圈來作圖,第一個迴圈決定的圓環個數和該圓環上圓環上圓點的個數的顏色,第二個迴圈決定了圓環上圓點的個數,每一次作圖前我們都儲存了原始畫布狀態,以便結束時可以復原狀態。畫布旋轉的弧度則以圓環上圓點的個數決定,像是最內圈的圓環共有六個圓點,所以每畫一個原點,畫布就旋轉60度(360度/6),第二的圓環有12個原點,所以畫布一次旋轉度數為30度(360度/12),以此類推。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  ctx.translate(75,75);
+
+  for (var i=1;i<6;i++){ // Loop through rings (from inside to out)
+    ctx.save();
+    ctx.fillStyle = 'rgb('+(51*i)+','+(255-51*i)+',255)';
+
+    for (var j=0;j<i*6;j++){ // draw individual dots
+      ctx.rotate(Math.PI*2/(i*6));
+      ctx.beginPath();
+      ctx.arc(0,i*12.5,5,0,Math.PI*2,true);
+      ctx.fill();
+    }
+
+    ctx.restore();
+  }
+}
+
+ + + +

{{EmbedLiveSample("A_rotate_example", "180", "180", "https://mdn.mozillademos.org/files/248/Canvas_rotate.png")}}

+ +

縮放

+ +

接下來這一個變形效果為縮放圖形。

+ +
+
scale(x, y)
+
x代表縮放畫布水平網格單位x倍,y代表縮放畫布垂直網格單位y倍,輸入1.0不會造成縮放。如果輸入負值會造成座標軸鏡射,假設輸入x為-1,那麼原本畫布網格X軸上的正座標點都會變成負座標點、負座標點則變成正座標點。
+
+ +

只要利用scale(),我們可以建立著名的笛卡兒座標系;執行translate(0,canvas.height)先移動畫布原點到左下角,再執行scale(1,-1)顛倒Y軸正負值,一個笛卡兒座標系便完成了。

+ +

預設上畫布網格前進一單位等於前進一像素大小,所以縮小0.5倍,就會變成前進0.5的像素大小,亦即縮小圖像一半大小,反之,放大2倍將放大圖像2倍。

+ +

縮放範例

+ +

本程式碼範例會畫出一系列不同縮放比例的萬花筒樣式圖案。

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  ctx.strokeStyle = "#fc0";
+  ctx.lineWidth = 1.5;
+  ctx.fillRect(0,0,300,300);
+
+  // Uniform scaling
+  ctx.save()
+  ctx.translate(50,50);
+  drawSpirograph(ctx,22,6,5);
+
+  ctx.translate(100,0);
+  ctx.scale(0.75,0.75);
+  drawSpirograph(ctx,22,6,5);
+
+  ctx.translate(133.333,0);
+  ctx.scale(0.75,0.75);
+  drawSpirograph(ctx,22,6,5);
+  ctx.restore();
+
+  // Non uniform scaling (y direction)
+  ctx.strokeStyle = "#0cf";
+  ctx.save()
+  ctx.translate(50,150);
+  ctx.scale(1,0.75);
+  drawSpirograph(ctx,22,6,5);
+
+  ctx.translate(100,0);
+  ctx.scale(1,0.75);
+  drawSpirograph(ctx,22,6,5);
+
+  ctx.translate(100,0);
+  ctx.scale(1,0.75);
+  drawSpirograph(ctx,22,6,5);
+  ctx.restore();
+
+  // Non uniform scaling (x direction)
+  ctx.strokeStyle = "#cf0";
+  ctx.save()
+  ctx.translate(50,250);
+  ctx.scale(0.75,1);
+  drawSpirograph(ctx,22,6,5);
+
+  ctx.translate(133.333,0);
+  ctx.scale(0.75,1);
+  drawSpirograph(ctx,22,6,5);
+
+  ctx.translate(177.777,0);
+  ctx.scale(0.75,1);
+  drawSpirograph(ctx,22,6,5);
+  ctx.restore();
+
+}
+function drawSpirograph(ctx,R,r,O){
+  var x1 = R-O;
+  var y1 = 0;
+  var i  = 1;
+  ctx.beginPath();
+  ctx.moveTo(x1,y1);
+  do {
+    if (i>20000) break;
+    var x2 = (R+r)*Math.cos(i*Math.PI/72) - (r+O)*Math.cos(((R+r)/r)*(i*Math.PI/72))
+    var y2 = (R+r)*Math.sin(i*Math.PI/72) - (r+O)*Math.sin(((R+r)/r)*(i*Math.PI/72))
+    ctx.lineTo(x2,y2);
+    x1 = x2;
+    y1 = y2;
+    i++;
+  } while (x2 != R-O && y2 != 0 );
+  ctx.stroke();
+}
+
+ + + +

第一排第一個黃色圖案是沒有縮放的圖案,然後往右到了第二個圖案,我們程式碼中輸入了 (0.75, 0.75)的縮放倍率,到了第三個圖案,我們還是輸入了 (0.75, 0.75)的縮放倍率,而基於之前有縮小過一次,所以第三個圖案相對於第一個沒有縮放的圖案是0.75 × 0.75 = 0.5625倍。

+ +

第二排藍色圖案我們只改變Y軸的縮放倍率,X軸維持不變,因而產生一個比一個更扁的橢圓圖形。同理,第三排綠色圖案改變X軸的縮放倍率,Y軸維持不變。

+ +

{{EmbedLiveSample("A_scale_example", "330", "330", "https://mdn.mozillademos.org/files/250/Canvas_scale.png")}}

+ +

變形

+ +

最後一個方法是設定變形矩陣,藉由改變變形矩陣,我們因此可以營造各種變形效果;其實先前所提到的rotate, translate, scale都是在設定變形矩陣,而這邊的這個方法就是直接去改變變形矩陣。

+ +
+
transform(m11, m12, m21, m22, dx, dy)
+
呼叫Transform會拿目前的變形矩陣乘以下列矩陣:
+
+
+
m11 	m21 	dx
+m12 	m22 	dy
+0 	0 	1
+
+
+
+ +
+
運算後的新矩陣將取代目前的變形矩陣。
+
其中m11代表水平縮放圖像,m12代表水平偏移圖像,m21代表垂直偏移圖像,m22代表垂直縮放圖像,dx代表水平移動圖像,dy代表垂直移動圖像。
+
如果輸入Infinity 值,不會引起例外錯誤,矩陣值會依照輸入設成無限。
+
setTransform(m11, m12, m21, m22, dx, dy)
+
復原目前矩陣為恆等矩陣(Identiy matrix,也就是預設矩陣),然後再以輸入參數呼叫transform()。
+
+ +

transform / setTransform範例

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  var sin = Math.sin(Math.PI/6);
+  var cos = Math.cos(Math.PI/6);
+  ctx.translate(100, 100);
+  var c = 0;
+  for (var i=0; i <= 12; i++) {
+    c = Math.floor(255 / 12 * i);
+    ctx.fillStyle = "rgb(" + c + "," + c + "," + c + ")";
+    ctx.fillRect(0, 0, 100, 10);
+    ctx.transform(cos, sin, -sin, cos, 0, 0);
+  }
+
+  ctx.setTransform(-1, 0, 0, 1, 100, 100);
+  ctx.fillStyle = "rgba(255, 128, 255, 0.5)";
+  ctx.fillRect(0, 50, 100, 100);
+}
+
+ + + +

{{EmbedLiveSample("transform_.2F_setTransform_examples", "230", "280", "https://mdn.mozillademos.org/files/255/Canvas_transform.png")}}

+ +

{{PreviousNext("Web/Guide/HTML/Canvas_tutorial/Applying_styles_and_colors", "Web/Guide/HTML/Canvas_tutorial/Compositing")}}

diff --git a/files/zh-tw/web/api/canvas_api/tutorial/using_images/index.html b/files/zh-tw/web/api/canvas_api/tutorial/using_images/index.html new file mode 100644 index 0000000000..7bb6bf791f --- /dev/null +++ b/files/zh-tw/web/api/canvas_api/tutorial/using_images/index.html @@ -0,0 +1,342 @@ +--- +title: 使用影像 +slug: Web/API/Canvas_API/Tutorial/Using_images +translation_of: Web/API/Canvas_API/Tutorial/Using_images +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_text", "Web/API/Canvas_API/Tutorial/Transformations" )}}
+ +

使用影像是{{HTMLElement("canvas")}}另一個有趣的功能,這個功能可以用來動態組合圖片或作為背景等等。任何瀏覽器支援的外部圖片格式都可以使用,例如PNG, GIF, JPEG,甚至也可以利用同一份頁面上其他畫布元素產生的影像.

+ +

載入影像到畫布中基本上需要兩個步驟:

+ +
    +
  1. +

    取得{{domxref("HTMLImageElement")}}物件或其他畫布元素的參照(reference)作為來源,透過單純提供URL或圖片位置的方式是行不通的.

    +
  2. +
  3. +

    drawImage()函數在畫布上畫影像.

    +
  4. +
+ +

接下來便來看看要怎麼做.

+ +

取得影像

+ +

畫布API能接受以下資料型態作為影像來源:

+ +
+
{{domxref("HTMLImageElement")}}
+
+

Image()建構成的影像或是{{HTMLElement("img")}}元素.

+
+
{{domxref("HTMLVideoElement")}}
+
+

{{domxref("HTMLVideoElement")}}元素作影像來源,抓取影片目前的影像畫格當作影像使用.

+
+
{{domxref("HTMLCanvasElement")}}
+
+

用另一個{{domxref("HTMLCanvasElement")}}元素當影像來源.

+
+
{{domxref("ImageBitmap")}}
+
+

可以被快速渲染的點陣圖(bitmap),點陣圖能由上述所有來源產生.

+
+
+ +

這些來源統一參照 CanvasImageSource型態.

+ +

有好幾種方法能夠取得影像用於畫布.

+ +

 

+ +

使用同一份網頁上的影像

+ +

我們能透過下面幾個方法取得影像:

+ + + +

使用來自其他網域的影像

+ +

Using the crossOrigin attribute on an 透過{{HTMLElement("HTMLImageElement")}}的crossOrigin屬性, 我們可以要求從另一個網域載入影像來使用,若是寄存網域(thehosting domain)准許跨網路存取該影像,那麼我們便可以使用它而不用污染(taint)我們的畫布,反之,使用該影像會污染畫布(taint the canvas)。

+ +

使用其他畫布元素

+ +

如同取得其他影像,我們一樣能用{{domxref("document.getElementsByTagName()")}}或{{domxref("document.getElementById()")}}方法取得其他畫布元素,但是在使用之前請記得來源畫布上已經有繪上圖了。

+ +

使用其他畫布元素作為影像來源有很多有用的應用用途,其中之一便是建立第二個小畫布作為另一個大畫布的縮小影像.

+ +

創造全新的影像

+ +

產生新的{{domxref("HTMLImageElement")}}物件也能當作影像來源,這邊,我們可以用Image()來建構一個新影像元素:

+ +
var img = new Image();   // Create new img element
+img.src = 'myImage.png'; // Set source path
+
+ +

上述程式碼執行後會載入影像.

+ +

在影像載入完成前呼叫drawImage()不會有任何效果,甚至某些瀏覽器還會拋出例外狀況,所以應該要透過利用載入事件來避免這類問題:

+ +
var img = new Image();   // Create new img element
+img.addEventListener("load", function() {
+  // execute drawImage statements here
+}, false);
+img.src = 'myImage.png'; // Set source path
+
+ +

若是只要載入一份影像,可以用上面的方法,不過當需要載入、追蹤多個影像時,我們就需要更好的方法了,雖然管理多個影像載入已經超出本教學的範疇,然而如果有興趣的話,可以參考JavaScript Image Preloader這份文件.

+ +

以data:URL嵌入影像

+ +

另一個載入影像的方法是利用data: url,透過data URL可以直接將影像定義成Base64編碼的字串,然後嵌入程式碼之中.

+ +
var img_src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==';
+
+ +

data URL的好處之一是立即產生影像而不用再和伺服器連線,另一個好處是這樣便能夠將影像包入你的CSS, JavaScript, HTML之中,讓影像更具可攜性.

+ +

壞處則是影像將不會被快取起來,而且對大影像來說編碼後的URL會很長.

+ +

Using frames from a video

+ +

我們還能夠使用{{HTMLElement("video")}}元素中的影片的影片畫格(縱使影片為隱藏),例如,現在我們有一個ID為”myvideo” 的{{HTMLElement("video")}}元素:

+ +
function getMyVideo() {
+  var canvas = document.getElementById('canvas');
+  if (canvas.getContext) {
+    var ctx = canvas.getContext('2d');
+
+    return document.getElementById('myvideo');
+  }
+}
+
+ +

上面的方法會回傳一個{{domxref("HTMLVideoElement")}}的影像物件,如前所述,這個物件可以被視為CanvasImageSource類別的物件來使用。
+ 關於如何利用<video>元素於畫布上的進階說明,可以參考html5Doctor的“video + canvas = magic”一文.

+ +

影像繪圖

+ +

一旦我們取得來源影像物件的參照(reference),便可以用drawImage()方法將影像渲染到畫布上,drawImage()方法是一個多載(overload)方法,有數個型態,待會我們會看到這項特性,現在我們先來看drawImage()最基本的型態:

+ +
+
drawImage(image, x, y)
+
從座標點(x, y)開始畫上image參數指定的來源影像(CanvasImageSource).
+
+ +

範例: 一條簡單的線段影像

+ +

這個範例會使用外部影像作為一個小型線圖的背景。利用預先劃好的圖作為背景的話就不用再靠程式來產生背景,如此一來可以顯著地減少程式碼。下面藉由影像物件的load事件處理器來處理繪圖作業,其中drawImage()方法把背景圖片放置在畫布左上角,座標點(0, 0)位置.

+ + + +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  var img = new Image();
+  img.onload = function(){
+    ctx.drawImage(img,0,0);
+    ctx.beginPath();
+    ctx.moveTo(30,96);
+    ctx.lineTo(70,66);
+    ctx.lineTo(103,76);
+    ctx.lineTo(170,15);
+    ctx.stroke();
+  };
+  img.src = 'https://mdn.mozillademos.org/files/5395/backdrop.png';
+}
+ +

結果如下:

+ +

{{EmbedLiveSample("Example.3A_A_simple_line_graph", 220, 160, "https://mdn.mozillademos.org/files/206/Canvas_backdrop.png")}}

+ +

縮放

+ +

drawImage()的第二個型態增加了兩個新參數,讓我們在畫布上放置影像的同時並縮放影像.

+ +
+
drawImage(image, x, y, width, height)
+
當放置影像於畫布上時,會按照參數width(寬)、height(高)來縮放影像.
+
+ +

範例: 排列影像

+ +

本例我們會取一張影像作為桌布,然後透過簡單的迴圈來重複縮放、貼上影像於畫布上。在程式碼中,第一個迴圈走一遍每一列,第二個迴圈走一遍每一行,影像則縮小成原始影像的三分之一,50 x 38像素.

+ +
+

Note: 過度縮放影像可能會造成影像模糊或產生顆粒感,所以如果影像中有文字需要閱讀,最好不要縮放影像.

+
+ + + +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  var img = new Image();
+  img.onload = function(){
+    for (var i=0;i<4;i++){
+      for (var j=0;j<3;j++){
+        ctx.drawImage(img,j*50,i*38,50,38);
+      }
+    }
+  };
+  img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
+}
+ +

結果如下:

+ +

{{EmbedLiveSample("Example.3A_Tiling_an_image", 160, 160, "https://mdn.mozillademos.org/files/251/Canvas_scale_image.png")}}

+ +

切割影像

+ +

drawImage()第三個型態接受9個參數,其中8個讓我們從原始影像中切出一部分影像、縮放並畫到畫布上.

+ +
+
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
+
image參數是來源影像物件,(sx, sy)代表在來源影像中以(sx, sy)座標點作為切割的起始點,sWidth和sHeight代表切割寬和高,(dx, dy)代表放到畫布上的座標點,dWidth和dHeight代表縮放影像至指定的寬和高.
+
+ +

請參照右圖,前四個參數定義了在來源影像上切割的起始點和切割大小,後四個參數定義了畫到畫布上的位置和影像大小.

+ +

切割是一個很有用的工具,我們可以把所有影像放到一張影像上,然後利用切割來組成最終完整的影像,比如說,我們可以把所有需要用來組成一張圖表的文字放到一張PNG圖檔內,之後只需要單純地再依據資料來縮放圖表,另外,我們也不用多次載入多張影像,這樣對提升載入影像效能頗有幫助.

+ +

 

+ +

 

+ +

範例: 畫一個有畫框的影像

+ +

本例用和前一個範例一樣的犀牛圖,然後切出犀牛頭部影像部分再放入一個影像畫框,這個影像畫框是一個有陰影的24位元PNG圖檔,因為24位元PNG影像具備完整的8位元不透明色版(alpha channel),所以不像GIF影像和8位元PNG影像,它能夠放任何背景之上而無須擔心產生消光色(matte color).

+ +
<html>
+ <body onload="draw();">
+   <canvas id="canvas" width="150" height="150"></canvas>
+   <div style="display:none;">
+     <img id="source" src="https://mdn.mozillademos.org/files/5397/rhino.jpg" width="300" height="227">
+     <img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150">
+   </div>
+ </body>
+</html>
+
+ +
function draw() {
+  var canvas = document.getElementById('canvas');
+  var ctx = canvas.getContext('2d');
+
+  // Draw slice
+  ctx.drawImage(document.getElementById('source'),
+                33, 71, 104, 124, 21, 20, 87, 104);
+
+  // Draw frame
+  ctx.drawImage(document.getElementById('frame'),0,0);
+}
+ +

這次我們不產生新的{{domxref("HTMLImageElement")}}物件,改採用直接把影像包入HTML的{{HTMLElement("img")}}標籤,然後再取得影像元素,其中HTML上的影像已經透過設定CSS屬性{{cssxref("display")}}為none來隱藏起來了.

+ +

{{EmbedLiveSample("Example.3A_Framing_an_image", 160, 160, "https://mdn.mozillademos.org/files/226/Canvas_drawimage2.jpg")}}

+ +

程式碼相當簡單,每個{{HTMLElement("img")}}有自己的ID屬性,這樣便可以利用{{domxref("document.getElementById()")}}輕易取得,之後再簡單地用drawImage()方法切割犀牛影像然後縮放並放到畫布上,最後第二個drawImage()再把畫框放到上面.

+ +

畫廊範例

+ +

在本章的最後一個範例,我們將建造一個小畫廊。當網頁載入完成時,我們會為每一張影像產生一個{{HTMLElement("canvas")}}元素,並且加上畫框.

+ +

本範例中,每一張影像的寬高是固定的,畫框也是一樣,你可以嘗試看看改進程式碼,依據影像的寬高來設定畫框,使畫框能剛剛好框住影像.

+ +

從下方的程式碼範例可以很清楚看到,我們為{{domxref("document.images")}}容器內的影像,一張一張地新建畫布,其中,對於不熟悉文件物件模型 (DOM)的人來說,大慨比較值得注意之處在於使用到{{domxref("Node.insertBefore")}} 方法;insertBefore()是影像元素的父節點(亦即<td>元素)的一個方法,這個方法會把新畫布元素插入於影像元素之前.

+ +
<html>
+ <body onload="draw();">
+     <table>
+      <tr>
+        <td><img src="https://mdn.mozillademos.org/files/5399/gallery_1.jpg"></td>
+        <td><img src="https://mdn.mozillademos.org/files/5401/gallery_2.jpg"></td>
+        <td><img src="https://mdn.mozillademos.org/files/5403/gallery_3.jpg"></td>
+        <td><img src="https://mdn.mozillademos.org/files/5405/gallery_4.jpg"></td>
+      </tr>
+      <tr>
+        <td><img src="https://mdn.mozillademos.org/files/5407/gallery_5.jpg"></td>
+        <td><img src="https://mdn.mozillademos.org/files/5409/gallery_6.jpg"></td>
+        <td><img src="https://mdn.mozillademos.org/files/5411/gallery_7.jpg"></td>
+        <td><img src="https://mdn.mozillademos.org/files/5413/gallery_8.jpg"></td>
+      </tr>
+     </table>
+     <img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150">
+ </body>
+</html>
+
+ +

這些是一些設定樣式的CSS:

+ +
body {
+  background: 0 -100px repeat-x url(https://mdn.mozillademos.org/files/5415/bg_gallery.png) #4F191A;
+  margin: 10px;
+}
+
+img {
+  display: none;
+}
+
+table {
+  margin: 0 auto;
+}
+
+td {
+  padding: 15px;
+}
+
+ +

綜合起來這就是建造出我們小畫廊的程式碼:

+ +
function draw() {
+
+  // Loop through all images
+  for (var i=0;i<document.images.length;i++){
+
+    // Don't add a canvas for the frame image
+    if (document.images[i].getAttribute('id')!='frame'){
+
+      // Create canvas element
+      canvas = document.createElement('canvas');
+      canvas.setAttribute('width',132);
+      canvas.setAttribute('height',150);
+
+      // Insert before the image
+      document.images[i].parentNode.insertBefore(canvas,document.images[i]);
+
+      ctx = canvas.getContext('2d');
+
+      // Draw image to canvas
+      ctx.drawImage(document.images[i],15,20);
+
+      // Add frame
+      ctx.drawImage(document.getElementById('frame'),0,0);
+    }
+  }
+}
+ +

{{EmbedLiveSample("Art_gallery_example", 725, 400, "https://mdn.mozillademos.org/files/205/Canvas_art_gallery.jpg")}}

+ +

控制影像縮放行為

+ +

如前所述,縮放影像會導致影像模糊化或是顆粒化,你可以嘗試透過繪圖環境的imageSmoothingEnabled屬性來控制影像平滑演算法的使用,預設上這個屬性的值為true,也就是說當縮放時,影像會經過平滑處理。如果要關掉這個功能,你可以這麼做:

+ +
ctx.mozImageSmoothingEnabled = false;
+
+ +

{{PreviousNext("Web/Guide/HTML/Canvas_tutorial/Drawing_shapes", "Web/Guide/HTML/Canvas_tutorial/Applying_styles_and_colors")}}

diff --git a/files/zh-tw/web/api/canvasrenderingcontext2d/clearrect/index.html b/files/zh-tw/web/api/canvasrenderingcontext2d/clearrect/index.html new file mode 100644 index 0000000000..e5792ffade --- /dev/null +++ b/files/zh-tw/web/api/canvasrenderingcontext2d/clearrect/index.html @@ -0,0 +1,189 @@ +--- +title: CanvasRenderingContext2D.clearRect() +slug: Web/API/CanvasRenderingContext2D/clearRect +translation_of: Web/API/CanvasRenderingContext2D/clearRect +--- +
{{APIRef}}
+ +

Canvas 2D API 的 CanvasRenderingContext2D.clearRect() 方法可以設定指定矩形(經由坐標 (x, y) 及大小 (width, height))範圍內的所有像素為透明,清除所有先前繪製的內容。

+ +

語法

+ +
void ctx.clearRect(x, y, width, height);
+
+ +

參數

+ +
+
x
+
The x axis of the coordinate for the rectangle starting point.
+
y
+
The y axis of the coordinate for the rectangle starting point.
+
width
+
The rectangle's width.
+
height
+
The rectangle's height.
+
+ +

Usage notes

+ +

A common problem with clearRect is that it may appear it does not work when not using paths properly. Don't forget to call {{domxref("CanvasRenderingContext2D.beginPath", "beginPath()")}} before starting to draw the new frame after calling clearRect.

+ +

範例

+ +

Using the clearRect method

+ +

This is just a simple code snippet which uses the clearRect method.

+ +

HTML

+ +
<canvas id="canvas"></canvas>
+
+ +

JavaScript

+ +
var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.beginPath();
+ctx.moveTo(20, 20);
+ctx.lineTo(200, 20);
+ctx.lineTo(120, 120);
+ctx.closePath(); // draws last line of the triangle
+ctx.stroke();
+
+ctx.clearRect(10, 10, 100, 100);
+
+// clear the whole canvas
+// ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ +

Edit the code below and see your changes update live in the canvas:

+ +
+
Playable code
+ +
<canvas id="canvas" width="400" height="200" class="playable-canvas"></canvas>
+<div class="playable-buttons">
+  <input id="edit" type="button" value="Edit" />
+  <input id="reset" type="button" value="Reset" />
+</div>
+<textarea id="code" class="playable-code" style="height:140px;">
+ctx.beginPath();
+ctx.moveTo(20,20);
+ctx.lineTo(200,20);
+ctx.lineTo(120,120);
+ctx.closePath(); // draws last line of the triangle
+ctx.stroke();
+
+ctx.clearRect(10, 10, 100, 100);</textarea>
+
+ +
var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+var textarea = document.getElementById("code");
+var reset = document.getElementById("reset");
+var edit = document.getElementById("edit");
+var code = textarea.value;
+
+function drawCanvas() {
+  ctx.clearRect(0, 0, canvas.width, canvas.height);
+  eval(textarea.value);
+}
+
+reset.addEventListener("click", function() {
+  textarea.value = code;
+  drawCanvas();
+});
+
+edit.addEventListener("click", function() {
+  textarea.focus();
+})
+
+textarea.addEventListener("input", drawCanvas);
+window.addEventListener("load", drawCanvas);
+
+
+ +

{{ EmbedLiveSample('Playable_code', 700, 400) }}

+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', "scripting.html#dom-context-2d-clearrect", "CanvasRenderingContext2D.clearRect")}}{{Spec2('HTML WHATWG')}} 
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/canvasrenderingcontext2d/index.html b/files/zh-tw/web/api/canvasrenderingcontext2d/index.html new file mode 100644 index 0000000000..31aa34ecdf --- /dev/null +++ b/files/zh-tw/web/api/canvasrenderingcontext2d/index.html @@ -0,0 +1,459 @@ +--- +title: CanvasRenderingContext2D +slug: Web/API/CanvasRenderingContext2D +translation_of: Web/API/CanvasRenderingContext2D +--- +
{{APIRef}}
+ +
CanvasRenderingContext2D 介面被使用於繪製矩形、文字、影像以及其它基於 canvas 元素的物件。此介面提供了繪製 {{ HTMLElement("canvas") }} 元素外觀的 2D 渲染環境。
+ +
 
+ +

要取得此實作此介面的實體物件,可以於一個 <canvas> 元素上以 "2d" 為參數呼叫 {{domxref("HTMLCanvasElement.getContext()", "getContext()")}} 方法:

+ +
var canvas = document.getElementById('mycanvas'); // in your HTML this element appears as <canvas id="mycanvas"></canvas>
+var ctx = canvas.getContext('2d');
+
+ +

只要你有了 canvas 的 2D 繪製背景物件,你就可以在其中繪圖。 舉個例子:

+ +
ctx.fillStyle = "rgb(200,0,0)"; // sets the color to fill in the rectangle with
+ctx.fillRect(10, 10, 55, 50);   // draws the rectangle at position 10, 10 with a width of 55 and a height of 50
+
+ +

canvas 教學有更多資訊、範例,以及資源。

+ +

繪製矩形

+ +

有三個函式可以馬上在點陣圖上畫出長方形。

+ +
+
{{domxref("CanvasRenderingContext2D.clearRect()")}}
+
Sets all pixels in the rectangle defined by starting point (x, y) and size (width, height) to transparent black, erasing any previously drawn content.
+
{{domxref("CanvasRenderingContext2D.fillRect()")}}
+
Draws a filled rectangle at (x, y) position whose size is determined by width and height.
+
{{domxref("CanvasRenderingContext2D.strokeRect()")}}
+
Paints a rectangle which has a starting point at (x, y) and has a w width and an h height onto the canvas, using the current stroke style.
+
+ +

繪製文字

+ +

The following methods are provided for drawing text. See also the {{domxref("TextMetrics")}} object for text properties.

+ +
+
{{domxref("CanvasRenderingContext2D.fillText()")}}
+
Draws (fills) a given text at the given (x,y) position.
+
{{domxref("CanvasRenderingContext2D.strokeText()")}}
+
Draws (strokes) a given text at the given (x, y) position.
+
{{domxref("CanvasRenderingContext2D.measureText()")}}
+
Returns a {{domxref("TextMetrics")}} object.
+
+ +

線條樣式

+ +

The following methods and properties control how lines are drawn.

+ +
+
{{domxref("CanvasRenderingContext2D.lineWidth")}}
+
Width of lines. Default 1.0
+
{{domxref("CanvasRenderingContext2D.lineCap")}}
+
Type of endings on the end of lines. Possible values: butt (default), round, square.
+
{{domxref("CanvasRenderingContext2D.lineJoin")}}
+
Defines the type of corners where two lines meet. Possible values: round, bevel, miter (default).
+
{{domxref("CanvasRenderingContext2D.miterLimit")}}
+
Miter limit ratio. Default 10.
+
{{domxref("CanvasRenderingContext2D.getLineDash()")}}
+
Returns the current line dash pattern array containing an even number of non-negative numbers.
+
{{domxref("CanvasRenderingContext2D.setLineDash()")}}
+
Sets the current line dash pattern.
+
{{domxref("CanvasRenderingContext2D.lineDashOffset")}}
+
Specifies where to start a dash array on a line.
+
+ +

文字樣式

+ +

The following properties control how text is laid out.

+ +
+
{{domxref("CanvasRenderingContext2D.font")}}
+
Font setting. Default value 10px sans-serif.
+
{{domxref("CanvasRenderingContext2D.textAlign")}}
+
Text alignment setting. Possible values: start (default), end, left, right or center.
+
{{domxref("CanvasRenderingContext2D.textBaseline")}}
+
Baseline alignment setting. Possible values: top, hanging, middle, alphabetic (default), ideographic, bottom.
+
{{domxref("CanvasRenderingContext2D.direction")}}
+
Directionality. Possible values: ltr, rtl, inherit (default).
+
+ +

填充及邊線樣式

+ +

Fill styling is used for colors and styles inside shapes and stroke styling is used for the lines around shapes.

+ +
+
{{domxref("CanvasRenderingContext2D.fillStyle")}}
+
Color or style to use inside shapes. Default #000 (black).
+
{{domxref("CanvasRenderingContext2D.strokeStyle")}}
+
Color or style to use for the lines around shapes. Default #000 (black).
+
+ +

漸層填色及圖案填充

+ +
+
{{domxref("CanvasRenderingContext2D.createLinearGradient()")}}
+
Creates a linear gradient along the line given by the coordinates represented by the parameters.
+
{{domxref("CanvasRenderingContext2D.createRadialGradient()")}}
+
Creates a radial gradient given by the coordinates of the two circles represented by the parameters.
+
{{domxref("CanvasRenderingContext2D.createPattern()")}}
+
Creates a pattern using the specified image (a {{domxref("CanvasImageSource")}}). It repeats the source in the directions specified by the repetition argument. This method returns a {{domxref("CanvasPattern")}}.
+
+ +

陰影

+ +
+
{{domxref("CanvasRenderingContext2D.shadowBlur")}}
+
Specifies the blurring effect. Default 0
+
{{domxref("CanvasRenderingContext2D.shadowColor")}}
+
Color of the shadow. Default fully-transparent black.
+
{{domxref("CanvasRenderingContext2D.shadowOffsetX")}}
+
Horizontal distance the shadow will be offset. Default 0.
+
{{domxref("CanvasRenderingContext2D.shadowOffsetY")}}
+
Vertical distance the shadow will be offset. Default 0.
+
+ +

路徑

+ +

The following methods can be used to manipulate paths of objects.

+ +
+
{{domxref("CanvasRenderingContext2D.beginPath()")}}
+
Starts a new path by emptying the list of sub-paths. Call this method when you want to create a new path.
+
{{domxref("CanvasRenderingContext2D.closePath()")}}
+
Causes the point of the pen to move back to the start of the current sub-path. It tries to draw a straight line from the current point to the start. If the shape has already been closed or has only one point, this function does nothing.
+
{{domxref("CanvasRenderingContext2D.moveTo()")}}
+
Moves the starting point of a new sub-path to the (x, y) coordinates.
+
{{domxref("CanvasRenderingContext2D.lineTo()")}}
+
Connects the last point in the subpath to the x, y coordinates with a straight line.
+
{{domxref("CanvasRenderingContext2D.bezierCurveTo()")}}
+
Adds a cubic Bézier curve to the path. It requires three points. The first two points are control points and the third one is the end point. The starting point is the last point in the current path, which can be changed using moveTo() before creating the Bézier curve.
+
{{domxref("CanvasRenderingContext2D.quadraticCurveTo()")}}
+
Adds a quadratic Bézier curve to the current path.
+
{{domxref("CanvasRenderingContext2D.arc()")}}
+
Adds an arc to the path which is centered at (x, y) position with radius r starting at startAngle and ending at endAngle going in the given direction by anticlockwise (defaulting to clockwise).
+
{{domxref("CanvasRenderingContext2D.arcTo()")}}
+
Adds an arc to the path with the given control points and radius, connected to the previous point by a straight line.
+
{{domxref("CanvasRenderingContext2D.ellipse()")}} {{experimental_inline}}
+
Adds an ellipse to the path which is centered at (x, y) position with the radii radiusX and radiusY starting at startAngle and ending at endAngle going in the given direction by anticlockwise (defaulting to clockwise).
+
{{domxref("CanvasRenderingContext2D.rect()")}}
+
Creates a path for a rectangle at position (x, y) with a size that is determined by width and height.
+
+ +

繪製路徑

+ +
+
{{domxref("CanvasRenderingContext2D.fill()")}}
+
Fills the subpaths with the current fill style.
+
{{domxref("CanvasRenderingContext2D.stroke()")}}
+
Strokes the subpaths with the current stroke style.
+
{{domxref("CanvasRenderingContext2D.drawFocusIfNeeded()")}}
+
If a given element is focused, this method draws a focus ring around the current path.
+
{{domxref("CanvasRenderingContext2D.scrollPathIntoView()")}}
+
Scrolls the current path or a given path into the view.
+
{{domxref("CanvasRenderingContext2D.clip()")}}
+
Creates a clipping path from the current sub-paths. Everything drawn after clip() is called appears inside the clipping path only. For an example, see Clipping paths in the Canvas tutorial.
+
{{domxref("CanvasRenderingContext2D.isPointInPath()")}}
+
Reports whether or not the specified point is contained in the current path.
+
{{domxref("CanvasRenderingContext2D.isPointInStroke()")}}
+
Reports whether or not the specified point is inside the area contained by the stroking of a path.
+
+ +

變形

+ +

Objects in the CanvasRenderingContext2D rendering context have a current transformation matrix and methods to manipulate it. The transformation matrix is applied when creating the current default path, painting text, shapes and {{domxref("Path2D")}} objects. The methods listed below remain for historical and compatibility reasons as {{domxref("SVGMatrix")}} objects are used in most parts of the API nowadays and will be used in the future instead.

+ +
+
{{domxref("CanvasRenderingContext2D.currentTransform")}}
+
Current transformation matrix ({{domxref("SVGMatrix")}} object).
+
{{domxref("CanvasRenderingContext2D.rotate()")}}
+
Adds a rotation to the transformation matrix. The angle argument represents a clockwise rotation angle and is expressed in radians.
+
{{domxref("CanvasRenderingContext2D.scale()")}}
+
Adds a scaling transformation to the canvas units by x horizontally and by y vertically.
+
{{domxref("CanvasRenderingContext2D.translate()")}}
+
Adds a translation transformation by moving the canvas and its origin x horzontally and y vertically on the grid.
+
{{domxref("CanvasRenderingContext2D.transform()")}}
+
Multiplies the current transformation matrix with the matrix described by its arguments.
+
{{domxref("CanvasRenderingContext2D.setTransform()")}}
+
Resets the current transform to the identity matrix, and then invokes the transform() method with the same arguments.
+
{{domxref("CanvasRenderingContext2D.resetTransform()")}} {{experimental_inline}}
+
Resets the current transform by the identity matrix.
+
+ +

合成

+ +
+
{{domxref("CanvasRenderingContext2D.globalAlpha")}}
+
Alpha value that is applied to shapes and images before they are composited onto the canvas. Default 1.0 (opaque).
+
{{domxref("CanvasRenderingContext2D.globalCompositeOperation")}}
+
With globalAlpha applied this sets how shapes and images are drawn onto the existing bitmap.
+
+ +

繪製圖形

+ +
+
{{domxref("CanvasRenderingContext2D.drawImage()")}}
+
Draws the specified image. This method is available in multiple formats, providing a great deal of flexibility in its use.
+
+ +

像素控制

+ +

See also the {{domxref("ImageData")}} object.

+ +
+
{{domxref("CanvasRenderingContext2D.createImageData()")}}
+
Creates a new, blank {{domxref("ImageData")}} object with the specified dimensions. All of the pixels in the new object are transparent black.
+
{{domxref("CanvasRenderingContext2D.getImageData()")}}
+
Returns an {{domxref("ImageData")}} object representing the underlying pixel data for the area of the canvas denoted by the rectangle which starts at (sx, sy) and has an sw width and sh height.
+
{{domxref("CanvasRenderingContext2D.putImageData()")}}
+
Paints data from the given {{domxref("ImageData")}} object onto the bitmap. If a dirty rectangle is provided, only the pixels from that rectangle are painted.
+
+ +

圖像平滑

+ +
+
{{domxref("CanvasRenderingContext2D.imageSmoothingEnabled")}} {{experimental_inline}}
+
Image smoothing mode; if disabled, images will not be smoothed if scaled.
+
+ +

canvas 狀態

+ +

The CanvasRenderingContext2D rendering context contains a variety of drawing style states (attributes for line styles, fill styles, shadow styles, text styles). The following methods help you to work with that state:

+ +
+
{{domxref("CanvasRenderingContext2D.save()")}}
+
Saves the current drawing style state using a stack so you can revert any change you make to it using restore().
+
{{domxref("CanvasRenderingContext2D.restore()")}}
+
Restores the drawing style state to the last element on the 'state stack' saved by save().
+
{{domxref("CanvasRenderingContext2D.canvas")}}
+
A read-only back-reference to the {{domxref("HTMLCanvasElement")}}. Might be {{jsxref("null")}} if it is not associated with a {{HTMLElement("canvas")}} element.
+
+ +

點擊區域

+ +
+
{{domxref("CanvasRenderingContext2D.addHitRegion()")}} {{experimental_inline}}
+
Adds a hit region to the canvas.
+
{{domxref("CanvasRenderingContext2D.removeHitRegion()")}} {{experimental_inline}}
+
Removes the hit region with the specified id from the canvas.
+
{{domxref("CanvasRenderingContext2D.clearHitRegions()")}} {{experimental_inline}}
+
Removes all hit regions from the canvas.
+
+ +

非標準 API

+ + + +

Most of these APIs are deprecated and will be removed in the future.

+ +
+
{{non-standard_inline}} CanvasRenderingContext2D.clearShadow()
+
Removes all shadow settings like {{domxref("CanvasRenderingContext2D.shadowColor")}} and {{domxref("CanvasRenderingContext2D.shadowBlur")}}.
+
{{non-standard_inline}} CanvasRenderingContext2D.drawImageFromRect()
+
This is redundant with an equivalent overload of drawImage.
+
{{non-standard_inline}} CanvasRenderingContext2D.setAlpha()
+
Use {{domxref("CanvasRenderingContext2D.globalAlpha")}} instead.
+
{{non-standard_inline}} CanvasRenderingContext2D.setCompositeOperation()
+
Use {{domxref("CanvasRenderingContext2D.globalCompositeOperation")}} instead.
+
{{non-standard_inline}} CanvasRenderingContext2D.setLineWidth()
+
Use {{domxref("CanvasRenderingContext2D.lineWidth")}} instead.
+
{{non-standard_inline}} CanvasRenderingContext2D.setLineJoin()
+
Use {{domxref("CanvasRenderingContext2D.lineJoin")}} instead.
+
{{non-standard_inline}} CanvasRenderingContext2D.setLineCap()
+
Use {{domxref("CanvasRenderingContext2D.lineCap")}} instead.
+
{{non-standard_inline}} CanvasRenderingContext2D.setMiterLimit()
+
Use {{domxref("CanvasRenderingContext2D.miterLimit")}} instead.
+
{{non-standard_inline}} CanvasRenderingContext2D.setStrokeColor()
+
Use {{domxref("CanvasRenderingContext2D.strokeStyle")}} instead.
+
{{non-standard_inline}} CanvasRenderingContext2D.setFillColor()
+
Use {{domxref("CanvasRenderingContext2D.fillStyle")}} instead.
+
{{non-standard_inline}} CanvasRenderingContext2D.setShadow()
+
Use {{domxref("CanvasRenderingContext2D.shadowColor")}} and {{domxref("CanvasRenderingContext2D.shadowBlur")}} instead.
+
{{non-standard_inline}} CanvasRenderingContext2D.webkitLineDash
+
Use {{domxref("CanvasRenderingContext2D.getLineDash()")}} and {{domxref("CanvasRenderingContext2D.setLineDash()")}} instead.
+
{{non-standard_inline}} CanvasRenderingContext2D.webkitLineDashOffset
+
Use {{domxref("CanvasRenderingContext2D.lineDashOffset")}} instead.
+
{{non-standard_inline}} CanvasRenderingContext2D.webkitImageSmoothingEnabled
+
Use {{domxref("CanvasRenderingContext2D.imageSmoothingEnabled")}} instead.
+
+ + + +
+
{{non-standard_inline}} CanvasRenderingContext2D.getContextAttributes()
+
Inspired by the same WebGLRenderingContext method it returns an Canvas2DContextAttributes object that contains the attributes "storage" to indicate which storage is used ("persistent" by default) and the attribute "alpha" (true by default) to indicate that transparency is used in the canvas.
+
{{non-standard_inline}} CanvasRenderingContext2D.isContextLost()
+
Inspired by the same WebGLRenderingContext method it returns true if the Canvas context has been lost, or false if not.
+
+ +

WebKit 引擎專屬

+ +
+
{{non-standard_inline}} CanvasRenderingContext2D.webkitBackingStorePixelRatio
+
The backing store size in relation to the canvas element. See High DPI Canvas.
+
{{non-standard_inline}} CanvasRenderingContext2D.webkitGetImageDataHD
+
Intended for HD backing stores, but removed from canvas specifications.
+
{{non-standard_inline}} CanvasRenderingContext2D.webkitPutImageDataHD
+
Intended for HD backing stores, but removed from canvas specifications.
+
+ +
+
+ +

Gecko 引擎專屬

+ +
+
{{non-standard_inline}} {{domxref("CanvasRenderingContext2D.filter")}}
+
CSS and SVG filters as Canvas APIs. Likely to be standardized in a new version of the specification.
+
+ +

Prefixed APIs

+ +
+
{{non-standard_inline}} CanvasRenderingContext2D.mozCurrentTransform
+
Sets or gets the current transformation matrix, see {{domxref("CanvasRenderingContext2D.currentTransform")}}.  {{ gecko_minversion_inline("7.0") }}
+
{{non-standard_inline}} CanvasRenderingContext2D.mozCurrentTransformInverse
+
Sets or gets the current inversed transformation matrix.  {{ gecko_minversion_inline("7.0") }}
+
{{non-standard_inline}} CanvasRenderingContext2D.mozImageSmoothingEnabled
+
See {{domxref("CanvasRenderingContext2D.imageSmoothingEnabled")}}.
+
{{non-standard_inline}} {{deprecated_inline}} CanvasRenderingContext2D.mozDash
+
An array which specifies the lengths of alternating dashes and gaps {{ gecko_minversion_inline("7.0") }}. Use {{domxref("CanvasRenderingContext2D.getLineDash()")}} and {{domxref("CanvasRenderingContext2D.setLineDash()")}} instead.
+
{{non-standard_inline}} {{deprecated_inline}} CanvasRenderingContext2D.mozDashOffset
+
Specifies where to start a dash array on a line. {{ gecko_minversion_inline("7.0") }}. Use {{domxref("CanvasRenderingContext2D.lineDashOffset")}} instead.
+
{{non-standard_inline}} {{deprecated_inline}} CanvasRenderingContext2D.mozTextStyle
+
Introduced in in Gecko 1.9, deprecated in favor of the {{domxref("CanvasRenderingContext2D.font")}} property.
+
{{non-standard_inline}} {{obsolete_inline}} CanvasRenderingContext2D.mozDrawText()
+
This method was introduced in Gecko 1.9 and is removed starting with Gecko 7.0. Use {{domxref("CanvasRenderingContext2D.strokeText()")}} or {{domxref("CanvasRenderingContext2D.fillText()")}} instead.
+
{{non-standard_inline}} {{obsolete_inline}} CanvasRenderingContext2D.mozMeasureText()
+
This method was introduced in Gecko 1.9 and is unimplemented starting with Gecko 7.0. Use {{domxref("CanvasRenderingContext2D.measureText()")}} instead.
+
{{non-standard_inline}} {{obsolete_inline}} CanvasRenderingContext2D.mozPathText()
+
This method was introduced in Gecko 1.9 and is removed starting with Gecko 7.0.
+
{{non-standard_inline}} {{obsolete_inline}} CanvasRenderingContext2D.mozTextAlongPath()
+
This method was introduced in Gecko 1.9 and is removed starting with Gecko 7.0.
+
+ +

Internal APIs (chrome-context only)

+ +
+
{{non-standard_inline}} {{domxref("CanvasRenderingContext2D.asyncDrawXULElement()")}}
+
Renders a region of a XUL element into the canvas.
+
{{non-standard_inline}} {{domxref("CanvasRenderingContext2D.drawWindow()")}}
+
Renders a region of a window into the canvas. The contents of the window's viewport are rendered, ignoring viewport clipping and scrolling.
+
{{non-standard_inline}} CanvasRenderingContext2D.demote()
+
This causes a context that is currently using a hardware-accelerated backend to fallback to a software one. All state should be preserved.
+
+ +

Internet Explorer

+ +
+
{{non-standard_inline}} CanvasRenderingContext2D.msFillRule
+
The fill rule to use. This must be one of evenodd or nonzero (default).
+
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', "scripting.html#2dcontext:canvasrenderingcontext2d", "CanvasRenderingContext2D")}}{{Spec2('HTML WHATWG')}} 
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatChrome("1")}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.8")}}{{CompatIE("9")}}{{CompatOpera("9")}}{{CompatSafari("2")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

相容性註記

+ + + +

參見

+ + + +
+ + +
 
+ +
 
+
+ +
+ + +
 
+ +
 
+
diff --git a/files/zh-tw/web/api/channel_messaging_api/index.html b/files/zh-tw/web/api/channel_messaging_api/index.html new file mode 100644 index 0000000000..1cf9d98692 --- /dev/null +++ b/files/zh-tw/web/api/channel_messaging_api/index.html @@ -0,0 +1,158 @@ +--- +title: Channel Messaging API +slug: Web/API/Channel_Messaging_API +translation_of: Web/API/Channel_Messaging_API +--- +

Channel Messaging API 讓同屬一份文件不同瀏覽環境的兩份程式腳本 (如兩個 IFrame、或主頁面和 IFrame、文件和 {{domxref("SharedWorker")}}、或兩個 worker),也能夠經由雙向 channel (通道) 兩端的 port (連接阜) 直接傳遞訊息互相溝通。

+ +

{{AvailableInWorkers}}

+ +

Channel 訊息概念與使用情境

+ +

{{domxref("MessageChannel.MessageChannel", "MessageChannel()")}} 建構子產生 channel, 一但生成了,便可以存取 channel 兩端的 port: {{domxref("MessageChannel.port1")}} 和 {{domxref("MessageChannel.port2")}},這兩個屬性會回傳 domxref("MessagePort")}} objects.)。建立 channel 的 app 使用 port1,另一端用 port2,利用 {{domxref("window.postMessage")}} 方法帶入參數,向 port2 傳送訊息以及移轉物件 (這裡也就是只 port)。

+ +

一但可移轉物件被移轉後,前任擁有者便失去所有權,例如當 port 移轉出去後,原本持有該 port 的環境便不能再使用之。目前可移轉物件只有 {{domxref("ArrayBuffer")}} 以及 {{domxref("MessagePort")}}。

+ +

另一端的瀏覽環境則藉由 {{domxref("MessagePort.onmessage")}} 監聽訊息、從訊息事件物件的 data 屬性擷取訊息資料,然後再呼叫 {{domxref("MessagePort.postMessage")}} 回傳訊息。

+ +

如果想關閉訊息 channel,則呼叫 {{domxref("MessagePort.close")}}。

+ +

更多 API 使用細節請見 Using channel messaging

+ +

Channel 訊息介面

+ +
+
{{domxref("MessageChannel")}}
+
生成一個新的 message channel。
+
{{domxref("MessagePort")}}
+
控制 port,用來傳送和監聽訊息。
+
{{domxref("PortCollection")}}
+
MessagePorts 陣列,實驗性質方案;用來同時廣播到多個訊息 port。
+
+ +

範例

+ + + +

標準規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#toc-comms')}}{{Spec2('HTML WHATWG')}}Channel messaging defined in section 9.5. No difference to the the HTML5 Web Messaging spec.
{{SpecName('HTML5 Web Messaging', '#channel-messaging')}}{{Spec2('HTML5 Web Messaging')}}W3C version of the spec.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support4{{CompatGeckoDesktop(41)}}10.010.65
PortCollection{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
Available in workers{{CompatVersionUnknown}}{{CompatGeckoDesktop(41)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome MobileFirefox Mobile (Gecko)Firefox OS (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support4.44{{CompatGeckoMobile(41)}}{{CompatNo}}10.011.55.1
PortCollection{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
Available in workers{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(41)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/api/characterdata/index.html b/files/zh-tw/web/api/characterdata/index.html new file mode 100644 index 0000000000..5e39a14822 --- /dev/null +++ b/files/zh-tw/web/api/characterdata/index.html @@ -0,0 +1,156 @@ +--- +title: CharacterData +slug: Web/API/CharacterData +translation_of: Web/API/CharacterData +--- +

{{APIRef("DOM")}}

+ +

CharacterData 介面表示了含有字元的 {{domxref("Node")}} 物件。CharacterData 為抽象介面,代表不會有型別為 CharacterData 的物件。物件是由其子介面,如 {{domxref("Text")}}、{{domxref("Comment")}} 或 {{domxref("ProcessingInstruction")}} 等非抽象介面來實作。

+ +

{{InheritanceDiagram}}

+ +

屬性

+ +

Inherits properties from its parent, {{domxref("Node")}}, and implements the {{domxref("ChildNode")}} and {{domxref("NonDocumentTypeChildNode")}} interface.

+ +
+
{{domxref("CharacterData.data")}}
+
Is a {{domxref("DOMString")}} representing the textual data contained in this object.
+
{{domxref("CharacterData.length")}} {{readonlyInline}}
+
Returns an unsigned long representing the size of the string contained in CharacterData.data.
+
{{domxref("NonDocumentTypeChildNode.nextElementSibling")}} {{readonlyInline}}
+
Returns the {{domxref("Element")}} immediately following the specified one in its parent's children list, or null if the specified element is the last one in the list.
+
{{domxref("NonDocumentTypeChildNode.previousElementSibling")}} {{readonlyInline}}
+
Returns the {{domxref("Element")}} immediately prior to the specified one in its parent's children list, or null if the specified element is the first one in the list.
+
+ +

方法

+ +

Inherits methods from its parent, {{domxref("Node")}}, and implements the {{domxref("ChildNode")}} and {{domxref("NonDocumentTypeChildNode")}} interface.

+ +
+
{{domxref("CharacterData.appendData()")}}
+
Appends the given {{domxref("DOMString")}} to the CharacterData.data string; when this method returns, data contains the concatenated {{domxref("DOMString")}}.
+
{{domxref("CharacterData.deleteData()")}}
+
Removes the specified amount of characters, starting at the specified offset, from the CharacterData.data string; when this method returns, data contains the shortened {{domxref("DOMString")}}.
+
{{domxref("CharacterData.insertData()")}}
+
Inserts the specified characters, at the specified offset, in the CharacterData.data string; when this method returns, data contains the modified {{domxref("DOMString")}}.
+
{{domxref("ChildNode.remove()")}} {{experimental_inline}}
+
Removes the object from its parent children list.
+
{{domxref("CharacterData.replaceData()")}}
+
Replaces the specified amount of characters, starting at the specified offset, with the specified {{domxref("DOMString")}}; when this method returns, data contains the modified {{domxref("DOMString")}}.
+
{{domxref("CharacterData.substringData()")}}
+
Returns a {{domxref("DOMString")}} containing the part of CharacterData.data of the specified length and starting at the specified offset.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#characterdata', 'CharacterData')}}{{Spec2('DOM WHATWG')}}Added implemention of the {{domxref("ChildNode")}} and {{domxref("NonDocumentTypeChildNode")}} interface.
{{SpecName('DOM3 Core', 'core.html#ID-FF21A306', 'CharacterData')}}{{Spec2('DOM3 Core')}}No change from {{SpecName('DOM2 Core')}}.
{{SpecName('DOM2 Core', 'core.html#ID-FF21A306', 'CharacterData')}}{{Spec2('DOM2 Core')}}No change from {{SpecName('DOM1')}}.
{{SpecName('DOM1', 'level-one-core.html#ID-FF21A306', 'CharacterData')}}{{Spec2('DOM1')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.0")}}6{{CompatVersionUnknown}}{{CompatVersionUnknown}}
Implements {{domxref("ChildNode")}} interface.{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("25.0")}} [1]{{CompatNo}}{{CompatUnknown}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("1.0")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
Implements {{domxref("ChildNode")}} interface.{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("25.0")}} [1]{{CompatNo}}{{CompatUnknown}}{{CompatNo}}
+
+ +

[1] Two properties, nextElementSibling and previousElementSibling, have been moved to the {{domxref("NonDocumentTypeChildNode")}} interface, also implemented by CharacterData.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/childnode/index.html b/files/zh-tw/web/api/childnode/index.html new file mode 100644 index 0000000000..1d7d3f753b --- /dev/null +++ b/files/zh-tw/web/api/childnode/index.html @@ -0,0 +1,182 @@ +--- +title: ChildNode +slug: Web/API/ChildNode +translation_of: Web/API/ChildNode +--- +
{{APIRef("DOM")}}
+ +

childNodes 介面定義了可以擁有父節點之 {{domxref("Node")}} 物件的方法。

+ +

childNodes 是一個原始的介面,且不能以此建立物件實體。{{domxref("Element")}}、{{domxref("DocumentType")}} 及 {{domxref("CharacterData")}} 物件皆實作了 childNodes

+ +

屬性

+ +

沒有繼承或自有的屬性。

+ +

方法

+ +

沒有繼承的方法。

+ +
+
{{domxref("childNodes.remove()")}} {{experimental_inline}}
+
Removes this childNodes from the children list of its parent.
+
{{domxref("childNodes.before()")}} {{experimental_inline}}
+
Inserts a set of {{domxref("Node")}} or {{domxref("DOMString")}} objects in the children list of this childNodes's parent, just before this childNodes. {{domxref("DOMString")}} objects are inserted as equivalent {{domxref("Text")}} nodes.
+
{{domxref("childNodes.after()")}} {{experimental_inline}}
+
Inserts a set of {{domxref("Node")}} or {{domxref("DOMString")}} objects in the children list of this childNodes's parent, just after this childNodes. {{domxref("DOMString")}} objects are inserted as equivalent {{domxref("Text")}} nodes.
+
{{domxref("childNodes.replaceWith()")}} {{experimental_inline}}
+
Replaces this childNodes in the children list of its parent with a set of {{domxref("Node")}} or {{domxref("DOMString")}} objects. {{domxref("DOMString")}} objects are inserted as equivalent {{domxref("Text")}} nodes.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#interface-childnode', 'childNodes')}}{{Spec2('DOM WHATWG')}}Split the ElementTraversal interface in {{domxref("ParentNode")}} and childNodes. previousElementSibling and nextElementSibling are now defined on the latter. The {{domxref("CharacterData")}} and {{domxref("DocumentType")}} implemented the new interfaces. Added the remove(), before(), after() and replaceWith() methods.
{{SpecName('Element Traversal', '#interface-elementTraversal', 'ElementTraversal')}}{{Spec2('Element Traversal')}}Added the initial definition of its properties to the ElementTraversal pure interface and use it on {{domxref("Element")}}.
+ +

Polyfill

+ +

External on github: childNode.js

+ +

瀏覽器相容性

+ +

{{ CompatibilityTable }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support (on {{domxref("Element")}}){{CompatChrome(1.0)}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(23)}}9.010.04.0
Support on {{domxref("DocumentType")}} and {{domxref("CharacterData")}} {{experimental_inline}}{{CompatChrome(23.0)}}{{CompatNo}}{{CompatGeckoDesktop(23)}}{{CompatNo}}16.0{{CompatNo}}
remove(){{experimental_inline}}{{CompatChrome(29.0)}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(23)}}{{CompatNo}}16.0{{CompatNo}}
before(), after(), and replaceWith() {{experimental_inline}}{{CompatChrome(54.0)}}{{CompatNo}}{{CompatGeckoDesktop(49)}}{{CompatNo}}{{CompatOpera(39)}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
Basic support (on {{domxref("Element")}}){{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(23)}}{{CompatVersionUnknown}}10.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
Support on {{domxref("DocumentType")}} and {{domxref("CharacterData")}} {{experimental_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatGeckoMobile(23)}}{{CompatNo}}16.0{{CompatNo}}{{CompatVersionUnknown}}
remove(){{experimental_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(23)}}{{CompatNo}}16.0{{CompatNo}}{{CompatVersionUnknown}}
before(), after(), and replaceWith() {{experimental_inline}}{{CompatNo}}{{CompatChrome(54.0)}}{{CompatNo}}{{CompatGeckoMobile(49)}}{{CompatNo}}{{CompatOperaMobile(39)}}{{CompatNo}}{{CompatChrome(54.0)}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/clients/index.html b/files/zh-tw/web/api/clients/index.html new file mode 100644 index 0000000000..000e36a804 --- /dev/null +++ b/files/zh-tw/web/api/clients/index.html @@ -0,0 +1,113 @@ +--- +title: Clients +slug: Web/API/Clients +translation_of: Web/API/Clients +--- +

{{SeeCompatTable}}{{APIRef("Service Workers API")}}

+ +

The Clients interface of the Service Workers API represents a container for a list of {{domxref("Client")}} objects.

+ +

Methods

+ +
+
{{domxref("Clients.get()")}}
+
Gets a service worker client matching a given id and returns it in a {{jsxref("Promise")}}.
+
{{domxref("Clients.matchAll()")}}
+
Gets a list of service worker clients and returns them in a {{jsxref("Promise")}}. Include the options parameter to return all service worker clients whose origin is the same as the associated service worker's origin. If options are not included, the method returns only the service worker clients controlled by the service worker. 
+
{{domxref("Clients.openWindow()")}}
+
Opens a service worker {{domxref("Client")}} in a new browser window.
+
{{domxref("Clients.claim()")}}
+
Allows an active Service Worker to set itself as the active worker for a client page when the worker and the page are in the same scope. 
+
+ +

Examples

+ +
clients.matchAll(options).then(function(clients) {
+  for(i = 0 ; i < clients.length ; i++) {
+    if(clients[i] === 'index.html') {
+      clients.openWindow(clients[i]);
+      // or do something else involving the matching client
+    }
+  }
+});
+ +

Specifications

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Service Workers', '#clients', 'Clients')}}{{Spec2('Service Workers')}}Initial definition
+ +

Browser compatibility

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome(40.0)}}{{ CompatGeckoDesktop("44.0") }}{{CompatNo}}{{CompatUnknown}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatUnknown}}{{ CompatGeckoMobile("44.0") }}{{ CompatVersionUnknown }}{{CompatNo}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}
+
+ +

See also

+ + diff --git a/files/zh-tw/web/api/clipboardevent/index.html b/files/zh-tw/web/api/clipboardevent/index.html new file mode 100644 index 0000000000..7353cf4978 --- /dev/null +++ b/files/zh-tw/web/api/clipboardevent/index.html @@ -0,0 +1,119 @@ +--- +title: ClipboardEvent +slug: Web/API/ClipboardEvent +translation_of: Web/API/ClipboardEvent +--- +

{{APIRef("Clipboard API")}} {{SeeCompatTable}}

+ +

ClipboardEvent 介面表示了與修改剪貼簿相關的事件,包括 {{event("cut")}}、{{event("copy")}} 及 {{event("paste")}} 事件。

+ +

屬性

+ +

Also inherits properties from its parent {{domxref("Event")}}.

+ +
+
{{domxref("ClipboardEvent.clipboardData")}} {{readonlyInline}}
+
Is a {{domxref("DataTransfer")}} object containing the data affected by the user-initiated {{event("cut")}}, {{event("copy")}}, or {{event("paste")}} operation, along with its MIME type.
+
+ +

建構式

+ +
+
{{domxref("ClipboardEvent.ClipboardEvent", "ClipboardEvent()")}}
+
Creates a ClipboardEvent event with the given parameters.
+
+ +

方法

+ +

No specific methods; inherits methods from its parent {{domxref("Event")}}.

+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('Clipboard API', '#clipboard-event-interfaces', 'ClipboardEvent') }}{{ Spec2('Clipboard API') }}Initial definition.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}4.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
clipboardData{{CompatVersionUnknown}}{{CompatGeckoDesktop("22.0")}}5.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}4.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
clipboardData{{CompatVersionUnknown}}{{CompatGeckoMobile("22.0")}}5.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/console/assert/index.html b/files/zh-tw/web/api/console/assert/index.html new file mode 100644 index 0000000000..415b4cfa9a --- /dev/null +++ b/files/zh-tw/web/api/console/assert/index.html @@ -0,0 +1,118 @@ +--- +title: Console.assert() +slug: Web/API/console/assert +tags: + - API + - DOM + - Debugging + - 函式 + - 控制台 + - 網頁控制台 + - 網頁開發 +translation_of: Web/API/console/assert +--- +
{{APIRef("Console API")}}
+ +

如果斷言(assertion)為非(false),主控台會顯示錯誤訊息;如果斷言為是(true),則不發生任何事。

+ +

{{AvailableInWorkers}}

+ +
+

注意在 Node.js 內 console.assert() 方法的實做,與瀏覽器並不相同。

+ +

瀏覽器內呼叫 falsy 的 console.assert() 斷言出現 message,但不會中斷程式碼的執行。然而在 Node.js 裡面,falsy 斷言會拋出 AssertionError 錯誤。

+
+ +

語法

+ +
console.assert(assertion, obj1 [, obj2, ..., objN]);
+console.assert(assertion, msg [, subst1, ..., substN]); // c-like message formatting
+
+ +

參數

+ +
+
assertion
+
布林表達式。如果斷言為非,訊息會出現在主控台上。
+
obj1 ... objN
+
要印出來的 JavaScript 物件名單。 The string representations of each of these objects are appended together in the order listed and output.
+
msg
+
包含零個以上的 JavaScript 替代(substitution)字串。
+
subst1 ... substN
+
JavaScript objects with which to replace substitution strings within msg. This parameter gives you additional control over the format of the output.
+
+ +

請參見 {{domxref("console")}} 的 Outputting text to the console 以獲取詳細資訊。

+ +

範例

+ +

以下程式碼示範一個 JavaScript 物件的斷言使用:

+ +
const errorMsg = 'the # is not even';
+for (let number = 2; number <= 5; number += 1) {
+    console.log('the # is ' + number);
+    console.assert(number % 2 === 0, {number: number, errorMsg: errorMsg});
+    // or, using ES2015 object property shorthand:
+    // console.assert(number % 2 === 0, {number, errorMsg});
+}
+// output:
+// the # is 2
+// the # is 3
+// Assertion failed: {number: 3, errorMsg: "the # is not even"}
+// the # is 4
+// the # is 5
+// Assertion failed: {number: 5, errorMsg: "the # is not even"}
+
+ +

請注意,雖然包含替換字符串的字符串在 Node 中用作 console.log 的參數,但很多(如果不是大多數)瀏覽器...

+ +
console.log('the word is %s', 'foo');
+// output: the word is foo
+
+ +

...在所有瀏覽器中,使用此類字符串目前無法作為console.assert的參數使用:

+ +
console.assert(false, 'the word is %s', 'foo');
+// correct output in Node (e.g. v8.10.0) and some browsers
+//     (e.g. Firefox v60.0.2):
+// Assertion failed: the word is foo
+// incorrect output in some browsers
+//     (e.g. Chrome v67.0.3396.87):
+// Assertion failed: the word is %s foo
+
+ +

有關詳細信息,請參閱 {{domxref("console")}} 文檔中的將文本輸出到控制台

+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("Console API", "#assert", "console.assert()")}}{{Spec2("Console API")}}初始定義
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Console.assert")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/console/index.html b/files/zh-tw/web/api/console/index.html new file mode 100644 index 0000000000..36320a69a8 --- /dev/null +++ b/files/zh-tw/web/api/console/index.html @@ -0,0 +1,289 @@ +--- +title: Console +slug: Web/API/Console +tags: + - API + - Debugging + - Interface + - NeedsCompatTable + - NeedsTranslation + - Reference + - TopicStub + - console + - web console +translation_of: Web/API/Console +--- +
{{APIRef("Console API")}}
+ +

The Console object provides access to the browser's debugging console (e.g. the Web Console in Firefox). The specifics of how it works varies from browser to browser, but there is a de facto set of features that are typically provided.

+ +

The Console object can be accessed from any global object. {{domxref("Window")}} on browsing scopes and {{domxref("WorkerGlobalScope")}} as specific variants in workers via the property console. It's exposed as {{domxref("Window.console")}}, and can be referenced as simply console. For example:

+ +
console.log("Failed to open the specified link")
+ +

This page documents the {{anch("Methods")}} available on the Console object and gives a few {{anch("Usage")}} examples.

+ +

{{AvailableInWorkers}}

+ +

Methods

+ +
+
{{domxref("Console.assert()")}}
+
Log a message and stack trace to console if the first argument is false.
+
{{domxref("Console.clear()")}}
+
Clear the console.
+
{{domxref("Console.count()")}}
+
Log the number of times this line has been called with the given label.
+
{{domxref("Console.debug()")}}
+
An alias for log(). +
Note: Starting with Chromium 58 this method only appears in Chromium browser consoles when level "Verbose" is selected.
+
+
{{domxref("Console.dir()")}} {{Non-standard_inline}}
+
Displays an interactive listing of the properties of a specified JavaScript object. This listing lets you use disclosure triangles to examine the contents of child objects.
+
{{domxref("Console.dirxml()")}} {{Non-standard_inline}}
+
+

Displays an XML/HTML Element representation of the specified object if possible or the JavaScript Object view if it is not possible.

+
+
{{domxref("Console.error()")}}
+
Outputs an error message. You may use string substitution and additional arguments with this method.
+
{{domxref("Console.exception()")}} {{Non-standard_inline}} {{deprecated_inline}}
+
An alias for error().
+
{{domxref("Console.group()")}}
+
Creates a new inline group, indenting all following output by another level. To move back out a level, call groupEnd().
+
{{domxref("Console.groupCollapsed()")}}
+
Creates a new inline group, indenting all following output by another level. However, unlike group() this starts with the inline group collapsed requiring the use of a disclosure button to expand it. To move back out a level, call groupEnd().
+
{{domxref("Console.groupEnd()")}}
+
Exits the current inline group.
+
{{domxref("Console.info()")}}
+
Informative logging of information. You may use string substitution and additional arguments with this method.
+
{{domxref("Console.log()")}}
+
For general output of logging information. You may use string substitution and additional arguments with this method.
+
{{domxref("Console.profile()")}} {{Non-standard_inline}}
+
Starts the browser's built-in profiler (for example, the Firefox performance tool). You can specify an optional name for the profile.
+
{{domxref("Console.profileEnd()")}} {{Non-standard_inline}}
+
Stops the profiler. You can see the resulting profile in the browser's performance tool (for example, the Firefox performance tool).
+
{{domxref("Console.table()")}}
+
Displays tabular data as a table.
+
{{domxref("Console.time()")}}
+
Starts a timer with a name specified as an input parameter. Up to 10,000 simultaneous timers can run on a given page.
+
{{domxref("Console.timeEnd()")}}
+
Stops the specified timer and logs the elapsed time in seconds since it started.
+
{{domxref("Console.timeStamp()")}} {{Non-standard_inline}}
+
Adds a marker to the browser's Timeline or Waterfall tool.
+
{{domxref("Console.trace()")}}
+
Outputs a stack trace.
+
{{domxref("Console.warn()")}}
+
Outputs a warning message. You may use string substitution and additional arguments with this method.
+
+ +

Usage

+ +

Outputting text to the console

+ +

The most frequently-used feature of the console is logging of text and other data. There are four categories of output you can generate, using the {{domxref("console.log()")}}, {{domxref("console.info()")}}, {{domxref("console.warn()")}}, and {{domxref("console.error()")}} methods respectively. Each of these results in output styled differently in the log, and you can use the filtering controls provided by your browser to only view the kinds of output that interest you.

+ +

There are two ways to use each of the output methods; you can simply pass in a list of objects whose string representations get concatenated into one string, then output to the console, or you can pass in a string containing zero or more substitution strings followed by a list of objects to replace them.

+ +

Outputting a single object

+ +

The simplest way to use the logging methods is to output a single object:

+ +
var someObject = { str: "Some text", id: 5 };
+console.log(someObject);
+
+ +

The output looks something like this:

+ +
[09:27:13.475] ({str:"Some text", id:5})
+ +

Outputting multiple objects

+ +

You can also output multiple objects by simply listing them when calling the logging method, like this:

+ +
var car = "Dodge Charger";
+var someObject = { str: "Some text", id: 5 };
+console.info("My first car was a", car, ". The object is:", someObject);
+ +

This output will look like this:

+ +
[09:28:22.711] My first car was a Dodge Charger . The object is: ({str:"Some text", id:5})
+
+ +

Using string substitutions

+ +

Gecko 9.0 {{geckoRelease("9.0")}} introduced support for string substitutions. When passing a string to one of the console object's methods that accepts a string, you may use these substitution strings:

+ + + + + + + + + + + + + + + + + + + + + + + + +
Substitution stringDescription
%o or %OOutputs a JavaScript object. Clicking the object name opens more information about it in the inspector.
%d or %iOutputs an integer. Number formatting is supported, for example  console.log("Foo %.2d", 1.1) will output the number as two significant figures with a leading 0: Foo 01
%sOutputs a string.
%fOutputs a floating-point value. Formatting is supported, for example  console.log("Foo %.2f", 1.1) will output the number to 2 decimal places: Foo 1.10
+ +
+

Note: Precision formatting doesn't work in Chrome

+
+ +

Each of these pulls the next argument after the format string off the parameter list. For example:

+ +
for (var i=0; i<5; i++) {
+  console.log("Hello, %s. You've called me %d times.", "Bob", i+1);
+}
+
+ +

The output looks like this:

+ +
[13:14:13.481] Hello, Bob. You've called me 1 times.
+[13:14:13.483] Hello, Bob. You've called me 2 times.
+[13:14:13.485] Hello, Bob. You've called me 3 times.
+[13:14:13.487] Hello, Bob. You've called me 4 times.
+[13:14:13.488] Hello, Bob. You've called me 5 times.
+
+ +

Styling console output

+ +

You can use the %c directive to apply a CSS style to console output:

+ +
console.log("This is %cMy stylish message", "color: yellow; font-style: italic; background-color: blue;padding: 2px");
+ +
The text before the directive will not be affected, but the text after the directive will be styled using the CSS declarations in the parameter.
+ +
 
+ +
+ +
 
+ +
+

Note: Quite a few CSS properties are supported by this styling; you should experiment and see which ones prove useful.

+
+ +
 
+ +
{{h3_gecko_minversion("Using groups in the console", "9.0")}}
+ +

You can use nested groups to help organize your output by visually combining related material. To create a new nested block, call console.group(). The console.groupCollapsed() method is similar but creates the new block collapsed, requiring the use of a disclosure button to open it for reading.

+ +
Note: Collapsed groups are not supported yet in Gecko; the groupCollapsed() method is the same as group() at this time.
+ +

To exit the current group, simply call console.groupEnd(). For example, given this code:

+ +
console.log("This is the outer level");
+console.group();
+console.log("Level 2");
+console.group();
+console.log("Level 3");
+console.warn("More of level 3");
+console.groupEnd();
+console.log("Back to level 2");
+console.groupEnd();
+console.debug("Back to the outer level");
+
+ +

The output looks like this:

+ +

nesting.png

+ +
{{h3_gecko_minversion("Timers", "10.0")}}
+ +

In order to calculate the duration of a specific operation, Gecko 10 introduced the support of timers in the console object. To start a timer, call the console.time() method, giving it a name as the only parameter. To stop the timer, and to get the elapsed time in milliseconds, just call the console.timeEnd() method, again passing the timer's name as the parameter. Up to 10,000 timers can run simultaneously on a given page.

+ +

For example, given this code:

+ +
console.time("answer time");
+alert("Click to continue");
+console.timeEnd("answer time");
+
+ +

Will log the time needed by the user to discard the alert box:

+ +

timerresult.png

+ +

Notice that the timer's name is displayed both when the timer is started and when it's stopped.

+ +
Note: It's important to note that if you're using this to log the timing for network traffic, the timer will report the total time for the transaction, while the time listed in the network panel is just the amount of time required for the header. If you have response body logging enabled, the time listed for the response header and body combined should match what you see in the console output.
+ +

Stack traces

+ +

The console object also supports outputting a stack trace; this will show you the call path taken to reach the point at which you call {{domxref("console.trace()")}}. Given code like this:

+ +
function foo() {
+  function bar() {
+    console.trace();
+  }
+  bar();
+}
+
+foo();
+
+ +

The output in the console looks something like this:

+ +

+ +

Specifications

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Console API')}}{{Spec2('Console API')}}Initial definition.
+ +

Browser compatibility

+ + + +

{{Compat("api.Console")}}

+ +

Notes

+ + + +

See also

+ + + +

Other implementations

+ + diff --git a/files/zh-tw/web/api/css_object_model/determining_the_dimensions_of_elements/index.html b/files/zh-tw/web/api/css_object_model/determining_the_dimensions_of_elements/index.html new file mode 100644 index 0000000000..589300d041 --- /dev/null +++ b/files/zh-tw/web/api/css_object_model/determining_the_dimensions_of_elements/index.html @@ -0,0 +1,33 @@ +--- +title: Determining the dimensions of elements +slug: Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements +translation_of: Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements +--- +

{{APIRef("CSSOM View")}}

+ +

There are several properties you can look at in order to determine the width and height of elements, and it can be tricky to determine which is the right one for your needs. This article is designed to help you make that decision.  Note that all these properties are read-only.  If you want to set the width and height of an element, use  width and height; or, the overriding min-width and max-width, and min-height and max-height properties.

+ +

How much room does it use up?

+ +

If you need to know the total amount of space an element occupies, including the width of the visible content, scrollbars (if any), padding, and border, you want to use the offsetWidth and offsetHeight properties. Most of the time these are the same as width and height of getBoundingClientRect(), when there aren't any transforms applied to the element. In case of transforms, the offsetWidth and offsetHeight returns the element's layout width and height, while getBoundingClientRect() returns the rendering width and height. As an example, if the element has width: 100px; and transform: scale(0.5); the getBoundingClientRect() will return 50 as the width, while offsetWidth will return 100.

+ +

Image:Dimensions-offset.png

+ +

What's the size of the displayed content?

+ +

If you need to know how much space the actual displayed content takes up, including padding but not including the border, margins, or scrollbars, you want to use the clientWidth and clientHeight properties:

+ +

Image:Dimensions-client.png

+ +

How big is the content?

+ +

If you need to know the actual size of the content, regardless of how much of it is currently visible, you need to use the scrollWidth and scrollHeight properties. These return the width and height of the entire content of an element, even if only part of it is presently visible due to the use of scroll bars.

+ +

For example, if a 600x400 pixel element is being displayed inside a 300x300 pixel scrollbox, scrollWidth will return 600 while scrollHeight will return 400.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/css_object_model/index.html b/files/zh-tw/web/api/css_object_model/index.html new file mode 100644 index 0000000000..e924a96301 --- /dev/null +++ b/files/zh-tw/web/api/css_object_model/index.html @@ -0,0 +1,131 @@ +--- +title: CSS Object Model +slug: Web/API/CSS_Object_Model +tags: + - API + - CSSOM + - NeedsTranslation + - Reference + - TopicStub +translation_of: Web/API/CSS_Object_Model +--- +

{{DefaultAPISidebar('CSSOM')}}

+ +

The CSS Object Model is a set of APIs allowing to manipulate CSS from JavaScript. It is the pendant of DOM and HTML APIs, but for CSS. It allows to read and modify CSS style dynamically.

+ +

Reference

+ +
+ +
+ +

Several other interfaces are also extended by the CSSOM-related specifications: {{domxref("Document")}}, {{domxref("Window")}}, {{domxref("Element")}}, {{domxref("HTMLElement")}}, {{domxref("HTMLImageElement")}}, {{domxref("Range")}}, {{domxref("MouseEvent")}}, and {{domxref("SVGElement")}}.

+ +

Tutorials

+ + + +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("CSSOM")}}{{Spec2("CSSOM")}} 
{{SpecName("CSSOM View")}}{{Spec2("CSSOM View")}} 
{{SpecName("Screen Orientation")}}{{Spec2("Screen Orientation")}} 
{{SpecName("CSS3 Fonts")}}{{Spec2("CSS3 Fonts")}} 
{{SpecName("CSS3 Animations")}}{{Spec2("CSS3 Animations")}} 
{{SpecName("CSS3 Transitions")}}{{Spec2("CSS3 Transitions")}} 
{{SpecName("CSS3 Variables")}}{{Spec2("CSS3 Variables")}} 
{{SpecName("CSS3 Conditional")}}{{Spec2("CSS3 Conditional")}} 
{{SpecName("CSS3 Device")}}{{Spec2("CSS3 Device")}} 
{{SpecName("CSS3 Counter Styles")}}{{Spec2("CSS3 Counter Styles")}} 
+ +

Browser compatibility notes

+ +

All these features have been added little by little over the years to the different browsers: it was a quite complex process that can't be summarized in a simple table. Please refer to the specific interfaces for its availability.

diff --git a/files/zh-tw/web/api/css_object_model/managing_screen_orientation/index.html b/files/zh-tw/web/api/css_object_model/managing_screen_orientation/index.html new file mode 100644 index 0000000000..806ac2d047 --- /dev/null +++ b/files/zh-tw/web/api/css_object_model/managing_screen_orientation/index.html @@ -0,0 +1,172 @@ +--- +title: 控制畫面方向 +slug: Web/API/CSS_Object_Model/Managing_screen_orientation +translation_of: Web/API/CSS_Object_Model/Managing_screen_orientation +--- +

{{SeeCompatTable}}{{APIRef}}

+ +

摘要

+ +

畫面方向(Screen Orientation)與裝置方向(Device Orientation)略有不同。有時甚至裝置本身不具備方向偵測功能,但裝置的螢幕仍搭載方向功能。如果裝置可測知本身的方向又能控制畫面方向,就能隨時配合 Web Apps 而達到最佳效果。

+ +

現有 2 種方法可處理畫面的方向,但均需搭配 CSS 與 JavaScript。第一種方法就是方向的 Media Query。根據瀏覽器視窗為橫放(寬度大於高度)或直放(高度大於寬度)狀態,而透過 CSS 調整網頁內容的配置。

+ +

第二種方法就是 JavaScript Screen Orientation API,可取得畫面目前的方向並進一步鎖定。

+ +

根據方向而調整配置

+ +

方向改變最常見的情形之一,就是根據裝置的方向而修正內容的配置方式。舉例來說,你可能想將按鈕列拉到與裝置螢幕等長。而透過 Media Query 即可輕鬆達到此效果。

+ +

來看看下列 HTML 程式碼範例:

+ +
<ul id="toolbar">
+  <li>A</li>
+  <li>B</li>
+  <li>C</li>
+</ul>
+
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis lacinia nisi nec sem viverra vitae fringilla nulla ultricies. In ac est dolor, quis tincidunt leo. Cras commodo quam non tortor consectetur eget rutrum dolor ultricies. Ut interdum tristique dapibus. Nullam quis malesuada est.</p>
+
+ +

CSS 將根據方向的 Media Query,處理畫面方向的特殊樣式:

+ +
/* First let's define some common styles */
+
+html, body {
+  width : 100%;
+  height: 100%;
+}
+
+body {
+  border: 1px solid black;
+
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+
+p {
+  font   : 1em sans-serif;
+  margin : 0;
+  padding: .5em;
+}
+
+ul {
+  list-style: none;
+
+  font   : 1em monospace;
+  margin : 0;
+  padding: .5em;
+
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+
+  background: black;
+}
+
+li {
+  display: inline-block;
+  margin : 0;
+  padding: 0.5em;
+  background: white;
+}
+
+ +

在設定某些通用的樣式之後,即可針對方向定義特殊條件:

+ +
/* For portrait, we want the tool bar on top */
+
+@media screen and (orientation: portrait) {
+  #toolbar {
+    width: 100%;
+  }
+}
+
+/* For landscape, we want the tool bar stick on the left */
+
+@media screen and (orientation: landscape) {
+  #toolbar {
+    position: fixed;
+    width: 2.65em;
+    height: 100%;
+  }
+
+  p {
+    margin-left: 2em;
+  }
+
+  li + li {
+    margin-top: .5em;
+  }
+}
+
+ +

結果如下所示(若無法顯示,可至本文右上角切換回英文原文觀看):

+ + + + + + + + + + + + + + +
PortraitLandscape
{{ EmbedLiveSample('Adjusting_layout_based_on_the_orientation', 180, 350) }}{{ EmbedLiveSample('Adjusting_layout_based_on_the_orientation', 350, 180) }}
+ +
+

注意:方向 Media Query 其實是以瀏覽器視窗 (或 iframe) 的方向為準,而非裝置本身的方向。

+
+ +

鎖定畫面方向

+ +
+

警告:此 API 仍屬實驗性質,目前仍具備 moz 前綴而僅能用於 Firefox OSFirefox for Android,而 Windows 8.1 以上版本的 Internet Explorer 則使用 ms 前綴。

+
+ +

某些裝置(主要為行動裝置)可根據本身方向而動態改變畫面的方向,讓使用者隨時閱讀畫面上的資訊。這種動作對文字類的內容影響不大,但某些內容就無法順利套用此功能。舉例來說,若遊戲需要裝置方向的相關資訊,就可能因為方向變化而發生混亂情形。

+ +

而 Screen Orientation API 即可用以避免或處理這類變化。

+ +

監聽方向變化

+ +

只要裝置改變了畫面方向與本身方向,就會觸發 {{event("orientationchange")}} 事件,再由 {{domxref("Screen.orientation")}} 屬性讀取之。

+ +
screen.addEventListener("orientationchange", function () {
+  console.log("The orientation of the screen is: " + screen.orientation);
+});
+
+ +

避免方向改變

+ +

任何 Web Apps 均可鎖定畫面以符合本身需求。{{domxref("Screen.lockOrientation()")}} 函式可鎖定畫面方向;{{domxref("Screen.unlockOrientation()")}} 函式可解鎖畫面方向。

+ +

{{domxref("Screen.lockOrientation()")}} 將接受一組字串或系列字串,以定義畫面鎖定的方向。有效字串為:「portrait-primary」、「portrait-secondary」、「landscape-primary」、「landscape-secondary」、「portrait」、「landscape」。另可參閱 {{domxref("Screen.lockOrientation")}} 進一步了解這些有效值。

+ +
screen.lockOrientation('landscape');
+ +
+

注意:畫面鎖定功能將依 Web Apps 而有所不同。如果 App A 鎖定為 landscape;App B 鎖定為 portrait,則此兩款 Apps 均將維持自己的方向。所以不論如何切換 A 與 B,均不會觸發 {{event("orientationchange")}} 事件。

+ +

但若必須改變方向以滿足畫面鎖定的需求,則鎖定方向時就會觸發 {{event("orientationchange")}} 事件。

+
+ +

Firefox OS and Android: Orientation lock using the manifest

+ +

For a Firefox OS and Firefox Android (soon to work on Firefox desktop too) specific way to lock orientation, you can set the orientation field in app's your manifest file, for example:

+ +
"orientation": "portrait"
+ +

參見

+ + diff --git a/files/zh-tw/web/api/css_object_model/using_dynamic_styling_information/index.html b/files/zh-tw/web/api/css_object_model/using_dynamic_styling_information/index.html new file mode 100644 index 0000000000..fa020403aa --- /dev/null +++ b/files/zh-tw/web/api/css_object_model/using_dynamic_styling_information/index.html @@ -0,0 +1,132 @@ +--- +title: 使用動態樣式資訊 +slug: Web/API/CSS_Object_Model/Using_dynamic_styling_information +translation_of: Web/API/CSS_Object_Model/Using_dynamic_styling_information +--- +

The CSS Object Model (CSSOM), part of the DOM, exposes specific interfaces allowing manipulation of a wide amount of information regarding CSS. Initially defined in the DOM Level 2 Style recommendation, these interfaces forms now a specification, CSS Object Model (CSSOM) which aims at superseding it.

+ +

In many cases, and where possible, it really is best practice to dynamically manipulate classes via the {{ domxref("element.className", "className") }} property since the ultimate appearance of all of the styling hooks can be controlled in a single stylesheet. One's JavaScript code also becomes cleaner since instead of being dedicated to styling details, it can focus on the overall semantics of each section it is creating or manipulating, leaving the precise style details to the stylesheet. However, there are cases where actually obtaining or manipulating the rules can be useful (whether for whole stylesheets or individual elements), and that is described in further detail below. Note also that, as with individual element's DOM styles, when speaking of manipulating the stylesheets, this is not actually manipulating the physical document(s), but merely the internal representation of the document.

+ +

The basic style object exposes the {{domxref("Stylesheet")}} and the {{domxref("CSSStylesheet")}} interfaces. Those interfaces contain members like insertRule, selectorText, and parentStyleSheet for accessing and manipulating the individual style rules that make up a CSS stylesheet.

+ +

To get to the style objects from the document, you can use the {{domxref("document.styleSheets")}} property and access the individual objects by index (e.g., document.styleSheets[0] is the first stylesheet defined for the document, etc.).

+ +

透過 CSSOM 修改樣式表規則

+ +
<html>
+<head>
+<title>Modifying a stylesheet rule with CSSOM</title>
+<style type="text/css">
+body {
+ background-color: red;
+}
+</style>
+<script type="text/javascript">
+var stylesheet = document.styleSheets[1];
+stylesheet.cssRules[0].style.backgroundColor="blue";
+</script>
+</head>
+<body>
+The stylesheet declaration for the body's background color is modified via JavaScript.
+</body>
+</html>
+ +

{{ EmbedLiveSample('Modify_a_stylesheet_rule') }}

+ +

The list of properties available in the DOM from the style property is given on the DOM CSS Properties List page.

+ +

To modify styles to a document using CSS syntax, one can insert rules or insert {{HTMLElement("style")}} tags whose innerHTML property is set to the desired CSS.

+ +

修改元素的樣式

+ +

The element {{domxref("HTMLElement.style", "style")}} property (see also the section "DOM Style Object" below) can also be used to get and set the styles on an element. However, this property only returns style attributes that have been set in-line (e.g, <td style="background-color: lightblue"> returns the string "background-color:lightblue", or directly for that element using element.style.propertyName, even though there may be other styles on the element from a stylesheet).

+ +

Also, when you set this property on an element, you override and erase any styles that have been set elsewhere for that element's particular property you are setting. Setting the border property, for example, will override settings made elsewhere for that element's border property in the head section, or external style sheets. However, this will not affect any other property declarations for that element's styles, such as padding or margin or font, for example.

+ +

To change a particular element's style, you can adapt the following example for the element(s) you want to style.

+ +
<html>
+<head>
+<title>simple style example</title>
+
+<script type="text/javascript">
+
+function alterStyle(elem) {
+  elem.style.background = 'green';
+}
+
+function resetStyle(elemId) {
+  elem = document.getElementById(elemId);
+  elem.style.background = 'white';
+}
+</script>
+
+<style type="text/css">
+#p1 {
+  border: solid blue 2px;
+}
+</style>
+</head>
+
+<body>
+
+<!-- passes a reference to the element's object as parameter 'this'. -->
+<p id="p1" onclick="alterStyle(this);">
+ Click here to change background color.
+</p>
+
+<!-- passes the 'p1' id of another element's style to modify. -->
+<button onclick="resetStyle('p1');">Reset background color</button>
+
+</body>
+</html>
+
+ +

{{ EmbedLiveSample('Modify_an_element_style') }}

+ +

The {{domxref("window.getComputedStyle", "getComputedStyle()")}} method on the document.defaultView object returns all styles that have actually been computed for an element. See Example 6: getComputedStyle in the examples chapter for more information on how to use this method.

+ +

DOM Style Object

+ +

The style object represents an individual style statement. Unlike the individual rules available from the document.styleSheets collection, the style object is accessed from the document or from the elements to which that style is applied. It represents the in-line styles on a particular element.

+ +

More important than the two properties noted here is the use of the style object to set individual style properties on an element:

+ +
+
<!DOCTYPE html>
+<html>
+ <head>
+  <title>style Property Example</title>
+  <link rel="StyleSheet" href="example.css" type="text/css">
+  <script type="text/javascript">
+    function stilo() {
+      document.getElementById('d').style.color = 'orange';
+    }
+    function resetStyle() {
+      document.getElementById('d').style.color = 'black';
+    }
+  </script>
+ </head>
+
+ <body>
+  <div id="d" class="thunder">Thunder</div>
+  <button onclick="stilo()">Click here to change text color</button>
+  <button onclick="resetStyle()">Reset text color</button>
+ </body>
+</html>
+
+
+ +

{{ EmbedLiveSample('DOM_Style_Object_code_sample') }}

+ +

The media and type of the style may or may not be given.

+ +

使用 setAttribute 方法

+ +

Note that you can also change style of an element by getting a reference to it and then use its setAttribute method to specify the CSS property and its value.

+ +
var el = document.getElementById('some-element');
+el.setAttribute('style', 'background-color:darkblue;');
+
+ +

Be aware, however, that setAttribute removes all other style properties that may already have been defined in the element's style object. If the some-element element above had an in–line style attribute of say style="font-size: 18px", that value would be removed by the use of setAttribute.

diff --git a/files/zh-tw/web/api/cssstyledeclaration/index.html b/files/zh-tw/web/api/cssstyledeclaration/index.html new file mode 100644 index 0000000000..8893e225d6 --- /dev/null +++ b/files/zh-tw/web/api/cssstyledeclaration/index.html @@ -0,0 +1,90 @@ +--- +title: CSSStyleDeclaration +slug: Web/API/CSSStyleDeclaration +translation_of: Web/API/CSSStyleDeclaration +--- +

{{ APIRef("CSSOM") }}

+ +

概要

+ +

CSSStyleDeclaration 表示了一個 CSS 屬性名值對(property-value pairs)的集合。它被用於幾個 API 當中:

+ + + +

屬性

+ +
+
{{domxref("CSSStyleDeclaration.cssText")}}
+
Textual representation of the declaration block. Setting this attribute changes the style.
+
{{domxref("CSSStyleDeclaration.length")}} {{readonlyInline}}
+
The number of properties. See the {{domxref("CSSStyleDeclaration.item", 'item()')}} method below.
+
{{domxref("CSSStyleDeclaration.parentRule")}} {{readonlyInline}}
+
The containing {{domxref("CSSRule")}}.
+
+ +

方法

+ +
+
{{domxref("CSSStyleDeclaration.getPropertyPriority()")}}
+
Returns the optional priority, "important".
+
{{domxref("CSSStyleDeclaration.getPropertyValue()")}}
+
Returns the property value given a property name.
+
{{domxref("CSSStyleDeclaration.item()")}}
+
Returns a property name.
+
{{domxref("CSSStyleDeclaration.removeProperty()")}}
+
Removes a property from the CSS declaration block.
+
{{domxref("CSSStyleDeclaration.setProperty()")}}
+
Modifies an existing CSS property or creates a new CSS property in the declaration block/.
+
{{domxref("CSSStyleDeclaration.getPropertyCSSValue()")}} {{obsolete_inline}}
+
Only supported via getComputedStyle in Firefox. Returns the property value as a {{ domxref("CSSPrimitiveValue") }} or null for shorthand properties.
+
+ +

範例

+ +
var styleObj = document.styleSheets[0].cssRules[0].style;
+console.log(styleObj.cssText);
+
+for (var i = styleObj.length; i--;) {
+  var nameString = styleObj[i];
+  styleObj.removeProperty(nameString);
+}
+
+console.log(styleObj.cssText);
+ +

備註

+ +

The declaration block is that part of the style rule that appears within the braces and that actually provides the style definitions (for the selector, the part that comes before the braces).

+ +

參見

+ + + +

規範

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSSOM', '#the-cssstyledeclaration-interface', 'CSSStyleDeclaration')}}{{Spec2('CSSOM')}} 
{{SpecName('DOM2 Style', 'css.html#CSS-CSSStyleDeclaration', 'CSSPrimitiveValue')}}{{Spec2('DOM2 Style')}}Initial definition
diff --git a/files/zh-tw/web/api/cssstylesheet/index.html b/files/zh-tw/web/api/cssstylesheet/index.html new file mode 100644 index 0000000000..01abf1a942 --- /dev/null +++ b/files/zh-tw/web/api/cssstylesheet/index.html @@ -0,0 +1,187 @@ +--- +title: CSSStyleSheet +slug: Web/API/CSSStyleSheet +tags: + - API + - CSSOM + - NeedsTranslation + - Reference + - TopicStub +translation_of: Web/API/CSSStyleSheet +--- +
{{APIRef("CSSOM")}}
+ +

The CSSStyleSheet interface represents a single CSS style sheet. It inherits properties and methods from its parent, {{domxref("StyleSheet")}}.

+ +

A style sheet consists of {{domxref("CSSRule", "rules", "", 1)}}, such as {{domxref("CSSStyleRule", "style rules", "", 1)}} ("h1,h2 { font-size: 16pt }"), various at-rules (@import, @media, ...), etc. This interface lets you inspect and modify the list of rules in the stylesheet.

+ +

See the {{anch("Notes")}} section for the various ways a CSSStyleSheet object can be obtained.

+ +

Properties

+ +

Inherits properties from its parent, {{domxref("StyleSheet")}}.

+ +
+
{{domxref("CSSStyleSheet.cssRules")}}
+
Returns a live {{domxref("CSSRuleList")}}, listing the {{domxref("CSSRule")}} objects in the style sheet.
+ This is normally used to access individual rules like this:
+    styleSheet.cssRules[i] // where i = 0..cssRules.length-1
+ To add or remove items in cssRules, use the CSSStyleSheet's deleteRule() and insertRule() methods, described below.
+
{{domxref("CSSStyleSheet.ownerRule")}}
+
If this style sheet is imported into the document using an {{cssxref("@import")}} rule, the ownerRule property will return that {{domxref("CSSImportRule")}}, otherwise it returns null.
+
+ +

Methods

+ +

Inherits methods from its parent, {{domxref("Stylesheet")}}.

+ +
+
{{domxref("CSSStyleSheet.deleteRule()")}}
+
Deletes a rule at the specified position from the style sheet.
+
{{domxref("CSSStyleSheet.insertRule()")}}
+
Inserts a new rule at the specified position in the style sheet, given the textual representation of the rule.
+
+ +

Notes

+ +

In some browsers, if a stylesheet is loaded from a different domain, calling cssRules results in SecurityError.

+ +

A stylesheet is associated with at most one {{domxref("Document")}}, which it applies to (unless {{domxref("StyleSheet.disabled", "disabled", "", 1)}}). A list of CSSStyleSheet objects for a given document can be obtained using the {{domxref("document.styleSheets")}} property. A specific style sheet can also be accessed from its owner object (Node or CSSImportRule), if any.

+ +

A CSSStyleSheet object is created and inserted into the document's styleSheets list automatically by the browser, when a style sheet is loaded for a document. As the {{domxref("document.styleSheets")}} list cannot be modified directly, there's no useful way to create a new CSSStyleSheet object manually (although Constructable Stylesheet Objects might get added to the Web APIs at some point). To create a new stylesheet, insert a {{HTMLElement("style")}} or {{HTMLElement("link")}} element into the document.

+ +

A (possibly incomplete) list of ways a style sheet can be associated with a document follows:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Reason for the style sheet to be associated with the documentAppears in document.
+ styleSheets
list
Getting the owner element/rule given the style sheet objectThe interface for the owner objectGetting the CSSStyleSheet object from the owner
{{HTMLElement("style")}} and {{HTMLElement("link")}} elements in the documentYes{{domxref("StyleSheet.ownerNode", ".ownerNode")}}{{domxref("HTMLLinkElement")}},
+ {{domxref("HTMLStyleElement")}},
+ or {{domxref("SVGStyleElement")}}
{{domxref("LinkStyle.sheet", ".sheet")}}
CSS {{cssxref("@import")}} rule in other style sheets applied to the documentYes{{domxref("CSSStyleSheet.ownerRule", ".ownerRule")}}{{domxref("CSSImportRule")}}{{domxref("CSSImportRule.styleSheet", ".styleSheet")}}
<?xml-stylesheet ?> processing instruction in the (non-HTML) documentYes{{domxref("StyleSheet.ownerNode", ".ownerNode")}}{{domxref("ProcessingInstruction")}}{{domxref("LinkStyle.sheet", ".sheet")}}
HTTP Link HeaderYesN/AN/AN/A
User agent (default) style sheetsNoN/AN/AN/A
+ +

Specifications

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("CSSOM", "#cssstylesheet", 'CSSStyleSheet')}}{{Spec2("CSSOM")}} 
{{SpecName("DOM2 Style", "css.html#CSS-CSSStyleSheet", "CSSStyleSheet")}}{{Spec2("DOM2 Style")}}Initial definition
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}9.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

See also

+ + diff --git a/files/zh-tw/web/api/cssstylesheet/insertrule/index.html b/files/zh-tw/web/api/cssstylesheet/insertrule/index.html new file mode 100644 index 0000000000..3cd8ba5a87 --- /dev/null +++ b/files/zh-tw/web/api/cssstylesheet/insertrule/index.html @@ -0,0 +1,219 @@ +--- +title: CSSStyleSheet.insertRule() +slug: Web/API/CSSStyleSheet/insertRule +translation_of: Web/API/CSSStyleSheet/insertRule +--- +
{{APIRef("CSSOM")}} 
+ +

CSSStyleSheet.insertRule() 方法新增一個新的 CSS 規則,到當前的樣式表,他伴隨著一些限制.  

+ +

更明確的說,雖然 insertRule() 只是一個 {{domxref("CSSStyleSheet")}} 的方法, 他實際上插入這份規則到 {{domxref("CSSStyleSheet")}}.cssRules, 在 {{domxref("CSSRuleList")}} 之中。

+ +

這份規則,必須包含的內容,取決於它的類型: 對於規則集 (rule-sets),規則同時指定了選擇器和样式聲明。 對於規則 (at-rules),規則同時指定 at 標識符( at-identifier )和規則內容。

+ +

Syntax

+ +

+
+stylesheet.insertRule(rule[, index])
+ +

Parameters

+ +
+
rule
+
一個  {{domxref("DOMString")}} 包含要被插入的規則,這份規則同時指定了選擇器( selector )和样式聲明,或 at 標識符 (at-identifier ) 和規則內容。
+
index {{optional_inline}}
+
+

無符號整數,代表在 {{domxref("CSSStyleSheet")}}.cssRules 中插入的位置,其中 index-0 是第一個規則,而 index-max 就是最後一個規則,並且與 CSSStyleSheet 的長度相同。cssRules 在舊的實現中是必需的。查詢「瀏覽器兼容」取得詳細信息。 默認值為 0。

+
+
+ +

Return value

+ +

The index within the style sheet's rule-list of the newly inserted rule.

+ +

Restrictions  限制

+ +

CSS 樣式表規則列表,有一些直覺的、和不是那麼直覺的限制 ,影響著規則的插入方式和位置。
+ 違反這些可能會導致 DOM 異常 ({{domxref("DOMException")}}) 引發錯誤。

+ + + +

Examples

+ +

Example 1

+ +
// push a new rule onto the top of my stylesheet
+myStyle.insertRule("#blanc { color: white }", 0);
+
+ +

Example 2

+ +
/**
+ * Add a stylesheet rule to the document (may be better practice, however,
+ * to dynamically change classes, so style information can be kept in
+ * genuine stylesheets (and avoid adding extra elements to the DOM))
+ * Note that an array is needed for declarations and rules since ECMAScript does
+ * not afford a predictable object iteration order and since CSS is
+ * order-dependent (i.e., it is cascading); those without need of
+ * cascading rules could build a more accessor-friendly object-based API.
+ * @param {Array} rules Accepts an array of JSON-encoded declarations
+ * @example
+addStylesheetRules([
+  ['h2', // Also accepts a second argument as an array of arrays instead
+    ['color', 'red'],
+    ['background-color', 'green', true] // 'true' for !important rules
+  ],
+  ['.myClass',
+    ['background-color', 'yellow']
+  ]
+]);
+ */
+function addStylesheetRules (rules) {
+  var styleEl = document.createElement('style'),
+      styleSheet;
+
+  // Append style element to head
+  document.head.appendChild(styleEl);
+
+  // Grab style sheet
+  styleSheet = styleEl.sheet;
+
+  for (var i = 0, rl = rules.length; i < rl; i++) {
+    var j = 1, rule = rules[i], selector = rules[i][0], propStr = '';
+    // If the second argument of a rule is an array of arrays, correct our variables.
+    if (Object.prototype.toString.call(rule[1][0]) === '[object Array]') {
+      rule = rule[1];
+      j = 0;
+    }
+
+    for (var pl = rule.length; j < pl; j++) {
+      var prop = rule[j];
+      propStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\n';
+    }
+
+    // Insert CSS Rule
+    styleSheet.insertRule(selector + '{' + propStr + '}', styleSheet.cssRules.length);
+  }
+}
+ +

Specifications

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSSOM', '#dom-cssstylesheet-insertrule', 'CSSStyleSheet.insertRule')}}{{Spec2('CSSOM')}}No change from {{SpecName('DOM2 Style')}}.
{{SpecName('DOM2 Style', 'css.html#CSS-CSSStyleSheet-insertRule', 'CSSStyleSheet.insertRule')}}{{Spec2('DOM2 Style')}}Initial definition
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}9{{CompatVersionUnknown}}{{CompatVersionUnknown}}
index is optional{{CompatChrome(60)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatOpera(47)}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroid WebviewChrome for AndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
index is optional{{CompatChrome(60)}}{{CompatChrome(60)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatOperaMobile(47)}}{{CompatUnknown}}
+
+ +

Legacy browser support

+ + + +

See also

+ + diff --git a/files/zh-tw/web/api/customevent/customevent/index.html b/files/zh-tw/web/api/customevent/customevent/index.html new file mode 100644 index 0000000000..0accf247e5 --- /dev/null +++ b/files/zh-tw/web/api/customevent/customevent/index.html @@ -0,0 +1,90 @@ +--- +title: CustomEvent() +slug: Web/API/CustomEvent/CustomEvent +translation_of: Web/API/CustomEvent/CustomEvent +--- +

{{APIRef("DOM")}}

+ +

CustomEvent() constructor 可用來建立 {{domxref("CustomEvent")}}.

+ +

語法

+ +
 event = new CustomEvent(typeArg, customEventInit);
+ +

參數

+ +
+
typeArg
+
一個 {{domxref("DOMString")}} 用來表示事件名稱。
+
customEventInit{{optional_inline}}
+
Is a CustomEventInit dictionary, having the following fields: +
    +
  • "detail", optional and defaulting to null, of type any, that is a event-dependant value associated with the event.
  • +
+ +
+

The CustomEventInit dictionary also accepts fields from the {{domxref("Event.Event", "EventInit")}} dictionary.

+
+
+
+ +

範例

+ +
// add an appropriate event listener
+obj.addEventListener("cat", function(e) { process(e.detail) });
+
+// create and dispatch the event
+var event = new CustomEvent("cat", {
+  detail: {
+    hazcheeseburger: true
+  }
+});
+obj.dispatchEvent(event);
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG','#interface-customevent','CustomEvent()')}}{{Spec2('DOM WHATWG')}}Initial definition.
+ +

瀏覽器支援度

+ + + +

{{Compat("api.CustomEvent.CustomEvent")}}

+ +

添加額外參數

+ +

在 Internet Explorer 9 或更高的版本,你可以用以下的方法給 CustomEvent() constructor 添加額外參數

+ +
(function () {
+  function CustomEvent ( event, params ) {
+    params = params || { bubbles: false, cancelable: false, detail: undefined };
+    var evt = document.createEvent( 'CustomEvent' );
+    evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
+    return evt;
+   }
+
+  CustomEvent.prototype = window.Event.prototype;
+
+  window.CustomEvent = CustomEvent;
+})();
+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/api/customevent/index.html b/files/zh-tw/web/api/customevent/index.html new file mode 100644 index 0000000000..e35df7df2e --- /dev/null +++ b/files/zh-tw/web/api/customevent/index.html @@ -0,0 +1,88 @@ +--- +title: CustomEvent +slug: Web/API/CustomEvent +tags: + - 待翻譯 +translation_of: Web/API/CustomEvent +--- +

{{APIRef("DOM")}}

+ +

CustomEvent interface 是應用程式為了任意目的所初始化的事件。

+ +

建構式

+ +
+
{{domxref("CustomEvent.CustomEvent", "CustomEvent()")}}
+
建立一個 CustomEvent。
+
+ +

屬性

+ +
+
{{domxref("CustomEvent.detail")}} {{readonlyinline}}
+
初始化事件時傳送的任意資料。
+
+ +

此介面繼承了其父介面 {{domxref("Event")}} 的屬性:

+ +

{{Page("/zh-TW/docs/Web/API/Event", "屬性")}}

+ +

方法

+ +
+
{{domxref("CustomEvent.initCustomEvent()")}} {{deprecated_inline}}
+
+

初始化一 CustomEvent object。若該事件已經被觸發,則不會進行任何動作。

+
+
+ +

此介面繼承了其父介面 {{domxref("Event")}} 的方法:

+ +

{{Page("/zh-TW/docs/Web/API/Event", "方法")}}

+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG','#interface-customevent','CustomEvent')}}{{Spec2('DOM WHATWG')}}原始定義
+ +

瀏覽器兼容性

+ + + +

{{Compat("api.CustomEvent")}}

+ +

Firing from privileged code to non-privileged code

+ +

當要從 privileged code (像是插件)到非 privileged code (例如網頁)執行 CustomEvent ,你必須要考慮這之間的安全性。Firefox 和其他 Gecko 應用會對此有所限制。雖然這可以自動防止安全漏洞發生,但也可能導致您的程式碼沒辦法正常執行。

+ +

When creating a CustomEvent object, you must create the object from the same window as you're going to fire against. The detail attribute of your CustomEvent will be subject to the same restrictions. String and Array values will be readable by the content without restrictions, but custom Objects will not. If using a custom Object, you will need to define the attributes of that object that are readable from the content script using Components.utils.cloneInto().

+ +
// doc is a reference to the content document
+function dispatchCustomEvent(doc) {
+  var eventDetail = Components.utils.cloneInto({foo: 'bar'}, doc.defaultView);
+  var myEvent = doc.defaultView.CustomEvent("mytype", eventDetail);
+  doc.dispatchEvent(myEvent);
+}
+ +

Note that exposing a function will allow the content script to run it with chrome privileges, which can open a security vulnerability.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/datatransfer/index.html b/files/zh-tw/web/api/datatransfer/index.html new file mode 100644 index 0000000000..d202c3b876 --- /dev/null +++ b/files/zh-tw/web/api/datatransfer/index.html @@ -0,0 +1,204 @@ +--- +title: DataTransfer +slug: Web/API/DataTransfer +translation_of: Web/API/DataTransfer +--- +
{{APIRef("HTML Drag and Drop API")}}
+ +

DataTransfer 物件被用來保存使用者於拖放操作過程中的資料,其中可能包含了一至多項資料以及多種資料類型。要瞭解拖放操作的更多細節,請參考拖放操作一文。

+ +

DataTransfer 只能是每一種 {{domxref("DragEvent")}} 型別物件的共同屬性-{{domxref("DragEvent.dataTransfer","dataTransfer")}},不能夠被單獨建立。

+ +

屬性

+ +

Standard properties

+ +
+
{{domxref("DataTransfer.dropEffect")}}
+
Gets the type of drag-and-drop operation currently selected or sets the operation to a new type. The value must be none copy link or move.
+
{{domxref("DataTransfer.effectAllowed")}}
+
Provides all of the types of operations that are possible. Must be one of none, copy, copyLink, copyMove, link, linkMove, move, all or uninitialized.
+
{{domxref("DataTransfer.files")}}
+
Contains a list of all the local files available on the data transfer. If the drag operation doesn't involve dragging files, this property is an empty list.
+
{{domxref("DataTransfer.items")}} {{readonlyInline}}
+
Gives a {{domxref("DataTransferItemList")}} object which is a list of all of the drag data.
+
{{domxref("DataTransfer.types")}} {{readonlyInline}}
+
An array of {{domxref("DOMString","strings")}} giving the formats that were set in the {{event("dragstart")}} event.
+
+ +

Gecko properties

+ +

{{SeeCompatTable}}

+ +
Note: All of the properties in this section are Gecko-specific.
+ +
+
{{domxref("DataTransfer.mozCursor")}}
+
Gives the drag cursor's state. This is primarily used to control the cursor during tab drags.
+
{{domxref("DataTransfer.mozItemCount")}} {{readonlyInline}}
+
Gives the number of items in the drag operation.
+
{{domxref("DataTransfer.mozSourceNode")}} {{readonlyInline}}
+
The {{ domxref("Node") }} over which the mouse cursor was located when the button was pressed to initiate the drag operation. This value is null for external drags or if the caller can't access the node.
+
{{domxref("DataTransfer.mozUserCancelled")}} {{readonlyInline}}
+
This property applies only to the dragend event, and is true if the user canceled the drag operation by pressing escape. It will be false in all other cases, including if the drag failed for any other reason, for instance due to a drop over an invalid location.
+
+ +

方法

+ +

Standard methods

+ +
+
{{domxref("DataTransfer.clearData()")}}
+
Remove the data associated with a given type. The type argument is optional. If the type is empty or not specified, the data associated with all types is removed. If data for the specified type does not exist, or the data transfer contains no data, this method will have no effect.
+
{{domxref("DataTransfer.getData()")}}
+
Retrieves the data for a given type, or an empty string if data for that type does not exist or the data transfer contains no data.
+
{{domxref("DataTransfer.setData()")}}
+
Set the data for a given type. If data for the type does not exist, it is added at the end, such that the last item in the types list will be the new format. If data for the type already exists, the existing data is replaced in the same position.
+
{{domxref("DataTransfer.setDragImage()")}}
+
Set the image to be used for dragging if a custom one is desired.
+
+ +

Gecko methods

+ +

{{SeeCompatTable}}

+ +
Note: All of the methods in this section are Gecko-specific.
+ +
+
{{domxref("DataTransfer.addElement()")}}
+
Sets the drag source to the given element.
+
{{domxref("DataTransfer.mozClearDataAt()")}}
+
Removes the data associated with the given format for an item at the specified index. The index is in the range from zero to the number of items minus one.
+
{{domxref("DataTransfer.mozGetDataAt()")}}
+
Retrieves the data associated with the given format for an item at the specified index, or null if it does not exist. The index should be in the range from zero to the number of items minus one.
+
{{domxref("DataTransfer.mozSetDataAt()")}}
+
A data transfer may store multiple items, each at a given zero-based index. mozSetDataAt() may only be called with an index argument less than mozItemCount in which case an existing item is modified, or equal to mozItemCount in which case a new item is added, and the mozItemCount is incremented by one.
+
{{domxref("DataTransfer.mozTypesAt()")}}
+
Holds a list of the format types of the data that is stored for an item at the specified index. If the index is not in the range from 0 to the number of items minus one, an empty string list is returned.
+
+ +

範例

+ +

Every method and property listed in this document has its own reference page and each reference page either directly includes an example of the interface or has a link to an example.

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', 'interaction.html#datatransfer','DataTransfer')}}{{Spec2('HTML WHATWG')}}mozCursor, mozItemCount, mozSourceNode, mozUserCancelled, addElement(), mozClearDataAt(), mozGetDataAt(), mozSetDataAt() and mozTypesAt are Gecko specific.
{{SpecName('HTML5.1', 'editing.html#the-datatransfer-interface','DataTransfer')}}{{Spec2('HTML5.1')}}Not included in W3C HTML5 {{Spec2('HTML5 W3C')}}
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support4{{CompatVersionUnknown}}3.5 [2]
+ {{CompatGeckoDesktop(52)}}[3]
10 [1] [2]123.1 [2]
{{domxref("DataTransfer.items", "items")}} property4{{CompatVersionUnknown}}50{{CompatNo}}12{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewChrome for AndroidEdgeFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari Mobile
Basic support{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+ {{CompatGeckoMobile(52)}}[3]
{{CompatNo}}{{CompatIE("10")}}[1][2]{{CompatNo}}{{CompatNo}}
{{domxref("DataTransfer.items", "items")}} property{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatGeckoMobile(50)}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

[1] Partial support refers to not supporting {{domxref("DataTransfer.setDragImage()")}} [CanIUse.com].

+ +

[2] Does not support {{domxref("DataTransfer.items")}} property.

+ +

[3] As of Firefox 52, the {{domxref("DataTransfer.types")}} property returns a frozen array of {{domxref("DOMString")}}s as per spec, rather than a {{domxref("DOMStringList")}}.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/detecting_device_orientation/index.html b/files/zh-tw/web/api/detecting_device_orientation/index.html new file mode 100644 index 0000000000..d81307ba57 --- /dev/null +++ b/files/zh-tw/web/api/detecting_device_orientation/index.html @@ -0,0 +1,278 @@ +--- +title: 偵測裝置方向 +slug: Web/API/Detecting_device_orientation +translation_of: Web/API/Detecting_device_orientation +--- +
{{SeeCompatTable}}
+ +

目前支援 Web 的裝置,已有越來越多可偵測本身的方向(Orientation);也就是說,這些裝置可根據重力牽引的相對關係而改變其畫面方向,同時回報該筆資料。特別是如行動電話的手持式裝置,同樣會判斷這種資訊而自動旋轉其畫面。如此除了能保持正向畫面之外,裝置橫放時亦能以寬螢幕呈現網頁內容。

+ +

現有 2 組 JavaScript 事件可處理方向資訊。第一個是 {{domxref("DeviceOrientationEvent")}} 事件。只要加速規偵測到裝置方向的變化,隨即送出此事件。在接收並處理這些方向事件所回報的資料之後,即可針對使用者移動裝置所造成的方向與高度變化,確實做出回應。

+ +

第二個為 {{domxref("DeviceMotionEvent")}} 事件。只要加速過程產生變化,隨即送出該事件。此事件用以監聽加速過程的變化,因此不同於 {{domxref("DeviceOrientationEvent")}} 的方向變化。如筆記型電腦中的感測器,一般均能夠偵測 {{domxref("DeviceMotionEvent")}} 而保護移動中的儲存裝置。{{domxref("DeviceOrientationEvent")}} 則較常用於行動裝置。

+ +

處理方向事件

+ +

若要開始接收方向變換的情形,只要監聽 {{event("deviceorientation")}} 事件即可:

+ +
+

Note: gyronorm.js is a polyfill for normalizing the accelerometer and gyroscope data on mobile devices. This is useful for overcoming some of the differences in device support for device orientation.

+
+ +
window.addEventListener("deviceorientation", handleOrientation, true);
+
+ +

在註冊了事件監聽器(Event listener。本範例使用 handleOrientation() 函式)之後,將以更新過的方向資料而定期呼叫你的監聽器函式。

+ +

方向事件共有 4 組值:

+ + + +

事件處理器(Event handler)函式則如下列:

+ +
function handleOrientation(event) {
+  var absolute = event.absolute;
+  var alpha    = event.alpha;
+  var beta     = event.beta;
+  var gamma    = event.gamma;
+
+  // Do stuff with the new orientation data
+}
+
+ +

方向值說明

+ +

所回報的各個軸線值,均是以標準座標而呈現對應各軸線的旋轉量 (Amount of rotation)。可參閱下方所提供的方向與動向資料說明文章以獲得詳細資訊。

+ + + +

方向範例

+ +

只要瀏覽器支援 {{event("deviceorientation")}} 事件,且該執行裝置可偵測自己的方向,均可使用此範例。

+ +

先想像花園裡有 1 顆球:

+ +
<div class="garden">
+  <div class="ball"></div>
+</div>
+
+<pre class="output"></pre>
+
+ +

這座花園為 200 像素寬(對,一座小花園),球就位在正中央:

+ +
.garden {
+  position: relative;
+  width : 200px;
+  height: 200px;
+  border: 5px solid #CCC;
+  border-radius: 10px;
+}
+
+.ball {
+  position: absolute;
+  top   : 90px;
+  left  : 90px;
+  width : 20px;
+  height: 20px;
+  background: green;
+  border-radius: 100%;
+}
+
+ +

現在只要移動裝置,球也會跟著移動:

+ +
var ball   = document.querySelector('.ball');
+var garden = document.querySelector('.garden');
+var output = document.querySelector('.output');
+
+var maxX = garden.clientWidth  - ball.clientWidth;
+var maxY = garden.clientHeight - ball.clientHeight;
+
+function handleOrientation(event) {
+  var x = event.beta;  // In degree in the range [-180,180]
+  var y = event.gamma; // In degree in the range [-90,90]
+
+  output.innerHTML  = "beta : " + x + "\n";
+  output.innerHTML += "gamma: " + y + "\n";
+
+  // Because we don't want to have the device upside down
+  // We constrain the x value to the range [-90,90]
+  if (x >  90) { x =  90};
+  if (x < -90) { x = -90};
+
+  // To make computation easier we shift the range of
+  // x and y to [0,180]
+  x += 90;
+  y += 90;
+
+  // 10 is half the size of the ball
+  // It center the positioning point to the center of the ball
+  ball.style.top  = (maxX*x/180 - 10) + "px";
+  ball.style.left = (maxY*y/180 - 10) + "px";
+}
+
+window.addEventListener('deviceorientation', handleOrientation);
+
+ +

這裡有即時結果 (若無法顯示,可至本文右上角切換回英文原文觀看):

+ +
{{EmbedLiveSample('Orientation_example', '230', '260')}}
+ +
+

警告:Chrome 與 Firefox 處理角度的方式不同,所以某些軸線可能方向顛倒。

+
+ +

處理動向事件

+ +

動向事件與方向事件的處理方式完全相同,但動向事件擁有自己的名稱:{{event("devicemotion")}}

+ +
window.addEventListener("devicemotion", handleMotion, true);
+ +

真正改變的是由 {{domxref("DeviceMotionEvent")}} 物件所提供的資訊;且該物件又作為 HandleMotion 函式的參數。

+ +

動向事件共有 4 組屬性:

+ + + +

動向值說明

+ +

{{domxref("DeviceMotionEvent")}} 物件將提供「裝置位置與方向的變化速度」的相關資訊,並根據 3 組軸線 (可參閱方向與動向資料說明的細節) 提供變化情形。

+ +

針對 {{domxref("DeviceMotionEvent.acceleration","acceleration")}} 與 {{domxref("DeviceMotionEvent.accelerationIncludingGravity","accelerationIncludingGravity")}},這些軸線將對應:

+ + + +

針對稍有差異的 {{domxref("DeviceMotionEvent.rotationRate","rotationRate")}},則資訊將對應:

+ + + +

最後,{{domxref("DeviceMotionEvent.interval","interval")}} 代表以毫秒(Millisecond)為單位的時間間隔,是裝置取得資料的頻率。

+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Device Orientation')}}{{Spec2('Device Orientation')}}Initial specification.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
{{domxref("DeviceOrientationEvent")}}7.0{{CompatVersionUnknown}}3.6[1]
+ 6
{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("DeviceMotionEvent")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}6{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
{{domxref("DeviceOrientationEvent")}}3.0{{CompatVersionUnknown}}3.6[1]
+ 6
{{CompatNo}}{{CompatNo}}4.2
{{domxref("DeviceMotionEvent")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}6{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Firefox 3.6 to 5 supported mozOrientation versus the standard {{domxref("DeviceOrientationEvent")}} event.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/devicemotionevent/index.html b/files/zh-tw/web/api/devicemotionevent/index.html new file mode 100644 index 0000000000..f21723a1e3 --- /dev/null +++ b/files/zh-tw/web/api/devicemotionevent/index.html @@ -0,0 +1,116 @@ +--- +title: DeviceMotionEvent +slug: Web/API/DeviceMotionEvent +translation_of: Web/API/DeviceMotionEvent +--- +

{{apiref("Device Orientation Events")}}{{SeeCompatTable}}

+ +

概要

+ +

DeviceMotionEvent 提供了網頁開發者關於裝置位置及旋轉方向改變時的速度資訊。

+ +
+

Warning: Currently, Firefox and Chrome does not handle the coordinates the same way. Take care about this while using them.

+
+ +

屬性

+ +
+
{{domxref("DeviceMotionEvent.acceleration")}} {{readonlyinline}}
+
An object giving the acceleration of the device on the three axis X, Y and Z. Acceleration is expressed in m/s2.
+
{{domxref("DeviceMotionEvent.accelerationIncludingGravity")}} {{readonlyinline}}
+
An object giving the acceleration of the device on the three axis X, Y and Z with the effect of gravity. Acceleration is expressed in m/s2.
+
{{domxref("DeviceMotionEvent.rotationRate")}} {{readonlyinline}}
+
An object giving the rate of change of the device's orientation on the three orientation axis alpha, beta and gamma. Rotation rate is express in degrees per seconds.
+
{{domxref("DeviceMotionEvent.interval")}} {{readonlyinline}}
+
A number representing the interval of time, in milliseconds, at which data is obtained from the device.
+
+ +

範例

+ +
window.addEventListener('devicemotion', function(event) {
+  console.log(event.acceleration.x + ' m/s2');
+});
+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Device Orientation')}}{{Spec2('Device Orientation')}}Initial specification.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{ CompatVersionUnknown() }}{{CompatVersionUnknown}}{{CompatGeckoDesktop("6")}}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{ CompatVersionUnknown() }}{{CompatVersionUnknown}}{{CompatGeckoMobile("6")}}{{ CompatNo() }}{{ CompatNo() }}4.2
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/deviceorientationevent/index.html b/files/zh-tw/web/api/deviceorientationevent/index.html new file mode 100644 index 0000000000..38bc8f5261 --- /dev/null +++ b/files/zh-tw/web/api/deviceorientationevent/index.html @@ -0,0 +1,122 @@ +--- +title: DeviceOrientationEvent +slug: Web/API/DeviceOrientationEvent +translation_of: Web/API/DeviceOrientationEvent +--- +

{{apiref("Device Orientation Events")}}{{SeeCompatTable}}

+ +

DeviceOrientationEvent 提供了網頁開發者關於目前瀏覽頁面之裝置的物理旋轉方向資訊。

+ +
+

Warning: Currently, Firefox and Chrome do not handle the coordinates the same way. Take care about this while using them.

+
+ +

屬性

+ +
+
{{domxref("DeviceOrientationEvent.absolute")}} {{readonlyinline}}
+
A boolean that indicates whether or not the device is providing orientation data absolutely.
+
{{domxref("DeviceOrientationEvent.alpha")}} {{readonlyinline}}
+
A number representing the motion of the device around the z axis, express in degrees with values ranging from 0 to 360
+
{{domxref("DeviceOrientationEvent.beta")}} {{readonlyinline}}
+
A number representing the motion of the device around the x axis, express in degrees with values ranging from -180 to 180. This represents a front to back motion of the device.
+
{{domxref("DeviceOrientationEvent.gamma")}} {{readonlyinline}}
+
A number representing the motion of the device around the y axis, express in degrees with values ranging from -90 to 90. This represents a left to right motion of the device.
+
+ +

範例

+ +
window.addEventListener('deviceorientation', function(event) {
+  console.log(event.alpha + ' : ' + event.beta + ' : ' + event.gamma);
+});
+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Device Orientation')}}{{Spec2('Device Orientation')}}Initial specification.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support7.0 [1]{{CompatVersionUnknown}}6 [2]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
Basic support3.0{{CompatVersionUnknown}} [1]{{CompatVersionUnknown}}6 [2]{{CompatNo}}{{CompatNo}}4.2{{CompatVersionUnknown}} [1]
+
+ +

[1] Before version 50, Chrome provided absolute values instead of relative values for this event. Developers still needing absolute values may use the {{domxref("ondeviceorientationabsolute")}} event.

+ +

[2] Firefox 3.6, 4, and 5 supported mozOrientation instead of the standard DeviceOrientationEvent interface

+ +

參見

+ + diff --git a/files/zh-tw/web/api/document.createtreewalker/index.html b/files/zh-tw/web/api/document.createtreewalker/index.html new file mode 100644 index 0000000000..9e74411a14 --- /dev/null +++ b/files/zh-tw/web/api/document.createtreewalker/index.html @@ -0,0 +1,224 @@ +--- +title: Document.createTreeWalker() +slug: Web/API/document.createTreeWalker +translation_of: Web/API/Document/createTreeWalker +--- +
+ {{ApiRef("Document")}}
+

Document.createTreeWalker() 方法,能建立一個 {{domxref("TreeWalker")}} 物件並傳回.

+

語法

+
treeWalker = document.createTreeWalker(root, whatToShow, filter, entityReferenceExpansion);
+
+

參數

+
+
+ root
+
+ 是這個 {{domxref("TreeWalker")}} 遍歷的根節點(root {{domxref("Node")}}). Typically this will be an element owned by the document.
+
+ whatToShow {{optional_inline}}
+
+ Is an optional unsigned long representing a bitmask created by combining the constant properties of NodeFilter. 它是一種方便的方法,用來過濾某些類型的節點。 It defaults to 0xFFFFFFFF representing the SHOW_ALL constant.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Constant數值說明
NodeFilter.SHOW_ALL-1 (that is the max value of unsigned long)顯示所有節點.
NodeFilter.SHOW_ATTRIBUTE {{deprecated_inline}}2Shows attribute {{ domxref("Attr") }} nodes. This is meaningful only when creating a {{ domxref("TreeWalker") }} with an {{ domxref("Attr") }} node as its root; in this case, it means that the attribute node will appear in the first position of the iteration or traversal. Since attributes are never children of other nodes, they do not appear when traversing over the document tree.
NodeFilter.SHOW_CDATA_SECTION {{deprecated_inline}}8Shows {{ domxref("CDATASection") }} nodes.
NodeFilter.SHOW_COMMENT128Shows {{ domxref("Comment") }} nodes.
NodeFilter.SHOW_DOCUMENT256Shows {{ domxref("Document") }} nodes.
NodeFilter.SHOW_DOCUMENT_FRAGMENT1024Shows {{ domxref("DocumentFragment") }} nodes.
NodeFilter.SHOW_DOCUMENT_TYPE512Shows {{ domxref("DocumentType") }} nodes.
NodeFilter.SHOW_ELEMENT1Shows {{ domxref("Element") }} nodes.
NodeFilter.SHOW_ENTITY {{deprecated_inline}}32Shows {{ domxref("Entity") }} nodes. This is meaningful only when creating a {{ domxref("TreeWalker") }} with an {{ domxref("Entity") }} node as its root; in this case, it means that the {{ domxref("Entity") }} node will appear in the first position of the traversal. Since entities are not part of the document tree, they do not appear when traversing over the document tree.
NodeFilter.SHOW_ENTITY_REFERENCE {{deprecated_inline}}16Shows {{ domxref("EntityReference") }} nodes.
NodeFilter.SHOW_NOTATION {{deprecated_inline}}2048Shows {{ domxref("Notation") }} nodes. This is meaningful only when creating a {{ domxref("TreeWalker") }} with a {{ domxref("Notation") }} node as its root; in this case, it means that the {{ domxref("Notation") }} node will appear in the first position of the traversal. Since entities are not part of the document tree, they do not appear when traversing over the document tree.
NodeFilter.SHOW_PROCESSING_INSTRUCTION64Shows {{ domxref("ProcessingInstruction") }} nodes.
NodeFilter.SHOW_TEXT4顯示文字節點({{ domxref("Text") }} nodes).
+
+
+ filter {{optional_inline}}
+
+ 是一個可選的 {{domxref("NodeFilter")}}, 這是一個物件有著 acceptNode 方法, 這方法被 {{domxref("TreeWalker")}} 呼叫來決定是否接受通過 whatToShow 檢查的節點.
+
+ entityReferenceExpansion {{optional_inline}} {{obsolete_inline}}
+
+ Is a {{domxref("Boolean")}} flag indicating if when discarding an {{domxref("EntityReference")}} its whole sub-tree must be discarded at the same time.
+
+

Example

+

The following example goes through all nodes in the body, reduces the set of nodes to elements, simply passes through as acceptable each node (it could reduce the set in the acceptNode() method instead), and then makes use of tree walker iterator that is created to advance through the nodes (now all elements) and push them into an array.

+
var treeWalker = document.createTreeWalker(
+  document.body,
+  NodeFilter.SHOW_ELEMENT,
+  { acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } },
+  false
+);
+
+var nodeList = [];
+
+while(treeWalker.nextNode()) nodeList.push(treeWalker.currentNode);
+
+

Specifications

+ + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-document-createtreewalker', 'Document.createTreeWalker')}}{{Spec2('DOM WHATWG')}}Removed the expandEntityReferences parameter.
+ Made the whatToShow and filter parameters optionals.
{{SpecName('DOM2 Traversal_Range', 'traversal.html#NodeIteratorFactory-createTreeWalker', 'Document.createTreeWalker')}}{{Spec2('DOM2 Traversal_Range')}}Initial definition.
+

Browser compatibility

+

{{CompatibilityTable}}

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0{{CompatGeckoDesktop("1.8.1")}}9.09.03.0
whatToShow and filter optional1.0{{CompatGeckoDesktop("12")}}{{CompatNo}}{{CompatVersionUnknown}}3.0
expandEntityReferences {{obsolete_inline}}1.0{{CompatGeckoDesktop("1.8.1")}}
+ Removed in {{CompatGeckoDesktop("12")}}
9.09.03.0
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatGeckoMobile("1.8.1")}}{{CompatVersionUnknown}}9.03.0
whatToShow and filter optional{{CompatVersionUnknown}}{{CompatGeckoDesktop("12")}}{{CompatNo}}{{CompatVersionUnknown}}3.0
expandEntityReferences {{obsolete_inline}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.8.1")}}
+ Removed in {{CompatGeckoDesktop("12")}}
{{CompatVersionUnknown}}9.03.0
+
+

See also

+ diff --git a/files/zh-tw/web/api/document/body/index.html b/files/zh-tw/web/api/document/body/index.html new file mode 100644 index 0000000000..a33d2a7901 --- /dev/null +++ b/files/zh-tw/web/api/document/body/index.html @@ -0,0 +1,128 @@ +--- +title: Document.body +slug: Web/API/Document/body +translation_of: Web/API/Document/body +--- +
{{APIRef("DOM")}}
+ +

回傳目前文件的 {{HTMLElement("body")}} 或 {{HTMLElement("frameset")}} 節點,如元素不存在則回傳 null

+ +

語法

+ +
var objRef = document.body;
+document.body = objRef;
+ +

範例

+ +
// in HTML: <body id="oldBodyElement"></body>
+alert(document.body.id); // "oldBodyElement"
+
+var aNewBodyElement = document.createElement("body");
+
+aNewBodyElement.id = "newBodyElement";
+document.body = aNewBodyElement;
+alert(document.body.id); // "newBodyElement"
+
+ +

備註

+ +

document.body is the element that contains the content for the document. In documents with <body> contents, returns the <body> element, and in frameset documents, this returns the outermost <frameset> element.

+ +

Though body is settable, setting a new body on a document will effectively remove all the current children of the existing <body> element.

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG','dom.html#dom-document-body','Document.body')}}{{Spec2('HTML WHATWG')}} 
{{SpecName('HTML5.1','dom.html#dom-document-body','Document.body')}}{{Spec2('HTML5.1')}} 
{{SpecName('HTML5 W3C','dom.html#dom-document-body','Document.body')}}{{Spec2('HTML5 W3C')}} 
{{SpecName('DOM2 HTML','html.html#ID-56360201','Document.body')}}{{Spec2('DOM2 HTML')}} 
{{SpecName('DOM1','level-one-html.html#attribute-body','Document.body')}}{{Spec2('DOM1')}}Initial definition.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1{{CompatVersionUnknown}}269.6 (possibly earlier)4 (possibly earlier)
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}5 (probably earlier)
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/document/createdocumentfragment/index.html b/files/zh-tw/web/api/document/createdocumentfragment/index.html new file mode 100644 index 0000000000..efdd4c31e6 --- /dev/null +++ b/files/zh-tw/web/api/document/createdocumentfragment/index.html @@ -0,0 +1,136 @@ +--- +title: Document.createDocumentFragment() +slug: Web/API/Document/createDocumentFragment +tags: + - API + - DOM + - 參考 + - 文本片段 + - 方法 +translation_of: Web/API/Document/createDocumentFragment +--- +
{{ApiRef("DOM")}}
+ +

建立新的 {{domxref("DocumentFragment")}}.

+ +

語法

+ +
var fragment = document.createDocumentFragment();
+
+ +

fragment 是 {{domxref("DocumentFragment")}} 的一個參考物件。

+ +

描述

+ +

DocumentFragments 是 DOM 節點(Nodes)。他們不會成為 DOM主幹的一部份。最常見的作法是先建立文本片段 (document fragment),然後將元素 (element) 加入文本片段中,最後再將文本片段加入 DOM 樹中。在 DOM 樹中,文本片段將會被他所有的子元素取代。

+ +

正因為文本片段是存在記憶體中,並且不是 DOM 主幹的一部分,增加子元素並不會導致網頁重刷 (reflow)(重新計算元素的位置和幾何)。因此採用文本片段通常會有比較好的效能表現 (better performance)。

+ +

舉例

+ +

這個例子中用清單來呈現主流瀏覽器。

+ +

HTML

+ +
<ul id="ul">
+</ul>
+ +

JavaScript

+ +
var element  = document.getElementById('ul'); // assuming ul exists
+var fragment = document.createDocumentFragment();
+var browsers = ['Firefox', 'Chrome', 'Opera',
+    'Safari', 'Internet Explorer'];
+
+browsers.forEach(function(browser) {
+    var li = document.createElement('li');
+    li.textContent = browser;
+    fragment.appendChild(li);
+});
+
+element.appendChild(fragment);
+
+ +

結果

+ +

jsfiddle 上看範例結果。

+ +

規格

+ + + + + + + + + + + + + + + + +
規格狀態註解
{{SpecName('DOM WHATWG', '#dom-document-createdocumentfragment', 'Document.createDocumentFragment()')}}{{Spec2('DOM WHATWG')}}Initial definition in the DOM 1 specification.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
特色Firefox (Gecko)ChromeEdgeInternet ExplorerOperaSafari
基礎支援{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
特色Firefox Mobile (Gecko)AndroidEdgeIE MobileOpera MobileSafari Mobile
基礎支援{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

更多參考

+ + diff --git a/files/zh-tw/web/api/document/createelement/index.html b/files/zh-tw/web/api/document/createelement/index.html new file mode 100644 index 0000000000..2d847004cc --- /dev/null +++ b/files/zh-tw/web/api/document/createelement/index.html @@ -0,0 +1,179 @@ +--- +title: Document.createElement() +slug: Web/API/Document/createElement +translation_of: Web/API/Document/createElement +--- +
{{APIRef("DOM")}}
+ +

HTML 文件中,Document.createElement() 方法可以依指定的標籤名稱(tagName)建立 HTML 元素,或是在未定義標籤名稱下建立一個 {{domxref("HTMLUnknownElement")}}。在 XUL 文件中,Document.createElement() 將會建立指定的 XUL 元素。而在其它文件,則會建立一個 namespace URI 為 null 的元素。

+ +

若要明確指定元素的 namespace URI,請使用 document.createElementNS()

+ +

語法

+ +
var element = document.createElement(tagName[, options]);
+
+ +

參數

+ +
+
tagName
+
一個指定類型給所創建的元素的字串。{{domxref("Node.nodeName", "nodeName")}} 創建的元素由 tagName 的值初始,不要使用吻合名稱(例如 "html:a")。當該方法在 HTML 文件中被調用時,createElement() 會先將 tagName 轉化為小寫後再創建元素。在 Firefox、Opera 和 Chrome,createElement(null) 與 createElement("null") 作用相同。
+
options{{optional_inline}}
+
選擇性 ElementCreationOptions 物件包含一個屬性 is,它的值是先前使用customElements.define() 所定義的自定義元素的標籤名稱。為了與以前的 自定義元素規範 相容,一些瀏覽器將允許你在此傳遞一個字串而非物件,其字串的值就是自定義元件的標籤名稱。了解更多訊息以及如何使用此參數,可以參閱 擴展原生 HTML 元素 。
+
新元素將被賦予一個 is 屬性,其值就是自定義元素的標籤名稱。自定義元素算是實驗中的功能,因此目前只作用於部分瀏覽器中。
+
+ +

回傳值

+ +

一個新的 Element.

+ +

範例

+ +

這邊創建一個新的 <div> ,並將它插入到 ID div1 之前。

+ +

HTML

+ +
<!DOCTYPE html>
+<html>
+<head>
+  <title>||Working with elements||</title>
+</head>
+<body>
+  <div id="div1">The text above has been created dynamically.</div>
+</body>
+</html>
+
+ +

JavaScript

+ +
document.body.onload = addElement;
+
+function addElement () {
+  // create a new div element
+  // and give it some content
+  var newDiv = document.createElement("div");
+  var newContent = document.createTextNode("Hi there and greetings!");
+  newDiv.appendChild(newContent); //add the text node to the newly created div.
+
+  // add the newly created element and its content into the DOM
+  var currentDiv = document.getElementById("div1");
+  document.body.insertBefore(newDiv, currentDiv);
+}
+ +

{{EmbedLiveSample("Example", 500, 50)}}

+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', "#dom-document-createelement", "Document.createElement")}}{{Spec2('DOM WHATWG')}}
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}[1][2]{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
options argument{{CompatVersionUnknown}}[3]{{CompatUnknown}}{{CompatGeckoDesktop(50)}}[4][5]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari MobileChrome for Android
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
options argument{{CompatVersionUnknown}}{{CompatVersionUnknown}}[3]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}[3]
+
+ +

[1] Starting with Gecko 22.0 {{geckoRelease("22.0")}} createElement() no longer uses the {{domxref("HTMLSpanElement")}} interface when the argument is "bgsounds", "multicol", or "image".  Instead, HTMLUnknownElement is used for "bgsound" and "multicol" and {{domxref("HTMLElement")}} HTMLElement is used for "image".

+ +

[2] The Gecko implementation of createElement doesn't conform to the DOM spec for XUL and XHTML documents: localName and namespaceURI are not set to null on the created element. See {{ Bug(280692) }} for details.

+ +

[3] In previous versions of the specification, this argument was just a string whose value was the custom element's tag name. For example: document.createElement("button", "custom-button") rather than document.createElement("button", {id: "custom-button"}). For the sake of backwards compatibility, Chrome accepts both forms.

+ +

[4] See [3] above: like Chrome, Firefox accepts a string instead of an object here, but only from version 51 onwards. In version 50,  options must be an object.

+ +

[5] To experiment with custom elements in Firefox, you must set the dom.webcomponents.enabled and dom.webcomponents.customelements.enabled preferences to true.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/document/createrange/index.html b/files/zh-tw/web/api/document/createrange/index.html new file mode 100644 index 0000000000..93703c54bb --- /dev/null +++ b/files/zh-tw/web/api/document/createrange/index.html @@ -0,0 +1,33 @@ +--- +title: Document.createRange() +slug: Web/API/Document/createRange +translation_of: Web/API/Document/createRange +--- +
{{APIRef("DOM")}}
+ +

回傳一 {{domxref("Range")}} 物件。

+ +

語法

+ +
range = document.createRange();
+
+ +

創造 range 為 {{domxref("Range")}} 物件.

+ +

示例

+ +
var range = document.createRange();
+
+range.setStart(startNode, startOffset);
+range.setEnd(endNode, endOffset);
+
+ +

註意

+ +

當  Range 被創建之後,必須先設定其範圍初始點及結束點, 才能使用大部分 {{domxref("Range")}} 所提供的方法。

+ +

規範

+ + diff --git a/files/zh-tw/web/api/document/createtextnode/index.html b/files/zh-tw/web/api/document/createtextnode/index.html new file mode 100644 index 0000000000..80d3d562b9 --- /dev/null +++ b/files/zh-tw/web/api/document/createtextnode/index.html @@ -0,0 +1,120 @@ +--- +title: Document.createTextNode() +slug: Web/API/Document/createTextNode +translation_of: Web/API/Document/createTextNode +--- +
{{APIRef("DOM")}}
+ +

創建一個新的文字節點.

+ +

Syntax

+ +
var text = document.createTextNode(data);
+
+ + + +

Example

+ +
<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>createTextNode example</title>
+<script>
+function addTextNode(text) {
+  var newtext = document.createTextNode(text),
+      p1 = document.getElementById("p1");
+
+  p1.appendChild(newtext);
+}
+</script>
+</head>
+
+<body>
+  <button onclick="addTextNode('YES! ');">YES!</button>
+  <button onclick="addTextNode('NO! ');">NO!</button>
+  <button onclick="addTextNode('WE CAN! ');">WE CAN!</button>
+
+  <hr />
+
+  <p id="p1">First line of paragraph.</p>
+</body>
+</html>
+
+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("DOM3 Core", "core.html#ID-1975348127", "Document.createTextNode()")}}{{Spec2("DOM3 Core")}}No change
{{SpecName("DOM2 Core", "core.html#ID-1975348127", "Document.createTextNode()")}}{{Spec2("DOM2 Core")}}Initial definition
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
diff --git a/files/zh-tw/web/api/document/defaultview/index.html b/files/zh-tw/web/api/document/defaultview/index.html new file mode 100644 index 0000000000..58905ebdeb --- /dev/null +++ b/files/zh-tw/web/api/document/defaultview/index.html @@ -0,0 +1,94 @@ +--- +title: Document.defaultView +slug: Web/API/Document/defaultView +translation_of: Web/API/Document/defaultView +--- +
{{ApiRef}}
+ +

在瀏覽器中,document.defaultView 屬性會指向一個目前 {{Glossary("Browsing_context", "document")}} 所屬的 {{domxref("Window", "window")}} 物件,若無則為 null

+ +

語法

+ +
var win = document.defaultView;
+ +

此為唯讀屬性。

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#dom-document-defaultview', 'Document.defaultView')}}{{Spec2('HTML WHATWG')}}No change
{{SpecName('HTML5 W3C', 'browsers.html#dom-document-defaultview', 'Document.defaultView')}}{{Spec2('HTML5 W3C')}}Initial definition
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox (Gecko)ChromeEdgeInternet ExplorerEdgeOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatIE("9.0")}}0.10{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox Mobile (Gecko)AndroidEdgeIE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
diff --git a/files/zh-tw/web/api/document/designmode/index.html b/files/zh-tw/web/api/document/designmode/index.html new file mode 100644 index 0000000000..9f04db7952 --- /dev/null +++ b/files/zh-tw/web/api/document/designmode/index.html @@ -0,0 +1,114 @@ +--- +title: Document.designMode +slug: Web/API/Document/designMode +tags: + - API + - Document + - HTML DOM + - NeedsBrowserCompatibility + - Property +translation_of: Web/API/Document/designMode +--- +
{{ ApiRef() }}
+ +
 
+ +

概要

+ +

document.designMode 控制整個文件是否能夠編輯。可用的數值是 "on""off"。根據規範,這個屬性預設值為 "off"。Firefox 遵從這個標準。較早以前的 Chrome 和 IE 預設值是 "inherit"。從 Chrome 43 起,預設值是 「off」;不再支援「inherit」。在 IE6-10 中,數值為大寫英文字母。

+ +

語法

+ +
var mode = document.designMode;
+document.designMode = "on";
+document.designMode = "off";
+ +

範例

+ +

讓 {{HTMLElement("iframe")}} 的文件可以給使用者編輯:

+ +
iframeNode.contentDocument.designMode = "on";
+
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('HTML WHATWG', '#making-entire-documents-editable:-the-designmode-idl-attribute', 'designMode')}}{{Spec2('HTML WHATWG')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
功能ChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
基本支援{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
功能AndroidAndroid WebviewEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
基本支援{{CompatNo}}{{ CompatVersionUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatVersionUnknown() }}
+
+ +

參考

+ + diff --git a/files/zh-tw/web/api/document/documentelement/index.html b/files/zh-tw/web/api/document/documentelement/index.html new file mode 100644 index 0000000000..aa3f5db82d --- /dev/null +++ b/files/zh-tw/web/api/document/documentelement/index.html @@ -0,0 +1,60 @@ +--- +title: Document.documentElement +slug: Web/API/Document/documentElement +translation_of: Web/API/Document/documentElement +--- +

{{ ApiRef("DOM") }}

+ +

Document.documentElement 會回傳目前文件({{domxref("document")}})中的根元素({{domxref("Element")}}),如:HTML 文件中的 <html> 元素。

+ +

語法

+ +
var element = document.documentElement;
+
+ +

範例

+ +
var rootElement = document.documentElement;
+var firstTier = rootElement.childNodes;
+
+// firstTier is the NodeList of the direct children of the root element
+for (var i = 0; i < firstTier.length; i++) {
+   // do something with each direct kid of the root element
+   // as firstTier[i]
+}
+ +

備註

+ +

對於所有非空的 HTML 文件, document.documentElement 將會是一個 {{HTMLElement("html")}}  元素 ; 對於所有非空的 XML 文件,document.documentElement 則會是文件的根元素。

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態 備註
{{SpecName('DOM2 Core','core.html#ID-87CD092','Document.documentElement')}}{{Spec2('DOM2 Core')}} 
{{SpecName('DOM3 Core','core.html#ID-87CD092','Document.documentElement')}}{{Spec2('DOM3 Core')}} 
{{SpecName('DOM4','#dom-document-documentelement','Document.documentElement')}}{{Spec2('DOM4')}} 
{{SpecName('DOM WHATWG','#dom-document-documentelement','Document.documentElement')}}{{Spec2('DOM WHATWG')}} 
diff --git a/files/zh-tw/web/api/document/execcommand/index.html b/files/zh-tw/web/api/document/execcommand/index.html new file mode 100644 index 0000000000..c06cd0d89c --- /dev/null +++ b/files/zh-tw/web/api/document/execcommand/index.html @@ -0,0 +1,172 @@ +--- +title: Document.execCommand() +slug: Web/API/Document/execCommand +translation_of: Web/API/Document/execCommand +--- +
{{ApiRef("DOM")}}{{Obsolete_header}}
+ +

當 HTML 文件(document)被切換到 designMode 時,它的 document 物件就會對外暴露 execCommand 方法作為操控目前可編輯區域的指令,譬如 form inputscontentEditable 元素。

+ +

多數的指令會作用在文件的選取 (粗體、斜體等),而其他則像是插入新的元素(新增一個連結)或是影響一整列的文字(縮排)。當使用 contentEditable 時, execCommand() 會作用在目前活躍的可編輯元素上。

+ +

語法

+ +
document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)
+
+ +

回傳值

+ +

如果該指令不被支援或停用將回傳一個 false 的 {{jsxref('Boolean')}} 值。

+ +
+

備註:只有在使用者互動的部分回傳 true 。請不要嘗試在呼叫指令前使用回傳值來確認瀏覽器是否支援。

+
+ +

參數

+ +
+
aCommandName
+
一個 {{domxref("DOMString")}} 作為指定要執行的指令。所有可用的指令列表請見 {{anch("Commands")}} 。
+
aShowDefaultUI
+
一個 {{jsxref("Boolean")}} 作為指示是否顯示預設的使用者介面。 Mozilla 並未實作這項功能。
+
aValueArgument
+
針對需要提供輸入引數的指令,藉由 {{domxref("DOMString")}} 提供相關的資訊。譬如, insertImage 需要提供圖片的 URL 。若沒有引數的需求則可指定為 null
+
+ +

指令

+ +
+
backColor
+
變更文件的背景色彩。在 styleWithCss 模式中,它作用於涵蓋區域的背景色彩。這個指令需要提供一個 {{cssxref("<color>")}} 值字串作為引數值。請留意, Internet Explorer 使用這個指令作為設定文字的背景色彩。
+
bold
+
切換選取區域插入點的粗體與否。 Internet Explorer 使用 {{HTMLElement("strong")}} 標籤而不是 {{HTMLElement("b")}}.
+
ClearAuthenticationCache
+
清除所有快取中的驗證憑證。
+
contentReadOnly
+
使內容文件成為唯讀或可編輯。此指令需要提供布林值 true/false 作為引數值。(Internet Explorer 不支援)。
+
copy
+
複製目前選取的區域到剪貼簿。各個瀏覽器對於這個指令的行為可能有所差異且不斷變更。如果你有使用這個指令的情境,請先查閱相容性表格來決定如何使用。
+
createLink
+
對選取的區域建立超連結,僅限於有選取內容。需要提供一個 URI 字串值作為超連結的 href 。 URI 必須最少包含一個字元且可以是空白字元(Internet Explorer 會建立一個 null 值的連結)。
+
cut
+
移除目前選取的區域並複製到剪貼簿。各個瀏覽器對於這個指令的行為可能有所差異且不斷變更。使用細節請查閱相容性表格
+
decreaseFontSize
+
在選取區域或插入點的前後加入一個 {{HTMLElement("small")}} 標籤( Internet Explorer 不支援)
+
defaultParagraphSeparator
+
變更可編輯文字區域於新增段落時的段落分隔器。更多細節請查閱 產生 markup 的區別
+
delete
+
刪除目前選取的區域。
+
enableAbsolutePositionEditor
+
啟用或停用用於移動絕對定位元素的抓取器。這個指令在 Firefox 63 Beta/Dev 版本中預設停用({{bug(1449564)}})。
+
enableInlineTableEditing
+
啟用或停用表格的列 / 欄的插入及刪除。此指令在 Firefox 63 Beta/Dev 版本中預設停用 ({{bug(1449564)}})。
+
enableObjectResizing
+
啟用或停用圖片、表格、絕對定位元素、其他可重設大小物件的重設大小處理。此指令在 Firefox 63 Beta/Dev 版本中預設停用 ({{bug(1449564)}})。
+
fontName
+
變更選取區域或插入點的字型名稱。此指令需要字型名稱字串(如「Arial」)作為引數值。
+
fontSize
+
變更選取區域或插入點的字型大小。此指令需要 1-7 的整數作為引數值。
+
foreColor
+
變更選取區域或插入點的字型色彩。此指令需要十六進位的色彩字串作為引數值。
+
formatBlock
+
在目前選取區域的前後加入一個 HTML 區塊層級元素,若選取區域已經存在區塊元素則取代之。(在 Firefox 中, {{HTMLElement("blockquote")}} 是個例外——它會包裹住任何所包含的區塊元素)。 此指令需要一個標籤名稱字串作為引數值。幾乎所有區塊層級元素都可以使用(Internet Explorer and Edge 僅支援標題標籤 H1H6ADDRESSPRE 且必須由角括號包裹起來,譬如 "<H1>" )。
+
forwardDelete
+
刪除游標位置後的字元,等同於在 Windows 按下 Delete 鍵盤按鍵。
+
heading
+
在選取區域或插入點前後加入一個標題元素。此指令需要標籤名稱字串作為引數值(例:"H1", "H6" )(Internet Explorer 及 Safari 不支援)。
+
hiliteColor
+
變更選取區域或插入點的背景色彩。此指令需要一個色彩字串作為引數值。 useCSS 必須為 true 才能有作用(Internet Explorer 不支援)。
+
increaseFontSize
+
在選取區域或插入點前後加入一個 {{HTMLElement("big")}} 標題(Internet Explorer 不支援)。
+
indent
+
縮排選取區域或插入點所包含的列。在 Firefox ,如果選取的範圍跨越多列且不同的縮排層級,只有選取中最淺層縮排列的才會被縮排。
+
insertBrOnReturn
+
控制 Enter 按鍵按下時在目前區塊元素中插入 {{HTMLElement("br")}} 元素或分割成為兩個元素(Internet Explorer 不支援)。
+
insertHorizontalRule
+
在插入點插入一個 {{HTMLElement("hr")}} 元素或以它取代選取的內容。
+
insertHTML
+
在插入點插入一個 HTML 字串(會刪除選取內容)需要一個有效的 HTML 字串作為引數值(Internet Explorer 不支援)。
+
insertImage
+
在插入點插入一個圖片(會刪除選取內容)。需要一個 URL 字串作為圖片的 src 引數值。這個需求跟 createLink 的字串是一樣的。
+
insertOrderedList
+
在選取區域或插入點建立一個有序的清單
+
insertUnorderedList
+
在選取區域或插入點建立一個無序的清單
+
insertParagraph
+
在選取區域或目前列的前後插入段落(Internet Explorer 會在插入點插入段落並刪除選取的內容)。
+
insertText
+
在插入點處插入給予的純文字(選取內容將被刪除)。
+
italic
+
切換選取區域或插入點的斜體開關(Internet Explorer 使用 {{HTMLElement("em")}} 元素而不是 {{HTMLElement("i")}} )。
+
justifyCenter
+
置中對齊選取區域或插入點的內容。
+
justifyFull
+
左右對齊選取區域或插入點的內容。
+
justifyLeft
+
靠左對齊選取區域或插入點的內容。
+
justifyRight
+
靠右對齊選取區域或插入點的內容。
+
outdent
+
凸排選取區域或插入點所包含的列。
+
paste
+
在目前的插入點貼上剪貼簿的內容(取代目前選取的項目)。網頁內容無法使用。詳閱 [1]。
+
redo
+
復原上一個取消的指令。
+
removeFormat
+
移除目前選取區域所有的格式。
+
selectAll
+
選取可編輯區域的所有內容。
+
strikeThrough
+
切換選取區域或插入點的刪除線開關。
+
subscript
+
切換選取區域或插入點的 subscript 開關。
+
superscript
+
切換選取區域或插入點的 superscript 開關。
+
underline
+
切換選取區域或插入點的底線開關。
+
undo
+
取消上一個執行的指令。
+
unlink
+
從選取的超連結刪除錨點元素
+
useCSS {{Deprecated_inline}}
+
針對產生的 markup 使用 HTML 標籤或 CSS。此指令需要一個布林值 true/false 作為引數值。
+
注意:這個引述在邏輯上是反向的(舉例:使用 false 會使用 CSS ,反之使用 true 則使用 HTML 且 Internet Explorer 不支援。這個指令已經被棄用並由 styleWithCSS 取而代之。
+
styleWithCSS
+
取代 useCSS 的指令。 true 會在 markup 修改 / 產生 style 屬性, false 會產生展示用的元素。
+
+ +

範例

+ +

一個在 CodePen 上展示如果使用的範例。

+ +

規格

+ + + + + + + + + + + + + + +
規格狀態備註
execCommand
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Document.execCommand")}}

+ +

相關資訊

+ + diff --git a/files/zh-tw/web/api/document/forms/index.html b/files/zh-tw/web/api/document/forms/index.html new file mode 100644 index 0000000000..769d80871c --- /dev/null +++ b/files/zh-tw/web/api/document/forms/index.html @@ -0,0 +1,75 @@ +--- +title: Document.forms +slug: Web/API/Document/forms +translation_of: Web/API/Document/forms +--- +
{{APIRef("DOM")}}
+ +

forms 屬性會回傳一個包含目前頁面中所有 {{HTMLElement("form")}} 元素的集合物件(型別為 {{domxref("HTMLCollection")}})。

+ +

語法

+ +
collection = document.forms;
+ +

範例:取得表單資訊

+ +
<!DOCTYPE html>
+<html lang="en">
+
+<head>
+<title>document.forms example</title>
+</head>
+
+<body>
+
+<form id="robby">
+  <input type="button" onclick="alert(document.forms[0].id);" value="robby's form" />
+</form>
+
+<form id="dave">
+  <input type="button" onclick="alert(document.forms[1].id);" value="dave's form" />
+</form>
+
+<form id="paul">
+  <input type="button" onclick="alert(document.forms[2].id);" value="paul's form" />
+</form>
+
+</body>
+</html>
+
+ +

範例 2:取得表單內的元素

+ +
var selectForm = document.forms[index];
+var selectFormElement = document.forms[index].elements[index];
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#dom-document-forms', 'Document.forms')}}{{ Spec2('HTML WHATWG') }} 
{{SpecName('DOM2 HTML', 'html.html#ID-1689064', 'Document.forms')}}{{ Spec2('DOM2 Events') }}Initial definition.
+ +

參見

+ + diff --git a/files/zh-tw/web/api/document/getelementsbyclassname/index.html b/files/zh-tw/web/api/document/getelementsbyclassname/index.html new file mode 100644 index 0000000000..b66647c82d --- /dev/null +++ b/files/zh-tw/web/api/document/getelementsbyclassname/index.html @@ -0,0 +1,127 @@ +--- +title: Document.getElementsByClassName() +slug: Web/API/Document/getElementsByClassName +tags: + - 待翻譯 +translation_of: Web/API/Document/getElementsByClassName +--- +

{{APIRef("DOM")}}

+ +

針對所有給定的 class 子元素,回傳類似陣列的物件。當呼叫 document 物件時,它會搜尋整個文件,包括根節點在內。你也可以在所有元素呼叫 {{domxref("Element.getElementsByClassName", "getElementsByClassName()")}},那它就只會回傳含有給定 class 的特定根元素的後代元素。

+ +

表達式

+ +
var elements = document.getElementsByClassName(names); // or:
+var elements = rootElement.getElementsByClassName(names);
+ + + +

範例

+ +

取得所有 class 為 “test” 的元素:

+ +
document.getElementsByClassName('test');
+ +

取得所有 class 為 “test” 和 “red” 的元素:

+ +
document.getElementsByClassName('red test');
+ +

取得所有在 id 為 '“main” 的元素裡 class 為 “test” 的元素:

+ +
document.getElementById('main').getElementsByClassName('test');
+ +

我們也可以藉由傳遞 {{ domxref("HTMLCollection") }} 為 this 來使用 Array.prototype 的方法。下面的例子將會找到所有 class 為 “test” 的 div 元素:

+ +
var testElements = document.getElementsByClassName('test');
+var testDivs = Array.prototype.filter.call(testElements, function(testElement){
+    return testElement.nodeName === 'DIV';
+});
+ +

取得 class 是 test 的元素

+ +

這是最常用的操作方法:

+ +
<!doctype html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>Document</title>
+</head>
+<body>
+    <div id="parent-id">
+        <p>hello word1</p>
+        <p class="test">hello word2</p>
+        <p>hello word3</p>
+        <p>hello word4</p>
+    </div>
+    <script>
+        var parentDOM = document.getElementById("parent-id");
+
+        var test=parentDOM.getElementsByClassName("test");//test is not target element
+        console.log(test);//HTMLCollection[1]
+
+        var testTarget=parentDOM.getElementsByClassName("test")[0];//year , this element is target
+        console.log(testTarget);//<p class="test">hello word2</p>
+    </script>
+</body>
+</html>
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{ CompatVersionUnknown() }}3.09.0{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +

規範

+ + diff --git a/files/zh-tw/web/api/document/head/index.html b/files/zh-tw/web/api/document/head/index.html new file mode 100644 index 0000000000..7ecde675ea --- /dev/null +++ b/files/zh-tw/web/api/document/head/index.html @@ -0,0 +1,114 @@ +--- +title: Document.head +slug: Web/API/Document/head +translation_of: Web/API/Document/head +--- +

{{APIRef("DOM")}}

+ +

回傳當前文件的 {{HTMLElement("head")}} 元素。如果該文件有超過一個 <head> 元素,那只會回傳第一個 <head> 元素。

+ +

語法

+ +
var objRef = document.head;
+
+ +

範例

+ +
// in HTML: <head id="my-document-head">
+var aHead = document.head;
+
+alert(aHead.id); // "my-document-head";
+
+alert( document.head === document.querySelector("head") ); // true
+
+ +

備註

+ +

document.head 是「唯讀」。若是想要將 document.head 改成別的值會失敗,這時有些瀏覽器不會告知任何錯誤訊息;有些,例如在 ECMAScript Strict 模式下 的 Gecko 瀏覽器,會給出 TypeError 異常。

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG','dom.html#dom-document-head','Document.head')}}{{Spec2('HTML WHATWG')}}Initial definition.
{{SpecName('HTML5.1','dom.html#dom-document-head','Document.head')}}{{Spec2('HTML5.1')}} 
{{SpecName('HTML5 W3C','dom.html#dom-document-head','Document.head')}}{{Spec2('HTML5 W3C')}} 
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support4.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("2")}}9.011.05.0
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("2")}}9.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/document/index.html b/files/zh-tw/web/api/document/index.html new file mode 100644 index 0000000000..ca1c9830b7 --- /dev/null +++ b/files/zh-tw/web/api/document/index.html @@ -0,0 +1,446 @@ +--- +title: Document +slug: Web/API/Document +tags: + - API + - DOM + - Gecko + - MakeBrowserAgnostic + - NeedsTranslation + - Reference + - TopicStub +translation_of: Web/API/Document +--- +
{{APIRef}}
+ +
+ +

Document 介面代表所有在瀏覽器中載入的網頁,也是作為網頁內容 DOM 樹(包含如 {{HTMLElement("body")}}、{{HTMLElement("table")}} 與其它的{{domxref("Element", "元素")}})的進入點。Document 提供了網頁文件所需的通用函式,例如取得頁面 URL 或是建立網頁文件中新的元素節點等。

+ +

{{inheritanceDiagram}}

+ +

Document 介面描述了各種類型文件的共同屬性與方法。根據文件的類型(如 HTMLXML、SVG 等),也會擁有各自的 API:HTML 文件(content type 為 text/html)實作了 {{domxref("HTMLDocument")}} 介面,而 XML 及 SVG 文件實作了 {{domxref("XMLDocument")}} 介面。

+ +

請注意 window.document 物件為 HTMLDocument 所建構。

+ +

屬性

+ +

這個介面繼承了  {{domxref("Node")}} 以及 {{domxref("EventTarget")}} 介面。

+ +
+
{{domxref("Document.all")}} {{Deprecated_inline}} {{non-standard_inline}}
+
Provides access to all elements with an id. This is a legacy, non-standard interface and you should use the {{domxref("document.getElementById()")}} method instead.
+
{{domxref("Document.async")}} {{Deprecated_inline}}
+
Used with {{domxref("Document.load")}} to indicate an asynchronous request.
+
{{domxref("Document.characterSet")}} {{readonlyinline}}
+
Returns the character set being used by the document.
+
{{domxref("Document.charset")}} {{readonlyinline}} {{Deprecated_inline}}
+
Alias of {{domxref("Document.characterSet")}}. Use this property instead.
+
{{domxref("Document.compatMode")}} {{readonlyinline}} {{experimental_inline}}
+
Indicates whether the document is rendered in quirks or strict mode.
+
{{domxref("Document.contentType")}} {{readonlyinline}} {{experimental_inline}}
+
Returns the Content-Type from the MIME Header of the current document.
+
{{domxref("Document.doctype")}} {{readonlyinline}}
+
回傳目前文件的 Document Type Definition(DTD)。
+
{{domxref("Document.documentElement")}} {{readonlyinline}}
+
回傳當前文件 {{domxref("Document")}} 的根元素。以 HTML documents為例:它會回傳 {{HTMLElement("html")}} 這項元素。
+
{{domxref("Document.documentURI")}} {{readonlyinline}}
+
Returns the document location as a string.
+
{{domxref("Document.domConfig")}} {{Deprecated_inline}}
+
Should return a {{domxref("DOMConfiguration")}} object.
+
{{domxref("Document.fullscreen")}} {{obsolete_inline}}
+
true when the document is in {{domxref("Using_full-screen_mode","full-screen mode")}}.
+
{{domxref("Document.hidden")}} {{readonlyinline}}
+
+
{{domxref("Document.implementation")}} {{readonlyinline}}
+
Returns the DOM implementation associated with the current document.
+
{{domxref("Document.inputEncoding")}} {{readonlyinline}} {{Deprecated_inline}}
+
Alias of {{domxref("Document.characterSet")}}. Use this property instead.
+
{{domxref("Document.lastStyleSheetSet")}} {{readonlyinline}}
+
Returns the name of the style sheet set that was last enabled. Has the value null until the style sheet is changed by setting the value of {{domxref("document.selectedStyleSheetSet","selectedStyleSheetSet")}}.
+
{{domxref("Document.mozSyntheticDocument")}} {{non-standard_inline}} {{gecko_minversion_inline("8.0")}}
+
Returns a {{jsxref("Boolean")}} that is true only if this document is synthetic, such as a standalone image, video, audio file, or the like.
+
{{domxref("Document.mozFullScreenElement")}} {{readonlyinline}} {{non-standard_inline}} {{gecko_minversion_inline("9.0")}}
+
The element that's currently in full screen mode for this document.
+
{{domxref("Document.mozFullScreenEnabled")}} {{readonlyinline}} {{non-standard_inline}} {{gecko_minversion_inline("9.0")}}
+
true if calling {{domxref("Element.mozRequestFullscreen()")}} would succeed in the curent document.
+
{{domxref("Document.pointerLockElement")}} {{readonlyinline}} {{experimental_inline}}
+
Returns the element set as the target for mouse events while the pointer is locked. null if lock is pending, pointer is unlocked, or if the target is in another document.
+
{{domxref("Document.preferredStyleSheetSet")}} {{readonlyinline}}
+
Returns the preferred style sheet set as specified by the page author.
+
{{domxref("Document.scrollingElement")}} {{experimental_inline}} {{readonlyinline}}
+
Returns a reference to the {{domxref("Element")}} that scrolls the document.
+
{{domxref("Document.selectedStyleSheetSet")}}
+
Returns which style sheet set is currently in use.
+
{{domxref("Document.styleSheets")}} {{readonlyinline}}
+
Returns a list of the style sheet objects on the current document.
+
{{domxref("Document.styleSheetSets")}} {{readonlyinline}}
+
Returns a list of the style sheet sets available on the document.
+
{{domxref("Document.timeline")}} {{readonlyinline}}
+
+
{{domxref("Document.undoManager")}} {{readonlyinline}} {{experimental_inline}}
+
+
{{domxref("Document.visibilityState")}} {{readonlyinline}}
+
+

Returns a string denoting the visibility state of the document. Possible values are visible, hidden, prerender, and unloaded.

+
+
{{domxref("Document.xmlEncoding")}} {{Deprecated_inline}}
+
Returns the encoding as determined by the XML declaration.
+
{{domxref("Document.xmlStandalone")}} {{obsolete_inline("10.0")}}
+
Returns true if the XML declaration specifies the document to be standalone (e.g., An external part of the DTD affects the document's content), else false.
+
{{domxref("Document.xmlVersion")}} {{obsolete_inline("10.0")}}
+
Returns the version number as specified in the XML declaration or "1.0" if the declaration is absent.
+
+ +

The Document interface is extended with the {{domxref("ParentNode")}} interface:

+ +

{{page("/en-US/docs/Web/API/ParentNode","Properties")}}

+ +

HTML 文件擴充

+ +

window.document 物件的部分屬性繼承自 HTML 文件的 {{domxref("HTMLDocument")}} 介面,或是來自 Document 從 HTML5 之後擴充的屬性。

+ +
+
{{domxref("Document.activeElement")}} {{readonlyinline}}
+
Returns the currently focused element.
+
{{domxref("Document.alinkColor")}} {{Deprecated_inline}}
+
Returns or sets the color of active links in the document body.
+
{{domxref("Document.anchors")}}
+
Returns a list of all of the anchors in the document.
+
{{domxref("Document.applets")}} {{Deprecated_inline}}
+
Returns an ordered list of the applets within a document.
+
{{domxref("Document.bgColor")}} {{Deprecated_inline}}
+
Gets/sets the background color of the current document.
+
{{domxref("Document.body")}}
+
Returns the {{HTMLElement("body")}} element of the current document.
+
{{domxref("Document.cookie")}}
+
Returns a semicolon-separated list of the cookies for that document or sets a single cookie.
+
{{domxref("Document.defaultView")}} {{readonlyinline}}
+
Returns a reference to the window object.
+
{{domxref("Document.designMode")}}
+
Gets/sets the ability to edit the whole document.
+
{{domxref("Document.dir")}} {{readonlyinline}}
+
Gets/sets directionality (rtl/ltr) of the document.
+
{{domxref("Document.domain")}} {{readonlyinline}}
+
Returns the domain of the current document.
+
{{domxref("Document.embeds")}} {{readonlyinline}}
+
Returns a list of the embedded {{HTMLElement('embed')}} elements within the current document.
+
{{domxref("document.fgColor")}} {{Deprecated_inline}}
+
Gets/sets the foreground color, or text color, of the current document.
+
{{domxref("Document.forms")}} {{readonlyinline}}
+
Returns a list of the {{HTMLElement("form")}} elements within the current document.
+
{{domxref("Document.head")}} {{readonlyinline}}
+
Returns the {{HTMLElement("head")}} element of the current document.
+
{{domxref("Document.height")}} {{non-standard_inline}} {{obsolete_inline}}
+
Gets/sets the height of the current document.
+
{{domxref("Document.images")}} {{readonlyinline}}
+
Returns a list of the images in the current document.
+
{{domxref("Document.lastModified")}} {{readonlyinline}}
+
Returns the date on which the document was last modified.
+
{{domxref("Document.linkColor")}} {{Deprecated_inline}}
+
Gets/sets the color of hyperlinks in the document.
+
{{domxref("Document.links")}} {{readonlyinline}}
+
Returns a list of all the hyperlinks in the document.
+
{{domxref("Document.location")}} {{readonlyinline}}
+
Returns the URI of the current document.
+
{{domxref("Document.plugins")}} {{readonlyinline}}
+
Returns a list of the available plugins.
+
{{domxref("Document.readyState")}} {{readonlyinline}} {{gecko_minversion_inline("1.9.2")}}
+
Returns loading status of the document.
+
{{domxref("Document.referrer")}} {{readonlyinline}}
+
Returns the URI of the page that linked to this page.
+
{{domxref("Document.scripts")}} {{readonlyinline}}
+
Returns all the {{HTMLElement("script")}} elements on the document.
+
{{domxref("Document.title")}}
+
Sets or gets title of the current document.
+
{{domxref("Document.URL")}} {{readonlyInline}}
+
Returns the document location as a string.
+
{{domxref("Document.vlinkColor")}} {{Deprecated_inline}}
+
Gets/sets the color of visited hyperlinks.
+
{{domxref("Document.width")}} {{non-standard_inline}} {{obsolete_inline}}
+
Returns the width of the current document.
+
+ +

事件處理器

+ +
+
{{domxref("Document.onafterscriptexecute")}} {{non-standard_inline}}
+
Represents the event handling code for the {{event("afterscriptexecute")}} event.
+
{{domxref("Document.onbeforescriptexecute")}} {{non-standard_inline}}
+
Represents the event handling code for the {{event("beforescriptexecute")}} event.
+
{{domxref("Document.oncopy")}} {{non-standard_inline}}
+
Represents the event handling code for the {{event("copy")}} event.
+
{{domxref("Document.oncut")}} {{non-standard_inline}}
+
Represents the event handling code for the {{event("cut")}} event.
+
{{domxref("Document.onfullscreenchange")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("fullscreenchange")}} event is raised.
+
{{domxref("Document.onfullscreenerror")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("fullscreenerror")}} event is raised.
+
{{domxref("Document.onpaste")}} {{non-standard_inline}}
+
Represents the event handling code for the {{event("paste")}} event.
+
{{domxref("Document.onpointerlockchange")}} {{experimental_inline}}
+
Represents the event handling code for the {{event("pointerlockchange")}} event.
+
{{domxref("Document.onpointerlockerror")}} {{experimental_inline}}
+
Represetnts the event handling code for the {{event("pointerlockerror")}} event.
+
{{domxref("Document.onreadystatechange")}} {{gecko_minversion_inline("1.9.2")}}
+
Represents the event handling code for the {{event("readystatechange")}} event.
+
{{domxref("Document.onselectionchange")}} {{experimental_inline}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("selectionchange")}} event is raised.
+
{{domxref("Document.onwheel")}} {{non-standard_inline}}
+
Represents the event handling code for the {{event("wheel")}} event.
+
+ +

此介面繼承了 {{domxref("GlobalEventHandlers")}} 的事件處理器:

+ +

{{Page("/zh-TW/docs/Web/API/GlobalEventHandlers", "屬性")}}

+ +

方法

+ +

This interface also inherits from the {{domxref("Node")}} and {{domxref("EventTarget")}} interfaces.

+ +
+
{{domxref("Document.adoptNode()")}}
+
Adopt node from an external document.
+
{{domxref("Document.captureEvents()")}} {{Deprecated_inline}}
+
See {{domxref("Window.captureEvents")}}.
+
{{domxref("Document.caretPositionFromPoint()")}}{{experimental_inline}}
+
Gets the {{domxref("CaretPosition")}} at or near the specified coordinates.
+
{{domxref("Document.caretRangeFromPoint()")}}{{non-standard_inline}}
+
Gets a {{Domxref("Range")}} object for the document fragment under the specified coordinates.
+
{{domxref("Document.createAttribute()")}}
+
Creates a new {{domxref("Attr")}} object and returns it.
+
{{domxref("Document.createAttributeNS()")}}
+
Creates a new attribute node in a given namespace and returns it.
+
{{domxref("Document.createCDATASection()")}}
+
Creates a new CDATA node and returns it.
+
{{domxref("Document.createComment()")}}
+
Creates a new comment node and returns it.
+
{{domxref("Document.createDocumentFragment()")}}
+
Creates a new document fragment.
+
{{domxref("Document.createElement()")}}
+
Creates a new element with the given tag name.
+
{{domxref("Document.createElementNS()")}}
+
Creates a new element with the given tag name and namespace URI.
+
{{domxref("Document.createEntityReference()")}} {{obsolete_inline}}
+
Creates a new entity reference object and returns it.
+
{{domxref("Document.createEvent()")}}
+
Creates an event object.
+
{{domxref("Document.createNodeIterator()")}}
+
Creates a {{domxref("NodeIterator")}} object.
+
{{domxref("Document.createProcessingInstruction()")}}
+
Creates a new {{domxref("ProcessingInstruction")}} object.
+
{{domxref("Document.createRange()")}}
+
Creates a {{domxref("Range")}} object.
+
{{domxref("Document.createTextNode()")}}
+
Creates a text node.
+
{{domxref("Document.createTouch()")}}
+
Creates a {{domxref("Touch")}} object.
+
{{domxref("Document.createTouchList()")}}
+
Creates a {{domxref("TouchList")}} object.
+
{{domxref("Document.createTreeWalker()")}}
+
Creates a {{domxref("TreeWalker")}} object.
+
{{domxref("Document.elementFromPoint()")}}{{experimental_inline}}
+
Returns the topmost element at the specified coordinates.
+
{{domxref("Document.elementsFromPoint()")}}{{experimental_inline}}
+
Returns an array of all elements at the specified coordinates.
+
{{domxref("Document.enableStyleSheetsForSet()")}}
+
Enables the style sheets for the specified style sheet set.
+
{{domxref("Document.exitPointerLock()")}} {{experimental_inline}}
+
Release the pointer lock.
+
{{domxref("Document.getAnimations()")}} {{experimental_inline}}
+
Returns an array of all {{domxref("Animation")}} objects currently in effect, whose target elements are descendants of the document.
+
{{domxref("Document.getElementsByClassName()")}}
+
Returns a list of elements with the given class name.
+
{{domxref("Document.getElementsByTagName()")}}
+
Returns a list of elements with the given tag name.
+
{{domxref("Document.getElementsByTagNameNS()")}}
+
Returns a list of elements with the given tag name and namespace.
+
{{domxref("Document.importNode()")}}
+
Returns a clone of a node from an external document.
+
{{domxref("Document.normalizeDocument()")}} {{obsolete_inline}}
+
Replaces entities, normalizes text nodes, etc.
+
{{domxref("Document.registerElement()")}} {{experimental_inline}}
+
Registers a web component.
+
{{domxref("Document.releaseCapture()")}} {{non-standard_inline}} {{gecko_minversion_inline("2.0")}}
+
Releases the current mouse capture if it's on an element in this document.
+
{{domxref("Document.releaseEvents()")}} {{non-standard_inline}} {{Deprecated_inline}}
+
See {{domxref("Window.releaseEvents()")}}.
+
{{domxref("Document.routeEvent()")}} {{non-standard_inline}} {{obsolete_inline(24)}}
+
See {{domxref("Window.routeEvent()")}}.
+
{{domxref("Document.mozSetImageElement()")}} {{non-standard_inline}} {{gecko_minversion_inline("2.0")}}
+
Allows you to change the element being used as the background image for a specified element ID.
+
+ +

The Document interface is extended with the {{domxref("ParentNode")}} interface:

+ +
+
{{domxref("document.getElementById","document.getElementById(String id)")}}
+
Returns an object reference to the identified element.
+
{{domxref("document.querySelector","document.querySelector(String selector)")}} {{gecko_minversion_inline("1.9.1")}}
+
Returns the first Element node within the document, in document order, that matches the specified selectors.
+
{{domxref("document.querySelectorAll","document.querySelectorAll(String selector)")}} {{gecko_minversion_inline("1.9.1")}}
+
Returns a list of all the Element nodes within the document that match the specified selectors.
+
+ +

The Document interface is extended with the {{domxref("XPathEvaluator")}} interface:

+ +
+
{{domxref("document.createExpression","document.createExpression(String expression, XPathNSResolver resolver)")}}
+
Compiles an XPathExpression which can then be used for (repeated) evaluations.
+
{{domxref("document.createNSResolver","document.createNSResolver(Node resolver)")}}
+
Creates an {{domxref("XPathNSResolver")}} object.
+
{{domxref("document.evaluate","document.evaluate(String expression, Node contextNode, XPathNSResolver resolver, Number type, Object result)")}}
+
Evaluates an XPath expression.
+
+ +

HTML 文件擴充

+ +

Document 物件的部分方法繼承自 HTML 文件的 {{domxref("HTMLDocument")}} 介面,或是來自 Document 從 HTML5 之後擴充的方法:

+ +
+
{{domxref("document.clear()")}} {{non-standard_inline}} {{Deprecated_inline}}
+
In majority of modern browsers, including recent versions of Firefox and Internet Explorer, this method does nothing.
+
{{domxref("document.close()")}}
+
Closes a document stream for writing.
+
{{domxref("document.execCommand","document.execCommand(String command[, Boolean showUI[, String value]])")}}
+
On an editable document, executes a formating command.
+
{{domxref("document.getElementsByName","document.getElementsByName(String name)")}}
+
Returns a list of elements with the given name.
+
{{domxref("document.getSelection()")}}
+
Returns a {{domxref("Selection")}} object related to text selected in the document.
+
{{domxref("document.hasFocus()")}}
+
Returns true if the focus is currently located anywhere inside the specified document.
+
{{domxref("document.open()")}}
+
Opens a document stream for writing.
+
{{domxref("document.queryCommandEnabled","document.queryCommandEnabled(String command)")}}
+
Returns true if the formating command can be executed on the current range.
+
{{domxref("document.queryCommandIndeterm","document.queryCommandIndeterm(String command)")}}
+
Returns true if the formating command is in an indeterminate state on the current range.
+
{{domxref("document.queryCommandState","document.queryCommandState(String command)")}}
+
Returns true if the formating command has been executed on the current range.
+
{{domxref("document.queryCommandSupported","document.queryCommandSupported(String command)")}}
+
Returns true if the formating command is supported on the current range.
+
{{domxref("document.queryCommandValue","document.queryCommandValue(String command)")}}
+
Returns the current value of the current range for a formating command.
+
{{domxref("document.write","document.write(String text)")}}
+
Writes text in a document.
+
{{domxref("document.writeln","document.writeln(String text)")}}
+
Writes a line of text in a document.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Selection API', '', 'Extend Document and GlobalEventHandlers')}}{{Spec2('Selection API')}}Adds onselectstart and onselectionchange.
{{SpecName('DOM1','#i-Document','Document')}}{{Spec2('DOM1')}}Initial definition for the interface
{{SpecName('DOM2 Core','#i-Document','Document')}}{{Spec2('DOM2 Core')}}Supersede DOM 1
{{SpecName('DOM3 Core','#i-Document','Document')}}{{Spec2('DOM3 Core')}}Supersede DOM 2
{{SpecName('DOM WHATWG','#interface-document','Document')}}{{Spec2('DOM WHATWG')}}Intend to supersede DOM 3
{{SpecName('HTML WHATWG','dom.html#the-document-object','Document')}}{{Spec2('HTML WHATWG')}}Turn the {{domxref("HTMLDocument")}} interface into a Document extension.
{{SpecName('DOM3 XPath','xpath.html#XPathEvaluator','XPathEvaluator')}}{{Spec2('DOM3 XPath')}}Define the {{domxref("XPathEvaluator")}} interface which extend document.
{{SpecName('Page Visibility API', '#sec-document-interface', 'Document')}}{{Spec2('Page Visibility API')}}Extend the Document interface with the visibilityState and hidden attributes
{{SpecName('HTML Editing','#dom-document-getselection','Document')}}{{Spec2('HTML Editing')}}Extend the Document interface
{{SpecName('CSSOM View','#extensions-to-the-document-interface','Document')}}{{Spec2('CSSOM View')}}Extend the Document interface
{{SpecName('CSSOM','#extensions-to-the-document-interface','Document')}}{{Spec2('CSSOM')}}Extend the Document interface
{{SpecName('Pointer Lock','#extensions-to-the-document-interface','Document')}}{{Spec2('Pointer Lock')}}Extend the Document interface
+ +

瀏覽器相容性備註

+ +

Firefox notes

+ +

Mozilla defines a set of non-standard properties made only for XUL content:

+ +
+
{{domxref("document.currentScript")}} {{non-standard_inline}} {{gecko_minversion_inline("2.0")}}
+
Returns the {{HTMLElement("script")}} element that is currently executing.
+
{{domxref("document.documentURIObject")}} {{gecko_minversion_inline("1.9")}}
+
(Mozilla add-ons only!) Returns the {{Interface("nsIURI")}} object representing the URI of the document. This property only has special meaning in privileged JavaScript code (with UniversalXPConnect privileges).
+
{{domxref("document.popupNode")}}
+
Returns the node upon which a popup was invoked.
+
{{domxref("document.tooltipNode")}}
+
Returns the node which is the target of the current tooltip.
+
+ +

Mozilla also define some non-standard methods:

+ +
+
{{domxref("document.execCommandShowHelp")}} {{obsolete_inline("14.0")}}
+
This method never did anything and always threw an exception, so it was removed in Gecko 14.0 {{geckoRelease("14.0")}}.
+
{{domxref("document.getBoxObjectFor")}} {{obsolete_inline}}
+
Use the {{domxref("Element.getBoundingClientRect()")}} method instead.
+
{{domxref("document.loadOverlay")}} {{Fx_minversion_inline("1.5")}}
+
Loads a XUL overlay dynamically. This only works in XUL documents.
+
{{domxref("document.queryCommandText")}} {{obsolete_inline("14.0")}}
+
This method never did anything but throw an exception, and was removed in Gecko 14.0 {{geckoRelease("14.0")}}.
+
+ +

Internet Explorer notes

+ +

Microsoft defines some non-standard properties:

+ +
+
{{domxref("document.fileSize")}}* {{non-standard_inline}} {{obsolete_inline}}
+
Returns size in bytes of the document. Starting with Internet Explorer 11, that property is no longer supported. See MSDN.
+
Internet Explorer does not support all methods from the Node interface in the Document interface:
+
+ +
+
{{domxref("document.contains")}}
+
As a work-around, document.body.contains() can be used.
+
diff --git a/files/zh-tw/web/api/document/keyup_event/index.html b/files/zh-tw/web/api/document/keyup_event/index.html new file mode 100644 index 0000000000..3568b30c18 --- /dev/null +++ b/files/zh-tw/web/api/document/keyup_event/index.html @@ -0,0 +1,149 @@ +--- +title: keyup +slug: Web/API/Document/keyup_event +translation_of: Web/API/Document/keyup_event +--- +

當鍵盤上的手指離開按鍵時,keyup事件會被觸發。

+ +

基本資料

+ +
+
詳述
+
DOM L3
+
介面
+
KeyboardEvent
+
Bubbles
+
Yes
+
Cancelable
+
Yes
+
Target
+
網頁文件, 網頁元素
+
Default Action
+
None
+
+ +

屬性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
target {{readonlyInline}}EventTargetThe event target (the topmost target in the DOM tree).
type {{readonlyInline}}DOMStringThe type of event.
bubbles {{readonlyInline}}BooleanWhether the event normally bubbles or not
cancelable {{readonlyInline}}BooleanWhether the event is cancellable or not?
view {{readonlyInline}}WindowProxydocument.defaultView (window of the document)
detail {{readonlyInline}}long (float)0.
target {{readonlyInline}}EventTarget (DOM element)Focused element processing the key event, root element if no suitable input element focused.
char {{readonlyInline}}DOMString (string)The character value of the key. If the key corresponds to a printable character, this value is a non-empty Unicode string containing that character. If the key doesn't have a printable representation, this is an empty string. See key names and char values for the detail. +
Note: If the key is used as a macro that inserts multiple characters, this attribute's value is the entire string, not just the first character.
+
key {{readonlyInline}}DOMString (string)The key value of the key represented by the event. If the value has a printed representation, this attribute's value is the same as the char attribute. Otherwise, it's one of the key value strings specified in {{ anch("Key values") }}. If the key can't be identified, this is the string "Unidentified". See key names and char values for the detail. Read Only.
charCode {{readonlyInline}}Unsigned long (int)The Unicode reference number of the key; this attribute is used only by the keypress event. For keys whose char attribute contains multiple characters, this is the Unicode value of the first character in that attribute. +
Warning: This attribute is deprecated; you should use char instead, if available.
+
keyCode {{readonlyInline}}Unsigned long (int)A system and implementation dependent numerical code identifying the unmodified value of the pressed key. This is usually the decimal ASCII ({{ RFC(20) }}) or Windows 1252 code corresponding to the key; see {{ anch("Virtual key codes") }} for a list of common values. If the key can't be identified, this value is 0. +
Warning: This attribute is deprecated; you should use key instead, if available.
+
which {{readonlyInline}}Unsigned long (int)A system and implementation dependent numeric code identifying the unmodified value of the pressed key; this is usually the same as keyCode. +
Warning: This attribute is deprecated; you should use key instead, if available.
+
location {{readonlyInline}}long (float)The location of the key on the device.
repeat {{readonlyInline}}booleantrue if a key has been depressed long enough to trigger key repetition, otherwise false.
locale {{readonlyInline}}stringThe language code for the key event, if available; otherwise, the empty string.
ctrlKey {{readonlyInline}}booleantrue if the control key was down when the event was fired. false otherwise.
shiftKey {{readonlyInline}}booleantrue if the shift key was down when the event was fired. false otherwise.
altKey {{readonlyInline}}booleantrue if the alt key was down when the event was fired. false otherwise.
metaKey {{readonlyInline}}booleantrue if the meta key was down when the event was fired. false otherwise.
+ + + + diff --git a/files/zh-tw/web/api/document/queryselector/index.html b/files/zh-tw/web/api/document/queryselector/index.html new file mode 100644 index 0000000000..a79edb1c1f --- /dev/null +++ b/files/zh-tw/web/api/document/queryselector/index.html @@ -0,0 +1,102 @@ +--- +title: document.querySelector +slug: Web/API/Document/querySelector +tags: + - DOM + - Fixit + - Gecko DOM Reference + - Gecko DOM 參考 + - Selectors + - 選擇器 +translation_of: Web/API/Document/querySelector +--- +
+ {{ApiRef()}}
+

摘要

+

回傳 document 第一個符合特定選擇器群組的元素(採用深度優先,前序追蹤 document 節點)。

+

語法

+
element = document.querySelector(selectors);
+

其中

+ +

範例

+

這個範例會回傳 document 選到的第一個 "myclass" class:

+
var el = document.querySelector(".myclass");
+
+

注意事項

+

若找不到相應元素就會回傳 null,否則回傳第一個符合的元素。

+

若選擇器符合某 ID,且該 ID 在 document 中誤用數次,就會回傳第一個符合的元素。

+

當特定選擇器群組無效,會擲回 SYNTAX_ERR 例外狀況。

+

querySelector() 是由 Selectors API 引入的選擇器。

+

傳入 querySelector 的字串參數必須遵循 CSS 語法。若要選取未遵循 CSS 語法的 ID 或選擇器(例如不當使用冒號或空格),必須強制加上兩個反斜線來跳脫錯誤的字元:

+
<div id="foo\bar"></div>
+<div id="foo:bar"></div>
+
+<script>
+document.querySelector('#foo\bar')    // 甚麼都沒選到
+document.querySelector('#foo\\\\bar') // 選到第一個 div
+document.querySelector('#foo:bar')     // 甚麼都沒選到
+document.querySelector('#foo\\:bar')   // 選到第二個 div
+</script>
+
+

瀏覽器相容性

+

{{CompatibilityTable()}}

+
+ + + + + + + + + + + + + + + + + + + +
功能特色ChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
基本支援13.5 (1.9.1)
+ {{bug(416317)}}
8103.2 (525.3)
+ {{Webkitbug("16587")}}
+
+
+ + + + + + + + + + + + + + + + + + + +
功能特色AndroidFirefox 行動版 (Gecko)IE 行動版Opera 行動版Safari 行動版
基本支援2.1910.03.2
+
+

規格文件

+ +

詳見

+ diff --git a/files/zh-tw/web/api/document/readystate/index.html b/files/zh-tw/web/api/document/readystate/index.html new file mode 100644 index 0000000000..13cf835aa7 --- /dev/null +++ b/files/zh-tw/web/api/document/readystate/index.html @@ -0,0 +1,108 @@ +--- +title: Document.readyState +slug: Web/API/Document/readyState +tags: + - API + - HTML DOM + - Reference +translation_of: Web/API/Document/readyState +--- +
{{APIRef("DOM")}} {{ gecko_minversion_header("1.9.2") }}
+ +

總覽

+ +

{{ domxref("document") }} 的 Document.readyState 屬性描述文件的讀取狀態。

+ +

數值

+ +

文件的 readyState 數值如下:

+ +
+
loading
+
{{ domxref("document") }} 正在讀取中。
+
interactive
+
文件已經完成讀取和解析,但是其他的子資源,如「圖片樣式層次表」,仍然在讀取。這個狀態表示 {{event("DOMContentLoaded")}} 事件已經被觸發。
+
complete
+
文件及子資源都完成讀取。這個狀態表示 {{event("load")}} 事件即將被觸發。
+
+ +

當這個屬性的數值改變時, {{event("readystatechange")}} 事件在 {{ domxref("document") }} 上觸發。

+ +

表達式

+ +
var string = document.readyState;
+
+ +

範例

+ +

不同的狀態

+ +
switch (document.readyState) {
+  case "loading":
+    // 文件讀取中。
+    break;
+  case "interactive":
+    // 文件已經完成讀取。可以使用 DOM 元素。
+    var span = document.createElement("span");
+    span.textContent = "A <span> element.";
+    document.body.appendChild(span);
+    break;
+  case "complete":
+    // 頁面已經完成讀取。
+    console.log("The first CSS rule is: " + document.styleSheets[0].cssRules[0].cssText);
+    break;
+}
+
+ +

readystatechange 替代 DOMContentLoaded

+ +
// alternative to DOMContentLoaded event
+document.onreadystatechange = function () {
+  if (document.readyState == "interactive") {
+    initApplication();
+  }
+}
+ +

readystatechange 替代 load

+ +
// alternative to load event
+document.onreadystatechange = function () {
+  if (document.readyState == "complete") {
+    initApplication();
+  }
+}
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態
{{SpecName("HTML WHATWG", "#current-document-readiness", "Document readiness")}}{{Spec2('HTML WHATWG')}} 
{{SpecName("HTML5.1", "#current-document-readiness", "Document readiness")}}{{Spec2('HTML5.1')}} 
{{SpecName("HTML5 W3C", "#current-document-readiness", "Document readiness")}}{{Spec2('HTML5 W3C')}}Initial specification.
+ +

參見

+ + diff --git a/files/zh-tw/web/api/document/registerelement/index.html b/files/zh-tw/web/api/document/registerelement/index.html new file mode 100644 index 0000000000..66c3330dca --- /dev/null +++ b/files/zh-tw/web/api/document/registerelement/index.html @@ -0,0 +1,113 @@ +--- +title: Document.registerElement() +slug: Web/API/Document/registerElement +tags: + - API + - DOM + - JavaScript + - 自訂標籤 +translation_of: Web/API/Document/registerElement +--- +

{{APIRef("DOM")}}{{Deprecated_header}}

+ +
+

Warning: document.registerElement()                       已經被棄用,建議使用               customElements.define().

+
+ +

{{draft}}

+ +

 document.registerElement()                 可以在瀏覽器中註冊一個新的自訂標籤(元素)and returns a constructor for the new element.

+ +
+

Note: This is an experimental technology. The browser you use it in must support Web Components. See Enabling Web Components in Firefox.

+
+ +

語法

+ +
var constructor = document.registerElement(tag-name, options);
+ +

參數

+ +
+
標籤名稱
+
自訂的標籤名稱需有一個 橫線  ( - ), 例如my-tag.
+
options {{optional_inline}}
+
+

An object with properties prototype to base the custom element on, and extends, an existing tag to extend. Both of these are optional.

+
+
+ +

例子

+ +

這是一個非常簡單的例子:

+ +
var Mytag = document.registerElement('my-tag');
+
+ +

現在新的標籤已經在瀏覽器中註冊了. The Mytag variable holds a constructor that you can use to create a my-tag element in the document as follows:

+ +
document.body.appendChild(new Mytag());
+ +

This inserts an empty my-tag element that will be visible if you use the browser's developer tools. It will not be visible if you use the browser's view source capability. And it won't be visible in the browser unless you add some content to the tag. Here is one way to add content to the new tag:

+ +
var mytag = document.getElementsByTagName("my-tag")[0];
+mytag.textContent = "I am a my-tag element.";
+
+ +

瀏覽器支援性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support3531[1]{{CompatNo}}25{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support4.4.431[1]{{CompatNo}}25{{CompatNo}}
+
+ +

[1] This API is implemented behind a preference.

+ +

也看一下

+ + diff --git a/files/zh-tw/web/api/document/scroll_event/index.html b/files/zh-tw/web/api/document/scroll_event/index.html new file mode 100644 index 0000000000..26dbb7640c --- /dev/null +++ b/files/zh-tw/web/api/document/scroll_event/index.html @@ -0,0 +1,103 @@ +--- +title: scroll +slug: Web/API/Document/scroll_event +translation_of: Web/API/Document/scroll_event +--- +

當文件的可視區或元素被滾動(scroll),scroll事件會被觸發

+ +

一般資訊

+ +
+
規範
+
DOM L3, CSSOM View
+
介面
+
UIEvent
+
Bubbles
+
Not on elements, but bubbles to the default view when fired on the document
+
Cancelable
+
No
+
Target
+
defaultView, Document, Element
+
Default Action
+
None
+
+ +

屬性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
target {{readonlyInline}}EventTargetThe event target (the topmost target in the DOM tree).
type {{readonlyInline}}DOMStringThe type of event.
bubbles {{readonlyInline}}BooleanWhether the event normally bubbles or not.
cancelable {{readonlyInline}}BooleanWhether the event is cancellable or not.
view {{readonlyInline}}WindowProxydocument.defaultView (window of the document)
detail {{readonlyInline}}long (float)0.
+ +

Example

+ +

因為 scroll 事件是高頻觸發,這樣的事件處理程式不該進行運算成本高的程式,像是DOM的修改。所以,建議使用 requestAnimationFrame, setTimeoutcustomEvent 如下所示

+ +

Scroll optimization with window.requestAnimationFrame

+ +
// Reference: http://www.html5rocks.com/en/tutorials/speed/animations/
+
+var last_known_scroll_position = 0;
+var ticking = false;
+
+function doSomething(scroll_pos) {
+  // do something with the scroll position
+}
+
+window.addEventListener('scroll', function(e) {
+  last_known_scroll_position = window.scrollY;
+  if (!ticking) {
+    window.requestAnimationFrame(function() {
+      doSomething(last_known_scroll_position);
+      ticking = false;
+    });
+  }
+  ticking = true;
+});
+ +

 

+ +

關於resize事件的更多類似例子。

+ +

瀏覽器相容性

+ +

iOS UIWebView

+ +

在iOS UIWebViews中,滾動捲軸時 scroll 事件不會觸發;它們要等到滾動完成時才被觸發。請參閱Bootstrap issue #16202。 Safari 和 WKWebViews 不受此bug的影響。

diff --git a/files/zh-tw/web/api/document/width/index.html b/files/zh-tw/web/api/document/width/index.html new file mode 100644 index 0000000000..39eef5c184 --- /dev/null +++ b/files/zh-tw/web/api/document/width/index.html @@ -0,0 +1,45 @@ +--- +title: Document.width +slug: Web/API/Document/width +translation_of: Web/API/Document/width +--- +
{{APIRef("DOM")}} {{Obsolete_header}}
+ +
+

注意: 從 {{Gecko("6.0")}} 開始, document.width 將不再被支援。取而代之的是 document.body.clientWidth 。請參照: {{domxref("element.clientWidth")}}.

+
+ +

傳回目前文件中,{{HTMLElement("body")}} 元素的寬度有多少像素。

+ +

Internet Explorer 不支援!

+ +

語法

+ +
pixels = document.width;
+
+ +

範例

+ +
function init() {
+    alert("文件的寬度是 " + document.width + " 像素。");
+}
+
+ +

其他替代

+ +
document.body.clientWidth              /* <body> 的寬度 */
+document.documentElement.clientWidth   /* <html> 的寬度 */
+window.innerWidth                      /* 視窗的寬度 */
+
+ +

規範於

+ +

HTML5

+ +

同時參考

+ + diff --git a/files/zh-tw/web/api/document_object_model/examples/index.html b/files/zh-tw/web/api/document_object_model/examples/index.html new file mode 100644 index 0000000000..66a1756da6 --- /dev/null +++ b/files/zh-tw/web/api/document_object_model/examples/index.html @@ -0,0 +1,373 @@ +--- +title: 使用 web 和 XML 開發來使用 DOM +slug: Web/API/Document_Object_Model/Examples +translation_of: Web/API/Document_Object_Model/Examples +--- +

本章介紹了使用 DOM 進行 Web 以及 XML 開發的一些長範例。只要可能,在例子就會使用通用的 JavaScript Web API 、技巧以及模式來操作文檔對象(the document object)。

+ +

範例一:高度和寬度

+ +

下面的例子展示了在不同尺寸的圖片時使用其高(height)和寬(width)屬性的情況:

+ +
<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>width/height example</title>
+<script>
+function init() {
+  var arrImages = new Array(3);
+
+  arrImages[0] = document.getElementById("image1");
+  arrImages[1] = document.getElementById("image2");
+  arrImages[2] = document.getElementById("image3");
+
+  var objOutput = document.getElementById("output");
+  var strHtml = "<ul>";
+
+  for (var i = 0; i < arrImages.length; i++) {
+    strHtml += "<li>image" + (i+1) +
+            ": height=" + arrImages[i].height +
+            ", width=" + arrImages[i].width +
+            ", style.height=" + arrImages[i].style.height +
+            ", style.width=" + arrImages[i].style.width +
+            "<\/li>";
+  }
+
+  strHtml += "<\/ul>";
+
+  objOutput.innerHTML = strHtml;
+}
+</script>
+</head>
+<body onload="init();">
+
+<p>Image 1: no height, width, or style
+  <img id="image1" src="http://www.mozilla.org/images/mozilla-banner.gif">
+</p>
+
+<p>Image 2: height="50", width="500", but no style
+  <img id="image2"
+       src="http://www.mozilla.org/images/mozilla-banner.gif"
+       height="50" width="500">
+</p>
+
+<p>Image 3: no height, width, but style="height: 50px; width: 500px;"
+  <img id="image3"
+       src="http://www.mozilla.org/images/mozilla-banner.gif"
+       style="height: 50px; width: 500px;">
+</p>
+
+<div id="output"> </div>
+</body>
+</html>
+
+ +

範例二:圖片屬性

+ +
<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Modifying an image border</title>
+
+<script>
+function setBorderWidth(width) {
+  document.getElementById("img1").style.borderWidth = width + "px";
+}
+</script>
+</head>
+
+<body>
+<p>
+  <img id="img1"
+       src="image1.gif"
+       style="border: 5px solid green;"
+       width="100" height="100" alt="border test">
+</p>
+
+<form name="FormName">
+  <input type="button" value="Make border 20px-wide" onclick="setBorderWidth(20);" />
+  <input type="button" value="Make border 5px-wide"  onclick="setBorderWidth(5);" />
+</form>
+
+</body>
+</html>
+
+ +

範例三:改變樣式(style)

+ +

在下面這個簡單的例子中,透過取得的 DOM 元素中的 style 物件和 style 物件中的屬性,我們可以取得 HTML 段落中的一些基本樣式屬性。在本例中,你可以直接操控各別的樣式屬性。在下一個的例子裡(見例4),你可以使用 stylesheets 和它的規則來改變整個文檔的樣式。

+ +
<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Changing color and font-size example</title>
+
+<script>
+function changeText() {
+  var p = document.getElementById("pid");
+
+  p.style.color = "blue"
+  p.style.fontSize = "18pt"
+}
+</script>
+</head>
+<body>
+
+<p id="pid" onclick="window.location.href = 'http://www.cnn.com/';">linker</p>
+
+<form>
+  <p><input value="rec" type="button" onclick="changeText();" /></p>
+</form>
+
+</body>
+</html>
+
+ +

範例四:使用樣式表(stylesheets)

+ +

在文檔物件的 styleSheets 屬性會回傳一系列載入文檔中的樣式表(stylesheets)。你可以透過 styleSheets、style 和 CSSRule 物件來獲取樣式表和每條樣式規則。在下面的例子中,把所有的樣式規則中的選擇器文本(字符串)打印到控制台中。

+ +
var ss = document.styleSheets;
+
+for(var i = 0; i < ss.length; i++) {
+  for(var j = 0; j < ss[i].cssRules.length; j++) {
+    dump( ss[i].cssRules[j].selectorText + "\n" );
+  }
+}
+ +

下面是一個只定義了三條樣式規則的單一樣式表的文檔:

+ +
body { background-color: darkblue; }
+p { font-face: Arial; font-size: 10pt; margin-left: .125in; }
+#lumpy { display: none; }
+
+ +

該腳本會輸出如下的結果:

+ +
BODY
+P
+#LUMPY
+
+ +

範例五:事件傳遞

+ +

本例以一種簡單的方法闡述了事件是如何觸發以及在 DOM 中是如何處理的。當這個 HTML 文檔 BODY 載入的時候,在表格的首行註冊了一個事件監聽器。事件監聽器透過執行函數 stopEvent 來處理事件,從而改變在該表格底部的值。

+ +

然而,stopEvent 同時也會另外執行一個事件物件的方法{{domxref("event.stopPropagation")}},這會使得該事件(點擊)無法在 DOM 中有進一步的冒泡行為。請注意,表格本身有一個 {{domxref("element.onclick","onclick")}} 事件,使得這個表格被點擊時的時候原本應該要會跳出一個訊息。但因為 stopEvent 方法已經阻止了冒泡,所以在表格中的數據更新後,該事件階段有效地結束,表格的點擊事件沒有被觸發,而是顯示一個警告框(event propagation halted)——證實了事件被有效結束而沒有進一步冒泡。

+ +
<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Event Propagation</title>
+
+<style>
+#t-daddy { border: 1px solid red }
+#c1 { background-color: pink; }
+</style>
+
+<script>
+function stopEvent(ev) {
+  c2 = document.getElementById("c2");
+  c2.innerHTML = "hello";
+
+  // this ought to keep t-daddy from getting the click.
+  ev.stopPropagation();
+  alert("event propagation halted.");
+}
+
+function load() {
+  elem = document.getElementById("tbl1");
+  elem.addEventListener("click", stopEvent, false);
+}
+</script>
+</head>
+
+<body onload="load();">
+
+<table id="t-daddy" onclick="alert('hi');">
+  <tr id="tbl1">
+    <td id="c1">one</td>
+  </tr>
+  <tr>
+    <td id="c2">two</td>
+  </tr>
+</table>
+
+</body>
+</html>
+
+ +

Example 6: getComputedStyle

+ +

這個例子演示了如何用 {{domxref("window.getComputedStyle")}} 方法來獲取一個尚未被透過樣式元素或 JavaScript 設定的元素樣式(例如,elt.style.backgroundColor="RGB(173,216,230)")。列舉在 {{domxref("element.style", "elt.style")}} 後面的類型的樣式可以用更直接{{domxref("element.style", "elt.style")}} 屬性獲取。

+ +

getComputedStyle() 返回了一個 ComputedCSSStyleDeclaration 物件,其獨立的樣式屬性可以用該物件的 getPropertyValue() 方法引用,如同下面的例子一樣:

+ +
<!DOCTYPE html>
+<html lang="en">
+<head>
+
+<title>getComputedStyle example</title>
+
+<script>
+function cStyles() {
+  var RefDiv = document.getElementById("d1");
+  var txtHeight = document.getElementById("t1");
+  var h_style = document.defaultView.getComputedStyle(RefDiv, null).getPropertyValue("height");
+
+  txtHeight.value = h_style;
+
+  var txtWidth = document.getElementById("t2");
+  var w_style = document.defaultView.getComputedStyle(RefDiv, null).getPropertyValue("width");
+
+  txtWidth.value = w_style;
+
+  var txtBackgroundColor = document.getElementById("t3");
+  var b_style = document.defaultView.getComputedStyle(RefDiv, null).getPropertyValue("background-color");
+
+  txtBackgroundColor.value = b_style;
+}
+</script>
+
+<style>
+#d1 {
+  margin-left: 10px;
+  background-color: rgb(173, 216, 230);
+  height: 20px;
+  max-width: 20px;
+}
+</style>
+
+</head>
+
+<body>
+
+<div id="d1">&nbsp;</div>
+
+<form action="">
+  <p>
+    <button type="button" onclick="cStyles();">getComputedStyle</button>
+    height<input id="t1" type="text" value="1" />
+    max-width<input id="t2" type="text" value="2" />
+    bg-color<input id="t3" type="text" value="3" />
+  </p>
+</form>
+
+</body>
+</html>
+
+ +

範例七:顯示事件物件的屬性

+ +

這個例子使用 DOM 方法來顯示所有 {{domxref("window.onload")}} {{domxref("event")}} 物件的屬性及其在 table 中的值。這個方法也展示一個有用的技術,使用 for...in 迴圈來來遍歷一個物件的屬性,以得到它們的值。

+ +

不同瀏覽器之間事件物件的屬性有很大不同,WHATWG DOM Standard 規範了事件的標準屬性,然而,許多瀏覽器都大大擴展了這些。

+ +

將下面的代碼放到一個空白的文本文件,並將其用各種瀏覽器開啟,你一定會對各種瀏覽器之間的不一致(事件屬性的名稱及其數量)感到驚訝。你可能還喜歡在這個頁面加入一些元素,並呼叫不同的事件處理函數(event handlers)。

+ +
<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8"/>
+<title>Show Event properties</title>
+
+<style>
+table { border-collapse: collapse; }
+thead { font-weight: bold; }
+td { padding: 2px 10px 2px 10px; }
+
+.odd { background-color: #efdfef; }
+.even { background-color: #ffffff; }
+</style>
+
+<script>
+
+function showEventProperties(e) {
+  function addCell(row, text) {
+    var cell = row.insertCell(-1);
+    cell.appendChild(document.createTextNode(text));
+  }
+
+  var e = e || window.event;
+  document.getElementById('eventType').innerHTML = e.type;
+
+  var table = document.createElement('table');
+  var thead = table.createTHead();
+  var row = thead.insertRow(-1);
+  var lableList = ['#', 'Property', 'Value'];
+  var len = lableList.length;
+
+  for (var i=0; i<len; i++) {
+    addCell(row, lableList[i]);
+  }
+
+  var tbody = document.createElement('tbody');
+  table.appendChild(tbody);
+
+  for (var p in e) {
+    row = tbody.insertRow(-1);
+    row.className = (row.rowIndex % 2)? 'odd':'even';
+    addCell(row, row.rowIndex);
+    addCell(row, p);
+    addCell(row, e[p]);
+  }
+
+  document.body.appendChild(table);
+}
+
+window.onload = function(event){
+  showEventProperties(event);
+}
+</script>
+</head>
+
+<body>
+<h1>Properties of the DOM <span id="eventType"></span> Event Object</h1>
+</body>
+
+</html>
+
+ +

範例八:使用 DOM Table 介面

+ +

DOM HTMLTableElement 介面提供了一些方便的方法用於創建和操作資料表。兩種常用的方法是{{domxref("HTMLTableElement.insertRow")}}和{{domxref("tableRow.insertCell")}}.。

+ +

增加一行和一些細格到現有的資料表:

+ +
<table id="table0">
+ <tr>
+  <td>Row 0 Cell 0</td>
+  <td>Row 0 Cell 1</td>
+ </tr>
+</table>
+
+<script>
+var table = document.getElementById('table0');
+var row = table.insertRow(-1);
+var cell,
+    text;
+
+for (var i = 0; i < 2; i++) {
+  cell = row.insertCell(-1);
+  text = 'Row ' + row.rowIndex + ' Cell ' + i;
+  cell.appendChild(document.createTextNode(text));
+}
+</script>
+
+ +

提醒

+ + + + + + diff --git a/files/zh-tw/web/api/document_object_model/how_to_create_a_dom_tree/index.html b/files/zh-tw/web/api/document_object_model/how_to_create_a_dom_tree/index.html new file mode 100644 index 0000000000..02a3ac01e2 --- /dev/null +++ b/files/zh-tw/web/api/document_object_model/how_to_create_a_dom_tree/index.html @@ -0,0 +1,145 @@ +--- +title: 如何建立 DOM 樹 +slug: Web/API/Document_Object_Model/How_to_create_a_DOM_tree +translation_of: Web/API/Document_object_model/How_to_create_a_DOM_tree +--- +

{{draft}}

+ +

This page describes how to use the DOM Core API in JavaScript to create and modify DOM objects. It applies to all Gecko-based applications (such as Firefox) both in privileged (extensions) and unprivileged (web pages) code.

+ +

Dynamically creating a DOM tree

+ +

Consider the following XML document:

+ +
<?xml version="1.0"?>
+<people>
+  <person first-name="eric" middle-initial="H" last-name="jung">
+    <address street="321 south st" city="denver" state="co" country="usa"/>
+    <address street="123 main st" city="arlington" state="ma" country="usa"/>
+  </person>
+
+  <person first-name="jed" last-name="brown">
+    <address street="321 north st" city="atlanta" state="ga" country="usa"/>
+    <address street="123 west st" city="seattle" state="wa" country="usa"/>
+    <address street="321 south avenue" city="denver" state="co" country="usa"/>
+  </person>
+</people>
+
+ +

The W3C DOM API, supported by Mozilla, can be used to create an in-memory representation of this document like so:

+ +
var doc = document.implementation.createDocument("", "", null);
+var peopleElem = doc.createElement("people");
+
+var personElem1 = doc.createElement("person");
+personElem1.setAttribute("first-name", "eric");
+personElem1.setAttribute("middle-initial", "h");
+personElem1.setAttribute("last-name", "jung");
+
+var addressElem1 = doc.createElement("address");
+addressElem1.setAttribute("street", "321 south st");
+addressElem1.setAttribute("city", "denver");
+addressElem1.setAttribute("state", "co");
+addressElem1.setAttribute("country", "usa");
+personElem1.appendChild(addressElem1);
+
+var addressElem2 = doc.createElement("address");
+addressElem2.setAttribute("street", "123 main st");
+addressElem2.setAttribute("city", "arlington");
+addressElem2.setAttribute("state", "ma");
+addressElem2.setAttribute("country", "usa");
+personElem1.appendChild(addressElem2);
+
+var personElem2 = doc.createElement("person");
+personElem2.setAttribute("first-name", "jed");
+personElem2.setAttribute("last-name", "brown");
+
+var addressElem3 = doc.createElement("address");
+addressElem3.setAttribute("street", "321 north st");
+addressElem3.setAttribute("city", "atlanta");
+addressElem3.setAttribute("state", "ga");
+addressElem3.setAttribute("country", "usa");
+personElem2.appendChild(addressElem3);
+
+var addressElem4 = doc.createElement("address");
+addressElem4.setAttribute("street", "123 west st");
+addressElem4.setAttribute("city", "seattle");
+addressElem4.setAttribute("state", "wa");
+addressElem4.setAttribute("country", "usa");
+personElem2.appendChild(addressElem4);
+
+var addressElem5 = doc.createElement("address");
+addressElem5.setAttribute("street", "321 south avenue");
+addressElem5.setAttribute("city", "denver");
+addressElem5.setAttribute("state", "co");
+addressElem5.setAttribute("country", "usa");
+personElem2.appendChild(addressElem5);
+
+peopleElem.appendChild(personElem1);
+peopleElem.appendChild(personElem2);
+doc.appendChild(peopleElem);
+
+ +

See also the DOM chapter of the XUL Tutorial.

+ +

You can automate the creation of a DOM tree using a JXON reverse algorithm in association with the following JSON representation:

+ +
{
+  "people": {
+    "person": [{
+      "address": [{
+        "@street": "321 south st",
+        "@city": "denver",
+        "@state": "co",
+        "@country": "usa"
+      }, {
+        "@street": "123 main st",
+        "@city": "arlington",
+        "@state": "ma",
+        "@country": "usa"
+      }],
+      "@first-name": "eric",
+      "@middle-initial": "H",
+      "@last-name": "jung"
+    }, {
+      "address": [{
+        "@street": "321 north st",
+        "@city": "atlanta",
+        "@state": "ga",
+        "@country": "usa"
+      }, {
+        "@street": "123 west st",
+        "@city": "seattle",
+        "@state": "wa",
+        "@country": "usa"
+      }, {
+        "@street": "321 south avenue",
+        "@city": "denver",
+        "@state": "co",
+        "@country": "usa"
+      }],
+      "@first-name": "jed",
+      "@last-name": "brown"
+    }]
+  }
+}
+
+ +

So what?

+ +

DOM trees can be queried using XPath expressions, converted to strings or written to a local or remote files using XMLSerializer (without having to first convert to a string), POSTed to a web server (via XMLHttpRequest), transformed using XSLT, XLink, converted to a JavaScript object through a JXON algorithm, etc.

+ +

You can use DOM trees to model data which isn't well-suited for RDF (or perhaps you just don't like RDF). Another application is that, since XUL is XML, the UI of your application can be dynamically manipulated, downloaded, uploaded, saved, loaded, converted, or transformed quite easily.

+ +

See also

+ + + +

{{ languages( { "fr": "fr/Comment_cr\u00e9er_un_arbre_DOM", "ja": "ja/How_to_create_a_DOM_tree", "zh-cn": "zh-cn/How_to_create_a_DOM_tree" } ) }}

diff --git a/files/zh-tw/web/api/document_object_model/index.html b/files/zh-tw/web/api/document_object_model/index.html new file mode 100644 index 0000000000..a2e07c7fdd --- /dev/null +++ b/files/zh-tw/web/api/document_object_model/index.html @@ -0,0 +1,384 @@ +--- +title: 文件物件模型 (DOM) +slug: Web/API/Document_Object_Model +tags: + - DOM + - DOM Reference + - DOM 參考 + - Intermediate +translation_of: Web/API/Document_Object_Model +--- +

{{DefaultAPISidebar("DOM")}}

+ +

文件物件模型(Document Object Model, DOM是 HTML、XML 和 SVG 文件的程式介面。它提供了一個文件(樹)的結構化表示法,並定義讓程式可以存取並改變文件架構、風格和內容的方法。DOM 提供了文件以擁有屬性與函式的節點與物件組成的結構化表示。節點也可以附加事件處理程序,一旦觸發事件就會執行處理程序。 本質上,它將網頁與腳本或程式語言連結在一起。

+ +

雖然常常使用 JavaScript 來存取 DOM,但它本身並不是 JavaScript 語言的一部分,而且它也可以被其他語言存取(雖然不太常見就是了)。

+ +

這裡有一篇 DOM 的介紹可供查閱。

+ +

DOM 介面

+ +
+ +
+ +

棄用的 DOM 介面

+ +

文件物件模型正被大量的簡化。為了達成這個目的,下這些介面是在 DOM level 3 或更早的規範中就被刪掉了。由於不清楚是否會被再度納入,請姑且當他們已經被遺棄,並避免使用:

+ +
+ +
+ +

HTML 介面

+ +

一份包含 html 的文件會透過 {{domxref("HTMLDocument")}} 介面來描述。注意 HTML 規範也擴展了 {{domxref("Document")}} 介面。

+ +

HTMLDocument 物件也提供了瀏覽器功能的存取:分頁、透過 {{domxref("Window")}} 介面描繪頁面的視窗、與其相關的 {{domxref("window.style", "樣式")}} (通常是 CSS )、與本文關聯的瀏覽器 {{domxref("window.history", "歷史")}}、以及一個文件內的 {{domxref("Selection", "選擇器")}}。

+ +

HTML 元素介面

+ +
+ +
+ +

其他介面

+ +
+ +
+ +

棄用的 HTML 介面

+ +
+ +
+ +

SVG 介面

+ +

SVG 元素介面

+ +
+ +
+ +

SVG 資料型別介面

+ +

這裡是資料型態的 DOM API,在 SVG 特性和性質的定義中被使用。

+ +
+

備註:從 {{Gecko("5.0")}} 開始,下列 SVG 相關的 DOM 介面物件的表示清單,現在可以被索引且可以像陣列般被取用;此外,他們也有 length 屬性來標示其清單中的項目個數:{{domxref("SVGLengthList")}}、{{domxref("SVGNumberList")}}、{{domxref("SVGPathSegList")}},和 {{domxref("SVGPointList")}}。

+
+ +

靜態類型

+ +
+ +
+ +

動畫類型

+ +
+ +
+ +

SMIL 相關介面

+ +
+ +
+ +

其他的 SVG 介面

+ +
+ +
+ +

相關連結

+ + diff --git a/files/zh-tw/web/api/document_object_model/whitespace/index.html b/files/zh-tw/web/api/document_object_model/whitespace/index.html new file mode 100644 index 0000000000..7e584a3dd6 --- /dev/null +++ b/files/zh-tw/web/api/document_object_model/whitespace/index.html @@ -0,0 +1,183 @@ +--- +title: DOM 中的空白字元 +slug: Web/API/Document_Object_Model/Whitespace +tags: + - DOM + - 所有類別 +translation_of: Web/API/Document_Object_Model/Whitespace +--- +

問題說明

+

DOM 裡的空白字元會讓處理節點結構時增加不少麻煩。Mozilla 相關軟體中,原始文件裡所有空白字元都會在 DOM 中出現(不包括標籤內含的空白字元)。這樣的處理方式有其必要,一方面編輯器中可逕行排列文字、二方面 CSS 裡的 white-space: pre 也才能發揮作用。 如此一來就表示:

+ +

換句話說,下面這段程式碼的 DOM 節點結構就如附圖一般,其中「\n」代表換行字元:

+
<!-- My document -->
+<html>
+<head>
+  <title>My Document</title>
+</head>
+<body>
+  <h1>Header</h1>
+  <p>
+    Paragraph
+  </p>
+</body>
+</html>
+
+ +

+ +

這麼一來,要使用 DOM 遊走於節點結構間又不想要無用的空白字元時,會有點困難。

+

助你一臂之力

+

以下的 JavaScript 程式碼定義了許多函式,讓你處理 DOM 中的空白字元時能輕鬆點:

+
/**
+ * 以下所謂的「空白字元」代表:
+ *  "\t" TAB \u0009 (移位字元)
+ *  "\n" LF  \u000A (換行字元)
+ *  "\r" CR  \u000D (歸位字元)
+ *  " "  SPC \u0020 (真正的空白)
+ *
+ * 不包括 JavaScript 的「\s」,因為那代表如不斷行字元等其他字元。
+ */
+
+
+/**
+ * 測知某節點的文字內容是否全為空白。
+ *
+ * @參數   nod  |CharacterData| 類的節點(如  |Text|、|Comment| 或 |CDATASection|)。
+ * @傳回值      若 |nod| 的文字內容全為空白則傳回 true,否則傳回 false。
+ */
+function is_all_ws( nod )
+{
+  // Use ECMA-262 Edition 3 String and RegExp features
+  return !(/[^\t\n\r ]/.test(nod.data));
+}
+
+
+/**
+ * 測知是否該略過某節點。
+ *
+ * @參數   nod  DOM1 |Node| 物件
+ * @傳回值      若 |Text| 節點內僅有空白字元或為 |Comment| 節點時,傳回 true,
+ *              否則傳回 false。
+ */
+
+function is_ignorable( nod )
+{
+  return ( nod.nodeType == 8) || // 註解節點
+         ( (nod.nodeType == 3) && is_all_ws(nod) ); // 僅含空白字元的文字節點
+}
+
+/**
+ * 此為會跳過空白字元節點及註解節點的 |previousSibling| 函式
+ * ( |previousSibling| 是 DOM 節點的特性值,為該節點的前一個節點。)
+ *
+ * @參數   sib  節點。
+ * @傳回值      有兩種可能:
+ *               1) |sib| 的前一個「非空白、非註解」節點(由 |is_ignorable| 測知。)
+ *               2) 若該節點前無任何此類節點,則傳回 null。
+ */
+function node_before( sib )
+{
+  while ((sib = sib.previousSibling)) {
+    if (!is_ignorable(sib)) return sib;
+  }
+  return null;
+}
+
+/**
+ * 此為會跳過空白字元節點及註解節點的 |nextSibling| 函式
+ *
+ * @參數   sib  節點。
+ * @傳回值      有兩種可能:
+ *               1) |sib| 的下一個「非空白、非註解」節點。
+ *               2) 若該節點後無任何此類節點,則傳回 null。
+ */
+function node_after( sib )
+{
+  while ((sib = sib.nextSibling)) {
+    if (!is_ignorable(sib)) return sib;
+  }
+  return null;
+}
+
+/**
+ * 此為會跳過空白字元節點及註解節點的 |lastChild| 函式
+ * ( lastChild| 是 DOM 節點的特性值,為該節點之中最後一個子節點。)
+ *
+ * @參數   par  節點。
+ * @傳回值      有兩種可能:
+ *               1) |par| 中最後一個「非空白、非註解」節點。
+ *               2) 若該節點中無任何此類子節點,則傳回 null。
+ */
+function last_child( par )
+{
+  var res=par.lastChild;
+  while (res) {
+    if (!is_ignorable(res)) return res;
+    res = res.previousSibling;
+  }
+  return null;
+}
+
+/**
+ * 此為會跳過空白字元節點及註解節點的 |firstChild| 函式
+ *
+ * @參數   par  節點。
+ * @傳回值      有兩種可能:
+ *               1) |par| 中第一個「非空白、非註解」節點。
+ *               2) 若該節點中無任何此類子節點,則傳回 null。
+ */
+function first_child( par )
+{
+  var res=par.firstChild;
+  while (res) {
+    if (!is_ignorable(res)) return res;
+    res = res.nextSibling;
+  }
+  return null;
+}
+
+/**
+ * 此為傳回值不包含文字節點資料的首尾所有空白字元、
+ * 並將兩個以上的空白字元縮減為一個的 |data| 函式。
+ *( data 是 DOM 文字節點的特性值,為該文字節點中的資料。)
+ *
+ * @參數   txt 欲傳回其中資料的文字節點
+ * @傳回值     文字節點的內容,其中空白字元已依前述方式處理。
+ */
+function data_of( txt )
+{
+  var data = txt.data;
+  // Use ECMA-262 Edition 3 String and RegExp features
+  data = data.replace(/[\t\n\r ]+/g, " ");
+  if (data.charAt(0) == " ")
+    data = data.substring(1, data.length);
+  if (data.charAt(data.length - 1) == " ")
+    data = data.substring(0, data.length - 1);
+  return data;
+}
+
+

範例

+

以下示範上述函式的應用方法,在節點結構中依序檢查、找出內容為「"This is the third paragraph"」的節點,並修改其 class 屬性及文字內容。

+
var cur = first_child(document.getElementById("test"));
+while (cur)
+{
+  if (data_of(cur.firstChild) == "This is the third paragraph.")
+  {
+      cur.className = "magic";
+      cur.firstChild.data = "This is the magic paragraph.";
+  }
+  cur = node_after(cur);
+}
+
+
+

原文資訊

+ +
diff --git "a/files/zh-tw/web/api/document_object_model/\344\272\213\344\273\266/index.html" "b/files/zh-tw/web/api/document_object_model/\344\272\213\344\273\266/index.html" new file mode 100644 index 0000000000..ff4ecfe572 --- /dev/null +++ "b/files/zh-tw/web/api/document_object_model/\344\272\213\344\273\266/index.html" @@ -0,0 +1,69 @@ +--- +title: 事件與DOM +slug: Web/API/Document_Object_Model/事件 +translation_of: Web/API/Document_Object_Model/Events +--- +

Introduction

+ +

This chapter describes the DOM Event Model. The Event interface itself is described, as well as the interfaces for event registration on nodes in the DOM, and event listeners, and several longer examples that show how the various event interfaces relate to one another.

+ +

There is an excellent diagram that clearly explains the three phases of event flow through the DOM in the DOM Level 3 Events draft.

+ +

Also see Example 5: Event Propagation in the Examples chapter for a more detailed example of how events move through the DOM.

+ +

Registering event listeners

+ +

There are 3 ways to register event handlers for a DOM element.

+ +

EventTarget.addEventListener

+ +
// Assuming myButton is a button element
+myButton.addEventListener('click', function(){alert('Hello world');}, false);
+
+ +

This is the method you should use in modern web pages.

+ +

Note: Internet Explorer 6-8 didn't support this method, offering a similar {{domxref("EventTarget.attachEvent")}} API instead. For cross-browser compatibility use one of the many JavaScript libraries available.

+ +

More details can be found on the {{domxref("EventTarget.addEventListener")}} reference page.

+ +

HTML attribute

+ +
<button onclick="alert('Hello world!')">
+
+ +

The JavaScript code in the attribute is passed the Event object via the event parameter. The return value is treated in a special way, described in the HTML specification.

+ +

This way should be avoided. This makes the markup bigger and less readable. Concerns of content/structure and behavior are not well-separated, making a bug harder to find.

+ +

DOM element properties

+ +
// Assuming myButton is a button element
+myButton.onclick = function(event){alert('Hello world');};
+
+ +

The function can be defined to take an event parameter. The return value is treated in a special way, described in the HTML specification.

+ +

The problem with this method is that only one handler can be set per element and per event.

+ +

Accessing Event interfaces

+ +

Event handlers may be attached to various objects including DOM elements, document, the window object, etc. When an event occurs, an event object is created and passed sequentially to the event listeners.

+ +

The {{domxref("Event")}} interface is accessible from within the handler function, via the event object passed as the first argument. The following simple example shows how an event object is passed to the event handler function, and can be used from within one such function.

+ +
function foo(evt) {
+  // the evt parameter is automatically assigned the event object
+  alert(evt);
+}
+table_el.onclick = foo;
+
+ + + + diff --git a/files/zh-tw/web/api/documentfragment/index.html b/files/zh-tw/web/api/documentfragment/index.html new file mode 100644 index 0000000000..a3926841e0 --- /dev/null +++ b/files/zh-tw/web/api/documentfragment/index.html @@ -0,0 +1,248 @@ +--- +title: DocumentFragment +slug: Web/API/DocumentFragment +translation_of: Web/API/DocumentFragment +--- +

{{ ApiRef("DOM") }}

+ +

DocumentFragment 介面表示了一個沒有父節點的最小化文件物件。DocumentFragment 被當作一種輕量化的 {{domxref("Document")}},用如同標準文件一般的方式保存片段的文件結構(由節點組成)。關鍵的區別在於文件片段不是真實的 DOM 結構,文件片段的變動並不會影響目前的網頁文件,也不會導致回流({{Glossary("reflow")}})或引起任何影響效能的情況發生。

+ +

一般的用法是建立一個 DocumentFragment 物件,在此物件中組織一個 DOM 的子樹。再使用 {{domxref("Node")}} 介面定義的方法,如 {{domxref("Node.appendChild", "appendChild()")}} 或 {{domxref("Node.insertBefore", "insertBefore()")}} 將這個文件片段加入或插入目前頁面的 DOM 當中。執行這個將文件片段中的節點置入 DOM 的動作之後,會留下一個空的 DocumentFragment 物件(只會插入物件中的節點,DocumentFragment 物件本身不會被插入)。由於文件片段中的所有節點是一次性的被插入目前頁面文件當中,故回流及頁面渲染只會被觸發一次,所以可用插入 DocumentFragment 物件的方式取代傳統分別插入多個節點至 DOM(將節點一個一個分次進行插入)的操作方式。

+ +

此介面也適合與 Web components 搭配使用:{{HTMLElement("template")}} 元素在其 {{domxref("HTMLTemplateElement.content")}} 屬性中便包含了一個 DocumentFragment 物件。

+ +

可使用 {{domxref("document.createDocumentFragment()")}} 方法或 DocumentFragment 的建構式來建立一個空的 DocumentFragment 物件。

+ +

屬性

+ +

This interface has no specific properties, but inherits those of its parent, {{domxref("Node")}}, and implements those of the {{domxref("ParentNode")}} interface.

+ +
+
{{ domxref("ParentNode.children") }} {{readonlyInline}}{{experimental_inline}}
+
Returns a live {{domxref("HTMLCollection")}} containing all objects of type {{domxref("Element")}} that are children of the DocumentFragment object.
+
{{ domxref("ParentNode.firstElementChild") }} {{readonlyInline}}{{experimental_inline}}
+
Returns the {{domxref("Element")}} that is the first child of the DocumentFragment object, or null if there is none.
+
{{ domxref("ParentNode.lastElementChild") }} {{readonlyInline}}{{experimental_inline}}
+
Returns the {{domxref("Element")}} that is the last child of the DocumentFragment object, or null if there is none.
+
{{ domxref("ParentNode.childElementCount") }} {{readonlyInline}}{{experimental_inline}}
+
Returns an unsigned long giving the amount of children that the DocumentFragment has.
+
+ +

建構式

+ +
+
{{ domxref("DocumentFragment.DocumentFragment()", "DocumentFragment()") }} {{experimental_inline}}
+
Returns an empty DocumentFragment object.
+
+ +

方法

+ +

This interface inherits the methods of its parent, {{domxref("Node")}}, and implements those of the {{domxref("ParentNode")}} interface.

+ +
+
{{domxref("DocumentFragment.find()")}} {{experimental_inline}}
+
Returns the first matching {{domxref("Element")}} in the tree of the DocumentFragment.
+
{{domxref("DocumentFragment.findAll()")}} {{experimental_inline}}
+
Returns a {{domxref("NodeList")}} of matching {{domxref("Element")}} in the tree of the DocumentFragment.
+
{{domxref("DocumentFragment.querySelector()")}}
+
Returns the first {{domxref("Element")}} node within the DocumentFragment, in document order, that matches the specified selectors.
+
{{domxref("DocumentFragment.querySelectorAll()")}}
+
Returns a {{domxref("NodeList")}} of all the {{domxref("Element")}} nodes within the DocumentFragment that match the specified selectors.
+
+ +
+
{{domxref("DocumentFragment.getElementById()")}}
+
Returns the first {{domxref("Element")}} node within the DocumentFragment, in document order, that matches the specified ID.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#interface-documentfragment', 'DocumentFragment')}}{{Spec2('DOM WHATWG')}}Added the constructor and the implementation of {{domxref("ParentNode")}}.
{{SpecName('Selectors API Level 2', '#the-apis', 'DocumentFragment')}}{{Spec2('Selectors API Level 2')}}Added the find() and findAll() methods.
{{SpecName('Selectors API Level 1', '#the-apis', 'DocumentFragment')}}{{Spec2('Selectors API Level 1')}}Added the querySelector() and querySelectorAll() methods.
{{SpecName('DOM3 Core', 'core.html#ID-B63ED1A3', 'DocumentFragment')}}{{Spec2('DOM3 Core')}}No change from {{SpecName('DOM2 Core')}}
{{SpecName('DOM2 Core', 'core.html#ID-B63ED1A3', 'DocumentFragment')}}{{Spec2('DOM2 Core')}}No change from {{SpecName('DOM1')}}
{{SpecName('DOM1', 'level-one-core.html#ID-B63ED1A3', 'DocumentFragment')}}{{Spec2('DOM1')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.0")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
querySelector() and querySelectorAll()1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9.1")}}8.010.03.2 (525.3)
findAll() and find() {{experimental_inline}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
DocumentFragment() constructor {{experimental_inline}}28.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("24.0")}}{{CompatNo}}15.0{{CompatNo}}
ParentNode properties {{experimental_inline}}28.0{{CompatNo}}{{CompatGeckoDesktop("25.0")}}{{CompatNo}}15.0{{CompatNo}}
ParentNode methods {{experimental_inline}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("1.0")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
querySelector() and querySelectorAll()2.1{{CompatVersionUnknown}}{{CompatGeckoMobile("1.0")}}8.010.03.2 (525.3)
findAll() and find() {{experimental_inline}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
DocumentFragment() constructor {{experimental_inline}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("24.0")}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}
ParentNode properties {{experimental_inline}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatGeckoMobile("25.0")}}{{CompatNo}}5.0{{CompatNo}}
ParentNode methods {{experimental_inline}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/documenttype/index.html b/files/zh-tw/web/api/documenttype/index.html new file mode 100644 index 0000000000..f0d7ae32b4 --- /dev/null +++ b/files/zh-tw/web/api/documenttype/index.html @@ -0,0 +1,200 @@ +--- +title: DocumentType +slug: Web/API/DocumentType +tags: + - API + - DOM + - DocumentType + - Interface +translation_of: Web/API/DocumentType +--- +
{{APIRef("DOM")}}
+ +

DocumentType 介面表示了一個代表文件類型的 {{domxref("Node")}} 節點。

+ +

{{InheritanceDiagram}}

+ +

屬性

+ +

此介面繼承了其父介面 {{domxref("Node")}} 的屬性,以及實作了 {{domxref("ChildNode")}} 介面。

+ +
+
{{domxref("DocumentType.entities")}} {{readonlyInline}} {{obsolete_Inline}}
+
A {{domxref("NamedNodeMap")}} of entities declared in the DTD. Every node in this map implements the {{domxref("Entity")}} interface.
+
{{domxref("DocumentType.internalSubset")}} {{readonlyInline}} {{obsolete_Inline}}
+
A {{domxref("DOMString")}} of the internal subset, or null if there is none. Eg "<!ELEMENT foo (bar)>".
+
{{domxref("DocumentType.name")}} {{readonlyInline}}
+
A {{domxref("DOMString")}}, eg "html" for <!DOCTYPE HTML>.
+
{{domxref("DocumentType.notations")}} {{readonlyInline}} {{obsolete_Inline}}
+
A {{domxref("NamedNodeMap")}} with notations declared in the DTD. Every node in this map implements the {{domxref("Notation")}} interface.
+
{{domxref("DocumentType.publicId")}} {{readonlyInline}}
+
A {{domxref("DOMString")}}, eg "-//W3C//DTD HTML 4.01//EN", empty string for HTML5.
+
{{domxref("DocumentType.systemId")}} {{readonlyInline}}
+
A {{domxref("DOMString")}}, eg "http://www.w3.org/TR/html4/strict.dtd", empty string for HTML5.
+
+ +

方法

+ +

此介面繼承了其父介面 {{domxref("Node")}} 的方法,以及實作了 {{domxref("ChildNode")}} 介面。

+ +
+
{{domxref("ChildNode.remove()")}} {{experimental_inline}}
+
Removes the object from its parent children list.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#documenttype', 'DocumentType')}}{{Spec2('DOM WHATWG')}}Added implemention of the {{domxref("ChildNode")}} interface.
+ Removed the internalSubset, entities, and notation properties.
{{SpecName('DOM3 Core', 'core.html#ID-412266927', 'DocumentType')}}{{Spec2('DOM3 Core')}}No change from {{SpecName('DOM2 Core')}}.
{{SpecName('DOM2 Core', 'core.html#ID-412266927', 'DocumentType')}}{{Spec2('DOM2 Core')}}Added the publicID, systemID, and internalSubset properties.
{{SpecName('DOM1', 'level-one-core.html#ID-412266927', 'DocumentType')}}{{Spec2('DOM1')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.0")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
entities and notations1.0[1]{{CompatVersionUnknown}}[3]{{CompatGeckoDesktop("1.0")}}
+ {{CompatNo}}{{CompatGeckoDesktop("6.0")}}
{{CompatVersionUnknown}}[3]{{CompatVersionUnknown}}[1]{{CompatVersionUnknown}}
internalSubset{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatNo}} (not anymore in any case){{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}
Implements {{domxref("ChildNode")}}29.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("25.0")}}[2]{{CompatNo}}16.0{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("1.0")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
entities and notations{{CompatVersionUnknown}}[1]{{CompatVersionUnknown}}{{CompatGeckoMobile("1.0")}}
+ {{CompatNo}}{{CompatGeckoMobile("6.0")}}
{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
internalSubset{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
Implements {{domxref("ChildNode")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("25.0")}}[2]{{CompatNo}}16.0{{CompatNo}}
+
+ +

[1] The Chromium project plans to drop supports for the internalSubset, entities and notations methods.

+ +

[2] Firefox 25 also added the previousElementSibling and nextElementSibling properties, this was removed in Firefox 28 due to compatibility problems.

+ +

[3] entities and notations properties exist in IE and Edge, but seem to always be null?

+ +

參見

+ + diff --git a/files/zh-tw/web/api/domparser/index.html b/files/zh-tw/web/api/domparser/index.html new file mode 100644 index 0000000000..4ded67f1c3 --- /dev/null +++ b/files/zh-tw/web/api/domparser/index.html @@ -0,0 +1,200 @@ +--- +title: DOMParser +slug: Web/API/DOMParser +tags: + - DOMParser SVG XML +translation_of: Web/API/DOMParser +--- +

{{APIRef("DOM")}}{{SeeCompatTable}}

+ +

DOMParser可以將XML或是HTML格式的字串轉成DOM 文件. DOMParser的規格請參閱DOM解譯與串流化.

+ +

請注意XMLHttpRequest解譯的是URL連結內容裡的XML與HTML文件.

+ +

產生一個 DOMParser

+ +

new DOMParser()" 可產生DOMParser.

+ +

關於如何在Firefox外掛程式中產生DOMParser,請參考nsIDOMParser文件

+ +

解譯 XML

+ +

產生解譯物件後,請呼叫parseFromString方法函式來將XML字串轉換成DOM物件:

+ +
var parser = new DOMParser();
+var doc = parser.parseFromString(stringContainingXMLSource, "application/xml");
+
+ +

錯誤處理

+ +

請注意如果解譯過程出錯,目前的DOMParser不會丟出異常物件(exception),但是會回傳一個錯誤文件(請看程式臭蟲{{Bug(45566)}}):

+ +
<parsererror xmlns="http://www.mozilla.org/newlayout/xml/parsererror.xml">
+(error description)
+<sourcetext>(a snippet of the source XML)</sourcetext>
+</parsererror>
+
+ +

解譯錯誤也會記錄在錯誤終端機中(Error Console), 紀錄裡頭的文件URI (如下) 則為錯誤來源.

+ +

解譯 SVG 或 HTML 文件

+ +

DOMParser也可以用來解譯 SVG 文件 {{geckoRelease("10.0")}} 或是 HTML 文件 {{geckoRelease("12.0")}}. 可以依 MIME 格式,輸出三種不同格式. 如果MIME 格式是 text/xml,輸出的格式為 XMLDocument, 如果 MIME 格式是 image/svg+xml, 輸出格式為 SVGDocument, 如果 MIME 格式是 text/html, 輸出格式則為 HTMLDocument.

+ +
var parser = new DOMParser();
+var doc = parser.parseFromString(stringContainingXMLSource, "application/xml");
+// returns a Document, but not a SVGDocument nor a HTMLDocument
+
+parser = new DOMParser();
+doc = parser.parseFromString(stringContainingXMLSource, "image/svg+xml");
+// returns a SVGDocument, which also is a Document.
+
+parser = new DOMParser();
+doc = parser.parseFromString(stringContainingHTMLSource, "text/html");
+// returns a HTMLDocument, which also is a Document.
+
+ +

其他瀏覽器可用的DOMParser HTML 外掛程式

+ +
/*
+ * DOMParser HTML extension
+ * 2012-09-04
+ *
+ * By Eli Grey, http://eligrey.com
+ * Public domain.
+ * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+ */
+
+/*! @source https://gist.github.com/1129031 */
+/*global document, DOMParser*/
+
+(function(DOMParser) {
+	"use strict";
+
+	var
+	  proto = DOMParser.prototype
+	, nativeParse = proto.parseFromString
+	;
+
+	// Firefox/Opera/IE throw errors on unsupported types
+	try {
+		// WebKit returns null on unsupported types
+		if ((new DOMParser()).parseFromString("", "text/html")) {
+			// text/html parsing is natively supported
+			return;
+		}
+	} catch (ex) {}
+
+	proto.parseFromString = function(markup, type) {
+		if (/^\s*text\/html\s*(?:;|$)/i.test(type)) {
+			var
+			  doc = document.implementation.createHTMLDocument("")
+			;
+	      		if (markup.toLowerCase().indexOf('<!doctype') > -1) {
+        			doc.documentElement.innerHTML = markup;
+      			}
+      			else {
+        			doc.body.innerHTML = markup;
+      			}
+			return doc;
+		} else {
+			return nativeParse.apply(this, arguments);
+		}
+	};
+}(DOMParser));
+
+ +

DOMParser from Chrome/JSM/XPCOM/Privileged Scope

+ +

See article here: nsIDOMParser

+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
XML support{{CompatChrome(1)}}{{CompatGeckoDesktop(1)}}{{CompatIE(9)}}{{CompatOpera(8)}}{{CompatSafari(3.2)}}
SVG support{{CompatChrome(4)}}{{CompatGeckoDesktop(10.0)}}{{CompatIE(10)}}{{CompatOpera(15)}}{{CompatSafari(3.2)}}
HTML support{{CompatChrome(30)}}{{CompatGeckoDesktop(12.0)}}{{CompatIE(10)}}{{CompatOpera(17)}}{{CompatSafari(7.1)}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
XML support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}
SVG support{{CompatUnknown}}{{CompatGeckoMobile(10.0)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
HTML support{{CompatUnknown}}{{CompatGeckoMobile(12.0)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

參考資料

+ + diff --git a/files/zh-tw/web/api/domstring/index.html b/files/zh-tw/web/api/domstring/index.html new file mode 100644 index 0000000000..396773ce7f --- /dev/null +++ b/files/zh-tw/web/api/domstring/index.html @@ -0,0 +1,50 @@ +--- +title: DOMString +slug: Web/API/DOMString +translation_of: Web/API/DOMString +--- +

{{APIRef("DOM")}}

+ +

DOMString 是編碼為 UTF-16 的字串。當 JavaScript 使用這類字串時, DOMString 會映射成一個 {{jsxref("String")}}.

+ +

傳送 null 給接受 DOMString 的 method 或參數時,會將其轉換成 "null"

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('WebIDL', '#idl-DOMString', 'DOMString')}}{{Spec2('WebIDL')}}修正定義文件用詞。並移除奇特的極端請況。
{{SpecName('DOM3 Core', 'core.html#DOMString', 'DOMString')}}{{Spec2('DOM3 Core')}}No change from {{SpecName('DOM2 Core')}}
{{SpecName('DOM2 Core', 'core.html#ID-C74D1578', 'DOMString')}}{{Spec2('DOM2 Core')}}No change from {{SpecName('DOM1')}}
{{SpecName('DOM1', 'level-one-core.html#ID-C74D1578', 'DOMString')}}{{Spec2('DOM1')}}初次定義 DOMString 。
+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/api/domtokenlist/index.html b/files/zh-tw/web/api/domtokenlist/index.html new file mode 100644 index 0000000000..998c3b6e48 --- /dev/null +++ b/files/zh-tw/web/api/domtokenlist/index.html @@ -0,0 +1,117 @@ +--- +title: DOMTokenList +slug: Web/API/DOMTokenList +translation_of: Web/API/DOMTokenList +--- +

{{APIRef("DOM")}}{{gecko_minversion_header("1.9.2")}}

+ +

DOMTokenList 介面表示了一個以空格作為分隔的內容集,通常來自 {{domxref("Element.classList")}}、{{domxref("HTMLLinkElement.relList")}}、{{domxref("HTMLAnchorElement.relList")}} 或 {{domxref("HTMLAreaElement.relList")}} 等屬性。本介面與 {{jsxref("Array")}} 同樣是由 0 開始索引,且 DOMTokenList 是區分大小寫的。

+ +

屬性

+ +

This interface doesn't inherit any property.

+ +
+
{{domxref("DOMTokenList.length")}} {{ReadOnlyInline}}
+
Is an integer representing the number of objects stored in the object.
+
+ +

方法

+ +

This interface doesn't inherit any method.

+ +
+
{{domxref("DOMTokenList.item()")}}
+
Returns an item in the list by its index (or undefined if the number is greater than or equal to the length of the list, prior to {{gecko("7.0")}} returned null)
+
{{domxref("DOMTokenList.contains()")}}
+
Returns true if the underlying string contains token, otherwise false
+
{{domxref("DOMTokenList.add()")}}
+
Adds token to the underlying string
+
{{domxref("DOMTokenList.remove()")}}
+
Removes token from the underlying string
+
{{domxref("DOMTokenList.replace()")}}
+
Replaces an existing token with a new token.
+
{{domxref("DOMTokenList.supports()")}}
+
Returns true if a given token is in the associated attribute's supported tokens.
+
{{domxref("DOMTokenList.toggle()")}}
+
Removes token from string and returns false. If token doesn't exist it's added and the function returns true
+
+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("DOM WHATWG", "#interface-domtokenlist", "DOMTokenList")}}{{Spec2("DOM WHATWG")}}Initial definition
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}10{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewFirefox Mobile (Gecko)IE PhoneOpera MobileSafari MobileChrome for Android
Basic support{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/dragevent/datatransfer/index.html b/files/zh-tw/web/api/dragevent/datatransfer/index.html new file mode 100644 index 0000000000..f46de41856 --- /dev/null +++ b/files/zh-tw/web/api/dragevent/datatransfer/index.html @@ -0,0 +1,118 @@ +--- +title: DragEvent.dataTransfer +slug: Web/API/DragEvent/dataTransfer +translation_of: Web/API/DragEvent/dataTransfer +--- +
{{APIRef("HTML Drag and Drop API")}}
+ +

DataEvent.dataTransfer 屬性保留了拖曳操作中的資料(指向一個 {{domxref("DataTransfer")}} 物件)。

+ +

此屬性為 {{readonlyInline}}。

+ +

語法

+ +
var data = dragEvent.dataTransfer;
+
+ +

回傳值

+ +
+
data
+
一個保存 {{domxref("DragEvent")}} 當中資料的 {{domxref("DataTransfer")}} 物件。
+
+ +

範例

+ +

This example illustrates accessing the drag and drop data within the {{event("dragend")}} event handler.

+ +
function process_data(d) {
+   // Process the data ...
+}
+
+dragTarget.addEventListener("dragend", function(ev) {
+   // Call the drag and drop data processor
+   if (ev.dataTransfer != null) process_data(ev.dataTransfer);
+ }, false);
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("HTML WHATWG", "interaction.html#dom-dragevent-datatransfer", "DragEvent.dataTransfer")}}{{Spec2("HTML WHATWG")}} 
{{SpecName("HTML5.1", "editing.html#dom-dragevent-datatransfer", "DragEvent.dataTransfer")}}{{Spec2("HTML5.1")}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support4{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9.1")}}10123.1
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewChrome for AndroidEdgeFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari Mobile
Basic support{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}{{CompatIE("10")}}{{CompatNo}}{{CompatNo}}
+
diff --git a/files/zh-tw/web/api/dragevent/index.html b/files/zh-tw/web/api/dragevent/index.html new file mode 100644 index 0000000000..45f233ab58 --- /dev/null +++ b/files/zh-tw/web/api/dragevent/index.html @@ -0,0 +1,160 @@ +--- +title: DragEvent +slug: Web/API/DragEvent +translation_of: Web/API/DragEvent +--- +
{{APIRef("HTML Drag and Drop API")}}
+ +

DragEvent 介面是一種 {{domxref("Event","DOM event")}},定義了拖放操作時產生的事件物件。使用者藉由把指標裝置 (例如滑鼠) 放到有效區域並拖移到另一個新的位置 ( 如另外一個 DOM 元素 ) 來開始一個拖動的動作。 而應用程式可以自由地決定互動的方式來達到符合該應用程式的使用情境。

+ + + +

This interface inherits properties from {{domxref("MouseEvent")}} and {{domxref("Event")}}.

+ +

屬性

+ +
+
{{domxref('DragEvent.dataTransfer')}} {{readonlyInline}}
+
The data that is transferred during a drag and drop interaction.
+
+ +

建構式

+ +

Although this interface has a constructor, it is not possible to create a useful DataTransfer object from script, since {{domxref("DataTransfer")}} objects have a processing and security model that is coordinated by the browser during drag-and-drops.

+ +
+
{{domxref("DragEvent.DragEvent", "DragEvent()")}}
+
Creates a synthetic and untrusted DragEvent.
+
+ +

事件類型

+ +
+
{{event('drag')}}
+
在『被選擇的物件』被拖曳時觸發。
+
{{event('dragend')}}
+
在『被選擇的物件』結束拖曳時觸發 (就是放開滑鼠鍵、或按下 Esc 鍵時)。
+
{{event('dragenter')}}
+
當『被選擇的物件』被拖曳到『可以當目標的物件』時, 在『進入』該目標物件上方的瞬間觸發。注意, 不是『被選擇的物件』觸發此事件, 而是『可以當目標的物件』。
+
{{event('dragexit')}}
+
This event is fired when an element is no longer the drag operation's immediate selection target.
+
{{event('dragleave')}}
+
當『被選擇的物件』被拖曳到『可以當目標的物件』時, 在『離開』該目標物件上方的瞬間觸發。注意, 不是『被選擇的物件』觸發此事件, 而是『可以當目標的物件』。
+
{{event('dragover')}}
+
當『被選擇的物件』被拖曳到『可以當目標的物件』的上方時觸發 (頻率大約每秒數次)。注意, 不是『被選擇的物件』觸發此事件, 而是『可以當目標的物件』 。
+
{{event('dragstart')}}
+
在『被選擇的物件』開始拖曳時觸發。
+
{{event('drop')}}
+
當『被選擇的物件』被拖曳、放到『目標物件』時觸發。注意, 不是『被選擇的物件』觸發此事件, 而是『目標物件』。
+
+ +

通用事件處理器

+ +
+
{{domxref('GlobalEventHandlers.ondrag')}}
+
A {{domxref('GlobalEventHandlers','global event handler')}} for the {{event('drag')}} event.
+
{{domxref('GlobalEventHandlers.ondragend')}}
+
A {{domxref('GlobalEventHandlers','global event handler')}} for the {{event('dragend')}} event.
+
{{domxref('GlobalEventHandlers.ondragenter')}}
+
A {{domxref('GlobalEventHandlers','global event handler')}} for the {{event('dragenter')}} event.
+
{{domxref('GlobalEventHandlers.ondragexit')}}
+
A {{domxref('GlobalEventHandlers','global event handler')}} for the {{event('dragexit')}} event.
+
{{domxref('GlobalEventHandlers.ondragleave')}}
+
A {{domxref('GlobalEventHandlers','global event handler')}} for the {{event('dragleave')}} event.
+
{{domxref('GlobalEventHandlers.ondragover')}}
+
A {{domxref('GlobalEventHandlers','global event handler')}} for the {{event('dragover')}} event.
+
{{domxref('GlobalEventHandlers.ondragstart')}}
+
A {{domxref('GlobalEventHandlers','global event handler')}} for the {{event('dragstart')}} event.
+
{{domxref('GlobalEventHandlers.ondrop')}}
+
A {{domxref('GlobalEventHandlers','global event handler')}} for the {{event('drop')}} event.
+
+ +

範例

+ +

An Example of each property, constructor, event type and global event handlers is included in their respective reference page.

+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("HTML WHATWG", "interaction.html#the-dragevent-interface", "DragEvent")}}{{Spec2("HTML WHATWG")}}
{{SpecName("HTML5.1", "editing.html#the-dragevent-interface", "DragEvent")}}{{Spec2("HTML5.1")}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support4{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9.1")}}10123.1
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewChrome for AndroidEdgeFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari Mobile
Basic support{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}{{CompatIE("10")}}{{CompatNo}}{{CompatNo}}
+
+ +

參見

+ +

{{page("/zh-TW/docs/Web/API/DataTransfer", "參見")}}

diff --git a/files/zh-tw/web/api/element/attributes/index.html b/files/zh-tw/web/api/element/attributes/index.html new file mode 100644 index 0000000000..ce24985c8b --- /dev/null +++ b/files/zh-tw/web/api/element/attributes/index.html @@ -0,0 +1,121 @@ +--- +title: Element.attributes +slug: Web/API/Element/attributes +translation_of: Web/API/Element/attributes +--- +

{{ APIRef("DOM") }}

+ +

 

+ +

The Element.attributes property returns a live collection of all attribute nodes registered to the specified node. It is a {{domxref("NamedNodeMap")}}, not an Array, so it has no {{jsxref("Array")}} methods and the {{domxref("Attr")}} nodes' indexes may differ among browsers. To be more specific, attributes is a key/value pair of strings that represents any information regarding that attribute.

+ +

 

+ +

Element.attribute 特性會把特定節點裡所有的屬性變成一個集合,然後回傳出來. 這是一個  NamedNodeMap, 而並非一個陣列. 所以它並沒有陣列的方法和在瀏覽器中  Attr節點裡的索引值也可能不同. 更詳細的來說, attributes 是一個鍵/值的配對, 它包含了所有有關於這個節點屬性的資訊

+ +

 

+ +

Syntax

+ +
var attr = element.attributes;
+
+ +

Example

+ +

Basic examples

+ +
// Get the first <p> element in the document
+var para = document.getElementsByTagName("p")[0];
+var atts = para.attributes;
+ +

Enumerating elements attributes

+ +

Numerical indexing is useful for going through all of an element's attributes.
+ The following example runs through the attribute nodes for the element in the document with id "paragraph", and prints each attribute's value.

+ +
<!DOCTYPE html>
+
+<html>
+
+ <head>
+  <title>Attributes example</title>
+  <script type="text/javascript">
+   function listAttributes() {
+     var paragraph = document.getElementById("paragraph");
+     var result = document.getElementById("result");
+
+     // First, let's verify that the paragraph has some attributes
+     if (paragraph.hasAttributes()) {
+       var attrs = paragraph.attributes;
+       var output = "";
+       for(var i = attrs.length - 1; i >= 0; i--) {
+         output += attrs[i].name + "->" + attrs[i].value;
+       }
+       result.value = output;
+     } else {
+       result.value = "No attributes to show";
+     }
+   }
+  </script>
+ </head>
+
+<body>
+ <p id="paragraph" style="color: green;">Sample Paragraph</p>
+ <form action="">
+  <p>
+    <input type="button" value="Show first attribute name and value"
+      onclick="listAttributes();">
+    <input id="result" type="text" value="">
+  </p>
+ </form>
+</body>
+</html>
+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-element-attributes', 'Element.attributes')}}{{Spec2('DOM WHATWG')}}From {{SpecName('DOM3 Core')}}, moved from {{domxref("Node")}} to {{domxref("Element")}}
{{SpecName('DOM3 Core', 'core.html#ID-84CF096', 'Element.attributes')}}{{Spec2('DOM3 Core')}}No change from {{SpecName('DOM2 Core')}}
{{SpecName('DOM2 Core', 'core.html#ID-84CF096', 'Element.attributes')}}{{Spec2('DOM2 Core')}}No change from {{SpecName('DOM1')}}
{{SpecName('DOM1', 'level-one-core.html#ID-84CF096', 'Element.attributes')}}{{Spec2('DOM1')}}Initial definition.
+ +

Browser compatibility

+ + + +

{{Compat("api.Element.attributes")}}

+ +

See also

+ + diff --git a/files/zh-tw/web/api/element/classlist/index.html b/files/zh-tw/web/api/element/classlist/index.html new file mode 100644 index 0000000000..afa5b7c862 --- /dev/null +++ b/files/zh-tw/web/api/element/classlist/index.html @@ -0,0 +1,403 @@ +--- +title: Element.classList +slug: Web/API/Element/classList +translation_of: Web/API/Element/classList +--- +
{{APIRef("DOM")}}
+ +

Element.classList 唯讀屬性代表了該元素所擁有之類別屬性(Class {{Glossary("Attribute")}})的即時更新集-{{domxref("DOMTokenList")}}。

+ +

使用 classList 屬性是取得元素 Class 的一種便利方式,也可以透過 {{domxref("element.className")}} 來得到以空格分隔之 Class 清單字串。

+ +

語法

+ +
var elementClasses = elementNodeReference.classList;
+
+ +

elementClasses is a {{domxref("DOMTokenList")}} representing the class attribute of elementNodeReference. If the class attribute was not set or is empty elementClasses.length returns 0. element.classList itself is read-only, although you can modify it using the add() and remove() methods.

+ +

方法

+ +
+
add( String [, String] )
+
Add specified class values. If these classes already exist in attribute of the element, then they are ignored.
+
remove( String [,String] )
+
Remove specified class values.
+
item ( Number )
+
Return class value by index in collection.
+
toggle ( String [, force] )
+
When only one argument is present: Toggle class value; i.e., if class exists then remove it and return false, if not, then add it and return true.
+ When a second argument is present: If the second argument is true, add specified class value, and if it is false, remove it.
+
contains( String )
+
Checks if specified class value exists in class attribute of the element.
+
+ +

範例

+ +
// div is an object reference to a <div> element with class="foo bar"
+div.classList.remove("foo");
+div.classList.add("anotherclass");
+
+// if visible is set remove it, otherwise add it
+div.classList.toggle("visible");
+
+//  add/remove visible, depending on test conditional, i less than 10
+div.classList.toggle("visible", i < 10 );
+
+alert(div.classList.contains("foo"));
+
+div.classList.add("foo","bar"); //add multiple classes
+ +
+

Versions of Firefox before 26 do not implement the use of several arguments in the add/remove/toggle methods. See https://bugzilla.mozilla.org/show_bug.cgi?id=814014

+
+ +

JavaScript shim for other implementations

+ +
Note: This shim does not work in Internet Explorer versions less than 8.
+ +
/*
+ * classList.js: Cross-browser full element.classList implementation.
+ * 2014-07-23
+ *
+ * By Eli Grey, http://eligrey.com
+ * Public Domain.
+ * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+ */
+
+/*global self, document, DOMException */
+
+/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
+
+if ("document" in self) {
+
+// Full polyfill for browsers with no classList support
+if (!("classList" in document.createElement("_"))) {
+
+(function (view) {
+
+"use strict";
+
+if (!('Element' in view)) return;
+
+var
+    classListProp = "classList"
+  , protoProp = "prototype"
+  , elemCtrProto = view.Element[protoProp]
+  , objCtr = Object
+  , strTrim = String[protoProp].trim || function () {
+    return this.replace(/^\s+|\s+$/g, "");
+  }
+  , arrIndexOf = Array[protoProp].indexOf || function (item) {
+    var
+        i = 0
+      , len = this.length
+    ;
+    for (; i < len; i++) {
+      if (i in this && this[i] === item) {
+        return i;
+      }
+    }
+    return -1;
+  }
+  // Vendors: please allow content code to instantiate DOMExceptions
+  , DOMEx = function (type, message) {
+    this.name = type;
+    this.code = DOMException[type];
+    this.message = message;
+  }
+  , checkTokenAndGetIndex = function (classList, token) {
+    if (token === "") {
+      throw new DOMEx(
+          "SYNTAX_ERR"
+        , "An invalid or illegal string was specified"
+      );
+    }
+    if (/\s/.test(token)) {
+      throw new DOMEx(
+          "INVALID_CHARACTER_ERR"
+        , "String contains an invalid character"
+      );
+    }
+    return arrIndexOf.call(classList, token);
+  }
+  , ClassList = function (elem) {
+    var
+        trimmedClasses = strTrim.call(elem.getAttribute("class") || "")
+      , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
+      , i = 0
+      , len = classes.length
+    ;
+    for (; i < len; i++) {
+      this.push(classes[i]);
+    }
+    this._updateClassName = function () {
+      elem.setAttribute("class", this.toString());
+    };
+  }
+  , classListProto = ClassList[protoProp] = []
+  , classListGetter = function () {
+    return new ClassList(this);
+  }
+;
+// Most DOMException implementations don't allow calling DOMException's toString()
+// on non-DOMExceptions. Error's toString() is sufficient here.
+DOMEx[protoProp] = Error[protoProp];
+classListProto.item = function (i) {
+  return this[i] || null;
+};
+classListProto.contains = function (token) {
+  token += "";
+  return checkTokenAndGetIndex(this, token) !== -1;
+};
+classListProto.add = function () {
+  var
+      tokens = arguments
+    , i = 0
+    , l = tokens.length
+    , token
+    , updated = false
+  ;
+  do {
+    token = tokens[i] + "";
+    if (checkTokenAndGetIndex(this, token) === -1) {
+      this.push(token);
+      updated = true;
+    }
+  }
+  while (++i < l);
+
+  if (updated) {
+    this._updateClassName();
+  }
+};
+classListProto.remove = function () {
+  var
+      tokens = arguments
+    , i = 0
+    , l = tokens.length
+    , token
+    , updated = false
+    , index
+  ;
+  do {
+    token = tokens[i] + "";
+    index = checkTokenAndGetIndex(this, token);
+    while (index !== -1) {
+      this.splice(index, 1);
+      updated = true;
+      index = checkTokenAndGetIndex(this, token);
+    }
+  }
+  while (++i < l);
+
+  if (updated) {
+    this._updateClassName();
+  }
+};
+classListProto.toggle = function (token, force) {
+  token += "";
+
+  var
+      result = this.contains(token)
+    , method = result ?
+      force !== true && "remove"
+    :
+      force !== false && "add"
+  ;
+
+  if (method) {
+    this[method](token);
+  }
+
+  if (force === true || force === false) {
+    return force;
+  } else {
+    return !result;
+  }
+};
+classListProto.toString = function () {
+  return this.join(" ");
+};
+
+if (objCtr.defineProperty) {
+  var classListPropDesc = {
+      get: classListGetter
+    , enumerable: true
+    , configurable: true
+  };
+  try {
+    objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
+  } catch (ex) { // IE 8 doesn't support enumerable:true
+    if (ex.number === -0x7FF5EC54) {
+      classListPropDesc.enumerable = false;
+      objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
+    }
+  }
+} else if (objCtr[protoProp].__defineGetter__) {
+  elemCtrProto.__defineGetter__(classListProp, classListGetter);
+}
+
+}(self));
+
+} else {
+// There is full or partial native classList support, so just check if we need
+// to normalize the add/remove and toggle APIs.
+
+(function () {
+  "use strict";
+
+  var testElement = document.createElement("_");
+
+  testElement.classList.add("c1", "c2");
+
+  // Polyfill for IE 10/11 and Firefox <26, where classList.add and
+  // classList.remove exist but support only one argument at a time.
+  if (!testElement.classList.contains("c2")) {
+    var createMethod = function(method) {
+      var original = DOMTokenList.prototype[method];
+
+      DOMTokenList.prototype[method] = function(token) {
+        var i, len = arguments.length;
+
+        for (i = 0; i < len; i++) {
+          token = arguments[i];
+          original.call(this, token);
+        }
+      };
+    };
+    createMethod('add');
+    createMethod('remove');
+  }
+
+  testElement.classList.toggle("c3", false);
+
+  // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
+  // support the second argument.
+  if (testElement.classList.contains("c3")) {
+    var _toggle = DOMTokenList.prototype.toggle;
+
+    DOMTokenList.prototype.toggle = function(token, force) {
+      if (1 in arguments && !this.contains(token) === !force) {
+        return force;
+      } else {
+        return _toggle.call(this, token);
+      }
+    };
+
+  }
+
+  testElement = null;
+}());
+
+}
+
+}
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("HTML WHATWG", "dom.html#dom-classlist", "Element.classList")}}{{Spec2("HTML WHATWG")}}Note within the HTML specification related to the {{htmlattrxref("class")}} attribute.
{{SpecName("DOM WHATWG", "#dom-element-classlist", "Element.classList")}}{{Spec2("DOM WHATWG")}}Initial definition
{{SpecName("DOM4", "#dom-element-classlist", "Element.classList")}}{{Spec2("DOM4")}} 
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support8.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9.2")}}10[1]11.505.1
toggle method's second argument24{{CompatVersionUnknown}}{{CompatGeckoDesktop("24")}}{{CompatNo}}[2]155.1
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support3.0{{CompatGeckoMobile("1.9.2")}}1011.105.0
toggle method's second argument{{CompatUnknown}}{{CompatGeckoMobile("24")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Not supported for SVG elements.  See a report at Microsoft about that.
+ [2] Internet Explorer never implemented this. See a report at Microsoft about that.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/element/click_event/index.html b/files/zh-tw/web/api/element/click_event/index.html new file mode 100644 index 0000000000..4c7044e4b3 --- /dev/null +++ b/files/zh-tw/web/api/element/click_event/index.html @@ -0,0 +1,205 @@ +--- +title: click +slug: Web/API/Element/click_event +tags: + - 待翻譯 +translation_of: Web/API/Element/click_event +--- +

click 事件通常會在設備的按鈕(通常是滑鼠按鍵)點擊元素時執行。

+ +

基本資料

+ +
+
詳述
+
DOM L3
+
介面
+
{{domxref("MouseEvent")}}
+
Bubbles
+
Yes
+
Cancelable
+
Yes
+
Target
+
網頁元素
+
Default Action
+
Varies
+
+ +

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
target {{readonlyInline}}EventTargetThe event target (the topmost target in the DOM tree).
type {{readonlyInline}}DOMStringThe type of event.
bubbles {{readonlyInline}}BooleanWhether the event normally bubbles or not
cancelable {{readonlyInline}}BooleanWhether the event is cancellable or not?
view {{readonlyInline}}WindowProxydocument.defaultView (window of the document)
detail {{readonlyInline}}long (float)A count of consecutive clicks that happened in a short amount of time, incremented by one.
currentTarget {{readonlyInline}}EventTargetThe node that had the event listener attached.
relatedTarget {{readonlyInline}}EventTargetFor mouseover, mouseout, mouseenter and mouseleave events: the target of the complementary event (the mouseleave target in the case of a mouseenter event). null otherwise.
screenX {{readonlyInline}}longThe X coordinate of the mouse pointer in global (screen) coordinates.
screenY {{readonlyInline}}longThe Y coordinate of the mouse pointer in global (screen) coordinates.
clientX {{readonlyInline}}longThe X coordinate of the mouse pointer in local (DOM content) coordinates.
clientY {{readonlyInline}}longThe Y coordinate of the mouse pointer in local (DOM content) coordinates.
button {{readonlyInline}}unsigned shortThe button number that was pressed when the mouse event was fired: Left button=0, middle button=1 (if present), right button=2. For mice configured for left handed use in which the button actions are reversed the values are instead read from right to left.
buttons {{readonlyInline}}unsigned shortThe buttons being pressed when the mouse event was fired: Left button=1, Right button=2, Middle (wheel) button=4, 4th button (typically, "Browser Back" button)=8, 5th button (typically, "Browser Forward" button)=16. If two or more buttons are pressed, returns the logical sum of the values. E.g., if Left button and Right button are pressed, returns 3 (=1 | 2). More info.
mozPressure {{readonlyInline}}floatThe amount of pressure applied to a touch or tabdevice when generating the event; this value ranges between 0.0 (minimum pressure) and 1.0 (maximum pressure).
ctrlKey {{readonlyInline}}booleantrue if the control key was down when the event was fired. false otherwise.
shiftKey {{readonlyInline}}booleantrue if the shift key was down when the event was fired. false otherwise.
altKey {{readonlyInline}}booleantrue if the alt key was down when the event was fired. false otherwise.
metaKey {{readonlyInline}}booleantrue if the meta key was down when the event was fired. false otherwise.
+ +

範例

+ +
<div id="test"></div>
+
+<script>
+  document.getElementById("test").addEventListener("click", function( event ) {
+    // 在 “clicked div”顯示點擊次數
+    event.target.innerHTML = "click count: " + event.detail;
+  }, false);
+</script>
+
+ +

Browser compatibility

+ +

Internet Explorer

+ +

Internet Explorer 8 & 9 suffer from a bug where elements with a computed {{cssxref("background-color")}} of transparent that are overlaid on top of other element(s) won't receive click events. Any click events will be fired at the underlying element(s) instead. See this live example for a demonstration.

+ +

Known workarounds for this bug:

+ + + +

Safari Mobile

+ +

Safari Mobile 7.0+ (and likely earlier versions too) suffers from a bug where click events aren't fired on elements that aren't typically interactive (e.g. {{HTMLElement("div")}}) and which also don't have event listeners directly attached to the elements themselves (i.e. event delegation is being used). See this live example for a demonstration. See also Safari's docs on making elements clickable and the definition of "clickable element".

+ +

Known workarounds for this bug:

+ + + +

Safari Mobile considers the following elements to be typically interactive (and thus they aren't affected by this bug):

+ + + +

關聯事件

+ + diff --git a/files/zh-tw/web/api/element/clientheight/index.html b/files/zh-tw/web/api/element/clientheight/index.html new file mode 100644 index 0000000000..99ae4faf06 --- /dev/null +++ b/files/zh-tw/web/api/element/clientheight/index.html @@ -0,0 +1,62 @@ +--- +title: Element.clientHeight +slug: Web/API/Element/clientHeight +tags: + - API + - Reference +translation_of: Web/API/Element/clientHeight +--- +

{{ APIRef("DOM") }}

+ +

Element.clientHeight 唯讀屬性會回傳元素內部高度(像素),包含 padding 但並未包含水平滾動條、border、margin。

+ +

clientHeight 可以被計算成 CSS height + CSS padding - 水平滾動條的高度(如果有顯示)

+ +
+

Note: 這個屬性會以四捨五入進位取整數. 如果要使用非整數值, 使用 {{ domxref("element.getBoundingClientRect()") }}.

+
+ +

表達式

+ +
var h = element.clientHeight;
+ +

h 代表元素高度(pixels)的正整數.

+ +

範例

+ +

 

+ +

             Image:Dimensions-client.png

+ + +

規範

+ + + + + + + + + + + + + + + + +
規範狀態
{{SpecName('CSSOM View', '#dom-element-clientheight', 'clientHeight')}}{{Spec2('CSSOM View')}} 
+ +

+ +

clientHeight 是在 the Internet Explorer 物件介紹的屬性.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/element/getattribute/index.html b/files/zh-tw/web/api/element/getattribute/index.html new file mode 100644 index 0000000000..e5b7a1c27e --- /dev/null +++ b/files/zh-tw/web/api/element/getattribute/index.html @@ -0,0 +1,71 @@ +--- +title: Element.getAttribute() +slug: Web/API/Element/getAttribute +translation_of: Web/API/Element/getAttribute +--- +
{{APIRef("DOM")}}
+ +

摘要

+ +

getAttribute() 函式會回傳該網頁元素的屬性。 如果該屬性不存在,其回傳值會是null或 "" (空字串); 詳見 {{Anch("Notes")}} 。

+ +

語法

+ +
var attribute = element.getAttribute(attributeName);
+
+ +

where

+ + + +

Example

+ +
var div1 = document.getElementById("div1");
+var align = div1.getAttribute("align");
+
+alert(align); // shows the value of align for the element with id="div1"
+ +

Notes

+ +

When called on an HTML element in a DOM flagged as an HTML document, getAttribute() lower-cases its argument before proceeding.

+ +

Essentially all web browsers (Firefox, Internet Explorer, recent versions of Opera, Safari, Konqueror, and iCab, as a non-exhaustive list) return null when the specified attribute does not exist on the specified element and this is what the current DOM specification draft specifies. The old DOM 3 Core specification, on the other hand, says that the correct return value in this case is actually the empty string, and some DOM implementations implement this behavior. The implementation of getAttribute in XUL (Gecko) actually follows the DOM 3 Core specification and returns an empty string. Consequently, you should use {{domxref("element.hasAttribute()")}} to check for an attribute's existence prior to calling getAttribute() if it is possible that the requested attribute does not exist on the specified element.

+ +

Browser compatibility

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support2923{{CompatVersionUnknown}}{{CompatVersionUnknown}}6
+
+ +
{{DOMAttributeMethods}}
+ +

Specification

+ + diff --git a/files/zh-tw/web/api/element/index.html b/files/zh-tw/web/api/element/index.html new file mode 100644 index 0000000000..d363baeead --- /dev/null +++ b/files/zh-tw/web/api/element/index.html @@ -0,0 +1,674 @@ +--- +title: Element +slug: Web/API/Element +tags: + - API + - DOM + - DOM Reference + - Element + - NeedsTranslation + - TopicStub + - Élément(2) +translation_of: Web/API/Element +--- +

{{ APIRef("DOM") }}

+ +

Element 介面表示了一個在 {{domxref("Document")}} 中的物件,其描述了各類型元素的共同屬性與方法,Element 的子介面則定義了不同類型元素的具體行為並增加額外的功能。例如 {{domxref("HTMLElement")}} 為所有 HTML 元素的基礎介面,而 {{domxref("SVGElement")}} 則是定義所有 SVG 元素的介面。

+ +

在 Web 領域之外,如 XUL 語言也能藉由 XULElement 介面來繼承 Element

+ +

{{InheritanceDiagram}}

+ +

屬性

+ +

Inherits properties from its parent interface, {{domxref("Node")}}, and by extension that interface's parent, {{domxref("EventTarget")}}. It implements the properties of {{domxref("ParentNode")}}, {{domxref("ChildNode")}}, {{domxref("NonDocumentTypeChildNode")}}, and {{domxref("Animatable")}}.

+ +
+
{{ domxref("Element.assignedSlot")}} {{experimental_inline}} {{readOnlyInline}}
+
Returns the {{domxref("HTMLSlotElement")}} interface associated with the element.
+
{{ domxref("Element.attributes") }} {{readOnlyInline}}
+
Returns a {{ domxref("NamedNodeMap") }} object containing the assigned attributes of the corresponding HTML element.
+
{{ domxref("Element.classList") }} {{readOnlyInline}}
+
Returns a {{ domxref("DOMTokenList") }} containing the list of class attributes.
+
{{ domxref("Element.className") }}
+
Is a {{domxref("DOMString")}} representing the class of the element.
+
{{ domxref("Element.clientHeight") }} {{experimental_inline}} {{readOnlyInline}}
+
Returns a {{jsxref("Number")}} representing the inner height of the element.
+
{{ domxref("Element.clientLeft") }} {{experimental_inline}} {{readOnlyInline}}
+
Returns a {{jsxref("Number")}} representing the width of the left border of the element.
+
{{ domxref("Element.clientTop") }} {{experimental_inline}} {{readOnlyInline}}
+
Returns a {{jsxref("Number")}} representing the width of the top border of the element.
+
{{ domxref("Element.clientWidth") }} {{experimental_inline}} {{readOnlyInline}}
+
Returns a {{jsxref("Number")}} representing the inner width of the element.
+
{{domxref("Element.computedName")}} {{readOnlyInline}}
+
Returns a {{domxref("DOMString")}} containing the label exposed to accessibility.
+
{{domxref("Element.computedRole")}} {{readOnlyInline}}
+
Returns a {{domxref("DOMString")}} containing the ARIA role that has been applied to a particular element.
+
{{ domxref("Element.id") }}
+
Is a {{domxref("DOMString")}} representing the id of the element.
+
{{ domxref("Element.innerHTML") }}
+
Is a {{domxref("DOMString")}} representing the markup of the element's content.
+
{{ domxref("Element.localName") }} {{readOnlyInline}}
+
A {{domxref("DOMString")}} representing the local part of the qualified name of the element.
+
{{domxref("Element.namespaceURI")}} {{readonlyInline}}
+
The namespace URI of the element, or null if it is no namespace. +
+

Note: In Firefox 3.5 and earlier, HTML elements are in no namespace. In later versions, HTML elements are in the http://www.w3.org/1999/xhtml namespace in both HTML and XML trees. {{ gecko_minversion_inline("1.9.2") }}

+
+
+
{{ domxref("NonDocumentTypeChildNode.nextElementSibling") }} {{readOnlyInline}}
+
Is a {{ domxref("Element") }}, the element immediately following the given one in the tree, or null if there's no sibling node.
+
{{ domxref("Element.outerHTML") }} {{experimental_inline}}
+
Is a {{domxref("DOMString")}} representing the markup of the element including its content. When used as a setter, replaces the element with nodes parsed from the given string.
+
{{ domxref("Element.prefix") }} {{readOnlyInline}}
+
A {{domxref("DOMString")}} representing the namespace prefix of the element, or null if no prefix is specified.
+
{{ domxref("NonDocumentTypeChildNode.previousElementSibling") }} {{readOnlyInline}}
+
Is a {{ domxref("Element") }}, the element immediately preceding the given one in the tree, or null if there is no sibling element.
+
{{ domxref("Element.scrollHeight") }} {{experimental_inline}} {{readOnlyInline}}
+
Returns a {{jsxref("Number")}} representing the scroll view height of an element.
+
{{ domxref("Element.scrollLeft") }} {{experimental_inline}}
+
Is a {{jsxref("Number")}} representing the left scroll offset of the element.
+
{{ domxref("Element.scrollLeftMax") }} {{non-standard_inline}} {{readOnlyInline}}
+
Returns a {{jsxref("Number")}} representing the maximum left scroll offset possible for the element.
+
{{ domxref("Element.scrollTop") }} {{experimental_inline}}
+
Is a {{jsxref("Number")}} representing the top scroll offset the an element.
+
{{ domxref("Element.scrollTopMax") }} {{non-standard_inline}} {{readOnlyInline}}
+
Returns a {{jsxref("Number")}} representing the maximum top scroll offset possible for the element.
+
{{ domxref("Element.scrollWidth") }} {{experimental_inline}} {{readOnlyInline}}
+
Returns a {{jsxref("Number")}} representing the scroll view width of the element.
+
{{domxref("Element.shadowRoot") }} {{experimental_inline}} {{readOnlyInline}}
+
Returns the youngest shadow root that is hosted by the element.
+
{{domxref("Element.slot")}} {{experimental_inline}}
+
Returns the name of the shadow DOM slot attatched to the element. A slot is a placeholder inside a web component that users can fill with their own markup.
+
{{domxref("Element.tabStop")}} {{non-standard_inline}}
+
Is a {{jsxref("Boolean")}} indicating if the element can receive input focus via the tab key.
+
{{ domxref("Element.tagName") }} {{readOnlyInline}}
+
Returns a {{domxref("String")}} with the name of the tag for the given element.
+
{{ domxref("Element.undoManager")}} {{experimental_inline}} {{readOnlyInline}}
+
Returns the {{domxref("UndoManager")}} associated with the element.
+
{{ domxref("Element.undoScope")}} {{experimental_inline}}
+
Is a {{jsxref("Boolean")}} indicating if the element is an undo scope host, or not.
+
+ +
+

Note: DOM Level 3 defined namespaceURI, localName and prefix on the {{domxref("Node")}} interface. In DOM4 they were moved to Element.

+ +

This change is implemented in Chrome since version 46.0 and Firefox since version 48.0.

+
+ +

事件處理器

+ +
+
{{ domxref("Element.ongotpointercapture") }}
+
Returns the event handler for the {{event("gotpointercapture")}} event type.
+
{{ domxref("Element.onlostpointercapture") }}
+
Returns the event handler for the {{event("lostpointercapture")}} event type.
+
{{ domxref("Element.onwheel") }} {{ non-standard_inline() }}
+
Returns the event handling code for the wheel event.
+
+ +

方法

+ +

Inherits methods from its parents {{domxref("Node")}}, and its own parent, {{domxref("EventTarget")}}, and implements those of {{domxref("ParentNode")}}, {{domxref("ChildNode")}}, {{domxref("NonDocumentTypeChildNode")}}, and {{domxref("Animatable")}}.

+ +
+
{{ domxref("EventTarget.addEventListener()") }}
+
Registers an event handler to a specific event type on the element.
+
{{domxref("Element.attachShadow()")}} {{experimental_inline}}
+
Attatches a shadow DOM tree to the specified element and returns a reference to its {{domxref("ShadowRoot")}}.
+
{{domxref("Element.animate()")}} {{experimental_inline}}
+
A shortcut method to create and run an animation on an element. Returns the created Animation object instance.
+
{{ domxref("Element.closest()")}} {{experimental_inline}}
+
Returns the {{domxref("Element")}}, descendant of this element (or this element itself), that is the closest ancestor of the elements selected by the selectors given in parameter.
+
{{ domxref("Element.createShadowRoot()")}} {{experimental_inline}} {{deprecated_inline()}}
+
Creates a shadow DOM on on the element, turning it into a shadow host. Returns a {{domxref("ShadowRoot")}}.
+
{{ domxref("EventTarget.dispatchEvent()") }}
+
Dispatches an event to this node in the DOM and returns a {{jsxref("Boolean")}} that indicates that at least one handler has not canceled it.
+
{{domxref("Element.find()")}}{{experimental_inline}}
+
...
+
{{domxref("Element.findAll()")}}{{experimental_inline}}
+
...
+
{{domxref("Element.getAnimations()")}} {{experimental_inline}}
+
Returns an array of Animation objects currently active on the element.
+
{{ domxref("Element.getAttribute()") }}
+
Retrieves the value of the named attribute from the current node and returns it as an {{jsxref("Object")}}.
+
{{ domxref("Element.getAttributeNames()") }}
+
 
+
{{ domxref("Element.getAttributeNS()") }}
+
Retrieves the value of the attribute with the specified name and namespace, from the current node and returns it as an {{jsxref("Object")}}.
+
{{ domxref("Element.getAttributeNode()") }} {{obsolete_inline}}
+
Retrieves the node representation of the named attribute from the current node and returns it as an {{ domxref("Attr") }}.
+
{{ domxref("Element.getAttributeNodeNS()") }} {{obsolete_inline}}
+
Retrieves the node representation of the attribute with the specified name and namespace, from the current node and returns it as an {{ domxref("Attr") }}.
+
{{ domxref("Element.getBoundingClientRect()") }}
+
...
+
{{ domxref("Element.getClientRects()") }}
+
Returns a collection of rectangles that indicate the bounding rectangles for each line of text in a client.
+
{{domxref("Element.getDestinationInsertionPoints()")}} {{experimental_inline}}
+
+
{{ domxref("Element.getElementsByClassName()") }}
+
Returns a live {{ domxref("HTMLCollection") }} that contains all descendants of the current element that possess the list of classes given in the parameter.
+
{{ domxref("Element.getElementsByTagName()") }}
+
Returns a live {{ domxref("HTMLCollection") }} containing all descendant elements, of a particular tag name, from the current element.
+
{{ domxref("Element.getElementsByTagNameNS()") }}
+
Returns a live {{ domxref("HTMLCollection") }} containing all descendant elements, of a particular tag name and namespace, from the current element.
+
{{ domxref("Element.hasAttribute()") }}
+
Returns a {{jsxref("Boolean")}} indicating if the element has the specified attribute or not.
+
{{ domxref("Element.hasAttributeNS()") }}
+
Returns a {{jsxref("Boolean")}} indicating if the element has the specified attribute, in the specified namespace, or not.
+
{{ domxref("Element.hasAttributes()") }}
+
Returns a {{jsxref("Boolean")}} indicating if the element has one or more HTML attributes present.
+
{{ domxref("Element.insertAdjacentElement") }} {{experimental_inline}}
+
Inserts a given element node at a given position relative to the element it is invoked upon.
+
{{ domxref("Element.insertAdjacentHTML") }} {{experimental_inline}}
+
Parses the text as HTML or XML and inserts the resulting nodes into the tree in the position given.
+
{{ domxref("Element.insertAdjacentText") }} {{experimental_inline}}
+
Inserts a given text node at a given position relative to the element it is invoked upon.
+
{{ domxref("Element.matches()") }} {{experimental_inline}}
+
Returns a {{jsxref("Boolean")}} indicating whether or not the element would be selected by the specified selector string.
+
{{ domxref("Element.querySelector()") }}
+
Returns the first {{ domxref("Node") }} which matches the specified selector string relative to the element.
+
{{ domxref("Element.querySelectorAll") }}
+
Returns a {{ domxref("NodeList") }} of nodes which match the specified selector string relative to the element.
+
{{ domxref("Element.releasePointerCapture")}}
+
Releases (stops) pointer capture that was previously set for a specific {{domxref("PointerEvent","pointer event")}}.
+
{{domxref("ChildNode.remove()")}} {{experimental_inline}}
+
Removes the element from the children list of its parent.
+
{{ domxref("Element.removeAttribute()") }}
+
Removes the named attribute from the current node.
+
{{ domxref("Element.removeAttributeNS()") }}
+
Removes the attribute with the specified name and namespace, from the current node.
+
{{ domxref("Element.removeAttributeNode()") }} {{obsolete_inline}}
+
Removes the node representation of the named attribute from the current node.
+
{{ domxref("EventTarget.removeEventListener()") }}
+
Removes an event listener from the element.
+
{{ domxref("Element.requestFullscreen()") }} {{experimental_inline}}
+
Asynchronously asks the browser to make the element full-screen.
+
{{ domxref("Element.requestPointerLock()")}} {{experimental_inline}}
+
Allows to asynchronously ask for the pointer to be locked on the given element.
+
+ +
+
{{ domxref("Element.scrollIntoView()") }} {{experimental_inline}}
+
Scrolls the page until the element gets into the view.
+
{{ domxref("Element.setAttribute()") }}
+
Sets the value of a named attribute of the current node.
+
{{ domxref("Element.setAttributeNS()") }}
+
Sets the value of the attribute with the specified name and namespace, from the current node.
+
{{ domxref("Element.setAttributeNode()") }} {{obsolete_inline}}
+
Sets the node representation of the named attribute from the current node.
+
{{ domxref("Element.setAttributeNodeNS()") }} {{obsolete_inline}}
+
Setw the node representation of the attribute with the specified name and namespace, from the current node.
+
{{ domxref("Element.setCapture()") }} {{non-standard_inline}}
+
Sets up mouse event capture, redirecting all mouse events to this element.
+
{{domxref("Element.setPointerCapture()")}}
+
Designates a specific element as the capture target of future {{domxref("PointerEvent","pointer events")}}.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Shadow DOM')}}{{Spec2('Shadow DOM')}} 
{{SpecName("Web Animations", '', '')}}{{Spec2("Web Animations")}}Added the getAnimations() method.
{{SpecName('Undo Manager', '', 'Element')}}{{Spec2('Undo Manager')}}Added the undoScope and undoManager properties.
{{SpecName('Pointer Events 2', '#extensions-to-the-element-interface', 'Element')}}{{Spec2('Pointer Events 2')}}Added the following event handlers: ongotpointercapture and onlostpointercapture.
+ Added the following methods: setPointerCapture() and releasePointerCapture().
{{SpecName('Pointer Events', '#extensions-to-the-element-interface', 'Element')}}{{Spec2('Pointer Events')}}Added the following event handlers: ongotpointercapture and onlostpointercapture.
+ Added the following methods: setPointerCapture() and releasePointerCapture().
{{SpecName('Selectors API Level 2', '#interface-definitions', 'Element')}}{{Spec2('Selectors API Level 2')}}Added the following methods: matches() (implemented as mozMatchesSelector()), find(), findAll().
{{SpecName('Selectors API Level 1', '#interface-definitions', 'Element')}}{{Spec2('Selectors API Level 1')}}Added the following methods: querySelector() and querySelectorAll().
{{SpecName('Pointer Lock', 'index.html#element-interface', 'Element')}}{{Spec2('Pointer Lock')}}Added the requestPointerLock() method.
{{SpecName('Fullscreen', '#api', 'Element')}}{{Spec2('Fullscreen')}}Added the requestFullscreen() method.
{{SpecName('DOM Parsing', '#extensions-to-the-element-interface', 'Element')}}{{Spec2('DOM Parsing')}}Added the following properties: innerHTML, and outerHTML.
+ Added the following method: insertAdjacentHTML().
{{SpecName('CSSOM View', '#extensions-to-the-element-interface', 'Element')}}{{Spec2('CSSOM View')}}Added the following properties: scrollTop, scrollLeft, scrollWidth, scrollHeight, clientTop, clientLeft, clientWidth, and clientHeight.
+ Added the following methods: getClientRects(), getBoundingClientRect(), and scrollIntoView().
{{SpecName('Element Traversal', '#ecmascript-bindings', 'Element')}}{{Spec2('Element Traversal')}}Added inheritance of the {{domxref("ElementTraversal")}} interface.
{{SpecName('DOM WHATWG', '#interface-element', 'Element')}}{{Spec2('DOM WHATWG')}}Removed the following methods: closest(), setIdAttribute(), setIdAttributeNS(), and setIdAttributeNode().
+ Removed the schemaTypeInfo property.
+ Modified the return value of getElementsByTag() and getElementsByTagNS().
+ Moved hasAttributes() from the Node interface to this one.
+ Inserted insertAdjacentElement() and insertAdjacentText().
{{SpecName('DOM3 Core', 'core.html#ID-745549614', 'Element')}}{{Spec2('DOM3 Core')}}Added the following methods: setIdAttribute(), setIdAttributeNS(), and setIdAttributeNode(). These methods were never implemented and have been removed in later specifications.
+ Added the schemaTypeInfo property. This property was never implemented and has been removed in later specifications.
{{SpecName('DOM2 Core', 'core.html#ID-745549614', 'Element')}}{{Spec2('DOM2 Core')}}The normalize() method has been moved to {{domxref("Node")}}.
{{SpecName('DOM1', 'level-one-core.html#ID-745549614', 'Element')}}{{Spec2('DOM1')}}Initial definition.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}1.0
children{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9")}}7.0 with a significant bug [1]
+ 9.0 according to the spec
{{CompatVersionUnknown}}{{CompatNo}}
childElementCount, nextElementSibling, previousElementSibling{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9.1")}}9.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
firstElementChild, lastElementChild{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9")}}9.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
classList{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9.2")}} {{CompatVersionUnknown}}{{CompatVersionUnknown}}
outerHTML {{experimental_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("11")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
clientLeft, clientTop {{experimental_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9.1")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
getBoundingClientRect(), getClientRects() {{experimental_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
querySelector(), querySelectorAll()1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9.1")}}8.010.03.2 (525.3)
insertAdjacentHTML() {{experimental_inline}}1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("8")}}4.07.04.0 (527)
setCapture() {{non-standard_inline}}{{CompatNo}}{{CompatNo}}{{CompatGeckoDesktop("2")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
oncopy, oncut, onpaste {{non-standard_inline}}{{CompatNo}}{{CompatNo}}{{CompatGeckoDesktop("1.9")}}{{CompatVersionUnknown}} {{CompatNo}}
onwheel {{non-standard_inline}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("17")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
ongotpointercapture, onlostpointercapture, setPointerCapture(), and releasePointerCapture(){{CompatChrome(52.0)}} [4]{{CompatVersionUnknown}}{{CompatVersionUnknown}} [3]10.0{{CompatNo}}{{CompatNo}}
matches() {{experimental_inline}}{{CompatVersionUnknown}} with the non-standard name webkitMatchesSelector{{CompatVersionUnknown}} {{property_prefix("webkit")}} {{property_prefix("ms")}}{{CompatGeckoDesktop("1.9.2")}} with the non-standard name mozMatchesSelector
+ {{CompatGeckoDesktop("34")}} with the standard name
9.0 with the non-standard name msMatchesSelector11.5 with the non-standard name oMatchesSelector
+ 15.0 with the non-standard name webkitMatchesSelector
5.0 with the non-standard name webkitMatchesSelector
find() and findAll(){{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
requestPointerLock()16.0 {{property_prefix("webkit")}}, behind an about:flags
+ 22.0 {{property_prefix("webkit")}} (with special cases, progressively lifted see [2])
{{CompatVersionUnknown}}{{CompatGeckoDesktop("14")}}{{property_prefix("moz")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
requestFullscreen()14.0 {{property_prefix("webkit")}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("10")}} {{property_prefix("moz")}}11.0 {{property_prefix("ms")}}12.10
+ 15.0 {{property_prefix("webkit")}}
5.1 {{property_prefix("webkit")}}
undoManager and undoScope{{CompatNo}}{{CompatNo}}{{CompatVersionUnknown}} (behind the dom.undo_manager.enabled pref){{CompatNo}}{{CompatNo}}{{CompatNo}}
attributes{{CompatUnknown}}{{CompatNo}}{{CompatGeckoDesktop("22")}}
+ Before this it was available via the {{domxref("Node")}} interface that any element inherits.
{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
scrollTopMax() and scrollLeftMax(){{CompatNo}}{{CompatNo}}{{CompatGeckoDesktop("16")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
closest(){{CompatUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("35")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
hasAttributes(){{CompatVersionUnknown}}{{CompatNo}}{{CompatGeckoDesktop("1.0")}} (on the {{domxref("Node")}} interface)
+ {{CompatGeckoDesktop("35")}} (on this interface
{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
insertAdjacentElement(), insertAdjacentText(){{CompatVersionUnknown}}{{CompatNo}}{{CompatGeckoDesktop("48.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
assignedSlot, attatchShadow, shadowRoot, and slot{{CompatChrome(53)}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
computedRole and computedName{{CompatChrome(41)}}[4]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}28[4]{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari MobileChrome for Android
Basic support1.0 {{CompatVersionUnknown}}{{CompatGeckoMobile("1")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}1.0 
scrollTopMax() and scrollLeftMax(){{CompatNo}} {{CompatNo}}{{CompatGeckoMobile("16")}}{{CompatNo}}{{CompatNo}}{{CompatNo}} 
closest(){{CompatUnknown}} {{CompatVersionUnknown}}{{CompatGeckoMobile("35")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}} 
hasAttributes(){{CompatVersionUnknown}} {{CompatNo}}{{CompatGeckoMobile("1.0")}} (on the {{domxref("Node")}} interface)
+ {{CompatGeckoMobile("35")}} (on this interface
{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}} 
insertAdjacentElement(), insertAdjacentText(){{CompatVersionUnknown}} {{CompatVersionUnknown}}{{CompatGeckoMobile("48.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}} 
assignedSlot, attatchShadow, shadowRoot, and slot{{CompatNo}}{{CompatChrome(53.0)}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatChrome(53)}}
computedRole and computedName{{CompatNo}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}28[4]{{CompatUnknown}}{{CompatNo}}
+
+ +

[1] Internet Explorer 7 and 8 incorrectly return the comments as part of the children of an Element. This is fixed in Internet Explorer 9 and later.

+ +

[2] Chrome 16 allowed webkitRequestPointerLock() only in fullscreen; Chrome 21 for trusted web site (permission asked); Chrome 22 allowed it by default for all same-origin document; Chrome 23 allowed it in sandboxed {{HTMLElement("iframe")}} if the non-standard value webkit-allow-pointer-lock is set to the {{htmlattrxref("sandbox", "iframe")}} attribute.

+ +

[3] Implementation withdrawn. See {{Bug("1166347")}}.

+ +

[4] Behind a flag.

diff --git a/files/zh-tw/web/api/element/innerhtml/index.html b/files/zh-tw/web/api/element/innerhtml/index.html new file mode 100644 index 0000000000..df002176e4 --- /dev/null +++ b/files/zh-tw/web/api/element/innerhtml/index.html @@ -0,0 +1,215 @@ +--- +title: Element.innerHTML +slug: Web/API/Element/innerHTML +tags: + - 元素組件 + - 注譯 + - 裏HTML + - 裏超文本 +translation_of: Web/API/Element/innerHTML +--- +
{{APIRef("DOM")}}
+ + + +

 Element  的「innerHTML」屬性獲取或設置元素中包含的HTML或XML標記。

+ +
Note:  如{{HTMLElement("div")}}, {{HTMLElement("span")}}, or {{HTMLElement("noembed")}} 節點有包含字符(&),(<)或(>),innerHTML分別地回傳這些字符成為HTML的“&” “<” “>” 。 使用 Node.textContent 得到的這些文本節點的內容的原始拷貝件。
+ +

To insert the HTML into the document rather than replace the contents of an element, use the method {{domxref("Element.insertAdjacentHTML", "insertAdjacentHTML()")}}.

+ +

Syntax

+ +
const content = element.innerHTML;
+
+element.innerHTML = htmlString;
+
+ +

Value

+ +

A {{domxref("DOMString")}} containing the HTML serialization of the element's descendants. Setting the value of innerHTML removes all of the element's descendants and replaces them with nodes constructed by parsing the HTML given in the string htmlString.

+ +

Exceptions

+ +
+
SyntaxError
+
An attempt was made to set the value of innerHTML using a string which is not properly-formed HTML.
+
NoModificationAllowedError
+
An attempt was made to insert the HTML into a node whose parent is a {{domxref("Document")}}.
+
+ +

Usage notes

+ +

The innerHTML property can be used to examine the current HTML source of the page, including any changes that have been made since the page was initially loaded.

+ +

Reading the HTML contents of an element

+ +

Reading innerHTML causes the user agent to serialize the HTML or XML fragment comprised of the elment's descendants. The resulting string is returned.

+ +
let contents = myElement.innerHTML;
+ +

This lets you look at the HTML markup of the element's content nodes.

+ +
+

Note: The returned HTML or XML fragment is generated based on the current contents of the element, so the markup and formatting of the returned fragment is likely not to match the original page markup.

+
+ +
+

Note:基於元素的當前內容產生返回的HTML或XML片段,所以返回的片段的標記和格式可能不匹配原始頁面標記。

+
+ +

Replacing the contents of an element

+ +

Setting the value of innerHTML lets you easily replace the existing contents of an element with new content.

+ +

For example, you can erase the entire contents of a document by clearing the contents of the document's {{domxref("Document.body", "body")}} attribute:

+ +
document.body.innerHTML = "";
+ +

This example fetches the document's current HTML markup and replaces the "<" characters with the HTML entity "&lt;", thereby essentially converting the HTML into raw text. This is then wrapped in a {{HTMLElement("pre")}} element. Then the value of innerHTML is changed to this new string. As a result, the document contents are replaced with a display of the page's entire source code.

+ +
document.documentElement.innerHTML = "<pre>" +
+         document.documentElement.innerHTML.replace(/</g,"&lt;") +
+            "</pre>";
+ +

Operational details

+ +

What exactly happens when you set value of innerHTML? Doing so causes the user agent to follow these steps:

+ +
    +
  1. The specified value is parsed as HTML or XML (based on the document type), resulting in a {{domxref("DocumentFragment")}} object representing the new set of DOM nodes for the new elements.
  2. +
  3. If the element whose contents are being replaced is a {{HTMLElement("template")}} element, then the <template> element's {{domxref("HTMLTemplateElement.content", "content")}} attribute is replaced with the new DocumentFragment created in step 1.
  4. +
  5. For all other elements, the element's contents are replaced with the nodes in the new DocumentFragment.
  6. +
+ +

Security considerations

+ +

It is not uncommon to see innerHTML used to insert text into a web page. There is potential for this to become an attack vector on a site, creating a potential security risk.

+ +
const name = "John";
+// assuming 'el' is an HTML DOM element
+el.innerHTML = name; // harmless in this case
+
+// ...
+
+name = "<script>alert('I am John in an annoying alert!')</script>";
+el.innerHTML = name; // harmless in this case
+ +

Although this may look like a {{interwiki("wikipedia", "cross-site scripting")}} attack, the result is harmless. HTML5 specifies that a {{HTMLElement("script")}} tag inserted with innerHTML should not execute.

+ +

However, there are ways to execute JavaScript without using {{HTMLElement("script")}} elements, so there is still a security risk whenever you use innerHTML to set strings over which you have no control. For example:

+ +
const name = "<img src='x' onerror='alert(1)'>";
+el.innerHTML = name; // shows the alert
+ +

For that reason, it is recommended that you do not use innerHTML when inserting plain text; instead, use {{domxref("Node.textContent")}}. This doesn't parse the passed content as HTML, but instead inserts it as raw text.

+ +
+

Warning: If your project is one that will undergo any form of security review, using innerHTML most likely will result in your code being rejected. For example, if you use innerHTML in a browser extension and submit the extension to addons.mozilla.org, it will not pass the automated review process.

+
+ +

Example

+ +

This example uses innerHTML to create a mechanism for logging messages into a box on a web page.

+ +

JavaScript

+ +
function log(msg) {
+  var logElem = document.querySelector(".log");
+
+  var time = new Date();
+  var timeStr = time.toLocaleTimeString();
+  logElem.innerHTML += timeStr + ": " + msg + "<br/>";
+}
+
+log("Logging mouse events inside this container...");
+
+ +

The log() function creates the log output by getting the current time from a {{jsxref("Date")}} object using {{jsxref("Date.toLocaleTimeString", "toLocaleTimeString()")}}, and building a string with the timestamp and the message text. Then the message is appended to the box with the class "log".

+ +

We add a second method that logs information about {{domxref("MouseEvent")}} based events (such as {{event("mousedown")}}, {{event("click")}}, and {{event("mouseenter")}}):

+ +
function logEvent(event) {
+  var msg = "Event <strong>" + event.type + "</strong> at <em>" +
+            event.clientX + ", " + event.clientY + "</em>";
+  log(msg);
+}
+ +

Then we use this as the event handler for a number of mouse events on the box that contains our log:

+ +
var boxElem = document.querySelector(".box");
+
+boxElem.addEventListener("mousedown", logEvent);
+boxElem.addEventListener("mouseup", logEvent);
+boxElem.addEventListener("click", logEvent);
+boxElem.addEventListener("mouseenter", logEvent);
+boxElem.addEventListener("mouseleave", logEvent);
+ +

HTML

+ +

The HTML is quite simple for our example.

+ +
<div class="box">
+  <div><strong>Log:</strong></div>
+  <div class="log"></div>
+</div>
+ +

The {{HTMLElement("div")}} with the class "box" is just a container for layout purposes, presenting the contents with a box around it. The <div> whose class is "log" is the container for the log text itself.

+ +

CSS

+ +

The following CSS styles our example content.

+ +
.box {
+  width: 600px;
+  height: 300px;
+  border: 1px solid black;
+  padding: 2px 4px;
+  overflow-y: scroll;
+  overflow-x: auto;
+}
+
+.log {
+  margin-top: 8px;
+  font-family: monospace;
+}
+ +

Result

+ +

The resulting content looks like this. You can see output into the log by moving the mouse in and out of the box, clicking in it, and so forth.

+ +

{{EmbedLiveSample("Example", 640, 350)}}

+ +

Specification

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM Parsing', '#dom-element-innerhtml', 'Element.innerHTML')}}{{Spec2('DOM Parsing')}}Initial definition
+ +

Browser compatibility

+ + + +

{{Compat("api.Element.innerHTML")}}

+ +

See also

+ + diff --git a/files/zh-tw/web/api/element/insertadjacenthtml/index.html b/files/zh-tw/web/api/element/insertadjacenthtml/index.html new file mode 100644 index 0000000000..6b9da0f403 --- /dev/null +++ b/files/zh-tw/web/api/element/insertadjacenthtml/index.html @@ -0,0 +1,135 @@ +--- +title: Element.insertAdjacentHTML() +slug: Web/API/Element/insertAdjacentHTML +translation_of: Web/API/Element/insertAdjacentHTML +--- +
{{APIRef("DOM")}}
+ +

insertAdjacentHTML() 把傳入的字串解析成 HTML 或 XML,並把該節點插入到 DOM 樹指定的位置。它不會重新解析被使用的元素,因此他不會破壞該元素裡面原有的元素。這避免了序列化的複雜步驟,使得它比直接操作  innerHTML 快上許多。

+ +

Syntax

+ +
element.insertAdjacentHTML(position, text);
+ +

Parameters

+ +
+
position
+
A {{domxref("DOMString")}} representing the position relative to the element; must be one of the following strings: +
    +
  • 'beforebegin': 在 element 之前。
  • +
  • 'afterbegin': 在 element 裡面,第一個子元素之前。
  • +
  • 'beforeend': 在 element 裡面,最後一個子元素之後。
  • +
  • 'afterend': 在 element 之後。
  • +
+
+
text
+
text 是即將被解析並插入到 DOM 樹裡的字串。
+
+ +

Visualization of position names

+ +
<!-- beforebegin -->
+<p>
+  <!-- afterbegin -->
+  foo
+  <!-- beforeend -->
+</p>
+<!-- afterend -->
+ +
Note:  beforebegin 和 afterend 只在該節點位於 DOM 樹內、並且有母元素時有效。
+ +

Example

+ +
// <div id="one">one</div>
+var d1 = document.getElementById('one');
+d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');
+
+// At this point, the new structure is:
+// <div id="one">one</div><div id="two">two</div>
+ +

Notes

+ +

Security Considerations

+ +

When inserting HTML into a page by using insertAdjacentHTML be careful not to use user input that hasn't been escaped.

+ +

It is not recommended you use insertAdjacentHTML when inserting plain text; instead, use the Node.textContent property or Element.insertAdjacentText() method. This doesn't interpret the passed content as HTML, but instead inserts it as raw text.

+ +

Specification

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM Parsing', '#widl-Element-insertAdjacentHTML-void-DOMString-position-DOMString-text', 'Element.insertAdjacentHTML()')}}{{ Spec2('DOM Parsing') }} 
+ +

Browser compatibility

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1.0{{ CompatGeckoDesktop("8.0") }}4.07.04.0 (527)
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{ CompatUnknown() }}{{ CompatGeckoMobile("8.0") }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +

See also

+ + diff --git a/files/zh-tw/web/api/element/queryselectorall/index.html b/files/zh-tw/web/api/element/queryselectorall/index.html new file mode 100644 index 0000000000..6f777763bf --- /dev/null +++ b/files/zh-tw/web/api/element/queryselectorall/index.html @@ -0,0 +1,140 @@ +--- +title: Element.querySelectorAll() +slug: Web/API/Element/querySelectorAll +translation_of: Web/API/Element/querySelectorAll +--- +
{{APIRef("DOM")}}
+ +

總覽

+ +

Returns a non-live NodeList of all elements descended from the element on which it is invoked that matches the specified group of CSS selectors. (The base element itself is not included, even if it matches.)

+ +

表達式

+ +
elementList = baseElement.querySelectorAll(selectors);
+ +
+
elementList
+
is a non-live node list [ NodeList[elements] of element objects.
+
baseElement
+
is an element object.
+
selectors
+
is a group of selectors to match on or elements of the DOM. 
+
+ +

範例

+ +

下例是從整個網頁的 body 中,取得所有 p 元素:

+ +
let matches = document.body.querySelectorAll('p');
+
+ +

This example returns a list of p children elements under a container, whose parent is a div that has the class 'highlighted':

+ +
let el = document.querySelector('#test');    //return an element with id='test'
+let matches = el.querySelectorAll('div.highlighted > p'); // return a NodeList of p wrapped in a div with attribute class "highlighted"
+
+ +

下例是取得所有有 attribute data-srciframe 元素:

+ +
let matches = el.querySelectorAll('iframe[data-src]');
+
+ +

+ +

If the specified “selectors” are not found inside the DOM of the page, the method queryselectorAll returns an empty NodeList as specified below:

+ +
> let x = document.body.querySelectorAll('.highlighted'); //case: if the class highlighted doesn't exist in any attribute "class" of the DOM the result is
+> [] //empty NodeList
+ +

querySelectorAll() was introduced in the WebApps API.

+ +

The string argument pass to querySelectorAll must follow the CSS syntax. See {{domxref("document.querySelector")}} for a concrete example.

+ +

We could access a single item inside the NodeList in the following way:

+ +
let x = document.body.querySelectorAll('.highlighted');
+x.length; //return the size of x
+x[i_item]; //where i_item has a value between 0 and x.length-1. The operator "[]" return as in an array the element at index "i_item"
+
+ +

We could iterate inside a NodeList with the construct for(....) {...} as in the following code:

+ +
 let x = document.body.querySelectorAll('.highlighted');
+ let index = 0;
+ for( index=0; index < x.length; index++ ) {
+       console.log(x[index]);
+ }
+ +

So in the above way, it is possible to manage and modify the behaviour of the page.

+ +

Quirks

+ +

querySelectorAll() behaves differently than most common JavaScript DOM libraries, which might lead to unexpected results:

+ +
<div class="outer">
+  <div class="select">
+    <div class="inner">
+    </div>
+  </div>
+</div>
+ +
let select = document.querySelector('.select');
+let inner = select.querySelectorAll('.outer .inner');
+inner.length; // 1, not 0!
+
+ +

In this example, when selecting .outer .inner in the context of .select, .inner is still found, even though .outer is not a descendant of the baseElement (.select).
+ querySelectorAll() only verifies that the last element in the selector is within the baseElement.

+ +

The :scope pseudo-class restores the expected behavior, only matching selectors on descendants of the baseElement:

+ +
let select = document.querySelector('.select');
+let inner = select.querySelectorAll(':scope .outer .inner');
+inner.length; // 0
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態評論
{{SpecName('DOM4','#dom-parentnode-queryselectorallselectors','querySelectorAll')}}{{Spec2('DOM4')}} 
{{SpecName('Selectors API Level 2','#queryselectorall','querySelectorAll')}}{{Spec2('Selectors API Level 2')}} 
{{SpecName('Selectors API Level 1','#queryselectorall','querySelectorAll')}}{{Spec2('Selectors API Level 1')}} 
+ +

瀏覽器相容性

+ + + +
{{Compat("api.Element.querySelectorAll")}}
+ +

[1] Supported in Opera 15+ by enabling the "Enable <style scoped>" or "Enable experimental Web Platform features" flag in chrome://flags.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/element/scrollheight/index.html b/files/zh-tw/web/api/element/scrollheight/index.html new file mode 100644 index 0000000000..eabf9987bf --- /dev/null +++ b/files/zh-tw/web/api/element/scrollheight/index.html @@ -0,0 +1,170 @@ +--- +title: Element.scrollHeight +slug: Web/API/Element/scrollHeight +tags: + - API + - Reference +translation_of: Web/API/Element/scrollHeight +--- +

{{APIRef("DOM")}}

+ +

Element.scrollHeight 是衡量元素包含因為 overflow 而沒顯示在螢幕上的內容高度的唯讀屬性. scrollHeight 的值相等於元素要求 clientHeight 在視域中沒有使用滾動條顯示所有內容的最小高度值 . 這當中只包含 padding, 並不包含 margin.

+ +
+

這個屬性會以四捨五入進位取整數. 如果要使用非整數值, 使用 {{ domxref("Element.getBoundingClientRect()") }}.

+
+ +

表達式

+ +
var intElemScrollHeight = document.getElementById(id_attribute_value).scrollHeight;
+
+ +

intElemScrollHeight 是個儲存了元素 scrollHeight 的正整數變數. scrollHeight是唯讀的屬性.

+ +

範例

+ +
+
+

padding-top

+ +

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

+ +

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ +

padding-bottom

+
+Left Top Right Bottom margin-top margin-bottom border-top border-bottom
+ +

Image:scrollHeight.png

+ +

問題與解決方法

+ +

了解元素是否被滾輪完全滾過

+ +

下面的等式代表如果元素被完全滾過將會回傳 true ,  否則回傳 false.

+ +
element.scrollHeight - element.scrollTop === element.clientHeight
+ +

scrollHeight 範例

+ +

藉由 onscroll 事件, 這個等式對於決定使用者是否已經讀完文字內容是很有用 (參見 element.scrollTopelement.clientHeight 屬性). 範例:

+ +

HTML

+ +
<form name="registration">
+  <p>
+    <textarea id="rules">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum at laoreet magna.
+Aliquam erat volutpat. Praesent molestie, dolor ut eleifend aliquam, mi ligula ultrices sapien, quis cursus
+neque dui nec risus. Duis tincidunt lobortis purus eu aliquet. Quisque in dignissim magna. Aenean ac lorem at
+velit ultrices consequat. Nulla luctus nisi ut libero cursus ultrices. Pellentesque nec dignissim enim. Phasellus
+ut quam lacus, sed ultricies diam. Vestibulum convallis rutrum dolor, sit amet egestas velit scelerisque id.
+Proin non dignissim nisl. Sed mi odio, ullamcorper eget mattis id, malesuada vitae libero. Integer dolor lorem,
+mattis sed dapibus a, faucibus id metus. Duis iaculis dictum pulvinar. In nisi nibh, dapibus ac blandit at, porta
+at arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent
+dictum ipsum aliquet erat eleifend sit amet sollicitudin felis tempus. Aliquam congue cursus venenatis. Maecenas
+luctus pellentesque placerat. Mauris nisl odio, condimentum sed fringilla a, consectetur id ligula. Praesent sem
+sem, aliquet non faucibus vitae, iaculis nec elit. Nullam volutpat, lectus et blandit bibendum, nulla lorem congue
+turpis, ac pretium tortor sem ut nibh. Donec vel mi in ligula hendrerit sagittis. Donec faucibus viverra fermentum.
+Fusce in arcu arcu. Nullam at dignissim massa. Cras nibh est, pretium sit amet faucibus eget, sollicitudin in
+ligula. Vivamus vitae urna mauris, eget euismod nunc. Aenean semper gravida enim non feugiat. In hac habitasse
+platea dictumst. Cras eleifend nisl volutpat ante condimentum convallis. Donec varius dolor malesuada erat
+consequat congue. Donec eu lacus ut sapien venenatis tincidunt. Quisque sit amet tellus et enim bibendum varius et
+a orci. Donec aliquet volutpat scelerisque. Proin et tortor dolor. Ut aliquet, dolor a mattis sodales, odio diam
+pulvinar sem, egestas pretium magna eros vitae felis. Nam vitae magna lectus, et ornare elit. Morbi feugiat, ipsum
+ac mattis congue, quam neque mollis tortor, nec mollis nisl dolor a tortor. Maecenas varius est sit amet elit
+interdum quis placerat metus posuere. Duis malesuada justo a diam vestibulum vel aliquam nisi ornare. Integer
+laoreet nisi a odio ornare non congue turpis eleifend. Cum sociis natoque penatibus et magnis dis parturient montes,
+nascetur ridiculus mus. Cras vulputate libero sed arcu iaculis nec lobortis orci fermentum.
+    </textarea>
+  </p>
+  <p>
+    <input type="checkbox" name="accept" id="agree" />
+    <label for="agree">I agree</label>
+    <input type="submit" id="nextstep" value="Next" />
+  </p>
+</form>
+ +

CSS

+ +
#notice {
+  display: inline-block;
+  margin-bottom: 12px;
+  border-radius: 5px;
+  width: 600px;
+  padding: 5px;
+  border: 2px #7FDF55 solid;
+}
+
+#rules {
+  width: 600px;
+  height: 130px;
+  padding: 5px;
+  border: #2A9F00 solid 2px;
+  border-radius: 5px;
+}
+ +

JavaScript

+ +
function checkReading () {
+  if (checkReading.read) {
+    return;
+  }
+  checkReading.read = this.scrollHeight - this.scrollTop === this.clientHeight;
+  document.registration.accept.disabled = document.getElementById("nextstep").disabled = !checkReading.read;
+  checkReading.noticeBox.innerHTML = checkReading.read ? "Thank you." : "Please, scroll and read the following text.";
+}
+
+onload = function () {
+  var oToBeRead = document.getElementById("rules");
+  checkReading.noticeBox = document.createElement("span");
+  document.registration.accept.checked = false;
+  checkReading.noticeBox.id = "notice";
+  oToBeRead.parentNode.insertBefore(checkReading.noticeBox, oToBeRead);
+  oToBeRead.parentNode.insertBefore(document.createElement("br"), oToBeRead);
+  oToBeRead.onscroll = checkReading;
+  checkReading.call(oToBeRead);
+}
+ +

{{ EmbedLiveSample('scrollHeight_Demo', '640', '400') }}

+ +

規範

+ +

scrollHeight 是 MSIE's DHTML 物件模型的一部份. scrollHeight 紀錄在下列的規範: {{SpecName("CSSOM View")}}.

+ +

瀏覽器相容性

+ + + + + + + + + + + + + + + + + + + + + + + + +
瀏覽器最低版本
Internet Explorer8.0
Firefox (Gecko)3.0 (1.9)
Opera?
Safari | Chrome | WebKit4.0 | 4.0 | ?
+ +

In FireFox versions earlier than 21: When an element's content does not generate a vertical scrollbar, then its scrollHeight property is equal to its clientHeight property. This can mean either the content is too short to require a scrollbar or that the element has CSS style overflow value of visible (non-scrollable).

+ +

參見

+ + diff --git a/files/zh-tw/web/api/element/scrolltop/index.html b/files/zh-tw/web/api/element/scrolltop/index.html new file mode 100644 index 0000000000..f4fdfe8e09 --- /dev/null +++ b/files/zh-tw/web/api/element/scrolltop/index.html @@ -0,0 +1,73 @@ +--- +title: Element.scrollTop +slug: Web/API/Element/scrollTop +tags: + - API + - CSSOM View + - Reference +translation_of: Web/API/Element/scrollTop +--- +

{{ APIRef("DOM") }}

+ +

Element.scrollTop 屬性可以設置和獲取元素被向上捲動的高度(pixels). 元素的 scrollTop 是元素頂端和能被看見的最頂端之間的距離. 當元素並未產生滾動條, 那麼 scrollTop 的值預設為 0.

+ +

表達式

+ +
// 獲得已經被滾動的距離(pixels)
+var  intElemScrollTop = someElement.scrollTop;
+
+ +

intElemScrollTop 為 {{domxref("element")}}已經被滾動的距離(pixels ).

+ +
// 設置已經被滾動的距離(pixels)
+element.scrollTop = intValue;
+
+ +

scrollTop 可以被設置為任何和正整數, 注意事項:

+ + + +

範例

+ +
+
+

padding-top

+ +

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

+ +

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ +

padding-bottom

+
+Left Top Right Bottom margin-top margin-bottom border-top border-bottom
+ +

Image:scrollTop.png

+ +

規範

+ + + + + + + + + + + + + + +
規範狀態
{{SpecName('CSSOM View', '#dom-element-scrolltop', 'scrollTop')}}{{Spec2("CSSOM View")}} 
+ +

參閱

+ + diff --git a/files/zh-tw/web/api/element/touchcancel_event/index.html b/files/zh-tw/web/api/element/touchcancel_event/index.html new file mode 100644 index 0000000000..99fa1c27a2 --- /dev/null +++ b/files/zh-tw/web/api/element/touchcancel_event/index.html @@ -0,0 +1,169 @@ +--- +title: touchcancel +slug: Web/API/Element/touchcancel_event +translation_of: Web/API/Element/touchcancel_event +--- +

{{APIRef}}

+ +

touchcancel 觸控點發生失效的事件被觸發(例如太多觸控點時)

+ +

一般資訊

+ +
+
規範
+
Touch Events
+
介面
+
TouchEvent
+
起泡事件
+
+
可取消
+
+
對象
+
Document, Element
+
預設行為
+
+
+ +

屬性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
target {{readonlyInline}}EventTargetThe event target (the topmost target in the DOM tree).
type {{readonlyInline}}DOMStringThe type of event.
bubbles {{readonlyInline}}BooleanWhether the event normally bubbles or not.
cancelable {{readonlyInline}}BooleanWhether the event is cancellable or not.
view {{readonlyInline}}WindowProxydocument.defaultView (window of the document)
detail {{readonlyInline}}long (float)0.
touches {{readonlyInline}}TouchListA list of Touches for every point of contact currently touching the surface.
targetTouches {{readonlyInline}}TouchListA list of Touches for every point of contact that is touching the surface and started on the element that is the target of the current event.
changedTouches {{readonlyInline}}TouchListA list of Touches for every point of contact which contributed to the event.
+ For the touchstart event this must be a list of the touch points that just became active with the current event. For the touchmove event this must be a list of the touch points that have moved since the last event. For the touchend and touchcancel events this must be a list of the touch points that have just been removed from the surface.
ctrlKey {{readonlyInline}}booleantrue if the control key was down when the event was fired. false otherwise.
shiftKey {{readonlyInline}}booleantrue if the shift key was down when the event was fired. false otherwise.
altKey {{readonlyInline}}booleantrue if the alt key was down when the event was fired. false otherwise.
metaKey {{readonlyInline}}booleantrue if the meta key was down when the event was fired. false otherwise.
+ +

範例

+ +

各種觸控事件的範例:Touch events

+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome("22.0")}}{{CompatGeckoDesktop("18.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewChrome for AndroidFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("6.0")}}{{CompatVersionUnknown}}11{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

相關事件

+ +

{{ domxref("GlobalEventHandlers.ontouchcancel","ontouchcancel")}}

diff --git a/files/zh-tw/web/api/errorevent/index.html b/files/zh-tw/web/api/errorevent/index.html new file mode 100644 index 0000000000..27e406ed7c --- /dev/null +++ b/files/zh-tw/web/api/errorevent/index.html @@ -0,0 +1,148 @@ +--- +title: ErrorEvent +slug: Web/API/ErrorEvent +translation_of: Web/API/ErrorEvent +--- +

{{APIRef("HTML DOM")}}

+ +

ErrorEvent 介面是用來提供程式碼或是檔案的錯誤訊息的事件。

+ +

Properties

+ +

此介面繼承了其父 {{domxref("Event")}} 的 properties 。

+ +
+
{{domxref("ErrorEvent.message")}} {{readonlyInline}}
+
一 {{domxref("DOMString")}} 提供具可讀性的關於問題的錯誤訊息。
+
{{domxref("ErrorEvent.filename")}} {{readonlyInline}}
+
一 {{domxref("DOMString")}} ,為發生錯誤的程式碼檔案的檔名。
+
{{domxref("ErrorEvent.lineno")}} {{readonlyInline}}
+
一 整數 ,為發生問題的程式的行數。
+
{{domxref("ErrorEvent.colno")}} {{readonlyInline}}
+
整數 ,為發生問題的程式的欄數。
+
{{domxref("ErrorEvent.error")}} {{readonlyInline}} {{experimental_inline}}
+
一個參與該事件的 JavaScript Object 。
+
+ +

Constructor

+ +
+
{{domxref("ErrorEvent.ErrorEvent", "ErrorEvent()")}}
+
建立一 ErrorEvent 事件,其包含提供的參數。
+
+ +

Methods

+ +

此介面繼承了其父 {{domxref("Event")}} 的 methods。

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('HTML WHATWG', 'webappapis.html#the-errorevent-interface', 'ErrorEvent') }}{{ Spec2('HTML WHATWG') }}追加 error propriety 以及 constructor 的第5個the 5th 參數。
{{ SpecName('HTML5 W3C', 'webappapis.html#the-errorevent-interface', 'ErrorEvent') }}{{ Spec2('HTML5 W3C') }}初始定義。
+ +

瀏覽器支援度比較

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
colno property and 4th argument to constructor{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
error property and 5th argument to constructor{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
colno property and 4th argument to constructor{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
error property and 5th argument to constructor{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/api/event/bubbles/index.html b/files/zh-tw/web/api/event/bubbles/index.html new file mode 100644 index 0000000000..4a495fc672 --- /dev/null +++ b/files/zh-tw/web/api/event/bubbles/index.html @@ -0,0 +1,63 @@ +--- +title: Event.bubbles +slug: Web/API/Event/bubbles +translation_of: Web/API/Event/bubbles +--- +

{{ ApiRef("DOM") }}

+ +

概述

+ +

表示事件是否會向上冒泡傳遞。

+ +

語法

+ +
var bool = event.bubbles;
+
+ +

回傳一個布林值,若事件會向上冒泡傳遞則回傳 true

+ +

備註

+ +

Only certain events can bubble. Events that do bubble have this property set to true. You can use this property to check if an event is allowed to bubble or not.

+ +

範例

+ +
 function goInput(e) {
+  // checks bubbles and
+  if (!e.bubbles) {
+     // passes event along if it's not
+     passItOn(e);
+  }
+  // already bubbling
+  doOutput(e)
+}
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-event-bubbles', 'Event.bubbles')}}{{ Spec2('DOM WHATWG') }} 
{{SpecName('DOM4', '#dom-event-bubbles', 'Event.bubbles')}}{{ Spec2('DOM4') }} 
{{SpecName('DOM2 Events', '#Events-Event-canBubble', 'Event.bubbles')}}{{ Spec2('DOM2 Events') }}Initial definition.
diff --git a/files/zh-tw/web/api/event/comparison_of_event_targets/index.html b/files/zh-tw/web/api/event/comparison_of_event_targets/index.html new file mode 100644 index 0000000000..211463b1a7 --- /dev/null +++ b/files/zh-tw/web/api/event/comparison_of_event_targets/index.html @@ -0,0 +1,164 @@ +--- +title: Comparison of Event Targets +slug: Web/API/Event/Comparison_of_Event_Targets +translation_of: Web/API/Event/Comparison_of_Event_Targets +--- +

{{ ApiRef() }}

+ +

Event targets

+ +

It's easy to get confused about which target to examine when writing an event handler. This article should clarify the use of the target properties.

+ +

There are 5 targets to consider:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyDefined inPurpose
event.targetDOM Event Interface +

The DOM element on the lefthand side of the call that triggered this event, eg:

+ +
+element.dispatchEvent(event)
+
+
event.currentTargetDOM Event InterfaceThe EventTarget whose EventListeners are currently being processed. As the event capturing and bubbling occurs this value changes.
event.relatedTargetDOM MouseEvent InterfaceIdentifies a secondary target for the event.
event.explicitOriginalTarget{{ Source("/dom/public/idl/events/nsIDOMNSEvent.idl", "nsIDOMNSEvent.idl") }}{{ Non-standard_inline() }} If the event was retargeted for some reason other than an anonymous boundary crossing, this will be set to the target before the retargeting occurs. For example, mouse events are retargeted to their parent node when they happen over text nodes ({{ Bug("185889") }}), and in that case .target will show the parent and .explicitOriginalTarget will show the text node.
+ Unlike .originalTarget, .explicitOriginalTarget will never contain anonymous content.
event.originalTarget{{ Source("/dom/public/idl/events/nsIDOMNSEvent.idl", "nsIDOMNSEvent.idl") }}{{ Non-standard_inline() }} The original target of the event, before any retargetings. See Anonymous Content#Event_Flow_and_Targeting for details.
+ +

Use of explicitOriginalTarget and originalTarget

+ +

TODO: Only available in a Mozilla-based browser? TODO: Only suitable for extension-developers?

+ +

範例

+ +
<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>Comparison of Event Targets</title>
+    <style>
+        table {
+            border-collapse: collapse;
+            height: 150px;
+            width: 100%;
+        }
+        td {
+            border: 1px solid #ccc;
+            font-weight: bold;
+            padding: 5px;
+            min-height: 30px;
+        }
+        .standard {
+            background-color: #99ff99;
+        }
+        .non-standard {
+            background-color: #902D37;
+        }
+    </style>
+</head>
+<body>
+    <table>
+    <thead>
+        <tr>
+            <td class="standard">Original target dispatching the event <small>event.target</small></td>
+            <td class="standard">Target who's event listener is being processed <small>event.currentTarget</small></td>
+            <td class="standard">Identify other element (if any) involved in the event <small>event.relatedTarget</small></td>
+            <td class="non-standard">If there was a retargetting of the event for some reason <small> event.explicitOriginalTarget</small> contains the target before retargetting (never contains anonymous targets)</td>
+            <td class="non-standard">If there was a retargetting of the event for some reason <small> event.originalTarget</small> contains the target before retargetting (may contain anonymous targets)</td>
+        </tr>
+    </thead>
+    <tr>
+        <td id="target"></td>
+        <td id="currentTarget"></td>
+        <td id="relatedTarget"></td>
+        <td id="explicitOriginalTarget"></td>
+        <td id="originalTarget"></td>
+    </tr>
+</table>
+<p>Clicking on the text will show the difference between explicitOriginalTarget, originalTarget and target</p>
+<script>
+    function handleClicks(e) {
+        document.getElementById('target').innerHTML = e.target;
+        document.getElementById('currentTarget').innerHTML = e.currentTarget;
+        document.getElementById('relatedTarget').innerHTML = e.relatedTarget;
+        document.getElementById('explicitOriginalTarget').innerHTML = e.explicitOriginalTarget;
+        document.getElementById('originalTarget').innerHTML = e.originalTarget;
+    }
+
+    function handleMouseover(e) {
+        document.getElementById('target').innerHTML = e.target;
+        document.getElementById('relatedTarget').innerHTML = e.relatedTarget;
+    }
+
+    document.addEventListener('click', handleClicks, false);
+    document.addEventListener('mouseover', handleMouseover, false);
+</script>
+</body>
+</html>
+ +

Use of target and relatedTarget

+ +

The relatedTarget property for the mouseover event holds the node that the mouse was previously over. For the mouseout event, it holds the node that the mouse moved to.

+ + + + + + + + + + + + + + + + + + + +
Event typeevent.targetevent.relatedTarget
mouseoverthe EventTarget which the pointing device enteredthe EventTarget which the pointing device exited
mouseoutthe EventTarget which the pointing device exitedthe EventTarget which the pointing device entered
+ +

TODO: Also needs descriptions about dragenter and dragexit events.

+ +

範例

+ +
<hbox id="outer">
+  <hbox id="inner"
+        onmouseover="dump('mouseover ' + event.relatedTarget.id + ' > ' + event.target.id + '\n');"
+        onmouseout="dump('mouseout  ' + event.target.id + ' > ' + event.relatedTarget.id + '\n');"
+        style="margin: 100px; border: 10px solid black; width: 100px; height: 100px;" />
+</hbox>
+
+ +

 

diff --git a/files/zh-tw/web/api/event/createevent/index.html b/files/zh-tw/web/api/event/createevent/index.html new file mode 100644 index 0000000000..fd60d1089d --- /dev/null +++ b/files/zh-tw/web/api/event/createevent/index.html @@ -0,0 +1,29 @@ +--- +title: Event.createEvent() +slug: Web/API/Event/createEvent +translation_of: Web/API/Document/createEvent +--- +

{{APIRef("DOM")}}

+ +

建立一個新的事件,該事件必須先以其 init() method 初始化才行。

+ +

語法

+ +
document.createEvent(type) 
+ +
+
type
+
一個 string 。表示所建立的事件名稱。
+
+ +

這個 method 會回傳一個新的 DOM {{ domxref("Event") }} object ,其事件類型為傳入的 type 。該事件必須先初始化才能使用。

+ +

範例

+ +
var newEvent = document.createEvent("UIEvents");
+ +

規格定義

+ + diff --git a/files/zh-tw/web/api/event/currenttarget/index.html b/files/zh-tw/web/api/event/currenttarget/index.html new file mode 100644 index 0000000000..2be9aeb4e7 --- /dev/null +++ b/files/zh-tw/web/api/event/currenttarget/index.html @@ -0,0 +1,70 @@ +--- +title: Event.currentTarget +slug: Web/API/Event/currentTarget +translation_of: Web/API/Event/currentTarget +--- +
{{APIRef("DOM")}}
+ +

{{domxref("Event")}} 介面的唯讀屬性 currentTarget 會標明事件指向(current target)、還有該事件所遍歷的 DOM。屬性總會指向當時處理該事件的事件監聽器所註冊的 DOM 物件,而 {{domxref("event.target")}} 屬性則是永遠指向觸發事件的 DOM 物件。

+ +

範例

+ +

event.currentTarget 在把相同的事件監聽器,附加到多個元素時,會出現很有趣的事情:

+ +
function hide(e){
+  e.currentTarget.style.visibility = "hidden";
+  // 在這個函式用於事件監聽器時: this === e.currentTarget
+}
+
+var ps = document.getElementsByTagName('p');
+
+for(var i = 0; i < ps.length; i++){
+  ps[i].addEventListener('click', hide, false);
+}
+
+// 單擊四周的話 p 元素就會消失
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態註解
{{SpecName("DOM WHATWG", "#dom-event-currenttarget", "Event.currentTarget")}}{{Spec2("DOM WHATWG")}}
{{SpecName("DOM4", "#dom-event-currenttarget", "Event.currentTarget")}}{{Spec2("DOM4")}}
{{SpecName("DOM3 Events", "#dfn-current-event-target", "current event target")}}{{Spec2("DOM3 Events")}}
{{SpecName("DOM2 Events", "#Events-Event-currentTarget", "Event.currentTarget")}}{{Spec2("DOM2 Events")}}Initial definition
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Event.currentTarget")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/event/defaultprevented/index.html b/files/zh-tw/web/api/event/defaultprevented/index.html new file mode 100644 index 0000000000..d0814682a8 --- /dev/null +++ b/files/zh-tw/web/api/event/defaultprevented/index.html @@ -0,0 +1,100 @@ +--- +title: Event.defaultPrevented +slug: Web/API/Event/defaultPrevented +translation_of: Web/API/Event/defaultPrevented +--- +
{{ APIRef("DOM") }}
+ +

概述

+ +

回傳一個布林值,表示事件的預設行為是否被取消,也就是事件物件是否曾執行 {{domxref("event.preventDefault()", "preventDefault()")}} 方法。

+ +
註:You should use this instead of the non-standard, deprecated getPreventDefault() method (see {{ bug(691151) }}).
+ +

語法

+ +
bool = event.defaultPrevented 
+ +

範例

+ +
 if (e.defaultPrevented) {
+   /* the default was prevented */
+ }
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-event-defaultprevented', 'Event.defaultPrevented()')}}{{ Spec2('DOM WHATWG') }} 
{{SpecName('DOM4', '#dom-event-defaultprevented', 'Event.defaultPrevented')}}{{Spec2('DOM4')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{ CompatChrome(18) }}{{ CompatGeckoDesktop("6.0") }}{{ CompatIE(9.0) }}{{ CompatOpera(11.0) }}{{ CompatSafari("5.0") }}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{ CompatUnknown() }}{{ CompatGeckoMobile("6.0") }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatSafari(5.0) }}
+
+ + diff --git a/files/zh-tw/web/api/event/event/index.html b/files/zh-tw/web/api/event/event/index.html new file mode 100644 index 0000000000..bbbd74c5b2 --- /dev/null +++ b/files/zh-tw/web/api/event/event/index.html @@ -0,0 +1,87 @@ +--- +title: Event() +slug: Web/API/Event/Event +translation_of: Web/API/Event/Event +--- +

{{APIRef("DOM")}}

+ +

Event() constructor 能用來建立一個 {{domxref("Event", "事件")}} 。

+ +

語法

+ +
event = new Event(typeArg, eventInit);
+ +

參數

+ +
+
typeArg
+
為一 {{domxref("DOMString")}} ,用來表示事件名稱。
+
eventInit{{optional_inline}}
+
一個 EventInit object,包含以下欄位 + + + + + + + + + + + + + + + + + + + + + + + + + + +
參數可選默認值類型說明
"bubbles"false{{jsxref("Boolean")}}表示該事件是否懸浮(bubble up)。
"cancelable"false{{jsxref("Boolean")}}表示該事件是否已取消(canale)。
+
+
+ +

範例

+ +
// 建立一個 bubbles up 、並未被取消的事件 “look” 。
+var ev = new Event("look", {"bubbles":true, "cancelable":false});
+document.dispatchEvent(ev);
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG','#interface-event','Event()')}}{{Spec2('DOM WHATWG')}}Initial definition.
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Event.Event")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/event/eventphase/index.html b/files/zh-tw/web/api/event/eventphase/index.html new file mode 100644 index 0000000000..e146e7b230 --- /dev/null +++ b/files/zh-tw/web/api/event/eventphase/index.html @@ -0,0 +1,179 @@ +--- +title: Event.eventPhase +slug: Web/API/Event/eventPhase +translation_of: Web/API/Event/eventPhase +--- +

{{ApiRef("DOM")}}

+ +

表示事件物件目前於事件流(Event Flow)中傳遞的進度為哪一個階段。

+ +

語法

+ +
var phase = event.eventPhase;
+
+ +

回傳一個整數值以代表目前事件於事件流中的傳遞階段,可能的值將於{{anch("事件傳遞階段常數")}}說明。

+ +

常數

+ +

事件傳遞階段常數

+ +

These values describe which phase the event flow is currently being evaluated.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
常數說明
{{domxref("Event.NONE")}} {{readonlyinline}}0No event is being processed at this time.
{{domxref("Event.CAPTURING_PHASE")}} {{readonlyinline}}1The event is being propagated through the target's ancestor objects. This process starts with the {{domxref("Window")}}, then {{domxref("Document")}}, then the {{domxref("HTMLHtmlElement")}}, and so on through the elements until the target's parent is reached. {{domxref("EventListener", "Event listeners", "", 1)}} registered for capture mode when {{domxref("EventTarget.addEventListener()")}} was called are triggered during this phase.
{{domxref("Event.AT_TARGET")}} {{readonlyinline}}2The event has arrived at {{domxref("EventTarget", "the event's target", "", 1)}}. Event listeners registered for this phase are called at this time. If {{domxref("Event.bubbles")}} is false, processing the event is finished after this phase is complete.
{{domxref("Event.BUBBLING_PHASE")}} {{readonlyinline}}3The event is propagating back up through the target's ancestors in reverse order, starting with the parent, and eventually reaching the containing {{domxref("Window")}}. This is known as bubbling, and occurs only if {{domxref("Event.bubbles")}} is true. {{domxref("EventListener", "Event listeners", "", 1)}} registered for this phase are triggered during this process.
+ +

For more details, see section 3.1, Event dispatch and DOM event flow, of the DOM Level 3 Events specification.

+ +

範例

+ +

HTML Content

+ +
<h4>Event Propagation Chain</h4>
+<ul>
+  <li>Click 'd1'</li>
+  <li>Analyse event propagation chain</li>
+  <li>Click next div and repeat the experience</li>
+  <li>Change Capturing mode</li>
+  <li>Repeat the experience</li>
+</ul>
+<input type="checkbox" id="chCapture" />
+<label for="chCapture">Use Capturing</label>
+ <div id="d1">d1
+  <div id="d2">d2
+      <div id="d3">d3
+          <div id="d4">d4</div>
+      </div>
+  </div>
+ </div>
+ <div id="divInfo"></div>
+
+ +

CSS Content

+ +
div {
+  margin: 20px;
+  padding: 4px;
+  border: thin black solid;
+}
+
+#divInfo {
+  margin: 18px;
+  padding: 8px;
+  background-color:white;
+  font-size:80%;
+}
+ +

JavaScript Content

+ +
var clear = false, divInfo = null, divs = null, useCapture = false;
+window.onload = function () {
+  divInfo = document.getElementById("divInfo");
+  divs = document.getElementsByTagName('div');
+  chCapture = document.getElementById("chCapture");
+  chCapture.onclick = function () {
+    RemoveListeners();
+    AddListeners();
+  }
+  Clear();
+  AddListeners();
+}
+
+function RemoveListeners() {
+  for (var i = 0; i < divs.length; i++) {
+    var d = divs[i];
+    if (d.id != "divInfo") {
+      d.removeEventListener("click", OnDivClick, true);
+      d.removeEventListener("click", OnDivClick, false);
+    }
+  }
+}
+
+function AddListeners() {
+  for (var i = 0; i < divs.length; i++) {
+    var d = divs[i];
+    if (d.id != "divInfo") {
+      d.addEventListener("click", OnDivClick, false);
+      if (chCapture.checked)
+        d.addEventListener("click", OnDivClick, true);
+      d.onmousemove = function () { clear = true; };
+    }
+  }
+}
+
+function OnDivClick(e) {
+  if (clear) {
+    Clear(); clear = false;
+  }
+  if (e.eventPhase == 2)
+    e.currentTarget.style.backgroundColor = 'red';
+  var level = e.eventPhase == 0 ? "none" : e.eventPhase == 1 ? "capturing" : e.eventPhase == 2 ? "target" : e.eventPhase == 3 ? "bubbling" : "error";
+  divInfo.innerHTML += e.currentTarget.id + "; eventPhase: " + level + "<br/>";
+}
+
+function Clear() {
+  for (var i = 0; i < divs.length; i++) {
+    if (divs[i].id != "divInfo")
+      divs[i].style.backgroundColor = (i & 1) ? "#f6eedb" : "#cceeff";
+  }
+  divInfo.innerHTML = '';
+}
+
+ +

{{ EmbedLiveSample('Example', '', '700', '', 'Web/API/Event/eventPhase') }}

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("DOM WHATWG", "#dom-event-eventphase", "Event.eventPhase")}}{{Spec2("DOM WHATWG")}} 
{{SpecName("DOM4", "#dom-event-eventphase", "Event.eventPhase")}}{{Spec2("DOM4")}} 
{{SpecName("DOM2 Events", "#Events-Event-eventPhase", "Event.eventPhase")}}{{Spec2("DOM2 Events")}}Initial definition
diff --git a/files/zh-tw/web/api/event/index.html b/files/zh-tw/web/api/event/index.html new file mode 100644 index 0000000000..4213c20080 --- /dev/null +++ b/files/zh-tw/web/api/event/index.html @@ -0,0 +1,210 @@ +--- +title: Event +slug: Web/API/Event +tags: + - API + - DOM + - Event + - Interface + - NeedsTranslation + - Reference + - Référence(2) + - TopicStub +translation_of: Web/API/Event +--- +

{{APIRef("DOM")}}

+ +

Event 介面表示了一個在 DOM 物件上所發生的事件。

+ +

一個事件可以是由使用者的操作行為所產生(如:點擊滑鼠按鈕或敲打鍵盤),或是來自 API 因處理非同步任務所產生。事件也可以為程式所觸發,例如呼叫元素的 HTMLElement.click() 方法,或是自行定義事件並使用 EventTarget.dispatchEvent() 發送至特定的目標。

+ +

事件有多種不同的類型,部分事件是使用基於 Event 的子介面。Event 本身包含了所有事件共同的屬性及方法。

+ +

許多 DOM 元素可被設定接受(accept,或稱為 listen "監聽")這些事件,並在發生時執行處理(process、handle)事件的程式碼。事件處理器(Event-handlers)通常會使用 EventTarget.addEventListener() 來被連結(connected,或稱為 attached "附加")至各個 HTML 元素(例如 <button>、<div>、<div>、<span> 等),且此方式一般也是用來取代舊的 HTML 事件處理器屬性(attributes)。此外,在需要時也可以使用 removeEventListener() 來中斷事件處理器與元素的連結。請留意一個元素可以擁有多個事件處理器(即使是處理同一種事件的不同處理器),特別是那些被切分開來彼此獨立且有不同目標的程式模組(舉例來說,廣告及統計模組可以同時監控網頁中的影片觀看資訊)。

+ +

When there are many nested elements, each with its own handler(s), event processing can become very complicated -- especially where a parent element receives the very same event as its child elements because "spatially" they overlap so the event technically occurs in both, and the processing order of such events depends on the Event bubbling and capture settings of each handler triggered.

+ +

基於 Event 的子介面

+ +

Below is a list of interfaces which are based on the main Event interface, with links to their respective documentation in the MDN API reference. Note that all event interfaces have names which end in "Event".

+ +
+ +
+ +

建構式

+ +
+
{{domxref("Event.Event", "Event()")}}
+
建立一個 Event 物件。
+
+ +

屬性

+ +
+
{{domxref("Event.bubbles")}} {{readonlyinline}}
+
布林值,表示事件是否會向上冒泡傳遞。
+
{{domxref("Event.cancelBubble")}}
+
由於歷史性因素,此屬性的效果等同於 {{domxref("Event.stopPropagation()", "stopPropagation()")}} 方法。若在事件處理器回傳前設定此值為 true,可阻止事件繼續向上冒泡傳遞。
+
{{domxref("Event.cancelable")}} {{readonlyinline}}
+
布林值,表示事件是否能被取消。
+
{{domxref("Event.composed")}} {{ReadOnlyInline}}
+
A Boolean value indicating whether or not the event can bubble across the boundary between the shadow DOM and the regular DOM.
+
{{domxref("Event.currentTarget")}} {{readonlyinline}}
+
指向目前處理事件之監聽器所屬的 DOM 物件。
+
{{domxref("Event.deepPath")}} {{non-standard_inline}}
+
An {{jsxref("Array")}} of DOM {{domxref("Node")}}s through which the event has bubbled.
+
{{domxref("Event.defaultPrevented")}} {{readonlyinline}}
+
布林值,表示事件的預設行為是否被 {{domxref("event.preventDefault()", "preventDefault()")}} 方法所取消。
+
{{domxref("Event.eventPhase")}} {{readonlyinline}}
+
表示事件目前的傳遞階段。
+
{{domxref("Event.explicitOriginalTarget")}} {{non-standard_inline}} {{readonlyinline}}
+
事件的明確原定目標(Mozilla 專屬)。
+
{{domxref("Event.originalTarget")}} {{non-standard_inline}} {{readonlyinline}}
+
事件重新導向前的原定目標(Mozilla 專屬)。
+
{{domxref("Event.returnValue")}}
+
非標準屬性。用以替代 {{domxref("Event.preventDefault()", "preventDefault()")}} 方法與 {{domxref("Event.defaultPrevented", "defaultPrevented")}} 屬性(舊版 Internet Explorer 專屬)。
+
{{domxref("Event.scoped")}} {{readonlyinline}} {{obsolete_inline}}
+
A {{jsxref("Boolean")}} indicating whether the given event will bubble across through the shadow root into the standard DOM. This property has been renamed to {{domxref("Event.composed", "composed")}}.
+
{{domxref("Event.srcElement")}} {{non-standard_inline}}
+
非標準屬性。為 {{domxref("Event.target", "target")}} 屬性的別名(舊版 Internet Explorer 專屬)。
+
{{domxref("Event.target")}} {{readonlyinline}}
+
指向最初觸發事件的 DOM 物件。
+
{{domxref("Event.timeStamp")}} {{readonlyinline}}
+
事件發生(事件物件建立)至今的時間。
+
{{domxref("Event.type")}} {{readonlyinline}}
+
事件類型(不區分大小寫)。
+
{{domxref("Event.isTrusted")}} {{readonlyinline}}
+
表示事件物件是否為瀏覽器建立(比如在用戶點擊之後),或由程式碼所建立(使用建立事件的方法,如 {{domxref("Event.initEvent()", "initEvent()")}})。
+
+ +

Obsolete properties

+ +
+
{{domxref("Event.scoped")}} {{readonlyinline}} {{obsolete_inline}}
+
A {{jsxref("Boolean")}} indicating whether the given event will bubble across through the shadow root into the standard DOM. This property has been renamed to {{domxref("Event.composed", "composed")}}.
+
+ +

方法

+ +
+
{{domxref("Event.createEvent()")}} {{deprecated_inline}}
+
+

Creates a new event, which must then be initialized by calling its initEvent() method.

+
+
{{domxref("Event.composedPath()")}}
+
Returns the event’s path (objects on which listeners will be invoked). This does not include nodes in shadow trees if the shadow root was created with its {{domxref("ShadowRoot.mode")}} closed.
+
+ +
+
{{domxref("Event.initEvent()")}} {{deprecated_inline}}
+
初始化已經建立的事件。若該事件已經被處理過,這方法就不會執行任何東西。
+
{{domxref("Event.preventDefault()")}}
+
取消該事件(如果該事件的 {{domxref("Event.cancelable", "cancelable")}} 屬性為 true)。
+
{{domxref("Event.stopImmediatePropagation()")}}
+
一旦事件物件呼叫此方法,目前元素中尚未執行的已註冊之相同事件類型監聽器將不會被呼叫,而事件也不會繼續捕捉或冒泡傳遞。
+
{{domxref("Event.stopPropagation()")}}
+
阻止事件物件繼續捕捉或冒泡傳遞。
+
+ +

已廢棄方法

+ +
+
{{domxref("Event.getPreventDefault()")}} {{non-standard_inline}}
+
非標準方法。回傳 defaultPrevented 屬性值。請直接改用 {{domxref("Event.defaultPrevented", "defaultPrevented")}} 屬性。
+
{{domxref("Event.preventBubble()")}} {{non-standard_inline}} {{Obsolete_inline(24)}}
+
已廢棄方法。阻止事件繼續冒泡傳遞。請改用 {{domxref("event.stopPropagation()", "stopPropagation()")}} 方法。
+
{{domxref("Event.preventCapture()")}} {{non-standard_inline}} {{Obsolete_inline(24)}}
+
已廢棄方法。請改用 {{domxref("event.stopPropagation()", "stopPropagation()")}} 方法。
+
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#interface-event', 'Event')}}{{Spec2('DOM WHATWG')}} 
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Event")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/event/istrusted/index.html b/files/zh-tw/web/api/event/istrusted/index.html new file mode 100644 index 0000000000..fe35fcc393 --- /dev/null +++ b/files/zh-tw/web/api/event/istrusted/index.html @@ -0,0 +1,107 @@ +--- +title: Event.isTrusted +slug: Web/API/Event/isTrusted +translation_of: Web/API/Event/isTrusted +--- +

{{APIRef("DOM")}}

+ +

{{domxref("Event")}} 介面的 isTrusted 唯讀屬性為一個布林值,若事件物件是由使用者操作而產生,則 isTrusted 值為 true。若事件物件是由程式碼所建立、修改,或是透過 {{domxref("EventTarget.dispatchEvent()")}} 來觸發,則 isTrusted 值為 false

+ +

語法

+ +
var bool = event.isTrusted;
+
+ +

範例

+ +
 if (e.isTrusted) {
+     /* The event is trusted. */
+ } else {
+     /* The event is not trusted. */
+ }
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-event-istrusted', 'Event.isTrusted')}}{{ Spec2('DOM WHATWG') }} 
{{SpecName('DOM3 Events', '#trusted-events', 'Trusted events')}}{{Spec2('DOM3 Events')}}Adds requirements regarding trusted and untrusted events, though it does not itself define the isTrusted property.
{{SpecName('DOM4', '#dom-event-istrusted', 'Event.isTrusted')}}{{Spec2('DOM4')}}Initial definition.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome(46.0)}}{{CompatVersionUnknown}}{{CompatNo}} [1]{{CompatOpera(33)}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatUnknown}}{{CompatChrome(46.0)}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatOperaMobile(33)}}{{CompatNo}}{{CompatChrome(46.0)}}
+
+ +

[1] In Internet Explorer, all events are trusted except those that are created with the createEvent() method.

diff --git a/files/zh-tw/web/api/event/preventdefault/index.html b/files/zh-tw/web/api/event/preventdefault/index.html new file mode 100644 index 0000000000..8553f5a23a --- /dev/null +++ b/files/zh-tw/web/api/event/preventdefault/index.html @@ -0,0 +1,129 @@ +--- +title: Event.preventDefault() +slug: Web/API/Event/preventDefault +translation_of: Web/API/Event/preventDefault +--- +
{{ ApiRef("DOM") }}
+ +
 
+ +

概要

+ +

如果事件可以被取消,就取消事件(即取消事件的預設行為)。但不會影響事件的傳遞,事件仍會繼續傳遞。

+ +

語法

+ +
event.preventDefault();
+ +

範例

+ +

Toggling a checkbox is the default action of clicking on a checkbox. This example demonstrates how to prevent that from happening:

+ +
<!DOCTYPE html>
+<html>
+<head>
+<title>preventDefault example</title>
+</head>
+
+<body>
+    <p>Please click on the checkbox control.</p>
+    <form>
+        <label for="id-checkbox">Checkbox</label>
+        <input type="checkbox" id="id-checkbox"/>
+    </form>
+    <script>
+        document.querySelector("#id-checkbox").addEventListener("click", function(event){
+            alert("preventDefault will stop you from checking this checkbox!")
+            event.preventDefault();
+        }, false);
+    </script>
+</body>
+</html>
+ +

You can see preventDefault in action here.

+ +

The following example demonstrates how invalid text input can be stopped from reaching the input field with preventDefault().

+ +
+
<!DOCTYPE html>
+<html>
+<head>
+<title>preventDefault example</title>
+
+<script>
+
+ +
function Init () {
+    var myTextbox = document.getElementById('my-textbox');
+    myTextbox.addEventListener( 'keypress', checkName, false );
+}
+
+function checkName(evt) {
+    var charCode = evt.charCode;
+    if (charCode != 0) {
+        if (charCode < 97 || charCode > 122) {
+            evt.preventDefault();
+            alert(
+                "Please use lowercase letters only."
+                + "\n" + "charCode: " + charCode + "\n"
+            );
+        }
+    }
+}
+
+ +
</script>
+</head>
+<body onload="Init ()">
+    <p>Please enter your name using lowercase letters only.</p>
+    <form>
+        <input type="text" id="my-textbox" />
+    </form>
+</body>
+</html>
+
+ +

Here is the result of the preceding code:

+ +

{{ EmbedLiveSample('preventDefault_invalid_text', '', '', '') }}

+ +

備註

+ +

Calling preventDefault during any stage of event flow cancels the event, meaning that any default action normally taken by the implementation as a result of the event will not occur.

+ +
+

Note: As of {{Gecko("6.0")}}, calling preventDefault() causes the {{ domxref("event.defaultPrevented") }} property's value to become true.

+
+ +

你可以查看 {{domxref("Event.cancelable")}} 屬性來檢查事件是否能夠被取消。對一個不能被取消的事件呼叫 preventDefault() 方法是沒有任何效果的。

+ +

preventDefault() 方法不會停止事件傳遞。若要停止事件繼續傳遞,可以使用 {{domxref("Event.stopPropagation()")}} 方法。

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-event-preventdefault', 'Event.preventDefault()')}}{{ Spec2('DOM WHATWG') }}
{{SpecName('DOM4', '#dom-event-preventdefault', 'Event.preventDefault()')}}{{ Spec2('DOM4') }}
{{SpecName('DOM2 Events', '#Events-Event-preventDefault', 'Event.preventDefault()')}}{{ Spec2('DOM2 Events') }}Initial definition.
diff --git a/files/zh-tw/web/api/event/stopimmediatepropagation/index.html b/files/zh-tw/web/api/event/stopimmediatepropagation/index.html new file mode 100644 index 0000000000..8b08a441cc --- /dev/null +++ b/files/zh-tw/web/api/event/stopimmediatepropagation/index.html @@ -0,0 +1,94 @@ +--- +title: Event.stopImmediatePropagation() +slug: Web/API/Event/stopImmediatePropagation +tags: + - API + - Event +translation_of: Web/API/Event/stopImmediatePropagation +--- +

{{APIRef("DOM")}}

+ +

除了停止事件繼續捕捉或冒泡傳遞外,也阻止事件被傳入同元素中註冊的其它相同事件類型之監聽器。

+ +

語法

+ +
event.stopImmediatePropagation();
+
+ +

備註

+ +

如果一個元素中註冊了多個相同事件類型的監聽器,監聽器將會按照註冊的先後順序被呼叫。在其中任何一個監聽器執行的期間,若是呼叫了事件物件的 stopImmediatePropagation() 方法,則接下來尚未執行的監聽器皆不會被呼叫。

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-event-stopimmediatepropagation', 'Event.stopImmediatePropagation()')}}{{Spec2('DOM WHATWG')}} 
{{SpecName('DOM4', '#dom-event-stopimmediatepropagation', 'Event.stopImmediatePropagation()')}}{{Spec2('DOM4')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatChrome("6.0")}}{{CompatGeckoDesktop("10.0")}}{{CompatIE(9.0)}}{{CompatOpera("15.0")}}{{CompatSafari("5.0")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
diff --git a/files/zh-tw/web/api/event/stoppropagation/index.html b/files/zh-tw/web/api/event/stoppropagation/index.html new file mode 100644 index 0000000000..652231306b --- /dev/null +++ b/files/zh-tw/web/api/event/stoppropagation/index.html @@ -0,0 +1,63 @@ +--- +title: Event.stopPropagation() +slug: Web/API/Event/stopPropagation +tags: + - API + - DOM + - Event + - Method + - NeedsRewrite + - Reference +translation_of: Web/API/Event/stopPropagation +--- +
{{APIRef("DOM")}}
+ +

{{domxref("Event")}} 介面的 stopPropagation() 方法可阻止當前事件繼續進行捕捉(capturing)及冒泡(bubbling)階段的傳遞。

+ +

語法

+ +
event.stopPropagation();
+ +

範例

+ +

請參考範例五:事件傳遞章節中關於此方法與 DOM 事件傳遞的更詳細範例。

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("DOM WHATWG", "#dom-event-stoppropagation", "Event.stopPropagation()")}}{{Spec2("DOM WHATWG")}}
{{SpecName("DOM4", "#dom-event-stoppropagation", "Event.stopPropagation()")}}{{Spec2("DOM4")}}
{{SpecName("DOM2 Events", "#Events-Event-stopPropagation", "Event.stopPropagation()")}}{{Spec2("DOM2 Events")}}Initial definition
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Event.stopPropagation")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/event/target/index.html b/files/zh-tw/web/api/event/target/index.html new file mode 100644 index 0000000000..9599be68c7 --- /dev/null +++ b/files/zh-tw/web/api/event/target/index.html @@ -0,0 +1,134 @@ +--- +title: Event.target +slug: Web/API/Event/target +translation_of: Web/API/Event/target +--- +

{{ApiRef("DOM")}}

+ +

指向最初觸發事件的 DOM 物件。與 {{domxref("event.currentTarget")}} 屬性不同的是,event.currentTarget 屬性總會指向目前於冒泡或捕捉階段正在處理該事件之事件處理器所註冊的 DOM 物件,而 event.target 屬性則是永遠指向觸發事件的 DOM 物件。

+ +

語法

+ +
theTarget = event.target
+ +

範例

+ +

The event.target property can be used in order to implement event delegation.

+ +
// Make a list
+var ul = document.createElement('ul');
+document.body.appendChild(ul);
+
+var li1 = document.createElement('li');
+var li2 = document.createElement('li');
+ul.appendChild(li1);
+ul.appendChild(li2);
+
+function hide(e){
+  // e.target refers to the clicked <li> element
+  // This is different than e.currentTarget which would refer to the parent <ul> in this context
+  e.target.style.visibility = 'hidden';
+}
+
+// Attach the listener to the list
+// It will fire when each <li> is clicked
+ul.addEventListener('click', hide, false);
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("DOM WHATWG", "#dom-event-target", "Event.target")}}{{Spec2("DOM WHATWG")}} 
{{SpecName("DOM4", "#dom-event-target", "Event.target")}}{{Spec2("DOM4")}} 
{{SpecName("DOM2 Events", "#Events-Event-target", "Event.target")}}{{Spec2("DOM2 Events")}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

Compatibility notes

+ +

On IE 6-8 the event model is different. Event listeners are attached with the non-standard {{domxref('EventTarget.attachEvent')}} method. In this model, the event object has a {{domxref('Event.srcElement')}} property, instead of the target property, and it has the same semantics as event.target.

+ +
function hide(e) {
+  // Support IE6-8
+  var target = e.target || e.srcElement;
+  target.style.visibility = 'hidden';
+}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/event/timestamp/index.html b/files/zh-tw/web/api/event/timestamp/index.html new file mode 100644 index 0000000000..3ec006a09e --- /dev/null +++ b/files/zh-tw/web/api/event/timestamp/index.html @@ -0,0 +1,54 @@ +--- +title: Event.timeStamp +slug: Web/API/Event/timeStamp +translation_of: Web/API/Event/timeStamp +--- +
{{ApiRef("DOM")}}
+ +

說明

+ +

回傳事件建立的時間(單位是毫秒;從 epoch 開始計算)。

+ +

Syntax

+ +
event.timeStamp
+
+ +

範例

+ +
var number = event.timeStamp;
+
+ +

下面是一個較為完整的範例:

+ +
<html>
+<head>
+
+<title>timeStamp example</title>
+
+<script type="text/javascript">
+function getTime(event) {
+  document.getElementById("time").firstChild.nodeValue = event.timeStamp;
+}
+</script>
+</head>
+
+<body onkeypress="getTime(event)">
+
+<p>Press any key to get the current timestamp
+for the onkeypress event.</p>
+<p>timeStamp: <span id="time">-</span></p>
+
+</body>
+</html>
+
+ +

注意

+ +

這個 property 僅在瀏覽器支持該事件才會有用。

+ +

詳細資料

+ + diff --git a/files/zh-tw/web/api/event/type/index.html b/files/zh-tw/web/api/event/type/index.html new file mode 100644 index 0000000000..12fcf0176d --- /dev/null +++ b/files/zh-tw/web/api/event/type/index.html @@ -0,0 +1,97 @@ +--- +title: Event.type +slug: Web/API/Event/type +translation_of: Web/API/Event/type +--- +

{{APIRef}}

+ +

Event.type 唯讀屬性會回傳一個代表此事件物件類型的字串。Event.type 屬性是於事件物件建立時被設定,而其屬性值-事件類型名稱也常被當作是特定的事件。

+ +

傳至 {{ domxref("EventTarget.addEventListener()") }} 和 {{ domxref("EventTarget.removeEventListener()") }} 方法中,代表事件類型的參數 event 是不區分大小寫的。

+ +

可用的事件類型,可參考 event reference

+ +

語法

+ +
event.type
+
+ +

範例

+ +
<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+
+    <title>Event.type Example</title>
+
+    <script>
+        var currEvent = null;
+        function getEvtType(evt) {
+            console.log("//Start------------getEvtType(evt)------------ ");
+
+            currEvent = evt.type;
+            console.log(currEvent);
+
+            //document.getElementById("Etype").firstChild.nodeValue = currEvent;
+            document.getElementById("Etype").innerHTML = currEvent;
+
+            console.log("//End--------------getEvtType(evt)------------ ");
+        }
+
+        //Keyboard events
+        document.addEventListener("keypress", getEvtType, false); //[second]
+
+        document.addEventListener("keydown", getEvtType, false); //first
+        document.addEventListener("keyup", getEvtType, false); //third
+
+        //Mouse events
+        document.addEventListener("click", getEvtType, false); // third
+
+        document.addEventListener("mousedown", getEvtType, false); //first
+        document.addEventListener("mouseup", getEvtType, false); //second
+
+    </script>
+</head>
+
+<body>
+
+<p>Press any key or click the mouse to get the event type.</p>
+<p>Event type: <span id="Etype" style="color:red">-</span></p>
+
+</body>
+</html>
+
+ +

Result

+ +

{{EmbedLiveSample('Example')}}

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-event-type', 'Event.type')}}{{ Spec2('DOM WHATWG') }}
{{SpecName('DOM4', '#dom-event-type', 'Event.type')}}{{ Spec2('DOM4') }}
{{SpecName('DOM2 Events', '#Events-Event-type', 'Event.type')}}{{ Spec2('DOM2 Events') }}Initial definition.
diff --git a/files/zh-tw/web/api/eventlistener/index.html b/files/zh-tw/web/api/eventlistener/index.html new file mode 100644 index 0000000000..8db3fba758 --- /dev/null +++ b/files/zh-tw/web/api/eventlistener/index.html @@ -0,0 +1,93 @@ +--- +title: EventListener +slug: Web/API/EventListener +tags: + - DOM + - 事件 + - 事件監聽 +translation_of: Web/API/EventListener +--- +
{{APIRef("DOM Events")}}
+ +

EventListener 介面表示一個可以處理由 {{domxref("EventTarget")}} 物件分派事件的物件。

+ +
+

注意:基於相容舊版內容的需要, EventListener 可以接受一個函式及一個帶有 handleEvent() 屬性函式的物件。相關的範例顯示在下方。

+
+ +

屬性

+ +

這個介面並不實作且不繼承任何屬性。

+ +

方法

+ +

這個介面不繼承任何方法。

+ +
+
{{domxref("EventListener.handleEvent()")}}
+
一個可以在指定類型事件發生時被呼叫的函數。
+
+ +

範例

+ +

HTML

+ +
<button id="btn">Click here!</button>
+ +

JavaScript

+ +
const buttonElement = document.getElementById('btn');
+
+// 透過提供回呼函數的方式對「click」事件新增處理器。
+// 當元素被點選後會出現「Element clicked!」的彈出訊息。
+buttonElement.addEventListener('click', function (event) {
+  alert('Element clicked through function!');
+});
+
+// 基於相容性,一個帶有 `handleEvent` 的非函式物件可被視為處理函式。
+buttonElement.addEventListener('click', {
+  handleEvent: function (event) {
+    alert('Element clicked through handleEvent property!');
+  }
+});
+
+ +

結果

+ +

{{EmbedLiveSample('Example')}}

+ +

檢閱相關:

+ + + +

規格

+ + + + + + + + + + + + + + + + + + + + + +
規格狀態註解
{{SpecName('DOM WHATWG', '#callbackdef-eventlistener', 'EventListener')}}{{Spec2('DOM WHATWG')}}No change.
{{SpecName('DOM2 Events', '#Events-EventListener', 'EventListener')}}{{Spec2('DOM2 Events')}}Initial definition.
+ +

瀏覽器相容性

+ + + +

{{Compat("api.EventListener")}}

diff --git a/files/zh-tw/web/api/eventtarget/dispatchevent/index.html b/files/zh-tw/web/api/eventtarget/dispatchevent/index.html new file mode 100644 index 0000000000..8977c22c9e --- /dev/null +++ b/files/zh-tw/web/api/eventtarget/dispatchevent/index.html @@ -0,0 +1,134 @@ +--- +title: EventTarget.dispatchEvent() +slug: Web/API/EventTarget/dispatchEvent +translation_of: Web/API/EventTarget/dispatchEvent +--- +

{{APIRef("DOM Events")}}

+ +

於此 {{domxref("EventTarget")}} 物件上觸發特定的 {{domxref("Event")}} 物件實體,相當於依照註冊的順序呼叫它的 {{domxref("EventListener")}}。一般事件處理規則(包含捕捉(capturing)和可選的冒泡(bubbling)階段)也適用於用 dispatchEvent() 手動觸發事件。

+ +

語法

+ +
cancelled = !target.dispatchEvent(event)
+
+ +

參數

+ + + +

回傳值

+ + + +

若遇到以下 3 種情況,dispatchEvent 會拋出錯誤資訊--  UNSPECIFIED_EVENT_TYPE_ERR :

+ +
    +
  1. 執行 dispatchEvent 前並未藉由初始化事件指定事件類型
  2. +
  3. 事件類型為 null
  4. +
  5. 事件類型是個空白字串。
  6. +
+ +

這些異常,處理器會報告「異常未捕獲(uncaught exceptions)」;

+ +

事件處理器(event handlers)會在一群呼叫堆(nested callstack)上執行:事件的呼叫方(caller)會先由處理器會阻擋暫停執行,直到事件完成才繼續執行,但是要注意的是,事件若發生異常並不會傳回給呼叫方。

+ +

注意

+ +

dispatchEvent 是「建立→初始化→觸發」的最後一步驟。這些步驟是用來觸發事件,讓事件完成。事件有多種建立方式,例如用 {{domxref("​document.createEvent")}} 並用 initEvent 或其他特殊 methods ,像是 initMouseEventinitUIEvent 來初始化。

+ +

詳請可參考《{{domxref("Event")}}》。

+ +

範例

+ +

請參閱《建立或觸發事件》。

+ +

規格

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-eventtarget-dispatchevent', 'EventTarget.dispatchEvent()')}}{{ Spec2('DOM WHATWG') }} 
{{SpecName('DOM4', '#dom-eventtarget-dispatchevent', 'EventTarget.dispatchEvent()')}}{{ Spec2('DOM4') }} 
{{SpecName('DOM2 Events', '#Events-EventTarget-dispatchEvent', 'EventTarget.dispatchEvent()')}}{{ Spec2('DOM2 Events') }}初始定義
+ +

瀏覽器支援度

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support4{{CompatVersionUnknown}}29 [1]9.64 (probably earlier)3.2 (probably earlier)
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{ CompatUnknown() }}{{CompatVersionUnknown}}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +

[1]:早期的 IE 版本只支持 IE 特有的 {{domxref("EventTarget.fireEvent()")}} 方法來觸發事件。

diff --git a/files/zh-tw/web/api/eventtarget/index.html b/files/zh-tw/web/api/eventtarget/index.html new file mode 100644 index 0000000000..4c10aa133e --- /dev/null +++ b/files/zh-tw/web/api/eventtarget/index.html @@ -0,0 +1,177 @@ +--- +title: EventTarget +slug: Web/API/EventTarget +tags: + - API + - DOM + - DOM Events + - Interface + - NeedsTranslation + - TopicStub + - 待翻譯 +translation_of: Web/API/EventTarget +--- +

{{ ApiRef("DOM Events") }}

+ +

EventTarget 介面定義了其實作的物件具有接收事件的能力,也可能擁有處理事件的監聽器。

+ +

除了最為常見的 {{domxref("Element")}}、{{domxref("Document")}} 與 {{domxref("Window")}} 繼承或實作了 EventTarget 介面之外,其它的物件還有 {{domxref("XMLHttpRequest")}}、{{domxref("AudioNode")}}、{{domxref("AudioContext")}}⋯等等。

+ +

許多 EventTarget(包括 Element、Document 和 Window)除了透過 {{domxref("EventTarget.addEventListener()", "addEventListener()")}} 方法外,還可藉由 {{domxref("Document_Object_Model", "DOM")}} 物件的屬性({{Glossary("property/JavaScript", "property")}})或 HTML 元素屬性({{Glossary("attribute")}})來設定事件處理器

+ +

{{InheritanceDiagram}}

+ +

方法

+ +
+
{{domxref("EventTarget.addEventListener()")}}
+
EventTarget 物件上註冊指定事件的監聽器。
+
{{domxref("EventTarget.removeEventListener()")}}
+
移除 EventTarget 物件上的指定事件監聽器。
+
{{domxref("EventTarget.dispatchEvent()")}}
+
對此 EventTarget 物件派送(dispatch)一個事件物件,也就是於此 EventTarget 物件上觸發一個指定的事件物件實體。
+
+ +

Mozilla chrome code 的額外方法

+ +

Mozilla extensions for use by JS-implemented event targets to implement on* properties. See also WebIDL bindings.

+ + + +

範例

+ +

Simple implementation of EventTarget

+ +
var EventTarget = function() {
+  this.listeners = {};
+};
+
+EventTarget.prototype.listeners = null;
+EventTarget.prototype.addEventListener = function(type, callback) {
+  if (!(type in this.listeners)) {
+    this.listeners[type] = [];
+  }
+  this.listeners[type].push(callback);
+};
+
+EventTarget.prototype.removeEventListener = function(type, callback) {
+  if (!(type in this.listeners)) {
+    return;
+  }
+  var stack = this.listeners[type];
+  for (var i = 0, l = stack.length; i < l; i++) {
+    if (stack[i] === callback){
+      stack.splice(i, 1);
+      return;
+    }
+  }
+};
+
+EventTarget.prototype.dispatchEvent = function(event) {
+  if (!(event.type in this.listeners)) {
+    return true;
+  }
+  var stack = this.listeners[event.type];
+  event.target = this;
+  for (var i = 0, l = stack.length; i < l; i++) {
+    stack[i].call(this, event);
+  }
+  return !event.defaultPrevented;
+};
+
+ +

{{ EmbedLiveSample('_Simple_implementation_of_EventTarget') }}

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#interface-eventtarget', 'EventTarget')}}{{Spec2('DOM WHATWG')}}No change.
{{SpecName('DOM3 Events', 'DOM3-Events.html#interface-EventTarget', 'EventTarget')}}{{Spec2('DOM3 Events')}}A few parameters are now optional (listener), or accepts the null value (useCapture).
{{SpecName('DOM2 Events', 'events.html#Events-EventTarget', 'EventTarget')}}{{Spec2('DOM2 Events')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1")}}9.071.0[1]
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support1.0{{CompatVersionUnknown}}{{CompatGeckoMobile("1")}}9.06.01.0
+
+ +

[1] window.EventTarget does not exist.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/eventtarget/removeeventlistener/index.html b/files/zh-tw/web/api/eventtarget/removeeventlistener/index.html new file mode 100644 index 0000000000..136aa0cf58 --- /dev/null +++ b/files/zh-tw/web/api/eventtarget/removeeventlistener/index.html @@ -0,0 +1,274 @@ +--- +title: EventTarget.removeEventListener() +slug: Web/API/EventTarget/removeEventListener +translation_of: Web/API/EventTarget/removeEventListener +--- +

{{APIRef("DOM Events")}}

+ +

EventTarget.removeEventListener() 方法可以移除先前由 {{domxref("EventTarget.addEventListener()", "addEventListener()")}} 所註冊的事件監聽器。

+ +

語法

+ +
target.removeEventListener(type, listener[, options]);
+target.removeEventListener(type, listener[, useCapture]);
+
+ +

參數

+ +
+
type
+
A string representing the event type to remove.
+
listener
+
The {{domxref("EventListener")}} function to remove from the event target.
+
options {{optional_inline}}
+
An options object that specifies characteristics about the event listener. The available options are: +
    +
  • capture: A {{jsxref("Boolean")}} that indicates that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree.  
  • +
  • passive: A {{jsxref("Boolean")}} indicating that the listener will never call preventDefault(). If it does, the user agent should ignore it and generate a console warning.
  • +
  • {{non-standard_inline}} mozSystemGroup: Available only in code running in XBL or in Firefox' chrome, it is a {{jsxref("Boolean")}} defining if the listener is added to the system group.
  • +
+
+
useCapture {{optional_inline}}
+
Specifies whether the {{domxref("EventListener")}} to be removed is registered as a capturing listener or not. If this parameter is absent, a default value of false is assumed.
+
If a listener is registered twice, one with capture and one without, remove each one separately. Removal of a capturing listener does not affect a non-capturing version of the same listener, and vice versa.
+
+ +
Note: useCapture was required in most major browsers' early versions. If broad compatibility is desired, you should always provide the useCapture parameter.
+ +

回傳值

+ +

無。

+ +

備註

+ +

If an {{domxref("EventListener")}} is removed from an {{domxref("EventTarget")}} while it is processing an event, it will not be triggered by the current actions. An {{domxref("EventListener")}} will not be invoked for the event it was registered for after being removed, however it can be reattached.

+ +

Calling removeEventListener() with arguments that do not identify any currently registered {{domxref("EventListener")}} on the EventTarget has no effect.

+ +

範例

+ +

This example shows how to add a click-based event listener and remove a mouseover-based event listener.

+ +
var body =
+        document.querySelector('body'),
+    clickTarget =
+        document.getElementById('click-target'),
+    mouseOverTarget =
+        document.getElementById('mouse-over-target'),
+    toggle = false;
+
+function makeBackgroundYellow() {
+    'use strict';
+
+    if (toggle) {
+        body.style.backgroundColor = 'white';
+    } else {
+        body.style.backgroundColor = 'yellow';
+    }
+
+    toggle = !toggle;
+}
+
+clickTarget.addEventListener('click',
+    makeBackgroundYellow,
+    false
+);
+
+mouseOverTarget.addEventListener('mouseover', function () {
+    'use strict';
+
+    clickTarget.removeEventListener('click',
+        makeBackgroundYellow,
+        false
+    );
+});
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("DOM WHATWG", "#dom-eventtarget-removeeventlistener", "EventTarget.removeEventListener()")}}{{Spec2("DOM WHATWG")}} 
{{SpecName("DOM4", "#dom-eventtarget-removeeventlistener", "EventTarget.removeEventListener()")}}{{Spec2("DOM4")}} 
{{SpecName("DOM2 Events", "#Events-EventTarget-removeEventListener", "EventTarget.removeEventListener()")}}{{Spec2("DOM2 Events")}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1.0[1][2]{{CompatGeckoDesktop("1")}}[3]9.07[4]1.0[1]
useCapture made optional{{CompatVersionUnknown}}6.09.011.60{{CompatVersionUnknown}}
options parameter{{CompatChrome(49.0)}}    
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewFirefox Mobile (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
Basic support1.0[1]{{CompatVersionUnknown}}[2]{{CompatGeckoMobile("1")}}[3]9.06.0[4]1.0[1]{{CompatVersionUnknown}}[2]
useCapture made optional{{CompatUnknown}}{{CompatVersionUnknown}}    {{CompatVersionUnknown}}
options parameter{{CompatNo}}{{CompatChrome(49.0)}}    {{CompatChrome(49.0)}}
+
+ +

[1] Although WebKit explicitly added "[optional]" to the useCapture parameter for Safari 5.1 and Chrome 13, it had been working before the change.

+ +

[2] Before Chrome 49, the type and listener parameters were optional.

+ +

[2] Prior to Firefox 6, the browser would throw an exception if the useCapture parameter was not explicitly false. Prior to Gecko 9.0 {{geckoRelease("9.0")}}, addEventListener() would throw an exception if the listener parameter was null; now the method returns without error, but without doing anything.

+ +

[4] Opera 11.60 made the useCapture parameter optional (source).

+ +

[5] For backwards compatibility, browsers that support options allow the third parameter to be either options or Boolean.

+ +

Polyfill to support older browsers

+ +

addEventListener() and removeEventListener() are not present in older browsers. You can work around this by inserting the following code at the beginning of your scripts, allowing the use of addEventListener() and removeEventListener() in implementations that do not natively support it. However, this method will not work on Internet Explorer 7 or earlier, since extending the Element.prototype was not supported until Internet Explorer 8.

+ +
if (!Element.prototype.addEventListener) {
+  var oListeners = {};
+  function runListeners(oEvent) {
+    if (!oEvent) { oEvent = window.event; }
+    for (var iLstId = 0, iElId = 0, oEvtListeners = oListeners[oEvent.type]; iElId < oEvtListeners.aEls.length; iElId++) {
+      if (oEvtListeners.aEls[iElId] === this) {
+        for (iLstId; iLstId < oEvtListeners.aEvts[iElId].length; iLstId++) { oEvtListeners.aEvts[iElId][iLstId].call(this, oEvent); }
+        break;
+      }
+    }
+  }
+  Element.prototype.addEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {
+    if (oListeners.hasOwnProperty(sEventType)) {
+      var oEvtListeners = oListeners[sEventType];
+      for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
+        if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
+      }
+      if (nElIdx === -1) {
+        oEvtListeners.aEls.push(this);
+        oEvtListeners.aEvts.push([fListener]);
+        this["on" + sEventType] = runListeners;
+      } else {
+        var aElListeners = oEvtListeners.aEvts[nElIdx];
+        if (this["on" + sEventType] !== runListeners) {
+          aElListeners.splice(0);
+          this["on" + sEventType] = runListeners;
+        }
+        for (var iLstId = 0; iLstId < aElListeners.length; iLstId++) {
+          if (aElListeners[iLstId] === fListener) { return; }
+        }
+        aElListeners.push(fListener);
+      }
+    } else {
+      oListeners[sEventType] = { aEls: [this], aEvts: [ [fListener] ] };
+      this["on" + sEventType] = runListeners;
+    }
+  };
+  Element.prototype.removeEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {
+    if (!oListeners.hasOwnProperty(sEventType)) { return; }
+    var oEvtListeners = oListeners[sEventType];
+    for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
+      if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
+    }
+    if (nElIdx === -1) { return; }
+    for (var iLstId = 0, aElListeners = oEvtListeners.aEvts[nElIdx]; iLstId < aElListeners.length; iLstId++) {
+      if (aElListeners[iLstId] === fListener) { aElListeners.splice(iLstId, 1); }
+    }
+  };
+}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/fetch_api/index.html b/files/zh-tw/web/api/fetch_api/index.html new file mode 100644 index 0000000000..2cd6f23d22 --- /dev/null +++ b/files/zh-tw/web/api/fetch_api/index.html @@ -0,0 +1,84 @@ +--- +title: Fetch API +slug: Web/API/Fetch_API +translation_of: Web/API/Fetch_API +--- +
{{DefaultAPISidebar("Fetch API")}}
+ +
Fetch API 提供了一個能獲取包含跨網路資源在的資源介面。它有點像我們所熟悉的 {{domxref("XMLHttpRequest")}} ,但這個新的 API 提供了更強更彈性的功能。
+ +

概念與應用

+ +

Fetch 提供了 {{domxref("Request")}} 與 {{domxref("Response")}} 物件,還有其他牽涉網路請求的通用定義。這能讓他們在需要的時候被使用到,不管是 service worker、Cache API、還是其他處理或更動請求回應的相類事物、或是任何需要產生有序化產生回應的用例(use case)。

+ +

它也提供了諸如 CORS 與 HTTP origin 標頭語意的分散定義,能取代分散的定義。

+ +

要發動請求並取得資源的話,請使用 {{domxref("GlobalFetch.fetch")}} 方法。他實作了數種介面,並指定了 {{domxref("Window")}} 與 {{domxref("WorkerGlobalScope")}},使它可以在任何想獲取資源的環境中使用。

+ +

fetch() 方法有一個強制性的參數,就是要取得資源的網址。該方法會回傳一個不論請求成敗,都會 resolve 的 promise {{domxref("Response","回應")}}。你也能選擇性地使用第二個稱為 init 的物件參數(請參見 {{domxref("Request")}})。

+ +

當 {{domxref("Response")}} 檢索後,在請求體裡面會定義一些請求體為何,還有要如何處理的方法(請參見 {{domxref("Body")}})。

+ +

你也可以直接用 {{domxref("Request.Request","Request()")}} 與 {{domxref("Response.Response","Response()")}} 建構子來建立請求與回應,不過你不太可能直接使用他,反而更可能是以其他 API 行動的結果為形式存在。(例如來自 service worker 的 {{domxref("FetchEvent.respondWith")}})

+ +
+

注意:你可以在使用 Fetch深入理解 Fetch,並在Fetch 的基本概念文章內理解概念。

+
+ +

中斷一次 Fetch

+ +

各家瀏覽器已經開始加入 {{DOMxRef("AbortController")}} 與 {{DOMxRef("AbortSignal")}} 介面(也就是 Abort API)的實驗性支援,讓 Fetch 和 XHR 這類的操作在完成前可以被中斷。詳情請參閱相關介面的文件。

+ +

Fetch 介面

+ +
+
{{DOMxRef("WindowOrWorkerGlobalScope.fetch()")}}
+
用於取得資源的 fetch() 方法。
+
{{domxref("Headers")}}
+
代表請求/回應標頭,讓你能 query 並針對結果不同,採取不同行動。
+
{{domxref("Request")}}
+
代表資源請求。
+
{{domxref("Response")}}
+
代表資源請求的回應。
+
+ +

Fetch mixin

+ +
+
{{domxref("Body")}}
+
提供請求/回應訊息體的相關方法,能宣告內容的類別為何,以及該如何處理。
+
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('Fetch')}}{{Spec2('Fetch')}}初始定義
+ +

瀏覽器相容性

+ + + +

{{Compat("api.WindowOrWorkerGlobalScope.fetch")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/fetch_api/using_fetch/index.html b/files/zh-tw/web/api/fetch_api/using_fetch/index.html new file mode 100644 index 0000000000..3af949b659 --- /dev/null +++ b/files/zh-tw/web/api/fetch_api/using_fetch/index.html @@ -0,0 +1,379 @@ +--- +title: Using Fetch +slug: Web/API/Fetch_API/Using_Fetch +tags: + - Fetch + - HTTP + - Promise + - Response + - request +translation_of: Web/API/Fetch_API/Using_Fetch +--- +

{{DefaultAPISidebar("Fetch API")}}

+ +
+

Fetch API 提供了一種 JavaScript Interface 來操作 HTTP pipeline,比方 request 和 response。同時它也提供了 global 的 {{domxref("GlobalFetch.fetch","fetch()")}} method,使得在網路上非同步地 fetch resources 這件事變得簡單易懂。

+
+ +

同樣的功能,以前都是使用 {{domxref("XMLHttpRequest")}},而 Fetch 作為其替代方案,能更方便地整合在如 {{domxref("ServiceWorker_API", "Service Workers")}} 等相關技術上。此外,Fetch 具備額外的 logical palce,能拿來定義其他和 HTTP 有關的東西,像是 CORS 和 HTTP extensions。

+ +

 fetch 和 jQuery.ajax() 有三個主要的差異:

+ + + +

使用 Fetch 發送請求 ( request )

+ +

用法簡單,如下:

+ +
fetch('http://example.com/movies.json')
+  .then(function(response) {
+    return response.json();
+  })
+  .then(function(myJson) {
+    console.log(myJson);
+  });
+
+
+ +

這裡要使用 fetch 透過網路取得 json 然後印出在 console,最簡單的方式只需要一個參數就是資料的 URI,fetch 會回傳一個包含 response 的 promise 。

+ +

這個範例使用的 url 只是示意用。

+ +

回傳的 response 需要透過 {{domxref("Body.json","json()")}} (在 {{domxref("Body")}} 可以找到定義, Body 是用 {{domxref("Request")}} 和 {{domxref("Response")}} 實作出來的物件.)

+ +
+

備註: 其實 Body 還提供了其他類似的功能可以將內容輸成其他類型格式,詳見{{anch("Body")}} 

+
+ +

Fetch 請求的安全性 Content Security Policy(內容安全策略) 是由 header 中的 connect-src directive 所設定 ,並非其他 directive ( 比如:img-src、default-src 等)。

+ +

Request 可用的設定值

+ +

fetch() 第二個參數是選用的,可以傳送一個 init Object 來設定 request。

+ +

更多可以用的設定值詳見 {{domxref("GlobalFetch.fetch","fetch()")}} 

+ +
// 來發個 POST Request:
+
+postData('http://example.com/answer', {answer: 42})
+  .then(data => console.log(data)) // JSON from `response.json()` call
+  .catch(error => console.error(error))
+
+function postData(url, data) {
+  // Default options are marked with *
+  return fetch(url, {
+    body: JSON.stringify(data), // must match 'Content-Type' header
+    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
+    credentials: 'same-origin', // include, same-origin, *omit
+    headers: {
+      'user-agent': 'Mozilla/4.0 MDN Example',
+      'content-type': 'application/json'
+    },
+    method: 'POST', // *GET, POST, PUT, DELETE, etc.
+    mode: 'cors', // no-cors, cors, *same-origin
+    redirect: 'follow', // manual, *follow, error
+    referrer: 'no-referrer', // *client, no-referrer
+  })
+  .then(response => response.json()) // 輸出成 json
+}
+
+ +

包含憑證(Credentials) 的 Request 用法

+ +

要讓瀏覽器將 credentials 跟著 request 一起送出, 方式就是在 init object 加上 credentials: 'include' 

+ +
fetch('https://example.com', {
+  credentials: 'include'
+})
+ +

如果只想要把 credentials 發送給同源的 URL ,加上credentials: 'same-origin'

+ +
// The calling script is on the origin 'https://example.com'
+
+fetch('https://example.com', {
+  credentials: 'same-origin'
+})
+ +

或要確保瀏覽器不會帶著 credentials 請求,可以用 credentials: 'omit' 。

+ +
fetch('https://example.com', {
+  credentials: 'omit'
+})
+ +

上傳JSON資料

+ +

使用 {{domxref("GlobalFetch.fetch","fetch()")}} 來 POST JSON 格式的資料。

+ +
var url = 'https://example.com/profile';
+var data = {username: 'example'};
+
+fetch(url, {
+  method: 'POST', // or 'PUT'
+  body: JSON.stringify(data), // data can be `string` or {object}!
+  headers: new Headers({
+    'Content-Type': 'application/json'
+  })
+}).then(res => res.json())
+.catch(error => console.error('Error:', error))
+.then(response => console.log('Success:', response));
+
+ +

上傳檔案

+ +

上傳檔案可以透過使用HTML <input type="file" /> input element, {{domxref("FormData.FormData","FormData()")}} 與{{domxref("GlobalFetch.fetch","fetch()")}}.

+ +
var formData = new FormData();
+var fileField = document.querySelector("input[type='file']");
+
+formData.append('username', 'abc123');
+formData.append('avatar', fileField.files[0]);
+
+fetch('https://example.com/profile/avatar', {
+  method: 'PUT',
+  body: formData
+})
+.then(response => response.json())
+.catch(error => console.error('Error:', error))
+.then(response => console.log('Success:', response));
+
+ +

如何確認fetch是否成功

+ +

當{{domxref("GlobalFetch.fetch","fetch()")}}遇到CORS或server設定錯誤導致network error時,  promise會reject並附上{{jsxref("TypeError")}}的回應, 但在權限或類似問題導致404的常見狀況下, 卻不會導致network error.

+ +

因此, 確認fetch()是否成功的正確方式, 應包含檢查promise resolved, 以及檢查{{domxref("Response.ok")}}的屬性是否為true. 代碼如下例:

+ +
fetch('flowers.jpg').then(function(response) {
+  if(response.ok) {
+    return response.blob();
+  }
+  throw new Error('Network response was not ok.');
+}).then(function(myBlob) {
+  var objectURL = URL.createObjectURL(myBlob);
+  myImage.src = objectURL;
+}).catch(function(error) {
+  console.log('There has been a problem with your fetch operation: ', error.message);
+});
+ +

Supplying your own request object

+ +

Instead of passing a path to the resource you want to request into the fetch() call, you can create a request object using the {{domxref("Request.Request","Request()")}} constructor, and pass that in as a fetch() method argument:

+ +
var myHeaders = new Headers();
+
+var myInit = { method: 'GET',
+               headers: myHeaders,
+               mode: 'cors',
+               cache: 'default' };
+
+var myRequest = new Request('flowers.jpg', myInit);
+
+fetch(myRequest).then(function(response) {
+  return response.blob();
+}).then(function(myBlob) {
+  var objectURL = URL.createObjectURL(myBlob);
+  myImage.src = objectURL;
+});
+ +

Request() accepts exactly the same parameters as the fetch() method. You can even pass in an existing request object to create a copy of it:

+ +
var anotherRequest = new Request(myRequest, myInit);
+ +

This is pretty useful, as request and response bodies are one use only. Making a copy like this allows you to make use of the request/response again, while varying the init options if desired.  The copy must be made before the body is read, and reading the body in the copy will also mark it as read in the original request.

+ +
+

Note: There is also a {{domxref("Request.clone","clone()")}} method that creates a copy. Both methods of creating a copy will fail if the body of the original request or response has already been read, but reading the body of a cloned response or request will not cause it to be marked as read in the original.

+
+ +

Headers

+ +

The {{domxref("Headers")}} interface allows you to create your own headers object via the {{domxref("Headers.Headers","Headers()")}} constructor. A headers object is a simple multi-map of names to values:

+ +
var content = "Hello World";
+var myHeaders = new Headers();
+myHeaders.append("Content-Type", "text/plain");
+myHeaders.append("Content-Length", content.length.toString());
+myHeaders.append("X-Custom-Header", "ProcessThisImmediately");
+ +

The same can be achieved by passing an array of arrays or an object literal to the constructor:

+ +
myHeaders = new Headers({
+  "Content-Type": "text/plain",
+  "Content-Length": content.length.toString(),
+  "X-Custom-Header": "ProcessThisImmediately",
+});
+ +

The contents can be queried and retrieved:

+ +
console.log(myHeaders.has("Content-Type")); // true
+console.log(myHeaders.has("Set-Cookie")); // false
+myHeaders.set("Content-Type", "text/html");
+myHeaders.append("X-Custom-Header", "AnotherValue");
+
+console.log(myHeaders.get("Content-Length")); // 11
+console.log(myHeaders.get("X-Custom-Header")); // ["ProcessThisImmediately", "AnotherValue"]
+
+myHeaders.delete("X-Custom-Header");
+console.log(myHeaders.get("X-Custom-Header")); // [ ]
+ +

Some of these operations are only useful in {{domxref("ServiceWorker_API","ServiceWorkers")}}, but they provide a much nicer API for manipulating headers.

+ +

All of the Headers methods throw a TypeError if a header name is used that is not a valid HTTP Header name. The mutation operations will throw a TypeError if there is an immutable guard (see below). Otherwise they fail silently. For example:

+ +
var myResponse = Response.error();
+try {
+  myResponse.headers.set("Origin", "http://mybank.com");
+} catch(e) {
+  console.log("Cannot pretend to be a bank!");
+}
+ +

A good use case for headers is checking whether the content type is correct before you process it further. For example:

+ +
fetch(myRequest).then(function(response) {
+    var contentType = response.headers.get("content-type");
+    if(contentType && contentType.includes("application/json")) {
+      return response.json();
+    }
+    throw new TypeError("Oops, we haven't got JSON!");
+  })
+  .then(function(json) { /* process your JSON further */ })
+  .catch(function(error) { console.log(error); });
+ +

Guard

+ +

Since headers can be sent in requests and received in responses, and have various limitations about what information can and should be mutable, headers objects have a guard property. This is not exposed to the Web, but it affects which mutation operations are allowed on the headers object.

+ +

Possible guard values are:

+ + + +
+

Note: You may not append or set a request guarded Headers’ Content-Length header. Similarly, inserting Set-Cookie into a response header is not allowed: ServiceWorkers are not allowed to set cookies via synthesized responses.

+
+ +

Response objects

+ +

As you have seen above, {{domxref("Response")}} instances are returned when fetch() promises are resolved.

+ +

The most common response properties you'll use are:

+ + + +

They can also be created programmatically via JavaScript, but this is only really useful in {{domxref("ServiceWorker_API", "ServiceWorkers")}}, when you are providing a custom response to a received request using a {{domxref("FetchEvent.respondWith","respondWith()")}} method:

+ +
var myBody = new Blob();
+
+addEventListener('fetch', function(event) { // ServiceWorker intercepting a fetch
+  event.respondWith(
+    new Response(myBody, {
+      headers: { "Content-Type" : "text/plain" }
+    })
+  );
+});
+ +

The {{domxref("Response.Response","Response()")}} constructor takes two optional arguments — a body for the response, and an init object (similar to the one that {{domxref("Request.Request","Request()")}} accepts.)

+ + + +
+

Note: The static method {{domxref("Response.error","error()")}} simply returns an error response. Similarly, {{domxref("Response.redirect","redirect()")}} returns a response resulting in a redirect to a specified URL. These are also only relevant to Service Workers.

+
+ +

Body

+ +

Both requests and responses may contain body data. A body is an instance of any of the following types:

+ + + +

The {{domxref("Body")}} mixin defines the following methods to extract a body (implemented by both {{domxref("Request")}} and {{domxref("Response")}}). These all return a promise that is eventually resolved with the actual content.

+ + + +

This makes usage of non-textual data much easier than it was with XHR.

+ +

Request bodies can be set by passing body parameters:

+ +
var form = new FormData(document.getElementById('login-form'));
+fetch("/login", {
+  method: "POST",
+  body: form
+});
+ +

Both request and response (and by extension the fetch() function), will try to intelligently determine the content type. A request will also automatically set a Content-Type header if none is set in the dictionary.

+ +

特性偵測

+ +

想確認是否支持 Fetch API,可透過檢查 {{domxref("Headers")}}、{{domxref("Request")}}、{{domxref("Response")}} 或 {{domxref("GlobalFetch.fetch","fetch()")}} 是否存在 {{domxref("Window")}} 或 {{domxref("Worker")}} 域中。例如:

+ +
if (self.fetch) {
+    // run my fetch request here
+} else {
+    // do something with XMLHttpRequest?
+}
+ +

Polyfill

+ +

在不支援 Fetch 的瀏覽器, 可改用 Fetch Polyfill 來重新支持缺少的 fetch 功能。

+ +

技術指標

+ + + + + + + + + + + + + + +
技術名稱狀態說明
{{SpecName('Fetch')}}{{Spec2('Fetch')}}Initial definition
+ +

瀏覽器相容性

+ +
+ + +

{{Compat("api.WindowOrWorkerGlobalScope.fetch")}}

+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/file/file/index.html b/files/zh-tw/web/api/file/file/index.html new file mode 100644 index 0000000000..1990248f72 --- /dev/null +++ b/files/zh-tw/web/api/file/file/index.html @@ -0,0 +1,112 @@ +--- +title: File.File() +slug: Web/API/File/File +translation_of: Web/API/File/File +--- +

{{APIRef("File")}}

+ +

File()  建構子建立一個新的 {{domxref("File")}} 物件實例

+ +

語法

+ +
var myFile = new File(bits, name[, options]);
+ +

參數

+ +
+
bits
+
An {{jsxref("Array")}} of {{jsxref("ArrayBuffer")}}, {{domxref("ArrayBufferView")}}, {{domxref("Blob")}}, or {{domxref("DOMString")}} objects — 或是由這些物件組成的集合。這是以 UTF-8 編碼的檔案內容。
+
name
+
檔案名稱或檔案的路徑({{domxref("USVString")}})。
+
options {{optional_inline}}
+
物件選項,包含物件非必要的屬性,以下為可得到的屬性: +
    +
  • type: 物件的 MIME 類型({{domxref("DOMString")}} )將被放進檔案中,預設為 ""(空值)。
  • +
  • lastModified: 檔案最後修改時間,格式為毫秒,預設為 {{jsxref("Date.now()")}}.
  • +
+
+
+ +

範例

+ +
var file = new File(["foo"], "foo.txt", {
+  type: "text/plain",
+});
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態說明
{{SpecName('File API')}}{{Spec2('File API')}}初始化定義
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support13{{CompatNo}}{{CompatGeckoDesktop("7")}}{{CompatNo}}11.510.1
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support4.4.4{{CompatVersionUnknown}}{{CompatGeckoMobile("7")}}{{CompatNo}}{{CompatNo}}6.0
+
+ +

看更多

+ + diff --git a/files/zh-tw/web/api/file/filename/index.html b/files/zh-tw/web/api/file/filename/index.html new file mode 100644 index 0000000000..0e6cceb4f3 --- /dev/null +++ b/files/zh-tw/web/api/file/filename/index.html @@ -0,0 +1,32 @@ +--- +title: File.fileName +slug: Web/API/File/fileName +translation_of: Web/API/File/fileName +--- +

{{APIRef("File API")}}{{non-standard_header}}

+ +

{{deprecated_header(7.0)}}

+ +

總覽

+ +

回傳檔案名稱,基於安全因素,檔案路徑不包含這個屬性。

+ +
這個檔案是廢棄的,使用 {{domxref("File.name")}} 取代。
+ +

語法

+ +
var name = instanceOfFile.fileName
+ +

數值

+ +

字串

+ +

格式

+ +

尚無資料

+ +

看更多

+ + diff --git a/files/zh-tw/web/api/file/index.html b/files/zh-tw/web/api/file/index.html new file mode 100644 index 0000000000..0dce936ff8 --- /dev/null +++ b/files/zh-tw/web/api/file/index.html @@ -0,0 +1,121 @@ +--- +title: File +slug: Web/API/File +tags: + - API + - File API + - Interface + - Reference + - Web + - 介面 + - 參考 + - 檔案 API + - 檔案API + - 網路 +translation_of: Web/API/File +--- +
{{APIRef}}
+ +

File 介面提供了檔案的資訊並且允許網頁中的 JavaScript 存取檔案的內容。

+ +

File 物件通常是從使用者於 {{HTMLElement("input")}} 元素選擇之檔案所回傳的 {{domxref("FileList")}} 物件當中取得,也可以來自拖放操作所產生的 {{domxref("DataTransfer")}} 物件之中,或是由 {{domxref("HTMLCanvasElement")}} 物件(元素物件)執行 mozGetAsFile() 方法後回傳。在 Gecko 引擎中,有專屬的程式碼能不需使用者操作即建立 File 物件來表示本地端的任一檔案(請參考 {{anch("Implementation notes")}} 以閱讀更多資訊)。

+ +

File 物件是一種特殊的 {{domxref("Blob")}},且可被用在任何接受 Blob 物件的地方。特別是 {{domxref("FileReader")}}、{{domxref("URL.createObjectURL()")}}、{{domxref("ImageBitmapFactories.createImageBitmap()", "createImageBitmap()")}} 和 {{domxref("XMLHttpRequest", "", "send()")}} 都能夠同樣接受 Blob 以及 File

+ +

請參考在網頁應用程式中使用本地檔案的更多細節與範例。

+ +

{{InheritanceDiagram}}

+ +

建構式

+ +
+
{{domxref("File.File", "File()")}}
+
回傳一個新建構的 File 物件。
+
+ +

屬性

+ +
+
{{domxref("File.lastModified")}} {{readonlyinline}}
+
回值檔案的最後修改時間,為 UNIX epoch 毫秒(自西元 1970 年一月 1 日零時至今)。
+
{{domxref("File.lastModifiedDate")}} {{readonlyinline}} {{deprecated_inline}} {{gecko_minversion_inline("15.0")}}
+
File 物件所代表之檔案的最後修改日期(Date)。
+
{{domxref("File.name")}} {{readonlyinline}}
+
File 物件所代表之檔案的名稱。
+
{{domxref("File.size")}} {{readonlyinline}}
+
回傳檔案大小。
+
{{domxref("File.webkitRelativePath")}} {{readonlyinline}} {{non-standard_inline}}
+
回傳相對於 {{domxref("File")}} 的網址位置。
+
{{domxref("File.type")}} {{readonlyinline}}
+
回傳檔案的 MIME 類型。
+
+ +

File 實作了 {{domxref("Blob")}},因此它也有以下可用屬性:

+ +
+
{{domxref("File.size")}} {{readonlyinline}}
+
回傳檔案大小(單位為位元組)。
+
{{domxref("File.type")}} {{readonlyinline}}
+
回傳檔案的 MIME 類型。
+
+ +

方法

+ +

File 介面沒有定義任何方法,但繼承了 {{domxref("Blob")}} 介面的方法:

+ +
+
{{domxref("Blob.slice()", "Blob.slice([start[, end[, contentType]]])")}}
+
+

回傳新的 Blob 物件,包含 Blob 來源之指定位元組範圍的資料。

+
+
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態備註
{{SpecName('File API')}}{{Spec2('File API')}}初次定義
+ +

瀏覽器相容性

+ +
+ + +

{{Compat("api.File")}}

+
+ +

 

+ +

實作備註

+ + + +

參見

+ + diff --git a/files/zh-tw/web/api/file/using_files_from_web_applications/index.html b/files/zh-tw/web/api/file/using_files_from_web_applications/index.html new file mode 100644 index 0000000000..52bd1928b3 --- /dev/null +++ b/files/zh-tw/web/api/file/using_files_from_web_applications/index.html @@ -0,0 +1,411 @@ +--- +title: 在網頁應用程式中使用本地檔案 +slug: Web/API/File/Using_files_from_web_applications +tags: + - 待翻譯 +translation_of: Web/API/File/Using_files_from_web_applications +--- +

 {{ gecko_minversion_header("1.9.2") }}

+ +

現在可以透過新增至HTML5 DOM的File API讓web內容要求使用者選取本地端的檔案後讀取被選取檔案中的內容。檔案的選取動作可以使用HTML的 input 元素,或是用拖曳檔案(drag and drop)的方式來完成。

+ +

如果你想要使用 DOM 檔案 API 的文件擴展或是其他Chrome 程式碼,你可以參考使用DOM檔案API在FireFox外觀代碼中

+ +

使用HTML選擇本地檔案

+ +

HTML 語法:

+ +
<input type="file" id="input">
+ +

File API 可以從 {{ domxref("File") }} 物件中讀取 {{ domxref("FileList") }} ,{{domxref("FileList") }} 內包含使用者所選取的檔案。

+ +

如果使用者只選擇一個檔案,那麼我們只需要考慮第一個檔案物件。

+ +

使用 DOM 獲取選擇的檔案:

+ +
var selectedFile = document.getElementById('input').files[0];
+ +

使用 jQuery 獲取選擇的檔案:

+ +
var selectedFile = $('#input').get(0).files[0];
+
+var selectedFile = $('#input')[0].files[0];
+
+ +
+

如果獲取 "files is undefined" 錯誤: 代表未選擇正確的 HTML 元素, 這時忘記 jQuery 回傳符合 DOM 元素的清單. 改使用 DOM 元素呼叫  "files" 方法.

+
+ +

使用 change event 獲取選擇的檔案

+ +

使用File API選擇單一檔案是非常簡單的,如下

+ +
<input type="file" id="input" onchange="handleFiles(this.files)">
+
+ +

當使用者選取一個檔案,呼叫 handleFiles() 會得到一個 {{domxref("FileList") }} 的物件。{{domxref("FileList") }} 裡面還會有一個 {{domxref("File")}} 的物件,裡面的東西就是使用者選取的檔案。

+ +

如果你想要讓使用者一次選擇多個檔案,可以在 input 元素中使用 multiple 的屬性:

+ +
<input type="file" id="input" multiple="true" onchange="handleFiles(this.files)">
+
+
+ +

在上述這個例子中,檔案名單會傳遞到 handleFiles() 函數,其中包含了使用者選的每個檔案 {{domxref("File")}} 物件

+ +

使用 EventListener 動態地監聽

+ +

如果使用了其他的函數庫(jQuery),你會需要使用 {{domxref("EventTarget.addEventListener()") }} 去監聽事件,例如:

+ +
var inputElement = document.getElementById("inputField");
+inputElement.addEventListener("change", handleFiles, false);
+
+function handleFiles() {
+  var fileList = this.files;
+
+  /* now you can work with the file list */
+}
+
+ +

在這個例子中,handleFiles() 函數找尋檔案清單而非接收參數, 因為這樣增加的 event listeners 不能接受參數.

+ +

獲得選取檔案的資訊

+ +

由DOM提供的 {{domxref("FileList") }} 物件代表使用者選取的所有檔案,每個又是 {{domxref("File")}} 物件。可以藉由 {{domxref("FileList") }} 的 length 屬性得知使用者選取的檔案數量:

+ +
var numFiles = files.length;
+
+ +

使用陣列獲取 {{domxref("File")}} 物件:

+ +
for (var i = 0; i < files.length; i++) {
+  var file = files[i];
+  ..
+}
+
+ +

上述的例子顯示獲取在檔案清單裡所有檔案物件的方法。

+ +

{{domxref("File")}} 提供三個包含檔案重要訊息的屬性。

+ +
+
name
+
唯讀的檔案名稱,並未包含檔案路徑。
+
size
+
為 64 位元的整數,用以表示檔案的 byte 的長度。
+
type
+
為唯讀字串。表示檔案的 MIME-type 。若是無法取得檔案的 Mime-type ,則其值會是一個空字串 ""
+
+ +

 

+ +

使用click() 方法隱藏檔案輸入元素

+ +

從 Gecko 2.0 {{ geckoRelease("2.0") }}開始,為了顯示個人化開啟檔案的UI和使用者選擇的檔案可以隱藏 {{ HTMLElement("input") }} 元素和顯示個人化的設計。可以藉由設置CSS 「display:none」 和對 {{ HTMLElement("input") }} 元素呼叫 click() 方法。

+ +

HTML 如下:

+ +
<input type="file" id="fileElem" multiple="true" accept="image/*" style="display:none" onchange="handleFiles(this.files)">
+<a href="#" id="fileSelect">Select some files</a>
+
+ +

doClick() 方法:

+ +
var fileSelect = document.getElementById("fileSelect"),
+  fileElem = document.getElementById("fileElem");
+
+fileSelect.addEventListener("click", function (e) {
+  if (fileElem) {
+    fileElem.click();
+  }
+  e.preventDefault(); // prevent navigation to "#"
+}, false);
+
+ +

很明顯的,可以使用CSS來設計新的上傳檔案的按鈕。

+ +

使用拖放選取檔案

+ +

使用者可以使用拖放來選取檔案,首先要設置放的區域,確定文件可以接收放的檔案,方法如下:

+ +
var dropbox;
+
+dropbox = document.getElementById("dropbox");
+dropbox.addEventListener("dragenter", dragenter, false);
+dropbox.addEventListener("dragover", dragover, false);
+dropbox.addEventListener("drop", drop, false);
+
+ +

在這個範例中,我們將 ID "dropbox" 設為放的區域,這是由於我們監聽了 dragenter dragover drop事件

+ +

我們甚至不需要處理 dragenter 和 dragover事件,所以這些函數很簡單。他們阻止了事件的傳播和預設事件的發生:

+ +
function dragenter(e) {
+  e.stopPropagation();
+  e.preventDefault();
+}
+
+function dragover(e) {
+  e.stopPropagation();
+  e.preventDefault();
+}
+
+ +

神奇的 drop() 函數:

+ +
function drop(e) {
+  e.stopPropagation();
+  e.preventDefault();
+
+  var dt = e.dataTransfer;
+  var files = dt.files;
+
+  handleFiles(files);
+}
+
+ +

這邊我們用 dataTransfer 來獲取檔案清單, 並傳遞給 handleFiles().。 我們可以發現,不論使用拖放或是其他取得檔案,處理檔案的方式都是相同。

+ +
+
+ +

範例:顯示選取的圖片

+ +

假設要開發一個分享照片的網站,想使用 HTML5 來讓使用者在上傳圖片前預覽縮圖。簡單來說就是像先前討論地一樣建立 input 元素或是 drop 區域,接著再呼叫類似 handleFiles() 的函數。

+ +
function handleFiles(files) {
+  for (var i = 0; i < files.length; i++) {
+    var file = files[i];
+    var imageType = /image.*/;
+
+    if (!file.type.match(imageType)) {
+      continue;
+    }
+
+    var img = document.createElement("img");
+    img.classList.add("obj");
+    img.file = file;
+    preview.appendChild(img);
+
+    var reader = new FileReader();
+    reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
+    reader.readAsDataURL(file);
+  }
+}
+
+ +

這邊迴圈處理了使用者選取的每個檔案並檢查每個檔案的類型是不是圖檔(藉由使用正規表達式檢查是否符合字串 "image.*")。每一個是圖片的檔案,我們創建一個 img 元素。CSS 被使用來美化外框、陰影、還有設定圖片的尺寸,所以那些並不需要在這邊寫入。

+ +

為了使圖片可以在DOM裡面更容易被找到,所以每個圖片都有設定CSS class “obj”。 我們也在每個圖檔標記 file 屬性以辨認 File;這使我們更容易取得真正要上傳的圖檔。最後我們使用{{ domxref("Node.appendChild()") }} 在文件中增加縮圖的元素。

+ +

FileReader 處理要非同步讀取的圖檔並跟 img 元素連接。在創建 FileReader 物件後,我們設置了 onload 並 呼叫 readAsDataURL() 在背景呼叫讀取的程序。當所有圖檔都被讀取時,他們被轉換為傳到 onload callback  data URL。 這個範例簡易的設置img 元素的 src 屬性來讀取圖檔並在螢幕上顯示。

+ +

使用 object URLs

+ +

Gecko 2.0 {{ geckoRelease("2.0") }} 支援 DOM 的{{ domxref("window.URL.createObjectURL()") }} 和 {{ domxref("window.URL.revokeObjectURL()") }} 方法。可以藉由這些方法創建表示任何為 DOM File 物件的 data URL 字串,包含了使用者電腦上的檔案。

+ +

可以使 File 物件作為 HTML 元素 URL 的參考,創建 object URL 的方法:

+ +
var objectURL = window.URL.createObjectURL(fileObj);
+
+ +

object URL 為表示 File 物件的字串。即使已經對相同檔案創建了 object URL,每次呼叫 {{ domxref("window.URL.createObjectURL()") }},就會創建一個 object URL。當文檔卸載時他們將會被自動釋放,如果要動態地使用,需要呼叫 {{ domxref("window.URL.revokeObjectURL()") }} 釋放:

+ +
window.URL.revokeObjectURL(objectURL);
+ +

範例:使用 object URLs 顯示圖片

+ +

{{ geckoRelease("2.0") }}這個範例使用 object URLs 顯示圖像縮圖。此外也顯示了其他包含檔案名稱和檔案大小的訊息。線上範例 (註:瀏覽器版本要求 11/22 之後的火狐版本)。

+ +
註: 這個 API 在較早的 Firefox 4 betas 存在但是 11/22 號後的版本有改變, 所以確定瀏覽器在最新的版本!
+ +

HTML:

+ +
<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
+<a href="#" id="fileSelect">Select some files</a>
+<div id="fileList">
+  <p>No files selected!</p>
+</div>
+
+ +

This establishes our file {{ HTMLElement("input") }} element, as well as a link that invokes the file picker, since we keep the file input hidden to prevent that less-than-attractive UI from being displayed. This is explained above in the section {{ anch("Using hidden file input elements using the click() method") }}, as is the doClick() method that invokes the file picker.

+ +

The handleFiles() method follows:

+ +
var fileSelect = document.getElementById("fileSelect"),
+  fileElem = document.getElementById("fileElem"),
+  fileList = document.getElementById("fileList");
+
+fileSelect.addEventListener("click", function (e) {
+  if (fileElem) {
+    fileElem.click();
+  }
+  e.preventDefault(); // prevent navigation to "#"
+}, false);
+
+function handleFiles(files) {
+  if (!files.length) {
+    fileList.innerHTML = "<p>No files selected!</p>";
+  }
+  else {
+    var list = document.createElement("ul");
+    for (var i = 0; i < files.length; i++) {
+      var li = document.createElement("li");
+      list.appendChild(li);
+
+      var img = document.createElement("img");
+      img.src = window.URL.createObjectURL(files[i]);
+      img.height = 60;
+      img.onload = function () {
+        window.URL.revokeObjectURL(this.src);
+      }
+      li.appendChild(img);
+
+      var info = document.createElement("span");
+      info.innerHTML = files[i].name + ": " + files[i].size + " bytes";
+      li.appendChild(info);
+    }
+    fileList.appendChild(list);
+  }
+}
+
+ +

This starts by fetching the URL of the {{ HTMLElement("div") }} with the ID "fileList". This is the block into which we'll insert out file list, including thumbmails.

+ +

If the {{ domxref("FileList") }} object passed to handleFiles() is null, we simply set the inner HTML of the block to display "No files selected!". Otherwise, we start building our file list, as follows:

+ +
    +
  1. A new unordered list ({{ HTMLElement("ul") }} element is created.
  2. +
  3. The new list element is inserted into the {{ HTMLElement("div") }} block by calling its {{ domxref("element.appendChild()") }} method.
  4. +
  5. For each {{ domxref("File") }} in the {{ domxref("FileList") }} represented by files: +
      +
    1. Create a new list item ({{ HTMLElement("li") }}) element and insert it into the list.
    2. +
    3. Create a new image ({{ HTMLElement("img") }}) element.
    4. +
    5. Set the image's source to a new object URL representing the file, using {{ domxref("window.URL.createObjectURL()") }} to create the blob URL.
    6. +
    7. Set the image's height to 60 pixels.
    8. +
    9. Set up the image's load event handler to release the object URL, since it's no longer needed once the image has been loaded. This is done by calling the {{ domxref("window.URL.revokeObjectURL()") }} method, passing in the object URL string as specified by img.src.
    10. +
    11. Append the new list item to the list.
    12. +
    +
  6. +
+ +

範例:上傳檔案

+ +

接下來這個範例顯示如何非同步的上傳檔案到伺服器。

+ +

新增上傳的工作

+ +

接續先前創建縮圖的範例,將每個縮圖都設置 CSS class “obj”,  這使得我們可以很容易地使用{{ domxref("Document.querySelectorAll()") }} 選擇使用者要上傳的圖檔,例如:

+ +
function sendFiles() {
+  var imgs = document.querySelectorAll(".obj");
+
+  for (var i = 0; i < imgs.length; i++) {
+    new FileUpload(imgs[i], imgs[i].file);
+  }
+}
+
+ +

第二行創建了 imgs 陣列,存放著所有文件中 CSS class 為 “obj” 的 Node。在這個範例中,我們使用這個來創建縮圖。Once we have that list, it's trivial to go through the list, creating a new FileUpload instance for each. Each of these handles uploading the corresponding file.

+ +

處理上傳檔案的程序

+ +

FileUpload 函數接受圖檔和檔案.

+ +
function FileUpload(img, file) {
+  var reader = new FileReader();
+  this.ctrl = createThrobber(img);
+  var xhr = new XMLHttpRequest();
+  this.xhr = xhr;
+
+  var self = this;
+  this.xhr.upload.addEventListener("progress", function(e) {
+        if (e.lengthComputable) {
+          var percentage = Math.round((e.loaded * 100) / e.total);
+          self.ctrl.update(percentage);
+        }
+      }, false);
+
+  xhr.upload.addEventListener("load", function(e){
+          self.ctrl.update(100);
+          var canvas = self.ctrl.ctx.canvas;
+          canvas.parentNode.removeChild(canvas);
+      }, false);
+  xhr.open("POST", "http://demos.hacks.mozilla.org/paul/demos/resources/webservices/devnull.php");
+  xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
+  reader.onload = function(evt) {
+    xhr.sendAsBinary(evt.target.result);
+  };
+  reader.readAsBinaryString(file);
+}
+
+ +

FileUpload() 函數創建被用來顯示上傳進度的 throbber,接著創建 {{domxref("XMLHttpRequest")}} 上傳檔案.

+ +

傳輸資料前的幾個準備工作:

+ +
    +
  1. The XMLHttpRequest's upload "progress" listener is set to update the throbber with new percentage information, so that as the upload progresses, the throbber will be updated based on the latest information.
  2. +
  3. The XMLHttpRequest's upload "load" event handler is set to update the throbber with 100% as the progress information (to ensure the progress indicator actually reaches 100%, in case of granularity quirks during the process). It then removes the throbber, since it's no longer needed. This causes the throbber to disappear once the upload is complete.
  4. +
  5. The request to upload the image file is opened by calling XMLHttpRequest's open() method to start generating a POST request.
  6. +
  7. The MIME type for the upload is set by calling the XMLHttpRequest function overrideMimeType(). In this case, we're using a generic MIME type; you may or may not need to set the MIME type at all, depending on your use case.
  8. +
  9. The FileReader object is used to convert the file to a binary string.
  10. +
  11. Finally, when the content is loaded the XMLHttpRequest function sendAsBinary() is called to upload the file's content.
  12. +
+ +
+

註: 範例中非標準的 sendAsBinary 方法已經在 Gecko 31 {{ geckoRelease(31) }} 廢棄且很快將會被移除。可以改使用標準的 send(Blob data)。

+
+ +

非同步處理上傳檔案的程序

+ +
function fileUpload(file) {
+  // Please report improvements to: marco.buratto at tiscali.it
+
+  var fileName = file.name,
+    fileSize = file.size,
+    fileData = file.getAsBinary(), // works on TEXT data ONLY.
+    boundary = "xxxxxxxxx",
+    uri = "serverLogic.php",
+    xhr = new XMLHttpRequest();
+
+  xhr.open("POST", uri, true);
+  xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary); // simulate a file MIME POST request.
+  xhr.setRequestHeader("Content-Length", fileSize);
+
+  xhr.onreadystatechange = function() {
+    if (xhr.readyState == 4) {
+      if ((xhr.status >= 200 && xhr.status <= 200) || xhr.status == 304) {
+
+        if (xhr.responseText != "") {
+          alert(xhr.responseText); // display response.
+        }
+      }
+    }
+  }
+
+  var body = "--" + boundary + "\r\n";
+  body += "Content-Disposition: form-data; name='fileId'; filename='" + fileName + "'\r\n";
+  body += "Content-Type: application/octet-stream\r\n\r\n";
+  body += fileData + "\r\n";
+  body += "--" + boundary + "--";
+
+  xhr.send(body);
+  return true;
+}
+
+ +

使用二進制數據時,這些程式碼還需要修改。

+ +

你也可以參考這些文章

+ + + +

{{ HTML5ArticleTOC() }}

diff --git a/files/zh-tw/web/api/file_handle_api/index.html b/files/zh-tw/web/api/file_handle_api/index.html new file mode 100644 index 0000000000..bd603fe78a --- /dev/null +++ b/files/zh-tw/web/api/file_handle_api/index.html @@ -0,0 +1,233 @@ +--- +title: FileHandle API +slug: Web/API/File_Handle_API +translation_of: Web/API/File_Handle_API +--- +

FileHandle API 可操作檔案,例如建立檔案、修改檔案內容 (不同於 File API)。而正在編輯中的部分,將使用回合制的鎖定機制,以避免發生競態 (Race) 問題。

+

API

+

建立 FileHandle

+

若要建立 FileHandle 物件,則需要 IndexedDB Database

+
+
var idbreq = indexedDB.open("MyTestDatabase");
+
+idbreq.onsuccess = function(){
+  var db = idbreq.result;
+  var handleReq = db.mozCreateFileHandle("test.bin", "binary");
+
+  handleReq.onsuccess = function(){
+    var handle = handleReq.result;
+    console.log('handle', handle);
+  };
+};
+
+
+

mozCreateFileHandle() 共使用 2 組參數 (Argument):1 組名稱與 1 組檔案類別 (Optional type)。但這 2 組數均只屬於敘述性數,不會用於資料庫。舉例來說,名稱可能是空白字串,而且不需為專屬字串。所以 API 根本不會注意這些參數值。

+

另請注意,上列程式碼僅會建立「暫時性檔案」,亦即當你保留 FileHandle 物件時,該檔案才會存在。如果你要在重新整理頁面/重新啟動 App 之後,仍能保留檔案,則必須將 Handle 儲存於更永久性的位置 (如資料庫本身之內) 中。

+
var transaction = db.transaction(["test"], "readwrite");
+var objectStore = transaction.objectStore("test");
+objectStore.add(myFile, myKey).onsuccess = function(event) {
+  // The file is now referenced from database too.
+}
+
+

FileHandle 介面

+
interface FileHandle
+{
+  LockedFile open(optional DOMString mode);
+  DOMRequest getFile()
+  readonly attribute DOMString name;
+  readonly attribute DOMString type;
+  attribute Function? onabort;
+  attribute Function? onerror;
+};
+
+
+ open([mode="readonly"])
+
+ 可回傳 LockedFilemode 可為「readonly」或「readwrite」。
+
+ getFile()
+
+ 針對檔案而回傳 DOMRequest。若成功,就會收到以 File 物件形式呈現的唯讀「snapshot」檔案內容 (可用於任何接受 Blob 的地方,如 FileReaderXMLHttpRequest 等)。 +
myFile.getFile().onsuccess = function(event) {
+  var file = event.target.result;
+  var transcation = myDatabase.transaction(["snapshots"], "readwrite");
+  var objectStore = transaction.objectStore("snapshots");
+  objectStore.add(file, snapshotKey).onsuccess = function(event) {
+    // A new readonly copy of the file has been created.
+  }
+}
+
+
+
+ name
+
+ 檔案名稱。
+
+ type
+
+ 代表 content-type。
+
+ abort event
+
+ 放棄已鎖定的檔案,就會發生此事件。
+
+ error event
+
+ 任何內部錯誤,都會發生此事件。
+
+

LockedFile 介面

+
interface LockedFile
+{
+  readonly attribute FileHandle fileHandle;
+  readonly attribute DOMString mode;
+  readonly attribute boolean active;
+  attribute any? location;
+  FileRequest getMetadata(optional FileMetadataParameters parameters);
+  FileRequest readAsArrayBuffer(unsigned long long size);
+  FileRequest readAsText(unsigned long long size, optional DOMString encoding);
+  FileRequest write(DOMString or ArrayBuffer or Blob value);
+  FileRequest append(DOMString or ArrayBuffer or Blob value);
+  FileRequest truncate(optional unsigned long long size);
+  FileRequest flush();
+  void abort();
+  attribute Function? oncomplete;
+  attribute Function? onabort;
+  attribute Function? onerror;
+};
+
+
+ fileHandle
+
+ 來自於解鎖的 FileHandle 物件。
+
+ mode
+
+ 「readonly」或「readwrite」。
+
+ active
+
+ 一旦建立之後,就隨即啟動 LockedFile。此 LockedFile 是「可寫入存取 (Write access) 實際底層檔案」的唯一物件。LockedFile 上的作業,均於 isolation 之中執行;也就是說,只要啟動了 LockedFile,則此 LockedFile 的所有作業都一定會在底層檔案上依序執行,而不會與其他 LockedFiles 的作業交錯執行。
+
+ 若停用了 LockedFile,則只要在同樣的 LockedFile 上執行讀/寫作業,都會丟出錯誤訊息。
+
+
+
+ location
+
+ 檔案中的位置 (Offset)。每次讀/寫作業之後,此數值均將自動變更。讀寫作業均從該 location 開始,而 null 代表檔案末端。
+
+ getMetadata(parameters)
+
+ 針對後設資料 (Metadata) 而回傳 FileRequest。此數亦屬於物件,其中將參數名稱作為物件鍵值,布林值作為數值,進而非同步檢索既有的屬性。無數值則代表 true。目前僅有 sizelastModified 為可能的參數。
+
+ readAsArrayBuffer(size)
+
+ 針對既有 size ArrayBuffer,回傳 FileRequest。此作業均從 location 開始,另根據讀取位元組的數目,移動 location
+
+ readAsText(size [, encoding])
+
+ 針對既有 size 的字串,以既定的 encoding 回傳 FileRequest。此作業均從 location 開始,另根據讀取位元組的數目,移動 locationFileReader API 中的對等函式,也以相同方式運作。 +
var lockedFile = myFile.open();
+var request = lockedFile.readAsText(3);
+request.onsuccess = function(event) {
+  var text = request.result;
+  // 3 characters have been read.
+}
+
+
+
+ write(value)
+
+ 針對成功/失敗的寫入作業,回傳 FileRequest。寫入作業將從 location 開始,另根據寫入位元組的數目,移動位置。 +
var lockedFile = myFile.open("readwrite");
+var request = lockedFile.write("foo");
+request.onsuccess = function(event) {
+  // The string "foo" has been written.
+}
+
+
+
+ append(value)
+
+ 針對成功/失敗的附加 (Append) 作業,回傳 FileRequest。不論 location 為何,該數值均附加於檔案末端。在附加資料完畢後,location 隨即設定為 null
+
+ truncate([size])
+
+ 針對成功/失敗的截斷 (Truncate) 作業,回傳 FileRequest。
+
+ 如果是以單一數呼叫該函式,則截斷成功之後,則不論 location 為何,檔案將剩下第一個 size 的位元組。
+
+ 若沒有用任何數呼叫該函式,則檔案將剩下 location 的第一個位元組。
+
+ flush()
+
+ 強制移轉緩衝過的資料至磁碟上,作業成功之後將回傳 FileRequest。此時即便 App 當機或非刻意中止,都能確保資料已經位於磁碟上了。
+
+ abort()
+
+ 停用 LockedFile 並取消全部尚未執行的作業。
+
+ complete, abort, error events
+
+

FileRequest 介面

+

此類型的物件,均是由 LockedFile 介面的所有非同步作業所回傳。此介面繼承了 DOMRequest 並類似 IDBRequest,同時還擁有 onprogress 事件。在成功之後,則可透過 result 屬性而取得必要檔案作業的結果。

+
interface FileRequest : DOMRequest
+{
+  readonly attribute LockedFile lockedFile;
+  attribute Function? onprogress;
+};
+
+
+  
+
+

說明

+

API 與 FileWriter 的差異?

+

FileWriter 規格定義了 FileWriter,也就是用以呈現「可編輯的檔案」的物件。Public-webapps 討論串則下了結論:若單一檔案同時寫入不同的實體 (Entity),將導致 API 成效不彰。最後就是 FileHandle API 應具備自己的 LockedFile 與交易機制。

+

瀏覽器相容性

+
+ {{CompatibilityTable}}
+
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatNo}}15{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatNo}}15{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+

 

diff --git a/files/zh-tw/web/api/filelist/index.html b/files/zh-tw/web/api/filelist/index.html new file mode 100644 index 0000000000..56c2f02235 --- /dev/null +++ b/files/zh-tw/web/api/filelist/index.html @@ -0,0 +1,149 @@ +--- +title: FileList +slug: Web/API/FileList +translation_of: Web/API/FileList +--- +
{{APIRef("File API")}}{{gecko_minversion_header("1.9")}}
+ +

FileList 型別物件通常來自 HTML {{HTMLElement("input")}} 元素 {{domxref("Document_Object_Model", "DOM")}} 物件的 files 屬性({{Glossary("property/JavaScript", "property")}})。你可以操作 FileList 物件來存取使用者透過 <input type="file"> 元素所選取的檔案,或由拖放操作所產生的檔案(請參考 {{domxref("DataTransfer")}} 物件的更多使用細節)。

+ +
+

註:在 {{Gecko("1.9.2")}} 之前,{{HTMLElement("input")}} 元素只支援一次選取一個檔案,這代表了 FileList 只能夠包含一個 File 物件。從 {{Gecko("1.9.2")}} 開始,假如 <input> 元素的 multiple 屬性(attribute)為 true,則 FileList 就可能會包含多個檔案。

+
+ +

使用 FileList

+ +

所有 <input> 元素節點的 {{domxref("Document_Object_Model", "DOM")}} 物件都擁有 files 屬性({{Glossary("property/JavaScript", "property")}}),此屬性即為 FileList,是一個可藉此存取使用者選取之檔案的類陣列物件。以下範例展示了一個 type 屬性({{Glossary("attribute")}})值為 file 的 HTML <input> 元素:

+ +
<input id="fileItem" type="file">
+
+ +

下面範例演示了如何取得 <input> 元素節點中所包含的第一個 {{domxref("File")}} 型別物件:

+ +
var file = document.getElementById('fileItem').files[0];
+
+ +

方法概觀

+ + + + + + + +
File item(index);
+ +

屬性

+ + + + + + + + + + + + + + +
屬性名稱型別描述
lengthinteger表示 FileList 物件中的檔案數量,唯讀。
+ +

方法

+ +

item()

+ +

回傳 FileList 中指定索引的 {{domxref("File")}} 物件。

+ +
File item(
+  index
+);
+
+ +
參數
+ +
+
index
+
要取得的檔案之索引(起始於零)。
+
+ +
回傳值
+ +

要求的 {{domxref("File")}} 物件。

+ +

範例

+ +

此範例演示了迭代所有之使用者於 <input> 元素選取的檔案:

+ +
// fileInput is an HTML input element: <input type="file" id="myfileinput" multiple>
+var fileInput = document.getElementById("myfileinput");
+
+// files is a FileList object (similar to NodeList)
+var files = fileInput.files;
+var file;
+
+// loop through files
+for (var i = 0; i < files.length; i++) {
+
+    // get item
+    file = files.item(i);
+    //or
+    file = files[i];
+
+    alert(file.name);
+}
+
+ +

以下是更完整的範例:

+ +
<!DOCTYPE HTML>
+<html>
+<head>
+</head>
+<body>
+<!--multiple is set to allow multiple files to be selected-->
+
+<input id="myfiles" multiple type="file">
+
+</body>
+
+<script>
+
+var pullfiles=function(){
+    // love the query selector
+    var fileInput = document.querySelector("#myfiles");
+    var files = fileInput.files;
+    // cache files.length
+    var fl = files.length;
+    var i = 0;
+
+    while ( i < fl) {
+        // localize file var in the loop
+        var file = files[i];
+        alert(file.name);
+        i++;
+    }
+}
+
+// set the input element onchange to call pullfiles
+document.querySelector("#myfiles").onchange=pullfiles;
+
+//a.t
+</script>
+
+</html>
+ +

規範

+ + + +

參見

+ + diff --git a/files/zh-tw/web/api/filereader/error/index.html b/files/zh-tw/web/api/filereader/error/index.html new file mode 100644 index 0000000000..572509db9e --- /dev/null +++ b/files/zh-tw/web/api/filereader/error/index.html @@ -0,0 +1,102 @@ +--- +title: FileReader.error +slug: Web/API/FileReader/error +translation_of: Web/API/FileReader/error +--- +
{{APIRef("File API")}}
+ +

總覽

+ +

回傳讀取檔案時發生的錯誤。

+ +

語法

+ +
var error = instanceOfFileReader.error
+
+ +

Value

+ +

A {{domxref("DOMError")}}

+ +

規格

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("File API", "#FileReader-interface", "FileReader")}}{{Spec2("File API")}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox (Gecko)ChromeEdgeInternet ExplorerOperaSafari
Basic support{{CompatGeckoDesktop("1.9.2")}}[1]7{{CompatVersionUnknown}}10[2]12.02[3]6.0.2
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox Mobile (Gecko)AndroidEdgeIE MobileOpera MobileSafari Mobile
Basic support323{{CompatVersionUnknown}}1011.56.1
+
+ +

[1] Prior to Gecko 2.0 beta 7 (Firefox 4.0 beta 7), all {{domxref("Blob")}} parameters below were {{domxref("File")}} parameters; this has since been updated to match the specification correctly. Prior to Gecko 13.0 {{geckoRelease("13.0")}} the FileReader.error property returned a {{domxref("FileError")}} object. This interface has been removed and FileReader.error is now returning the {{domxref("DOMError")}} object as defined in the latest FileAPI draft.

+ +

[2] IE9 has a File API Lab.

+ +

[3] Opera has partial support in 11.1.

+ +

閱讀更多

+ + diff --git a/files/zh-tw/web/api/filereader/index.html b/files/zh-tw/web/api/filereader/index.html new file mode 100644 index 0000000000..4b80e334a4 --- /dev/null +++ b/files/zh-tw/web/api/filereader/index.html @@ -0,0 +1,213 @@ +--- +title: FileReader +slug: Web/API/FileReader +tags: + - API + - File API + - Files + - Interface + - Reference +translation_of: Web/API/FileReader +--- +
{{APIRef("File API")}}
+ +

藉由 FileReader 物件,Web 應用程式能以非同步(asynchronously)方式讀取儲存在用戶端的檔案(或原始資料暫存)內容,可以使用 {{domxref("File")}} 或 {{domxref("Blob")}} 物件指定要讀取的資料。

+ +

File 物件可以從使用者於 {{HTMLElement("input")}} 元素選擇之檔案所回傳的 {{domxref("FileList")}} 物件當中取得,或是來自拖放操作所產生的 {{domxref("DataTransfer")}} 物件之中,也能由 {{domxref("HTMLCanvasElement")}} 物件(元素物件)執行 mozGetAsFile() 方法後回傳。

+ +

{{AvailableInWorkers}}

+ +

建構式

+ +
+
{{domxref("FileReader.FileReader", "FileReader()")}}
+
建立新的 FileReader 物件。
+
+ +

請參考在網頁應用程式中使用本地檔案的更多細節與範例。

+ +

屬性

+ +
+
{{domxref("FileReader.error")}} {{readonlyinline}}
+
此 {{domxref("DOMException")}} 類型的物件記錄了讀取資料時發生的錯誤資訊。
+
{{domxref("FileReader.readyState")}} {{readonlyinline}}
+
表示目前 FileReader 狀態的數字,其代表的意義為: + + + + + + + + + + + + + + + + + + +
EMPTY0尚未讀入任何資料。
LOADING1正在讀入資料。
DONE2完成資料讀取。
+
+
{{domxref("FileReader.result")}} {{readonlyinline}}
+
讀入的資料內容。只有在讀取完成之後此屬性才有效,而資料的格式則取決於是由哪一個方法進行讀取。
+
+ +

事件處理器

+ +
+
{{domxref("FileReader.onabort")}}
+
{{event("abort")}} 事件處理器,於讀取被中斷時觸發。
+
{{domxref("FileReader.onerror")}}
+
{{event("error")}} 事件處理器,於讀取發生錯誤時觸發。
+
{{domxref("FileReader.onload")}}
+
{{event("load")}} 事件處理器,於讀取完成時觸發。
+
{{domxref("FileReader.onloadstart")}}
+
{{event("loadstart")}} 事件處理器,於讀取開始時觸發。
+
{{domxref("FileReader.onloadend")}}
+
{{event("loadend")}} 事件處理器,於每一次讀取結束之後觸發(不論成功或失敗),會於 onloadonerror 事件處理器之後才執行。
+
{{domxref("FileReader.onprogress")}}
+
{{event("progress")}} 事件處理器,於讀取 {{domxref("Blob")}} 內容時觸發。
+
+ +
+

FileReader 物件繼承自 {{domxref("EventTarget")}},其所有的事件也都能夠透過 {{domxref("EventTarget.addEventListener()","addEventListener")}} 方法來註冊事件監聽器。

+
+ +

方法

+ +
+
{{domxref("FileReader.abort()")}}
+
中斷目前的讀取,此方法回傳後屬性 readyState 將會是 DONE
+
{{domxref("FileReader.readAsArrayBuffer()")}} {{gecko_minversion_inline("7.0")}}
+
開始讀取指定的 {{domxref("Blob")}},讀取完成後屬性 result 將以 {{domxref("ArrayBuffer")}} 物件來表示讀入的資料內容。
+
{{domxref("FileReader.readAsBinaryString()")}} {{non-standard_inline}}
+
開始讀取指定的 {{domxref("Blob")}},讀取完成後屬性 result 將以字串型式來表示讀入的原始二進位資料(raw binary data)。
+
{{domxref("FileReader.readAsDataURL()")}}
+
開始讀取指定的 {{domxref("Blob")}},讀取完成後屬性 result 將以 data: URL 格式(base64 編碼)的字串來表示讀入的資料內容。
+
{{domxref("FileReader.readAsText()")}}
+
開始讀取指定的 {{domxref("Blob")}},讀取完成後屬性 result 將以文字字串型式來表示讀入的資料內容。
+
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態註解
{{SpecName("File API", "#dfn-filereader", "FileReader")}}{{Spec2("File API")}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能Firefox (Gecko)ChromeEdgeInternet ExplorerOperaSafari
基本支援{{CompatGeckoDesktop("1.9.2")}}[1]7{{CompatVersionUnknown}}10[2]12.02[2]6.0
在 Web Workers 的支援{{CompatGeckoDesktop(46)}}{{CompatVersionUnknown()}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatVersionUnknown()}}{{CompatNo}}
error property uses {{domxref("DOMException")}}, not {{domxref("DOMError")}}{{CompatGeckoDesktop(58)}}{{CompatVersionUnknown()}}{{CompatVersionUnknown()}}{{CompatNo}}{{CompatVersionUnknown()}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能Firefox Mobile (Gecko)AndroidEdgeIE MobileOpera MobileSafari Mobile
基本支援323{{CompatVersionUnknown}}1011.56.1
在 Web Workers 的支援{{CompatGeckoMobile(46)}}{{CompatVersionUnknown()}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatVersionUnknown()}}{{CompatNo}}
error property uses {{domxref("DOMException")}}, not {{domxref("DOMError")}}{{CompatGeckoMobile(58)}}{{CompatUnknown()}}{{CompatVersionUnknown()}}{{CompatNo}}{{CompatVersionUnknown()}}{{CompatNo}}
+
+ +

[1] 在 Gecko 2.0 beta 7 (Firefox 4.0 beta 7) 以前,所有的 {{domxref("Blob")}} 參數都屬於 {{domxref("File")}} 參數;之後為了更符合規範,所以更新了這個特徵。在 Gecko 13.0 {{geckoRelease("13.0")}} 以前,FileReader.error 屬性回傳了 {{domxref("FileError")}} 物件。這個介面之後被移除、而 FileReader.error 目前會回傳 {{domxref("DOMError")}} 並定義為 FileAPI draft。

+ +

[2] Opera 在 11.1 有限度支援

+ +

參見

+ + diff --git a/files/zh-tw/web/api/filereader/readystate/index.html b/files/zh-tw/web/api/filereader/readystate/index.html new file mode 100644 index 0000000000..f6ff1fa5f6 --- /dev/null +++ b/files/zh-tw/web/api/filereader/readystate/index.html @@ -0,0 +1,98 @@ +--- +title: FileReader.readyState +slug: Web/API/FileReader/readyState +translation_of: Web/API/FileReader/readyState +--- +
{{APIRef("File API")}}
+ +

提供目前讀取狀態

+ +

語法

+ +
var state = instanceOfFileReader.readyState
+
+ +

數值

+ +

數字代表 {{domxref("FileReader")}} API 三個可能的狀態:

+ +

{{page("/en-US/docs/Web/API/FileReader","State constants")}}

+ +

規格

+ + + + + + + + + + + + + + +
規格狀態說明
{{SpecName("File API", "#FileReader-interface", "FileReader")}}{{Spec2("File API")}}初始化定義
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
功能Firefox (Gecko)ChromeInternet ExplorerOperaSafari
基本支援{{CompatGeckoDesktop("1.9.2")}}[1]710[2]12.02[3]6.0.2
+
+ +
+ + + + + + + + + + + + + + + + + + + +
功能Firefox 手機版 (Gecko)AndroidIE 手機版Opera 手機版Safari 手機版
基本支援3231011.56.1
+
+ +

[1] Prior to Gecko 2.0 beta 7 (Firefox 4.0 beta 7), all {{domxref("Blob")}} parameters below were {{domxref("File")}} parameters; this has since been updated to match the specification correctly. Prior to Gecko 13.0 {{geckoRelease("13.0")}} the FileReader.error property returned a {{domxref("FileError")}} object. This interface has been removed and FileReader.error is now returning the {{domxref("DOMError")}} object as defined in the latest FileAPI draft.

+ +

[2] IE9 has a File API Lab.

+ +

[3] Opera has partial support in 11.1.

+ +

閱讀更多

+ + diff --git a/files/zh-tw/web/api/filesystem/index.html b/files/zh-tw/web/api/filesystem/index.html new file mode 100644 index 0000000000..49b4f70b84 --- /dev/null +++ b/files/zh-tw/web/api/filesystem/index.html @@ -0,0 +1,118 @@ +--- +title: FileSystem +slug: Web/API/FileSystem +tags: + - 檔案系統 +translation_of: Web/API/FileSystem +--- +

{{APIRef("File System API")}} {{non-standard_header}}

+ +

FileSystem 實作文件和目錄介面,描述一個檔案系統。在任何檔案系統上,這個物件包含 {{domxref("FileSystemEntry.filesystem", "filesystem")}}的特性。某些網頁瀏覽器提供額外的API去創建和管理檔案系統,如Google Chrome的{{domxref("LocalFileSystem.requestFileSystem", "requestFileSystem()")}}函式。

+ +
+

此介面並非標準API, 代表規格並未依造標準制定, 因此必須注意並非所有網頁瀏覽器都有實作此介面, 有實作的網頁瀏覽器可能只有實作一小部分. 請在{{anch("Browser compatibility")}} 查看更多細節.

+
+ +

基礎概念

+ +

存取 FileSystem 物件的兩種方法:

+ +
    +
  1. 你可以直接要求一個使用window.requestFileSystem(),只用在你的網頁應用程式的沙盒類型 FileSystem 物件。如果要求成功,將會執行callback handler去接收描述檔案系統的FileSystem物件參數。
  2. +
  3. 你可以從檔案系統接口物件取得,透過他的{{domxref("FileSystemEntry.filesystem", "filesystem")}}特性
  4. +
+ +

屬性

+ +
+
{{domxref("FileSystem.name")}} {{ReadOnlyInline}}
+
{{domxref("USVString")}} 代表檔案系統的名稱. 此名稱在整個已宣告的檔案系統清單中是唯一的。
+
{{domxref("FileSystem.root")}} {{ReadOnlyInline}}
+
 {{domxref("FileSystemDirectoryEntry")}} 物件表示檔案系統的根目錄。 透過此物件, 你可以取得權限存取所有檔案系統中的文件和目錄
+
+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('File System API')}}{{Spec2('File System API')}}Draft of proposed API
+ +

This API has no official W3C or WHATWG specification.

+ +

瀏覽器相容性

+ +

{{ CompatibilityTable }}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerMicrosoft EdgeOperaSafari (WebKit)
Basic support13{{ property_prefix("webkit") }}{{ CompatGeckoDesktop(50) }}{{ CompatNo }}{{CompatVersionUnknown}}[1]{{ CompatNo }}{{ CompatNo }}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{ CompatNo }}0.16{{ property_prefix("webkit") }}{{ CompatGeckoMobile(50) }}{{ CompatNo }}{{ CompatNo }}{{ CompatNo }}
+
+ +

[1] Microsoft Edge 使用 WebKitFileSystem 名稱實作, 且只被用在 drag-and-drop scenarios 透過 {{domxref("DataTransferItem.webkitGetAsEntry()")}} 函式. 此函式不被使用在文件和目錄選擇的面板( 如當你以{{domxref("HTMLInputElement.webkitdirectory")}} 標籤使用 {{HTMLElement("input")}} 物件

+ +

參見

+ + diff --git a/files/zh-tw/web/api/formdata/get/index.html b/files/zh-tw/web/api/formdata/get/index.html new file mode 100644 index 0000000000..b234ecb551 --- /dev/null +++ b/files/zh-tw/web/api/formdata/get/index.html @@ -0,0 +1,145 @@ +--- +title: FormData.get() +slug: Web/API/FormData/get +translation_of: Web/API/FormData/get +--- +

{{APIRef("XMLHttpRequest")}}

+ +

{{domxref("FormData")}} 的  get() 方法會返回 FormData 物件中,指定 key 值所對應之第一組物件中的 value 值 。然而,如果您想要獲得多組以及全部的 value ,那應該使用 {{domxref("FormData.getAll()","getAll()")}} 方法。

+ +

注意:  這個方法已可以在 Web Workers 中使用。

+ +

語法

+ +
formData.get(name);
+ +

參數

+ +
+
name
+
一個 {{domxref("USVString")}} ,代表您想要得到的 value 所對應的 key 值名稱。
+
+ +

回傳值

+ +

A {{domxref("FormDataEntryValue")}} containing the value.

+ +

範例

+ +

下面一行程式會產生一個空的 FormData 物件:

+ +
var formData = new FormData();
+ +

用 {{domxref("FormData.append")}} 方法新增兩組 username 值

+ +
formData.append('username', 'Chris');
+formData.append('username', 'Bob');
+ +

接下來使用 get() 方法,將只會返回上一步驟,第一組新增的 username 所對應的值

+ +
formData.get('username'); // Returns "Chris"
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('XMLHttpRequest','#dom-formdata-get','get()')}}{{Spec2('XMLHttpRequest')}} 
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatChrome(50.0)}}{{CompatGeckoDesktop('39.0')}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}
Available in web workers{{CompatChrome(50.0)}}{{CompatGeckoDesktop('39.0')}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewFirefox Mobile (Gecko)Firefox OS (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatNo}}{{CompatChrome(50.0)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatNo}} +

{{CompatVersionUnknown}}

+
{{CompatNo}}{{CompatChrome(50.0)}}
Available in web workers{{CompatNo}}{{CompatChrome(50.0)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatChrome(50.0)}}
+
+ +

 

+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/api/formdata/index.html b/files/zh-tw/web/api/formdata/index.html new file mode 100644 index 0000000000..4151641a6e --- /dev/null +++ b/files/zh-tw/web/api/formdata/index.html @@ -0,0 +1,218 @@ +--- +title: FormData +slug: Web/API/FormData +translation_of: Web/API/FormData +--- +

{{APIRef("XMLHttpRequest")}}

+ +

FormData 介面可為表單資料中的欄位/值建立相對應的的鍵/值對(key/value)集合,之後便可使用 {{domxref("XMLHttpRequest.send()")}} 方法來送出資料。它在編碼類型設定為 multipart/form-data 時會採用與表單相同的格式送出。

+ +

實作 FormData 的物件可以直接利用 {{jsxref("Statements/for...of", "for...of")}} 語法結構來替代 {{domxref('FormData.entries()', 'entries()')}}:for (var p of myFormData) 等同於 for (var p of myFormData.entries())

+ +
+

備註:此特性適用於 Web Workers

+
+ +

建構式

+ +
+
{{domxref("FormData.FormData","FormData()")}}
+
建立一個新的 FormData 物件。
+
+ +

方法

+ +
+
{{domxref("FormData.append()")}}
+
追加新值到 FormData 物件已有的對應鍵上;若該鍵不存在,則為其追加新的鍵。
+
{{domxref("FormData.delete()")}}
+
刪除指定的鍵值對。
+
{{domxref("FormData.entries()")}}
+
回傳 {{jsxref("Iteration_protocols","iterator")}},可用來處理物件中所有的鍵值對。
+
{{domxref("FormData.get()")}}
+
回傳指定的鍵在 FormData 物件中找到的第一個對應值。
+
{{domxref("FormData.getAll()")}}
+
回傳指定的鍵在 FormData 物件中所有對應值的陣列。
+
{{domxref("FormData.has()")}}
+
回傳 FormData 物件是否含有指定鍵值對的布林值。
+
{{domxref("FormData.keys()")}}
+
回傳 {{jsxref("Iteration_protocols", "iterator")}},可用來處理物件中所有鍵值對之中的鍵。
+
{{domxref("FormData.set()")}}
+
為 FormData 物件已有的鍵設定新值;若該鍵不存在,則為其追加新的鍵。
+
{{domxref("FormData.values()")}}
+
回傳 {{jsxref("Iteration_protocols", "iterator")}},可用來處理物件中所有鍵值對之中的值。
+
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('XMLHttpRequest','#interface-formdata','FormData')}}{{Spec2('XMLHttpRequest')}}FormData defined in XHR spec
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatChrome(7.0)}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("2.0")}}[1]10125
append with filename{{CompatVersionUnknown}}{{CompatNo}}{{CompatGeckoDesktop("22.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
delete(), get(), getAll(), has(), set(){{CompatChrome(50.0)}}{{CompatNo}}{{CompatGeckoDesktop("39.0")}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}
entries(), keys(), values(), and support of for...of{{CompatChrome(50.0)}}{{CompatNo}}{{CompatGeckoDesktop("44.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatNo}}
Available in web workers{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("39.0")}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewEdgeFirefox Mobile (Gecko)Firefox OS (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
Basic support3.0[2]{{CompatVersionUnknown}}[2]{{CompatVersionUnknown}}{{CompatGeckoMobile("2.0")}}[1]1.0.1{{CompatUnknown}}12{{CompatUnknown}}{{CompatVersionUnknown}}
append with filename{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatGeckoMobile("22.0")}}1.2{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
delete(), get(), getAll(), has(), set(){{CompatVersionUnknown}}{{CompatChrome(50.0)}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatChrome(50.0)}}
entries(), keys(), values(), and support of for...of{{CompatUnknown}}{{CompatChrome(50.0)}}{{CompatNo}}{{CompatGeckoMobile("44.0")}}2.5{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatChrome(50.0)}}
Available in web workers{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatVersionUnknown}}
+
+ +

[1] 在 Gecko 7.0 {{geckoRelease("7.0")}} 之前,若把 {{domxref("Blob")}} 設定為物件中的值,則 HTTP 標頭中 "Content-Disposition" 的檔案名稱會是空字串,此行為會被某些伺服器視為錯誤。Gecko 7.0 之後則會將檔名設為 "blob" 送出。

+ +

[2] XHR in Android 4.0 sends empty content for FormData with blob.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/formdata/using_formdata_objects/index.html b/files/zh-tw/web/api/formdata/using_formdata_objects/index.html new file mode 100644 index 0000000000..e01b15eb90 --- /dev/null +++ b/files/zh-tw/web/api/formdata/using_formdata_objects/index.html @@ -0,0 +1,137 @@ +--- +title: Using FormData Objects +slug: Web/API/FormData/Using_FormData_Objects +translation_of: Web/API/FormData/Using_FormData_Objects +--- +

The FormData object lets you compile a set of key/value pairs to send using XMLHttpRequest. It is primarily intended for use in sending form data, but can be used independently from forms in order to transmit keyed data. The transmitted data is in the same format that the form's {{domxref("HTMLFormElement.submit","submit()")}} method would use to send the data if the form's encoding type were set to multipart/form-data.

+ +

Creating a FormData object from scratch

+ +

You can build a FormData object yourself, instantiating it then appending fields to it by calling its {{domxref("FormData.append","append()")}} method, like this:

+ +
var formData = new FormData();
+
+formData.append("username", "Groucho");
+formData.append("accountnum", 123456); // number 123456 is immediately converted to a string "123456"
+
+// HTML file input, chosen by user
+formData.append("userfile", fileInputElement.files[0]);
+
+// JavaScript file-like object
+var content = '<a id="a"><b id="b">hey!</b></a>'; // the body of the new file...
+var blob = new Blob([content], { type: "text/xml"});
+
+formData.append("webmasterfile", blob);
+
+var request = new XMLHttpRequest();
+request.open("POST", "http://foo.com/submitform.php");
+request.send(formData);
+
+ +
Note: The fields "userfile" and "webmasterfile" both contain a file. The number assigned to the field "accountnum" is immediately converted into a string by the FormData.append() method (the field's value can be a {{ domxref("Blob") }}, {{ domxref("File") }}, or a string: if the value is neither a Blob nor a File, the value is converted to a string).
+ +

This example builds a FormData instance containing values for fields named "username", "accountnum", "userfile" and "webmasterfile", then uses the XMLHttpRequest method send() to send the form's data. The field "webmasterfile" is a {{domxref("Blob")}}. A Blob object represents a file-like object of immutable, raw data. Blobs represent data that isn't necessarily in a JavaScript-native format. The {{ domxref("File") }} interface is based on Blob, inheriting blob functionality and expanding it to support files on the user's system. In order to build a Blob you can invoke the {{domxref("Blob.Blob","Blob() constructor")}}.

+ +

Retrieving a FormData object from an HTML form

+ +

To construct a FormData object that contains the data from an existing {{ HTMLElement("form") }}, specify that form element when creating the FormData object:

+ +
var formData = new FormData(someFormElement);
+
+ +

For example:

+ +
var formElement = document.querySelector("form");
+var request = new XMLHttpRequest();
+request.open("POST", "submitform.php");
+request.send(new FormData(formElement));
+
+ +

You can also append additional data to the FormData object between retrieving it from a form and sending it, like this:

+ +
var formElement = document.querySelector("form");
+var formData = new FormData(formElement);
+var request = new XMLHttpRequest();
+request.open("POST", "submitform.php");
+formData.append("serialnumber", serialNumber++);
+request.send(formData);
+ +

This lets you augment the form's data before sending it along, to include additional information that's not necessarily user-editable.

+ +

使用 FormData 物件傳送檔案

+ +

You can also send files using FormData. Simply include an {{ HTMLElement("input") }} element of type file in your {{htmlelement("form")}}:

+ +
<form enctype="multipart/form-data" method="post" name="fileinfo">
+  <label>Your email address:</label>
+  <input type="email" autocomplete="on" autofocus name="userid" placeholder="email" required size="32" maxlength="64" /><br />
+  <label>Custom file label:</label>
+  <input type="text" name="filelabel" size="12" maxlength="32" /><br />
+  <label>File to stash:</label>
+  <input type="file" name="file" required />
+  <input type="submit" value="Stash the file!" />
+</form>
+<div></div>
+
+ +

Then you can send it using code like the following:

+ +
var form = document.forms.namedItem("fileinfo");
+form.addEventListener('submit', function(ev) {
+
+  var oOutput = document.querySelector("div"),
+      oData = new FormData(form);
+
+  oData.append("CustomField", "This is some extra data");
+
+  var oReq = new XMLHttpRequest();
+  oReq.open("POST", "stash.php", true);
+  oReq.onload = function(oEvent) {
+    if (oReq.status == 200) {
+      oOutput.innerHTML = "Uploaded!";
+    } else {
+      oOutput.innerHTML = "Error " + oReq.status + " occurred when trying to upload your file.<br \/>";
+    }
+  };
+
+  oReq.send(oData);
+  ev.preventDefault();
+}, false);
+
+ +
+

Note: If you pass in a reference to the form the method specified in the form will be used over the method specified in the open() call.

+
+ +

You can also append a {{ domxref("File") }} or {{ domxref("Blob") }} directly to the {{ domxref("FormData") }} object, like this:

+ +
data.append("myfile", myBlob, "filename.txt");
+
+ +

When using the {{domxref("FormData.append","append()")}} method it is possible to use the third optional parameter to pass a filename inside the Content-Disposition header that is sent to the server. When no filename is specified (or the parameter isn't supported), the name "blob" is used.

+ +

You can also use FormData with jQuery if you set the right options:

+ +
var fd = new FormData(document.querySelector("form"));
+fd.append("CustomField", "This is some extra data");
+$.ajax({
+  url: "stash.php",
+  type: "POST",
+  data: fd,
+  processData: false,  // tell jQuery not to process the data
+  contentType: false   // tell jQuery not to set contentType
+});
+
+ +

Submitting forms and uploading files via AJAX without FormData objects

+ +

If you want to know how to serialize and submit a form via AJAX without using FormData objects, please read this paragraph.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/fullscreen_api/index.html b/files/zh-tw/web/api/fullscreen_api/index.html new file mode 100644 index 0000000000..182f96c922 --- /dev/null +++ b/files/zh-tw/web/api/fullscreen_api/index.html @@ -0,0 +1,240 @@ +--- +title: 使用全螢幕模式 +slug: Web/API/Fullscreen_API +translation_of: Web/API/Fullscreen_API +--- +

{{DefaultAPISidebar("Fullscreen API")}}

+ +

全螢幕 API 提供一個簡便的方式使網頁可以使用佔用使用者的整個螢幕的方式來顯示內容。該 API 讓您能夠容易地指示瀏覽器使某個元素及其子系(如有)佔用整個螢幕,並隱藏螢幕上所有瀏覽器使用者介面及其他應用程式。

+ +
目前並非所有瀏覽器均使用 API 的沒有前綴的版本。請查閱有關前綴以及名稱差異的表格(您也可以使用 Fscreen 來提供跨瀏覽器 API 存取)。
+ +

啟動全螢幕模式

+ +

如果您有一個元素打算以全螢幕模式展示(例如 {{ HTMLElement("video") }}),您可以呼叫該元素之 {{ domxref("Element.requestFullscreen()") }} 方法使之以全螢幕模式顯示。

+ +

考慮此 {{ HTMLElement("video") }} 元素:

+ +
<video controls id="myvideo">
+  <source src="somevideo.webm"></source>
+  <source src="somevideo.mp4"></source>
+</video>
+
+ +

我們可以使用指令碼將此影片全螢幕顯示:

+ +
var elem = document.getElementById("myvideo");
+if (elem.requestFullscreen) {
+  elem.requestFullscreen();
+} else if (elem.msRequestFullscreen) {
+  elem.msRequestFullscreen();
+} else if (elem.mozRequestFullScreen) {
+  elem.mozRequestFullScreen();
+} else if (elem.webkitRequestFullscreen) {
+  elem.webkitRequestFullscreen();
+}
+
+ +

呈現差異

+ +

值得留意的是,Gecko 及 WebKit 的實作有關鍵分別:Gecko 會增加 CSS 規則讓全螢幕的元素展延至填滿整個螢幕:"width: 100%; height: 100%"。WebKit 則不會執行此動作,取而代之的是把該元素置中,並以原先的大小顯示。要取得同樣的全螢幕行為,您需要為該元素自行添加 "width: 100%; height: 100%;" 的 CSS 規則:

+ +
#myvideo:-webkit-full-screen {
+  width: 100%;
+  height: 100%;
+}
+
+ +

另一方面,如果您嘗試在 Gecko 上模擬 WebKit 的行為,您需要把呈現的元素放置在另一個實際調整為全螢幕的元素裡面,再使用 CSS 規則來調整內部元素至您想要的外觀。

+ +

通知

+ +

如果成功進入全螢幕模式,包含該元素的文件將會接收到 {{ event("fullscreenchange") }} 事件。當離開全螢幕模式時,則會收到 {{ event("fullscreenchange") }} 事件。注意 {{ event("fullscreenchange") }} 事件並不提供任何資訊指示進入或離開全螢幕模式,但如果文件的 {{ domxref("document.fullscreenElement", "fullscreenElement") }} 屬性的值不為 null,則表示您正在處於全螢幕模式。

+ +

全螢幕要求失敗

+ +

並不是所有情況下都保證可以進入全螢幕模式。例如,{{ HTMLElement("iframe") }} 元素含有 {{ HTMLAttrXRef("allowfullscreen", "iframe") }} 屬性來選擇是否容許其內容能以全螢幕方式呈現。而且,例如視窗式外掛程式等的某些內容並不可以在全螢幕模式中顯示。把無法呈現為全螢幕的元素設定為全螢幕模式的嘗試都沒有作用,而要求顯示為全螢幕的元素會接收到 mozfullscreenerror 事件。當全螢幕要求失敗時,Firefox 會在網頁主控台上紀錄一則錯誤訊息,解釋要求失敗的原因。但在 Chrome 以及新版的 Opera 上,則不會產生這些錯誤訊息。

+ +
+

注意:全螢幕要求必須在事件處理常式中呼叫,否則將會被拒絕。

+
+ +

離開全螢幕模式

+ +

使用者永遠可以自行離開全螢幕模式,詳見 {{ anch("Things your users want to know") }}。您也可以呼叫 {{domxref("Document.exitFullscreen()")}} 方法來達到相同效果。

+ +

其他資訊

+ +

{{ domxref("document") }} 提供一些附加資訊,對於開發全螢幕網頁應用程式的時候非常有用:

+ +
+
{{ domxref("document.fullscreenElement", "fullscreenElement") }}
+
fullscreenElement 屬性傳回正在顯示為全螢幕模式的 {{ domxref("element") }}。如其為非 null 值,表示文件目前在全螢幕模式。如其為 null,表示文件目前不在全螢幕模式。
+
{{ domxref("document.fullscreenEnabled", "fullscreenEnabled") }}
+
fullscreenEnabled 屬性傳回文件是否容許您要求進入全螢幕訊息。
+
+ +

使用者可能想了解的訊息

+ +

您可能會讓使用者知道他們可以按 ESCF11 鍵來離開全螢幕模式。

+ +

此外,瀏覽其他頁面、切換分頁、或切換到其他應用程式(例如按 鍵)亦會離開全螢幕模式。

+ +

範例

+ +

In this example, a video is presented in a web page. Pressing the Return or Enter key lets the user toggle between windowed and fullscreen presentation of the video.

+ +

查看示例

+ +

監視 Enter 鍵

+ +

When the page is loaded, this code is run to set up an event listener to watch for the 'enter' key.

+ +
document.addEventListener("keydown", function(e) {
+  if (e.keyCode == 13) {
+    toggleFullScreen();
+  }
+}, false);
+
+ +

Toggling fullscreen mode

+ +

This code is called when the user hits the Enter key, as seen above.

+ +
function toggleFullScreen() {
+  if (!document.fullscreenElement &&    // alternative standard method
+      !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement ) {  // current working methods
+    if (document.documentElement.requestFullscreen) {
+      document.documentElement.requestFullscreen();
+    } else if (document.documentElement.msRequestFullscreen) {
+      document.documentElement.msRequestFullscreen();
+    } else if (document.documentElement.mozRequestFullScreen) {
+      document.documentElement.mozRequestFullScreen();
+    } else if (document.documentElement.webkitRequestFullscreen) {
+      document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
+    }
+  } else {
+    if (document.exitFullscreen) {
+      document.exitFullscreen();
+    } else if (document.msExitFullscreen) {
+      document.msExitFullscreen();
+    } else if (document.mozCancelFullScreen) {
+      document.mozCancelFullScreen();
+    } else if (document.webkitExitFullscreen) {
+      document.webkitExitFullscreen();
+    }
+  }
+}
+
+ +

This starts by looking at the value of the fullscreenElement attribute on the {{ domxref("document") }} (checking it prefixed with both moz, ms, and webkit). If it's null, the document is currently in windowed mode, so we need to switch to fullscreen mode. Switching to fullscreen mode is done by calling either {{ domxref("element.mozRequestFullScreen()") }} msRequestFullscreen()or webkitRequestFullscreen(), depending on which is available.

+ +

If fullscreen mode is already active (fullscreenElement is non-null), we call {{ domxref("document.mozCancelFullScreen()") }}, msExitFullscreen or webkitExitFullscreen(), again depending on which browser is in use.

+ +

瀏覽器兼容性

+ +

Although  Gecko , Trident, and WebKit implement a draft of this API, there are some subtle differences. This document doesn't necessarily try to call them all into focus. The article will be revised as the spec and implementations fall closer into alignment with one another.

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support15 {{ property_prefix("-webkit") }}{{ CompatGeckoDesktop("9.0") }} {{ property_prefix("-moz") }}11 {{ property_prefix("-ms") }}12.105.0 {{ property_prefix("-webkit") }}
fullscreenEnabled20 {{ property_prefix("-webkit") }}{{ CompatGeckoDesktop("10.0") }} {{ property_prefix("-moz") }}11 {{ property_prefix("-ms") }}12.105.1 {{ property_prefix("-webkit") }}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChromeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{ CompatUnknown() }}28 {{ property_prefix("-webkit") }}{{ CompatGeckoMobile("9.0") }}{{ property_prefix("-moz") }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
fullscreenEnabled{{ CompatUnknown() }}28 {{ property_prefix("-webkit") }}{{ CompatGeckoMobile("10.0") }} {{ property_prefix("moz") }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +

Gecko notes

+ +

Although this API was introduced in Gecko 9.0 {{ geckoRelease("9.0") }}, it's not enabled by default in that release. To enable it, set the full-screen-api.enabled preference to true. The API is enabled by default in Gecko 10.0 {{ geckoRelease("10.0") }}. In Gecko all the API is spelt "fullScreen".

+ +

規範

+ +

Fullscreen API

+ +

非標準方法

+ +

These are some of the methods that browsers implemented before the standard was drafted. Having the standard methods described above it's better to avoid using the following ones:

+ + + +

參見

+ + + + diff --git a/files/zh-tw/web/api/gainnode/gain/index.html b/files/zh-tw/web/api/gainnode/gain/index.html new file mode 100644 index 0000000000..895a356e25 --- /dev/null +++ b/files/zh-tw/web/api/gainnode/gain/index.html @@ -0,0 +1,113 @@ +--- +title: GainNode.gain +slug: Web/API/GainNode/gain +tags: + - API +translation_of: Web/API/GainNode/gain +--- +

{{ APIRef("Web Audio API") }}

+ +
+

{{ domxref("GainNode") }} 介面的 gain 屬性是 a-rate {{domxref("AudioParam")}},代表增益的數值。

+
+ +

語法

+ +
var audioCtx = new AudioContext();
+var gainNode = audioCtx.createGain();
+gainNode.gain.value = 0.5;
+
+ +

傳回值

+ +

一個 {{domxref("AudioParam")}}.

+ +
+

註: 雖然傳回的 AudioParam 是唯讀的,但是它所代表的值可以更改。

+
+ +

範例

+ +

{{page("/en-US/docs/Web/API/AudioContext.createGain","Example")}}

+ +

規格

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Web Audio API', '#widl-GainNode-gain', 'gain')}}{{Spec2('Web Audio API')}} 
+ +

瀏覽器相容度

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome(10.0)}}{{property_prefix("webkit")}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(25.0)}} {{CompatNo}}15.0{{property_prefix("webkit")}}
+ 22 (unprefixed)
6.0{{property_prefix("webkit")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatUnknown}}{{CompatVersionUnknown}}26.01.2{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}33.0
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/gainnode/index.html b/files/zh-tw/web/api/gainnode/index.html new file mode 100644 index 0000000000..1d52092799 --- /dev/null +++ b/files/zh-tw/web/api/gainnode/index.html @@ -0,0 +1,168 @@ +--- +title: GainNode +slug: Web/API/GainNode +translation_of: Web/API/GainNode +--- +

{{ APIRef("Web Audio API") }}

+ +
+

GainNode 介面代表的是音量改變。 這是 {{domxref("AudioNode")}} 音訊處理模組,可以對輸入的訊號做增益 (gain) 後輸出。一個 GainNode 有一個輸入和一個輸出,兩者有相同的聲道數。

+
+ +

增益 (gain) 是無單位的數值,隨時間變化,會用來和所有輸入聲道的取樣做相乘。 如果更改的話,新的增益會用 de-zippering 演算法處理,以避免輸出聲音出現難聽的「喀」聲。

+ +

The GainNode is increasing the gain of the output.

+ + + + + + + + + + + + + + + + + + + + + + + + +
Number of inputs1
Number of outputs1
Channel count mode"max"
Channel count2 (not used in the default count mode)
Channel interpretation"speakers"
+ +

Constructor

+ +
+
{{domxref("GainNode.GainNode", "GainNode()")}}
+
Creates a new instance of an GainNode object.
+
+ +

Properties

+ +

Inherits properties from its parent, {{domxref("AudioNode")}}.

+ +
+
{{domxref("GainNode.gain")}} {{readonlyinline}}
+
a-rate {{domxref("AudioParam")}} ,代表增益值
+
+ +

Methods

+ +

No specific method; inherits methods from its parent, {{domxref("AudioNode")}}.

+ +

Example

+ +

{{page("/en-US/docs/Web/API/AudioContext.createGain","Example")}}

+ +

Specifications

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Web Audio API', '#the-gainnode-interface', 'GainNode')}}{{Spec2('Web Audio API')}} 
+ +

Browser compatibility

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome(10.0)}}{{property_prefix("webkit")}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(25.0)}} {{CompatNo}}{{CompatOpera(15)}}{{property_prefix("webkit")}}
+ {{CompatOpera(22)}}
6.0{{property_prefix("webkit")}}
constructor{{CompatChrome(55.0)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatOpera(42)}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewEdgeFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatNo}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}26.01.2{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatChrome(33.0)}}
constructor{{CompatNo}}{{CompatChrome(55.0)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatOpera(42)}}{{CompatUnknown}}{{CompatChrome(55.0)}}
+
+ +

See also

+ + diff --git a/files/zh-tw/web/api/geolocation/clearwatch/index.html b/files/zh-tw/web/api/geolocation/clearwatch/index.html new file mode 100644 index 0000000000..c1d2979db2 --- /dev/null +++ b/files/zh-tw/web/api/geolocation/clearwatch/index.html @@ -0,0 +1,132 @@ +--- +title: Geolocation.clearWatch() +slug: Web/API/Geolocation/clearWatch +translation_of: Web/API/Geolocation/clearWatch +--- +

{{ APIref("Geolocation API") }}

+ +

Geolocation.clearWatch() 這個函式是用來取消   {{domxref("Geolocation.watchPosition()")}} 註冊的函式。

+ +

語法

+ +
navigator.geolocation.clearWatch(id);
+ +

參數

+ +
+
編號(id)
+
這個編號(ID) 是由 {{domxref("Geolocation.watchPosition()")}} 這個函式所回傳,當你不再需要收到位置更新時,你可以用此編號,取消 {{domxref("Geolocation.watchPosition()")}} 的註冊。
+
+ +

範例

+ +
var id, target, option;
+
+function success(pos) {
+  var crd = pos.coords;
+
+  if (target.latitude === crd.latitude && target.longitude === crd.longitude) {
+    console.log('Congratulation, you reach the target');
+    navigator.geolocation.clearWatch(id);
+  }
+};
+
+function error(err) {
+  console.warn('ERROR(' + err.code + '): ' + err.message);
+};
+
+target = {
+  latitude : 0,
+  longitude: 0,
+}
+
+options = {
+  enableHighAccuracy: false,
+  timeout: 5000,
+  maximumAge: 0
+};
+
+id = navigator.geolocation.watchPosition(success, error, options);
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ Removed in 15.0
+ Reintroduced in 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown()}}{{CompatUnknown()}}{{CompatGeckoMobile("4")}}{{CompatUnknown()}}10.60{{CompatUnknown()}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocation/getcurrentposition/index.html b/files/zh-tw/web/api/geolocation/getcurrentposition/index.html new file mode 100644 index 0000000000..78c26d3e8e --- /dev/null +++ b/files/zh-tw/web/api/geolocation/getcurrentposition/index.html @@ -0,0 +1,127 @@ +--- +title: Geolocation.getCurrentPosition() +slug: Web/API/Geolocation/getCurrentPosition +translation_of: Web/API/Geolocation/getCurrentPosition +--- +

{{ APIRef("Geolocation API") }}

+ +

Geolocation.getCurrentPosition() 方法用來獲取設備當前的位置。

+ +

語法

+ +
navigator.geolocation.getCurrentPosition(success[, error[, options]])
+ +

參數

+ +
+
success
+
一個回呼函式(callback function) 會被傳入一個{{domxref("Position")}} 的物件。
+
error {{optional_inline}}
+
一個選擇性的錯誤回呼函式(callback function),會被傳入一個 {{domxref("PositionError")}} 的物件。
+
options {{optional_inline}}
+
一個選擇性的 {{domxref("PositionOptions")}} 的物件。
+
+ +

範例

+ +
var options = {
+  enableHighAccuracy: true,
+  timeout: 5000,
+  maximumAge: 0
+};
+
+function success(pos) {
+  var crd = pos.coords;
+
+  console.log('Your current position is:');
+  console.log('Latitude : ' + crd.latitude);
+  console.log('Longitude: ' + crd.longitude);
+  console.log('More or less ' + crd.accuracy + ' meters.');
+};
+
+function error(err) {
+  console.warn('ERROR(' + err.code + '): ' + err.message);
+};
+
+navigator.geolocation.getCurrentPosition(success, error, options);
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ Removed in 15.0
+ Reintroduced in 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown()}}{{CompatUnknown()}}{{CompatGeckoMobile("4")}}{{CompatUnknown()}}10.60{{CompatUnknown()}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocation/index.html b/files/zh-tw/web/api/geolocation/index.html new file mode 100644 index 0000000000..3dda732dbf --- /dev/null +++ b/files/zh-tw/web/api/geolocation/index.html @@ -0,0 +1,118 @@ +--- +title: Geolocation +slug: Web/API/Geolocation +tags: + - API + - Advanced + - Geolocation API + - Interface + - NeedsTranslation + - Reference + - TopicStub +translation_of: Web/API/Geolocation +--- +
{{APIRef("Geolocation API")}}
+ +

Geolocation 介面代表一個物件可以透過你的網頁程式去獲得你的裝置位置。這個介面提供了網站或應用程式根據使用者的位置去客製化呈現的內容。

+ +

{{domxref("Navigator")}} 此物件實作了 {{domxref("Navigator.geolocation")}} 介面。

+ +
+

備註: 因為隱私的因素,當網頁要求存取位置資訊時,用戶會被提示通知並且詢問授權與否。注意不同的瀏覽器在詢問授權時有各自不同的策略和方式。

+
+ +

性質

+ +

Geolocation 介面沒有繼承也沒有時做任何方法

+ +

方法

+ +

Geolocation 介面沒有繼承任何方法

+ +
+
{{domxref("Geolocation.getCurrentPosition()")}}
+
取得裝置當前位置,並回傳{{domxref("Position")}}。
+
{{domxref("Geolocation.watchPosition()")}}
+
返回一個長整數,註冊一個回呼函數。這個方法是用來註冊一個處理的函式,當使用者的裝置位置更新時,這個函式所傳入的回呼函式(callback function) 就會自動被呼叫。
+
{{domxref("Geolocation.clearWatch()")}}
+
移除指定註冊的 watchPosition()
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ Removed in 15.0
+ Reintroduced in 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown()}}{{CompatUnknown()}}{{CompatGeckoMobile("4")}}{{CompatUnknown()}}10.60{{CompatUnknown()}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocation/using_geolocation/index.html b/files/zh-tw/web/api/geolocation/using_geolocation/index.html new file mode 100644 index 0000000000..cdc56770c4 --- /dev/null +++ b/files/zh-tw/web/api/geolocation/using_geolocation/index.html @@ -0,0 +1,251 @@ +--- +title: 地理位置定位 (Geolocation) +slug: Web/API/Geolocation/Using_geolocation +translation_of: Web/API/Geolocation_API +--- +

Web Apps 若需要使用者的位置,可透過 Geolocation API 取得相關資訊。而基於隱私權的考量,這些 Web Apps 均必須取得使用者的許可之後,才能發佈位置資訊。

+ +

地理位置定位 (Geolocation) 物件

+ +

Geolocation API,是透過 navigator.geolocation 物件所發佈。

+ +

若該物件可用,即可進行地理位置定位服務。因此可先測試地理位置定位是否存在:

+ +
if ("geolocation" in navigator) {
+  /* geolocation is available */
+} else {
+  /* geolocation IS NOT available */
+}
+
+ +
注意:在 Firefox 24 之後的版本,即使停用此 API,navigator 中的「geolocation」也同樣回傳 true。此問題已根據規格而於 Firefox 25 中修正 (bug 884921)。
+ +

取得目前位置

+ +

若要取得使用者目前的位置,可呼叫 getCurrentPosition() 函式。如此將啟動非同步化的請求,以偵測使用者的位置,並將查詢定位硬體而取得最新資訊。一旦決定位置,隨即執行特定的回呼常式 (Callback routine)。若發生錯誤,則可選擇是否提供第二次回呼。第三項參數為選項介面 (亦可選擇是否使用之),可設定位置回傳的的最長時間,與請求的等待時間。
+ 若不論定位精確度而想儘快固定單一位置,則可使用 getCurrentPosition()。以具備 GPS 的裝置為例,往往需耗時 1 分鐘或更長的時間而固定 GPS 資訊。也因此,getCurrentPosition() 可能取得較低精確度的資料 (IP 位置或 WiFi) 而隨即開始作業。

+ +
+

注意:依預設值,getCurrentPosition() 將儘快回傳較低精確度的結果。若不論精確度而只要儘快獲得答案,則可使用 getCurrentPosition()。舉例來說,搭載 GPS 的裝置可能需要一段時間才能取得 GPS 定位資訊,所以可能將低精確度的資料 (IP 位置或 Wifi) 回傳至 getCurrentPosition()

+
+ +
navigator.geolocation.getCurrentPosition(function(position) {
+  do_something(position.coords.latitude, position.coords.longitude);
+});
+ +

一旦取得定位位置之後,上列範例隨即將執行 do_something() 函式。

+ +

觀看目前位置

+ +

如果定位資料改變 (可能是裝置移動,或取得更精確的地理位置資訊),則可設定 1 組回呼函式,使其隨著更新過的定位資訊而呼叫之。而這個動作可透過 watchPosition() 函式完成。watchPosition() 所具備的輸入參數與 getCurrentPosition() 相同。回呼函式將呼叫數次,讓瀏覽器可於使用者移動期間更新位置,或可根據目前所使用的不同定位技術,提供更精確的定位資訊。若一直未回傳有效結果,則錯誤回呼 (Error Callback) 函式僅將呼叫 1 次。另請注意,錯誤回呼函式僅限於 getCurrentPosition(),因此為選填

+ +
+

注意:不需啟動 getCurrentPosition() 呼叫,亦可使用 watchPosition()

+
+ +
var watchID = navigator.geolocation.watchPosition(function(position) {
+  do_something(position.coords.latitude, position.coords.longitude);
+}
+);
+ +

watchPosition() 函式將回傳 1 組 ID 編號,專用以識別必要的定位監看員 (Watcher)。而此數值若搭配 clearWatch() 函式,即可停止觀看使用者的位置。

+ +
navigator.geolocation.clearWatch(watchID);
+
+ +

微調回應

+ +

getCurrentPosition()watchPosition() 均可容納 1 組成功回呼、1 組錯誤回呼 (選填)、1 組 PositionOptions 物件 (選填)。

+ +

watchPosition 的呼叫應類似如下:

+ +
function geo_success(position) {
+  do_something(position.coords.latitude, position.coords.longitude);
+}
+
+function geo_error() {
+  alert("Sorry, no position available.");
+}
+
+var geo_options = {
+  enableHighAccuracy: true,
+  maximumAge        : 30000,
+  timeout           : 27000
+};
+
+var wpid = navigator.geolocation.watchPosition(geo_success, geo_error, geo_options);
+ +

現成的 watchPosition Demo:http://www.thedotproduct.org/experiments/geo/
+ 

+ +

敘述位置

+ +

Position 物件參照 Coordinates 物件,即可敘述使用者的位置。

+ +

處理錯誤

+ +

在呼叫 getCurrentPosition()watchPosition() 時,若獲得錯誤回呼函式,則錯誤回呼函式的第一組參數將為 PositionError 物件:

+ +
function errorCallback(error) {  alert('ERROR(' + error.code + '): ' + error.message);};
+
+ +

地理位置定位實際範例

+ +

HTML 內容

+ +
<p><button onclick="geoFindMe()">Show my location</button></p>
+<div id="out"></div>
+ +

JavaScript 內容

+ +
function geoFindMe() {
+  var output = document.getElementById("out");
+
+  if (!navigator.geolocation){
+    output.innerHTML = "<p>Geolocation is not supported by your browser</p>";
+    return;
+  }
+
+  function success(position) {
+    var latitude  = position.coords.latitude;
+    var longitude = position.coords.longitude;
+
+    output.innerHTML = '<p>Latitude is ' + latitude + '° <br>Longitude is ' + longitude + '°</p>';
+
+    var img = new Image();
+    img.src = "http://maps.googleapis.com/maps/api/staticmap?center=" + latitude + "," + longitude + "&zoom=13&size=300x300&sensor=false";
+
+    output.appendChild(img);
+  };
+
+  function error() {
+    output.innerHTML = "Unable to retrieve your location";
+  };
+
+  output.innerHTML = "<p>Locating…</p>";
+
+  navigator.geolocation.getCurrentPosition(success, error);
+}
+
+ +

現場測試結果

+ +

若無法顯示,可至本文右上角「Language」切換回英文原文觀看。

+ + +

{{EmbedLiveSample('Examples', 350, 150, "", "", "", "geolocation")}}

+ + +

請求權限

+ +

addons.mozilla.org 上所提供的任何附加元件,只要使用地理位置定位資料,均必須明確取得許可才能繼續作業。下列函式詢問許可的方法,則類似網頁詢問許可的自動提示方法,但更為簡單。若為可套用的狀態,則使用者的回應將儲存於 pref 參數所指定的偏好中。於 callback 參數中所提供的函式,將透過 1 組代表使用者反應的布林值而呼叫之。若使用者的回應為 true,則附加元件才會存取地理位置定位資料。

+ +
function prompt(window, pref, message, callback) {
+    let branch = Components.classes["@mozilla.org/preferences-service;1"]
+                           .getService(Components.interfaces.nsIPrefBranch);
+
+    if (branch.getPrefType(pref) === branch.PREF_STRING) {
+        switch (branch.getCharPref(pref)) {
+        case "always":
+            return callback(true);
+        case "never":
+            return callback(false);
+        }
+    }
+
+    let done = false;
+
+    function remember(value, result) {
+        return function() {
+            done = true;
+            branch.setCharPref(pref, value);
+            callback(result);
+        }
+    }
+
+    let self = window.PopupNotifications.show(
+        window.gBrowser.selectedBrowser,
+        "geolocation",
+        message,
+        "geo-notification-icon",
+        {
+            label: "Share Location",
+            accessKey: "S",
+            callback: function(notification) {
+                done = true;
+                callback(true);
+            }
+        }, [
+            {
+                label: "Always Share",
+                accessKey: "A",
+                callback: remember("always", true)
+            },
+            {
+                label: "Never Share",
+                accessKey: "N",
+                callback: remember("never", false)
+            }
+        ], {
+            eventCallback: function(event) {
+                if (event === "dismissed") {
+                    if (!done) callback(false);
+                    done = true;
+                    window.PopupNotifications.remove(self);
+                }
+            },
+            persistWhileVisible: true
+        });
+}
+
+prompt(window,
+       "extensions.foo-addon.allowGeolocation",
+       "Foo Add-on wants to know your location.",
+       function callback(allowed) { alert(allowed); });
+
+ +

瀏覽器相容性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
瀏覽器基本支援Geolocation Level 2
Internet ExplorerIE9 RC---
Firefox (Gecko)3.5 (1.9.1)---
Opera10.60---
Safari | Chrome | WebKit5 | 5 | 533---
+ +

Gecko 註記

+ +

Firefox 可透過 Google 的定位服務 (Google Location Services,GLS),根據使用者的 WiFi 資訊而找出使用者的位置。與 Google 之間所交換的資料,包含 WiFi 存取點 (Access Point) 資料、Access token (類似 2 個禮拜的 cookie)、使用者的 IP 位址。若需更多資訊,可參閱 Mozilla 的隱私權政策Google 的隱私權政策。其內將詳述資料的使用方式。

+ +

Firefox 3.6 (Gecko 1.9.2) 新支援了 GPSD (GPS daemon) 服務,適合 Linux 的地理位置定位。

+ +

另請參閱

+ + diff --git a/files/zh-tw/web/api/geolocation/watchposition/index.html b/files/zh-tw/web/api/geolocation/watchposition/index.html new file mode 100644 index 0000000000..fc5109f1f5 --- /dev/null +++ b/files/zh-tw/web/api/geolocation/watchposition/index.html @@ -0,0 +1,143 @@ +--- +title: Geolocation.watchPosition() +slug: Web/API/Geolocation/watchPosition +translation_of: Web/API/Geolocation/watchPosition +--- +

{{ APIref("Geolocation API") }}

+ +

Geolocation.watchPosition() 這個方法是用來註冊一個處理的函式,當使用者的裝置位置更新時,這個函式所傳入的回呼函式(callback function) 就會自動被呼叫。你也可以選擇性的定義錯誤時哪些錯誤回呼函式(error callback function) 需要被呼叫。

+ +

這個函式將回傳一組 ID 編號,此編號搭配 {{domxref("Geolocation.clearWatch()")}} 函式,即可停止更新使用者的位置。

+ +

語法

+ +
id = navigator.geolocation.watchPosition(success[, error[, options]])
+ +

參數

+ +
+
success
+
一個回呼函式(callback function) 會被傳入一個 {{domxref("Position")}} 的物件。
+
error {{optional_inline}}
+
一個選擇性的錯誤回呼函式(callback function),會被傳入一個{{domxref("PositionError")}} 的物件。
+
options {{optional_inline}}
+
一個選擇性 {{domxref("PositionOptions")}} 的物件。
+
+ +

範例

+ +
var id, target, options;
+
+function success(pos) {
+  var crd = pos.coords;
+
+  if (target.latitude === crd.latitude && target.longitude === crd.longitude) {
+    console.log('Congratulations, you reached the target');
+    navigator.geolocation.clearWatch(id);
+  }
+}
+
+function error(err) {
+  console.warn('ERROR(' + err.code + '): ' + err.message);
+}
+
+target = {
+  latitude : 0,
+  longitude: 0
+};
+
+options = {
+  enableHighAccuracy: false,
+  timeout: 5000,
+  maximumAge: 0
+};
+
+id = navigator.geolocation.watchPosition(success, error, options);
+
+ +

備註

+ +

如果你的應用程式是跑在 firefox OS上,請參考 geolocation wake lock,此方法可以讓你的程式在背景或螢幕關上時也能持續收到位置更新。

+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#watch-position', 'Geolocation.watchPosition()')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ Removed in 15.0
+ Reintroduced in 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown()}}{{CompatUnknown()}}{{CompatGeckoMobile("4")}}{{CompatUnknown()}}10.60{{CompatUnknown()}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationcoordinates/accuracy/index.html b/files/zh-tw/web/api/geolocationcoordinates/accuracy/index.html new file mode 100644 index 0000000000..4670394148 --- /dev/null +++ b/files/zh-tw/web/api/geolocationcoordinates/accuracy/index.html @@ -0,0 +1,93 @@ +--- +title: Coordinates.accuracy +slug: Web/API/GeolocationCoordinates/accuracy +translation_of: Web/API/GeolocationCoordinates/accuracy +--- +
{{APIRef("Geolocation API")}}
+ +

Coordinates.accuracy 是個唯讀的正複數用來代表 {{domxref("Coordinates.latitude")}} 和 {{domxref("Coordinates.longitude")}} 的準確度,單位為公尺,並有 95% 可靠度。

+ +

語法

+ +
acc = coordinates.accuracy
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#accuracy', 'Coordinates.accuracy')}}{{Spec2('Geolocation')}}Initial definition
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationcoordinates/altitude/index.html b/files/zh-tw/web/api/geolocationcoordinates/altitude/index.html new file mode 100644 index 0000000000..a9e2141793 --- /dev/null +++ b/files/zh-tw/web/api/geolocationcoordinates/altitude/index.html @@ -0,0 +1,93 @@ +--- +title: Coordinates.altitude +slug: Web/API/GeolocationCoordinates/altitude +translation_of: Web/API/GeolocationCoordinates/altitude +--- +
{{APIRef("Geolocation API")}}
+ +

Coordinates.altitude 是個唯讀的正複數用來代表距離海平面的高度,單位為公尺。如果無法提供這個值則回傳 null。

+ +

語法

+ +
alt = coordinates.altitude
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#altitude', 'Coordinates.altitude')}}{{Spec2('Geolocation')}}Initial definition
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationcoordinates/altitudeaccuracy/index.html b/files/zh-tw/web/api/geolocationcoordinates/altitudeaccuracy/index.html new file mode 100644 index 0000000000..e0ad663ba0 --- /dev/null +++ b/files/zh-tw/web/api/geolocationcoordinates/altitudeaccuracy/index.html @@ -0,0 +1,93 @@ +--- +title: Coordinates.altitudeAccuracy +slug: Web/API/GeolocationCoordinates/altitudeAccuracy +translation_of: Web/API/GeolocationCoordinates/altitudeAccuracy +--- +
{{APIRef("Geolocation API")}}
+ +

Coordinates.altitudeAccuracy 是個唯讀的正複數用來代表高度的精準度,單位為公尺,並有 95% 可靠度。如果裝置無法提供這個值則回傳 null。

+ +

語法

+ +
altAcc = coordinates.altitudeAccuracy
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#altitudeaccuracy', 'Coordinates.altitudeAccuracy')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationcoordinates/heading/index.html b/files/zh-tw/web/api/geolocationcoordinates/heading/index.html new file mode 100644 index 0000000000..be762eb369 --- /dev/null +++ b/files/zh-tw/web/api/geolocationcoordinates/heading/index.html @@ -0,0 +1,93 @@ +--- +title: Coordinates.heading +slug: Web/API/GeolocationCoordinates/heading +translation_of: Web/API/GeolocationCoordinates/heading +--- +
{{APIRef("Geolocation API")}}
+ +

Coordinates.heading 是個唯讀的正複數用來代表裝置前進的方向。這個數值代表你偏離北方多少度,0度代表你向著正北方,照著順時針的方向遞增(90度代表正東方,270度代表正西方)。如果{{domxref("Coordinates.speed")}} 為0度,則此值為 NaN。如果這個裝置無法提供這個值則回傳 null。

+ +

語法

+ +
heading = coordinates.heading
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#heading', 'Coordinates.heading')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationcoordinates/index.html b/files/zh-tw/web/api/geolocationcoordinates/index.html new file mode 100644 index 0000000000..08be554dff --- /dev/null +++ b/files/zh-tw/web/api/geolocationcoordinates/index.html @@ -0,0 +1,113 @@ +--- +title: Coordinates +slug: Web/API/GeolocationCoordinates +translation_of: Web/API/GeolocationCoordinates +--- +
{{APIRef("Geolocation API")}}
+ +

Coordinates 這個介面用來存取裝置的經緯度,速度以及這些數值的準確度。

+ +

屬性

+ +

Coordinates 這個介面沒有繼承任何屬性

+ +
+
{{domxref("Coordinates.latitude")}} {{readonlyInline}}
+
回傳一個十進位的 double 代表緯度。
+
{{domxref("Coordinates.longitude")}} {{readonlyInline}}
+
回傳一個十進位的 double 代表經度。
+
{{domxref("Coordinates.altitude")}} {{readonlyInline}}
+
回傳一個 double 代表距離海平面的高度,單位為公尺。如果無法提供這個值則回傳 null。
+
{{domxref("Coordinates.accuracy")}} {{readonlyInline}}
+
回傳一個 double 代表經緯度的精準值,單位為公尺。
+
{{domxref("Coordinates.altitudeAccuracy")}} {{readonlyInline}}
+
回傳一個 double 代表高度的精準度,單位為公尺。如果無法提供這個值則回傳 null。
+
{{domxref("Coordinates.heading")}} {{readonlyInline}}
+
回傳一個 double 代表裝置前進的方向,這個數值代表你偏離北方多少度,0度代表你向著正北方,照著順時針的方向遞增(90度代表正東方,270度代表正西方) 。如果速度值為0度,則此值為 NaN。如果無法提供這個值則回傳 null。
+
{{domxref("Coordinates.speed")}} {{readonlyInline}}
+
回傳一個 double 代表速度,單位為公尺/秒。如果無法提供這個值則回傳 null。
+
+ +

方法

+ +

Coordinates 這個介面,沒有實作也沒有繼承自任何的方法。

+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#coordinates', 'Coordinates')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown()}}{{CompatUnknown()}}{{CompatGeckoMobile("4")}}{{CompatUnknown()}}10.60{{CompatUnknown()}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationcoordinates/latitude/index.html b/files/zh-tw/web/api/geolocationcoordinates/latitude/index.html new file mode 100644 index 0000000000..18c43451f2 --- /dev/null +++ b/files/zh-tw/web/api/geolocationcoordinates/latitude/index.html @@ -0,0 +1,93 @@ +--- +title: Coordinates.latitude +slug: Web/API/GeolocationCoordinates/latitude +translation_of: Web/API/GeolocationCoordinates/latitude +--- +
{{APIRef("Geolocation API")}}
+ +

Coordinates.latitude 是個唯讀十進位的複數用來代表裝置緯度的位置。

+ +

語法

+ +
lat = coordinates.latitude
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#lat', 'Coordinates.latitude')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationcoordinates/longitude/index.html b/files/zh-tw/web/api/geolocationcoordinates/longitude/index.html new file mode 100644 index 0000000000..f5625d20c6 --- /dev/null +++ b/files/zh-tw/web/api/geolocationcoordinates/longitude/index.html @@ -0,0 +1,93 @@ +--- +title: Coordinates.longitude +slug: Web/API/GeolocationCoordinates/longitude +translation_of: Web/API/GeolocationCoordinates/longitude +--- +
{{APIRef("Geolocation API")}}
+ +

Coordinates.longitude 是個唯讀十進位的複數用來代表裝置經度的位置。

+ +

語法

+ +
lon = coordinates.longitude
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#lon', 'Coordinates.longitude')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationcoordinates/speed/index.html b/files/zh-tw/web/api/geolocationcoordinates/speed/index.html new file mode 100644 index 0000000000..74c1940232 --- /dev/null +++ b/files/zh-tw/web/api/geolocationcoordinates/speed/index.html @@ -0,0 +1,93 @@ +--- +title: Coordinates.speed +slug: Web/API/GeolocationCoordinates/speed +translation_of: Web/API/GeolocationCoordinates/speed +--- +
{{APIRef("Geolocation API")}}
+ +

Coordinates.speed 回傳唯讀的正複數代表速度,單位為公尺/秒。 如果裝置無法測量這個值則回傳 null。

+ +

語法

+ +
speed = coordinates.speed
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#speed', 'Coordinates.speed')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationposition/coords/index.html b/files/zh-tw/web/api/geolocationposition/coords/index.html new file mode 100644 index 0000000000..c6e018c8cc --- /dev/null +++ b/files/zh-tw/web/api/geolocationposition/coords/index.html @@ -0,0 +1,93 @@ +--- +title: Position.coords +slug: Web/API/GeolocationPosition/coords +translation_of: Web/API/GeolocationPosition/coords +--- +
{{APIRef("Geolocation API")}}
+ +

Position.coords 是一個 {{domxref("Coordinates")}} 物件的唯讀屬性,表示地理的特性:回傳的物件中包括位置、地球經緯度、海拔高度和速度,同時也包含著這些值的精準度訊息。

+ +

語法

+ +
coord = position.coords
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#coords', 'Position.coords')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationposition/index.html b/files/zh-tw/web/api/geolocationposition/index.html new file mode 100644 index 0000000000..ecf342ff49 --- /dev/null +++ b/files/zh-tw/web/api/geolocationposition/index.html @@ -0,0 +1,103 @@ +--- +title: Position +slug: Web/API/GeolocationPosition +translation_of: Web/API/GeolocationPosition +--- +
{{APIRef("Geolocation API")}}
+ +

Position 介面表示在給定時間相關裝置的位置。這個位置用一個 {{domxref("Coordinates")}} 物件表示,包括裝置在地球上的二維位置,以及裝置的海拔高度和速度。

+ +

屬性

+ +

Position 介面沒有繼承任何屬性

+ +
+
{{domxref("Position.coords")}} {{readonlyInline}}
+
回傳一個定義當前位置的 {{domxref("Coordinates")}} 物件。
+
{{domxref("Position.timestamp")}} {{readonlyInline}}
+
回傳一個時間戳 {{domxref("DOMTimeStamp")}} ,這個時間戳表示獲取到位置的時間。
+
+ +

方法

+ +

Position 介面沒有實作或繼承任何方法

+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#position', 'Position')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationposition/timestamp/index.html b/files/zh-tw/web/api/geolocationposition/timestamp/index.html new file mode 100644 index 0000000000..26c72e5e14 --- /dev/null +++ b/files/zh-tw/web/api/geolocationposition/timestamp/index.html @@ -0,0 +1,93 @@ +--- +title: Position.timestamp +slug: Web/API/GeolocationPosition/timestamp +translation_of: Web/API/GeolocationPosition/timestamp +--- +
{{APIRef("Geolocation API")}}
+ +

Position.timestamp 是一個唯讀的 {{domxref("DOMTimeStamp")}} 物件, 此物件代表建立 {{domxref("Position")}} 物件的日期和時間,精確度為毫秒。

+ +

語法

+ +
coord = position.timestamp
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#timestamp', 'Position.timestamp')}}{{Spec2('Geolocation')}}Initial definition
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationpositionerror/code/index.html b/files/zh-tw/web/api/geolocationpositionerror/code/index.html new file mode 100644 index 0000000000..e561a780d0 --- /dev/null +++ b/files/zh-tw/web/api/geolocationpositionerror/code/index.html @@ -0,0 +1,120 @@ +--- +title: PositionError.code +slug: Web/API/GeolocationPositionError/code +translation_of: Web/API/GeolocationPositionError/code +--- +
{{APIRef("Geolocation API")}}
+ +

PositionError.code 是一個唯讀無符號整數(unsigned short)表示錯誤碼 。以下列出可能的值:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
相對應的常數描述
1PERMISSION_DENIED取得地理資訊失敗,因為此頁面沒有獲取地理位置信息的權限。
2POSITION_UNAVAILABLE取得地理資訊失敗,因為至少有一個地理位置信息內的資訊回傳了錯誤。
3TIMEOUT取得地理資訊超過時限,利用 {{domxref("PositionOptions.timeout")}} i來定義取得地理資訊的時限。
+ +

語法

+ +
typeErr = poserr.code
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#code', 'PositionError.code')}}{{Spec2('Geolocation')}}Initial definition
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationpositionerror/index.html b/files/zh-tw/web/api/geolocationpositionerror/index.html new file mode 100644 index 0000000000..e721bd062c --- /dev/null +++ b/files/zh-tw/web/api/geolocationpositionerror/index.html @@ -0,0 +1,128 @@ +--- +title: PositionError +slug: Web/API/GeolocationPositionError +translation_of: Web/API/GeolocationPositionError +--- +
{{APIRef("Geolocation API")}}
+ +

PositionError 介面表示使用定位設備時發生錯誤的原因。

+ +

屬性

+ +

PositionError 介面沒有繼承任何屬性

+ +
+
{{domxref("PositionError.code")}} {{readonlyInline}}
+
回傳一個無符號整數(unsigned short)來表示錯誤碼。以下列出可能的值: + + + + + + + + + + + + + + + + + + + + + + + +
相對應的常數描述
1PERMISSION_DENIED取得地理資訊失敗,因為此頁面沒有獲取地理位置信息的權限。
2POSITION_UNAVAILABLE取得地理資訊失敗,因為至少有一個地理位置信息內的資訊回傳了錯誤。
3TIMEOUT取得地理資訊超過時限,利用{{domxref("PositionOptions.timeout")}} 來定義取得地理資訊的時限。
+
+
{{domxref("PositionError.message")}} {{readonlyInline}}
+
回傳一個可讀的 {{domxref("DOMString")}} 來描述錯誤的詳細訊息。注意規格中指出此訊息是用來除錯而非直接顯示在使用者介面。
+
+ +

方法

+ +

PositionError 介面沒有實作也沒有繼承任何方法

+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#positionerror', 'PositionError')}}{{Spec2('Geolocation')}}Initial specification.
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/geolocationpositionerror/message/index.html b/files/zh-tw/web/api/geolocationpositionerror/message/index.html new file mode 100644 index 0000000000..839fb18818 --- /dev/null +++ b/files/zh-tw/web/api/geolocationpositionerror/message/index.html @@ -0,0 +1,93 @@ +--- +title: PositionError.message +slug: Web/API/GeolocationPositionError/message +translation_of: Web/API/GeolocationPositionError/message +--- +
{{APIRef("Geolocation API")}}
+ +

PositionError.message 是一個可讀的 {{domxref("DOMString")}} 來描述錯誤的詳細訊息。

+ +

語法

+ +
msg = positionError.message
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#message', 'PositionError.message')}}{{Spec2('Geolocation')}}Initial definition
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/globaleventhandlers/index.html b/files/zh-tw/web/api/globaleventhandlers/index.html new file mode 100644 index 0000000000..492ed0ae93 --- /dev/null +++ b/files/zh-tw/web/api/globaleventhandlers/index.html @@ -0,0 +1,682 @@ +--- +title: GlobalEventHandlers +slug: Web/API/GlobalEventHandlers +translation_of: Web/API/GlobalEventHandlers +--- +
{{ApiRef("HTML DOM")}}
+ +

GlobalEventHandlers(通用事件處理器)在多個介面,如 {{domxref("HTMLElement")}}、{{domxref("Document")}} 和 {{domxref("Window")}} 當中加入了共有的事件處理器屬性,這些介面皆能夠加入除了以下清單外的更多事件處理器。

+ +
+

Note: GlobalEventHandlers is a mixin and not an interface; you can't actually create an object of type GlobalEventHandlers.

+
+ +

屬性

+ +

This interface doesn't include any properties except for the event handlers listed below.

+ +

事件處理器

+ +

These event handlers are defined on the {{domxref("GlobalEventHandlers")}} mixin, and implemented by {{domxref("HTMLElement")}}, {{domxref("Document")}}, {{domxref("Window")}}, as well as by {{domxref("WorkerGlobalScope")}} for Web Workers.

+ +
+
+
{{domxref("GlobalEventHandlers.onabort")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("abort")}} event is raised.
+
{{domxref("GlobalEventHandlers.onanimationcancel")}} {{Non-standard_inline}}
+
An {{domxref("EventHandler")}} called when an {{event("animationcancel")}} event is sent, indicating that a running CSS animation has been canceled.
+
{{domxref("GlobalEventHandlers.onanimationend")}} {{Non-standard_inline}}
+
An {{domxref("EventHandler")}} called when an {{event("animationend")}} event is sent, indicating that a CSS animation has stopped playing.
+
{{domxref("GlobalEventHandlers.onanimationiteration")}} {{Non-standard_inline}}
+
An {{domxref("EventHandler")}} called when an {{event("animationiteration")}} event has been sent, indicating that a CSS animation has begun playing a new iteration of the animation sequence.
+
{{domxref("GlobalEventHandlers.onanimationstart")}} {{Non-standard_inline}}
+
An {{domxref("EventHandler")}} called when an {{event("animationstart")}} event is sent, indicating that a CSS animation has started playing.
+
{{domxref("GlobalEventHandlers.onauxclick")}} {{Non-standard_inline}}
+
An {{domxref("EventHandler")}} called when an {{event("auxclick")}} event is sent, indicating that a non-primary button has been pressed on an input device (e.g. a middle mouse button).
+
{{domxref("GlobalEventHandlers.onblur")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("blur")}} event is raised.
+
{{domxref("GlobalEventHandlers.onerror")}}
+
Is an {{domxref("OnErrorEventHandler")}} representing the code to be called when the {{event("error")}} event is raised.
+
{{domxref("GlobalEventHandlers.onfocus")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("focus")}} event is raised.
+
{{domxref("GlobalEventHandlers.oncancel")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("cancel")}} event is raised.
+
{{domxref("GlobalEventHandlers.oncanplay")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("canplay")}} event is raised.
+
{{domxref("GlobalEventHandlers.oncanplaythrough")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("canplaythrough")}} event is raised.
+
{{domxref("GlobalEventHandlers.onchange")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("change")}} event is raised.
+
{{domxref("GlobalEventHandlers.onclick")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("click")}} event is raised.
+
{{domxref("GlobalEventHandlers.onclose")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("close")}} event is raised.
+
{{domxref("GlobalEventHandlers.oncontextmenu")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("contextmenu")}} event is raised.
+
{{domxref("GlobalEventHandlers.oncuechange")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("cuechange")}} event is raised.
+
{{domxref("GlobalEventHandlers.ondblclick")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("dblclick")}} event is raised.
+
{{domxref("GlobalEventHandlers.ondrag")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("drag")}} event is raised.
+
{{domxref("GlobalEventHandlers.ondragend")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("dragend")}} event is raised.
+
{{domxref("GlobalEventHandlers.ondragenter")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("dragenter")}} event is raised.
+
{{domxref("GlobalEventHandlers.ondragexit")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("dragexit")}} event is raised.
+
{{domxref("GlobalEventHandlers.ondragleave")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("dragleave")}} event is raised.
+
{{domxref("GlobalEventHandlers.ondragover")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("dragover")}} event is raised.
+
{{domxref("GlobalEventHandlers.ondragstart")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("dragstart")}} event is raised.
+
{{domxref("GlobalEventHandlers.ondrop")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("drop")}} event is raised.
+
{{domxref("GlobalEventHandlers.ondurationchange")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("durationchange")}} event is raised.
+
{{domxref("GlobalEventHandlers.onemptied")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("emptied")}} event is raised.
+
{{domxref("GlobalEventHandlers.onended")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("ended")}} event is raised.
+
{{domxref("GlobalEventHandlers.ongotpointercapture")}}
+
+

Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("gotpointercapture")}} event type is raised.

+
+
{{domxref("GlobalEventHandlers.oninput")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("input")}} event is raised.
+
{{domxref("GlobalEventHandlers.oninvalid")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("invalid")}} event is raised.
+
{{domxref("GlobalEventHandlers.onkeydown")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("keydown")}} event is raised.
+
{{domxref("GlobalEventHandlers.onkeypress")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("keypress")}} event is raised.
+
{{domxref("GlobalEventHandlers.onkeyup")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("keyup")}} event is raised.
+
{{domxref("GlobalEventHandlers.onload")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("load")}} event is raised.
+
{{domxref("GlobalEventHandlers.onloadeddata")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("loadeddata")}} event is raised.
+
{{domxref("GlobalEventHandlers.onloadedmetadata")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("loadedmetadata")}} event is raised.
+
{{domxref("GlobalEventHandlers.onloadend")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("loadend")}} event is raised (when progress has stopped on the loading of a resource.)
+
{{domxref("GlobalEventHandlers.onloadstart")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("loadstart")}} event is raised (when progress has begun on the loading of a resource.)
+
{{domxref("GlobalEventHandlers.onlostpointercapture")}}
+
+

Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("lostpointercapture")}} event type is raised.

+
+
{{domxref("GlobalEventHandlers.onmousedown")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("mousedown")}} event is raised.
+
{{domxref("GlobalEventHandlers.onmouseenter")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("mouseenter")}} event is raised.
+
{{domxref("GlobalEventHandlers.onmouseleave")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("mouseleave")}} event is raised.
+
{{domxref("GlobalEventHandlers.onmousemove")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("mousemove")}} event is raised.
+
{{domxref("GlobalEventHandlers.onmouseout")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("mouseout")}} event is raised.
+
{{domxref("GlobalEventHandlers.onmouseover")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("mouseover")}} event is raised.
+
{{domxref("GlobalEventHandlers.onmouseup")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("mouseup")}} event is raised.
+
{{domxref("GlobalEventHandlers.onmousewheel")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("mousewheel")}} event is raised.
+
{{domxref("GlobalEventHandlers.onpause")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pause")}} event is raised.
+
{{domxref("GlobalEventHandlers.onplay")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("play")}} event is raised.
+
{{domxref("GlobalEventHandlers.onplaying")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("playing")}} event is raised.
+
{{domxref("GlobalEventHandlers.onpointerdown")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pointerdown")}} event is raised.
+
{{domxref("GlobalEventHandlers.onpointermove")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pointermove")}} event is raised.
+
{{domxref("GlobalEventHandlers.onpointerup")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pointerup")}} event is raised.
+
{{domxref("GlobalEventHandlers.onpointercancel")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pointercancel")}} event is raised.
+
{{domxref("GlobalEventHandlers.onpointerover")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pointerover")}} event is raised.
+
{{domxref("GlobalEventHandlers.onpointerout")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pointerout")}} event is raised.
+
{{domxref("GlobalEventHandlers.onpointerenter")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pointerevent")}} event is raised.
+
{{domxref("GlobalEventHandlers.onpointerleave")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pointerleave")}} event is raised.
+
{{domxref("GlobalEventHandlers.onpointerlockchange")}} {{experimental_inline}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pointerlockchange")}} event is raised.
+
{{domxref("GlobalEventHandlers.onpointerlockerror")}} {{experimental_inline}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pointerlockerror")}} event is raised.
+
{{domxref("GlobalEventHandlers.onprogress")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("progress")}} event is raised.
+
{{domxref("GlobalEventHandlers.onratechange")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("ratechange")}} event is raised.
+
{{domxref("GlobalEventHandlers.onreset")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("reset")}} event is raised.
+
{{domxref("GlobalEventHandlers.onscroll")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("scroll")}} event is raised.
+
{{domxref("GlobalEventHandlers.onseeked")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("seeked")}} event is raised.
+
{{domxref("GlobalEventHandlers.onseeking")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("seeking")}} event is raised.
+
{{domxref("GlobalEventHandlers.onselect")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("select")}} event is raised.
+
{{domxref("GlobalEventHandlers.onselectstart")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("selectionchange")}} event is raised, i.e. when the user starts to make a new text selection on a web page.
+
{{domxref("GlobalEventHandlers.onselectionchange")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("selectionchange")}} event is raised, i.e. when the text selected on a web page changes.
+
{{domxref("GlobalEventHandlers.onshow")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("show")}} event is raised.
+
{{domxref("GlobalEventHandlers.onsort")}} {{experimental_inline}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("sort")}} event is raised.
+
{{domxref("GlobalEventHandlers.onstalled")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("stalled")}} event is raised.
+
{{domxref("GlobalEventHandlers.onsubmit")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("submit")}} event is raised.
+
{{domxref("GlobalEventHandlers.onsuspend")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("suspend")}} event is raised.
+
{{domxref("GlobalEventHandlers.ontimeupdate")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("timeupdate")}} event is raised.
+
{{domxref("GlobalEventHandlers.onvolumechange")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("volumechange")}} event is raised.
+
{{domxref("GlobalEventHandlers.ontouchcancel")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("touchcancel")}} event is raised.
+
{{domxref("GlobalEventHandlers.ontouchend")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("touchend")}} event is raised.
+
{{domxref("GlobalEventHandlers.ontouchmove")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("touchmove")}} event is raised.
+
{{domxref("GlobalEventHandlers.ontouchstart")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("touchstart")}} event is raised.
+
{{domxref("GlobalEventHandlers.ontransitioncancel")}}
+
An {{domxref("EventHandler")}} called when a {{event("transitioncancel")}} event is sent, indicating that a CSS transition has been cancelled.
+
{{domxref("GlobalEventHandlers.ontransitionend")}}
+
An {{domxref("EventHandler")}} called when a {{event("transitionend")}} event is sent, indicating that a CSS transition has finished playing.
+
{{domxref("GlobalEventHandlers.onwaiting")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("waiting")}} event is raised.
+
+
+ +

方法

+ +

This interface defines no methods.

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("Selection API",'', 'Extension to GlobalEventHandlers')}}{{Spec2('Selection API')}}Adds onselectionchange.
{{SpecName('Pointer Lock', '#extensions-to-the-document-interface', 'Extension of Document')}}{{Spec2('Pointer Lock')}}Adds onpointerlockchange and onpointerlockerror on {{domxref("Document")}}. It is experimentally implemented on GlobalEventHandlers.
{{SpecName('HTML WHATWG', '#globaleventhandlers', 'GlobalEventHandlers')}}{{Spec2('HTML WHATWG')}}No change since the latest snapshot, {{SpecName("HTML5.1")}}.
{{SpecName('HTML5.1', '#globaleventhandlers', 'GlobalEventHandlers')}}{{Spec2('HTML5.1')}}Snapshot of {{SpecName("HTML WHATWG")}}. Added onsort since the {{SpecName("HTML5 W3C")}} snapshot.
{{SpecName("HTML5 W3C", "#globaleventhandlers", "GlobalEventHandlers")}}{{Spec2('HTML5 W3C')}}Snapshot of {{SpecName("HTML WHATWG")}}. Creation of GlobalEventHandlers (properties where on the target before it).
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox (Gecko)ChromeEdgeInternet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
oncanplay, oncanplaythrough, ondurationchange, onemptied, onended, onloadeddata, onloadedmetadata, onloadstart, onpause, onplay, onplaying, onprogress, onratechange, onseeked, onseeking, onstalled, ontimeupdate, onvolumechange, onwaiting{{CompatGeckoDesktop(1.9.1)}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onsuspend{{CompatGeckoDesktop(1.9.2)}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
ondrag, ondragend, ondragenter, ondragleave, ondragover, ondragstart, ondrop{{CompatGeckoDesktop(1.9.1)}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onmouseenter, onmouseleave{{CompatGeckoDesktop(10)}}{{CompatChrome(30.0)}}{{CompatUnknown}}5.517{{CompatUnknown}}
ondragexit{{CompatNo}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
oncancel{{CompatNo}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onclose{{CompatNo}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
oncuechange{{CompatNo}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onmousewheel{{CompatNo}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onsort {{experimental_inline}}{{CompatNo}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onmozfullscreenchange, onmozfullscreenerror {{non-standard_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}} {{property_prefix("-webkit")}}
+ {{CompatVersionUnknown}} (unprefixed)
{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
onpointerlockchange, onpointerlockerror{{CompatGeckoDesktop(10)}}[1]{{CompatVersionUnknown}}[2] {{property_prefix("-webkit")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onpointercancel, onpointerdown, onpointerup, onpointermove, onpointerout, onpointerover, onpointerenter, onpointerleave{{CompatVersionUnknown}}[3]{{CompatChrome(55.0)}}{{CompatVersionUnknown}}10{{CompatUnknown}}{{CompatUnknown}}
onselectionchange{{CompatGeckoDesktop(43)}}[4]{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
ontouchend, ontouchcancel, ontouchmove, ontouchstart{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
animationstart, animationend, animationcancel, animationiteration{{CompatGeckoDesktop(51)}}{{CompatVersionUnknown}} {{property_prefix("-webkit")}}
+ {{CompatVersionUnknown}} (unprefixed)
{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
ongotpointercapture, onlostpointercapture{{CompatUnknown}}{{CompatChrome(57.0)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatOpera(44)}}{{CompatUnknown}}
onauxclick{{CompatGeckoDesktop(53)}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroid WebviewEdgeFirefox Mobile (Gecko)AndroidIE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
ondrag, ondragend, ondragenter, ondragleave, ondragover, ondragstart, ondrop{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile(1.9.1)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
oncanplay, oncanplaythrough, ondurationchange, onemptied, onended, onloadeddata, onloadedmetadata, onloadstart, onpause, onplay, onplaying, onprogress, onratechange, onseeked, onseeking, onstalled, ontimeupdate, onvolumechange, onwaiting{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatGeckoMobile(1.9.1)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
onmouseenter, onmouseleave{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatGeckoMobile(10)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
onsuspend{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatGeckoMobile(1.9.2)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
ondragexit{{CompatNo}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}
oncancel{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
onclose{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
oncuechange{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
onmousewheel{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
onsort{{CompatNo}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}
onmozfullscreenchange, onmozfullscreenerror {{non-standard_inline}}{{CompatVersionUnknown}} {{property_prefix("-webkit")}}
+ {{CompatVersionUnknown}} (unprefixed)
{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatVersionUnknown}} {{property_prefix("-webkit")}}
+ {{CompatVersionUnknown}} (unprefixed)
onpointerlockchange, onpointerlockerror{{CompatNo}}{{CompatUnknown}}{{CompatGeckoMobile(10)}}[1]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}
onpointercancel, onpointerdown, onpointerup, onpointermove, onpointerout, onpointerover, onpointerenter, onpointerleave{{CompatChrome(55.0)}}{{CompatUnknown}}{{CompatVersionUnknown}}[3]{{CompatNo}}10{{CompatNo}}{{CompatNo}}{{CompatChrome(55.0)}}
onselectionchange{{CompatNo}}{{CompatUnknown}}{{CompatGeckoMobile(43)}}[4]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}
ontouchend, ontouchcancel, ontouchmove, ontouchstart{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
animationstart, animationend, animationcancel, animationiteration{{CompatVersionUnknown}} {{property_prefix("-webkit")}}
+ {{CompatVersionUnknown}} (unprefixed)
{{CompatUnknown}}{{CompatGeckoMobile(51)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}} {{property_prefix("-webkit")}}
+ {{CompatVersionUnknown}} (unprefixed)
ongotpointercapture, onlostpointercapture{{CompatChrome(57.0)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatOperaMobile(44)}}{{CompatUnknown}}{{CompatChrome(57.0)}}
onauxclick{{CompatVersionUnknown}}{{CompatNo}}{{CompatGeckoMobile(53)}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatVersionUnknown}}
+
+ +

[1] In Gecko this is implemented as onmozpointerlockchange, onmozpointerlockerror.

+ +

[2] In Blink this is implemented as onwebkitpointerlockchange, onwebkitpointerlockerror.

+ +

[3] This is implemented behind the dom.w3c_pointer_events.enabled preference, defaulting to false.

+ +

[4] This is implemented behind the dom.select_events.enabled preference, that default to false, except on Nightly.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/globaleventhandlers/onclick/index.html b/files/zh-tw/web/api/globaleventhandlers/onclick/index.html new file mode 100644 index 0000000000..d5a1ac1845 --- /dev/null +++ b/files/zh-tw/web/api/globaleventhandlers/onclick/index.html @@ -0,0 +1,144 @@ +--- +title: GlobalEventHandlers.onclick +slug: Web/API/GlobalEventHandlers/onclick +tags: + - API + - HTML DOM + - Property + - Reference +translation_of: Web/API/GlobalEventHandlers/onclick +--- +
+
{{ ApiRef("HTML DOM") }}
+
+ +
 
+ +

onclick 屬性回傳當前元件 click 事件處理器的程式碼(event handler code)。

+ +
注意: 當使用 click 事件觸發動作時,同時考慮將此動作加到 keydown 事件中,讓沒使用滑鼠或使用觸控螢幕的使用者也可以進行此動作。
+ +

語法

+ +
element.onclick = functionRef;
+
+ +

此處的 functionRef 為一個函式-通常是函式的名字或是函式表示式(function expression) 見 "JavaScript Guide:Functions" 來了解更多。

+ +

傳入事件處理函式(event handler function)的唯一引數為 {{domxref("MouseEvent")}} 物件。在這函式中,this 為觸發此事件的元件。

+ +

範例

+ +
<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <title>onclick event example</title>
+    <script>
+      function initElement() {
+        var p = document.getElementById("foo");
+        // NOTE: showAlert(); or showAlert(param); will NOT work here.
+        // Must be a reference to a function name, not a function call.
+        p.onclick = showAlert;
+      };
+
+      function showAlert(event) {
+        alert("onclick Event detected!");
+      }
+    </script>
+    <style>
+      #foo {
+        border: solid blue 2px;
+      }
+    </style>
+  </head>
+  <body onload="initElement();">
+    <span id="foo">My Event Element</span>
+    <p>click on the above element.</p>
+  </body>
+</html>
+
+ +

你也可以使用如下的匿名函式:

+ +
p.onclick = function(event) { alert("moot!"); };
+
+ +

備註

+ +

使用者點擊元件時會觸發 click 事件。click 事件發生在 mousedown 及 mouseup 事件之後。

+ +

這個屬性同一時間中只能指定一個 click 處理器(handler)。你也許會比較想使用 {{domxref("EventTarget.addEventListener()")}},因為它有更多的彈性而且是 DOM 事件規範的一部份。

+ +

規範

+ + + + + + + + + + + + + + +
規範狀態備註
{{SpecName('HTML WHATWG','webappapis.html#handler-onclick','onclick')}}{{Spec2('HTML WHATWG')}} 
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewChrome for AndroidFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
diff --git a/files/zh-tw/web/api/globaleventhandlers/onclose/index.html b/files/zh-tw/web/api/globaleventhandlers/onclose/index.html new file mode 100644 index 0000000000..abe97bcd4c --- /dev/null +++ b/files/zh-tw/web/api/globaleventhandlers/onclose/index.html @@ -0,0 +1,102 @@ +--- +title: GlobalEventHandlers.onclose +slug: Web/API/GlobalEventHandlers/onclose +tags: + - API + - HTML DOM + - Property + - Reference +translation_of: Web/API/GlobalEventHandlers/onclose +--- +
{{ApiRef("HTML DOM")}}
+ +

送至視窗的 close event 的處理器(handler)。(不支援 Firefox 2 及 Safari)

+ +

語法

+ +
window.onclose = funcRef;
+
+ +

參數

+ + + +

範例

+ +
window.onclose = resetThatServerThing;
+
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態備註
{{SpecName('HTML WHATWG','webappapis.html#handler-onclose','onclose')}}{{Spec2('HTML WHATWG')}} 
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewChrome for AndroidFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}
+
diff --git a/files/zh-tw/web/api/history/index.html b/files/zh-tw/web/api/history/index.html new file mode 100644 index 0000000000..b4a1d7603e --- /dev/null +++ b/files/zh-tw/web/api/history/index.html @@ -0,0 +1,183 @@ +--- +title: History +slug: Web/API/History +translation_of: Web/API/History +--- +
{{ APIRef("HTML DOM") }}
+ +

History 介面允許操控瀏覽器的 session history 紀錄,為當前面頁所在分頁中訪問、或於當前面頁中透過頁面框架(frame)所載入的頁面。

+ +

屬性

+ +

The History interface doesn't inherit any property.

+ +
+
{{domxref("History.length")}} {{readOnlyInline}}
+
Returns an Integer representing the number of elements in the session history, including the currently loaded page. For example, for a page loaded in a new tab this property returns 1.
+
{{domxref("History.current")}} {{readOnlyInline}} {{ non-standard_inline() }} {{ obsolete_inline(26) }}
+
Returns a {{domxref("DOMString")}} representing the URL of the active item of the session history. This property was never available to web content and is no more supported by any browser. Use {{domxref("Location.href")}} instead.
+
{{domxref("History.next")}} {{readOnlyInline}} {{ non-standard_inline() }} {{ obsolete_inline(26) }}
+
Returns a {{domxref("DOMString")}} representing the URL of the next item in the session history. This property was never available to web content and is not supported by other browsers.
+
{{domxref("History.previous")}} {{readOnlyInline}} {{ non-standard_inline() }} {{ obsolete_inline(26) }}
+
Returns a {{domxref("DOMString")}} representing the URL of the previous item in the session history. This property was never available to web content and is not supported by other browsers.
+
{{domxref("History.scrollRestoration")}} {{experimental_inline}}
+
Allows web applications to explicitly set default scroll restoration behavior on history navigation. This property can be either auto or manual.
+
{{domxref("History.state")}} {{readOnlyInline}} {{ gecko_minversion_inline("2.0") }}
+
Returns an any value representing the state at the top of the history stack. This is a way to look at the state without having to wait for a {{event("popstate")}} event.
+
+ +

方法

+ +

The History interface doesn't inherit any methods.

+ +
+
{{domxref("History.back()")}}
+
回到 session history 紀錄中的前一頁,等同於使用者按下瀏覽器的上一頁按鈕。相當於 history.go(-1)。 +
Calling this method to go back beyond the first page in the session history has no effect and doesn't raise an exception.
+
+
{{domxref("History.forward()")}}
+
回到 session history 紀錄中的下一頁,等同於使用者按下瀏覽器的下一頁按鈕。相當於 history.go(1)。 +
Calling this method to go forward beyond the most recent page in the session history has no effect and doesn't raise an exception.
+
+
{{domxref("History.go()")}}
+
自 session history 紀錄中載入一個頁面,利用該頁面相對於目前頁面的所在位置,例如 -1 為前一頁或 1 為下一頁。若指定了一個超出範圍的值(舉例來說,在 session history 沒有先前訪頁面的情況下指定 -1),此方法將會是靜默(不會產生錯誤)且沒有任何效果的。不帶參數或是傳入 0 呼叫 go() 會重新載入目前頁面。Internet Explorer 也可以傳入字串來前往一個於瀏覽歷史列表中指定的頁面。
+
{{domxref("History.pushState()")}} {{ gecko_minversion_inline("2.0") }}
+
插入給定的資料與指定的標題(title)以及選擇性的 URL 至 session history 堆疊(stack)中。給定的資料將被 DOM 視為不透明的(opaque);可以指定任何可被序列化的 JavaScript 物件。請注意 Firefox 目前會忽略標題(title)參數;更多資訊請參閱操控瀏覽器歷史紀錄
+
{{domxref("History.replaceState()")}} {{ gecko_minversion_inline("2.0") }}
+
以指定的資料、標題(title)及可選的 URL 來更新歷史紀錄堆疊(history stack)中近期的項目。給定的資料將被 DOM 視為不透明的(opaque);可以指定任何可被序列化的 JavaScript 物件。請注意 Firefox 目前會忽略標題(title)參數;更多資訊請參閱操控瀏覽器歷史紀錄
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', "browsers.html#the-history-interface", "History")}}{{Spec2('HTML WHATWG')}}Adds the scrollRestoration attribute.
{{SpecName('HTML5 W3C', "browsers.html#the-history-interface", "History")}}{{Spec2('HTML5 W3C')}}Initial definition.
{{SpecName('Custom Scroll Restoration', '#web-idl', "History")}}{{Spec2('Custom Scroll Restoration')}}Adds the scrollRestoration attribute.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
pushState and replaceState{{CompatChrome(5.0)}}{{CompatVersionUnknown}}4.0 [1]1011.55
scrollRestoration{{CompatChrome(46.0)}}{{CompatNo}}{{CompatGeckoDesktop("46.0")}}{{CompatNo}}33{{CompatVersionUnknown}}[2]
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari MobileChrome for Android
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
pushState and replaceState2.2{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}10{{CompatVersionUnknown}}4.3{{CompatVersionUnknown}}
scrollRestoration{{CompatNo}}{{CompatChrome(46.0)}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}[2]{{CompatChrome(46.0)}}
+
+ +

[1] In Firefox 2 through 5, the passed object is serialized using JSON. Starting in Firefox 6, the object is serialized using the structured clone algorithm. This allows a wider variety of objects to be safely passed.

+ +

[2] WebKit bug 147782

+ +

參見

+ + diff --git a/files/zh-tw/web/api/history_api/index.html b/files/zh-tw/web/api/history_api/index.html new file mode 100644 index 0000000000..2554fe6801 --- /dev/null +++ b/files/zh-tw/web/api/history_api/index.html @@ -0,0 +1,255 @@ +--- +title: 操控瀏覽器歷史紀錄 +slug: Web/API/History_API +tags: + - DOM + - HTML5 + - History +translation_of: Web/API/History_API +--- +

DOM {{ domxref("window") }} 物件透過 {{ domxref("window.history", "history") }} 物件,提供了進入瀏覽歷史的方式。他透過一些方便的屬性與方法,讓你可以在歷史紀錄中往上一步或往下一步移動,並且讓你——從 HTML5 開始——能操作歷史紀錄堆疊(history stack)的內容。

+ +

在歷史紀錄中移動

+ +

往前往後歷史紀錄可以用 back(), forward(), 和 go() 的方法。

+ +

往前往後

+ +

要在歷史紀錄中往上一步移動,可以:

+ +
window.history.back();
+
+ +

這完全等同於用戶在瀏覽器上點選「上一頁」按鈕。

+ +

同樣的,你也可以往下一步移動(等同於用戶點擊往後一頁的按鈕):

+ +
window.history.forward();
+
+ +

移動到特定的歷史紀錄

+ +

你可以用 go() 方法來從頁面的 session history 紀錄中載入特定紀錄,以目前頁面的相對位置而定(目前的頁面想當然爾是 index 0)。

+ +

往前一頁(等同於呼叫 back()):

+ +
window.history.go(-1);
+
+ +

往後一頁(等同於呼叫 forward()):

+ +
window.history.go(1);
+
+ +

同樣的你也可以傳入 2,讓頁面直往後兩頁,依此類推。

+ +

你可以查看 length 這個屬性來取得目前瀏覽歷史的總數我:

+ +
var numberOfEntries = window.history.length;
+
+ +
備註:Internet Explorer 支援在 go() 中以 URL 的值作為參數;這不在標準中,Gecko 也不支援。
+ +

加入和修改歷史紀錄

+ +

{{ gecko_minversion_header("2") }}

+ +

HTML5 加入了 history.pushState()history.replaceState() 方法,讓你可以加入或修改歷史紀錄。這些方法都可以跟 {{ domxref("window.onpopstate") }} 事件一同應用。

+ +

使用 history.pushState()後,會改變 XMLHttpRequest 時 HTTP 標頭中 referrer 的值。referrer 會是創造 XMLHttpRequest 物件時的當前視窗文件(this)的 URL。

+ +

pushState() 方法範例

+ +

假設 http://mozilla.org/foo.html 執行了下面的 JavaScript:

+ +
var stateObj = { foo: "bar" };
+history.pushState(stateObj, "page 2", "bar.html");
+
+ +

這會讓網址列顯示 http://mozilla.org/bar.html,但不會讓瀏覽器去載入 bar.html,甚或去檢查 bar.html 存在與否。

+ +

假設現在使用者瀏覽到 http://google.com,然後點擊上一頁鈕。這時網址列會顯示 http://mozilla.org/bar.html,頁面會獲得 popstate 的事件(state object 會包含一份 stateObj 的副件)。頁面長得跟 foo.html 很像,但是可能在 popstate 事件執行中被修改。

+ +

如果我再點一次上一頁鈕, 網址會改變成為 http://mozilla.org/foo.html,且文件會得到另外一個 popstate 事件,此次會包含一個 null state object。同樣的,回上頁鈕不會改變文件的內容,只是文件可能會在 popstate 事件中被手動更新。

+ +

pushState() 方法

+ +

pushState() 取用三個參數:一個 state 物件、title(目前忽略)與 URL(可選用)。我們來看看三個參數的細節之處:

+ + + +
備註:在 Gecko 2.0 {{ geckoRelease("2.0") }} 到 Gecko 5.0 {{ geckoRelease("5.0") }},是採用 JSON 來序列化這個傳送的物件。從 Gecko 6.0 {{ geckoRelease("6.0") }} 開始,這個物件是以 the structured clone algorithm 序列化。這會允許更多種不同的物件可以被安全的傳送。
+ +

從某種意義上,呼叫 pushState() 與設定 window.location = "#foo" 是類似的,兩個都會去建立和啟用另一個和目前文件有關的歷史紀錄。但是 pushState() 有一些優勢:

+ + + +

注意 pushState() 永遠不會造成一個 hashchange 事件被觸發,即使新的 URL 和舊的 URL 的不同處只有 hash 的部份也不會。

+ +

In a XUL document, it creates the specified XUL element.

+ +

In other documents, it creates an element with a null namespace URI.

+ +

replaceState() 方法

+ +

history.replaceState() 的執行就像 history.pushState() ,除了 replaceState() 是修改目前的歷史紀錄而不是創造一個新的。

+ +

replaceState() 很實用的時機是當你要更新目前歷史紀錄的 state object 或是URL來反應一些使用者的動作時。

+ +
備註:在 Gecko 2.0 {{ geckoRelease("2.0") }} 到 Gecko 5.0 {{ geckoRelease("5.0") }},是採用 JSON 來序列化這個傳送的物件。從 Gecko 6.0 {{ geckoRelease("6.0") }} 開始, 這個物件是以 the structured clone algorithm 序列化。這會允許更多種不同的物件可以被安全的傳送。
+ +

replaceState() 方法範例

+ +

Suppose http://mozilla.org/foo.html executes the following JavaScript:

+ +
var stateObj = { foo: "bar" };
+history.pushState(stateObj, "page 2", "bar.html");
+
+ +

The explanation of these two lines above can be found at "Example of pushState() method" section. Then suppose http://mozilla.org/bar.html executes the following JavaScript:

+ +
history.replaceState(stateObj, "page 3", "bar2.html");
+
+ +

This will cause the URL bar to display http://mozilla.org/bar2.html, but won't cause the browser to load bar2.html or even check that bar2.html exists.

+ +

Suppose now that the user now navigates to http://www.microsoft.com, then clicks back. At this point, the URL bar will display http://mozilla.org/bar2.html. If the user now clicks back again, the URL bar will display http://mozilla.org/foo.html, and totaly bypass bar.html.

+ +

popstate 事件

+ +

每次 active 的歷史紀錄被更動的時候,一個 popstate 事件會被發送到目前的 window。如果被啟用的歷史紀錄是由於呼叫 pushState 建立的或是呼叫 replaceState 所影響的,這個 popstate 事件的 state 屬性會含有一個歷史紀錄的 state object 的副本。

+ +

使用範例參閱 {{ domxref("window.onpopstate") }}。

+ +

讀取目前的 state

+ +

當你讀取頁面的時候,可能會有 non-null state 的物件。這會發生在,例如說,如果設定一個 state 物件(用 pushState() 或是 replaceState()),然後使用者重新啟動他的瀏覽器。當重新讀取你的頁面的時候,頁面會得到一個 onload 事件,但是沒有 popstate 事件。然而,如果你讀取了 history.state 屬性,你會得到像是 popstate 被觸發時,你會得到的 state object 。

+ +

像這樣使用 history.state 屬性,你可以讀取目前的歷史紀錄的狀態而不需要等待一個 popstate 事件:

+ +
var currentState = history.state;
+
+ +

範例

+ +

完整的 AJAX 網站範例 ,請參閱:Ajax navigation example

+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', "browsers.html#history", "History")}}{{Spec2('HTML WHATWG')}}No change from {{SpecName("HTML5 W3C")}}.
{{SpecName('HTML5 W3C', "browsers.html#history", "History")}}{{Spec2('HTML5 W3C')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
replaceState, pushState5{{CompatVersionUnknown}}{{ CompatGeckoDesktop("2.0") }}1011.505.0
history.state18{{CompatVersionUnknown}}{{ CompatGeckoDesktop("2.0") }}1011.506.0
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
replaceState, pushState{{ CompatUnknown() }}{{CompatVersionUnknown}}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
history.state{{ CompatUnknown() }}{{CompatVersionUnknown}}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +

參見

+ + + +

{{ languages( { "ja": "ja/DOM/Manipulating_the_browser_history"} ) }}

diff --git a/files/zh-tw/web/api/html_drag_and_drop_api/drag_operations/index.html b/files/zh-tw/web/api/html_drag_and_drop_api/drag_operations/index.html new file mode 100644 index 0000000000..c609d6f4d4 --- /dev/null +++ b/files/zh-tw/web/api/html_drag_and_drop_api/drag_operations/index.html @@ -0,0 +1,336 @@ +--- +title: 拖曳操作 +slug: Web/API/HTML_Drag_and_Drop_API/Drag_operations +translation_of: Web/API/HTML_Drag_and_Drop_API/Drag_operations +--- +

{{DefaultAPISidebar("HTML Drag and Drop API")}}

+ +

本文會一一說明拖曳各步驟的作業。

+ +

The drag operations described in this document use the {{domxref("DataTransfer")}} interface. This document does not use the {{domxref("DataTransferItem")}} interface nor the {{domxref("DataTransferItemList")}} interface.

+ +

Draggable 屬性

+ +

網頁中有些預設的拖曳行為,例如文字選擇、圖片或超連結,當拖曳圖片或超連結時,圖片或超連結的 URL 會被當作拖曳作業中所攜帶的資料,而其他類型元素則必須另外處理才能拖曳,試試看選擇網頁某一部分,然後按住滑鼠鍵來進行拖曳,依據OS不同,或許會有一些跟著滑鼠移動的效果,但這僅僅只是預設效果行為,實際上沒有任何資料跟著被拖曳。

+ +

In HTML, apart from the default behavior for images, links, and selections, no other elements are draggable by default. In XUL, all elements are draggable.

+ +

除了文字選擇、圖片或超連結之外,沒有元素預設是可拖曳的。所以要讓一個元素可以拖曳,有幾件事必須要做:

+ + + +

以下是一段簡單的範例。

+ +
<div draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
+  This text <strong>may</strong> be dragged.
+</div>
+
+ +

draggable 為 true後,該 DIV 元素便可以拖曳,反之,倘若 draggable 為 false 或無設定則不可拖曳,只有其中下含的文字可以被選擇。draggable 屬性適用於任何元素,一般來說預設為false,除了圖片和連結預設為 true,所以說如果想要阻止圖片和連結被拖曳,則可以設定draggable 為 false。

+ +

請注意,一旦元素被定為可拖曳之後,其下內含的文字或其他元素便無法像平常一樣用滑鼠選擇,使用者之能夠改用鍵盤或按住 Alt 鍵搭配滑鼠進行選擇。

+ +

至於 XUL 元素則是預設皆可拖曳。

+ +
<button label="Drag Me" ondragstart="event.dataTransfer.setData('text/plain', 'Drag Me Button');">
+
+ +

開始拖曳

+ +

下方範例在dragstart註冊一個事件處理器。

+ +
<div draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
+  This text <strong>may</strong> be dragged.
+</div>
+
+ +

當拖曳作業開始,dragstart 事件會觸發,然後我們可以在事件處理器中準備好我們所要攜帶的資料、想要的拖曳回饋效果,不過基本上其實只需要準備資料就好,因為預設拖曳回饋效果已經足以應付大多數的狀況,此外,我們也可以改在上一層父元素註冊事件處理器,因為拖曳事件會上向傳遞 ( Bubble up ) 。

+ +

拖曳資料

+ +

所有的拖曳事件物件都有一個 dataTransfer 屬性,這個屬性是用來攜帶資料。

+ +

當拖曳時,資料必須和被拖曳目標作連結,比如說拖曳文字框中反白選擇的文字,那麼文字本身便是連結資料,同理,拖曳連結時URL便是連結資料。

+ +

資料包含兩個部分,一是資料型態(或格式)、二是資料值。所謂資料型態是用文字描述資料型態(如text/plain代表文字資料),而資料值則是文字,要加入拖資料需要提供資料的型態和內容值;有了資料後,我們可以在dragenter或dragover事件處理器中,透過檢查資料型態來決定是否可以接受後續的放置操作,比如說只接受連結類資料的拖目標區(drop target),會檢查資料型態是否為text/uri-list

+ +

資料型態符合MIME型態,如text/plainimage/jpeg等等,而我們自己也可以自定義其他型態,最常使用的型態請見推薦拖曳資料型態

+ +

一趟拖曳作業中可以攜帶多個多種型態的資料,所以我們可以自定義自己的型態同時,還提供其他資料給不認得自定義資料型態的其他拖曳目標區使用。通常最通用的資料會是文字類型資料。

+ +

呼叫setData方法,傳入資料型態和資料,這樣就可以攜帶想要的資料了:

+ +
event.dataTransfer.setData("text/plain", "Text to drag");
+
+ +

上例資料是”Text to drag”文字,型態是text/plain。

+ +

呼叫多次setData我們就可以攜帶多種資料。

+ +
var dt = event.dataTransfer;
+dt.setData("application/x-bookmark", bookmarkString);
+dt.setData("text/uri-list", "http://www.mozilla.org");
+dt.setData("text/plain", "http://www.mozilla.org");
+
+ +

這裡加入了三種資料,第一種是自定義的”application/x-bookmark”,雖然有更豐富的內容可使用,但只有我們自己認識,而另外我們又為其他網站或應用加入了兩種比較常見的資料,”text/uri-list”以及”text/plain”。

+ +

如果對同一種資料型態加入兩次資料,則新加資料會取代舊資料。

+ +

呼叫clearData會清除資料。

+ +
event.dataTransfer.clearData("text/uri-list");
+
+ +

如果呼叫clearData時有傳入資料型態,則只會清除該型態資料,如果沒有傳入任何型態,則所有資料皆會被清除。

+ +

設定拖曳圖片

+ +

當拖曳進行中,以拖曳元素為基礎,一個半透明的圖片會自動產生出來,並且跟著滑鼠移動。如果想要,我們也可以呼叫setDragImage()來指定我們自己的拖曳使用圖片。

+ +
event.dataTransfer.setDragImage(image, xOffset, yOffset);
+
+ +

setDragImage需要三個參數,一是圖片來源(通常是圖片元素,但也可以是canvas元素或其他元素),拖曳使用圖片會依照圖片來源在螢幕上所顯示的樣子產生;二和三是圖片相對於滑鼠指標的位置位移量。

+ +

不過也是能夠使用文件外部的圖片或canvas元素,當需要透過canvas元素產生客製圖片時,這個技巧很有用,如下範例所示:

+ +
function dragWithCustomImage(event) {
+  var canvas = document.createElementNS("http://www.w3.org/1999/xhtml","canvas");
+  canvas.width = canvas.height = 50;
+
+  var ctx = canvas.getContext("2d");
+  ctx.lineWidth = 4;
+  ctx.moveTo(0, 0);
+  ctx.lineTo(50, 50);
+  ctx.moveTo(0, 50);
+  ctx.lineTo(50, 0);
+  ctx.stroke();
+
+  var dt = event.dataTransfer;
+  dt.setData('text/plain', 'Data to Drag');
+  dt.setDragImage(canvas, 25, 25);
+}
+
+ +

上面我們的canvas是50 x 50px大小,然後我們位移一半25讓圖片落在滑鼠指標中央。 

+ +

{{h2_gecko_minversion("使用XUL panel元素作為拖曳圖片", "9.0")}}

+ +

在Gecko上開發,比如說外掛或Mozllia應用程式,Gecko9.0{{geckoRelease("9.0")}}支援使用{{XULElem("panel")}}元素作為拖曳圖片,簡單將XUL panel元素傳入setDragImage方法即可。

+ +

試想下面這個 {{XULElem("panel")}}元素:

+ +
<panel id="panel" style="opacity: 0.6">
+  <description id="pb">Drag Me</description>
+</panel>
+
+<vbox align="start" style="border: 1px solid black;" ondragstart="startDrag(event)">
+  <description>Drag Me</description>
+</vbox>
+
+ +

當使用者拖曳{{XULElem("vbox")}} 元素時,startDrag函數會被呼叫。

+ +
function startDrag(event) {
+  event.dataTransfer.setData("text/plain", "<strong>Body</strong>");
+  event.dataTransfer.setDragImage(document.getElementById("panel"), 20, 20);
+}
+
+ +

我們用HTML格式的"<strong>Body</strong>"作為資料,然後用pnael元素作為圖片。

+ +

拖曳效果

+ +

拖曳作業有好機種;copy作業代表被拖曳資料會被複製一份到拖曳目標區,move作業代表移動被拖曳的資料,link作業代表拖曳來源區和拖曳目標區有某種關係。

+ +

在dragstart事件中可以設定effectAllowed屬性,指定拖曳源頭允許的作業。

+ +
event.dataTransfer.effectAllowed = "copy";
+
+ +

上面只有copy被允許,但還有其他種類:

+ +

     只能移動或連結。

+ +
+
none
+
不允許任何作業。
+
copy
+
只能複製。
+
move
+
只能移動。
+
link
+
只有連結。
+
copyMove
+
只能複製或移動。
+
copyLink
+
只能複製或連結。
+
linkMove
+
all
+
複製、移動或連結皆可。
+
+ +

effectAllowed 屬性預設所有作業都接受,如all值。

+ +

在dragenter或dragover事件中,我們可以藉由檢查effectAllowed來知道那些作業是被允許的,另外,另一個相關聯的dropEffect屬性應該要是effectAllowed的其中一個作業,但是dropEffect不接受多重作業,只可以是none, copy, move和link。

+ +

dropEffect屬性會在在dragenter以及dragover事件中初始化為使用者想要執行的作業效果,使用者能夠透過按鍵(依平台不同,通常是Shift或Ctrl鍵),在複製、移動、連接作業之間切換,同時滑鼠指標也會跟著相應變換,例如複製作業的滑鼠旁會多出一個+的符號。

+ +

effectAllowed和dropEffect屬性可以在dragenter或dragover事件中更改,更改effectAllowed屬性能讓拖曳作業只能在支援被允許作業類型的拖曳目標上執行,好比說effectAllowed為copyMove的作業就會阻止使用者進行link類型的作業。

+ +

我們也可以更改dropEffect來強迫使用者執行某項作業,而且應該要是effectAllowed所列舉的作業。

+ +
event.dataTransfer.effectAllowed = "copyMove";
+event.dataTransfer.dropEffect = "copy";
+
+ +

上面的範例中copy就是會被執行的作業效果。

+ +

若effectAllowed或dropEffect為none,那麼沒有放置作業可以被執行。

+ +

指定拖曳目標

+ +

dragenter和dragover事件就是用來指定拖曳目標區,也就是放置資料的目標區,絕大多數的元素預設的事件都不准放置資料。

+ +

所以想要放置資料到元素上,就必須取消預設事件行為。取消預設事件行為能夠藉由回傳false或呼叫event.preventDefault方法。

+ +
<div ondragover="return false">
+<div ondragover="event.preventDefault()">
+
+ +

通常我們只有在適當的時機點才需要呼叫event.preventDefault方法、取消預設事件行為,比如說被拖曳進來的是連結。所以檢查被拖曳進來的物件,當符合條件後再來取消預設事件行為。

+ +

藉由檢查拖曳資料型態來決定是否允許放置,是最常見的作法。dataTransfer物件的types屬性是一個拖曳資料型態的列表,其中順序按照資料被加入之先後排序。

+ +
function doDragOver(event)
+{
+  var isLink = event.dataTransfer.types.contains("text/uri-list");
+  if (isLink)
+    event.preventDefault();
+}
+
+ +

上面我們呼叫contains方法檢察text/uri-list是否存在拖曳資料型態的列表之內,有的話才取消預設行為、准許放置作業,否則,不取消預設行為、不准許放置作業。

+ +

檢查拖曳資料型態後,我們也可以依此更動effectAllowed和dropEffect屬性,只不過,如果沒有取消預設行為,更動並不會有甚麼影響。

+ +

Updates to DataTransfer.types

+ +

Note that the latest spec now dictates that {{domxref("DataTransfer.types")}} should return a frozen array of {{domxref("DOMString")}}s rather than a {{domxref("DOMStringList")}} (this is supported in Firefox 52 and above).

+ +

As a result, the contains method no longer works on the property; the includes method should be used instead to check if a specific type of data is provided, using code like the following:

+ +
if ([...event.dataTransfer.types].includes('text/html')) {
+  // Do something
+}
+ +

You could always use some feature detection to determine which method is supported on types, and run code as appropriate.

+ +

放置回饋

+ +

有好幾種方法回饋使用者,告訴使用者甚麼元素可以接受放置作業,最簡單的是滑鼠會指標會自動變換樣式(視平台而定)。

+ +

滑鼠指標提示雖然夠用了,不過有時我們還是會想做其他UI上的樣式變化。-moz-drag-over的CSS pseudo-class便可以應用在拖曳目標元素上。

+ +
.droparea:-moz-drag-over {
+  border: 1px solid black;
+}
+
+ +

當目標元素的dragenter預設事件有被取消時,這個pseudo-class就會啟動,目標UI會套用1px的黑色border,請注意dragover並不會檢查這項設定。

+ +

其他比如說插入圖片等,在dragenter事件內執行更多更複雜的樣式變化也是可以的。

+ +

倘若想要做出圖片更著滑鼠在拖曳目標區上面移動的效果,那麼可以在dragover事件內來取得的clientXclientY的滑鼠座標資訊。

+ +

最後,應該要在dragleave事件內復原之前所做樣式變更,dragleave事件不需要取消預設事件行為、永遠都會觸發,即使拖曳被取消了;至於使用-moz-drag-over的CSS方法的話,樣式復原會自動執行,不用擔心。

+ +

執行放置作業

+ +

當使用者在拖曳目標區上放開滑鼠時,drop事件就會觸發。當drop事件發生,我們需要取出被丟入的資料,然後處理之。

+ +

要取出被丟入的資料,那就要呼叫dataTransfer物件的getData方法。getData方法接受資料型態的參數,它會回傳setData所存入的對應資料型態的資料,倘若沒有對應型態資料,那空字串就會被回傳。

+ +
function onDrop(event)
+{
+  var data = event.dataTransfer.getData("text/plain");
+  event.target.textContent = data;
+  event.preventDefault();
+} 
+ +

上面的範例會取出文字資料,假設拖曳目標區是文字區域,例如p或div元素,那麼資料就會被當作文字內容,插入目標元素之中。

+ +

網頁之中,如果我們已經處理過放置資料,那應該要呼叫{preventDefault}方法防止瀏覽器再次處理資料,比如說,Firefox預設是會開啟拖入的連結,但我們可以取消這項預設行為來避免開啟連結。

+ +

當然也可以取得其他種類資料來使用,比如說連結資料,text/uri-list

+ +
function doDrop(event)
+{
+  var links = event.dataTransfer.getData("text/uri-list").split("\n");
+  for each (var link in links) {
+    if (link.indexOf("#") == 0)
+      continue;
+
+    var newlink = document.createElement("a");
+    newlink.href = link;
+    newlink.textContent = link;
+    event.target.appendChild(newlink);
+  }
+  event.preventDefault();
+}
+
+ +

上面的範例取得連結資料,然後生成連結元素、加入頁面。從text/uri-list字面上不難猜出這種資料是一行行的URL,所以我們呼叫split方法拆開一行行的URL,再將URL一個一個加入頁面。請注意我們有避開開頭為”#”字元的註解。

+ +

更簡單的作法是採用特別URL型態。URL型態是一個特殊簡寫用途形態,它不會出現在{types}屬性中,但它可以方便的取得第一個連結,如下:

+ +
var link = event.dataTransfer.getData("URL");
+
+ +

這個作法能夠省去檢查註解和一個一個掃過URL,但只會得到第一個URL。

+ +

下面的例子會從多個支援的資料型態中,找出支援的資料。

+ +
function doDrop(event)
+{
+  var types = event.dataTransfer.types;
+  var supportedTypes = ["application/x-moz-file", "text/uri-list", "text/plain"];
+  types = supportedTypes.filter(function (value) types.contains(value));
+  if (types.length)
+    var data = event.dataTransfer.getData(types[0]);
+  event.preventDefault();
+}
+ +

完成拖曳

+ +

拖曳作業完成後,不論成功或取消於否,被拖曳元素的dragend事件都會觸發,如果想要判別作業是否完成,可以檢查dropEffect屬性,若是dropEffect為none,代表拖曳作業被取消,否則dropEffect的值代表所完成的作業類型。

+ +

有一個Gecko專屬的mozUserCancelled屬性,當使用者按ESC鍵取消拖曳後,這個屬性會為true,但若是因其他理由被取消或成功,則為false

+ +

拖曳作業的放置可以發生在同一個視窗或其他應用程式,而且dragend事件還是會觸發,不過事件中的screenXscreenY屬性會是放置發生點的資訊。

+ +

當dragend事件結束傳遞後,拖曳作業也完成了。

+ +

[1] 在Gecko,如果被拖曳元素在拖曳作業還在進行中移動或刪除,那麼dragend事件就不會觸發。bug 460801

+ +
+ + +
 
+ +
 
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/html_drag_and_drop_api/index.html b/files/zh-tw/web/api/html_drag_and_drop_api/index.html new file mode 100644 index 0000000000..ac7be3f0b0 --- /dev/null +++ b/files/zh-tw/web/api/html_drag_and_drop_api/index.html @@ -0,0 +1,249 @@ +--- +title: HTML 拖放 API +slug: Web/API/HTML_Drag_and_Drop_API +translation_of: Web/API/HTML_Drag_and_Drop_API +--- +

{{DefaultAPISidebar("HTML Drag and Drop API")}}

+ +

HTML 拖放介面能讓網頁應用程式於 Firefox 及其他瀏覽器中使用拖放功能。舉例來說,使用者可以利用此功能以滑鼠選擇可拖曳(draggable)元素,拖曳至一個可放置(droppable)元素上,並放開滑鼠按鍵來放置此元素。在拖曳操作時,一個半透明的可拖曳(draggable)元素會跟隨著滑鼠游標。

+ +

對於網站、擴充套件以及 XUL 應用程式來說,你可以自定義能成為可拖曳(draggable)的元素類型、可拖曳(draggable)元素產生的回鐀類型,以及可放置(droppable)的元素。

+ +

此文件為 HTML 拖放的概述,包含了相關介面的說明、在應用程式中加入拖放支援的基本步驟,以及相關介面使用簡介。

+ +

拖曳事件

+ +

HTML 拖放操作基於 {{domxref("Event","DOM 事件模型")}}並且使用繼承自{{domxref("MouseEvent","滑鼠事件")}}的{{domxref("DragEvent","拖曳事件")}}介面。一個典型的拖曳操作開始於使用者利用滑鼠選取了一個可拖曳(draggable)元素、移動滑鼠至一個可放置(droppable)元素並放開滑鼠按鍵。在操作的過程中,會觸發多種類型的事件,且一些事件類型可能會被觸發多次(如 {{event("drag")}} 及 {{event("dragover")}} 事件類型)。

+ +

所有的拖曳事件類型都有相關的通用事件處理器(global event handler)。每一種拖曳事件類型及拖曳通用事件處理器屬性都有說明此事件的參考文件。以下的表格提供了每一種事件的簡要說明,以及參考文件的連結。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
事件事件處理器屬性說明
{{event('drag')}}{{domxref('GlobalEventHandlers.ondrag','ondrag')}}於一個元素或文字選取區塊被拖曳時觸發。
{{event('dragend')}}{{domxref('GlobalEventHandlers.ondragend','ondragend')}}於拖曳操作結束時觸發(如放開滑鼠按鍵或按下鍵盤的 escape 鍵)。(請參考結束拖曳。)
{{event('dragenter')}}{{domxref('GlobalEventHandlers.ondragenter','ondragenter')}}於一個元素或文字選取區塊被拖曳移動進入一個有效的放置目標時觸發。(請參考指定拖曳目標。)
{{event('dragexit')}}{{domxref('GlobalEventHandlers.ondragexit','ondragexit')}}當一個元素不再是被選取中的拖曳元素時觸發。
{{event('dragleave')}}{{domxref('GlobalEventHandlers.ondragleave','ondragleave')}}於一個元素或文字選取區塊被拖曳移動離開一個有效的放置目標時觸發。
{{event('dragover')}}{{domxref('GlobalEventHandlers.ondragover','ondragover')}}於一個元素或文字選取區塊被拖曳移動經過一個有效的放置目標時觸發(每幾百毫秒觸發一次)。
{{event('dragstart')}}{{domxref('GlobalEventHandlers.ondragstart','ondragstart')}}於使用者開始拖曳一個元素或文字選取區塊時觸發。(請參考開始拖曳。)
{{event('drop')}}{{domxref('GlobalEventHandlers.ondrop','ondrop')}}於一個元素或文字選取區塊被放置至一個有效的放置目標時觸發。(請參考執行放置。)
+ +

注意:dragstartdragend 事件,在把檔案從作業系統拖放到瀏覽器時,並不會觸發。

+ +

介面

+ +

HTML 拖放介面有 {{domxref("DragEvent")}}、{{domxref("DataTransfer")}}、{{domxref("DataTransferItem")}} 以及 {{domxref("DataTransferItemList")}}。

+ +

{{domxref("DragEvent")}} 介面擁有一個建構式及一個屬性-{{domxref("DragEvent.dataTransfer","dataTransfer")}} 屬性為一個 {{domxref("DataTransfer")}} 物件。{{domxref("DataTransfer")}} 物件包含了拖放事件的狀態,如正在進行的拖放事件類型(例如 copymove)、拖放中的資料(一或多個項目)以及每一個拖放項目(drag item)的檔案類型(MIME type)。{{domxref("DataTransfer")}} 物件也擁有加入及移除拖放資料項目的方法。{{domxref("DragEvent")}} 與 {{domxref("DataTransfer")}} 介面應該是唯一須要加至應用程式中的 HTML 拖放功能。另外,請留意 Firefox 支援了一些 {{anch("Gecko specific interfaces","Gecko-specific 擴充")}}予 {{domxref("DataTransfer")}} 物件使用,雖然這些擴充只能在 Firefox 上作用。

+ +

每個 {{domxref("DataTransfer")}} 物件都包含了 {{domxref("DataTransfer.items","items")}} 屬性。此屬性乃 {{domxref("DataTransferItem")}} 物件的 {{domxref("DataTransferItemList","list")}}。而每個 {{domxref("DataTransferItem")}} 物件,則代表著一個拖放單元,每個拖放單元則擁有代表該資料種類的 {{domxref("DataTransferItem.kind","kind")}} 屬性(stringfile)、還有表示該單元檔案類型(如 MIME)的{{domxref("DataTransferItem.type","type")}} 屬性。另外,{{domxref("DataTransferItem")}} 物件能取得拖放單元的資料。

+ +

{{domxref("DataTransferItemList")}} 物件為 {{domxref("DataTransferItem")}} 的列表。該物件列表擁有以下方法:給列表增加拖放單元、從列表刪除拖放單元、還有清除列表內所有的拖放單元。

+ +

{{domxref("DataTransfer")}} 與 {{domxref("DataTransferItem")}} 介面的最大不同,就是前者使用同步的 {{domxref("DataTransfer.getData","getData()")}} 方法訪問拖放單元的資料;後者則使用非同步的 {{domxref("DataTransferItem.getAsString","getAsString()")}} 方法訪問。

+ +

注意:{{domxref("DragEvent")}} 與 {{domxref("DataTransfer")}} 介面受廣泛的桌面瀏覽器支援。但只有少數瀏覽器支援 {{domxref("DataTransferItem")}} 與 {{domxref("DataTransferItemList")}} 介面。請參見 {{anch("Interoperability")}} 以取得有關拖放功能互通性的資訊。

+ +

Gecko-specific interfaces

+ +

Mozilla and Firefox support some features not in the standard drag and drop model. These are convenience functions to facilitate dragging multiple items and dragging non-string data (such as files). For more information, see Dragging and Dropping Multiple Items. Additionally, see the {{domxref("DataTransfer")}} reference page for all of the Gecko-specific properties and Gecko-specific methods.

+ +

基本用法

+ +

This section provides a summary of the basic steps to add drag and drop functionality to an application. Each section includes a description of the step, a short code example, and links to additional information.

+ +

Identify what is draggable

+ +

To make an element draggable requires adding the {{htmlattrxref("draggable")}} attribute plus the {{domxref("GlobalEventHandlers.ondragstart","ondragstart")}} global event handler, as shown in the following code sample

+ +
function dragstart_handler(ev) {
+ console.log("dragStart");
+ // Add the target element's id to the data transfer object
+ ev.dataTransfer.setData("text/plain", ev.target.id);
+}
+
+<body>
+ <p id="p1" draggable="true" ondragstart="dragstart_handler(event);">This element is draggable.</p>
+</body>
+
+ +

See the draggable attribute reference and the Drag operations guide for more information.

+ +

Define the drag's data

+ +

The application is free to include any number of data items in a drag operation. Each data item is a {{domxref("DOMString","string")}} of a particular type, typically a MIME type such as text/html.

+ +

Each {{domxref("DragEvent","drag event")}} has a {{domxref("DragEvent.dataTransfer","dataTransfer")}} property that holds the event's data. This property (which is a {{domxref("DataTransfer")}} object) also has methods to manage drag data. The {{domxref("DataTransfer.setData","setData()")}} method is used to add an item to the drag data, as shown in the following example.

+ +
function dragstart_handler(ev) {
+  // Add the drag data
+  ev.dataTransfer.setData("text/plain", ev.target.id);
+  ev.dataTransfer.setData("text/html", "<p>Example paragraph</p>");
+  ev.dataTransfer.setData("text/uri-list", "http://developer.mozilla.org");
+}
+
+ +

For a list of common data types used for drag and drop (such as text, HTML, links, and files), see Recommended Drag Types and for more information about drag data, see Drag Data.

+ +

Define the drag image

+ +

By default, the browser supplies an image that appears beside the mouse pointer during a drag operation. However, an application may define a custom image by using the {{domxref("DataTransfer.setDragImage","setDragImage()")}} method as shown in the following example.

+ +
function dragstart_handler(ev) {
+  // Create an image and then use it for the drag image.
+  // NOTE: change "example.gif" to an existing image or the image
+  // will not be created and the default drag image will be used.
+  var img = new Image();
+  img.src = 'example.gif';
+  ev.dataTransfer.setDragImage(img, 10, 10);
+}
+
+ +

To learn more about drag feedback images, see Setting the Drag Feedback Image.

+ +

Define the drag effect

+ +

The {{domxref("DataTransfer.dropEffect","dropEffect")}} property is used to control the feedback (typically visual) the user is given during a drag and drop operation. It affects which cursor the browser displays while dragging. For example, when the user hovers over a target drop element, the browser's cursor may indicate the type of operation that will occur.

+ +

Three effects may be defined:

+ +

copy indicates that the data being dragged will be copied from its present location to the drop location.

+ +

move indicates that the data being dragged will be moved

+ +

link indicates that some form of relationship or connection will be created between the source and drop locations.

+ +

During the drag operation, the drag effects may be modified to indicate that certain effects are allowed at certain locations. If allowed, a drop may occur at that location.

+ +

The following example shows how to use this property.

+ +
function dragstart_handler(ev) {
+  // Set the drag effect to copy
+  ev.dataTransfer.dropEffect = "copy";
+}
+
+ +

See Drag Effects for more details.

+ +

Define a drop zone

+ +

By default, the browser prevents anything from happening when dropping something onto the HTML element. To change that behavior so that an element becomes a drop zone or is droppable, the element must have both {{domxref("GlobalEventHandlers.ondragover","ondragover")}} and {{domxref("GlobalEventHandlers.ondrop","ondrop")}} event handler attributes. The following example shows how to use those attributes and includes basic event handlers for each attribute.

+ +
function dragover_handler(ev) {
+ ev.preventDefault();
+ // Set the dropEffect to move
+ ev.dataTransfer.dropEffect = "move"
+}
+function drop_handler(ev) {
+ ev.preventDefault();
+ // Get the id of the target and add the moved element to the target's DOM
+ var data = ev.dataTransfer.getData("text");
+ ev.target.appendChild(document.getElementById(data));
+}
+<body>
+ <div id="target" ondrop="drop_handler(event);" ondragover="dragover_handler(event);">Drop Zone</div>
+</body>
+
+ +

Note each handler calls {{domxref("Event.preventDefault","preventDefault()")}} to prevent additional event processing for this prevent (such as touch events or pointer events).

+ +

For more information, see Specifying Drop Targets.

+ +

Handle the drop effect

+ +

The handler for the {{event("drop")}} event is free to process the drag data in an application specific way. Typically, an application will use the {{domxref("DataTransfer.getData","getData()")}} method to retrieve drag items and process them accordingly. Additionally, application semantics may differ depending on the value of the {{domxref("DataTransfer.dropEffect","dropEffect")}} and/or the state of modifier keys.

+ +

The following example shows a drop handler getting the source element's id from the drag data and then using the id to move the source element to the drop element.

+ +
function dragstart_handler(ev) {
+ // Add the target element's id to the data transfer object
+ ev.dataTransfer.setData("text/plain", ev.target.id);
+ ev.dropEffect = "move";
+}
+function dragover_handler(ev) {
+ ev.preventDefault();
+ // Set the dropEffect to move
+ ev.dataTransfer.dropEffect = "move"
+}
+function drop_handler(ev) {
+ ev.preventDefault();
+ // Get the id of the target and add the moved element to the target's DOM
+ var data = ev.dataTransfer.getData("text");
+ ev.target.appendChild(document.getElementById(data));
+}
+<body>
+ <p id="p1" draggable="true" ondragstart="dragstart_handler(event);">This element is draggable.</p>
+ <div id="target" ondrop="drop_handler(event);" ondragover="dragover_handler(event);">Drop Zone</div>
+</body>
+
+ +

For more information, see Performing a Drop.

+ +

Drag end

+ +

At the end of a drag operation, the {{event("dragend")}} event fires at the source element - the element that was the target of the drag start. This event fires whether the drag completed or was canceled. The {{event("dragend")}} event handler can check the value of the {{domxref("DataTransfer.dropEffect","dropEffect")}} property to determine if the drag operation succeeded or not.

+ +

For more information about handling the end of a drag operation, see Finishing a Drag.

+ +

Interoperability

+ +

As can be seen in the DataTransferItem interface's Browser Compatibility table, drag-and-drop interoperability is relatively broad among desktop browsers (except the {{domxref("DataTransferItem")}} and {{domxref("DataTransferItemList")}} interfaces have less support). This data also indicates drag and drop support among mobile browsers is very low.

+ +

Examples and demos

+ + + +

參見

+ + diff --git a/files/zh-tw/web/api/htmlcanvaselement/index.html b/files/zh-tw/web/api/htmlcanvaselement/index.html new file mode 100644 index 0000000000..fffa314976 --- /dev/null +++ b/files/zh-tw/web/api/htmlcanvaselement/index.html @@ -0,0 +1,262 @@ +--- +title: HTMLCanvasElement +slug: Web/API/HTMLCanvasElement +tags: + - API + - Canvas + - HTML DOM + - Interface + - NeedsTranslation + - Reference + - TopicStub +translation_of: Web/API/HTMLCanvasElement +--- +
+
{{APIRef("Canvas API")}}
+
+ +

HTMLCanvasElement 介面提供控制 canvas 元素的屬性和方法. HTMLCanvasElement 介面也繼承了 {{domxref("HTMLElement")}} 介面的屬性和方法.

+ +

{{InheritanceDiagram}}

+ +

屬性

+ +

從父代繼承的屬性,{{domxref("HTMLElement")}}.

+ +
+
{{domxref("HTMLCanvasElement.height")}}
+
Is a positive integer reflecting the {{htmlattrxref("height", "canvas")}} HTML attribute of the {{HTMLElement("canvas")}} element interpreted in CSS pixels. When the attribute is not specified, or if it is set to an invalid value, like a negative, the default value of 150 is used.
+
{{domxref("HTMLCanvasElement.mozOpaque")}} {{non-standard_inline}}
+
Is a {{jsxref("Boolean")}} reflecting the {{htmlattrxref("moz-opaque", "canvas")}} HTML attribute of the {{HTMLElement("canvas")}} element. It lets the canvas know whether or not translucency will be a factor. If the canvas knows there's no translucency, painting performance can be optimized.
+
{{domxref("HTMLCanvasElement.width")}}
+
Is a positive integer reflecting the {{htmlattrxref("width", "canvas")}} HTML attribute of the {{HTMLElement("canvas")}} element interpreted in CSS pixels. When the attribute is not specified, or if it is set to an invalid value, like a negative, the default value of 300 is used.
+
{{domxref("HTMLCanvasElement.mozPrintCallback")}}{{non-standard_inline}}
+
Is a function that is Initially null, Web content can set this to a JavaScript function that will be called if the page is printed. This function can then redraw the canvas at a higher resolution that is suitable for the printer being used. See this blog post.
+
+ +

方法

+ +

從父代繼承的方法, {{domxref("HTMLElement")}}.

+ +
+
{{domxref("HTMLCanvasElement.captureStream()")}} {{experimental_inline}}
+
Returns a {{domxref("CanvasCaptureMediaStream")}} that is a real-time video capture of the surface of the canvas.
+
{{domxref("HTMLCanvasElement.getContext()")}}
+
Returns a drawing context on the canvas, or null if the context ID is not supported. A drawing context lets you draw on the canvas. Calling getContext with "2d" returns a {{domxref("CanvasRenderingContext2D")}} object, whereas calling it with "experimental-webgl" (or "webgl") returns a {{domxref("WebGLRenderingContext")}} object. This context is only available on browsers that implement WebGL.
+
{{domxref("HTMLCanvasElement.toDataURL()")}}
+
Returns a data-URL containing a representation of the image in the format specified by the type parameter (defaults to png). The returned image is in a resolution of 96dpi.
+
{{domxref("HTMLCanvasElement.toBlob()")}}
+
Creates a {{domxref("Blob")}} object representing the image contained in the canvas; this file may be cached on the disk or stored in memory at the discretion of the user agent.
+
{{domxref("HTMLCanvasElement.mozGetAsFile()")}} {{non-standard_inline}} {{deprecated_inline}}
+
Returns a {{domxref("File")}} object representing the image contained in the canvas; this file is a memory-based file, with the specified name. If type is not specified, the image type is image/png.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態
{{SpecName('Media Capture DOM Elements', '#html-media-element-media-capture-extensions', 'HTMLCanvasElement')}}{{Spec2('Media Capture DOM Elements')}}Adds the method captureStream().
{{SpecName('HTML WHATWG', "#the-canvas-element", "HTMLCanvasElement")}}{{Spec2('HTML WHATWG')}}The method getContext() now returns a {{domxref("RenderingContext")}} rather than an opaque object.
+ The methods probablySupportsContext(), setContext() and transferControlToProxy()have been added.
{{SpecName('HTML5.1', "scripting-1.html#the-canvas-element", "HTMLCanvasElement")}}{{Spec2('HTML5.1')}} 
{{SpecName('HTML5 W3C', "scripting-1.html#the-canvas-element", "HTMLCanvasElement")}}{{Spec2('HTML5 W3C')}}Initial definition.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support (2D context)4.0{{CompatVersionUnknown}}{{CompatGeckoDesktop('1.9.2')}}9.09.0 [1]3.1
toBlob()50{{CompatNo}}{{CompatGeckoDesktop('19')}} [2]{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}} (bug 71270)
probablySupportsContext(),
+ setContext(),
+ transferControlToProxy() {{experimental_inline}}
{{CompatNo}}{{CompatUnknown}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
mozGetAsFile() {{non-standard_inline}} {{deprecated_inline}}{{CompatNo}}{{CompatNo}}{{CompatGeckoDesktop('2')}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
captureStream() {{experimental_inline}}{{CompatNo}}{{CompatNo}}{{CompatGeckoDesktop('41')}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
transferControlToOffscreen() {{experimental_inline}}{{CompatNo}}{{CompatNo}}{{CompatGeckoDesktop(44)}} [3]{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support (2D context)2.1{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}10.0 [1]3.2
webgl context{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}} as experimental-webgl{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
toBlob(){{CompatNo}} (bug 67587)50{{CompatNo}}{{CompatGeckoMobile('18')}} [2]{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}} (bug 71270)
probablySupportsContext(),
+ setContext(),
+ transferControlToProxy() {{experimental_inline}}
{{CompatNo}}{{CompatNo}}{{CompatUnknown}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
mozGetAsFile() {{non-standard_inline}} {{deprecated_inline}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatGeckoMobile('2')}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
captureStream() {{experimental_inline}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatGeckoMobile('41')}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
transferControlToOffscreen() {{experimental_inline}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatGeckoMobile(44)}} [3]{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

[1] Opera Mini 5.0 and later has partial support.

+ +

[2] Support for the third parameter, has been added in Gecko 25 only: when used with the "image/jpeg" type, this argument specifies the image quality.

+ +

[3] This feature is behind a feature preference setting. In about:config, set gfx.offscreencanvas.enabled to true.

+ +

See also

+ + diff --git a/files/zh-tw/web/api/htmlcanvaselement/todataurl/index.html b/files/zh-tw/web/api/htmlcanvaselement/todataurl/index.html new file mode 100644 index 0000000000..7a87309580 --- /dev/null +++ b/files/zh-tw/web/api/htmlcanvaselement/todataurl/index.html @@ -0,0 +1,201 @@ +--- +title: HTMLCanvasElement.toDataURL() +slug: Web/API/HTMLCanvasElement/toDataURL +tags: + - API + - Canvas +translation_of: Web/API/HTMLCanvasElement/toDataURL +--- +
+
+
{{APIRef("Canvas API")}}
+
+
+ +

HTMLCanvasElement.toDataURL() 方法回傳含有圖像和參數設置特定格式的 data URIs (預設 PNG). 回傳的圖像解析度為 96 dpi.

+ + + +

表達式

+ +
canvas.toDataURL(type, encoderOptions);
+
+ +

參數

+ +
+
type {{optional_inline}}
+
圖像格式的 {{domxref("DOMString")}}. 預設為 image/png.
+
encoderOptions {{optional_inline}}
+
表示 image/jpeg 或是 image/webp 的圖像品質, 為0 到 1 之間的 {{jsxref("Number")}}.
+ 如果值不在上述範圍中, 將會使用預設值. 其他的會忽略.
+
+ +

回傳值

+ +

包含 data URI 的 {{domxref("DOMString")}}.

+ +

範例

+ +

創建 {{HTMLElement("canvas")}} 元素:

+ +
<canvas id="canvas" width="5" height="5"></canvas>
+
+ +

可以使用下面的方式獲取 data-URL:

+ +
var canvas = document.getElementById("canvas");
+var dataURL = canvas.toDataURL();
+console.log(dataURL);
+// "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNby
+// blAAAADElEQVQImWNgoBMAAABpAAFEI8ARAAAAAElFTkSuQmCC"
+
+ +

設置圖像的品質

+ +
var fullQuality = canvas.toDataURL("image/jpeg", 1.0);
+// data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...9oADAMBAAIRAxEAPwD/AD/6AP/Z"
+var mediumQuality = canvas.toDataURL("image/jpeg", 0.5);
+var lowQuality = canvas.toDataURL("image/jpeg", 0.1);
+
+ +

範例: 動態改變圖像

+ +

為了動態改變圖像, 可以與滑鼠事件一起使用 (gray-scale versus color in this example):

+ +

HTML

+ +
<img class="grayscale" src="myPicture.png" alt="Description of my picture" />
+ +

JavaScript

+ +
window.addEventListener("load", removeColors);
+
+function showColorImg() {
+  this.style.display = "none";
+  this.nextSibling.style.display = "inline";
+}
+
+function showGrayImg() {
+  this.previousSibling.style.display = "inline";
+  this.style.display = "none";
+}
+
+function removeColors() {
+  var aImages = document.getElementsByClassName("grayscale"),
+      nImgsLen = aImages.length,
+      oCanvas = document.createElement("canvas"),
+      oCtx = oCanvas.getContext("2d");
+  for (var nWidth, nHeight, oImgData, oGrayImg, nPixel, aPix, nPixLen, nImgId = 0; nImgId < nImgsLen; nImgId++) {
+    oColorImg = aImages[nImgId];
+    nWidth = oColorImg.offsetWidth;
+    nHeight = oColorImg.offsetHeight;
+    oCanvas.width = nWidth;
+    oCanvas.height = nHeight;
+    oCtx.drawImage(oColorImg, 0, 0);
+    oImgData = oCtx.getImageData(0, 0, nWidth, nHeight);
+    aPix = oImgData.data;
+    nPixLen = aPix.length;
+    for (nPixel = 0; nPixel < nPixLen; nPixel += 4) {
+      aPix[nPixel + 2] = aPix[nPixel + 1] = aPix[nPixel] = (aPix[nPixel] + aPix[nPixel + 1] + aPix[nPixel + 2]) / 3;
+    }
+    oCtx.putImageData(oImgData, 0, 0);
+    oGrayImg = new Image();
+    oGrayImg.src = oCanvas.toDataURL();
+    oGrayImg.onmouseover = showColorImg;
+    oColorImg.onmouseout = showGrayImg;
+    oCtx.clearRect(0, 0, nWidth, nHeight);
+    oColorImg.style.display = "none";
+    oColorImg.parentNode.insertBefore(oGrayImg, oColorImg);
+  }
+}
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態
{{SpecName('HTML WHATWG', "scripting.html#dom-canvas-todataurl", "HTMLCanvasElement.toDataURL")}}{{Spec2('HTML WHATWG')}}No change since the latest snapshot, {{SpecName('HTML5 W3C')}}
{{SpecName('HTML5.1', "scripting-1.html#dom-canvas-todataurl", "HTMLCanvasElement.toDataURL")}}{{Spec2('HTML5.1')}} 
{{SpecName('HTML5 W3C', "scripting-1.html#dom-canvas-todataurl", "HTMLCanvasElement.toDataURL")}}{{Spec2('HTML5 W3C')}}Snapshot of the {{SpecName('HTML WHATWG')}} containing the initial definition.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{ CompatChrome(4) }}{{ CompatGeckoDesktop("1.9.2") }}{{ CompatIE(9) }}{{ CompatOpera(9) }}{{ CompatSafari(4.0) }}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{ CompatAndroid(3.2) }}{{ CompatAndroid(18) }}{{ CompatGeckoMobile("1.9.2") }}{{ CompatVersionUnknown() }}{{ CompatOpera(19) }}{{ CompatSafari(3.0) }}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/htmlcollection/index.html b/files/zh-tw/web/api/htmlcollection/index.html new file mode 100644 index 0000000000..dac516a65b --- /dev/null +++ b/files/zh-tw/web/api/htmlcollection/index.html @@ -0,0 +1,95 @@ +--- +title: HTMLCollection +slug: Web/API/HTMLCollection +translation_of: Web/API/HTMLCollection +--- +

{{APIRef("HTML DOM")}}

+ +

HTMLCollection 介面表示了一種成員為 {{domxref("Element")}} 物件的通用集合(如 arguments 一般的類陣列,成員順序同元素在文件中的順序),並提供了可用來選取集合成員的方法與屬性。

+ +
Note: This interface is called HTMLCollection for historical reasons (before DOM4, collections implementing this interface could only have HTML elements as their items).
+ +

HTMLCollection 物件對 HTML DOM 而言具有即時性(live),如果底層的文件(document 物件)發生改變,HTMLCollection 物件會自動更新至最新的狀態。

+ +

屬性

+ +
+
{{domxref("HTMLCollection.length")}} {{readonlyInline}}
+
Returns the number of items in the collection.
+
+ +

方法

+ +
+
{{domxref("HTMLCollection.item()")}}
+
Returns the specific node at the given zero-based index into the list. Returns null if the index is out of range.
+
{{domxref("HTMLCollection.namedItem()")}}
+
Returns the specific node whose ID or, as a fallback, name matches the string specified by name. Matching by name is only done as a last resort, only in HTML, and only if the referenced element supports the name attribute. Returns null if no node exists by the given name.
+
+ +

Usage in JavaScript

+ +

HTMLCollection also exposes its members directly as properties by both name and index. HTML IDs may contain : and . as valid characters, which would necessitate using bracket notation for property access. Currently HTMLCollections does not recognize purely numeric IDs, which would cause conflict with the array-style access, though HTML5 does permit these.

+ +

For example, assuming there is one <form> element in the document and its id is "myForm":

+ +
var elem1, elem2;
+
+// document.forms is an HTMLCollection
+
+elem1 = document.forms[0];
+elem2 = document.forms.item(0);
+
+alert(elem1 === elem2); // shows: "true"
+
+elem1 = document.forms.myForm;
+elem2 = document.forms.namedItem("myForm");
+
+alert(elem1 === elem2); // shows: "true"
+
+elem1 = document.forms["named.item.with.periods"];
+ +

瀏覽器相容性

+ +

Different browsers behave differently when there are more than one elements matching the string used as an index (or namedItem's argument). Firefox 8 behaves as specified in DOM 2 and DOM4, returning the first matching element. WebKit browsers and Internet Explorer in this case return another HTMLCollection and Opera returns a {{domxref("NodeList")}} of all matching elements.

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#htmlcollection', 'HTMLCollection')}}{{ Spec2('DOM WHATWG') }} 
{{SpecName('DOM4', '#htmlcollection', 'HTMLCollection')}}{{ Spec2('DOM4') }} 
{{SpecName('DOM2 HTML', 'html.html#ID-75708506', 'HTMLCollection')}}{{ Spec2('DOM2 HTML') }} 
{{SpecName('DOM1', 'level-one-html.html#ID-75708506', 'HTMLCollection')}}{{ Spec2('DOM1') }}Initial definition.
+ +

參見

+ + diff --git a/files/zh-tw/web/api/htmldataelement/index.html b/files/zh-tw/web/api/htmldataelement/index.html new file mode 100644 index 0000000000..56e15b834d --- /dev/null +++ b/files/zh-tw/web/api/htmldataelement/index.html @@ -0,0 +1,59 @@ +--- +title: HTMLDataElement +slug: Web/API/HTMLDataElement +translation_of: Web/API/HTMLDataElement +--- +
{{APIRef("HTML DOM")}}
+ +

The HTMLDataElement interface provides special properties (beyond the regular {{domxref("HTMLElement")}} interface it also has available to it by inheritance) for manipulating {{HTMLElement("data")}} elements.

+ +

{{InheritanceDiagram(600, 120)}}

+ +

屬性

+ +

從它的父繼承屬性, {{domxref("HTMLElement")}}.

+ +
+
{{domxref("HTMLDataElement.value")}}
+
Is a {{domxref("DOMString")}} reflecting the {{htmlattrxref("value", "data")}} HTML attribute, containing a machine-readable form of the element's value.
+
+ +

方法

+ +

無具體的方法; 從它的父繼承, {{domxref("HTMLElement")}}.

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', "#htmldataelement", "HTMLDataElement")}}{{Spec2('HTML WHATWG')}} 
{{SpecName('HTML5 W3C', 'text-level-semantics.html#the-data-element', 'HTMLDataElement')}}{{Spec2('HTML5 W3C')}} 
+ +

Browser compatibility

+ +
+ + +

{{Compat("api.HTMLDataElement")}}

+
+ +

See also

+ + diff --git a/files/zh-tw/web/api/htmldocument/index.html b/files/zh-tw/web/api/htmldocument/index.html new file mode 100644 index 0000000000..7317d54508 --- /dev/null +++ b/files/zh-tw/web/api/htmldocument/index.html @@ -0,0 +1,16 @@ +--- +title: HTMLDocument +slug: Web/API/HTMLDocument +translation_of: Web/API/HTMLDocument +--- +

{{ APIRef("HTML DOM") }}

+ +

HTMLDocument 是一個關於 {{domxref("Document_Object_Model", "DOM")}} 的抽象介面,提供了 {{domxref("Document")}} 定義之外的 XML 文件屬性及方法,以用來操作 HTML。

+ +

window.document 為 HTMLDocument 的物件實體,HTMLDocument 所有屬性與方法的說明已包含在 Document 頁面。由於現在的 HTMLDocument 是透過了綁定轉型(binding-specific casting)的方式來運作,所以 HTMLDocument 已不再是繼承 Document

+ +

規範

+ + diff --git a/files/zh-tw/web/api/htmlelement/click/index.html b/files/zh-tw/web/api/htmlelement/click/index.html new file mode 100644 index 0000000000..123206ca2f --- /dev/null +++ b/files/zh-tw/web/api/htmlelement/click/index.html @@ -0,0 +1,115 @@ +--- +title: HTMLElement.click() +slug: Web/API/HTMLElement/click +translation_of: Web/API/HTMLElement/click +--- +
+
{{ APIRef("HTML DOM") }}
+
+ +

HTMLElement.click() 方法可以模擬滑鼠點擊一個元素。

+ +

click() 被使用在支援的元素(例如任一 {{HTMLElement("input")}} 元素),便會觸發該元素的點擊事件。事件會冒泡至 document tree(或 event chain)的上層元素,並觸發它們的點擊事件。其中的例外是:click() 方法不會讓 {{HTMLElement("a")}} 元素和接收到真實滑鼠點擊一樣進行頁面跳轉。

+ +

語法

+ +
elt.click()
+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM2 HTML', 'html.html#ID-2651361')}}{{Spec2('DOM2 HTML')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support20[3]{{CompatVersionUnknown}}5[1]{{CompatVersionUnknown}}{{CompatVersionUnknown}}[2]6[3]
input@file (limited){{CompatVersionUnknown}}{{CompatVersionUnknown}}4{{CompatVersionUnknown}}12.10{{CompatVersionUnknown}}
input@file (full){{CompatVersionUnknown}}{{CompatVersionUnknown}}4{{CompatVersionUnknown}}{{CompatNo}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatNo}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Prior to Gecko 5.0 {{geckoRelease("5.0")}}, Gecko would not implement the click() method on other elements that might be expected to respond to mouse clicks, such as links ({{HTMLElement("a")}} elements), nor would it necessarily fire the click event of other elements.

+ +

[2] In Presto-based versions of Opera, the click() method will be silently ignored if made on an {{HTMLElement("input")}} with its type attribute set to file and its CSS {{cssxref('display')}} property set to none.

+ +

[3] Older versions had HTMLInputElement.click(), and HTMLButtonElement.click() only.

diff --git a/files/zh-tw/web/api/htmlelement/dataset/index.html b/files/zh-tw/web/api/htmlelement/dataset/index.html new file mode 100644 index 0000000000..690f8e1189 --- /dev/null +++ b/files/zh-tw/web/api/htmlelement/dataset/index.html @@ -0,0 +1,167 @@ +--- +title: HTMLElement.dataset +slug: Web/API/HTMLElement/dataset +translation_of: Web/API/HTMLOrForeignElement/dataset +--- +

{{ APIRef("HTML DOM") }}

+ +

HTMLElement.dataset 允許在讀取與寫入模式時使用HTML或DOM裡,所有設置在元件上的自定義資料屬性(data-*)。他是一個DOMStringMap,每個項目表示一個不同的資料屬性。須注意的是,資料集(dataset)可以被讀取,但不能直接被修改。所有修改必須經由其眾多"屬性"才行,也就是資料屬性。另外,雖然HTML data- 屬性與它相關的 DOM dataset. 名稱不同,但是他們總是有相似之處: 

+ + + +

除了以下的資訊之外,你也可以在 Using data attributes.此篇文章找到使用HTML資料屬性的用法。

+ +

名稱變換

+ +

 

+ +

dash-style 到 camelCase: 將自訂義的資料屬性名稱變換至{{ domxref("DOMStringMap") }}各項目的key值,需根據以下規則:

+ + + +

camelCase 到 dash-style: 與上述相反,將key值轉為資料屬性名稱,需根據以下規則:

+ + + +

上面所提的限制是為了確保兩個轉換方法互為相反。

+ +

舉例來說,資料屬性名稱 data-abc-def 之對應key值為abcDef

+ +

 

+ +

存取數值

+ + + +

語法

+ + + +

範例

+ +
<div id="user" data-id="1234567890" data-user="johndoe" data-date-of-birth>John Doe</div>
+
+let el = document.querySelector('#user');
+
+// el.id == 'user'
+// el.dataset.id === '1234567890'
+// el.dataset.user === 'johndoe'
+// el.dataset.dateOfBirth === ''
+
+el.dataset.dateOfBirth = '1960-10-03'; // 設定 DOB.
+
+// 'someDataAttr' in el.dataset === false
+el.dataset.someDataAttr = 'mydata';
+// 'someDataAttr' in el.dataset === true
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態備註
{{SpecName('HTML WHATWG', "dom.html#dom-dataset", "HTMLElement.dataset")}}{{Spec2('HTML WHATWG')}}No change from latest snapshot, {{SpecName('HTML5.1')}}
{{SpecName('HTML5.1', "dom.html#dom-dataset", "HTMLElement.dataset")}}{{Spec2('HTML5.1')}}Snapshot of {{SpecName('HTML WHATWG')}}, no change from {{SpecName('HTML5 W3C')}}
{{SpecName('HTML5 W3C', "dom.html#dom-dataset", "HTMLElement.dataset")}}{{Spec2('HTML5 W3C')}}Snapshot of  {{SpecName('HTML WHATWG')}}, initial definition.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
功能ChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
基本支援8{{CompatVersionUnknown}}{{ CompatGeckoDesktop("6.0") }}1111.106
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
功能AndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
基本支援{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(6)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/htmlelement/index.html b/files/zh-tw/web/api/htmlelement/index.html new file mode 100644 index 0000000000..f0b3eb55e0 --- /dev/null +++ b/files/zh-tw/web/api/htmlelement/index.html @@ -0,0 +1,447 @@ +--- +title: HTMLElement +slug: Web/API/HTMLElement +translation_of: Web/API/HTMLElement +--- +
+
{{ APIRef("HTML DOM") }}
+
+ +
 
+ +

HTMLElement 介面表示了所有的 HTML 元素。部分元素直接實作了此介面,其它則是實作繼承自 HTMLElement 的子介面。

+ +

{{InheritanceDiagram}}

+ +

屬性

+ +

Inherits properties from its parent, {{domxref("Element")}}, and implements those from {{domxref("GlobalEventHandlers")}} and {{domxref("TouchEventHandlers")}}.

+ +
+
{{domxref("HTMLElement.accessKey")}}
+
Is a {{domxref("DOMString")}} representing the access key assigned to the element.
+
{{domxref("HTMLElement.accessKeyLabel")}} {{readonlyInline}}
+
Returns a {{domxref("DOMString")}} containing the element's assigned access key.
+
{{domxref("HTMLElement.contentEditable")}}
+
Is a {{domxref("DOMString")}}, where a value of "true" means the element is editable and a value of "false" means it isn't.
+
{{domxref("HTMLElement.isContentEditable")}} {{readonlyInline}}
+
Returns a {{domxref("Boolean")}} that indicates whether or not the content of the element can be edited.
+
{{domxref("HTMLElement.contextMenu")}}
+
Is a {{domxref("HTMLMenuElement")}} representing the contextual menu associated with the element. It may be null.
+
{{domxref("HTMLElement.dataset")}} {{readonlyInline}}
+
Returns a {{domxref("DOMStringMap")}} with which script can read and write the element's custom data attributes (data-*) .
+
{{domxref("HTMLElement.dir")}}
+
Is a {{domxref("DOMString")}}, reflecting the dir global attribute, representing the directionality of the element. Possible values are "ltr", "rtl", and "auto".
+
{{domxref("HTMLElement.draggable")}}
+
Is a {{jsxref("Boolean")}} indicating if the element can be dragged.
+
{{domxref("HTMLElement.dropzone")}} {{readonlyInline}}
+
Returns a {{domxref("DOMSettableTokenList")}} reflecting the dropzone global attribute and describing the behavior of the element regarding a drop operation.
+
{{domxref("HTMLElement.hidden")}}
+
Is a {{jsxref("Boolean")}} indicating if the element is hidden or not.
+
{{domxref("HTMLElement.itemScope")}} {{experimental_inline}}
+
Is a {{jsxref("Boolean")}} representing the item scope.
+
{{domxref("HTMLElement.itemType")}} {{readonlyInline}}{{experimental_inline}}
+
Returns a {{domxref("DOMSettableTokenList")}}…
+
{{domxref("HTMLElement.itemId")}} {{experimental_inline}}
+
Is a {{domxref("DOMString")}} representing the item ID.
+
{{domxref("HTMLElement.itemRef")}} {{readonlyInline}}{{experimental_inline}}
+
Returns a {{domxref("DOMSettableTokenList")}}…
+
{{domxref("HTMLElement.itemProp")}} {{readonlyInline}}{{experimental_inline}}
+
Returns a {{domxref("DOMSettableTokenList")}}…
+
{{domxref("HTMLElement.itemValue")}} {{experimental_inline}}
+
Returns a {{jsxref("Object")}} representing the item value.
+
{{domxref("HTMLElement.lang")}}
+
Is a {{domxref("DOMString")}} representing the language of an element's attributes, text, and element contents.
+
{{domxref("HTMLElement.offsetHeight")}} {{readonlyInline}}{{experimental_inline}}
+
Returns a double containing the height of an element, relative to the layout.
+
{{domxref("HTMLElement.offsetLeft")}}{{readonlyInline}}{{experimental_inline}}
+
Returns a double, the distance from this element's left border to its offsetParent's left border.
+
{{domxref("HTMLElement.offsetParent")}}{{readonlyInline}}{{experimental_inline}}
+
Returns a {{domxref("Element")}} that is the element from which all offset calculations are currently computed.
+
{{domxref("HTMLElement.offsetTop")}}{{readonlyInline}}{{experimental_inline}}
+
Returns a double, the distance from this element's top border to its offsetParent's top border.
+
{{domxref("HTMLElement.offsetWidth")}}{{readonlyInline}}{{experimental_inline}}
+
Returns a double containing the width of an element, relative to the layout.
+
{{domxref("HTMLElement.properties")}} {{readonlyInline}}{{experimental_inline}}
+
Returns a {{domxref("HTMLPropertiesCollection")}}…
+
{{domxref("HTMLElement.spellcheck")}}{{ gecko_minversion_inline("1.9")}}
+
Is a {{jsxref("Boolean")}} that controls spell-checking. It is present on all HTML elements, though it doesn't have an effect on all of them.
+
{{domxref("HTMLElement.style")}}
+
Is a {{domxref("CSSStyleDeclaration")}}, an object representing the declarations of an element's style attributes.
+
{{domxref("HTMLElement.tabIndex")}}
+
Is a long representing the position of the element in the tabbing order.
+
{{domxref("HTMLElement.title")}}
+
Is a {{domxref("DOMString")}} containing the text that appears in a popup box when mouse is over the element.
+
{{domxref("HTMLElement.translate")}} {{experimental_inline}}
+
Is a {{jsxref("Boolean")}} representing the translation.
+
+ +

事件處理器

+ +

Most events properties, of the form onXYZ, are defined on the {{domxref("GlobalEventHandlers")}} or {{domxref("TouchEventHandlers")}}, implemented by HTMLElement. A few more are specific to HTMLElement.

+ +
+
{{ domxref("HTMLElement.oncopy") }}  {{ non-standard_inline() }}
+
Returns the event handling code for the copy event ({{bug("280959")}}).
+
{{ domxref("HTMLElement.oncut") }}  {{ non-standard_inline() }}
+
Returns the event handling code for the cut event ({{bug("280959")}}).
+
{{ domxref("HTMLElement.onpaste") }} {{ non-standard_inline() }}
+
Returns the event handling code for the paste event ({{bug("280959")}}).
+
{{domxref("TouchEventHandlers.ontouchstart")}} {{non-standard_inline}}
+
Returns the event handling code for the {{event("touchstart")}} event.
+
{{domxref("TouchEventHandlers.ontouchend")}} {{non-standard_inline}}
+
Returns the event handling code for the {{event("touchend")}} event.
+
{{domxref("TouchEventHandlers.ontouchmove")}} {{non-standard_inline}}
+
Returns the event handling code for the {{event("touchmove")}} event.
+
{{domxref("TouchEventHandlers.ontouchenter")}} {{non-standard_inline}}
+
Returns the event handling code for the {{event("touchenter")}} event.
+
{{domxref("TouchEventHandlers.ontouchleave")}} {{non-standard_inline}}
+
Returns the event handling code for the {{event("touchleave")}} event.
+
{{domxref("TouchEventHandlers.ontouchcancel")}} {{non-standard_inline}}
+
Returns the event handling code for the {{event("touchcancel")}} event.
+
+ +

方法

+ +

Inherits methods from its parent, {{domxref("Element")}}.

+ +
+
{{domxref("HTMLElement.blur()")}}
+
Removes keyboard focus from the currently focused element.
+
{{domxref("HTMLElement.click()")}}
+
Sends a mouse click event to the element.
+
{{domxref("HTMLElement.focus()")}}
+
Makes the element the current keyboard focus.
+
{{domxref("HTMLElement.forceSpellCheck()")}} {{experimental_inline}}
+
Runs the spell checker on the element's contents.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSSOM View', '#extensions-to-the-htmlelement-interface', 'HTMLElement')}}{{Spec2('CSSOM View')}}Added the following properties: offsetParent, offsetTop, offsetLeft, offsetWidth, and offsetHeight.
{{SpecName('HTML WHATWG', 'elements.html#htmlelement', 'HTMLElement')}}{{Spec2('HTML WHATWG')}}Added the following properties: translate, itemScope, itemType, itemId, itemRef, itemProp, properties, and itemValue.
+ Added the following method: forceSpellcheck().
+ Moved the onXYZ attributes to the {{domxref("GlobalEventHandlers")}} interface and added an inheritance from it.
{{SpecName('HTML5 W3C', 'dom.html#htmlelement', 'HTMLElement')}}{{Spec2('HTML5 W3C')}}Added the following properties: dataset, hidden, tabindex, accessKey, accessKeyLabel, draggable, dropzone, contentEditable, isContentEditable, contextMenu, spellcheck, commandType, commandLabel, commandIcon, commandHidden, commandDisabled, commandChecked, style, and all the onXYZ properties.
+ Moved the id and className properties to the {{domxref("Element")}} interface.
{{SpecName('DOM2 HTML', 'html.html#ID-011100101', 'HTMLElement')}}{{Spec2('DOM2 HTML')}}No change from {{SpecName('DOM2 HTML')}}
{{SpecName('DOM1', 'level-one-html.html#ID-011100101', 'HTMLElement')}}{{Spec2('DOM1')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox (Gecko)ChromeEdgeInternet ExplorerOperaSafari
Basic support{{CompatGeckoDesktop("1.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.accessKey", "accessKey")}}{{CompatGeckoDesktop("5.0")}}17.0{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}6.0
{{domxref("HTMLElement.accessKeyLabel", "accessKeyLabel")}}{{CompatGeckoDesktop("8.0")}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}{{WebkitBug(72715)}}
{{domxref("HTMLElement.blur()", "blur()")}}{{CompatGeckoDesktop("5.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}9{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.click()", "click()")}}{{CompatGeckoDesktop("5.0")}}{{CompatUnknown}}9{{CompatVersionUnknown}}9{{CompatUnknown}}6.0
{{domxref("HTMLElement.dataset", "dataset")}}{{CompatGeckoDesktop("6.0")}}8{{CompatVersionUnknown}}1111.105.1
{{domxref("HTMLElement.focus()", "focus()")}}{{CompatGeckoDesktop("5.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}9{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.contentEditable", "contentEditable")}}{{CompatGeckoDesktop("1.9")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}5.59{{CompatVersionUnknown}}
{{domxref("HTMLElement.spellcheck", "spellcheck")}}{{CompatGeckoDesktop("1.8.1")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.style", "style")}}{{CompatVersionUnknown}} (returns a {{domxref("CSS2Properties")}}, rather than a {{domxref("CSSStyleDeclaration")}}){{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
{{domxref("HTMLElement.forceSpellCheck", "forceSpellCheck()")}} {{experimental_inline}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
{{domxref("HTMLElement.draggable", "draggable")}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}12.0{{CompatUnknown}}
{{domxref("HTMLElement.dropzone", "dropzone")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}12.0{{CompatNo}}
{{domxref("HTMLElement.offsetLeft", "offsetLeft")}}, {{domxref("HTMLElement.offsetTop", "offsetTop")}}, {{domxref("HTMLElement.offsetParent", "offsetParent")}}, {{domxref("HTMLElement.offsetHeight", "offsetHeight")}} and {{domxref("HTMLElement.offsetWidth", "offsetWidth")}} {{experimental_inline}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.translate", "translate")}} {{experimental_inline}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
{{domxref("HTMLElement.itemScope", "itemScope")}}, {{domxref("HTMLElement.itemType", "itemType")}}, {{domxref("HTMLElement.itemRef", "itemRef")}}, {{domxref("HTMLElement.itemId", "itemId")}}, {{domxref("HTMLElement.itemProp", "itemProp")}}, and {{domxref("HTMLElement.itemValue", "itemValue")}} {{experimental_inline}}{{CompatGeckoDesktop("6.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}11.60
+ (Removed in Opera 15)
{{CompatNo}}
{{domxref("HTMLElement.properties", "properties")}} {{experimental_inline}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.ontouchstart")}}, {{domxref("HTMLElement.ontouchend")}}, {{domxref("HTMLElement.ontouchmove")}}, {{domxref("HTMLElement.ontouchenter")}}, {{domxref("HTMLElement.ontouchleave")}}, and {{domxref("HTMLElement.ontouchcancel")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}{{CompatUnknown}}{{CompatVersionUnknown}}
{{domxref("HTMLElement.oncopy")}}, {{domxref("HTMLElement.oncut")}}, and {{domxref("HTMLElement.onpaste")}} {{Non-standard_inline}}{{CompatGeckoDesktop("1.9")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox Mobile (Gecko)AndroidEdgeIE MobileOpera MobileSafari Mobile
Basic support +

{{CompatGeckoMobile("1.0")}}

+
{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.accessKey", "accessKey")}}{{CompatGeckoMobile("5.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.accessKeyLabel", "accessKeyLabel")}}{{CompatGeckoMobile("8.0")}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.blur()", "blur()")}}{{CompatGeckoMobile("5.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.click()", "click()")}}{{CompatGeckoMobile("5.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.dataset", "dataset")}}{{CompatGeckoMobile("6.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.focus()", "focus()")}}{{CompatGeckoMobile("5.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
{{domxref("HTMLElement.oncopy")}}, {{domxref("HTMLElement.oncut")}}, and {{domxref("HTMLElement.onpaste")}} {{Non-standard_inline}}{{CompatGeckoMobile("1.9")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/htmlelement/lang/index.html b/files/zh-tw/web/api/htmlelement/lang/index.html new file mode 100644 index 0000000000..ff546e3ca9 --- /dev/null +++ b/files/zh-tw/web/api/htmlelement/lang/index.html @@ -0,0 +1,59 @@ +--- +title: HTMLElement.lang +slug: Web/API/HTMLElement/lang +tags: + - API + - HTML DOM + - HTMLElement + - NeedsBrowserCompatibility + - NeedsUpdate + - Property + - Reference +translation_of: Web/API/HTMLElement/lang +--- +
{{ APIRef("HTML DOM") }}
+ +

HTMLElement.lang 屬性({{Glossary("property")}})可以讀取或設定一個表示元素之語系的標籤屬性({{Glossary("attribute")}})值。

+ +

HTMLElement.lang 屬性所回傳的語系代碼定義於網際網路工程任務小組(IETF)的 Tags for Identifying Languages (BCP47) 文件中。常見的例子如 "en" 代表英語、"ja" 代表日語、"es" 代表西班牙語等等。此標籤屬性的預設值為 unknown。請留意,雖然此標籤屬性於個別層級的元素上是有效的,但大部分都設定於文件的根元素。

+ +

HTMLElement.lang 屬性只對 lang 標籤屬性有作用,而不是 xml:lang

+ +

語法

+ +
var languageUsed = elementNodeReference.lang; // Get the value of lang
+elementNodeReference.lang = NewLanguage; // Set new value for lang
+
+ +

languageUsed is a string variable that gets the language in which the text of the current element is written. NewLanguage is a string variable with its value setting the language in which the text of the current element is written.

+ +

範例

+ +
// this snippet compares the base language and
+// redirects to another url based on language
+if (document.documentElement.lang === "en") {
+  window.location.href = "Some_document.html.en";
+} else if (document.documentElement.lang === "ru") {
+  window.location.href = "Some_document.html.ru";
+}
+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM2 HTML', 'html.html#ID-59132807', 'lang')}}{{Spec2('DOM2 HTML')}} 
+ +

 

diff --git a/files/zh-tw/web/api/htmlelement/style/index.html b/files/zh-tw/web/api/htmlelement/style/index.html new file mode 100644 index 0000000000..e9e6d1171a --- /dev/null +++ b/files/zh-tw/web/api/htmlelement/style/index.html @@ -0,0 +1,79 @@ +--- +title: HTMLElement.style +slug: Web/API/HTMLElement/style +translation_of: Web/API/ElementCSSInlineStyle/style +--- +
{{ APIRef("HTML DOM") }}
+ +

The HTMLElement.style property is used to get as well as set the inline style of an element. While getting, it returns a CSSStyleDeclaration object that contains a list of all styles properties for that element with values assigned for the attributes that are defined in the element's inline style attribute. See the CSS Properties Reference for a list of the CSS properties accessible via style.The style property has the same (and highest) priority in the CSS cascade as an inline style declaration set via the style attribute.

+ +

設定 styles

+ +

Styles can be set by assigning a string directly to the style property (as in elt.style = "color: blue;") or by assigning values to the properties of style. For adding specific styles to an element without altering other style values, it is preferred to use the individual properties of style (as in elt.style.color = '...' ) as using elt.style.cssText = '...' or elt.setAttribute('style', '...') sets the complete inline style for the element by overriding the existing inline styles. Note that the property names are in camel-case and not kebab-case while setting the style using elt.style.<property> (i.e. elt.style.fontSize, not elt.style.font-size)

+ +

範例

+ +
// Set multiple styles in a single statement
+elt.style.cssText = "color: blue; border: 1px solid black";
+// OR
+elt.setAttribute("style", "color:red; border: 1px solid blue;");
+
+
+elt.style.color = "blue";  // Set specific style while leaving other inline style values untouched
+
+ +

取得樣式資訊

+ +

The style property is not useful for completely learning about the styles applied on the element, since it represents only the CSS declarations set in the element's inline style attribute, not those that come from style rules elsewhere, such as style rules in the {{HTMLElement("head")}} section, or external style sheets. To get the values of all CSS properties for an element you should use {{domxref("window.getComputedStyle()")}} instead.

+ +

The following code snippet demonstrates the difference between the values obtained using the element's style property and that obtained using the computedStyle() method:

+ +
<!DOCTYPE HTML>
+<html>
+ <body style="font-weight:bold;">
+
+    <div style="color:red" id="myElement">..</div>
+
+ </body>
+</html>
+
+ +
var element = document.getElementById("myElement");
+var out = "";
+var elementStyle = element.style;
+var computedStyle = window.getComputedStyle(element, null);
+
+for (prop in elementStyle) {
+  if (elementStyle.hasOwnProperty(prop)) {
+    out += "  " + prop + " = '" + elementStyle[prop] + "' > '" + computedStyle[prop] + "'\n";
+  }
+}
+console.log(out)
+
+ +

The output would be something like:

+ +
...
+fontWeight = '' > 'bold'
+color = 'red' > 'rgb(255, 0, 0)'
+...
+ +

Note the presence of the value "bold" for font-weight in the computed style and the absence of it in the element's style property

+ +

規範

+ +

DOM Level 2 Style: ElementCSSInlineStyle.style

+ +

瀏覽器相容性

+ +
+

Note: Starting in {{Gecko("2.0")}}, you can set SVG properties' values using the same shorthand syntax. For example:

+ +
element.style.fill = 'lime';
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/htmlformelement/index.html b/files/zh-tw/web/api/htmlformelement/index.html new file mode 100644 index 0000000000..614eebbad2 --- /dev/null +++ b/files/zh-tw/web/api/htmlformelement/index.html @@ -0,0 +1,245 @@ +--- +title: HTMLFormElement +slug: Web/API/HTMLFormElement +translation_of: Web/API/HTMLFormElement +--- +
{{APIRef("HTML DOM")}}
+ +

HTMLFormElement 介面提供了建立及修改 {{HTMLElement("form")}} 元素的方法。
+ document.forms - returns an array of HTMLFormElement objects referencing all forms on the page.
+ document.forms[index] - returns an HTMLFormElement object referencing the form at the specified index.
+ document.forms['id'] - returns an HTMLFormElement object referencing the form with the specified id.
+ document.forms['name'] - returns an HTMLFormElement object referencing the form with the specified name.

+ +

{{InheritanceDiagram(600,120)}}

+ +

屬性

+ +

This interface also inherits properties from its parent, {{domxref("HTMLElement")}}.

+ +
+
{{domxref("HTMLFormElement.elements")}}{{ReadOnlyInline}}
+
A {{domxref("HTMLFormControlsCollection")}} holding all form controls belonging to this form element.
+
{{domxref("HTMLFormElement.length")}}{{ReadOnlyInline}}
+
A long reflecting the number of controls in the form.
+
{{domxref("HTMLFormElement.name")}}
+
A {{domxref("DOMString")}} reflecting the value of the form's {{ htmlattrxref("name", "form") }} HTML attribute, containing the name of the form.
+
{{domxref("HTMLFormElement.method")}}
+
A {{domxref("DOMString")}} reflecting the value of the form's {{ htmlattrxref("method", "form") }} HTML attribute, indicating the HTTP method used to submit the form. Only specified values can be set.
+
{{domxref("HTMLFormElement.target")}}
+
A {{domxref("DOMString")}} reflecting the value of the form's {{ htmlattrxref("target", "form") }} HTML attribute, indicating where to display the results received from submitting the form.
+
{{domxref("HTMLFormElement.action")}}
+
A {{domxref("DOMString")}} reflecting the value of the form's {{ htmlattrxref("action", "form") }} HTML attribute, containing the URI of a program that processes the information submitted by the form.
+
{{domxref("HTMLFormElement.encoding")}} or {{domxref("HTMLFormElement.enctype")}}
+
A {{domxref("DOMString")}} reflecting the value of the form's {{ htmlattrxref("enctype", "form") }} HTML attribute, indicating the type of content that is used to transmit the form to the server. Only specified values can be set. The two methods are synonyms.
+
{{domxref("HTMLFormElement.acceptCharset")}}
+
A {{domxref("DOMString")}} reflecting the value of the form's {{ htmlattrxref("accept-charset", "form") }} HTML attribute, representing the character encoding that the server accepts.
+
{{domxref("HTMLFormElement.autocomplete")}}
+
A {{domxref("DOMString")}} reflecting the value of the form's {{ htmlattrxref("autocomplete", "form") }} HTML attribute, indicating whether the controls in this form can have their values automatically populated by the browser.
+
{{domxref("HTMLFormElement.noValidate")}}
+
A {{jsxref("Boolean")}} reflecting the value of the form's {{ htmlattrxref("novalidate", "form") }} HTML attribute, indicating whether the form should not be validated.
+
+ +

方法

+ +

This interface also inherits methods from its parent, {{domxref("HTMLElement")}}.

+ +
+
{{domxref("HTMLFormElement.submit()")}}
+
Submits the form to the server.
+
{{domxref("HTMLFormElement.reset()")}}
+
Resets the form to its initial state.
+
{{domxref("HTMLFormElement.checkValidity()")}}
+
Returns true if the element's child controls are subject to constraint validation and satisfy those contraints; returns false if some controls do not satisfy their constraints. Fires an event named {{event("invalid")}} at any control that does not satisfy its constraints; such controls are considered invalid if the event is not canceled. It is up to the programmer to decide how to respond to false.
+
{{domxref("HTMLFormElement.reportValidity()")}}
+
Returns true if the element's child controls satisfy their validation constraints. When false is returned, cancelable {{Event("invalid")}} events are fired for each invalid child and validation problems are reported to the user.
+
{{domxref("HTMLFormElement.requestAutocomplete()")}}
+
Triggers a native browser interface to assist the user in completing the fields which have an autofill field name value that is not off or on. The form will receive an event once the user has finished with the interface, the event will either be {{event("autocomplete")}} when the fields have been filled or {{event("autocompleteerror")}} when there was a problem.
+
+ +

範例

+ +

Create a new form element, modify its attributes and submit it:

+ +
var f = document.createElement("form");// Create a form
+document.body.appendChild(f);          // Add it to the document body
+f.action = "/cgi-bin/some.cgi";        // Add action and method attributes
+f.method = "POST"
+f.submit();                            // Call the form's submit method
+
+ +

Extract information from a form element and set some of its attributes:

+ +
<form name="formA" id="formA" action="/cgi-bin/test" method="POST">
+ <p>Click "Info" for form details; "Set" to change settings.</p>
+ <p>
+  <input type="button" value="info" onclick="getFormInfo();">
+  <input type="button" value="set"  onclick="setFormInfo(this.form);">
+  <input type="reset" value="reset"><br>
+  <textarea id="tex" style="height:15em; width:20em"></textarea>
+ </p>
+</form>
+
+<script type="text/javascript">
+  function getFormInfo(){
+    var info;
+    var f = document.forms["formA"]; //Get a reference to the form via id.
+    info = "elements: " + f.elements     + "\n"
+         + "length: "   + f.length       + "\n"
+         + "name: "     + f.name         + "\n"
+         + "charset: "  + f.acceptCharset+ "\n"
+         + "action: "   + f.action       + "\n"
+         + "enctype: "  + f.enctype      + "\n"
+         + "encoding: " + f.encoding     + "\n"
+         + "method: "   + f.method       + "\n"
+         + "target: "   + f.target;
+    document.forms["formA"].elements['tex'].value = info;
+  }
+  function setFormInfo(f){ //Argument is a reference to the form.
+    f.method = "GET";
+    f.action = "/cgi-bin/evil_executable.cgi";
+    f.name   = "totally_new";
+  }
+</script>
+
+ +

Submit a form in a popup window:

+ +
<!doctype html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>MDN Example</title>
+<script type="text/javascript">
+function popupSend (oFormElement) {
+  if (oFormElement.method && oFormElement.method.toLowerCase() !== "get") {
+    console.error("This script supports the GET method only.");
+    return;
+  }
+  var oField, sFieldType, nFile, sSearch = "";
+  for (var nItem = 0; nItem < oFormElement.elements.length; nItem++) {
+    oField = oFormElement.elements[nItem];
+    if (!oField.hasAttribute("name")) { continue; }
+    sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT";
+    if (sFieldType === "FILE") {
+      for (nFile = 0; nFile < oField.files.length; sSearch += "&" + escape(oField.name) + "=" + escape(oField.files[nFile++].name));
+    } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {
+      sSearch += "&" + escape(oField.name) + "=" + escape(oField.value);
+    }
+  }
+  open(oFormElement.action.replace(/(?:\?.*)?$/, sSearch.replace(/^&/, "?")), "submit-" + (oFormElement.name || Math.floor(Math.random() * 1e6)), "resizable=yes,scrollbars=yes,status=yes");
+}
+</script>
+
+</head>
+
+<body>
+
+<form name="yourForm" action="test.php" method="get" onsubmit="popupSend(this); return false;">
+  <p>First name: <input type="text" name="firstname" /><br />
+  Last name: <input type="text" name="lastname" /><br />
+  Password: <input type="password" name="pwd" /><br />
+  <input type="radio" name="sex" value="male" /> Male <input type="radio" name="sex" value="female" /> Female</p>
+  <p><input type="checkbox" name="vehicle" value="Bike" />I have a bike<br />
+  <input type="checkbox" name="vehicle" value="Car" />I have a car</p>
+  <p><input type="submit" value="Submit" /></p>
+</form>
+
+</body>
+</html>
+ +

使用 XMLHttpRequest 提交表單及上傳檔案

+ +

If you want to know how to serialize and submit a form using the {{domxref("XMLHttpRequest")}} API, please read this paragraph.

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', "forms.html#the-form-element", "HTMLFormElement")}}{{Spec2('HTML WHATWG')}}The following method has been added: requestAutocomplete().
{{SpecName('HTML5 W3C', "forms.html#the-form-element", "HTMLFormElement")}}{{Spec2('HTML5 W3C')}}The elements properties returns an {{domxref("HTMLFormControlsCollection")}} instead of a raw {{domxref("HTMLCollection")}}. This is mainly a technical change. The following method has been added: checkValidity(). The following properties have been added: autocomplete, noValidate, and encoding.
{{SpecName('DOM2 HTML', 'html.html#ID-40002357', 'HTMLFormElement')}}{{Spec2('DOM2 HTML')}}No change
{{SpecName('DOM1', 'level-one-html.html#ID-40002357', 'HTMLFormElement')}}{{Spec2('DOM1')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(1.0)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(1.0)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/htmlformelement/submit_event/index.html b/files/zh-tw/web/api/htmlformelement/submit_event/index.html new file mode 100644 index 0000000000..6c5b030f7c --- /dev/null +++ b/files/zh-tw/web/api/htmlformelement/submit_event/index.html @@ -0,0 +1,60 @@ +--- +title: submit +slug: Web/API/HTMLFormElement/submit_event +translation_of: Web/API/HTMLFormElement/submit_event +--- +

submit 事件會在表單送出時觸發。

+ +

要注意的是,submit 事件只會form element 上觸發, button 或是 submit input 則不會觸發。(送出的是「表單」,而非「按鈕」)

+ +

基本資料

+ +
+
定義規範
+
HTML5
+
Interface
+
{{domxref("Event")}}
+
Bubbles
+
是 
+ 雖說在規範上這是個不 bubble 的事件
+
Cancelable
+
+
Target
+
Element
+
默認行動
+
修改(傳送表單內容至伺服器)。
+
+ +

屬性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
target {{readonlyInline}}{{domxref("EventTarget")}}The event target (the topmost target in the DOM tree).
type {{readonlyInline}}{{domxref("DOMString")}}The type of event.
bubbles {{readonlyInline}}{{jsxref("Boolean")}}Whether the event normally bubbles or not.
cancelable {{readonlyInline}}{{jsxref("Boolean")}}Whether the event is cancellable or not.
diff --git a/files/zh-tw/web/api/htmlimageelement/index.html b/files/zh-tw/web/api/htmlimageelement/index.html new file mode 100644 index 0000000000..0bf5e96953 --- /dev/null +++ b/files/zh-tw/web/api/htmlimageelement/index.html @@ -0,0 +1,408 @@ +--- +title: HTMLImageElement +slug: Web/API/HTMLImageElement +translation_of: Web/API/HTMLImageElement +--- +
{{APIRef("HTML DOM")}}
+ +

HTMLImageElement 介面提供了特殊的屬性及方法以用來操作 {{HTMLElement("img")}} 元素的畫面佈局與外觀呈現。

+ +

{{InheritanceDiagram(600,120)}}

+ +

屬性

+ +

Inherits properties from its parent, {{domxref("HTMLElement")}}.

+ +
+
{{domxref("HTMLImageElement.align")}} {{obsolete_inline}}
+
Is a {{domxref("DOMString")}} indicating the alignment of the image with respect to the surrounding context.
+
{{domxref("HTMLImageElement.alt")}}
+
Is a {{domxref("DOMString")}} that reflects the {{htmlattrxref("alt", "img")}} HTML attribute,  thus indicating fallback context for the image.
+
{{domxref("HTMLImageElement.border")}} {{obsolete_inline}}
+
Is a {{domxref("DOMString")}} that is responsible for the width of the border surrounding the image. This is now deprecated and the CSS {{cssxref("border")}} property should be used instead.
+
{{domxref("HTMLImageElement.complete")}} {{readonlyInline}}
+
Returns a {{domxref("Boolean")}} that is true if the browser has finished fetching the image, whether successful or not. It also shows true, if the image has no {{domxref("HTMLImageElement.src", "src")}} value.
+
{{domxref("HTMLImageElement.crossOrigin")}}
+
Is a {{domxref("DOMString")}} representing the CORS setting for this image element. See CORS settings attributes for further details.
+
{{domxref("HTMLImageElement.currentSrc")}} {{readonlyInline}}{{experimental_inline}}
+
Returns a {{domxref("DOMString")}} representing the URL to the currently displayed image (which may change, for example in response to media queries).
+
{{domxref("HTMLImageElement.height")}}
+
一個反映了 HTML img 元素之 {{htmlattrxref("height", "img")}} 屬性的無符號(unsigned)整數,表示圖片經渲染後的高度(CSS pixels)。
+
{{domxref("HTMLImageElement.hspace")}} {{obsolete_inline}}
+
Is a long representing the space on either side of the image.
+
{{domxref("HTMLImageElement.isMap")}}
+
Is a {{domxref("Boolean")}} that reflects the {{htmlattrxref("ismap", "img")}} HTML attribute, indicating that the image is part of a server-side image map.
+
{{domxref("HTMLImageElement.longDesc")}} {{obsolete_inline}}
+
Is a {{domxref("DOMString")}} representing the URI of a long description of the image.
+
{{domxref("HTMLImageElement.lowSrc")}} {{obsolete_inline}}
+
Is a {{domxref("DOMString")}} that refers to a low-quality (but faster to load) copy of the image.
+
{{domxref("HTMLImageElement.name")}} {{obsolete_inline}}
+
Is a {{domxref("DOMString")}} representing the name of the element.
+
{{domxref("HTMLImageElement.naturalHeight")}} {{readonlyInline}}
+
回傳一個代表圖片固有高度(CSS pixels)的無符號(unsigned)整數,如果無法取得則回傳 0
+
{{domxref("HTMLImageElement.naturalWidth")}} {{readonlyInline}}
+
回傳一個代表圖片固有寬度(CSS pixels)的無符號(unsigned)整數,如果無法取得則回傳 0
+
{{domxref("HTMLImageElement.referrerPolicy")}} {{experimental_inline}}
+
Is a {{domxref("DOMString")}} that reflects the {{htmlattrxref("referrerpolicy", "img")}} HTML attribute indicating which referrer to use in order to fetch the image.
+
{{domxref("HTMLImageElement.src")}}
+
Is a {{domxref("DOMString")}} that reflects the {{htmlattrxref("src", "img")}} HTML attribute, containing the full URL of the image including base URI.
+
{{domxref("HTMLImageElement.sizes")}} {{experimental_inline}}
+
Is a {{domxref("DOMString")}} reflecting the {{htmlattrxref("sizes", "img")}} HTML attribute.
+
{{domxref("HTMLImageElement.srcset")}} {{experimental_inline}}
+
Is a {{domxref("DOMString")}} reflecting the {{htmlattrxref("srcset", "img")}} HTML attribute, containing a list of candidate images, separated by a comma (',', U+002C COMMA). A candidate image is a URL followed by a 'w' with the width of the images, or an 'x' followed by the pixel density.
+
{{domxref("HTMLImageElement.useMap")}}
+
Is a {{domxref("DOMString")}} that reflects the {{htmlattrxref("usemap", "img")}} HTML attribute, containing a partial URL of a map element.
+
{{domxref("HTMLImageElement.vspace")}} {{obsolete_inline}}
+
Is a long representing the space above and below the image.
+
{{domxref("HTMLImageElement.width")}}
+
一個反映了 HTML img 元素之 {{htmlattrxref("width", "img")}} 屬性的無符號(unsigned)整數,表示圖片經渲染後的寬度(CSS pixels)。
+
{{domxref("HTMLImageElement.x")}} {{readonlyInline}}{{experimental_inline}}
+
Returns a long representing the horizontal offset from the nearest layer. This property mimics an old Netscape 4 behavior.
+
{{domxref("HTMLImageElement.y")}} {{readonlyInline}} {{experimental_inline}}
+
Returns a long representing the vertical offset from the nearest layer. This property is also similar to behavior of an old Netscape 4.
+
+ +

方法

+ +

Inherits properties from its parent, {{domxref("HTMLElement")}}.

+ +
+
{{domxref("HTMLImageElement.Image()", "Image()")}}
+
The Image() constructor, taking two optional unsigned long, which are the width and the height of the resource, creates an instance of HTMLImageElement , not inserted in a DOM tree.
+
+ +

Errors

+ +

If an error occurs while trying to load or render the image, and an {{htmlattrxref("onerror")}} event handler has been configured to handle the {{event("error")}} event, that event handler will get called. This can happen in a number of situations, including:

+ + + +

範例

+ +
var img1 = new Image(); // HTML5 Constructor
+img1.src = 'image1.png';
+img1.alt = 'alt';
+document.body.appendChild(img1);
+
+var img2 = document.createElement('img'); // use DOM HTMLImageElement
+img2.src = 'image2.jpg';
+img2.alt = 'alt text';
+document.body.appendChild(img2);
+
+// using first image in the document
+alert(document.images[0].src);
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Referrer Policy', '#referrer-policy-delivery-referrer-attribute', 'referrer attribute')}}{{Spec2('Referrer Policy')}}Added the referrerPolicy property.
{{SpecName("CSSOM View", "#excensions-to-the-htmlimageelement-interface", "Extensions to HTMLImageElement")}}{{Spec2('CSSOM View')}}Added the x and y properties.
{{SpecName('HTML WHATWG', "embedded-content.html#the-img-element", "HTMLImageElement")}}{{Spec2('HTML WHATWG')}}The following properties have been added: srcset, currentSrc and sizes.
{{SpecName('HTML5 W3C', "embedded-content-0.html#the-img-element", "HTMLImageElement")}}{{Spec2('HTML5 W3C')}}A constructor (with 2 optional parameters) has been added.
+ The following properties are now obsolete: name, border, align, hspace, vspace, and longdesc.
+ The following properties are now unsigned long, instead of long: height, and width.
+ The following properties have been added: crossorigin, naturalWidth, naturalHeight, and complete.
{{SpecName('DOM2 HTML', 'html.html#ID-17701901', 'HTMLImgElement')}}{{Spec2('DOM2 HTML')}}The lowSrc property has been removed.
+ The following properties are now long, instead of DOMString: height, width, hspace, and vspace.
{{SpecName('DOM1', 'level-one-html.html#ID-17701901', 'HTMLImgElement')}}{{Spec2('DOM1')}}Initial definition.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(1.0)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
lowSrc{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
naturalWidth, naturalHeight{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}9{{CompatVersionUnknown}}{{CompatVersionUnknown}}
crossorigin{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}9{{CompatVersionUnknown}}{{CompatVersionUnknown}}
complete{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}5[4]{{CompatVersionUnknown}}{{CompatVersionUnknown}}
srcset {{experimental_inline}}{{CompatChrome(34)}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(32)}}[2]{{CompatNo}}21{{CompatSafari(7.1)}}
currentSrc {{experimental_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(32)}}[2]{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}
sizes {{experimental_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(33)}}[3]{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}
x and y{{CompatVersionUnknown}}{{CompatVersionUnknown}}14[1]{{CompatNo}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
referrerPolicy {{experimental_inline}}{{CompatChrome(51)}}{{CompatNo}}{{CompatGeckoDesktop(50)}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
onerror event handler{{CompatNo}}{{CompatUnknown}}{{CompatGeckoDesktop(51)}}[5]{{CompatNo}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroid WebviewChrome for AndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(1.0)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
lowSrc{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
naturalWidth, naturalHeight{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}9{{CompatUnknown}}{{CompatVersionUnknown}}
crossorigin{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
complete{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
srcset {{experimental_inline}}{{CompatChrome(34)}}{{CompatChrome(34)}}{{CompatVersionUnknown}}{{CompatGeckoMobile(32)}}[2]{{CompatNo}}{{CompatNo}}iOS 8
currentSrc {{experimental_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(32)}}[2]{{CompatNo}}{{CompatNo}}{{CompatNo}}
sizes {{experimental_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(33)}}[3]{{CompatNo}}{{CompatNo}}{{CompatNo}}
x and y{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}14[1]{{CompatNo}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
referrerPolicy {{experimental_inline}}{{CompatChrome(51)}}{{CompatChrome(51)}}{{CompatNo}}{{CompatGeckoMobile(50)}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
onerror event handler{{CompatNo}}{{CompatNo}}{{CompatUnknown}}{{CompatGeckoMobile(51)}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

[1] Though, these x and y properties were removed in Gecko 7.0 {{geckoRelease("7.0")}} but later, they were restored in Gecko 14.0 {{geckoRelease("14.0")}} for compatibility reasons.

+ +

[2] This feature is behind the dom.image.srcset.enabled preference, defaulting to false.

+ +

[3] This feature is behind the dom.image.picture.enabled preference, defaulting to false.

+ +

[4] IE reports false for broken images.

+ +

[5] May also be supported in earlier versions.

+ +

See also

+ + diff --git a/files/zh-tw/web/api/htmlinputelement/index.html b/files/zh-tw/web/api/htmlinputelement/index.html new file mode 100644 index 0000000000..f2b9c9c6ef --- /dev/null +++ b/files/zh-tw/web/api/htmlinputelement/index.html @@ -0,0 +1,592 @@ +--- +title: HTMLInputElement +slug: Web/API/HTMLInputElement +translation_of: Web/API/HTMLInputElement +--- +
{{ APIRef("HTML DOM") }}
+ +

HTMLInputElement 介面提供了特殊的屬性及方法以操作 input 元素的顯示與佈局。

+ +

{{InheritanceDiagram(600,120)}}

+ +

屬性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Properties related to the parent form
form {{readonlyInline}}{{domxref("HTMLFormElement")}} object:  Returns a reference to the parent form element.
formActionstring: Returns / Sets the element's {{ htmlattrxref("formaction", "input") }} attribute, containing the URI of a program that processes information submitted by the element. This overrides the {{ htmlattrxref("action", "form") }} attribute of the parent form.
formEncTypestring: Returns / Sets the element's {{ htmlattrxref("formenctype", "input") }} attribute, containing the type of content that is used to submit the form to the server. This overrides the {{ htmlattrxref("enctype", "form") }} attribute of the parent form.
formMethodstring: Returns / Sets the element's {{ htmlattrxref("formmethod", "input") }} attribute, containing the HTTP method that the browser uses to submit the form. This overrides the {{ htmlattrxref("method", "form") }} attribute of the parent form.
formNoValidateboolean: Returns / Sets the element's {{ htmlattrxref("formnovalidate", "input") }} attribute, indicating that the form is not to be validated when it is submitted. This overrides the {{ htmlattrxref("novalidate", "form") }} attribute of the parent form.
formTargetstring: Returns / Sets the element's {{ htmlattrxref("formtarget", "input") }} attribute, containing a name or keyword indicating where to display the response that is received after submitting the form. This overrides the {{ htmlattrxref("target", "form") }} attribute of the parent form.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Properties that apply to any type of input element that is not hidden
namestring: Returns / Sets the element's {{ htmlattrxref("name", "input") }} attribute, containing a name that identifies the element when submitting the form.
typestring: Returns / Sets the element's {{ htmlattrxref("type", "input") }} attribute, indicating the type of control to display. See {{ htmlattrxref("type", "input") }} attribute of {{ HTMLElement("input") }} for possible values.
disabledboolean: Returns / Sets the element's {{ htmlattrxref("disabled", "input") }} attribute, indicating that the control is not available for interaction. The input values will not be submitted with the form. See also {{ htmlattrxref("readOnly", "input") }} 
autofocusboolean: Returns / Sets the element's {{ htmlattrxref("autofocus", "input") }} attribute, which specifies that a form control should have input focus when the page loads, unless the user overrides it, for example by typing in a different control. Only one form element in a document can have the {{htmlattrxref("autofocus","input")}} attribute. It cannot be applied if the {{htmlattrxref("type","input")}} attribute is set to hidden (that is, you cannot automatically set focus to a hidden control).
requiredboolean: Returns / Sets the element's {{ htmlattrxref("required", "input") }} attribute, indicating that the user must fill in a value before submitting a form.
valuestring: Returns / Sets the current value of the control. +

Note: If the user enters a value different from the value expected, this may return an empty string.

+
validity {{readonlyInline}}{{domxref("ValidityState")}} object: Returns the validity state that this element is in.
validationMessage {{readonlyInline}}string: Returns a localized message that describes the validation constraints that the control does not satisfy (if any). This is the empty string if the control is not a candidate for constraint validation ({{htmlattrxref("willValidate","input")}} is false), or it satisfies its constraints.
willValidate {{readonlyInline}}{{jsxref("Boolean")}}: Indicates whether the element is a candidate for constraint validation. It is false if any conditions bar it from constraint validation.
+ + + + + + + + + + + + + + + + + +
Properties that apply only to elements of type "checkbox" or "radio"
checked boolean: Returns / Sets the current state of the element when {{htmlattrxref("type","input")}} is checkbox or radio.
defaultCheckedboolean: Returns / Sets the default state of a radio button or checkbox as originally specified in HTML that created this object.
indeterminateboolean: indicates that the checkbox is neither on nor off.
+ + + + + + + + + + + + + + + + + + + + + +
Properties that apply only to elements of type "image"
altstring: Returns / Sets the element's {{ htmlattrxref("alt", "input") }} attribute, containing alternative text to use when {{htmlattrxref("type","input")}} is image.
heightstring: Returns / Sets the element's {{ htmlattrxref("height", "input") }} attribute, which defines the height of the image displayed for the button, if the value of {{htmlattrxref("type","input")}} is image.
srcstring: Returns / Sets the element's {{ htmlattrxref("src", "input") }} attribute, which specifies a URI for the location of an image to display on the graphical submit button, if the value of {{htmlattrxref("type","input")}} is image; otherwise it is ignored.
widthstring: Returns / Sets the document's {{ htmlattrxref("width", "input") }} attribute, which defines the width of the image displayed for the button, if the value of {{htmlattrxref("type","input")}} is image.
+ + + + + + + + + + + + + + + + + + + + + +
Properties that apply only to elements of type "file"
acceptstring: Returns / Sets the element's {{ htmlattrxref("accept", "input") }} attribute, containing comma-separated list of file types accepted by the server when {{htmlattrxref("type","input")}} is file.
allowdirs {{non-standard_inline}}boolean: Part of the non-standard Directory Upload API; indicates whether or not to allow directories and files both to be selected in the file list. Implemented only in Firefox and is hidden behind a preference.
{{domxref("HTMLInputElement.webkitdirectory", "webkitdirectory")}} {{Non-standard_inline}}boolean: Returns the {{htmlattrxref("webkitdirectory", "input")}} attribute; if true, the file system picker interface only accepts directories instead of files.
{{domxref("HTMLInputElement.webkitEntries", "webkitEntries")}} {{Non-standard_inline}}Array of {{domxref("FileSystemEntry")}} objects describing the currently-selected files or directories.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Properties that apply only to text/number-containing or elements
autocompletestring: Returns / Sets the element's {{htmlattrxref("autocomplete", "input")}} attribute, indicating whether the value of the control can be automatically completed by the browser. Ignored if the value of the {{htmlattrxref("type","input")}} attribute is hidden, checkbox, radio, file, or a button type (button, submit, reset, image). Possible values are:
+ "on": the browser can autocomplete the value using previously stored value
+ "off": the user must explicity enter a value
maxLengthlong: Returns / Sets the element's {{ htmlattrxref("maxlength", "input") }} attribute, containing the maximum length of characters (in Unicode code points) that the value can have. (If you set this to a negative number, an exception will be thrown.)
sizeunsigned long: Returns / Sets the element's {{ htmlattrxref("size", "input") }} attribute, containing size of the control. This value is in pixels unless the value of {{htmlattrxref("type","input")}} is text or password, in which case, it is an integer number of characters. Applies only when {{htmlattrxref("type","input")}} is set to text, search, tel, url, email, or password; otherwise it is ignored.
patternstring: Returns / Sets the element's {{ htmlattrxref("pattern", "input") }} attribute, containing a regular expression that the control's value is checked against.  Use the {{htmlattrxref("title","input")}} attribute to describe the pattern to help the user. This attribute applies when the value of the {{htmlattrxref("type","input")}} attribute is text, search, tel, url or email; otherwise it is ignored.
placeholderstring: Returns / Sets the element's {{ htmlattrxref("placeholder", "input") }} attribute, containing a hint to the user of what can be entered in the control. The placeholder text must not contain carriage returns or line-feeds. This attribute applies when the value of the {{htmlattrxref("type","input")}} attribute is text, search, tel, url or email; otherwise it is ignored.
readOnlyboolean: Returns / Sets the element's {{ htmlattrxref("readonly", "input") }} attribute, indicating that the user cannot modify the value of the control.
+ {{HTMLVersionInline(5)}}This is ignored if the value of the {{htmlattrxref("type","input")}} attribute is hidden, range, color, checkbox, radio, file, or a button type.
minstring: Returns / Sets the element's {{ htmlattrxref("min", "input") }} attribute, containing the minimum (numeric or date-time) value for this item, which must not be greater than its maximum ({{htmlattrxref("max","input")}} attribute) value.
maxstring: Returns / Sets the element's {{ htmlattrxref("max", "input") }} attribute, containing the maximum (numeric or date-time) value for this item, which must not be less than its minimum (min attribute) value.
selectionStartunsigned long: Returns / Sets the beginning index of the selected text. When nothing is selected, this returns the position of the text input cursor (caret) inside of the {{HTMLElement("input")}} element.
selectionEndunsigned long: Returns / Sets the end index of the selected text. When there's no selection, this returns the offset of the character immediately following the current text input cursor position.
selectionDirectionstring: Returns / Sets the direction in which selection occurred. Possible values are:
+ "forward" if selection was performed in the start-to-end direction of the current locale,
+ "backward" for the opposite direction,
+ "none" if the direction is unknown."
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Properties not yet categorized
defaultValuestring: Returns / Sets the default value as originally specified in the HTML that created this object.
dirNamestring: Returns / Sets the directionality of the element.
accessKeystring: Returns a string containing a single character that switches input focus to the control when pressed.
list {{readonlyInline}}{{domxref("HTMLElement")}} object: Returns the element pointed by the {{ htmlattrxref("list", "input") }} attribute. The property may be null if no HTML element found in the same tree.
multipleboolean: Returns / Sets the element's {{ htmlattrxref("multiple", "input") }} attribute, indicating whether more than one value is possible (e.g., multiple files).
files {{readonlyInline}}{{domxref("FileList")}} array: Returns the list of selected files.
labels {{readonlyInline}}{{domxref("NodeList")}} array: Returns a list of {{ HTMLElement("label") }} elements that are labels for this element.
stepstring: Returns / Sets the element's {{ htmlattrxref("step", "input") }} attribute, which works with {{htmlattrxref("min","input")}} and {{htmlattrxref("max","input")}} to limit the increments at which a numeric or date-time value can be set. It can be the string any or a positive floating point number. If this is not set to any, the control accepts only values at multiples of the step value greater than the minimum.
valueAsDate{{jsxref("Date")}} object: Returns / Sets the value of the element, interpreted as a date, or null if conversion is not possible.
valueAsNumberdouble: Returns the value of the element, interpreted as one of the following, in order: +
    +
  • a time value
  • +
  • a number
  • +
  • NaN if conversion is impossible
  • +
+
autocapitalize {{experimental_inline}}string: defines the capitalization behavior for user input. Valid values are none, off, characters, words, or sentences.
+ +
+
{{domxref("HTMLInputElement.align")}} {{obsolete_inline}}
+
string: represents the alignment of the element. Use CSS instead.
+
{{domxref("HTMLInputElement.useMap")}} {{ obsolete_inline }}
+
string: represents a client-side image map.
+
+ +

方法

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
focus()Focus on the input element; keystrokes will subsequently go to this element.
blur()Removes focus from input; keystrokes will subsequently go nowhere.
select()Selects the input text in the element, and focuses it so the user can subsequently replace the whole entry.
click()Simulates a click on the element.
setSelectionRange()Selects a range of text in the element (but does not focus it). The optional selectionDirection parameter may be "forward" or "backward" to establish the direction in which selection was set, or "none" if the direction is unknown or not relevant. The default is "none". Specifying a selectionDirection parameter sets the value of the selectionDirection property.
setRangeText()Selects a range of text in the element (but does not focus it). The optional selectionDirection parameter may be "forward" or "backward" to establish the direction in which selection was set, or "none" if the direction is unknown or not relevant. The default is "none". Specifying a selectionDirection parameter sets the value of the selectionDirection property.
setCustomValidity()Sets a custom validity message for the element. If this message is not the empty string, then the element is suffering from a custom validity error, and does not validate.
checkValidity()Returns a {{jsxref("Boolean")}} that is false if the element is a candidate for constraint validation, and it does not satisfy its constraints. In this case, it also fires an {{event("invalid")}} event at the element. It returns true if the element is not a candidate for constraint validation, or if it satisfies its constraints.
+ +
+
{{domxref("HTMLInputElement.stepDown()")}}
+
Decrements the {{htmlattrxref("value","input")}} by ({{htmlattrxref("step","input")}} * n), where n defaults to 1 if not specified. Throws an INVALID_STATE_ERR exception: +
    +
  • if the method is not applicable to for the current {{htmlattrxref("type","input")}} value,
  • +
  • if the element has no {{htmlattrxref("step","input")}} value,
  • +
  • if the {{htmlattrxref("value","input")}} cannot be converted to a number,
  • +
  • if the resulting value is above the {{htmlattrxref("max","input")}} or below the {{htmlattrxref("min","input")}}. 
  • +
+
+
{{domxref("HTMLInputElement.stepUp()")}}
+
Increments the {{htmlattrxref("value","input")}} by ({{htmlattrxref("step","input")}} * n), where n defaults to 1 if not specified. Throws an INVALID_STATE_ERR exception: +
    +
  • if the method is not applicable to for the current {{htmlattrxref("type","input")}} value.,
  • +
  • if the element has no {{htmlattrxref("step","input")}} value,
  • +
  • if the {{htmlattrxref("value","input")}} cannot be converted to a number,
  • +
  • if the resulting value is above the {{htmlattrxref("max","input")}} or below the {{htmlattrxref("min","input")}}.
  • +
+
+
{{domxref("HTMLInputElement.mozSetFileArray()")}}{{non-standard_inline}}
+
Sets the files selected on the input to the given array of {{domxref("File")}} objects.  This is an alternative to mozSetFileNameArray() which can be used in frame scripts: a chrome script can open files as File objects and send them via message manager.
+
{{domxref("HTMLInputElement.mozGetFileNameArray()")}}
+
Returns an array of all the file names from the input.
+
{{domxref("HTMLInputElement.mozSetFileNameArray()")}}
+
Sets the filenames for the files selected on the input.  Not for use in frame scripts, because it accesses the file system.
+
+
    +
+
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', "forms.html#the-input-element", "HTMLInputElement")}}{{Spec2('HTML WHATWG')}}No change from {{SpecName("HTML5 W3C")}}
{{SpecName('HTML5 W3C', "forms.html#the-input-element", "HTMLInputElement")}}{{Spec2('HTML5 W3C')}}Technically, the  tabindex and accesskey properties, as well as the blur(), click(), and focus() methods, are now defined on {{domxref("HTMLElement")}}.
+ The following properties are now obsolete: align and useMap.
+ The following properties have been added: autocomplete, autofocus, dirName, files, formAction, formEncType, formMethod, formNoValidate, formTarget, height, indeterminate, labels, list, max, min, multiple, pattern, placeholder, required, selectionDirection, selectionEnd, selectionStart, step, validationMessage, validity, valueAsDate, valueAsNumber, width, and willValidate.
+ The following methods have been added: checkValidity(), setCustomValidity(), setSelectionRange(), stepUp(), and stepDown().
{{SpecName('DOM2 HTML', 'html.html#ID-6043025', 'HTMLInputElement')}}{{Spec2('DOM2 HTML')}}The size property is now an unsigned long. The type property must be entirely given in lowercase characters.
{{SpecName('DOM1', 'level-one-html.html#ID-6043025', 'HTMLInputElement')}}{{Spec2('DOM1')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatGeckoDesktop(1.0)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
autocomplete & autofocus properties{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
files property{{CompatVersionUnknown}}{{CompatGeckoDesktop(1.9)}}10{{CompatUnknown}}{{CompatUnknown}}
multiple property{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9.2")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
indeterminate property{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
list property{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
formAction, formEncType, formMethod, formTarget properties{{CompatVersionUnknown}}{{CompatGeckoDesktop(2)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
formNoValidate, validationMessage, validity, willValidate properties and setCustomValidity() and checkValidity() methods.{{CompatVersionUnknown}}{{CompatGeckoDesktop(2)}}10{{CompatVersionUnknown}}{{CompatVersionUnknown}}
pattern, placeholder, required properties{{CompatVersionUnknown}}{{CompatGeckoDesktop(2)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
height and weight properties{{CompatVersionUnknown}}{{CompatGeckoDesktop(16)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
labels property{{CompatChrome(14.0)}}{{CompatNo}} ({{bug("556743")}}){{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
min, max, and step for <input type="number">{{CompatVersionUnknown}}Experimental, and without specific UI, since {{CompatGeckoDesktop(16)}}: behind the pref dom.experimental_forms{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
stepUp and stepDown methods{{CompatUnknown}}Experimental since {{CompatGeckoDesktop(16)}}: behind the pref dom.experimental_forms
+
+ There are still differences with the latest spec: {{bug(835773)}}
{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
min, max, and step properties for <input type="range">{{CompatVersionUnknown}}{{CompatGeckoDesktop(23)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
min, max, and step properties for <input type="date">{{CompatVersionUnknown}}Experimental, and without specific UI, since {{CompatGeckoDesktop(20)}}: behind the pref dom.experimental_forms{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
min, max, and step properties for other date-related type values{{CompatVersionUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
mozGetFileNameArray() and mozSetFileNameArray() methods {{non-standard_inline}}{{CompatNo}}{{CompatGeckoDesktop("1.9.2")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
mozSetFileArray() method {{non-standard_inline}}{{CompatNo}}{{CompatGeckoDesktop("38")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
autocapitalize{{CompatChrome(43.0)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewFirefox Mobile (Gecko)IE PhoneOpera MobileSafari MobileChrome for Android
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(1.0)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
autocapitalize{{CompatNo}}{{CompatChrome(43.0)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatChrome(43.0)}}
+ +

 

+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/htmlmediaelement/index.html b/files/zh-tw/web/api/htmlmediaelement/index.html new file mode 100644 index 0000000000..68d1122e81 --- /dev/null +++ b/files/zh-tw/web/api/htmlmediaelement/index.html @@ -0,0 +1,243 @@ +--- +title: HTMLMediaElement +slug: Web/API/HTMLMediaElement +translation_of: Web/API/HTMLMediaElement +--- +

{{APIRef("HTML DOM")}}

+ +

The HTMLMediaElement interface adds to {{domxref("HTMLElement")}} the properties and methods needed to support basic media-related capabilities that are common to audio and video. The {{domxref("HTMLVideoElement")}} and {{domxref("HTMLAudioElement")}} elements both inherit this interface.

+ +

{{InheritanceDiagram(600, 120)}}

+ +

屬性

+ +

這個介面從{{domxref("HTMLElement")}}、{{domxref("Element")}}、{{domxref("Node")}},和{{domxref("EventTarget")}}繼承了屬性

+ +
+
{{domxref("HTMLMediaElement.audioTracks")}}
+
{{domxref("AudioTrackList")}} 會列出包含在該媒體元素內部的{{domxref("AudioTrack")}}物件。
+
{{domxref("HTMLMediaElement.autoplay")}}
+
是一個布林值,表達了HTML中是否有{{htmlattrxref("autoplay", "video")}}屬性;意即;表明是否只要在媒體可以播放且不中斷的時候,能夠自動播放。 +
在網站上自動播放音訊(或是有音訊的影片),可能是惱人的使用者體驗;因此,應該盡可能地避免。如果你必須要有自動播放的功能,你應該讓它是可選擇的(讓使用者特地去啟動)。 However, this can be useful when creating media elements whose source will be set at a later time, under user control.
+
+
{{domxref("HTMLMediaElement.buffered")}} {{readonlyinline}}
+
回傳一個{{domxref("TimeRanges")}}物件,表示媒體當下buffered屬性被瀏覽器存取時的緩存(如果有的話)區間。
+
{{domxref("HTMLMediaElement.controller")}}
+
Is a {{domxref("MediaController")}} object that represents the media controller assigned to the element, or null if none is assigned.
+
{{domxref("HTMLMediaElement.controls")}}
+
Is a {{jsxref('Boolean')}} that reflects the {{htmlattrxref("controls", "video")}} HTML attribute, indicating whether user interface items for controlling the resource should be displayed.
+
{{domxref("HTMLMediaElement.controlsList")}} {{readonlyinline}}
+
Returns a {{domxref("DOMTokenList")}} that helps the user agent select what controls to show on the media element whenever the user agent shows its own set of controls. The DOMTokenList takes one or more of three possible values: nodownload, nofullscreen, and noremoteplayback.
+
{{domxref("HTMLMediaElement.crossOrigin")}}
+
Is a {{domxref("DOMString")}} indicating the CORS setting for this media element.
+
{{domxref("HTMLMediaElement.currentSrc")}} {{readonlyinline}}
+
Returns a {{domxref("DOMString")}} with the absolute URL of the chosen media resource.
+
{{domxref("HTMLMediaElement.currentTime")}}
+
Is a double indicating the current playback time in seconds. Setting this value seeks the media to the new time.
+
{{domxref("HTMLMediaElement.defaultMuted")}}
+
Is a {{jsxref('Boolean')}} that reflects the {{htmlattrxref("muted", "video")}} HTML attribute, which indicates whether the media element's audio output should be muted by default.
+
{{domxref("HTMLMediaElement.defaultPlaybackRate")}}
+
Is a double indicating the default playback rate for the media.
+
{{domxref("HTMLMediaElement.disableRemotePlayback")}}
+
Is a {{jsxref('Boolean')}} that sets or returns the remote playback state, indicating whether the media element is allowed to have a remote playback UI.
+
{{domxref("HTMLMediaElement.duration")}} {{readonlyinline}}
+
Returns a double indicating the length of the media in seconds, or 0 if no media data is available.
+
{{domxref("HTMLMediaElement.ended")}} {{readonlyinline}}
+
Returns a {{jsxref('Boolean')}} that indicates whether the media element has finished playing.
+
{{domxref("HTMLMediaElement.error")}} {{readonlyinline}}
+
Returns a {{domxref("MediaError")}} object for the most recent error, or null if there has not been an error.
+
{{domxref("HTMLMediaElement.loop")}}
+
Is a {{jsxref('Boolean')}} that reflects the {{htmlattrxref("loop", "video")}} HTML attribute, which indicates whether the media element should start over when it reaches the end.
+
{{domxref("HTMLMediaElement.mediaGroup")}}
+
Is a {{domxref("DOMString")}} that reflects the {{ htmlattrxref("mediagroup", "video")}} HTML attribute, which indicates the name of the group of elements it belongs to. A group of media elements shares a common {{domxref('MediaController')}}.
+
{{domxref("HTMLMediaElement.mediaKeys")}} {{readonlyinline}} {{experimental_inline}}
+
Returns a {{domxref("MediaKeys")}} object or null. MediaKeys is a set of keys that an associated HTMLMediaElement can use for decryption of media data during playback.
+
{{domxref("HTMLMediaElement.mozAudioCaptured")}} {{readonlyinline}} {{non-standard_inline}}
+
Returns a {{jsxref('Boolean')}}. Related to audio stream capture.
+
{{domxref("HTMLMediaElement.mozFragmentEnd")}} {{non-standard_inline}}
+
Is a double that provides access to the fragment end time if the media element has a fragment URI for currentSrc, otherwise it is equal to the media duration.
+
{{domxref("HTMLMediaElement.mozFrameBufferLength")}} {{non-standard_inline}} {{deprecated_inline}}
+
+

Is a unsigned long that indicates the number of samples that will be returned in the framebuffer of each MozAudioAvailable event. This number is a total for all channels, and by default is set to be the number of channels * 1024 (e.g., 2 channels * 1024 samples = 2048 total).

+ +

The mozFrameBufferLength property can be set to a new value for lower latency, larger amounts of data, etc. The size given must be a number between 512 and 16384. Using any other size results in an exception being thrown. The best time to set a new length is after the loadedmetadata event fires, when the audio info is known, but before the audio has started or MozAudioAvailable events have begun firing.

+
+
{{domxref("HTMLMediaElement.mozSampleRate")}} {{readonlyinline}} {{non-standard_inline}} {{deprecated_inline}}
+
Returns a double representing the number of samples per second that will be played. For example, 44100 samples per second is the sample rate used by CD audio.
+
{{domxref("HTMLMediaElement.muted")}}
+
Is a {{jsxref('Boolean')}} that determines whether audio is muted. true if the audio is muted and false otherwise.
+
{{domxref("HTMLMediaElement.networkState")}} {{readonlyinline}}
+
Returns a unsigned short (enumeration) indicating the current state of fetching the media over the network.
+
{{domxref("HTMLMediaElement.paused")}} {{readonlyinline}}
+
Returns a {{jsxref('Boolean')}} that indicates whether the media element is paused.
+
{{domxref("HTMLMediaElement.playbackRate")}}
+
Is a double that indicates the rate at which the media is being played back. 
+
{{domxref("HTMLMediaElement.played")}} {{readonlyinline}}
+
Returns a {{domxref('TimeRanges')}} object that contains the ranges of the media source that the browser has played, if any.
+
{{domxref("HTMLMediaElement.preload")}}
+
Is a {{domxref("DOMString")}} that reflects the {{htmlattrxref("preload", "video")}} HTML attribute, indicating what data should be preloaded, if any. Possible values are: none, metadata, auto.
+
{{domxref("HTMLMediaElement.preservesPitch")}} {{non-standard_inline}}
+
Is a {{jsxref('Boolean')}} that determines if the pitch of the sound will be preserved. If set to false, the pitch will adjust to the speed of the audio. This is implemented with prefixes in Firefox (mozPreservesPitch) and WebKit (webkitPreservesPitch).
+
{{domxref("HTMLMediaElement.readyState")}} {{readonlyinline}}
+
Returns a unsigned short (enumeration) indicating the readiness state of the media.
+
{{domxref("HTMLMediaElement.seekable")}} {{readonlyinline}}
+
Returns a {{domxref('TimeRanges')}} object that contains the time ranges that the user is able to seek to, if any.
+
{{domxref("HTMLMediaElement.seeking")}} {{readonlyinline}}
+
Returns a {{jsxref('Boolean')}} that indicates whether the media is in the process of seeking to a new position.
+
{{domxref("HTMLMediaElement.sinkId")}} {{readonlyinline}} {{experimental_inline}}
+
Returns a {{domxref("DOMString")}} that is the unique ID of the audio device delivering output, or an empty string if it is using the user agent default. This ID should be one of the MediaDeviceInfo.deviceid values returned from {{domxref("MediaDevices.enumerateDevices()")}}, id-multimedia, or id-communications.
+
{{domxref("HTMLMediaElement.src")}}
+
Is a {{domxref("DOMString")}} that reflects the {{htmlattrxref("src", "video")}} HTML attribute, which contains the URL of a media resource to use.
+
{{domxref("HTMLMediaElement.srcObject")}}
+
Is a {{domxref('MediaStream')}} representing the media to play or that has played in the current HTMLMediaElement, or null if not assigned.
+
{{domxref("HTMLMediaElement.textTracks")}} {{readonlyinline}}
+
Returns the list of {{domxref("TextTrack")}} objects contained in the element.
+
{{domxref("HTMLMediaElement.videoTracks")}} {{readonlyinline}}
+
Returns the list of {{domxref("VideoTrack")}} objects contained in the element. +
+

Gecko supports only single track playback, and the parsing of tracks' metadata is only available for media with the Ogg container format.

+
+
+
{{domxref("HTMLMediaElement.volume")}}
+
Is a double indicating the audio volume, from 0.0 (silent) to 1.0 (loudest).
+
+ +

Event handlers

+ +
+
 
+
{{domxref("HTMLMediaElement.onencrypted")}}
+
Sets the {{domxref('EventHandler')}} called when the media is encrypted.
+
{{domxref("HTMLMediaElement.onwaitingforkey")}}
+
Sets the {{domxref('EventHandler')}} called when playback is blocked while waiting for an encryption key.
+
+ +

Obsolete attributes

+ +

These attributes are obsolete and should not be used, even if a browser still supports them.

+ +

 

+ +
+
{{domxref("HTMLMediaElement.initialTime")}} {{readonlyinline}} {{non-standard_inline}} {{obsolete_inline}}
+
Returns a double that indicates the initial playback position in seconds.
+
{{domxref("HTMLMediaElement.mozChannels")}} {{readonlyinline}} {{non-standard_inline}} {{deprecated_inline}}
+
Returns a double representing the number of channels in the audio resource (e.g., 2 for stereo).
+
+ +

Obsolete event handlers

+ +

 

+ +
+
{{domxref("HTMLMediaElement.onmozinterruptbegin")}} {{non-standard_inline}} {{obsolete_inline}}
+
Sets the {{domxref("EventHandler")}} called when the media element is interrupted because of the Audio Channel manager. This was Firefox-specific, having been implemented for Firefox OS, and was removed in Firefox 55.
+
{{domxref("HTMLMediaElement.onmozinterruptend")}} {{non-standard_inline}} {{obsolete_inline}}
+
Sets the {{domxref('EventHandler')}} called when the interruption is concluded. This was Firefox-specific, having been implemented for Firefox OS, and was removed in Firefox 55.
+
+ +

 

+ +

 

+ +

Methods

+ +

This interface also inherits methods from its ancestors {{domxref("HTMLElement")}}, {{domxref('Element')}}, {{domxref('Node')}}, and {{domxref('EventTarget')}}.

+ +
+
{{domxref("HTMLMediaElement.addTextTrack()")}}
+
Adds a text track (such as a track for subtitles) to a media element.
+
{{domxref("HTMLMediaElement.captureStream()")}} {{experimental_inline}}
+
Returns {{domxref("MediaStream")}}, captures a stream of the media content.
+
{{domxref("HTMLMediaElement.canPlayType()")}}
+
Determines whether the specified media type can be played back.
+
{{domxref("HTMLMediaElement.fastSeek()")}}
+
Directly seeks to the given time.
+
{{domxref("HTMLMediaElement.load()")}}
+
Resets the media element and restarts the media resource. Any pending events are discarded. How much media data is fetched is still affected by the preload attribute. This method can be useful for releasing resources after any src attribute and source element descendants have been removed. Otherwise, it is usually unnecessary to use this method, unless required to rescan source element children after dynamic changes.
+
{{domxref("HTMLMediaElement.mozCaptureStream()")}} {{non-standard_inline}}
+
[enter description]
+
{{domxref("HTMLMediaElement.mozCaptureStreamUntilEnded()")}} {{non-standard_inline}}
+
[enter description]
+
{{domxref("HTMLMediaElement.mozGetMetadata()")}} {{non-standard_inline}}
+
Returns {{jsxref('Object')}}, which contains properties that represent metadata from the playing media resource as {key: value} pairs. A separate copy of the data is returned each time the method is called. This method must be called after the loadedmetadata event fires.
+
{{domxref("HTMLMediaElement.pause()")}}
+
Pauses the media playback.
+
{{domxref("HTMLMediaElement.play()")}}
+
Begins playback of the media.
+
{{domxref("HTMLMediaElement.seekToNextFrame()")}} {{non-standard_inline}} {{experimental_inline}}
+
Seeks to the next frame in the media. This non-standard, experimental method makes it possible to manually drive reading and rendering of media at a custom speed, or to move through the media frame-by-frame to perform filtering or other operations.
+
{{domxref("HTMLMediaElement.setMediaKeys()")}} {{experimental_inline}}
+
Returns {{jsxref("Promise")}}. Sets the {{domxref("MediaKeys")}} keys to use when decrypting media during playback.
+
{{domxref("HTMLMediaElement.setSinkId()")}} {{experimental_inline}}
+
Sets the ID of the audio device to use for output and returns a {{jsxref("Promise")}}. This only works when the application is authorized to use the specified device.
+
+ +

Obsolete methods

+ +

These methods are obsolete and should not be used, even if a browser still supports them.

+ +

 

+ +
+
{{domxref("HTMLMediaElement.mozLoadFrom()")}} {{non-standard_inline}} {{deprecated_inline}}
+
This method, available only in Mozilla's implementation, loads data from another media element. This works similarly to load() except that instead of running the normal resource selection algorithm, the source is simply set to the other element's currentSrc. This is optimized so this element gets access to all of the other element's cached and buffered data; in fact, the two elements share downloaded data, so data downloaded by either element is available to both.
+
+ +

 

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', "the-video-element.html#htmlmediaelement", "HTMLMediaElement")}}{{Spec2('HTML WHATWG')}}No change from {{SpecName('HTML5 W3C')}}
{{SpecName('HTML5 W3C', "embedded-content-0.html#htmlmediaelement", "HTMLMediaElement")}}{{Spec2('HTML5 W3C')}}Initial definition.
{{SpecName('EME', '#introduction', 'Encrypted Media Extensions')}}{{Spec2('EME')}}Adds {{domxref("MediaKeys")}}, {{domxref("MediaEncryptedEvent")}}, {{domxref("setMediaKeys")}}, {{domxref("onencrypted")}}, and {{domxref("onwaitingforkey")}}.
{{SpecName('Media Capture','#htmlmediaelement-extensions','HTMLMediaElement')}}{{Spec2('Media Capture')}}Adds sinkId and setSinkId(), and captureStream().
+ +

Browser compatibility

+ + + +

{{Compat("api.HTMLMediaElement")}}

+ +

See also

+ + diff --git a/files/zh-tw/web/api/htmlmediaelement/ratechange_event/index.html b/files/zh-tw/web/api/htmlmediaelement/ratechange_event/index.html new file mode 100644 index 0000000000..e4c6a3d743 --- /dev/null +++ b/files/zh-tw/web/api/htmlmediaelement/ratechange_event/index.html @@ -0,0 +1,82 @@ +--- +title: 'HTMLMediaElement: ratechange' +slug: Web/API/HTMLMediaElement/ratechange_event +tags: + - 播放速度 速度 速率 +translation_of: Web/API/HTMLMediaElement/ratechange_event +--- +

ratechange 事件將在播放速度改變時被觸發

+ +

基本資訊

+ +
+
規格
+
HTML5 Media
+
介面
+
事件
+
是否冒泡
+
+
是否可取消
+
+
目標
+
元素
+
預設行為
+
+
+ +

屬性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
屬性類型描述
target {{readonlyInline}}{{domxref("EventTarget")}}事件目標(DOM樹中最頂層的目標)
type {{readonlyInline}}{{domxref("DOMString")}}事件類型
bubbles {{readonlyInline}}{{jsxref("Boolean")}}事件是否觸發冒泡
cancelable {{readonlyInline}}{{jsxref("Boolean")}}事件是否可取消
+ +

相關事件

+ + diff --git a/files/zh-tw/web/api/htmlmediaelement/readystate/index.html b/files/zh-tw/web/api/htmlmediaelement/readystate/index.html new file mode 100644 index 0000000000..14df7bb4e0 --- /dev/null +++ b/files/zh-tw/web/api/htmlmediaelement/readystate/index.html @@ -0,0 +1,110 @@ +--- +title: HTMLMediaElement.readyState +slug: Web/API/HTMLMediaElement/readyState +translation_of: Web/API/HTMLMediaElement/readyState +--- +
{{APIRef("HTML DOM")}}
+ +
HTMLMediaElement.readyState 屬性回傳目前媒體的就緒狀態。
+ +

語法

+ +
var readyState = audioOrVideo.readyState;
+ +

+ +

一個 unsigned short,可能的值有:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
常數描述
HAVE_NOTHING0沒有可用的媒體資源。
HAVE_METADATA1已經取得足夠的媒體資源並已初始化元資料。繼續取得媒體資源不會導致例外。
HAVE_CURRENT_DATA2媒體資料已經足夠播放目前的時間,但沒有足夠的資料再播放一幀。
HAVE_FUTURE_DATA3資料已經足夠播放目前的時間,而且有至少一點點資料可以播放未來的時間(換句話說,可能只多了一到兩幀)。
HAVE_ENOUGH_DATA4資料足夠,且下載率夠高。媒體可以播放到結束而不被中斷。
+ +

範例

+ +

下面這個例子會監聽 `example` 這個元素,並檢查是否已載入足夠的媒體資源。如果是的話,它會繼續播放。

+ +
<audio id="example" preload="auto">
+ <source src="sound.ogg" type="audio/ogg" />
+</audio>
+
+
+ +
var obj = document.getElementById('example');
+
+obj.addEventListener('loadeddata', function() {
+
+  if(obj.readyState >= 2) {
+    obj.play();
+  }
+
+});
+
+ +

 

+ +

標準

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', "the-video-element.html#htmlmediaelement", "HTMLMediaElement.readyState")}}{{Spec2('HTML WHATWG')}}No change from {{SpecName('HTML5 W3C')}}
{{SpecName('HTML5 W3C', "embedded-content-0.html#htmlmediaelement", "HTMLMediaElement.readyState")}}{{Spec2('HTML5 W3C')}}Initial definition.
+ +

瀏覽器相容性

+ + + +

{{Compat("api.HTMLMediaElement.readyState")}}

+ +

也參考看看

+ + diff --git a/files/zh-tw/web/api/htmlselectelement/checkvalidity/index.html b/files/zh-tw/web/api/htmlselectelement/checkvalidity/index.html new file mode 100644 index 0000000000..8ded860ac4 --- /dev/null +++ b/files/zh-tw/web/api/htmlselectelement/checkvalidity/index.html @@ -0,0 +1,98 @@ +--- +title: HTMLSelectElement.checkValidity() +slug: Web/API/HTMLSelectElement/checkValidity +translation_of: Web/API/HTMLSelectElement/checkValidity +--- +
{{ APIRef("HTML DOM") }}
+ +

HTMLSelectElement.checkValidity() 方法會檢查元素是否有任何的檢核、驗證條件,並且檢查是否滿足這些條件。如果元素沒有通過這些檢核,瀏覽器會於該元素上觸發一個可取消的 {{event("invalid")}} 事件,並回傳 false

+ +

語法

+ +
var result = selectElt.checkValidity();
+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#dom-cva-checkvalidity', 'HTMLSelectElement.checkValidity()')}}{{Spec2('HTML WHATWG')}}No change since the latest snapshot, {{SpecName('HTML5 W3C')}}.
{{SpecName('HTML5 W3C', 'forms.html#dom-cva-checkvalidity', 'HTMLSelectElement.checkValidity()')}}{{Spec2('HTML5 W3C')}}Initial definition, snapshot of {{SpecName('HTML WHATWG')}}
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(2.0)}}10{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChromeEdgeFirefox Mobile (Gecko)Firefox OSIE PhoneOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(2.0)}}1.0{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/htmlselectelement/index.html b/files/zh-tw/web/api/htmlselectelement/index.html new file mode 100644 index 0000000000..0110568dd6 --- /dev/null +++ b/files/zh-tw/web/api/htmlselectelement/index.html @@ -0,0 +1,283 @@ +--- +title: HTMLSelectElement +slug: Web/API/HTMLSelectElement +translation_of: Web/API/HTMLSelectElement +--- +
{{APIRef("HTML DOM")}}
+ +

HTMLSelectElement 介面代表了 {{HTMLElement("select")}} HTML 元素。此介面也自 {{domxref("HTMLElement")}} 介面繼承了所有 HTML 元素的屬性及方法。

+ +

{{InheritanceDiagram(600, 120)}}

+ +

屬性

+ +

This interface inherits the properties of {{domxref("HTMLElement")}}, and of {{domxref("Element")}} and {{domxref("Node")}}.

+ +
+
{{domxref("HTMLSelectElement.autofocus")}}
+
A {{jsxref("Boolean")}} reflecting the {{htmlattrxref("autofocus", "select")}} HTML attribute, which indicates whether the control should have input focus when the page loads, unless the user overrides it, for example by typing in a different control. Only one form-associated element in a document can have this attribute specified. {{gecko_minversion_inline("2.0")}}
+
{{domxref("HTMLSelectElement.disabled")}}
+
A {{jsxref("Boolean")}} reflecting the {{htmlattrxref("disabled", "select")}} HTML attribute, which indicates whether the control is disabled. If it is disabled, it does not accept clicks.
+
{{domxref("HTMLSelectElement.form")}}{{ReadOnlyInline}}
+
An {{domxref("HTMLFormElement")}} referencing the form that this element is associated with. If the element is not associated with of a {{HTMLElement("form")}} element, then it returns null.
+
{{domxref("HTMLSelectElement.labels")}}{{ReadOnlyInline}}
+
A {{domxref("NodeList")}} of {{HTMLElement("label")}} elements associated with the element.
+
{{domxref("HTMLSelectElement.length")}}
+
An unsigned long The number of {{HTMLElement("option")}} elements in this select element.
+
{{domxref("HTMLSelectElement.multiple")}}
+
A {{jsxref("Boolean")}} reflecting the {{htmlattrxref("multiple", "select")}} HTML attribute, which indicates whether multiple items can be selected.
+
{{domxref("HTMLSelectElement.name")}}
+
A {{domxref("DOMString")}} reflecting the {{htmlattrxref("name", "select")}} HTML attribute, containing the name of this control used by servers and DOM search functions.
+
{{domxref("HTMLSelectElement.options")}}{{ReadOnlyInline}}
+
An {{domxref("HTMLOptionsCollection")}} representing the set of {{HTMLElement("option")}} elements contained by this element.
+
{{domxref("HTMLSelectElement.required")}}
+
A {{jsxref("Boolean")}} reflecting the {{htmlattrxref("required", "select")}} HTML attribute, which indicates whether the user is required to select a value before submitting the form. {{gecko_minversion_inline("2.0")}}
+
{{domxref("HTMLSelectElement.selectedIndex")}}
+
A long reflecting the index of the first selected {{HTMLElement("option")}} element. The value -1 indicates no element is selected.
+
{{domxref("HTMLSelectElement.selectedOptions")}}{{ReadOnlyInline}}
+
An {{domxref("HTMLCollection")}} representing the set of {{HTMLElement("option")}} elements that are selected.
+
{{domxref("HTMLSelectElement.size")}}
+
A long reflecting the {{htmlattrxref("size", "select")}} HTML attribute, which contains the number of visible items in the control. The default is 1, unless multiple is true, in which case it is 4.
+
{{domxref("HTMLSelectElement.type")}}{{ReadOnlyInline}}
+
A {{domxref("DOMString")}} represeting the form control's type. When multiple is true, it returns "select-multiple"; otherwise, it returns "select-one".
+
{{domxref("HTMLSelectElement.validationMessage")}}{{ReadOnlyInline}}
+
A {{domxref("DOMString")}} representing a localized message that describes the validation constraints that the control does not satisfy (if any). This attribute is the empty string if the control is not a candidate for constraint validation (willValidate is false), or it satisfies its constraints.
+
{{domxref("HTMLSelectElement.validity")}}{{ReadOnlyInline}}
+
A {{domxref("ValidityState")}} reflecting the validity state that this control is in.
+
{{domxref("HTMLSelectElement.value")}}
+
A {{domxref("DOMString")}} reflecting the value of the form control (the first selected option).
+
{{domxref("HTMLSelectElement.willValidate")}}{{ReadOnlyInline}}
+
A {{jsxref("Boolean")}} that indicates whether the button is a candidate for constraint validation. It is false if any conditions bar it from constraint validation.
+
+ +

Methods

+ +

This interface inherits the methods of {{domxref("HTMLElement")}}, and of {{domxref("Element")}} and {{domxref("Node")}}.

+ +
+
{{domxref("HTMLSelectElement.add()")}}
+
Adds an element to the collection of option elements for this select element.
+
{{domxref("HTMLSelectElement.blur()")}}{{obsolete_inline}}
+
Removes input focus from this element. This method is now implemented on {{domxref("HTMLElement")}}.
+
{{domxref("HTMLSelectElement.checkValidity()")}}
+
Checks whether the element has any constraints and whether it satisfies them. If the element fails its constraints, the browser fires a cancelable {{event("invalid")}} event at the element (and returns false).
+
{{domxref("HTMLSelectElement.focus()")}}{{obsolete_inline}}
+
Gives input focus to this element. This method is now implemented on {{domxref("HTMLElement")}}.
+
{{domxref("HTMLSelectElement.item()")}}
+
Gets an item from the options collection for this {{HTMLElement("select")}} element. You can also access an item by specifying the index in array-style brackets or parentheses, without calling this method explicitly.
+
{{domxref("HTMLSelectElement.namedItem()")}}
+
Gets the item in the options collection with the specified name. The name string can match either the id or the name attribute of an option node. You can also access an item by specifying the name in array-style brackets or parentheses, without calling this method explicitly.
+
{{domxref("HTMLSelectElement.remove()")}}
+
Removes the element at the specified index from the options collection for this select element.
+
{{domxref("HTMLSelectElement.setCustomValidity()")}}
+
Sets the custom validity message for the selection element to the specified message. Use the empty string to indicate that the element does not have a custom validity error.
+
+ +

範例

+ +

Get information about the selected option

+ +
/* assuming we have the following HTML
+<select id='s'>
+    <option>First</option>
+    <option selected>Second</option>
+    <option>Third</option>
+</select>
+*/
+
+var select = document.getElementById('s');
+
+// return the index of the selected option
+console.log(select.selectedIndex); // 1
+
+// return the value of the selected option
+console.log(select.options[select.selectedIndex].value) // Second
+
+ +

A better way to track changes to the user's selection is to watch for the {{event("change")}} event to occur on the <select>. This will tell you when the value changes, and you can then update anything you need to. See the example provided in the documentation for the change event for details.

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#htmlselectelement', 'HTMLSelectElement')}}{{Spec2('HTML WHATWG')}}Since the latest snapshot, {{SpecName('HTML5 W3C')}}, it adds the autocomplete property and the reportValidity() method.
{{SpecName('HTML5 W3C', 'forms.html#htmlselectelement', 'HTMLSelectElement')}}{{Spec2('HTML5 W3C')}}Is a snapshot of {{SpecName("HTML WHATWG")}}.
+ It adds the autofocus, form, required, labels, selectedOptions, willValidate, validity and validationMessage properties.
+ The tabindex property and the blur() and focus() methods have been moved to {{domxref("HTMLElement")}}.
+ The methods item(), namedItem(), checkValidity() and setCustomValidity().
{{SpecName('DOM2 HTML', 'html.html#ID-94282980', 'HTMLSelectElement')}}{{Spec2('DOM2 HTML')}}options now returns an {{domxref("HTMLOptionsCollection")}}.
+ length now returns an unsigned long.
{{SpecName('DOM1', 'level-one-html.html#ID-94282980', 'HTMLSelectElement')}}{{Spec2('DOM1')}}Initial definition
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop(1.0)}} [2]1.01.01.0
item() and namedItem(){{CompatVersionUnknown}}{{CompatVersionUnknown}}[3]{{CompatGeckoDesktop(2.0)}}8[3]{{CompatVersionUnknown}}{{CompatVersionUnknown}}
setCustomValidity(), checkValidity(), willValidate, validationMessage, validity{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(2.0)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}
selectedOptions{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(26)}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
labels{{CompatVersionUnknown}}{{CompatNo}}{{CompatGeckoDesktop(56)}}[1]{{CompatNo}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChromeEdgeFirefox Mobile (Gecko)Firefox OSIE PhoneOpera MobileSafari Mobile
Basic support1.01.0{{CompatVersionUnknown}}{{CompatGeckoMobile(1)}}1.01.01.01.0
item() and namedItem(){{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(2.0)}}1.0{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
setCustomValidity(), checkValidity(), willValidate, validationMessage, validity{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(2.0)}}1.0{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
selectedOptions{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(26)}}1.2{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
labels{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}{{CompatGeckoMobile(56)}}[1]{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
+
+ +

[1] Implemented in {{bug("556743")}}.

+ +

[2] Historically, Firefox has allowed keyboard and mouse events to bubble up from the <option> element to the parent {{HTMLElement("select")}} element. This doesn't happen in Chrome, however, although this behavior is inconsistent across many browsers. For better Web compatibility (and for technical reasons), when Firefox is in multi-process mode and the <select> element is displayed as a drop-down list. The behavior is unchanged if the <select> is presented inline and it has either the multiple attribute defined or a size attribute set to more than 1. Rather than watching <option> elements for events, you should watch for {event("change")}} events on {{HTMLElement("select")}}. See {{bug(1090602)}} for details.

+ +

[3] namedItem does not appear to take the name attribute into account (only the id attribute) on Internet Explorer and Edge. There is a bug report to Microsoft about this.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/htmlselectelement/setcustomvalidity/index.html b/files/zh-tw/web/api/htmlselectelement/setcustomvalidity/index.html new file mode 100644 index 0000000000..54e47edf3c --- /dev/null +++ b/files/zh-tw/web/api/htmlselectelement/setcustomvalidity/index.html @@ -0,0 +1,50 @@ +--- +title: HTMLSelectElement.setCustomValidity() +slug: Web/API/HTMLSelectElement/setCustomValidity +translation_of: Web/API/HTMLSelectElement/setCustomValidity +--- +
{{ APIRef("HTML DOM") }}
+ +

HTMLSelectElement.setCustomValidity() 方法可為指定的元素設定自定義檢核訊息。使用空字串表示元素沒有發生違反自定檢核條件的錯誤。

+ +

語法

+ +
selectElt.setCustomValidity(string);
+ +

參數

+ + + +

規範

+ + + + + + + + + + + + + + + + + + + +
規範狀態意見
{{SpecName('HTML WHATWG', '#dom-cva-setcustomvalidity', 'HTMLSelectElement.setCustomValidity()')}}{{Spec2('HTML WHATWG')}}No change since the latest snapshot, {{SpecName('HTML5 W3C')}}.
{{SpecName('HTML5 W3C', 'forms.html#dom-cva-setcustomvalidity', 'HTMLSelectElement.setCustomValidity()')}}{{Spec2('HTML5 W3C')}}Initial definition, snapshot of {{SpecName('HTML WHATWG')}}
+ +

瀏覽器相容性

+ +

{{Compat("api.HTMLSelectElement.setCustomValidity")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/idbdatabase/index.html b/files/zh-tw/web/api/idbdatabase/index.html new file mode 100644 index 0000000000..843eac92f5 --- /dev/null +++ b/files/zh-tw/web/api/idbdatabase/index.html @@ -0,0 +1,219 @@ +--- +title: IDBDatabase +slug: Web/API/IDBDatabase +translation_of: Web/API/IDBDatabase +--- +

{{APIRef("IndexedDB")}}

+ +
+

The IDBDatabase interface of the IndexedDB API provides a connection to a database; you can use an IDBDatabase object to open a transaction on your database then create, manipulate, and delete objects (data) in that database. The interface provides the only way to get and manage versions of the database.

+ +

{{AvailableInWorkers}}

+
+ +
+

Note: Everything you do in IndexedDB always happens in the context of a transaction, representing interactions with data in the database. All objects in IndexedDB — including object stores, indexes, and cursors — are tied to a particular transaction. Thus, you cannot execute commands, access data, or open anything outside of a transaction.

+
+ +
+

Note: Note that as of Firefox 40, IndexedDB transactions have relaxed durability guarantees to increase performance (see {{Bug("1112702")}}.) Previously in a readwrite transaction {{domxref("IDBTransaction.oncomplete")}} was fired only when all data was guaranteed to have been flushed to disk. In Firefox 40+ the complete event is fired after the OS has been told to write the data but potentially before that data has actually been flushed to disk. The complete event may thus be delivered quicker than before, however, there exists a small chance that the entire transaction will be lost if the OS crashes or there is a loss of system power before the data is flushed to disk. Since such catastrophic events are rare most consumers should not need to concern themselves further. If you must ensure durability for some reason (e.g. you're storing critical data that cannot be recomputed later) you can force a transaction to flush to disk before delivering the complete event by creating a transaction using the experimental (non-standard) readwriteflush mode (see {{domxref("IDBDatabase.transaction")}}.

+
+ +

Methods

+ +

Inherits from: EventTarget

+ +
+
{{domxref("IDBDatabase.close()")}}
+
Returns immediately and closes the connection to a database in a separate thread.
+
{{domxref("IDBDatabase.createObjectStore()")}}
+
Creates and returns a new object store or index.
+
{{domxref("IDBDatabase.deleteObjectStore()")}}
+
Destroys the object store with the given name in the connected database, along with any indexes that reference it.
+
{{domxref("IDBDatabase.transaction()")}}
+
Immediately returns a transaction object ({{domxref("IDBTransaction")}}) containing the {{domxref("IDBTransaction.objectStore")}} method, which you can use to access your object store. Runs in a separate thread.
+
+ +

屬性

+ +
+
{{domxref("IDBDatabase.name")}} {{readonlyInline}}
+
A {{ domxref("DOMString") }} that contains the name of the connected database.
+
{{domxref("IDBDatabase.version")}} {{readonlyInline}}
+
A 64-bit integer that contains the version of the connected database. When a database is first created, this attribute is an empty string.
+
{{domxref("IDBDatabase.objectStoreNames")}} {{readonlyInline}}
+
A {{ domxref("DOMStringList") }} that contains a list of the names of the object stores currently in the connected database.
+
+ +

Event handlers

+ +
+
{{domxref("IDBDatabase.onabort")}}
+
Fires when access of the database is aborted.
+
{{domxref("IDBDatabase.onerror")}}
+
Fires when access to the database fails.
+
{{domxref("IDBDatabase.onversionchange")}}
+
+

Fires when a database structure change ({{domxref("IDBOpenDBRequest.onupgradeneeded")}} event or {{domxref("IDBFactory.deleteDatabase")}} was requested elsewhere (most probably in another window/tab on the same computer). This is different from the version change transaction (see {{domxref("IDBVersionChangeEvent")}}), but it is related.

+
+
+ +

範例

+ +

In the following code snippet, we open a database asynchronously ({{domxref("IDBFactory")}}), handle success and error cases, and create a new object store in the case that an upgrade is needed ({{ domxref("IDBdatabase") }}). For a complete working example, see our To-do Notifications app (view example live.)

+ +
// Let us open our database
+  var DBOpenRequest = window.indexedDB.open("toDoList", 4);
+
+  // these two event handlers act on the IDBDatabase object, when the database is opened successfully, or not
+  DBOpenRequest.onerror = function(event) {
+    note.innerHTML += '<li>Error loading database.</li>';
+  };
+
+  DBOpenRequest.onsuccess = function(event) {
+    note.innerHTML += '<li>Database initialised.</li>';
+
+    // store the result of opening the database in the db variable. This is used a lot later on
+    db = DBOpenRequest.result;
+
+    // Run the displayData() function to populate the task list with all the to-do list data already in the IDB
+    displayData();
+  };
+
+  // This event handles the event whereby a new version of the database needs to be created
+  // Either one has not been created before, or a new version number has been submitted via the
+  // window.indexedDB.open line above
+
+  DBOpenRequest.onupgradeneeded = function(event) {
+    var db = event.target.result;
+
+    db.onerror = function(event) {
+      note.innerHTML += '<li>Error loading database.</li>';
+    };
+
+    // Create an objectStore for this database using IDBDatabase.createObjectStore
+
+    var objectStore = db.createObjectStore("toDoList", { keyPath: "taskTitle" });
+
+    // define what data items the objectStore will contain
+
+    objectStore.createIndex("hours", "hours", { unique: false });
+    objectStore.createIndex("minutes", "minutes", { unique: false });
+    objectStore.createIndex("day", "day", { unique: false });
+    objectStore.createIndex("month", "month", { unique: false });
+    objectStore.createIndex("year", "year", { unique: false });
+
+    objectStore.createIndex("notified", "notified", { unique: false });
+
+    note.innerHTML += '<li>Object store created.</li>';
+  };
+ +

This next line opens up a transaction on the Database, then opens an object store that we can then manipulate the data inside of.

+ +
    var objectStore = db.transaction('toDoList').objectStore('toDoList'); 
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('IndexedDB', '#idl-def-IDBDatabase', 'IDBDatabase')}}{{Spec2('IndexedDB')}} 
+ +

Browser compatibility

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support23{{property_prefix("webkit")}}
+ 24
10 {{property_prefix("moz")}}
+ {{CompatGeckoDesktop("16.0")}}
10, partial157.1
Available in workers{{CompatVersionUnknown}}{{CompatGeckoMobile("37.0")}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)Firefox OSIE PhoneOpera MobileSafari Mobile
Basic support4.4{{CompatGeckoMobile("22.0")}}1.0.110228
Available in workers{{CompatVersionUnknown}}{{CompatGeckoMobile("37.0")}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}
+
+ +
+

Important: Be careful in Chrome as it still implements the old specification along with the new one. Similarly it still has the prefixed webkitIndexedDB property even if the unprefixed indexedDB is present.

+
+ +

閱讀更多

+ + + +

 

diff --git a/files/zh-tw/web/api/index.html b/files/zh-tw/web/api/index.html new file mode 100644 index 0000000000..982a2aa3c0 --- /dev/null +++ b/files/zh-tw/web/api/index.html @@ -0,0 +1,15 @@ +--- +title: Web APIs +slug: Web/API +tags: + - API + - DOM + - JavaScript + - Reference +translation_of: Web/API +--- +

當你使用 JavaScript 為網站寫程式碼時,有很多很棒的 API 可以使用。

+ +

以下清單列出所有能夠用在你開發網路程式或網站時的介面(即是物件的類型)。

+ +
{{APIListAlpha}}
diff --git a/files/zh-tw/web/api/indexeddb_api/basic_concepts_behind_indexeddb/index.html b/files/zh-tw/web/api/indexeddb_api/basic_concepts_behind_indexeddb/index.html new file mode 100644 index 0000000000..a57486e7b2 --- /dev/null +++ b/files/zh-tw/web/api/indexeddb_api/basic_concepts_behind_indexeddb/index.html @@ -0,0 +1,209 @@ +--- +title: IndexedDB基礎概念 +slug: Web/API/IndexedDB_API/Basic_Concepts_Behind_IndexedDB +translation_of: Web/API/IndexedDB_API/Basic_Concepts_Behind_IndexedDB +--- +

IndexedDB 用來儲存資料到使用者的瀏覽器,所以我們的網頁應用程式不論在線上或線下都可以運作。IndexedDB 對需要儲存大量資料上 (如儲存 DVD 出租型錄) 的應用和不用一直存取網路的應用 (如郵件客戶端瀏覽、代辦事項、記事本等) 來說十分好用。

+ +

關於本文

+ +

本文介紹 IndexedDB 重要概念和專有名詞,旨在提供 IndexedDB 全貌和關鍵概念,如要了解更多 IndexedDB 專有名詞,請參照定義部分。

+ +

想了解如何使用相關 API,請參照使用 IndexedDB;相關參考資料請參照 IndexedDB 一文,該文介紹了 IndexedDB 使用物件型態以及同步和非同步 API 。

+ +

IndexedDB 概要

+ +

IndexedDB 讓我們透過資料鍵 (key) 儲存、取回物件。所有對資料庫的變更都發生在交易操作;如同大部分網頁儲存方案,IndexedDB 遵守同源政策,也就是說我們只能存取同網域下的資料。

+ +

API 有分非同步同步,非同步 API 適用於大部分情況,包括 Web Worker,而同步 API 應該只用在 Web Worker 內。目前主流瀏覽器尚不支援同步 API,不過即使同步 API 存在,大部分的情況還是以非同步 API 使用為主。

+ +

W3C 在 2011/11/18 宣布 WebSQL 已棄用,請用 IndexedDB 作為替代方案。IndexedDB 和 WebSQL 雖然都是儲存方案,但功能並不相同,IndexedDB 是索引資料表資料庫,而 WebSQL 是關聯式資料庫系統。

+ +

概念總覽

+ +

請將你在其他類型資料庫上的預期從 IndexedDB 上拋開,然後謹記以下重要概念:

+ + + +

定義

+ +

以下是 IndexedDB API 專有名詞定義與解說。

+ +

Database

+ +
+
資料庫
+
資訊集中存放之處,由一或數個物件存檔 (Object store) 組成,每一個資料庫必須具有: +
    +
  • 名稱。用以辨識資料庫所屬來源,在生命週期間固定不變,可以任意字串 (甚至空白字串) 。
  • +
  • +

    目前版本。當資料庫創建後,如未指定,它的版本是整數1。每一個資料庫同一時間只能有一個版本。

    +
  • +
+
+
物件存檔 (object store)
+
+

資料存放於資料庫的機制;物件存檔持有紀錄,也就是資料鍵和資料值的成對紀錄。記錄在物件存檔中依資料鍵 (keys)大小由小到大排列。

+ +

每一個物件存檔都具備獨特名稱,物件存檔能夠選擇性地持有 key generator 和 key path;若有 key path 便會採用 in-line keys,否則便採用 out-of-line keys

+ +

更多物件存檔細節,請參照 IDBObjectStore 或 IDBObjectStoreSync

+
+
版本 (version)
+
當資料庫創建後,如未指定,它的版本是整數 1;每一個資料庫同一時間只能有一個版本,唯一變更版本的方法是開啟比目前更大的版本,變更版本將啟動 versionchange 交易並且觸發 upgradeneeded 事件,upgradeneeded 事件處理器也是唯一可以變更資料庫結構之處。
+
注意: 本處解說涵蓋近期大部分規範,舊版瀏覽器支援現在已經廢棄的 IDBDatabase.setVersion() 方法。
+
 
+
database connection
+
開啟資料庫的作業,一個資料庫同一時間可以擁有多個連線。
+
交易 (transaction)
+
+

在特定資料庫上進行資料存取和資料修改的一連串作業,這便是我們和資料庫的互動,事實上,任何讀取或變更資料庫資料都會發生在交易之中。

+ +

只要寫入交易間沒有重疊範疇 (scopes),一個資料庫連結可以同時擁有多個進行中交易。交易範疇在交易創建當下決定,交易範疇定義了與交易互動的物件存檔以及將交易期間不可變更部分,例如說,有一個資料庫連結正在進行寫入交易,這項寫入交易涵蓋 flyingMonkey 物件存檔,我們可以進行第二項有關 unicornCentaur 與 unicornPegasus 物件存檔的交易。至於讀取交易則不受交易範疇重疊限制。

+ +

交易的生命應該不可過長,所以瀏覽器可以終止交易時間過長的交易,好讓長時間被鎖定的資料得以解除鎖定;交易可以中止,中止後交易所造成的變更都會被復原;交易的中止不必要等到交易開始或進行中。

+ +

交易有三種模式: readwrite, readonly 和 versionchange,只能透過 versionchange 交易創建、刪除物件存檔與索引。

+ +

由於交易是相當重要的觀念,尤其是交易和版本間的關係,請參照 IDBTransaction 以了解更多交易相
+ 關細節,另外關於同步API,請參照IDBTransactionSync

+
+
請求 (request)
+
每一個讀寫作業都是一個請求。
+
索引 (index)
+
+

一個用來查詢其他物件存檔內紀錄的特殊物件存檔,被查詢的物件存檔我們稱為參照物件存檔 (referenced object store) 。索引是資料鍵和值的成對紀錄,其中值就是參照物件存檔內的記錄的資料鍵;當參照物件存檔有紀錄新增、變更或刪除時索引內的紀錄也會相應自動產生,索引內的紀錄只能指向參照物件存檔內的一筆紀錄,但可以有多筆索引紀錄參照同一個物件存檔。物件存檔變更同時,所有的相關索引也會自動相應更新。

+ +

除此之外,我們也可以透過資料鍵 (key) 來查詢物件存檔中的紀錄。

+ +

了解如何使用索引請參照使用 IndexedDB,要知道更多索引細節請參照 IDBKeyRange 和 IDBIndex 。

+
+
+ +

資料鍵 (Key) 和資料值 (Value)

+ +
+
資料鍵 (key)
+
+

資料存放在物件存檔中。物件存檔有三種方式產生資料鍵: 資料鍵產生器 (key generator)、資料鍵路徑 (key path) 以及指定值。資料鍵的資料型態 (data type) 必須要是能夠進行大小排序;物件存檔中的每一筆紀錄都要有一支獨特的對應資料鍵,不能和同一個物件存檔中其他紀錄的資料鍵相同。

+ +

資料鍵可以是: string, date, float和 array (陣列);對於 array,資料鍵範圍可以是空值到無限,還可以在 array 中包含另一個 array,至於以字串或整數作資料鍵則無特殊規定。

+ +

除此之外,我們也可以透過索引 (index) 來查詢物件存檔中的紀錄。

+
+
資料鍵產生器 (key generator)
+
自動生成有大小順序關係的資料鍵的機制;因為資料鍵是必要的,所以如果沒有資料鍵或想省去給定資料鍵的步驟,那就需要用產生器自動產生資料鍵。
+
in-line key
+
當物件存檔有資料鍵路徑時稱為有使用 in-line key。
+
out-of-line key
+
當物件存檔沒有資料鍵路徑時稱為使用 out-of--line key。
+
資料鍵路徑 (key path)
+
定義瀏覽器應該如何從物件存檔資料值或索引中提取資料鍵。以下為有效的資料鍵路徑: 一個空字串、一個 Javascript 辨識名稱 (JavaScript identifier) 或數個由”.”(ASCII字元第46字碼) 分隔的 Javascript 辨識名稱。路徑不可含有空白字元。
+
資料值 (value)
+
+

每筆紀錄都有資料值,資料值可以是任意Javascript所能表達的項目,包括boolean, number, string, date, object, array, regexp, undefined 以及 null。

+ +

儲存物件或陣列裡的屬性和值也可以是任意Javascript所能表達的項目。

+ +

可以儲存 Blobs 和檔案,請參照 W3C 規範

+
+
+ +

範圍和範疇

+ +
+
範疇
+
交易影響到的物件和索引。讀取交易間的範疇可以互相重疊、同時進行,然後寫入交易範疇則不可,如果同時開啟多項交易範疇相同的寫入交易的話,那麼這些交易會排入佇列 (queue),一個接著一個完成後執行。
+
指標 (Cursor)
+
在一定資料鍵範圍以內往覆 (iterate) 資料的機制。指標指向了一個物件存檔或索引,它會在一定範圍內,由小到大或由大到小循著紀錄的資料鍵移動,詳細資訊請參照 IDBCursor 或 IDBCursorSync 。
+
資料鍵範圍
+
+

某種資料型態的一段連續區間,這個區間將作為資料鍵的上下限,我們透過資料鍵或資料鍵範圍取出物件存檔和索引值;藉由上下限我們可以做到存取資料鍵介於 x 和 y 之間的資料,詳細請參考 IDBKeyRange 。

+
+
+ +

限制

+ +

IndexedDB 設計上足以滿足大部分客戶端儲存需求,不過,以下情況並不適用 IndexedDB :

+ + + +

除此之外,請小心瀏覽器可能會清空資料庫,例如:

+ + + +

瀏覽器確切的狀況和功能範疇未來會變更,但基本上瀏覽器還是會盡可能保存資料。

+ +

下一步

+ +

現在我們已經了解 IndexedDB 的整體概念,接下來請到 “使用 IndexedDB” 看看如何實際使用 IndexedDB。

+ +

延伸閱讀

+ +

標準規範

+ + + +

參照

+ + + +

相關教學

+ + + +

相關文章

+ + diff --git a/files/zh-tw/web/api/indexeddb_api/index.html b/files/zh-tw/web/api/indexeddb_api/index.html new file mode 100644 index 0000000000..91f2fc812d --- /dev/null +++ b/files/zh-tw/web/api/indexeddb_api/index.html @@ -0,0 +1,148 @@ +--- +title: IndexedDB +slug: Web/API/IndexedDB_API +tags: + - Database + - IndexedDB + - bug-840092 +translation_of: Web/API/IndexedDB_API +--- +
{{SeeCompatTable}}
+ +

IndexedDB 為用戶端的儲存用 API,可用於大量的結構化資料,並透過索引功能而高效率搜尋資料。DOM Storage 適合儲存較少量的資料;IndexedDB 則適合大量結構化資料的儲存方案。

+ +

本篇文章僅為 API 物件的入門技術說明。若需進一步了解,則請參閱 IndexedDB 基本概念。更多細節則可參閱使用 IndexedDB

+ +

IndexedDB 提供不同 APIs 用於同步與非同步的存取作業。同步 API 僅能用於Web Workers 之中,但尚未有瀏覽器支援同步API。非同步 API 則用於 Web Workers 內外均可,但 Firefox 目前尚未建構。

+ +

非同步 API

+ +

非同步API不會阻塞呼叫它的執行緒。若要非同步存取資料庫,可於 window 物件的 indexedDB 屬性上呼叫 open()。此函式將回傳 IDBRequest 物件 (IDBOpenDBRequest),開始非同步存取資料庫;呼叫端程式利用IDBRequest物件上的事件來進行非同步溝通。

+ +
+

注意:在舊版瀏覽器 (Gecko 16 版之前的 indexedDB 屬性;Chrome 中的 webkitIndexedDB;IE 10 中的 msIndexedDB) 中的 indexedDB 物件,均具備前綴屬性。

+
+ + + +

以下API在早期規範中有定義,但現已移除。這邊列出僅供參考:

+ + + +

除了非同步API,也有應用在WebWorkers內的同步API,但請注意目前還沒有瀏覽器支援同步API。這裡也提供 API 的同步版本

+ +

儲存限制

+ +

單一資料庫項目的容量/大小並沒有任何限制,但是各個 IndexedDB資料庫的容量就有限制。此限制,還有使用者介面的斷言 (Assert) 方式,又將因瀏覽器而有所不同:

+ + + +

範例

+ +

Web 上的 IndexedDB 使用範例,是由 Marco Castelluccio 所提供。Marco 是 IndexedDB Mozilla DevDerby 的優勝者,而該得獎 Demo 為 eLibri,屬於函式庫與 eBook 閱讀器的 App。

+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Asynchronous API +

24.0
+ 11.0 {{property_prefix("webkit")}}

+
+

{{CompatGeckoDesktop("16.0")}}
+ {{CompatGeckoDesktop("2.0")}} {{property_prefix("moz")}}

+
10 {{property_prefix("ms")}}{{CompatNo}}{{CompatNo}}
Synchronous API
+ (used with WebWorkers)
{{CompatNo}}{{CompatNo}}
+ See {{bug(701634)}}
{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Asynchronous API{{CompatNo}}{{CompatGeckoDesktop("6.0")}} {{property_prefix("moz")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

瀏覽器相容性表格則請參閱:When Can I Use IndexedDB

+ +

另可透過 IndexedDB Polyfill,在支援 WebSQL 的瀏覽器上使用 IndexedDB。

+ +

另可參閱

+ + diff --git a/files/zh-tw/web/api/indexeddb_api/using_indexeddb/index.html b/files/zh-tw/web/api/indexeddb_api/using_indexeddb/index.html new file mode 100644 index 0000000000..5bddd965b4 --- /dev/null +++ b/files/zh-tw/web/api/indexeddb_api/using_indexeddb/index.html @@ -0,0 +1,1085 @@ +--- +title: 使用IndexedDB +slug: Web/API/IndexedDB_API/Using_IndexedDB +translation_of: Web/API/IndexedDB_API/Using_IndexedDB +--- +

IndexedDB提供了在瀏覽器上儲存保留資料的功能,藉由它,不論是線上或線下我們的應用都可以進行資料存取。

+

關於本文

+

本文會帶領各位操作非同步IndexedDB的API,如果不知道甚麼是IndexedDB,請先看看"IndexedDB基本礎念"

+

基本操作步驟

+

操作IndexedDB的基本步驟建議如下:

+
    +
  1. 開啟資料庫和交易(transaction)。
  2. +
  3. 建立物件存檔(object store)
  4. +
  5. 發出資料庫操作請求,例如新增或取得資料。
  6. +
  7. +
    + 聆聽對應DOM事件等待操作完成。
    +
  8. +
  9. +
    + 從result物件上取得結果進行其他工作。
    +
  10. +
+

好了,知道了上述概念後,我們可以來實際做些甚麼。

+

建立和結構資料庫

+

由於IndexedDB的標準仍在演進,所以目前一些實作還需要加上瀏覽器前綴標示(如Gecko基礎瀏覽器的前綴標示為moz,WebKit基礎瀏覽器的前綴標示為webkit),瀏覽器的實作也可能會有所差異,不過一旦共識標準達成,無瀏覽器前綴標示實作將出現。其實,Internet Explorer 10, Firefox 16, Chrome 24已經有了無瀏覽器前綴標示實作。

+

操作實驗性質的IndexedDB

+

如果需要試驗瀏覽器的前綴標示,可以如下:

+
// In the following line, you should include the prefixes of implementations you want to test.
+window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+// DON'T use "var indexedDB = ..." if you're not in a function.
+// Moreover, you may need references to some window.IDB* objects:
+window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
+window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
+// (Mozilla has never prefixed these objects, so we don't need window.mozIDB*)
+

請注意瀏覽器前綴標示的實作可能不完整、有些問題或仍然遵守舊版標準,因此不建議在正式版程式碼中使用。與其宣稱支援又有問題,倒不如直接不支援。

+
if (!window.indexedDB) {
+    window.alert("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.");
+}
+
+

開啟資料庫

+

開頭如下:

+
// Let us open our database
+var request = window.indexedDB.open("MyTestDatabase", 3);
+
+

注意到了嗎,開啟資料庫必須要進行請求。

+

開啟請求並不會立刻開啟資料庫或交易,呼叫open()方法會回傳一個IDBOpenDBRequest物件,這個物件擁有兩個事件(success和error)。大部分IndexedDB的非同步功能都會回傳一個IDBDatabase類物件,然後我們可以註冊成功和失敗事件處理器。

+

Open方法第二個參數是資料庫版本,資料庫版本決定了資料庫結構,也就是資料庫物件存檔的結構。如果請求版本不存在(比如因為這是一個新資料庫或是資料庫版本已升級),onupgradeneeded事件會被觸發,然後我們可以在onupgradeneeded事件處理器中再建立新的版本,下面升級資料庫版本有更詳細的說明。

+

產生事件處理器

+

幾乎所有第一件要對請求做的事都是產生success和error事件處理器:

+
request.onerror = function(event) {
+  // Do something with request.errorCode!
+};
+request.onsuccess = function(event) {
+  // Do something with request.result!
+};
+

如果一切正常,success事件(也就是DOM事件的type屬性設為success)會以request為目標觸發,然後request物件上的onsuccess函數接著被呼叫,其中success事件就是參數;否則error事件(也就是DOM事件的type屬性設為error)會以request為目標觸發,然後request物件上的onerror函數接著被呼叫,其中error事件就是參數。

+

IndexedDB的API設計上盡量減少錯誤處理,所以不太常看到錯誤事件,不過開啟資料庫的時候還是有一些狀況會產產生錯誤,最常見的狀況是使用者拒絕我們建立資料庫。

+

IndexedDB設計目標之一為存放大量資料以供離線使用(請參考"儲存限制"了解更多細節)。但很明顯地,瀏覽器又不樂見一些廣告網站或惡意網站汙染電腦,所以當任一個網路應用第一次開啟IndexedDB資料庫,瀏覽器會徵詢使用者是否准許其作業;同時在私密瀏覽中開啟作業也會失敗,因為私密瀏覽不會留下任何瀏覽痕跡。

+

這裡呼叫indexedDB.open()開啟indexedDB資料庫並回傳request物件,假設使用者允許我們建立indexedDB資料庫,我們也收到suceess事件觸發了success回呼函數(callback),request物件的result屬性會是一個IDBDatabase物件 ,接下來便是要儲存這個物件之後使用。下方是整個作業的示範程式碼:

+
var db;
+var request = indexedDB.open("MyTestDatabase");
+request.onerror = function(event) {
+  alert("Why didn't you allow my web app to use IndexedDB?!");
+};
+request.onsuccess = function(event) {
+  db = request.result;
+};
+
+

錯誤處理

+

錯誤事件會向上傳遞;錯誤事件以產生錯誤之請求為目標觸發,然後一路傳遞到交易,最後到資料庫物件;如果不想要為每一個請求新增錯誤處理器,可以改為資料庫物件加入一個錯誤處理器。

+
db.onerror = function(event) {
+  // Generic error handler for all errors targeted at this database's
+  // requests!
+  alert("Database error: " + event.target.errorCode);
+};
+
+

最常見的錯誤之一就是VER_ERR,該錯誤代表現在資料料庫版本大於嘗試開啟的資料庫版本,這項錯誤必須要有錯誤處理器處理。

+

建立或更新資料庫版本

+

新版本資料庫建立會觸發onupgradeneeded事件,在這個事件的處理器中要建立這個版本資料庫需要的物件存檔。

+
// This event is only implemented in recent browsers
+request.onupgradeneeded = function(event) {
+  var db = event.target.result;
+
+  // Create an objectStore for this database
+  var objectStore = db.createObjectStore("name", { keyPath: "myKey" });
+};
+

資料庫版本是unsigned long long的數字,所以能夠非常長。

+
+

請注意這也意味著版本不能為浮點數,否則小數點部分將會無條件捨去,而交易也可能不會開始,upgradeneeded事件也不會觸發。不要像以下例子以2.4作版本:

+
var request = indexedDB.open("MyTestDatabase", 2.4); // don't do this, as the version will be rounded to 2
+
+

升級版本資料庫建立會觸發onupgradeneeded事件,這個時候資料庫裡面已經含有前版本下的物件存檔,所以說不需要再次建立這些物件存檔了,剩下的是新增或刪除物件存檔。如果想要更動既存物件存檔(例如改變資料鍵路徑),那麼會需要先刪除舊的再產生一個新的(請注意這也會刪除物件存檔裡的資料,所以如果資料需要保留的話,請在升級前先讀出資料備份。)

+

Webkit支援最新標準不過只有Chrome 23才開始導入,而較舊不支援最新版標準的版本則不支援indexedDB.open(name, version).onupgradeneeded。關於如何在舊版標準下升級資料庫版本請參考"IDBDatabase參考文章"

+

結構化資料庫

+

indexedDB不用資料表而是物件存檔,物件存檔可以有很多。一筆物件存檔裡的資料值對應一筆資料鍵,依據使用{資料鍵路徑(key path)}或{資料鍵產生器(key generator)}。

+

下表列出資料建各類產生途徑:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Key PathKey Generator描述
NoNo物件存檔資料值能為任何型別,即使像數字或字串。每當新增一筆資料,必須提供不同的資料鍵。
YesNo物件存檔資料值僅能為Javacript物件,而該資料物件必須含有和資料鍵路徑相同名稱之屬性成員。
NoYes物件存檔資料值能為任何型別,資料鍵自動產生,但如果想要指定資料鍵也可以另外提供資料鍵。
YesYes物件存檔資料值僅能為Javascript物件。通常被產生的新資料鍵的值會被存在物件屬性名稱和資料鍵路徑名稱相同的物件屬性下,如果這個屬性已經存在,這個已經存在之屬性之值將被用作為資料鍵,而非新產生的資料鍵。
+

我們可以替任何儲存資料為物件型態而非原始資料型態的物件存檔建立索引,索引讓我們能夠用物件存檔中資料物件內的某一個屬性值查找資料,而非僅僅物件的資料鍵。

+

除此之外,利用索引還可以施加簡單的儲存限制;建立索引時設定獨特旗標(flag),這個索引保證在此索引資料鍵下不會存在兩個物件存檔擁有同樣資料值,比如說現在有一個存放許多使用者的物件存檔,而且我們希望保證不會存在有兩個使用者的電子郵件地址一樣,此使索引的獨特旗標便可以幫助我們達成目標。

+

以上聽起來可能會有些複雜,請看一下下面的實例:

+
// This is what our customer data looks like.
+const customerData = [
+  { ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com" },
+  { ssn: "555-55-5555", name: "Donna", age: 32, email: "donna@home.org" }
+];
+const dbName = "the_name";
+
+var request = indexedDB.open(dbName, 2);
+
+request.onerror = function(event) {
+  // Handle errors.
+};
+request.onupgradeneeded = function(event) {
+  var db = event.target.result;
+
+  // Create an objectStore to hold information about our customers. We're
+  // going to use "ssn" as our key path because it's guaranteed to be
+  // unique.
+  var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });
+
+  // Create an index to search customers by name. We may have duplicates
+  // so we can't use a unique index.
+  objectStore.createIndex("name", "name", { unique: false });
+
+  // Create an index to search customers by email. We want to ensure that
+  // no two customers have the same email, so use a unique index.
+  objectStore.createIndex("email", "email", { unique: true });
+
+  // Store values in the newly created objectStore.
+  for (var i in customerData) {
+    objectStore.add(customerData[i]);
+  }
+};
+
+

請注意onupgradeneeded事件是唯一能夠變更資料庫結構之處,在此事件才能建立或刪除物件存檔以及建立和刪除索引。

+
+ 呼叫IDBDatabase類別物件的createObjectStore方法會立刻創造一個物件存檔,這個方法接收兩個參數,一個是物件存檔名稱,一個是非必填的參數物件,雖然參數物件不為必填但是卻相當重要,因為它讓我們定義了一些重要屬性(請參考createObjectStore)。本例中我們要求建立了一個"customer"物件存檔,定義"ssn"屬性為資料件路徑,使用"ssn"作為資料鍵路徑是因為每個客戶的ssn碼一定是獨立的。一旦決定了"ssn"作為資料鍵路徑,那麼每一筆資料一定要含有"ssn"。
+

本例還創建一個稱為"name"的索引,"name"索引查找目標為資料的"name"屬性,且不設立其獨特旗標(unique為false),同樣地,我們又呼叫createIndex方法創建了一個"email"索引,不過"email"索引具備獨特旗標(unique為true)。雖然存在"name"索引,但資料不一定要含有"name"屬性,只是當搜索"name"索引時資料不會出現。

+

接下來我們可以開始用ssn從物件存檔中取出資料,或是用索引找出資料(請參考使用索引)。

+

使用資料鍵產生器

+

當建立物件存檔時設定autoIncrement旗標為ture將啟動資料鍵產生器,預設上該旗標為false。

+

有了資料鍵產生器,當新增資料到物件存檔中,資料鍵產生器會自動幫我們產生資料鍵。資料鍵產生器產生的資料鍵由整數1開始,而基本上新產生的資料鍵是由前一個資料鍵加1產生。資料鍵的產生不會因為資料刪除或清空所有資料而重新開始起算,所以資料鍵值是一直累加上去的,除非資料庫操作中斷,整個交易作業被取消。

+

我們可以建立一個有資料鍵產生器的物件存檔如下:

+
// Open the indexedDB.
+var request = indexedDB.open(dbName, 3);
+
+request.onupgradeneeded = function (event) {
+    var db = event.target.result;
+
+    // Create another object store called "names" with the autoIncrement flag set as true.
+    var objStore = db.createObjectStore("names", { autoIncrement : true });
+
+    // Because the "names" object store has the key generator, the key for the name value is generated automatically.
+    // The added records would be like:
+    // key : 1 => value : "Bill"
+    // key : 2 => value : "Donna"
+    for (var i in customerData) {
+        objStore.add(customerData[i].name);
+    }
+}
+

關於資料鍵產生器細節,請參考"W3C Key Generators"

+

新增和刪除資料

+

在操作資料庫之前必須要先進行交易,交易來自資料庫物件,在交易中要指定涵蓋物件存檔範圍,然後也要決定是要變更資料庫或純粹讀取資料。交易共有三種種類,分別是讀取(read-only),讀寫(read/write), 以及版本變更(versionchange),如果只需要讀資料最好只使用讀取(read-only)交易,因為讀取(read-only)交易可以多重同步進行。

+

新增資料到資料庫

+

創建資料庫後,如果要寫入資料請這麼做:

+
var transaction = db.transaction(["customers"], "readwrite");
+// Note: Older experimental implementations use the deprecated constant IDBTransaction.READ_WRITE instead of "readwrite".
+// In case you want to support such an implementation, you can just write:
+// var transaction = db.transaction(["customers"], IDBTransaction.READ_WRITE);
+

呼叫transaction()方法會回傳一個交易物件。transaction()第一個接受參數代表交易涵蓋的物件存檔,雖然傳入空陣列會讓交易涵蓋所有物件存檔,但請不要這麼做,因為根據正式標準傳入空陣列應該要導致InvalidAccessError錯誤;第二個參數代表交易種類,不傳入的話預設為讀取交易,本例要寫入資料庫所以傳入讀寫("readwrite")。

+

交易的生命週期和事件循環關係密切。當我們發起交易又回到事件循環中後,如果忽略,那麼交易將轉成結束,唯一保持交易存活的方法是在交易上發出請求;當請求完成後我們會收到DOM事件,假設請求結果成功,我們可以在事件的回呼函數(callback中)繼續進行交易,反之,如果我們沒有繼續進行交易,那麼交易將結束,也就是說只要尚有未完成請求的話,交易就會繼續存活,如果收到TRANSACTION_INACTIVE_ERR錯誤那便意謂著交易早已結束,我們錯過了繼續進行交易的機會。

+

交易能收到三種事件: 錯誤(error)、中斷(abort)以及完成(complete),其中錯誤事件會向上傳遞,所以任何一個交易下轄的請求產生錯誤事件,該交易都會收到。如果交易收到錯誤事件時,瀏覽器預設行為會中斷交易,除非我們有在錯誤事件上呼叫preventDefault()阻擋瀏覽器預設行動,否則整筆交易都將取消、復原,這樣的設計告訴我們必須要思考如何處裡錯誤,或者說如果對每一個錯誤進行處裡過於麻煩,那麼至少加入一個概括性的錯誤處理器也是可以。只要不處裡錯誤或呼叫abort(),交易將取消、復原,然後中斷事件接著觸發,反之,當所有請求都完成後,我們會收到一個完成事件,所以說如果我們同時發起多項請求時,可以只追蹤單一交易而非個別請求,這樣會大大減輕我們的負擔。

+

有了交易之後便能夠從中取得物件存檔,有了物件存檔便能夠新增資料(請注意唯有在建立交易時指定的物件存檔能夠取得)。

+
// Do something when all the data is added to the database.
+transaction.oncomplete = function(event) {
+  alert("All done!");
+};
+
+transaction.onerror = function(event) {
+  // Don't forget to handle errors!
+};
+
+var objectStore = transaction.objectStore("customers");
+for (var i in customerData) {
+  var request = objectStore.add(customerData[i]);
+  request.onsuccess = function(event) {
+    // event.target.result == customerData[i].ssn;
+  };
+}
+

呼叫add方法可以加入一筆新資料,呼叫後會回傳一個IDBRequest物件,即為上方範例中的request,如果新增成功,request的成功事件會被觸發,而成功事件物件中有一個result屬性,這個result值剛好就等於新資料的資料鍵,所以說上方範例中的event.target.result剛好就等於顧客的ssn值(因為我們用ssn屬性作為資料鍵路徑)。請注意add方法只在當物件存檔中沒有相同資料鍵資料存在時有用,如果想要更動或是直接覆蓋現存資料請呼叫put方法。

+

移除資料

+

移除資料十分容易:

+
var request = db.transaction(["customers"], "readwrite")
+                .objectStore("customers")
+                .delete("444-44-4444");
+request.onsuccess = function(event) {
+  // It's gone!
+};
+

讀取資料

+

要圖取資料庫內的資料有數種途徑,第一個最簡單的途徑就是提供資料鍵,呼叫get方法取得資料:

+
var transaction = db.transaction(["customers"]);
+var objectStore = transaction.objectStore("customers");
+var request = objectStore.get("444-44-4444");
+request.onerror = function(event) {
+  // Handle errors!
+};
+request.onsuccess = function(event) {
+  // Do something with the request.result!
+  alert("Name for SSN 444-44-4444 is " + request.result.name);
+};
+

假設我們把錯誤處理放在資料庫層級,我們可以再縮短上面的程式碼如下:

+
db.transaction("customers").objectStore("customers").get("444-44-4444").onsuccess = function(event) {
+  alert("Name for SSN 444-44-4444 is " + event.target.result.name);
+};
+

呼叫transcation方法而不指定模式會開啟讀取(readonly)模式,接著取得我們的目標物件存檔,輸入目標資料的資料鍵,呼叫get方法取得請求物件,然後在請求物件上註冊成功事件處理器,當作業成功後,成功事件會觸發,成功事件的物件中含有請求物件(event.target如上述範例),請求物件中含有請求結果(event.target.result如上述範例)。

+

使用指標(Cursor)

+

使用get方法需要知道資料鍵,如果想要一一存取物件存檔中的資料,我們可以利用指標:

+
var objectStore = db.transaction("customers").objectStore("customers");
+
+objectStore.openCursor().onsuccess = function(event) {
+  var cursor = event.target.result;
+  if (cursor) {
+    alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
+    cursor.continue();
+  }
+  else {
+    alert("No more entries!");
+  }
+};
+

openCursor方法第一個參數用來接受資料鍵範圍物件來限制存取資料範圍,第二個參數用來指定存取進行方向,像上面的範例程式便是以資料鍵由小到大之方向存取資料;呼叫openCursor方法後一樣會回傳一個請求物件,成功時成功事件會觸發,不過這裡有些地方要特別注意,當成功事件處裡函數被喚起時,指標物件(cursor)會存放在result屬性內(亦即上述event.target.result),cursor物件下有兩個屬性,key屬性是資料鍵,value屬性是資料值,如果要取得下一份資料就呼叫cursor的continue()方法,然後cursor物件就會指向下一份資料,當沒有資料時,cursor會是undefined,當請求一開始便找沒有資料,result屬性也會是undefined。

+

以下用cursor存取一遍資料後放在陣列中的作法相當常見:

+
var customers = [];
+
+objectStore.openCursor().onsuccess = function(event) {
+  var cursor = event.target.result;
+  if (cursor) {
+    customers.push(cursor.value);
+    cursor.continue();
+  }
+  else {
+    alert("Got all customers: " + customers);
+  }
+};
+
+ Warning: 以下範例不是IndexedDB標準!
+

Mozilla瀏覽器自己做了一個getAll()方法來方便一次取得所有cursor下的資料值,這個方法相當方便,不過請小心未來它有可能會消失。以下程式碼的效果和上面的一樣:

+
objectStore.getAll().onsuccess = function(event) {
+  alert("Got all customers: " + event.target.result);
+};
+

一一檢查cursor的value屬性較不利性能表現,因為物件是被動一一建立,然而呼叫getAll(),Gecko一定要一次建立所有物件,所以如果想要一次取得所有物件的資料值陣列使用getAll()比較好,如果想要一一檢查每筆資料則請利用cursor的方法。

+

使用索引

+

利用一定唯一的ssn碼作為資料鍵相當合乎邏輯(隱私權的問題先擱置一放,不在本文探討範圍)。不過當我們想要查詢使用者的名字的時候,如果沒有索引就需要一一檢查每一筆資料,十分沒有效率,所以我們可以建立name的索引。

+
var index = objectStore.index("name");
+index.get("Donna").onsuccess = function(event) {
+  alert("Donna's SSN is " + event.target.result.ssn);
+};
+

因為name不是唯一值,所以可能會有多筆資料符合"Donna"名字,此時呼叫get()會取得資料鍵最小值的資料。

+

如果我們想要查看特定名字下所有的資料,可以利用cursor。有兩種cursor能用在索引上,第一種一般cursor會比對索引值並回傳整份資料(物件存檔中的物件),第二種資料鍵cursor則只會回傳資料鍵值,請參考下方範例比較兩者差異:

+
index.openCursor().onsuccess = function(event) {
+  var cursor = event.target.result;
+  if (cursor) {
+    // cursor.key is a name, like "Bill", and cursor.value is the whole object.
+    alert("Name: " + cursor.key + ", SSN: " + cursor.value.ssn + ", email: " + cursor.value.email);
+    cursor.continue();
+  }
+};
+
+index.openKeyCursor().onsuccess = function(event) {
+  var cursor = event.target.result;
+  if (cursor) {
+    // cursor.key is a name, like "Bill", and cursor.value is the SSN.
+    // No way to directly get the rest of the stored object.
+    alert("Name: " + cursor.key + ", SSN: " + cursor.value);
+    cursor.continue();
+  }
+};
+

設定指標查詢範圍和方向

+

如果想要限定指標查詢範圍,那麼在乎叫openCursor()或openKeyCursor()時第一個參數要傳入IDBKeyRange物件以限制範圍。IDBKeyRange物件能夠只聚焦在單一資料鍵上或者一段上下限區間;上下限區間可以是封閉(含界限)或開放(不含界限),請看以下範例:

+
// Only match "Donna"
+var singleKeyRange = IDBKeyRange.only("Donna");
+
+// Match anything past "Bill", including "Bill"
+var lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill");
+
+// Match anything past "Bill", but don't include "Bill"
+var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);
+
+// Match anything up to, but not including, "Donna"
+var upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true);
+
+// Match anything between "Bill" and "Donna", but not including "Donna"
+var boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true);
+
+index.openCursor(boundKeyRange).onsuccess = function(event) {
+  var cursor = event.target.result;
+  if (cursor) {
+    // Do something with the matches.
+    cursor.continue();
+  }
+};
+

有時候我們會想要由大到小查看資料而非預設由小到大方向,傳入第二個"prev"字串便能做到:

+
objectStore.openCursor(null, "prev").onsuccess = function(event) {
+  var cursor = event.target.result;
+  if (cursor) {
+    // Do something with the entries.
+    cursor.continue();
+  }
+};
+

由於"name"索引不具唯一性,所以一個名字下可能會出現多筆資料,此時如果想要避開這多筆資料,請傳入"nextunique"或"prevunique"做為第二個方向參數,當傳入之後,如一個名字下遇到多筆資料,則只有資料鍵最小的資料會被回傳。

+
index.openKeyCursor(null, "nextunique").onsuccess = function(event) {
+  var cursor = event.target.result;
+  if (cursor) {
+    // Do something with the entries.
+    cursor.continue();
+  }
+};
+

關於可傳入的方向參數,請參考IDBCursor常數。

+

當網頁應用程式於瀏覽器另一個分頁開啟時變更版本

+

請思考以下狀況: 使用者在第一個瀏覽器分頁中使用著舊版本,然後使用者又打開第二個分頁載入網頁,此時我們在新分頁需要對資料庫進行升級,所以呼叫open()以更新版本開啟資料庫,但是由於第一個瀏覽器分頁並沒有關閉資料庫,因此第二個分頁的資料庫升級作業會被擋住。所以我們需要注意多個分頁同時開啟的狀況,每個分頁都得注意當發生資料庫升級事件時,要記得關閉資料庫,讓資料庫升級作業得以進行。實際作法如下:

+
var openReq = mozIndexedDB.open("MyTestDatabase", 2);
+
+openReq.onblocked = function(event) {
+  // If some other tab is loaded with the database, then it needs to be closed
+  // before we can proceed.
+  alert("Please close all other tabs with this site open!");
+};
+
+openReq.onupgradeneeded = function(event) {
+  // All other databases have been closed. Set everything up.
+  db.createObjectStore(/* ... */);
+  useDatabase(db);
+}
+
+openReq.onsuccess = function(event) {
+  var db = event.target.result;
+  useDatabase(db);
+  return;
+}
+
+function useDatabase(db) {
+  // Make sure to add a handler to be notified if another page requests a version
+  // change. We must close the database. This allows the other page to upgrade the database.
+  // If you don't do this then the upgrade won't happen until the user closes the tab.
+  db.onversionchange = function(event) {
+    db.close();
+    alert("A new version of this page is ready. Please reload!");
+  };
+
+  // Do stuff with the database.
+}
+
+

安全性

+

IndexedDB遵守同源政策,所以它綁定創建它的來源網站,其他來源網站無法存取。
+ 就像對載入{{ HTMLElement("frame") }}和{{ HTMLElement("iframe") }}網頁的第三方cookie所設下的安全性和隱私權考量限制,IndexedDB無法在載入{{ HTMLElement("frame") }}和{{ HTMLElement("iframe") }}網頁上運作,詳情請見{{ bug(595307) }}。

+

瀏覽器關閉風險

+

當瀏覽器關閉,例如使用者按下關閉鈕,任何未完成IndexedDB交易都將默默中止,這些交易不會完成,錯誤事件也不會觸發。既然瀏覽器可能隨時被關閉,我們無法完全指望任何特定交易一定會完成,或是依賴錯誤事件做出相應處理,針對這種狀況,我們需要注意:

+

第一、每一筆交易結束後都應該要保持資料庫完整性,例如說,有一串使用者編輯項目清單正要存入資料庫,我們如果先在一個交易中清除舊清單,然後在另一個交易中存入新清單,那就會面臨到清除完就清單後,新清單存入交易還來不及回存,瀏覽器就關閉的風險,而這個時候資料庫裡面的清單資料將消失。所以比較好的做法應該是在同一筆交易中完成清除舊清單和存入新清單。

+

第二、永遠不要在unload事件中執行資料庫交易,因為如果unload事件是觸發在瀏覽器關閉下,任何資料庫交易都不會發生,或許,瀏覽器(或分頁)打開時讀取資料庫,更新資料庫當使用者編輯資料,當瀏覽器(或分頁)關閉時儲存資料這樣的做法比較直覺,不過資料庫的操作是非同步進行地,所以瀏覽器關閉的執行會在資料庫操作前發生,進而中斷後續非同步的資料庫交易,所以在unload事件中執行資料庫交易是行不通地。

+

事實上不論瀏覽器是否正常關閉,都沒有任何方法保證IndexedDB交易能夠順利完成,請見{{ bug(870645) }}。

+

完整IndexedDB範例

+

HTML

+
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
+
+    <h1>IndexedDB Demo: storing blobs, e-publication example</h1>
+    <div class="note">
+      <p>
+        Works and tested with:
+      </p>
+      <div id="compat">
+      </div>
+    </div>
+
+    <div id="msg">
+    </div>
+
+    <form id="register-form">
+      <table>
+        <tbody>
+          <tr>
+            <td>
+              <label for="pub-title" class="required">
+                Title:
+              </label>
+            </td>
+            <td>
+              <input type="text" id="pub-title" name="pub-title" />
+            </td>
+          </tr>
+          <tr>
+            <td>
+              <label for="pub-biblioid" class="required">
+                Bibliographic ID:<br/>
+                <span class="note">(ISBN, ISSN, etc.)</span>
+              </label>
+            </td>
+            <td>
+              <input type="text" id="pub-biblioid" name="pub-biblioid"/>
+            </td>
+          </tr>
+          <tr>
+            <td>
+              <label for="pub-year">
+                Year:
+              </label>
+            </td>
+            <td>
+              <input type="number" id="pub-year" name="pub-year" />
+            </td>
+          </tr>
+        </tbody>
+        <tbody>
+          <tr>
+            <td>
+              <label for="pub-file">
+                File image:
+              </label>
+            </td>
+            <td>
+              <input type="file" id="pub-file"/>
+            </td>
+          </tr>
+          <tr>
+            <td>
+              <label for="pub-file-url">
+                Online-file image URL:<br/>
+                <span class="note">(same origin URL)</span>
+              </label>
+            </td>
+            <td>
+              <input type="text" id="pub-file-url" name="pub-file-url"/>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+
+      <div class="button-pane">
+        <input type="button" id="add-button" value="Add Publication" />
+        <input type="reset" id="register-form-reset"/>
+      </div>
+    </form>
+
+    <form id="delete-form">
+      <table>
+        <tbody>
+          <tr>
+            <td>
+              <label for="pub-biblioid-to-delete">
+                Bibliographic ID:<br/>
+                <span class="note">(ISBN, ISSN, etc.)</span>
+              </label>
+            </td>
+            <td>
+              <input type="text" id="pub-biblioid-to-delete"
+                     name="pub-biblioid-to-delete" />
+            </td>
+          </tr>
+          <tr>
+            <td>
+              <label for="key-to-delete">
+                Key:<br/>
+                <span class="note">(for example 1, 2, 3, etc.)</span>
+              </label>
+            </td>
+            <td>
+              <input type="text" id="key-to-delete"
+                     name="key-to-delete" />
+            </td>
+          </tr>
+        </tbody>
+      </table>
+      <div class="button-pane">
+        <input type="button" id="delete-button" value="Delete Publication" />
+        <input type="button" id="clear-store-button"
+               value="Clear the whole store" class="destructive" />
+      </div>
+    </form>
+
+    <form id="search-form">
+      <div class="button-pane">
+        <input type="button" id="search-list-button"
+               value="List database content" />
+      </div>
+    </form>
+
+    <div>
+      <div id="pub-msg">
+      </div>
+      <div id="pub-viewer">
+      </div>
+      <ul id="pub-list">
+      </ul>
+    </div>
+
+

CSS

+
body {
+  font-size: 0.8em;
+  font-family: Sans-Serif;
+}
+
+form {
+  background-color: #cccccc;
+  border-radius: 0.3em;
+  display: inline-block;
+  margin-bottom: 0.5em;
+  padding: 1em;
+}
+
+table {
+  border-collapse: collapse;
+}
+
+input {
+  padding: 0.3em;
+  border-color: #cccccc;
+  border-radius: 0.3em;
+}
+
+.required:after {
+  content: "*";
+  color: red;
+}
+
+.button-pane {
+  margin-top: 1em;
+}
+
+#pub-viewer {
+  float: right;
+  width: 48%;
+  height: 20em;
+  border: solid #d092ff 0.1em;
+}
+#pub-viewer iframe {
+  width: 100%;
+  height: 100%;
+}
+
+#pub-list {
+  width: 46%;
+  background-color: #eeeeee;
+  border-radius: 0.3em;
+}
+#pub-list li {
+  padding-top: 0.5em;
+  padding-bottom: 0.5em;
+  padding-right: 0.5em;
+}
+
+#msg {
+  margin-bottom: 1em;
+}
+
+.action-success {
+  padding: 0.5em;
+  color: #00d21e;
+  background-color: #eeeeee;
+  border-radius: 0.2em;
+}
+
+.action-failure {
+  padding: 0.5em;
+  color: #ff1408;
+  background-color: #eeeeee;
+  border-radius: 0.2em;
+}
+
+.note {
+  font-size: smaller;
+}
+
+.destructive {
+  background-color: orange;
+}
+.destructive:hover {
+  background-color: #ff8000;
+}
+.destructive:active {
+  background-color: red;
+}
+
+

 

+

JavaScript

+
(function () {
+  var COMPAT_ENVS = [
+    ['Firefox', ">= 16.0"],
+    ['Google Chrome',
+     ">= 24.0 (you may need to get Google Chrome Canary), NO Blob storage support"]
+  ];
+  var compat = $('#compat');
+  compat.empty();
+  compat.append('<ul id="compat-list"></ul>');
+  COMPAT_ENVS.forEach(function(val, idx, array) {
+    $('#compat-list').append('<li>' + val[0] + ': ' + val[1] + '</li>');
+  });
+
+  const DB_NAME = 'mdn-demo-indexeddb-epublications';
+  const DB_VERSION = 1; // Use a long long for this value (don't use a float)
+  const DB_STORE_NAME = 'publications';
+
+  var db;
+
+  // Used to keep track of which view is displayed to avoid uselessly reloading it
+  var current_view_pub_key;
+
+  function openDb() {
+    console.log("openDb ...");
+    var req = indexedDB.open(DB_NAME, DB_VERSION);
+    req.onsuccess = function (evt) {
+      // Better use "this" than "req" to get the result to avoid problems with
+      // garbage collection.
+      // db = req.result;
+      db = this.result;
+      console.log("openDb DONE");
+    };
+    req.onerror = function (evt) {
+      console.error("openDb:", evt.target.errorCode);
+    };
+
+    req.onupgradeneeded = function (evt) {
+      console.log("openDb.onupgradeneeded");
+      var store = evt.currentTarget.result.createObjectStore(
+        DB_STORE_NAME, { keyPath: 'id', autoIncrement: true });
+
+      store.createIndex('biblioid', 'biblioid', { unique: true });
+      store.createIndex('title', 'title', { unique: false });
+      store.createIndex('year', 'year', { unique: false });
+    };
+  }
+
+  /**
+   * @param {string} store_name
+   * @param {string} mode either "readonly" or "readwrite"
+   */
+  function getObjectStore(store_name, mode) {
+    var tx = db.transaction(store_name, mode);
+    return tx.objectStore(store_name);
+  }
+
+  function clearObjectStore(store_name) {
+    var store = getObjectStore(DB_STORE_NAME, 'readwrite');
+    var req = store.clear();
+    req.onsuccess = function(evt) {
+      displayActionSuccess("Store cleared");
+      displayPubList(store);
+    };
+    req.onerror = function (evt) {
+      console.error("clearObjectStore:", evt.target.errorCode);
+      displayActionFailure(this.error);
+    };
+  }
+
+  function getBlob(key, store, success_callback) {
+    var req = store.get(key);
+    req.onsuccess = function(evt) {
+      var value = evt.target.result;
+      if (value)
+        success_callback(value.blob);
+    };
+  }
+
+  /**
+   * @param {IDBObjectStore=} store
+   */
+  function displayPubList(store) {
+    console.log("displayPubList");
+
+    if (typeof store == 'undefined')
+      store = getObjectStore(DB_STORE_NAME, 'readonly');
+
+    var pub_msg = $('#pub-msg');
+    pub_msg.empty();
+    var pub_list = $('#pub-list');
+    pub_list.empty();
+    // Resetting the iframe so that it doesn't display previous content
+    newViewerFrame();
+
+    var req;
+    req = store.count();
+    // Requests are executed in the order in which they were made against the
+    // transaction, and their results are returned in the same order.
+    // Thus the count text below will be displayed before the actual pub list
+    // (not that it is algorithmically important in this case).
+    req.onsuccess = function(evt) {
+      pub_msg.append('<p>There are <strong>' + evt.target.result +
+                     '</strong> record(s) in the object store.</p>');
+    };
+    req.onerror = function(evt) {
+      console.error("add error", this.error);
+      displayActionFailure(this.error);
+    };
+
+    var i = 0;
+    req = store.openCursor();
+    req.onsuccess = function(evt) {
+      var cursor = evt.target.result;
+
+      // If the cursor is pointing at something, ask for the data
+      if (cursor) {
+        console.log("displayPubList cursor:", cursor);
+        req = store.get(cursor.key);
+        req.onsuccess = function (evt) {
+          var value = evt.target.result;
+          var list_item = $('<li>' +
+                            '[' + cursor.key + '] ' +
+                            '(biblioid: ' + value.biblioid + ') ' +
+                            value.title +
+                            '</li>');
+          if (value.year != null)
+            list_item.append(' - ' + value.year);
+
+          if (value.hasOwnProperty('blob') &&
+              typeof value.blob != 'undefined') {
+            var link = $('<a href="' + cursor.key + '">File</a>');
+            link.on('click', function() { return false; });
+            link.on('mouseenter', function(evt) {
+                      setInViewer(evt.target.getAttribute('href')); });
+            list_item.append(' / ');
+            list_item.append(link);
+          } else {
+            list_item.append(" / No attached file");
+          }
+          pub_list.append(list_item);
+        };
+
+        // Move on to the next object in store
+        cursor.continue();
+
+        // This counter serves only to create distinct ids
+        i++;
+      } else {
+        console.log("No more entries");
+      }
+    };
+  }
+
+  function newViewerFrame() {
+    var viewer = $('#pub-viewer');
+    viewer.empty();
+    var iframe = $('<iframe />');
+    viewer.append(iframe);
+    return iframe;
+  }
+
+  function setInViewer(key) {
+    console.log("setInViewer:", arguments);
+    key = Number(key);
+    if (key == current_view_pub_key)
+      return;
+
+    current_view_pub_key = key;
+
+    var store = getObjectStore(DB_STORE_NAME, 'readonly');
+    getBlob(key, store, function(blob) {
+      console.log("setInViewer blob:", blob);
+      var iframe = newViewerFrame();
+
+      // It is not possible to set a direct link to the
+      // blob to provide a mean to directly download it.
+      if (blob.type == 'text/html') {
+        var reader = new FileReader();
+        reader.onload = (function(evt) {
+          var html = evt.target.result;
+          iframe.load(function() {
+            $(this).contents().find('html').html(html);
+          });
+        });
+        reader.readAsText(blob);
+      } else if (blob.type.indexOf('image/') == 0) {
+        iframe.load(function() {
+          var img_id = 'image-' + key;
+          var img = $('<img id="' + img_id + '"/>');
+          $(this).contents().find('body').html(img);
+          var obj_url = window.URL.createObjectURL(blob);
+          $(this).contents().find('#' + img_id).attr('src', obj_url);
+          window.URL.revokeObjectURL(obj_url);
+        });
+      } else if (blob.type == 'application/pdf') {
+        $('*').css('cursor', 'wait');
+        var obj_url = window.URL.createObjectURL(blob);
+        iframe.load(function() {
+          $('*').css('cursor', 'auto');
+        });
+        iframe.attr('src', obj_url);
+        window.URL.revokeObjectURL(obj_url);
+      } else {
+        iframe.load(function() {
+          $(this).contents().find('body').html("No view available");
+        });
+      }
+
+    });
+  }
+
+  /**
+   * @param {string} biblioid
+   * @param {string} title
+   * @param {number} year
+   * @param {string} url the URL of the image to download and store in the local
+   *   IndexedDB database. The resource behind this URL is subjected to the
+   *   "Same origin policy", thus for this method to work, the URL must come from
+   *   the same origin as the web site/app this code is deployed on.
+   */
+  function addPublicationFromUrl(biblioid, title, year, url) {
+    console.log("addPublicationFromUrl:", arguments);
+
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, true);
+    // Setting the wanted responseType to "blob"
+    // http://www.w3.org/TR/XMLHttpRequest2/#the-response-attribute
+    xhr.responseType = 'blob';
+    xhr.onload = function (evt) {
+                           if (xhr.status == 200) {
+                             console.log("Blob retrieved");
+                             var blob = xhr.response;
+                             console.log("Blob:", blob);
+                             addPublication(biblioid, title, year, blob);
+                           } else {
+                             console.error("addPublicationFromUrl error:",
+                                           xhr.responseText, xhr.status);
+                           }
+                         };
+    xhr.send();
+
+    // We can't use jQuery here because as of jQuery 1.8.3 the new "blob"
+    // responseType is not handled.
+    // http://bugs.jquery.com/ticket/11461
+    // http://bugs.jquery.com/ticket/7248
+    // $.ajax({
+    //   url: url,
+    //   type: 'GET',
+    //   xhrFields: { responseType: 'blob' },
+    //   success: function(data, textStatus, jqXHR) {
+    //     console.log("Blob retrieved");
+    //     console.log("Blob:", data);
+    //     // addPublication(biblioid, title, year, data);
+    //   },
+    //   error: function(jqXHR, textStatus, errorThrown) {
+    //     console.error(errorThrown);
+    //     displayActionFailure("Error during blob retrieval");
+    //   }
+    // });
+  }
+
+  /**
+   * @param {string} biblioid
+   * @param {string} title
+   * @param {number} year
+   * @param {Blob=} blob
+   */
+  function addPublication(biblioid, title, year, blob) {
+    console.log("addPublication arguments:", arguments);
+    var obj = { biblioid: biblioid, title: title, year: year };
+    if (typeof blob != 'undefined')
+      obj.blob = blob;
+
+    var store = getObjectStore(DB_STORE_NAME, 'readwrite');
+    var req;
+    try {
+      req = store.add(obj);
+    } catch (e) {
+      if (e.name == 'DataCloneError')
+        displayActionFailure("This engine doesn't know how to clone a Blob, " +
+                             "use Firefox");
+      throw e;
+    }
+    req.onsuccess = function (evt) {
+      console.log("Insertion in DB successful");
+      displayActionSuccess();
+      displayPubList(store);
+    };
+    req.onerror = function() {
+      console.error("addPublication error", this.error);
+      displayActionFailure(this.error);
+    };
+  }
+
+  /**
+   * @param {string} biblioid
+   */
+  function deletePublicationFromBib(biblioid) {
+    console.log("deletePublication:", arguments);
+    var store = getObjectStore(DB_STORE_NAME, 'readwrite');
+    var req = store.index('biblioid');
+    req.get(biblioid).onsuccess = function(evt) {
+      if (typeof evt.target.result == 'undefined') {
+        displayActionFailure("No matching record found");
+        return;
+      }
+      deletePublication(evt.target.result.id, store);
+    };
+    req.onerror = function (evt) {
+      console.error("deletePublicationFromBib:", evt.target.errorCode);
+    };
+  }
+
+  /**
+   * @param {number} key
+   * @param {IDBObjectStore=} store
+   */
+  function deletePublication(key, store) {
+    console.log("deletePublication:", arguments);
+
+    if (typeof store == 'undefined')
+      store = getObjectStore(DB_STORE_NAME, 'readwrite');
+
+    // As per spec http://www.w3.org/TR/IndexedDB/#object-store-deletion-operation
+    // the result of the Object Store Deletion Operation algorithm is
+    // undefined, so it's not possible to know if some records were actually
+    // deleted by looking at the request result.
+    var req = store.get(key);
+    req.onsuccess = function(evt) {
+      var record = evt.target.result;
+      console.log("record:", record);
+      if (typeof record == 'undefined') {
+        displayActionFailure("No matching record found");
+        return;
+      }
+      // Warning: The exact same key used for creation needs to be passed for
+      // the deletion. If the key was a Number for creation, then it needs to
+      // be a Number for deletion.
+      req = store.delete(key);
+      req.onsuccess = function(evt) {
+        console.log("evt:", evt);
+        console.log("evt.target:", evt.target);
+        console.log("evt.target.result:", evt.target.result);
+        console.log("delete successful");
+        displayActionSuccess("Deletion successful");
+        displayPubList(store);
+      };
+      req.onerror = function (evt) {
+        console.error("deletePublication:", evt.target.errorCode);
+      };
+    };
+    req.onerror = function (evt) {
+      console.error("deletePublication:", evt.target.errorCode);
+      };
+  }
+
+  function displayActionSuccess(msg) {
+    msg = typeof msg != 'undefined' ? "Success: " + msg : "Success";
+    $('#msg').html('<span class="action-success">' + msg + '</span>');
+  }
+  function displayActionFailure(msg) {
+    msg = typeof msg != 'undefined' ? "Failure: " + msg : "Failure";
+    $('#msg').html('<span class="action-failure">' + msg + '</span>');
+  }
+  function resetActionStatus() {
+    console.log("resetActionStatus ...");
+    $('#msg').empty();
+    console.log("resetActionStatus DONE");
+  }
+
+  function addEventListeners() {
+    console.log("addEventListeners");
+
+    $('#register-form-reset').click(function(evt) {
+      resetActionStatus();
+    });
+
+    $('#add-button').click(function(evt) {
+      console.log("add ...");
+      var title = $('#pub-title').val();
+      var biblioid = $('#pub-biblioid').val();
+      if (!title || !biblioid) {
+        displayActionFailure("Required field(s) missing");
+        return;
+      }
+      var year = $('#pub-year').val();
+      if (year != '') {
+        // Better use Number.isInteger if the engine has EcmaScript 6
+        if (isNaN(year))  {
+          displayActionFailure("Invalid year");
+          return;
+        }
+        year = Number(year);
+      } else {
+        year = null;
+      }
+
+      var file_input = $('#pub-file');
+      var selected_file = file_input.get(0).files[0];
+      console.log("selected_file:", selected_file);
+      // Keeping a reference on how to reset the file input in the UI once we
+      // have its value, but instead of doing that we rather use a "reset" type
+      // input in the HTML form.
+      //file_input.val(null);
+      var file_url = $('#pub-file-url').val();
+      if (selected_file) {
+        addPublication(biblioid, title, year, selected_file);
+      } else if (file_url) {
+        addPublicationFromUrl(biblioid, title, year, file_url);
+      } else {
+        addPublication(biblioid, title, year);
+      }
+
+    });
+
+    $('#delete-button').click(function(evt) {
+      console.log("delete ...");
+      var biblioid = $('#pub-biblioid-to-delete').val();
+      var key = $('#key-to-delete').val();
+
+      if (biblioid != '') {
+        deletePublicationFromBib(biblioid);
+      } else if (key != '') {
+        // Better use Number.isInteger if the engine has EcmaScript 6
+        if (key == '' || isNaN(key))  {
+          displayActionFailure("Invalid key");
+          return;
+        }
+        key = Number(key);
+        deletePublication(key);
+      }
+    });
+
+    $('#clear-store-button').click(function(evt) {
+      clearObjectStore();
+    });
+
+    var search_button = $('#search-list-button');
+    search_button.click(function(evt) {
+      displayPubList();
+    });
+
+  }
+
+  openDb();
+  addEventListeners();
+
+})(); // Immediately-Invoked Function Expression (IIFE)
+
+

{{ LiveSampleLink('Full_IndexedDB_example', "線上範例") }}

+

下一步

+

請參考IndexedDB文件,看看有甚麼IndexedDB API可供使用,實際試玩一下吧。

+

延伸閱讀

+

參照

+ +

相關教學

+ +

相關文章

+ +

Firefox

+ diff --git a/files/zh-tw/web/api/keyboardevent/index.html b/files/zh-tw/web/api/keyboardevent/index.html new file mode 100644 index 0000000000..31d75cdf1f --- /dev/null +++ b/files/zh-tw/web/api/keyboardevent/index.html @@ -0,0 +1,449 @@ +--- +title: KeyboardEvent +slug: Web/API/KeyboardEvent +tags: + - 待翻譯 +translation_of: Web/API/KeyboardEvent +--- +

{{APIRef("DOM Events")}}

+ +

KeyboardEvent objects 用來詳述使用者和網頁之間,經由鍵盤產生的互動。每個事件(event)都記錄著一次鍵盤動作。事件類型(keydownkeypresskeyup)用來表示鍵盤執行哪種動作。

+ +
注意: KeyboardEvent 僅顯示在鍵盤上發生的事。當你需要進行文字輸入的操作,請使用 HTML5 input event 代替 KeyboardEvent 。舉例來說,當使用者在手寫系統,例如平板電腦,輸入文字時,並不會啟動 key events 。
+ +

Constructor

+ +
+
{{domxref("KeyboardEvent.KeyboardEvent", "KeyboardEvent()")}}
+
建立一 KeyboardEvent object。
+
+ +

Methods

+ +

本介面( interface)亦繼承其父, {{domxref("UIEvent")}} 和 {{domxref("Event")}} ,的 methods

+ +
+
{{domxref("KeyboardEvent.getModifierState()")}}
+
回傳一 {{jsxref("Boolean")}}。用來表示當事件建立時,修飾鍵(例如 Alt、 Shift、 Ctrl、或是 Meta) 是否是按下的。
+
{{domxref("KeyboardEvent.initKeyEvent()")}}{{deprecated_inline}}
+
初始化一個 KeyboardEvent object。這個 method 只有 Gecko 有在使用(其他瀏覽器是使用 {{domxref("KeyboardEvent.initKeyboardEvent()")}}),並且不應該再繼續使用。現代的標準規範是使用 {{domxref("KeyboardEvent.KeyboardEvent", "KeyboardEvent()")}} constructor。
+
{{domxref("KeyboardEvent.initKeyboardEvent()")}}{{deprecated_inline}}
+
初始化一個 KeyboardEvent object。 Gecko 從未實作過該 method (Gecko 是使用 {{domxref("KeyboardEvent.initKeyEvent()")}}) ,並且不應該再繼續使用。現代的標準規範是使用 {{domxref("KeyboardEvent.KeyboardEvent", "KeyboardEvent()")}} constructor。
+
+ +

Properties

+ +

本介面( interface)亦繼承其父,{{domxref("UIEvent")}} 和 {{domxref("Event")}} ,的 properties 。

+ +
+
{{domxref("KeyboardEvent.altKey")}} {{Readonlyinline}}
+
一個 {{jsxref("Boolean")}} 。用來表示在事件建立時, Alt (OS X 中是 Option ) 鍵是否執行中。
+
{{domxref("KeyboardEvent.char")}} {{Non-standard_inline}}{{Deprecated_inline}}{{Readonlyinline}}
+
一個 {{domxref("DOMString")}} ,返回鍵盤對應的字符。若是該鍵對應一個實際的字符,則其值為對應該字符的一個非空的 Unicode 字串;若沒對應的話,則返回一個空字串。 +
Note: If the key is used as a macro that inserts multiple characters, this attribute's value is the entire string, not just the first character.
+ +
警告: 在 DOM Level 3 Events ,該 propertie 已被移除。現在只有 IE9+ 支持它。
+
+
{{domxref("KeyboardEvent.charCode")}} {{Deprecated_inline}}{{Readonlyinline}}
+
Returns a {{jsxref("Number")}} representing the Unicode reference number of the key; this attribute is used only by the keypress event. For keys whose char attribute contains multiple characters, this is the Unicode value of the first character in that attribute. In Firefox 26 this returns codes for printable characters. +
警告: 此 attribute 已被淘汰。如果可以,建議使用 {{domxref("KeyboardEvent.key")}} 。
+
+
{{domxref("KeyboardEvent.code")}} {{Readonlyinline}}
+
一個 {{domxref("DOMString")}} 。返回事件對應的按鍵的代碼。
+
{{domxref("KeyboardEvent.ctrlKey")}} {{Readonlyinline}}
+
一個 {{jsxref("Boolean")}} 。用來表示在事件建立時, Ctrl 鍵是否執行中。
+
{{domxref("KeyboardEvent.isComposing")}} {{Readonlyinline}}
+
一個 {{jsxref("Boolean")}} 。用來表示其觸發時間是否在 compositionstartcompositionend 之間。
+
{{domxref("KeyboardEvent.key")}} {{Readonlyinline}}
+
一個 {{domxref("DOMString")}} ,用來事件對應的按鍵的值(key value)。
+
{{domxref("KeyboardEvent.keyCode")}} {{deprecated_inline}}{{Readonlyinline}}
+
Returns a {{jsxref("Number")}} representing a system and implementation dependent numerical code identifying the unmodified value of the pressed key. +
警告: 此 attribute 已被淘汰。如果可以,建議使用{{domxref("KeyboardEvent.key")}} 。
+
+
{{domxref("KeyboardEvent.locale")}} {{Readonlyinline}}
+
Returns a {{domxref("DOMString")}} representing a locale string indicating the locale the keyboard is configured for. This may be the empty string if the browser or device doesn't know the keyboard's locale. +
Note: This does not describe the locale of the data being entered. A user may be using one keyboard layout while typing text in a different language.
+
+
{{domxref("KeyboardEvent.location")}} {{Readonlyinline}}
+
Returns a {{jsxref("Number")}} representing the location of the key on the keyboard or other input device.
+
{{domxref("KeyboardEvent.metaKey")}} {{Readonlyinline}}
+
Returns a {{jsxref("Boolean")}} that is true if the Meta (on Mac keyboards, the ⌘ Command key; on Windows keyboards, the Windows key ()) key was active when the key event was generated.
+
{{domxref("KeyboardEvent.repeat")}} {{Readonlyinline}}
+
Returns a {{jsxref("Boolean")}} that is true if the key is being held down such that it is automatically repeating.
+
{{domxref("KeyboardEvent.shiftKey")}} {{Readonlyinline}}
+
Returns a {{jsxref("Boolean")}} that is true if the Shift key was active when the key event was generated.
+
{{domxref("KeyboardEvent.which")}} {{deprecated_inline}}{{Readonlyinline}}
+
Returns a {{jsxref("Number")}} representing a system and implementation dependent numeric code identifying the unmodified value of the pressed key; this is usually the same as keyCode. +
警告: 此 attribute 已被淘汰。如果可以,建議使用 {{domxref("KeyboardEvent.key")}} 。
+
+
+ +

注意

+ +

KeyboardEvent 有 keydownkeypresskeyup 三種事件。對大多數的按鍵而言, Gecko 觸發事件的順序如下:

+ +
    +
  1. 當按鍵按下時,會送出 keydown event 。
  2. +
  3. 當按鍵不是特殊鍵( modifier key),例如CtrlAlt……等等,會送出 keypress event 。
  4. +
  5. 當按鍵放開時,會送出 keyup event 。
  6. +
+ +

特殊狀況

+ +

某些按鍵,例如 Caps Lock 、 Num Lock 和 Scroll Lock 能切換鍵盤上的 LED 燈。在 Windows 和 Linux 系統上,這些按鍵只會觸發 keydown 和 keyup 事件。但是 Linux 上的 Firefox 12 或更早的版本亦會觸發 keypress 事件。

+ +

而在 Mac 電腦則不同, Caps Lock 只會觸發 keydown 事件;而 Num Lock 則是只有舊版的 Mac 電腦(2007 或之前的版本)才有,現在的 Mac 即便使用外部鍵盤也不支援  Num Lock 。雖說舊版的 Mac 電腦支援 Num Lock 鍵,但 Num Lock  並不會執行任何 KeyboardEvent;而 Gecko 瀏覽器在特殊情況(外接一個有 F14 的鍵盤)下能支援 Scroll Lock ,但是它會產生 keypress 事件。這個異常狀態是個 bug ,詳情可參考 {{bug(602812)}}。

+ +

自動迴圈(Auto-Repeat )的執行

+ +

當按鍵按下去不放時,它會開始一個自動迴圈。並導致觸發一系列的相似事件,如下所示:

+ +
    +
  1. keydown
  2. +
  3. keypress
  4. +
  5. keydown
  6. +
  7. keypress
  8. +
  9. (不斷重複,直到使用者放開按鍵)
  10. +
  11. keyup
  12. +
+ +

在 DOM Level 3 說明書有提及這問題是會發生的。其中所存在的問題如下說明:

+ +

部分 GTK 環境,例如 Ubuntu 9.4 ,的自動迴圈

+ +

部分的 GTK-based 環境之中,自動迴圈在發生的過程中會自動觸發電腦本機的 key-up 事件。然而,對 Gecko 而言,並沒有方法可以分辨使用者重複點擊按鍵與自動迴圈(按鍵按住不放)的差異。在這類的環境下,按鍵按住不放會重複執行下列事件:

+ +
    +
  1. keydown
  2. +
  3. keypress
  4. +
  5. keyup
  6. +
  7. keydown
  8. +
  9. keypress
  10. +
  11. keyup
  12. +
  13. (不斷重複,直到使用者放開按鍵)
  14. +
  15. keyup
  16. +
+ +

不幸地,在這些環境之下,web content 亦沒有方法告訴使用者重複點擊按鍵與自動迴圈的差異。

+ +

Gecko 5.0 以前的自動迴圈

+ +

Gecko 5.0 {{geckoRelease('5.0')}} 以前,在不同平台上,鍵盤的處理與現在相比較不統一。

+ +
+
Windows
+
自動迴圈的結果與 Gecko 4.0 或更新的版本類似
+
Mac
+
在第一個 keydown 執行後,僅執行 keypress 事件,一直到案件放開(即送出 keyup 事件指令),過程中不會送出任何 keydown 事件。
+
Linux
+
鍵盤事件的執行根據平台不同而有所不同。它有可能表現得像是 Windows 也有可能像 Mac ,這取決於本地的事件模型(native event model)是如何執行的。
+
+ +

範例

+ +
<!DOCTYPE html>
+<html>
+<head>
+<script>
+var metaChar = false;
+var exampleKey = 16;
+
+function keyEvent(event) {
+  var key = event.keyCode || event.which;
+  var keychar = String.fromCharCode(key);
+  if (key == exampleKey) {
+    metaChar = true;
+  }
+  if (key != exampleKey) {
+    if (metaChar) {
+      alert("Combination of metaKey + " + keychar);
+      metaChar = false;
+    } else {
+      alert("Key pressed " + key);
+    }
+  }
+}
+
+function metaKeyUp (event) {
+  var key = event.keyCode || event.which;
+
+  if (key == exampleKey) {
+    metaChar = false;
+  }
+}
+</script>
+</head>
+
+<body onkeydown="keyEvent(event)" onkeyup="metaKeyUp(event)">
+</body>
+</html>
+
+ +

規格

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM3 Events', '#interface-KeyboardEvent', 'KeyboardEvent')}}{{Spec2('DOM3 Events')}}原始定義
+ +

The KeyboardEvent interface specification went through numerous draft versions, first under DOM Events Level 2 where it was dropped as no consensus arose, then under DOM Events Level 3. This led to the implementation of non-standard initialization methods, the early DOM Events Level 2 version, {{domxref("KeyboardEvent.initKeyEvent()")}} by Gecko browsers and the early DOM Events Level 3 version, {{domxref("KeyboardEvent.initKeyboardEvent()")}} by others. Both have been superseded by the modern usage of a constructor: {{domxref("KeyboardEvent.KeyboardEvent", "KeyboardEvent()")}}.

+ +

瀏覽器支援度

+ +

More compatibility data is available on other pages:

+ + + +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
constructor{{CompatVersionUnknown}}{{CompatGeckoDesktop("31.0")}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatUnknown}}
.char{{CompatNo}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}
.charCode{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
.codeSee Browser compatibility of {{domxref("KeyboardEvent.code")}}.
.isComposing{{CompatNo}}{{CompatGeckoDesktop("31.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
.keySee Browser compatibility of {{domxref("KeyboardEvent.key")}}.
.keyCode{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
.locale{{CompatNo}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}
.location{{CompatVersionUnknown}}{{CompatGeckoDesktop("15.0")}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}
.repeat{{CompatVersionUnknown}}{{CompatGeckoDesktop("28.0")}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}
.which{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
.getModifierState()See Browser compatibility of {{domxref("KeyboardEvent.getModifierState")}}
.initKeyboardEvent(){{CompatVersionUnknown}}[1]{{CompatNo}}[2]{{CompatIE("9.0")}}[3]{{CompatUnknown}}{{CompatVersionUnknown}}[1]
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
constructor{{CompatUnknown}}{{CompatGeckoMobile("31.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
.char{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
.charCode{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
.codeSee Browser compatibility of {{domxref("KeyboardEvent.code")}}.
.isComposing{{CompatNo}}{{CompatGeckoMobile("31.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
.keySee Browser compatibility table of {{domxref("KeyboardEvent.key")}}.
.keyCode{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
.locale{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
.location{{CompatUnknown}}{{CompatGeckoMobile("15.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
.repeat{{CompatUnknown}}{{CompatGeckoMobile("28.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
.which{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
.getModifierState()See Browser compatibility of {{domxref("KeyboardEvent.getModifierState")}}
.initKeyboardEvent(){{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] The arguments of initKeyboardEvent() of WebKit and Blink's are different from the definition in DOM Level 3 Events. The method is: initKeyboardEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in views::AbstractView viewArg, in DOMString keyIndentifierArg, in number locationArg, in boolean ctrlKeyArg, in boolean altKeyArg, in boolean shiftKeyArg, in boolean metaKeyArg, in boolean altGraphKeyArg)

+ +

[2] Gecko won't support initKeyboardEvent() because supporting it completely breaks feature detection of web applications. See {{Bug(999645)}}.

+ +

[3] The argument of initKeyboardEvent() of IE is different from the definition in DOM Level 3 Events. The method is: initKeyboardEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in views::AbstractView viewArg, in DOMString keyArg, in number locationArg, in DOMString modifierListArg, in boolean repeatArt, in DOMString locationArg). See document of initKeyboardEvent() in MSDN.

+ +

[4] Note that manually firing an event does not generate the default action associated with that event. For example, manually firing a key event does not cause that letter to appear in a focused text input. In the case of UI events, this is important for security reasons, as it prevents scripts from simulating user actions that interact with the browser itself.

diff --git a/files/zh-tw/web/api/keyboardevent/keyboardevent/index.html b/files/zh-tw/web/api/keyboardevent/keyboardevent/index.html new file mode 100644 index 0000000000..3af92514bb --- /dev/null +++ b/files/zh-tw/web/api/keyboardevent/keyboardevent/index.html @@ -0,0 +1,202 @@ +--- +title: KeyboardEvent() +slug: Web/API/KeyboardEvent/KeyboardEvent +translation_of: Web/API/KeyboardEvent/KeyboardEvent +--- +

{{APIRef("DOM Events")}}

+ +

KeyboardEvent() constructor 能用來建立一個新的 {{domxref("KeyboardEvent")}}。

+ +

語法

+ +
 event = new KeyboardEvent(typeArg, KeyboardEventInit);
+ +

參數

+ +
+
typeArg
+
一 {{domxref("DOMString")}} 用來表示事件名稱。
+
KeyboardEventInit{{optional_inline}}
+
一個 KeyboardEventInit dictionary,能接受以下參數: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
參數可選默認值類型說明
"key"""{{domxref("DOMString")}}用來設定 {{domxref("KeyboardEvent.key")}} 的值
"code"""{{domxref("DOMString")}}用來設定 {{domxref("KeyboardEvent.code")}} 的值
"location"0unsigned long用來設定 {{domxref("KeyboardEvent.location")}} 的值
"ctrlKey"false{{jsxref("Boolean")}}用來設定 {{domxref("KeyboardEvent.ctrlKey")}} 的值
"shiftKey"false{{jsxref("Boolean")}}用來設定 {{domxref("KeyboardEvent.shiftKey")}} 的值
"altKey"false{{jsxref("Boolean")}}用來設定 {{domxref("KeyboardEvent.altKey")}} 的值
"metaKey"false{{jsxref("Boolean")}}用來設定 {{domxref("KeyboardEvent.metaKey")}} 的值
"repeat"false{{jsxref("Boolean")}}用來設定 {{domxref("KeyboardEvent.repeat")}} 的值
"isComposing"false{{jsxref("Boolean")}}用來設定 {{domxref("KeyboardEvent.isComposing")}} 的值
"charCode"0unsigned long用來設定 {{domxref("KeyboardEvent.charCode")}} 的值
"keyCode"0unsigned long用來設定 {{domxref("KeyboardEvent.keyCode")}} 的值
"which"0unsigned long用來設定 {{domxref("KeyboardEvent.which")}} 的值
+ +
+

 KeyboardEventInit dictionary 亦接受 {{domxref("UIEvent.UIEvent", "UIEventInit")}} 和{{domxref("Event.Event", "EventInit")}} 所接受的參數。

+
+
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM3 Events','#interface-KeyboardEvent','KeyboardEvent()')}}{{Spec2('DOM3 Events')}}Initial definition.
+ +

瀏覽器支援度

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{ CompatVersionUnknown() }}{{ CompatGeckoDesktop(13) }}{{ CompatNo() }}{{ CompatVersionUnknown() }}{{ CompatUnknown() }}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewFirefox Mobile (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
Basic support{{ CompatUnknown }}{{ CompatVersionUnknown() }}{{ CompatGeckoMobile(31) }}{{ CompatNo() }}{{ CompatVersionUnknown() }}{{ CompatUnknown() }}{{CompatVersionUnknown}}
+
+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/api/media_streams_api/index.html b/files/zh-tw/web/api/media_streams_api/index.html new file mode 100644 index 0000000000..6813a5d1d6 --- /dev/null +++ b/files/zh-tw/web/api/media_streams_api/index.html @@ -0,0 +1,87 @@ +--- +title: Media Capture and Streams API (Media Stream) +slug: Web/API/Media_Streams_API +tags: + - API + - Audio + - Media + - Video +translation_of: Web/API/Media_Streams_API +--- +
{{DefaultAPISidebar("Media Capture and Streams")}}
+ +

媒體捕獲和流API,通常被稱為媒體流API或者乾脆MediaStream API,是關係到一個API的WebRTC提供流式音頻和視頻數據的支持。它提供了用於處理流及其組成軌道的接口和方法,與數據格式關聯的約束,異步使用數據時的成功和錯誤回調以及在此過程中觸發的事件。

+ +

概念和用法

+ +

該API基於{{domxref("MediaStream")}}對象的操作,該對象代表與音頻或視頻相關的數據流。請參閱“獲取視頻”中的示例。

+ +

A MediaStream consists of zero or more {{domxref("MediaStreamTrack")}} objects, representing various audio or video tracks. Each MediaStreamTrack may have one or more channels. The channel represents the smallest unit of a media stream, such as an audio signal associated with a given speaker, like left or right in a stereo audio track.

+ +

MediaStream objects have a single input and a single output. A MediaStream object generated by {{domxref("MediaDevices.getUserMedia", "getUserMedia()")}} is called local, and has as its source input one of the user's cameras or microphones. A non-local MediaStream may be representing to a media element, like {{HTMLElement("video")}} or {{HTMLElement("audio")}}, a stream originating over the network, and obtained via the WebRTC {{domxref("RTCPeerConnection")}} API, or a stream created using the Web Audio API {{domxref("MediaStreamAudioSourceNode")}}.

+ +

The output of the MediaStream object is linked to a consumer. It can be a media elements, like {{HTMLElement("audio")}} or {{HTMLElement("video")}}, the WebRTC {{domxref("RTCPeerConnection")}} API or a Web Audio API {{domxref("MediaStreamAudioSourceNode")}}.

+ +

Interfaces

+ +

In these reference articles, you'll find the fundamental information you'll need to know about each of the interfaces that make up the Media Capture and Streams API.

+ +
+ +
+ +

Early versions of the Media Capture and Streams API specification included separate AudioStreamTrack and VideoStreamTrack interfaces—each based upon {{domxref("MediaStreamTrack")}}—which represented streams of those types. These no longer exist, and you should update any existing code to instead use MediaStreamTrack directly.

+ +

Events

+ +
+ +
+ +

Guides and tutorials

+ +

The articles below provide additional guidance and how-to information that will help you learn to use the API, and how to perform specific tasks that you may wish to handle.

+ +

{{LandingPageListSubpages}}

+ +

Browser compatibility

+ + + +

{{Compat("api.MediaStream")}}

+ +

也可以看看

+ + diff --git a/files/zh-tw/web/api/mediaquerylist/index.html b/files/zh-tw/web/api/mediaquerylist/index.html new file mode 100644 index 0000000000..ef3128a4b8 --- /dev/null +++ b/files/zh-tw/web/api/mediaquerylist/index.html @@ -0,0 +1,144 @@ +--- +title: MediaQueryList +slug: Web/API/MediaQueryList +translation_of: Web/API/MediaQueryList +--- +
{{APIRef("CSSOM View")}}{{SeeCompatTable}}
+ +

MediaQueryList 物件維護一組針對 {{ domxref("document") }} 的 media querie , 並且當 media querie 相對應的文件狀態改變時,觸發註冊的事件處理器通知之。

+ +

MediaQueryList 物件讓我們不用一直定期去偵測,而是直接去觀察文件的狀態變化。

+ +

Method overview

+ + + + + + + + + + +
void addListener(MediaQueryListListener listener);
void removeListener(MediaQueryListListener listener);
+ +

Properties

+ + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
matchesbooleantrue 當 {{ domxref("document") }} 目前狀態符合 media query list 所維護的條件; 否則 false。 唯獨
mediaDOMString序列化 (serialized) 的 media query list.
+ +

Methods

+ +

addListener()

+ +

添加一個新的事件處理器 (listener),若 listener 已存在則無作用。

+ +
void addListener(
+  MediaQueryListListener listener
+);
+ +

Parameter (for addListener method)

+ +
+
listener
+
當 media query 對應的狀態改變時所觸發的事件處理函數 ({{ domxref("MediaQueryListListener") }})。
+
+ +

removeListener()

+ +

移除一個事件處理器 (listener),若 listener 不存在則無作用。

+ +
void removeListener(
+  MediaQueryListListener listener
+);
+ +

Parameter (for removeListener method)

+ +
+
listener
+
欲移除的事件處理函數 ({{ domxref("MediaQueryListListener") }})。
+
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support9{{ CompatGeckoDesktop("6.0") }}1012.15
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

 

+ +

規範標準

+ + + +

延伸閱讀

+ + diff --git a/files/zh-tw/web/api/mediasource/activesourcebuffers/index.html b/files/zh-tw/web/api/mediasource/activesourcebuffers/index.html new file mode 100644 index 0000000000..90777f675c --- /dev/null +++ b/files/zh-tw/web/api/mediasource/activesourcebuffers/index.html @@ -0,0 +1,126 @@ +--- +title: MediaSource.activeSourceBuffers +slug: Web/API/MediaSource/activeSourceBuffers +translation_of: Web/API/MediaSource/activeSourceBuffers +--- +
{{APIRef("Media Source Extensions")}}{{SeeCompatTable}}
+ +

activeSourceBuffers 是 {{domxref("MediaSource")}} 介面的唯讀屬性,回傳一個 {{domxref("SourceBufferList")}} 物件,含有在 {{domxref("SourceBuffers")}} 之中的 {{domxref("SourceBuffer")}} 物件子集合—物件的串列提供被選擇的影片軌 (video track), 啟用的音軌 (audio tracks), 以及顯示或隱藏的字軌。

+ +

語法

+ +
var myActiveSourceBuffers = mediaSource.activeSourceBuffers;
+ +

回傳值

+ +

一個 {{domxref("SourceBufferList")}} 。

+ +

範例

+ +

以下的片段基於 Nick Desaulniers 所編纂的簡單範例(觀看實際演示,或者下載原始碼 以利更進一步研究。)

+ +
function sourceOpen (_) {
+  //console.log(this.readyState); // open
+  var mediaSource = this;
+  var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
+  fetchAB(assetURL, function (buf) {
+    sourceBuffer.addEventListener('updateend', function (_) {
+      mediaSource.endOfStream();
+      console.log(mediaSource.activeSourceBuffers);
+      // will contain the source buffer that was added above,
+      // as it is selected for playing in the video player
+      video.play();
+      //console.log(mediaSource.readyState); // ended
+    });
+    sourceBuffer.appendBuffer(buf);
+  });
+};
+
+...
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態注釋
{{SpecName('Media Source Extensions', '#widl-MediaSource-activeSourceBuffers', 'activeSourceBuffers')}}{{Spec2('Media Source Extensions')}}Initial definition.
+ +

相容性表格

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support23{{CompatVersionUnknown}}{{CompatGeckoDesktop("25.0")}}[1]
+ {{CompatGeckoDesktop("42.0")}}
11[2]158
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)Firefox OS (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support4.4.4{{CompatVersionUnknown}} +

{{CompatNo}}

+
{{CompatNo}}1130{{CompatNo}}
+
+ +

[1] 在切換 about:config 偏好設定 media.mediasource.enabled 為 true 時可以使用。此外,支援只限於白名單內的網站,如:YouTube, Netflix, 以及其他熱門的串流網站。白名單已經被移除且 Media Source Extensions 在 42+ 對所有網站已預設為啟用。

+ +

[2] 只在 Windows 8+ 上有效。

+ +

相關資料

+ + diff --git a/files/zh-tw/web/api/mediasource/duration/index.html b/files/zh-tw/web/api/mediasource/duration/index.html new file mode 100644 index 0000000000..b9fab966e4 --- /dev/null +++ b/files/zh-tw/web/api/mediasource/duration/index.html @@ -0,0 +1,149 @@ +--- +title: MediaSource.duration +slug: Web/API/MediaSource/duration +translation_of: Web/API/MediaSource/duration +--- +
{{APIRef("Media Source Extensions")}}{{SeeCompatTable}}
+ +

{{domxref("MediaSource")}} 介面的 duration 屬性用來取得以及設置正被表示的媒體時間長度。

+ +

語法

+ +
mediaSource.duration = 5.5; // 5.5 seconds
+
+var myDuration = mediaSource.duration;
+ +

回傳值

+ +

單位為秒的 double 型別。

+ +

錯誤

+ +

當設置此屬性一個新的值時以下錯誤可能發生。

+ + + + + + + + + + + + + + + + + + +
錯誤解釋
InvalidAccessError嘗試設置的時間長度是負值,或者 NaN
InvalidStateError{{domxref("MediaSource.readyState")}} 不是 open,或者 {{domxref("MediaSource.sourceBuffers")}} 中一個或多個以上的 {{domxref("SourceBuffer")}} 物件正在被更新(例如:他們的 {{domxref("SourceBuffer.updating")}} 屬性為 true。)
+ +

範例

+ +

以下的片段基於 Nick Desaulniers 所編纂的簡單範例(觀看實際演示,或者下載原始碼以利更進一步研究。)

+ +
function sourceOpen (_) {
+  //console.log(this.readyState); // open
+  var mediaSource = this;
+  var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
+  fetchAB(assetURL, function (buf) {
+    sourceBuffer.addEventListener('updateend', function (_) {
+      mediaSource.endOfStream();
+      mediaSource.duration = 120;
+      video.play();
+      //console.log(mediaSource.readyState); // ended
+    });
+    sourceBuffer.appendBuffer(buf);
+  });
+};
+
+...
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態注釋
{{SpecName('Media Source Extensions', '#widl-MediaSource-duration', 'duration')}}{{Spec2('Media Source Extensions')}}Initial definition.
+ +

相容性表格

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support23{{CompatVersionUnknown}}{{CompatGeckoDesktop("25.0")}}[1]
+ {{CompatGeckoDesktop("42.0")}}
11[2]158
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)Firefox OS (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support4.4.4{{CompatVersionUnknown}} +

{{CompatNo}}

+
{{CompatNo}}1130{{CompatNo}}
+
+ +

[1] 在切換 about:config 偏好設定 media.mediasource.enabledtrue時可以使用。此外,支援只限於白名單內的網站,如:YouTube, Netflix, 以及其他熱門的串流網站。白名單已經被移除且 Media Source Extensions 在 42+ 對所有網站已預設為啟用。

+ +

[2] 只在 Windows 8+ 上有效。

+ +

相關資料

+ + diff --git a/files/zh-tw/web/api/mediasource/index.html b/files/zh-tw/web/api/mediasource/index.html new file mode 100644 index 0000000000..0006121f46 --- /dev/null +++ b/files/zh-tw/web/api/mediasource/index.html @@ -0,0 +1,144 @@ +--- +title: MediaSource +slug: Web/API/MediaSource +translation_of: Web/API/MediaSource +--- +

{{APIRef("Media Source Extensions")}}{{SeeCompatTable}}

+ +

Media Source Extensions APIMediaSource 介面代表 {{domxref("HTMLMediaElement")}} 物件的媒體資料來源。一個 MediaSource 物件可以被附加到一個 {{domxref("HTMLMediaElement")}} 以被用戶代理 (user agent) 播放。

+ +

{{InheritanceDiagram}}

+ +

建構子 (Constructor)

+ +
+
{{domxref("MediaSource.MediaSource", "MediaSource()")}}
+
建構且回傳一個新的 MediaSource 物件但不與任何來源緩衝 (source buffers) 關聯 (associate)。
+
+ +

屬性 (Properties)

+ +
+
{{domxref("MediaSource.sourceBuffers")}} {{readonlyInline}}
+
回傳一個含有與此 MediaSource 關聯的 {{domxref("SourceBuffer")}} 物件串列的 {{domxref("SourceBufferList")}} 物件。
+
{{domxref("MediaSource.activeSourceBuffers")}} {{readonlyInline}}
+
回傳一個 {{domxref("SourceBufferList")}} 物件,含有 {{domxref("SourceBuffers")}} 的子集合 {{domxref("SourceBuffer")}} 物件 — 物件的串列提供被選擇的影片軌 (video track), 啟用的音軌 (audio tracks), 以及顯示或隱藏的字軌。
+
{{domxref("MediaSource.readyState")}} {{readonlyInline}}
+
回傳一個列舉類型表示目前 MediaSource 的狀態:沒有附加到媒體元件 (closed),已經附加且可以接收 {{domxref("SourceBuffer")}} 物件 (open),已經附加但是串流已經經由 {{domxref("MediaSource.endOfStream()")}} 結束 (ended)。
+
{{domxref("MediaSource.duration")}}
+
取得或設置現在正被表示的媒體的時間長度。
+
+

事件處理函數 (Event handlers)

+ + +
+
{{domxref("MediaSource.onsourceclose")}}
+
sourceclose 事件的事件處理函數。
+
{{domxref("MediaSource.onsourceended")}}
+
sourceended 事件的事件處理函數。
+
{{domxref("MediaSource.onsourceopen")}}
+
sourceopen 事件的事件處理函數。
+
+ +
+
+ +
+
+ +

方法 (Methods)

+ +

從親介面 (parent interface) {{domxref("EventTarget")}} 繼承屬性。

+ +
+
{{domxref("MediaSource.addSourceBuffer()")}}
+
依據指定的 MIME 類型建立一個新的 {{domxref("SourceBuffer")}} 且將其加入 MediaSource 的 {{domxref("SourceBuffers")}} 串列。
+
{{domxref("MediaSource.clearLiveSeekableRange()")}}
+
清除先前藉由呼叫 setLiveSeekableRange() 所設定的可尋找範圍。
+
{{domxref("MediaSource.endOfStream()")}}
+
示意串流的結束。
+
{{domxref("MediaSource.removeSourceBuffer()")}}
+
從與此 MediaSource 物件關聯的 {{domxref("SourceBuffers")}} 串列移除指定的 {{domxref("SourceBuffer")}}。
+
{{domxref("MediaSource.setLiveSeekableRange()")}}
+
設定使用者可以在媒體元素中的可尋找範圍。
+
+ +

靜態方法 (Static methods)

+ +
+
{{domxref("MediaSource.isTypeSupported()")}}
+
回傳一個 {{domxref("Boolean")}} 值表示指定的 MIME 類型是否被現在的用戶代理支援 — 意即可否成功的為該 MIME 類型建立 {{domxref("SourceBuffer")}} 物件。
+
+ +

範例

+ +

以下簡單的範例儘快的載入一個個影片塊 (chunk) 且儘快的播放。這個範例是由 Nick Desaulniers 所撰寫且可以在此實際觀看(您也可以下載原始碼以更進一步研究)

+ +
var video = document.querySelector('video');
+
+var assetURL = 'frag_bunny.mp4';
+// Need to be specific for Blink regarding codecs
+// ./mp4info frag_bunny.mp4 | grep Codec
+var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
+
+if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
+  var mediaSource = new MediaSource();
+  //console.log(mediaSource.readyState); // closed
+  video.src = URL.createObjectURL(mediaSource);
+  mediaSource.addEventListener('sourceopen', sourceOpen);
+} else {
+  console.error('Unsupported MIME type or codec: ', mimeCodec);
+}
+
+function sourceOpen (_) {
+  //console.log(this.readyState); // open
+  var mediaSource = this;
+  var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
+  fetchAB(assetURL, function (buf) {
+    sourceBuffer.addEventListener('updateend', function (_) {
+      mediaSource.endOfStream();
+      video.play();
+      //console.log(mediaSource.readyState); // ended
+    });
+    sourceBuffer.appendBuffer(buf);
+  });
+};
+
+function fetchAB (url, cb) {
+  console.log(url);
+  var xhr = new XMLHttpRequest;
+  xhr.open('get', url);
+  xhr.responseType = 'arraybuffer';
+  xhr.onload = function () {
+    cb(xhr.response);
+  };
+  xhr.send();
+};
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態註釋
{{SpecName('Media Source Extensions', '#mediasource', 'MediaSource')}}{{Spec2('Media Source Extensions')}}Initial definition.
+ +

相容性表格

+ +
{{Compat("api.MediaSource")}}
+ +

相關資料

+ + diff --git a/files/zh-tw/web/api/mediasource/mediasource/index.html b/files/zh-tw/web/api/mediasource/mediasource/index.html new file mode 100644 index 0000000000..54e9e6dfef --- /dev/null +++ b/files/zh-tw/web/api/mediasource/mediasource/index.html @@ -0,0 +1,122 @@ +--- +title: MediaSource.MediaSource() +slug: Web/API/MediaSource/MediaSource +translation_of: Web/API/MediaSource/MediaSource +--- +
{{APIRef("Media Source Extensions")}}{{SeeCompatTable}}
+ +

{{domxref("MediaSource")}} 介面的 MediaSource() 建構子建構且回傳一個沒有與任何來源緩衝 (source buffer) 關聯的新 MediaSource 物件。

+ +

語法

+ +
var mediaSource = new MediaSource();
+ +

參數

+ +

無。

+ +

範例

+ +

以下的片段擷取自 Nick Desaulniers 所編纂的簡單範例(觀看實際演示,或者下載原始碼 以利更進一步研究。)

+ +
var video = document.querySelector('video');
+
+var assetURL = 'frag_bunny.mp4';
+// Need to be specific for Blink regarding codecs
+// ./mp4info frag_bunny.mp4 | grep Codec
+var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
+
+if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
+  var mediaSource = new MediaSource;
+  //console.log(mediaSource.readyState); // closed
+  video.src = URL.createObjectURL(mediaSource);
+  mediaSource.addEventListener('sourceopen', sourceOpen);
+} else {
+  console.error('Unsupported MIME type or codec: ', mimeCodec);
+}
+
+...
+
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態註釋
{{SpecName('Media Source Extensions', '#mediasource', 'MediaSource')}}{{Spec2('Media Source Extensions')}}Initial definition.
+ +

相容性表格

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support23{{CompatGeckoDesktop("25.0")}}[1]
+ {{CompatGeckoDesktop("42.0")}}
11[2]158
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)Firefox OS (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support4.4.4 +

{{CompatNo}}

+
{{CompatNo}}1130{{CompatNo}}
+
+ +

[1] 在切換 about:config 偏好設定 media.mediasource.enabled 為 true 時可以使用。此外,支援只限於白名單內的網站,如:YouTube, Netflix, 以及其他熱門的串流網站。白名單已經被移除且 Media Source Extensions 在 42+ 對所有網站已預設為啟用。

+ +

[2] 只在 Windows 8+ 上有效。

+ +

相關資料

+ + diff --git a/files/zh-tw/web/api/mediasource/readystate/index.html b/files/zh-tw/web/api/mediasource/readystate/index.html new file mode 100644 index 0000000000..b7e5f1835b --- /dev/null +++ b/files/zh-tw/web/api/mediasource/readystate/index.html @@ -0,0 +1,136 @@ +--- +title: MediaSource.readyState +slug: Web/API/MediaSource/readyState +translation_of: Web/API/MediaSource/readyState +--- +
{{APIRef("Media Source Extensions")}}{{SeeCompatTable}}
+ +

{{domxref("MediaSource")}} 介面的唯讀屬性 readyState 回傳表示當前 MediaSource 狀態的列舉值。三種可能的值為:

+ + + +

語法

+ +
var myReadyState = mediaSource.readyState;
+ +

回傳值

+ +

一個 {{domxref("DOMString")}}。

+ +

範例

+ +

以下片段是由 Nick Desaulniers 所撰寫的簡單範例(在此實際觀看,或者下載原始碼以更進一步研究)

+ +
if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
+  var mediaSource = new MediaSource;
+  //console.log(mediaSource.readyState); // closed
+  video.src = URL.createObjectURL(mediaSource);
+  mediaSource.addEventListener('sourceopen', sourceOpen);
+} else {
+  console.error('Unsupported MIME type or codec: ', mimeCodec);
+}
+
+function sourceOpen (_) {
+  //console.log(this.readyState); // open
+  var mediaSource = this;
+  var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
+  fetchAB(assetURL, function (buf) {
+    sourceBuffer.addEventListener('updateend', function (_) {
+      mediaSource.endOfStream();
+      video.play();
+      //console.log(mediaSource.readyState); // ended
+    });
+    sourceBuffer.appendBuffer(buf);
+  });
+};
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態註釋
{{SpecName('Media Source Extensions', '#widl-MediaSource-readyState', 'readyState')}}{{Spec2('Media Source Extensions')}}Initial definition.
+ +

相容性表格

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support23{{CompatVersionUnknown}}{{CompatGeckoDesktop("25.0")}}[1]
+ {{CompatGeckoDesktop("42.0")}}
11[2]158
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)Firefox OS (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support4.4.4{{CompatVersionUnknown}} +

{{CompatNo}}

+
{{CompatNo}}1130{{CompatNo}}
+
+ +

[1] 在切換 about:config preference media.mediasource.enabled 為 true 時可以使用。此外,支援只限於白名單內的網站,如:YouTube, Netflix, 以及其他熱門的串流網站。白名單已經被移除且 Media Source Extensions 在 42+ 對所有網站已預設為啟用。

+ +

[2] 只在 Windows 8+ 上有效。

+ +

相關資料

+ + diff --git a/files/zh-tw/web/api/mouseevent/index.html b/files/zh-tw/web/api/mouseevent/index.html new file mode 100644 index 0000000000..43f2a3a26d --- /dev/null +++ b/files/zh-tw/web/api/mouseevent/index.html @@ -0,0 +1,317 @@ +--- +title: MouseEvent +slug: Web/API/MouseEvent +translation_of: Web/API/MouseEvent +--- +

{{APIRef("DOM Events")}}

+ +

MouseEvent 介面表示了由使用者經指標裝置(如滑鼠)進行互動所發生的事件。常見的 MouseEvent 實作事件包括了 {{event("click")}}、{{event("dblclick")}}、{{event("mouseup")}} 與 {{event("mousedown")}}。

+ +

MouseEvent 繼承自 {{domxref("UIEvent")}},而 UIEvent 則繼承自 {{domxref("Event")}}。雖然 {{domxref("MouseEvent.initMouseEvent()")}} 方法仍然向下相容新的瀏覽器,但現今應該使用 {{domxref("MouseEvent.MouseEvent", "MouseEvent()")}} 建構式來建立 MouseEvent 物件。

+ +

另外還有一些特定的事件繼承自 MouseEvent:{{domxref("WheelEvent")}} 及 {{domxref("DragEvent")}}。

+ +

建構式

+ +
+
{{domxref("MouseEvent.MouseEvent", "MouseEvent()")}}
+
建立一個 MouseEvent 物件。
+
+ +

屬性

+ +

此介面也繼承了其父介面 {{domxref("UIEvent")}} 與 {{domxref("Event")}} 的屬性

+ +
+
{{domxref("MouseEvent.altKey")}} {{readonlyinline}}
+
Returns true if the alt key was down when the mouse event was fired.
+
{{domxref("MouseEvent.button")}} {{readonlyinline}}
+
The button number that was pressed when the mouse event was fired. 
+
{{domxref("MouseEvent.buttons")}} {{readonlyinline}} {{gecko_minversion_inline("15.0")}}
+
+

The buttons being pressed when the mouse event was fired

+
+
{{domxref("MouseEvent.clientX")}} {{readonlyinline}}
+
The X coordinate of the mouse pointer in local (DOM content) coordinates.
+
{{domxref("MouseEvent.clientY")}} {{readonlyinline}}
+
The Y coordinate of the mouse pointer in local (DOM content) coordinates.
+
{{domxref("MouseEvent.ctrlKey")}} {{readonlyinline}}
+
Returns true if the control key was down when the mouse event was fired.
+
{{domxref("MouseEvent.metaKey")}} {{readonlyinline}}
+
Returns true if the meta key was down when the mouse event was fired.
+
{{domxref("MouseEvent.movementX")}} {{readonlyinline}}
+
The X coordinate of the mouse pointer relative to the position of the last {{event("mousemove")}} event.
+
{{domxref("MouseEvent.movementY")}} {{readonlyinline}}
+
The Y coordinate of the mouse pointer relative to the position of the last {{event("mousemove")}} event.
+
{{domxref("MouseEvent.offsetX")}} {{readonlyinline}}{{experimental_inline}}
+
The X coordinate of the mouse pointer relative to the position of the padding edge of the target node.
+
{{domxref("MouseEvent.offsetY")}} {{readonlyinline}}{{experimental_inline}}
+
The Y coordinate of the mouse pointer relative to the position of the padding edge of the target node.
+
{{domxref("MouseEvent.pageX")}} {{readonlyinline}}{{experimental_inline}}
+
The X coordinate of the mouse pointer relative to the whole document.
+
{{domxref("MouseEvent.pageY")}} {{readonlyinline}}{{experimental_inline}}
+
The Y coordinate of the mouse pointer relative to the whole document.
+
{{domxref("MouseEvent.region")}} {{readonlyinline}}
+
Returns the id of the hit region affected by the event. If no hit region is affected, null is returned.
+
{{domxref("MouseEvent.relatedTarget")}} {{readonlyinline}}
+
+

The secondary target for the event, if there is one.

+
+
{{domxref("MouseEvent.screenX")}} {{readonlyinline}}
+
The X coordinate of the mouse pointer in global (screen) coordinates.
+
{{domxref("MouseEvent.screenY")}} {{readonlyinline}}
+
The Y coordinate of the mouse pointer in global (screen) coordinates.
+
{{domxref("MouseEvent.shiftKey")}} {{readonlyinline}}
+
Returns true if the shift key was down when the mouse event was fired.
+
{{domxref("MouseEvent.which")}} {{non-standard_inline}} {{readonlyinline}}
+
The button being pressed when the mouse event was fired.
+
{{domxref("MouseEvent.mozPressure")}} {{non-standard_inline()}} {{readonlyinline}}
+
The amount of pressure applied to a touch or tablet device when generating the event; this value ranges between 0.0 (minimum pressure) and 1.0 (maximum pressure).
+
{{domxref("MouseEvent.mozInputSource")}} {{non-standard_inline()}} {{readonlyinline}}
+
+

The type of device that generated the event (one of the MOZ_SOURCE_* constants listed below). This lets you, for example, determine whether a mouse event was generated by an actual mouse or by a touch event (which might affect the degree of accuracy with which you interpret the coordinates associated with the event).

+
+
{{domxref("MouseEvent.webkitForce")}} {{non-standard_inline()}} {{readonlyinline}}
+
The amount of pressure applied when clicking
+
{{domxref("MouseEvent.x")}} {{experimental_inline}}{{readonlyinline}}
+
Alias for {{domxref("MouseEvent.clientX")}}.
+
{{domxref("MouseEvent.y")}} {{experimental_inline}}{{readonlyinline}}
+
Alias for {{domxref("MouseEvent.clientY")}}
+
+ +

Constants

+ +
+
{{domxref("MouseEvent.WEBKIT_FORCE_AT_MOUSE_DOWN")}} {{non-standard_inline}}{{readonlyinline}}
+
Minimum force necessary for a normal click
+
{{domxref("MouseEvent.WEBKIT_FORCE_AT_FORCE_MOUSE_DOWN")}} {{non-standard_inline}}{{readonlyinline}}
+
Minimum force necessary for a force click
+
+ +

方法

+ +

此介面也繼承了其父介面 {{domxref("UIEvent")}} 與 {{domxref("Event")}} 的方法

+ +
+
{{domxref("MouseEvent.getModifierState()")}}
+
Returns the current state of the specified modifier key. See the {{domxref("KeyboardEvent.getModifierState")}}() for details.
+
{{domxref("MouseEvent.initMouseEvent()")}} {{deprecated_inline}}
+
Initializes the value of a MouseEvent created. If the event has already being dispatched, this method does nothing.
+
+ +

範例

+ +

This example demonstrates simulating a click (that is programmatically generating a click event) on a checkbox using DOM methods. 

+ +
function simulateClick() {
+  var evt = new MouseEvent("click", {
+    bubbles: true,
+    cancelable: true,
+    view: window
+  });
+  var cb = document.getElementById("checkbox"); //element to click on
+  var canceled = !cb.dispatchEvent(evt);
+  if(canceled) {
+    // A handler called preventDefault
+    alert("canceled");
+  } else {
+    // None of the handlers called preventDefault
+    alert("not canceled");
+  }
+}
+document.getElementById("button").addEventListener('click', simulateClick);
+ +
<p><label><input type="checkbox" id="checkbox"> Checked</label>
+<p><button id="button">Click me</button>
+ +

Click on the button to see how the sample works:

+ +

{{ EmbedLiveSample('Example', '', '', '') }}

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSSOM View','#extensions-to-the-mouseevent-interface', 'MouseEvent')}}{{Spec2('CSSOM View')}}Redefines MouseEvent from long to double. This means that a PointerEvent whose pointerType is mouse will be a double.
{{SpecName("HTML WHATWG", "#dom-mouseevent-region", "MouseEvent.region")}}{{Spec2('HTML WHATWG')}}From {{SpecName('DOM3 Events')}}, added the region property.
{{SpecName('Pointer Lock','#extensions-to-the-mouseevent-interface','MouseEvent')}}{{Spec2('Pointer Lock')}}From {{SpecName('DOM3 Events')}}, added movementX and movementY properties.
{{SpecName('CSSOM View', '#extensions-to-the-mouseevent-interface', 'MouseEvent')}}{{Spec2('CSSOM View')}}From {{SpecName('DOM3 Events')}}, added offsetX and offsetY, pageX and pageY, x, and y properties. Redefined screen, page, client and coordinate (x and y) properties as double from long.
{{SpecName('DOM3 Events','#events-mouseevents','MouseEvent')}}{{Spec2('DOM3 Events')}}From {{SpecName('DOM2 Events')}}, added the MouseEvent() constructor, the getModifierState() method and the buttons property.
{{SpecName('DOM2 Events','#Events-MouseEvent','MouseEvent')}}{{Spec2('DOM2 Events')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown()}}{{CompatVersionUnknown()}}{{CompatVersionUnknown()}}{{CompatVersionUnknown()}}{{CompatVersionUnknown()}}{{CompatVersionUnknown()}}
{{domxref("MouseEvent.movementX","movementX")}}
+ {{domxref("MouseEvent.movementY","movementY")}}
{{CompatChrome(37)}}{{CompatVersionUnknown()}}{{CompatVersionUnknown()}} {{property_prefix("moz")}}{{ CompatUnknown() }}{{CompatVersionUnknown()}}{{ CompatUnknown() }}
{{ domxref("MouseEvent.buttons", "buttons") }}{{CompatChrome(43)}}{{CompatVersionUnknown()}}{{ CompatVersionUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{CompatNo}}
{{ domxref("MouseEvent.which", "which") }}{{CompatChrome(1)}}{{CompatVersionUnknown()}}1.09.05.01.0
{{domxref("MouseEvent.getModifierState()", "getModifierState()")}}{{CompatChrome(47)}}{{CompatVersionUnknown()}}{{CompatGeckoDesktop(15)}}{{CompatVersionUnknown()}}{{CompatVersionUnknown()}}{{CompatVersionUnknown()}}
{{domxref("MouseEvent.mozPressure", "mozPressure")}} and {{domxref("MouseEvent.mozInputSource", "mozInputSource")}} {{non-standard_inline}}{{CompatNo}}{{ CompatUnknown() }}{{CompatGeckoDesktop(2)}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
{{domxref("MouseEvent.MouseEvent", "MouseEvent()")}}{{CompatChrome(45)}}{{ CompatUnknown() }}{{CompatGeckoDesktop(11)}}9.0{{CompatVersionUnknown()}}{{ CompatUnknown() }}
{{domxref("MouseEvent.region")}}{{CompatChrome(51)}}[1]{{ CompatUnknown() }}{{CompatGeckoDesktop(32)}}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
{{domxref("MouseEvent.offsetX")}}, and {{domxref("MouseEvent.offsetY")}}{{CompatVersionUnknown()}}9{{CompatGeckoDesktop(40)}}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
{{domxref("MouseEvent.screenX")}}, {{domxref("MouseEvent.screenY")}}, {{domxref("MouseEvent.clientX")}}, and {{domxref("MouseEvent.Y")}} are double instead of long.{{CompatChrome(56)}}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatNo}}{{CompatNo}}{{CompatVersionUnknown}}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +

[1] Requires enabling the ExperimentalCanvasFeatures flag.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/mutationobserver/index.html b/files/zh-tw/web/api/mutationobserver/index.html new file mode 100644 index 0000000000..e2e1e50bfd --- /dev/null +++ b/files/zh-tw/web/api/mutationobserver/index.html @@ -0,0 +1,276 @@ +--- +title: MutationObserver +slug: Web/API/MutationObserver +translation_of: Web/API/MutationObserver +--- +

{{APIRef("DOM")}}

+ +

MutationObserver 提供開發人員一個方法,來對 DOM tree 的變動來作反應,這被設計用來替換在 DOM3 事件規範中的 Mutation Events

+ +

建構式

+ +

MutationObserver()

+ +

以下舉例為一個新的 DOM mutation observers 建構式。

+ +
new MutationObserver(
+  function callback
+);
+
+ +
參數
+ +
+
callback
+
這個函式會在 DOM 有變化時被呼叫,observer 會用兩個參數來呼叫它,第一個是 MutationRecord 物件陣列,而第二個參數則是觀察者目標本身。
+
+ +

Instance methods

+ + + + + + + + + + + + + +
void observe( {{domxref("Node")}} target, MutationObserverInit options );
void disconnect();
Array takeRecords();
+ +
+

筆記: {{domxref("Node")}} target should not be confused with NodeJS.

+
+ +

observe()

+ +

Registers the MutationObserver instance to receive notifications of DOM mutations on the specified node.

+ +
void observe(
+  {{domxref("Node")}} target,
+  MutationObserverInit options
+);
+
+ +
Parameters
+ +
+
target
+
The {{domxref("Node")}} on which to observe DOM mutations.
+
options
+
A MutationObserverInit object, specifies which DOM mutations should be reported.
+
+ +
NOTE: Adding an observer to an element is just like addEventListener, if you observe the element multiple times it does not make a difference. Meaning if you observe element twice, the observe callback does not fire twice, nor will you have to run disconnect() twice. In other words, once an element is observed, observing it again with the same observer instance will do nothing. However if the callback object is different it will of course add another observer to it.
+ +

disconnect()

+ +

Stops the MutationObserver instance from receiving notifications of DOM mutations. Until the observe() method is used again, observer's callback will not be invoked.

+ +
void disconnect();
+
+ +

takeRecords()

+ +

Empties the MutationObserver instance's record queue and returns what was in there.

+ +
Array takeRecords();
+
+ +
Return value
+ +

Returns an Array of MutationRecords.

+ +

MutationObserverInit

+ +

MutationObserverInit is an object which can specify the following properties:

+ +
NOTE: At the very least, childList, attributes, or characterData must be set to true. Otherwise, "An invalid or illegal string was specified" error is thrown.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyDescription
childListSet to true if additions and removals of the target node's child elements (including text nodes) are to be observed.
attributesSet to true if mutations to target's attributes are to be observed.
characterDataSet to true if mutations to target's data are to be observed.
subtreeSet to true if mutations to not just target, but also target's descendants are to be observed.
attributeOldValueSet to true if attributes is set to true and target's attribute value before the mutation needs to be recorded.
characterDataOldValueSet to true if characterData is set to true and target's data before the mutation needs to be recorded.
attributeFilterSet to an array of attribute local names (without namespace) if not all attribute mutations need to be observed.
+ +

MutationRecord

+ +

MutationRecord is the object that will be passed to the observer's callback. It has the following properties:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
typeStringReturns attributes if the mutation was an attribute mutation, characterData if it was a mutation to a CharacterData node, and childList if it was a mutation to the tree of nodes.
target{{domxref("Node")}}Returns the node the mutation affected, depending on the type. For attributes, it is the element whose attribute changed. For characterData, it is the CharacterData node. For childList, it is the node whose children changed.
addedNodes{{domxref("NodeList")}}Return the nodes added. Will be an empty NodeList if no nodes were added.
removedNodes{{domxref("NodeList")}}Return the nodes removed. Will be an empty NodeList if no nodes were removed.
previousSibling{{domxref("Node")}}Return the previous sibling of the added or removed nodes, or null.
nextSibling{{domxref("Node")}}Return the next sibling of the added or removed nodes, or null.
attributeNameStringReturns the local name of the changed attribute, or null.
attributeNamespaceStringReturns the namespace of the changed attribute, or null.
oldValueStringThe return value depends on the type. For attributes, it is the value of the changed attribute before the change. For characterData, it is the data of the changed node before the change. For childList, it is null.
+ +

Example usage

+ +

The following example was taken from this blog post.

+ +
// select the target node
+var target = document.querySelector('#some-id');
+
+// create an observer instance
+var observer = new MutationObserver(function(mutations) {
+  mutations.forEach(function(mutation) {
+    console.log(mutation.type);
+  });
+});
+
+// configuration of the observer:
+var config = { attributes: true, childList: true, characterData: true };
+
+// pass in the target node, as well as the observer options
+observer.observe(target, config);
+
+// later, you can stop observing
+observer.disconnect();
+
+ +

Additional reading

+ + + +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support18 {{property_prefix("-webkit")}}
+ 26
{{CompatGeckoDesktop(14)}}11156.0 {{property_prefix("-webkit")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatUnknown}}18 {{property_prefix("-webkit")}}
+ 26
{{CompatGeckoMobile(14)}}11 (8.1)156 {{property_prefix("-webkit")}}
+ 7
+
diff --git a/files/zh-tw/web/api/namednodemap/index.html b/files/zh-tw/web/api/namednodemap/index.html new file mode 100644 index 0000000000..1aafe72d0a --- /dev/null +++ b/files/zh-tw/web/api/namednodemap/index.html @@ -0,0 +1,156 @@ +--- +title: NamedNodeMap +slug: Web/API/NamedNodeMap +translation_of: Web/API/NamedNodeMap +--- +
{{APIRef("DOM")}}
+ +

NamedNodeMap 介面表示了 {{domxref("Attr")}} 物件的集合。雖然 NamedNodeMap 與 {{domxref("NodeList")}} 都能如陣列一般透過索引訪問成員,但和 NodeList 不同的是,NamedNodeMap 中的成員並沒有順序。

+ +

NamedNodeMap 物件具有即時性(live),如果其內部成員(屬性節點物件)發生改變,NamedNodeMap 物件會自動更新至最新的狀態。

+ +
+

僅管被稱作 NamedNodeMap,但本介面並不是直接用來處理節點物件({{domxref("Node")}}),而是專門負責屬性節點物件({{domxref("Attr")}})。屬性節點是一種特殊的節點,在部分瀏覽器實作中依然存在。

+
+ +

屬性

+ +

This interface doesn't inherit any property.

+ +
+
{{domxref("NamedNodeMap.length")}} {{ReadOnlyInline}}
+
Returns the amount of objects in the map.
+
+ +

方法

+ +

This interface doesn't inherit any method.

+ +
+
{{domxref("NamedNodeMap.getNamedItem()")}}
+
Returns a {{domxref("Attr")}}, corresponding to the given name.
+
{{domxref("NamedNodeMap.setNamedItem()")}}
+
Replaces, or adds, the {{domxref("Attr")}} identified in the map by the given name.
+
{{domxref("NamedNodeMap.removeNamedItem()")}}
+
Removes the {{domxref("Attr")}} identified by the given map.
+
{{domxref("NamedNodeMap.item()")}}
+
Returns the {{domxref("Attr")}} at the given index, or null if the index is higher or equal to the number of nodes.
+
{{domxref("NamedNodeMap.getNamedItemNS()")}}
+
Returns a {{domxref("Attr")}} identified by a namespace and related local name.
+
{{domxref("NamedNodeMap.setNamedItemNS()")}}
+
Replaces, or adds, the {{domxref("Attr")}} identified in the map by the given namespace and related local name.
+
{{domxref("NamedNodeMap.removeNamedItemNS()")}}
+
Removes the {{domxref("Attr")}} identified by the given namespace and related local name.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#interface-namednodemap', 'NamedNodeMap')}}{{Spec2('DOM WHATWG')}}Deals with {{domxref("Attr")}} instead of {{domxref("Node")}}
{{SpecName('DOM3 Core', 'core.html#ID-1780488922', 'NamedNodeMap')}}{{Spec2('DOM3 Core')}}No change from {{SpecName('DOM2 Core')}}
{{SpecName('DOM2 Core', 'core.html#ID-1780488922', 'NamedNodeMap')}}{{Spec2('DOM2 Core')}}Added getNamedItemNS(), setNamedItemNS() and removeNamedItemNS()
{{SpecName('DOM1', 'core.html#ID-1780488922', 'NamedNodeMap')}}{{Spec2('DOM1')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
Deals with {{domxref("Attr")}} rather than {{domxref("Node")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoDesktop(22)}}[1]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
Deals with {{domxref("Attr")}} rather than {{domxref("Node")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile(22)}}[1]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] In Gecko 22 this interface was named mozNamedAttrMap. In Gecko 34 it was named back to NamedNodeMap.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/navigator/geolocation/index.html b/files/zh-tw/web/api/navigator/geolocation/index.html new file mode 100644 index 0000000000..7c709b0b21 --- /dev/null +++ b/files/zh-tw/web/api/navigator/geolocation/index.html @@ -0,0 +1,96 @@ +--- +title: Navigator.geolocation +slug: Web/API/Navigator/geolocation +translation_of: Web/API/Navigator/geolocation +--- +
{{APIRef("Geolocation API")}}
+ +

Navigator.geolocation 回傳一個唯讀的 {{domxref("Geolocation")}} 物件,透過這個物件可以存取設備的位置訊息。同時也允許網站或應用程式根據使用者的位置提供客製化的結果。

+ +
+

備註: 因為隱私的因素,當網頁要求存取位置資訊時,用戶會被提示通知並且詢問授權與否。注意不同的瀏覽器在詢問授權時有各自不同的策略和方式。

+
+ +

語法

+ +
geo = navigator.geolocation
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#navi-geo', 'Navigator.geolocation')}}{{Spec2('Geolocation')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/navigator/index.html b/files/zh-tw/web/api/navigator/index.html new file mode 100644 index 0000000000..84fcfacf61 --- /dev/null +++ b/files/zh-tw/web/api/navigator/index.html @@ -0,0 +1,154 @@ +--- +title: Navigator +slug: Web/API/Navigator +tags: + - API + - HTML-DOM + - Interface + - NeedsTranslation + - Reference + - TopicStub + - Web Performance +translation_of: Web/API/Navigator +--- +

{{ APIRef("DOM4") }}

+ +

Navigator 介面標示了用戶代理(user agent)的狀態與身份。它允許腳本查詢與註冊,以進行一些活動。

+ +

Navigator 可以被檢索,只要使用唯讀的 {{domxref("window.navigator")}} 屬性。

+ +

屬性

+ +

它並不繼承任何屬性,但其實做已被定義於 {{domxref("NavigatorID")}}、{{domxref("NavigatorLanguage")}}、{{domxref("NavigatorOnLine")}}、{{domxref("NavigatorContentUtils")}}、{{domxref("NavigatorStorage")}}、{{domxref("NavigatorStorageUtils")}}、{{domxref("NavigatorConcurrentHardware")}}、{{domxref("NavigatorPlugins")}}、{{domxref("NavigatorUserMedia")}}.

+ +

標準

+ +
+
{{domxref("Navigator.activeVRDisplays")}} {{readonlyInline}}{{experimental_inline}}
+
Returns an array containing every {{domxref("VRDisplay")}} object that is currently presenting ({{domxref("VRDisplay.ispresenting")}} is true).
+
{{domxref("NavigatorID.appCodeName")}} {{readonlyInline}}{{experimental_inline}}
+
Returns the internal "code" name of the current browser. Do not rely on this property to return the correct value.
+
{{domxref("NavigatorID.appName")}} {{readonlyInline}}{{experimental_inline}}
+
Returns a {{domxref("DOMString")}} with the official name of the browser. Do not rely on this property to return the correct value.
+
{{domxref("NavigatorID.appVersion")}} {{readonlyInline}}{{experimental_inline}}
+
Returns the version of the browser as a {{domxref("DOMString")}}. Do not rely on this property to return the correct value.
+
{{domxref("Navigator.battery")}} {{readonlyInline}}
+
Returns a {{domxref("BatteryManager")}} object you can use to get information about the battery charging status.
+
{{domxref("Navigator.connection")}} {{readonlyInline}}{{experimental_inline}}
+
Provides a {{domxref("NetworkInformation")}} object containing information about the network connection of a device.
+
{{domxref("Navigator.cookieEnabled")}} {{readonlyinline}}
+
Returns false if setting a cookie will be ignored and true otherwise.
+
{{domxref("Navigator.geolocation")}} {{readonlyInline}}
+
Returns a {{domxref("Geolocation")}} object allowing accessing the location of the device.
+
{{domxref("NavigatorConcurrentHardware.hardwareConcurrency")}} {{readOnlyInline}}
+
Returns the number of logical processor cores available.
+
{{domxref("NavigatorPlugins.javaEnabled")}} {{readonlyInline}}{{experimental_inline}}
+
Returns a {{domxref("Boolean")}} flag indicating whether the host browser is Java-enabled or not.
+
{{domxref("NavigatorLanguage.language")}} {{readonlyInline}}
+
Returns a {{domxref("DOMString")}} representing the preferred language of the user, usually the language of the browser UI. The null value is returned when this is unknown.
+
{{domxref("NavigatorLanguage.languages")}} {{readonlyInline}}
+
Returns an array of {{domxref("DOMString")}} representing the languages known to the user, by order of preference.
+
{{domxref("NavigatorPlugins.mimeTypes")}} {{readonlyInline}}{{experimental_inline}}
+
Returns an {{domxref("MimeTypeArray")}} listing the MIME types supported by the browser.
+
{{domxref("NavigatorOnLine.onLine")}} {{readonlyInline}}
+
Returns a {{domxref("Boolean")}} indicating whether the browser is working online.
+
{{domxref("Navigator.oscpu")}}
+
Returns a string that represents the current operating system.
+
{{domxref("Navigator.permissions")}} {{readonlyinline}}{{experimental_inline}}
+
Returns a {{domxref("Permissions")}} object that can be used to query and update permission status of APIs covered by the Permissions API.
+
{{domxref("NavigatorID.platform")}} {{readonlyInline}}{{experimental_inline}}
+
Returns a string representing the platform of the browser. Do not rely on this function to return a significant value.
+
{{domxref("NavigatorPlugins.plugins")}} {{readonlyInline}}{{experimental_inline}}
+
Returns a {{domxref("PluginArray")}} listing the plugins installed in the browser.
+
{{domxref("NavigatorID.product")}} {{readonlyInline}} {{experimental_inline}}
+
Always returns 'Gecko', on any browser. This property is kept only for compatibility purpose.
+
{{domxref("Navigator.serviceWorker")}} {{readonlyInline}}
+
Returns a {{domxref("ServiceWorkerContainer")}} object, which provides access to registration, removal, upgrade, and communication with the {{domxref("ServiceWorker")}} objects for the associated document.
+
{{domxref("Navigator.storage")}} {{readonlyinline}}
+
Returns the singleton {{domxref('StorageManager')}} object used for managing persistance permissions and estimating available storage on a site-by-site/app-by-app basis.
+
{{domxref("NavigatorID.userAgent")}} {{readonlyInline}}
+
Returns the user agent string for the current browser.
+
+ +

Non-standard

+ +
+

Firefox OS devices adds more non-standard properties. You can consult them on the Firefox OS Navigator extensions article.

+
+ +
+
{{domxref("Navigator.buildID")}} {{non-standard_inline}}
+
Returns the build identifier of the browser (e.g., "2006090803").
+
{{domxref("Navigator.cookieEnabled")}} {{non-standard_inline}}
+
Returns a boolean indicating whether cookies are enabled in the browser or not.
+
{{domxref("Navigator.credentials")}} {{non-standard_inline}}
+
Returns the {{domxref("CredentialsContainer")}} interface which exposes methods to request credentials and notify the user agent when interesting events occur such as successful sign in or sign out. 
+
{{domxref("Navigator.doNotTrack")}} {{non-standard_inline}}
+
Reports the value of the user's do-not-track preference. When this value is "yes", your web site or application should not track the user.
+
{{domxref("Navigator.id")}} {{non-standard_inline}}
+
Returns the {{domxref("window.navigator.id", "id")}} object which you can use to add support for BrowserID to your web site.
+
{{domxref("Navigator.mediaDevices")}} {{non-standard_inline}}
+
Returns a reference to a {{domxref("MediaDevices")}} object which can then be used to get information about available media devices ({{domxref("MediaDevices.enumerateDevices()")}}), find out what constrainable properties are supported for media on the user's computer and user agent ({{domxref("MediaDevices.getSupportedConstraints()")}}), and to request access to media using {{domxref("MediaDevices.getUserMedia()")}}.
+
{{domxref("Navigator.mozNotification")}} {{deprecated_inline("22")}} {{non-standard_inline}}
+ {{domxref("Navigator.webkitNotification")}}
+
Returns a {{domxref("navigator.mozNotification", "notification")}} object you can use to deliver notifications to the user from your web application.
+
{{domxref("Navigator.mozSocial")}} {{non-standard_inline}}
+
The Object, returned by the navigator.mozSocial property, is available within the social media provider's panel to provide functionality it may need.
+
{{domxref("Navigator.presentation")}} {{non-standard_inline}}
+
Returns a reference to the {{domxref("Presentation")}} API.
+
{{domxref("Navigator.productSub")}} {{non-standard_inline}}
+
Returns the build number of the current browser (e.g., "20060909").
+
{{domxref("Navigator.securitypolicy")}} {{non-standard_inline}}
+
Returns an empty string. In Netscape 4.7x, returns "US & CA domestic policy" or "Export policy".
+
{{domxref("Navigator.standalone")}} {{non-standard_inline}}
+
Returns a boolean indicating whether the browser is running in standalone mode. Available on Apple's iOS Safari only.
+
{{domxref("Navigator.storageQuota")}} {{readonlyinline}} {{experimental_inline}}
+
Returns a {{domxref('StorageQuota')}} interface which provides means to query and request storage usage and quota information.
+
{{domxref("Navigator.vendor")}} {{non-standard_inline}}
+
Returns the vendor name of the current browser (e.g., "Netscape6").
+
{{domxref("Navigator.vendorSub")}} {{non-standard_inline}}
+
Returns the vendor version number (e.g. "6.1").
+
{{domxref("Navigator.webkitPointer")}} {{non-standard_inline}}
+
Returns a PointerLock object for the Mouse Lock API.
+
+ +

方法

+ +

Doesn't inherit any method, but implements those defined in {{domxref("NavigatorID")}}, {{domxref("NavigatorContentUtils")}}, {{domxref("NavigatorUserMedia")}}, and {{domxref("NavigatorStorageUtils")}}.

+ +

Standard

+ +
+
{{domxref("Navigator.getVRDisplays()")}} {{experimental_inline}}
+
Returns a promise that resolves to an array of {{domxref("VRDisplay")}} objects representing any available VR devices connected to the computer.
+
{{domxref("Navigator.getUserMedia", "Navigator.getUserMedia()")}} {{experimental_inline}}
+
After having prompted the user for permission, returns the audio or video stream associated to a camera or microphone on the local computer.
+
{{domxref("Navigator.registerContentHandler()")}}
+
Allows web sites to register themselves as a possible handler for a given MIME type.
+
{{domxref("Navigator.registerProtocolHandler()")}}
+
Allows web sites to register themselves as a possible handler for a given protocol.
+
{{domxref("Navigator.requestMediaKeySystemAccess()")}} {{experimental_inline}}
+
Returns a {{jsxref("Promise")}} for a MediaKeySystemAccess object.
+
{{domxref("Navigator.sendBeacon()")}}{{experimental_inline}}
+
Used to asynchronously transfer a small amount of data using {{Glossary("HTTP")}} from the User Agent to a web server.
+
{{domxref("Navigator.share()")}}{{experimental_inline}}
+
Invokes the native sharing mechanism of the current platform.
+
{{domxref("NavigatorID.taintEnabled()")}} {{deprecated_inline("1.7.8")}} {{obsolete_inline("9.0")}} {{experimental_inline}}
+
Returns false. JavaScript taint/untaint functions removed in JavaScript 1.2.
+
{{domxref("Navigator.vibrate()")}} {{gecko_minversion_inline("11.0")}}
+
Causes vibration on devices with support for it. Does nothing if vibration support isn't available.
+
+ +

Non-standard

+ +
+

Firefox OS devices adds more non-standard methods. You can consult them on the Firefox OS Navigator extensions article.

+
+ +

{{domxref("Navigator.mozIsLocallyAvailable()")}} {{non-standard_inline}}

+ +
+
Lets code check to see if the document at a given URI is available without using the network.
+
{{domxref("Navigator.mozPay()")}} {{non-standard_inline}}
+
Allows in-app payment.
+
diff --git a/files/zh-tw/web/api/navigator/registerprotocolhandler/index.html b/files/zh-tw/web/api/navigator/registerprotocolhandler/index.html new file mode 100644 index 0000000000..2ffd20da9d --- /dev/null +++ b/files/zh-tw/web/api/navigator/registerprotocolhandler/index.html @@ -0,0 +1,170 @@ +--- +title: Navigator.registerProtocolHandler() +slug: Web/API/Navigator/registerProtocolHandler +translation_of: Web/API/Navigator/registerProtocolHandler +--- +
{{APIRef("HTML DOM")}}
+ +

In progress. Allows web sites to register themselves as possible handlers for particular protocols.

+ +

For security reasons, by default, web sites may only register protocol handlers for themselves — the domain and protocol of the handler must match the current site. However, users may set a preference in Firefox to allow cross website installation, by setting the gecko.handlerService.allowRegisterFromDifferentHost pref to true in about:config.

+ +

Extensions can register protocol handlers targeting other sites: see the 'See Also' section for how to use them from XPCOM.

+ +

Syntax

+ +
window.navigator.registerProtocolHandler(protocol, url, title);
+
+ +

Parameters

+ +
+
protocol
+
The protocol the site wishes to handle, specified as a string. For example, you can register to handle SMS text message links by registering to handle the "sms" scheme.
+
url
+
The URL of the handler, as a string. This string should include "%s" as a placeholder which will be replaced with the escaped URL of the document to be handled. This URL might be a true URL, or it could be a phone number, email address, or so forth. +
The handler's URL must use one of "http" or "https" as its scheme.
+
+
title
+
A user-readable title string for the protocol handler. This will be displayed to the user in interface objects as needed.
+
+ +

Exceptions

+ +
+
SecurityError
+
The user agent blocked registration of the protocol handler. This might happen if an invalid scheme is specified, such as "http", which cannot be registered for obvious security reasons.
+
SyntaxError
+
The "%s" string is missing from the specified protocol handler URL.
+
+ +

Permitted schemes

+ +

For security reasons, registerProtocolHandler() has restrictions on which schemes may be registered. A custom scheme may be registered as long as the scheme's name begins with "web+", is at least five characters long (including the "web+" prefix), and has only lower-case ASCII letters in its name. For example, "web+burger", as shown in the {{anch("Example")}} below.

+ +

Otherwise, the scheme must be one of the schemes on the whitelist below:

+ +
+ +
+ +

Example

+ +

If your web application is located at http://www.google.co.uk, you can register a protocol handler for it to handle "web+burger" links like this:

+ +
navigator.registerProtocolHandler("web+burger",
+                                  "https://www.google.co.uk/?uri=%s",
+                                  "Burger handler");
+
+ +

This creates a handler that allows web+burger:// links to direct the user to your web application, inserting the burger information specified in the link into the URL. Recall that this script must be run from the same domain (so any page location at google.co.uk) and the second argument passed must be of http or https scheme (in this example it is https) .

+ +

The user will be notified that your code has asked to register the protocol handler, so that they can decide whether or not to permit it. See the screenshot below for an example.

+ +

+ +
+

"Register a webmail service as mailto handler" shows how to do this from XPCOM scope.

+
+ +

Specifications

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', 'webappapis.html#dom-navigator-registerprotocolhandler', 'registerProtocolHandler()')}}{{Spec2('HTML WHATWG')}}Initial definition
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support13[1]{{CompatGeckoDesktop("1.9")}}{{CompatUnknown}}11.60{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatGeckoMobile("3.5")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Protocol whitelist includes mailto, mms, nntp, rtsp, and webcal. Custom protocols must be prefixed with web+.

+ +

See also

+ + diff --git a/files/zh-tw/web/api/navigator/registerprotocolhandler/web-based_protocol_handlers/index.html b/files/zh-tw/web/api/navigator/registerprotocolhandler/web-based_protocol_handlers/index.html new file mode 100644 index 0000000000..f32ac8ca88 --- /dev/null +++ b/files/zh-tw/web/api/navigator/registerprotocolhandler/web-based_protocol_handlers/index.html @@ -0,0 +1,28 @@ +--- +title: Firefox 3 Web-based protocol handler +slug: Web/API/Navigator/registerProtocolHandler/Web-based_protocol_handlers +translation_of: Web/API/Navigator/registerProtocolHandler/Web-based_protocol_handlers +--- +

摘要

+

window.navigator.registerProtocolHandler 讓網站可以將自己註冊為特定通訊協定的處理者。

+

語法

+
window.navigator.registerProtocolHandler(protocol, uri, title);
+ +

例子

+
navigator.registerProtocolHandler("mailto",
+                                 "https://mail.google.com/mail?view=cm&tf=0&to=%s",
+                                 "Google Mail");
+
+

這會建立一個 handler,它允許 mailto 的鏈結將使用者帶到 Google Mail,將鏈結中指定的 email 位址插入到 URL。

+

參考資料

+
    +
  1. DOM:window.navigator.registerProtocolHandler 原始網頁
  2. +
+

延伸閱讀

+
    +
  1. WHATWG's Web Applications 1.0 working draft
  2. +
diff --git a/files/zh-tw/web/api/navigatoronline/index.html b/files/zh-tw/web/api/navigatoronline/index.html new file mode 100644 index 0000000000..6e6eafaa48 --- /dev/null +++ b/files/zh-tw/web/api/navigatoronline/index.html @@ -0,0 +1,129 @@ +--- +title: NavigatorOnLine +slug: Web/API/NavigatorOnLine +translation_of: Web/API/NavigatorOnLine +--- +

{{APIRef("HTML DOM")}}

+ +

In progress The NavigatorOnLine interface contains methods and properties related to the connectivity status of the browser.

+ +

There is no object of type NavigatorOnLine, but other interfaces, like {{domxref("Navigator")}} or {{domxref("WorkerNavigator")}}, implement it.

+ +

Properties

+ +

The NavigatorOnLine interface doesn't inherit any property.

+ +
+
{{domxref("NavigatorOnLine.onLine")}} {{readonlyInline}}
+
Returns a {{domxref("Boolean")}} indicating whether the browser is working online.
+
+ +

Methods

+ +

The NavigatorOnLine interface neither implements, nor inherit any method.

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#navigatoronline', 'NavigatorOnLine')}}{{Spec2('HTML WHATWG')}}No change from the latest snapshot, {{SpecName('HTML5 W3C')}}
{{SpecName('HTML5 W3C', '#navigatoronline', 'NavigatorOnLine')}}{{Spec2('HTML5 W3C')}}Snapshot of {{SpecName('HTML WHATWG')}} with its initial specification.
+ +

Browser compatibility

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
on {{domxref("WorkerNavigator")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoDesktop(29)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
on {{domxref("WorkerNavigator")}}{{CompatUnknown}}{{CompatGeckoMobile(29)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

See also

+ + diff --git a/files/zh-tw/web/api/navigatoronline/online_and_offline_events/index.html b/files/zh-tw/web/api/navigatoronline/online_and_offline_events/index.html new file mode 100644 index 0000000000..c8bf629d8c --- /dev/null +++ b/files/zh-tw/web/api/navigatoronline/online_and_offline_events/index.html @@ -0,0 +1,101 @@ +--- +title: Firefox 3 Online and Offline Events +slug: Web/API/NavigatorOnLine/Online_and_offline_events +translation_of: Web/API/NavigatorOnLine/Online_and_offline_events +--- +

Firefox 3 Online and Offline Events From MoztwWiki

+

Firefox 3 依據 WHATWG Web Applications 1.0 Specification 實做了 Offline/Online Events

+

概觀

+

打造可以離線跑的網路應用程式時,我們往往需要讓程式知道目前的網路狀況。實際上,網路應用程式一般的需求可細分如下:

+ +

有了 Online/offline events,要滿足這些需求變得很簡單。

+

此外,你的網路應用程式有時可能必須將某些 HTML 文件列入快取中,以便使用者離線時可以存取,如有這個需求,你可以在 HTML 文件的 <HEAD> 加入 <link> 元素:

+
<link rel="offline-resource" href="myresource">
+

Firefox 3 看到這些語法時,就會將這些資源列入一個特殊的離線資源快取(offline resource cache)中,讓使用者在離線時,依舊可以被存取這些資源。

+

API

+ +
+
+ avigator.onLine 是一個 property,其值可為 true/false (true 代表 online, false 代表 offline)。當使用者將瀏覽器切換成 Offline Mode 時(透過 主選單 -> 檔案 -> 離線模式),這個 property 就會被更新。
+
+
+
+ 除此之外,根據規格書的建議,在瀏覽器無法連接到網路時,也應該更新這個 property。規格書上是這樣寫的:
+
+
+ The navigator.onLine attribute must return false if the user agent will not contact the network when the user follows links or when a script requests a remote page (or knows that such an attempt would fail)...
+
+
+
+
+ Firefox 2 在我們將瀏覽器切換成為離線模式、或離開離線模式時,會更新這個 property,在失去網路連線、或重新連線到網路時,也會更新這個 property。
+
+
+
+ 在比較老的 Firefox 與 Internet Explorer 版本,也有支援這個 property (事實上,規格書是依據這些之前版本的實做結果來制定的),所以現在就可以馬上開始使用它。
+
+
+
+ 但「自動偵測網路狀況」是在 Firefox 2 中才實做出來。
+
+

online and offline events

+
+
+ Firefox 3 新增了兩個 events 的支援: "online" 及 "offline"。當我們切換瀏覽器的 online/offline 狀態時,就會對每個頁面的 <body> 觸發這兩個事件。除此之外,這兩個事件會從 document.body bubble up 到 document,到 window 才結束。這兩個事件都是 non-cancellable 的(因為你無法防止使用者連線到網路、或離線)。
+
+
+
+ 有好幾種你熟悉的方式可以用來註冊這兩個事件的 listeners:
+
+
+
+
    +
  • 對 window, document 或 document.body 使用 addEventListener。
  • +
  • 對 document 或 document.body 設定 .ononline 或 .onoffline properties 作為一個 JavaScript Function object. (注意: 使用 window.ononline 或 window.onoffline 無法作用,這是為了相容性。)
  • +
  • 在 html 文件的 <body> 指定 ononline="..." 或 onoffline="..." attributes。
  • +
+
+
+

例子

+

這裡有個簡單的例子

+
<!doctype html>
+ <html>
+ <head>
+   <script>
+     function updateOnlineStatus(msg) {
+       var status = document.getElementById("status");
+       var condition = navigator.onLine ? "ONLINE" : "OFFLINE";
+       status.setAttribute("class", condition);
+       var state = document.getElementById("state");
+       state.innerHTML = condition;
+       var log = document.getElementById("log");
+       log.appendChild(document.createTextNode("Event: " + msg + "; status=" + condition + "\n"));
+     }
+     function loaded() {
+       updateOnlineStatus("load");
+       document.body.addEventListener("offline", function () {
+         updateOnlineStatus("offline")
+       }, false);
+       document.body.addEventListener("online", function () {
+         updateOnlineStatus("online")
+       }, false);
+     }
+   </script>
+   <style>...</style>
+ </head>
+ <body onload="loaded()">
+   <div id="status"><p id="state"></p></div>
+   <div id="log"></div>
+ </body>
+ </html>
+

參考資料

+ diff --git a/files/zh-tw/web/api/network_information_api/index.html b/files/zh-tw/web/api/network_information_api/index.html new file mode 100644 index 0000000000..c7f24856a4 --- /dev/null +++ b/files/zh-tw/web/api/network_information_api/index.html @@ -0,0 +1,46 @@ +--- +title: Network Information API +slug: Web/API/Network_Information_API +translation_of: Web/API/Network_Information_API +--- +

{{ SeeCompatTable() }}

+

Network Information API 將提供系統連線的相關資訊,如使用者裝置的現有頻寬,或目前的連線狀態。根據使用者的連線情形,可進一步選擇高解析度或低解析度的內容。此完整的 API 另包含 domxref("Connection") 介面,以及 Navigator 介面的單一屬性 ─ Navigator.connection

+

偵測連線變化

+

此範例將觀察使用者連線的變化。舉例來說,當使用者從高價位連線轉用低價位連線時,就會降低頻寬需求以避免連線費用暴增,並採用類似 Apps 受到警示的方法。

+
var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
+
+function updateConnectionStatus() {
+  alert("Connection bandwidth: " + connection.bandwidth + " MB/s");
+  if (connection.metered) {
+    alert("The connection is metered!");
+  }
+}
+
+connection.addEventListener("change", updateConnectionStatus);
+updateConnectionStatus();
+
+

規格

+ + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('Network Information', '', 'Network Information API') }}{{ Spec2('Network Information') }}Initial specification
+

瀏覽器相容性

+

{{Page('/en-US/docs/Web/API/window.navigator.connection','Browser compatibility')}}

+

See also

+ diff --git a/files/zh-tw/web/api/node/childnodes/index.html b/files/zh-tw/web/api/node/childnodes/index.html new file mode 100644 index 0000000000..a828bd781b --- /dev/null +++ b/files/zh-tw/web/api/node/childnodes/index.html @@ -0,0 +1,66 @@ +--- +title: Node.childNodes +slug: Web/API/Node/childNodes +translation_of: Web/API/Node/childNodes +--- +
+
{{APIRef("DOM")}}
+
+ +

Node.childNodes 唯讀屬性會回傳一個即時更新的動態集合(live collection),其包含了指定元素的子{{domxref("Node","節點")}},而第一個子節點會被指派為索引 0。

+ +

語法

+ +
var ndList = elementNodeReference.childNodes;
+
+ +

ndList 是一個 {{domxref("NodeList")}},為一個有順序性、由目前元素之 DOM 子節點組成之集合。假如目前元素沒有子節點,則 ndList 會是空的。

+ +

範例

+ +
// parg is an object reference to a <p> element
+
+// First check that the element has child nodes
+if (parg.hasChildNodes()) {
+  var children = parg.childNodes;
+
+  for (var i = 0; i < children.length; i++) {
+    // do something with each child as children[i]
+    // NOTE: List is live, adding or removing children will change the list
+  }
+}
+ +
+
// This is one way to remove all children from a node
+// box is an object reference to an element
+
+while (box.firstChild) {
+    //The list is LIVE so it will re-index each call
+    box.removeChild(box.firstChild);
+}
+ +

備註

+ +

The items in the collection of nodes are objects and not strings. To get data from node objects, use their properties (e.g. elementNodeReference.childNodes[1].nodeName to get the name, etc.).

+ +

The document object itself has 2 children: the Doctype declaration and the root element, typically referred to as documentElement. (In (X)HTML documents this is the HTML element.)

+ +

childNodes includes all child nodes, including non-element nodes like text and comment nodes. To get a collection of only elements, use {{ domxref("ParentNode.children") }} instead.

+ +

規範

+ + + +

參見

+ + diff --git a/files/zh-tw/web/api/node/clonenode/index.html b/files/zh-tw/web/api/node/clonenode/index.html new file mode 100644 index 0000000000..2bd1998650 --- /dev/null +++ b/files/zh-tw/web/api/node/clonenode/index.html @@ -0,0 +1,160 @@ +--- +title: Node.cloneNode() +slug: Web/API/Node/cloneNode +translation_of: Web/API/Node/cloneNode +--- +
{{APIRef("DOM")}}
+ +

Node.cloneNode() 方法會回傳一個呼叫此方法之節點物件的拷貝。

+ +

語法

+ +
var dupNode = node.cloneNode(deep);
+
+ +
+
node
+
The node to be cloned.
+
dupNode
+
The new node that will be a clone of node
+
deep {{optional_inline}}
+
true if the children of the node should also be cloned, or false to clone only the specified node.
+
+ +
+

Note: In the DOM4 specification (as implemented in Gecko 13.0 {{geckoRelease(13)}}), deep is an optional argument. If omitted, the method acts as if the value of deep was true, defaulting to using deep cloning as the default behavior. To create a shallow clone, deep must be set to false.

+ +

This behavior has been changed in the latest spec, and if omitted, the method will act as if the value of deep was false. Though It's still optional, you should always provide the deep argument both for backward and forward compatibility. With Gecko 28.0 {{geckoRelease(28)}}), the console warned developers not to omit the argument. Starting with Gecko 29.0 {{geckoRelease(29)}}), a shallow clone is defaulted instead of a deep clone.

+
+ +

範例

+ +
var p = document.getElementById("para1");
+var p_prime = p.cloneNode(true);
+
+ +

備註

+ +

Cloning a node copies all of its attributes and their values, including intrinsic (in–line) listeners. It does not copy event listeners added using addEventListener() or those assigned to element properties. (e.g. node.onclick = fn) Moreover, for a <canvas> element, the painted image is not copied.

+ +

The duplicate node returned by cloneNode() is not part of the document until it is added to another node that is part of the document using {{domxref("Node.appendChild()")}} or a similar method. It also has no parent until it is appended to another node.

+ +

If deep is set to false, child nodes are not cloned. Any text that the node contains is not cloned either, as it is contained in one or more child {{domxref("Text")}} nodes.

+ +

If deep evaluates to true, the whole subtree (including text that may be in child {{domxref("Text")}} nodes) is copied too. For empty nodes (e.g. {{HTMLElement("img")}} and {{HTMLElement("input")}} elements) it doesn't matter whether deep is set to true or false.

+ +
Warning: cloneNode() may lead to duplicate element IDs in a document.
+ +

If the original node has an ID and the clone is to be placed in the same document, the ID of the clone should be modified to be unique. Name attributes may need to be modified also, depending on whether duplicate names are expected.

+ +

To clone a node for appending to a different document, use {{domxref("Document.importNode()")}} instead.

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("DOM WHATWG", "#dom-node-clonenode", "Node.cloneNode()")}}{{Spec2("DOM WHATWG")}} 
{{SpecName("DOM3 Core", "core.html#ID-3A0ED0A4", "Node.cloneNode()")}}{{Spec2("DOM3 Core")}} 
{{SpecName("DOM2 Core", "core.html#ID-3A0ED0A4", "Node.cloneNode()")}}{{Spec2("DOM2 Core")}}Initial definition
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
deep as an optional parameter +

{{CompatVersionUnknown}}[1]

+
{{CompatUnknown}}{{CompatGeckoDesktop("13.0")}}{{CompatVersionUnknown}}{{CompatUnknown}} +

{{CompatVersionUnknown}}[1]

+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
deep as an optional parameter{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("13.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Default value for the deep parameter is false.

diff --git a/files/zh-tw/web/api/node/index.html b/files/zh-tw/web/api/node/index.html new file mode 100644 index 0000000000..fc04145fce --- /dev/null +++ b/files/zh-tw/web/api/node/index.html @@ -0,0 +1,529 @@ +--- +title: Node +slug: Web/API/Node +tags: + - API + - DOM + - DOM Reference + - Interface + - NeedsTranslation + - Node + - Reference + - TopicStub +translation_of: Web/API/Node +--- +
{{APIRef("DOM")}}
+ +

Node 是一個被多種 DOM 類型繼承的介面,它讓各種類型的 DOM 都能以同樣的方式來操作。如繼承了相同的方法,或能以相同的方式測試。

+ +

Node 繼承自 {{domxref("EventTarget")}},而繼承了 Node 的屬性及方法的介面則有:{{domxref("Document")}}、{{domxref("Element")}}、{{domxref("CharacterData")}}(被 {{domxref("Text")}}、{{domxref("Comment")}} 以及 {{domxref("CDATASection")}} 所繼承)、{{domxref("ProcessingInstruction")}}、{{domxref("DocumentFragment")}}、{{domxref("DocumentType")}}、{{domxref("Notation")}}、{{domxref("Entity")}}、{{domxref("EntityReference")}}。

+ +

These interfaces may return null in particular cases where the methods and properties are not relevant. They may throw an exception - for example when adding children to a node type for which no children can exist.

+ +

{{InheritanceDiagram}}

+ +

屬性

+ +

Inherits properties from its parents {{domxref("EventTarget")}}.[1]

+ +
+
{{domxref("Node.baseURI")}} {{readonlyInline}}
+
Returns a {{domxref("DOMString")}} representing the base URL. The concept of base URL changes from one language to another; in HTML, it corresponds to the protocol, the domain name and the directory structure, that is all until the last '/'.
+
{{domxref("Node.baseURIObject")}} {{Non-standard_inline()}} {{ Fx_minversion_inline("3") }}
+
(Not available to web content.) The read-only {{ Interface("nsIURI") }} object representing the base URI for the element.
+
{{domxref("Node.childNodes")}} {{readonlyInline}}
+
Returns a live {{domxref("NodeList")}} containing all the children of this node. {{domxref("NodeList")}} being live means that if the children of the Node change, the {{domxref("NodeList")}} object is automatically updated.
+
{{domxref("Node.firstChild")}} {{readonlyInline}}
+
Returns a {{domxref("Node")}} representing the first direct child node of the node, or null if the node has no child.
+
{{domxref("Node.lastChild")}} {{readonlyInline}}
+
Returns a {{domxref("Node")}} representing the last direct child node of the node, or null if the node has no child.
+
{{domxref("Node.nextSibling")}} {{readonlyInline}}
+
Returns a {{domxref("Node")}} representing the next node in the tree, or null if there isn't such node.
+
{{domxref("Node.nodeName")}} {{readonlyInline}}
+
Returns a {{domxref("DOMString")}} containing the name of the Node. The structure of the name will differ with the node type. E.g. An {{domxref("HTMLElement")}} will contain the name of the corresponding tag, like 'audio' for an {{domxref("HTMLAudioElement")}}, a {{domxref("Text")}} node will have the '#text' string, or a {{domxref("Document")}} node will have the '#document' string.
+
{{domxref("Node.nodePrincipal")}} {{Non-standard_inline()}}{{ Fx_minversion_inline("3") }}
+
A {{ Interface("nsIPrincipal") }} representing the node principal.
+
{{domxref("Node.nodeType")}}{{readonlyInline}}
+
Returns an unsigned short representing the type of the node. Possible values are: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameValue
ELEMENT_NODE1
ATTRIBUTE_NODE {{deprecated_inline()}}2
TEXT_NODE3
CDATA_SECTION_NODE {{deprecated_inline()}}4
ENTITY_REFERENCE_NODE {{deprecated_inline()}}5
ENTITY_NODE {{deprecated_inline()}}6
PROCESSING_INSTRUCTION_NODE7
COMMENT_NODE8
DOCUMENT_NODE9
DOCUMENT_TYPE_NODE10
DOCUMENT_FRAGMENT_NODE11
NOTATION_NODE {{deprecated_inline()}}12
+
+
{{domxref("Node.nodeValue")}}
+
Returns / Sets the value of the current node
+
{{domxref("Node.ownerDocument")}} {{readonlyInline}}
+
Returns the {{domxref("Document")}} that this node belongs to. If no document is associated with it, returns null.
+
{{domxref("Node.parentNode")}} {{readonlyInline}}
+
Returns a {{domxref("Node")}} that is the parent of this node. If there is no such node, like if this node is the top of the tree or if doesn't participate in a tree, this property returns null.
+
{{domxref("Node.parentElement")}} {{readonlyInline}}
+
Returns an {{domxref("Element")}} that is the parent of this node. If the node has no parent, or if that parent is not an {{domxref("Element")}}, this property returns null.
+
{{domxref("Node.previousSibling")}} {{readonlyInline}}
+
Returns a {{domxref("Node")}} representing the previous node in the tree, or null if there isn't such node.
+
{{domxref("Node.textContent")}}
+
Returns / Sets the textual content of an element and all its descendants.
+
+ +

Deprecated properties

+ +
+
{{domxref("Node.rootNode")}} {{readOnlyInline}} {{deprecated_inline}}
+
Returns a {{domxref("Node")}} object representing the topmost node in the tree, or the current node if it's the topmost node in the tree. This has been replaced by {{domxref("Node.getRootNode()")}}.
+
+ +

Obsolete properties

+ +
+
{{domxref("Node.localName")}} {{obsolete_inline}}{{readonlyInline}}
+
Returns a {{domxref("DOMString")}} representing the local part of the qualified name of an element. +
+

Note: In Firefox 3.5 and earlier, the property upper-cases the local name for HTML elements (but not XHTML elements). In later versions, this does not happen, so the property is in lower case for both HTML and XHTML. {{gecko_minversion_inline("1.9.2")}}

+
+
+
{{domxref("Node.namespaceURI")}} {{obsolete_inline}}{{readonlyInline}}
+
The namespace URI of this node, or null if it is no namespace. +
+

Note: In Firefox 3.5 and earlier, HTML elements are in no namespace. In later versions, HTML elements are in the https://www.w3.org/1999/xhtml/ namespace in both HTML and XML trees. {{gecko_minversion_inline("1.9.2")}}

+
+
+
{{domxref("Node.prefix")}} {{obsolete_inline}}{{readonlyInline}}
+
Is a {{domxref("DOMString")}} representing the namespace prefix of the node, or null if no prefix is specified.
+
+ +

方法

+ +

Inherits methods from its parent, {{domxref("EventTarget")}}.[1]

+ +
+
{{domxref("Node.appendChild()")}}
+
Adds the specified childNode argument as the last child to the current node.
+ If the argument referenced an existing node on the DOM tree, the node will be detached from its current position and attached at the new position.
+
{{domxref("Node.cloneNode()")}}
+
Clone a {{domxref("Node")}}, and optionally, all of its contents. By default, it clones the content of the node.
+
{{domxref("Node.compareDocumentPosition()")}}
+
Compares the position of the current node against another node in any other document.
+
{{domxref("Node.contains()")}}
+
Returns a {{jsxref("Boolean")}} value indicating whether a node is a descendant of a given node or not.
+
{{domxref("Node.getRootNode()")}}
+
Returns the context object's root which optionally includes the shadow root if it is available.
+
{{domxref("Node.hasChildNodes()")}}
+
Returns a {{jsxref("Boolean")}} indicating if the element has any child nodes, or not.
+
{{domxref("Node.insertBefore()")}}
+
Inserts a {{domxref("Node")}} before the reference node as a child of the current node.
+
{{domxref("Node.isDefaultNamespace()")}}
+
Accepts a namespace URI as an argument and returns a {{jsxref("Boolean")}} with a value of true if the namespace is the default namespace on the given node or false if not.
+
{{domxref("Node.isEqualNode()")}}
+
Returns a {{jsxref("Boolean")}} which indicates whether or not two nodes are of the same type and all their defining data points match.
+
{{domxref("Node.isSameNode()")}}
+
Returns a {{jsxref("Boolean")}} value indicating whether or not the two nodes are the same (that is, they reference the same object).
+
{{domxref("Node.lookupPrefix()")}}
+
Returns a {{domxref("DOMString")}} containing the prefix for a given namespace URI, if present, and null if not. When multiple prefixes are possible, the result is implementation-dependent.
+
{{domxref("Node.lookupNamespaceURI()")}}
+
Accepts a prefix and returns the namespace URI associated with it on the given node if found (and null if not). Supplying null for the prefix will return the default namespace.
+
{{domxref("Node.normalize()")}}
+
Clean up all the text nodes under this element (merge adjacent, remove empty).
+
{{domxref("Node.removeChild()")}}
+
Removes a child node from the current element, which must be a child of the current node.
+
{{domxref("Node.replaceChild()")}}
+
Replaces one child {{domxref("Node")}} of the current one with the second one given in parameter.
+
+ +

Obsolete methods

+ +
+
{{domxref("Node.getFeature()")}} {{obsolete_inline}}
+
x
+
{{domxref("Node.getUserData()")}} {{obsolete_inline}}
+
Allows a user to get some {{domxref("DOMUserData")}} from the node.
+
{{domxref("Node.hasAttributes()")}} {{obsolete_inline}}
+
Returns a {{jsxref("Boolean")}} indicating if the element has any attributes, or not.
+
{{domxref("Node.isSupported()")}} {{obsolete_inline}}
+
Returns a {{jsxref("Boolean")}} flag containing the result of a test whether the DOM implementation implements a specific feature and this feature is supported by the specific node.
+
{{domxref("Node.setUserData()")}} {{obsolete_inline}}
+
Allows a user to attach, or remove, {{domxref("DOMUserData")}} to the node.
+
+ +

範例

+ +

Browse all child nodes

+ +

The following function recursively cycles all child nodes of a node and executes a callback function upon them (and upon the parent node itself).

+ +
function DOMComb (oParent, oCallback) {
+  if (oParent.hasChildNodes()) {
+    for (var oNode = oParent.firstChild; oNode; oNode = oNode.nextSibling) {
+      DOMComb(oNode, oCallback);
+    }
+  }
+  oCallback.call(oParent);
+}
+ +

Syntax

+ +
DOMComb(parentNode, callbackFunction);
+ +

Description

+ +

Recursively cycle all child nodes of parentNode and parentNode itself and execute the callbackFunction upon them as this objects.

+ +

Parameters

+ +
+
parentNode
+
The parent node (Node Object).
+
callbackFunction
+
The callback function (Function).
+
+ +

Sample usage

+ +

The following example send to the console.log the text content of the body:

+ +
function printContent () {
+  if (this.nodeValue) { console.log(this.nodeValue); }
+}
+
+onload = function () {
+  DOMComb(document.body, printContent);
+};
+ +

Remove all children nested within a node

+ +
Element.prototype.removeAll = function () {
+  while (this.firstChild) { this.removeChild(this.firstChild); }
+  return this;
+};
+ +

Sample usage

+ +
/* ... an alternative to document.body.innerHTML = "" ... */
+document.body.removeAll();
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#interface-node', 'Node')}}{{Spec2('DOM WHATWG')}}Removed the following properties: attributes, namespaceURI, prefix, and localName.
+ Removed the following methods: isSupported(), hasAttributes(), getFeature(), setUserData(), and getUserData().
{{SpecName('DOM3 Core', 'core.html#ID-1950641247', 'Node')}}{{Spec2('DOM3 Core')}}The methods insertBefore(), replaceChild(), removeChild(), and appendChild() returns one more kind of error (NOT_SUPPORTED_ERR) if called on a {{domxref("Document")}}.
+ The normalize() method has been modified so that {{domxref("Text")}} node can also be normalized if the proper {{domxref("DOMConfiguration")}} flag is set.
+ Added the following methods: compareDocumentPosition(), isSameNode(), lookupPrefix(), isDefaultNamespace(), lookupNamespaceURI(), isEqualNode(), getFeature(), setUserData(), and getUserData().
+ Added the following properties: baseURI and textContent.
{{SpecName('DOM2 Core', 'core.html#ID-1950641247', 'Node')}}{{Spec2('DOM2 Core')}}The ownerDocument property was slightly modified so that {{domxref("DocumentFragment")}} also returns null.
+ Added the following properties: namespaceURI, prefix, and localName.
+ Added the following methods: normalize(), isSupported() and hasAttributes().
{{SpecName('DOM1', 'level-one-core.html#ID-1950641247', 'Node')}}{{Spec2('DOM1')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}[1]{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.0")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}[1]{{CompatVersionUnknown}}[1]
getFeature(){{obsolete_inline}}{{CompatNo}}{{CompatUnknown}}{{CompatGeckoDesktop("1.0")}}
+ {{CompatNo}}{{CompatGeckoDesktop("7.0")}}
{{CompatUnknown}}{{CompatNo}}{{CompatNo}}
getUserData(), setUserData() and hasAttributes() {{deprecated_inline}}{{CompatNo}}{{CompatUnknown}}{{CompatGeckoDesktop("1.0")}}
+ {{CompatNo}}{{CompatGeckoDesktop("22.0")}}
{{CompatUnknown}}{{CompatNo}}{{CompatNo}}
isSameNode(){{CompatVersionUnknown}}{{CompatUnknown}}{{CompatGeckoDesktop("1.0")}}
+ Removed in {{CompatGeckoDesktop("10")}}
+ Returned in {{CompatGeckoDesktop("48")}}
{{CompatUnknown}}{{CompatNo}}{{CompatNo}}
isSupported() {{obsolete_inline}}{{CompatNo}}{{CompatUnknown}}{{CompatGeckoDesktop("1.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
attributes{{CompatNo}}{{CompatUnknown}}{{CompatGeckoDesktop("1.0")}}
+ {{CompatNo}}{{CompatGeckoDesktop("22.0")}}[2]
{{CompatNo}}{{CompatNo}}{{CompatNo}}
rootNode(){{CompatUnknown}}{{CompatUnknown}}CompatGeckoDesktop(48)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
namespaceURI, localName, prefix {{obsolete_inline}}{{CompatVersionUnknown}}
+ {{CompatNo}}46.0[3]
{{CompatUnknown}}{{CompatVersionUnknown}}
+ {{CompatNo}}48.0[3]
{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
getRootNode(), and rootNode deprecated{{CompatChrome(54.0)}}{{CompatUnknown}}{{CompatGeckoDesktop(53)}}{{CompatUnknown}}{{CompatOpera(41)}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatUnknown}}{{CompatVersionUnknown}}[1]{{CompatVersionUnknown}}{{CompatGeckoMobile("1.0")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}[1]{{CompatVersionUnknown}}[1]{{CompatVersionUnknown}}[1]
getFeature(){{obsolete_inline}}{{CompatNo}}{{CompatNo}}{{CompatUnknown}}{{CompatGeckoMobile("1.0")}}
+ {{CompatNo}}{{CompatGeckoDesktop("7.0")}}
{{CompatUnknown}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
getUserData(), setUserData() and hasAttributes() {{deprecated_inline}}{{CompatNo}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}
isSameNode(){{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}} +

{{CompatGeckoDesktop("1.0")}}
+ Removed in {{CompatGeckoDesktop("10")}}
+ Returned in {{CompatGeckoDesktop("48")}}

+
{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
isSupported() {{obsolete_inline}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}
attributes{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}
rootNode(){{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatGeckoMobile(48)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}
namespaceURI, localName, prefix {{obsolete_inline}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatVersionUnknown}}
+ {{CompatNo}}48.0[3]
{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}
getRootNode(), and rootNode deprecated{{CompatNo}}{{CompatChrome(54.0)}}{{CompatUnknown}}{{CompatGeckoMobile(53)}}{{CompatUnknown}}{{CompatOperaMobile(41)}}{{CompatUnknown}}{{CompatChrome(54.0)}}
+
+ +

[1] WebKit and old versions of Blink incorrectly do not make Node inherit from {{domxref("EventTarget")}}.

+ +

[2] In Gecko 22.0 {{geckoRelease("22.0")}} the attributes property was moved to {{domxref("Element")}}.

+ +

[3] The properties were moved to the {{domxref("Element")}} and {{domxref("Attr")}} APIs according to the DOM4 standard.

diff --git a/files/zh-tw/web/api/node/innertext/index.html b/files/zh-tw/web/api/node/innertext/index.html new file mode 100644 index 0000000000..4c8a4272fc --- /dev/null +++ b/files/zh-tw/web/api/node/innertext/index.html @@ -0,0 +1,86 @@ +--- +title: Node.innerText +slug: Web/API/Node/innerText +translation_of: Web/API/HTMLElement/innerText +--- +
{{APIRef("DOM")}}
+ +

概述

+ +

Node.innerText 是一個代表節點及其後代之「已渲染」(rendered)文字內容的屬性。如同一個存取器,Node.innerText 近似於使用者利用游標選取成高亮後複製至剪貼簿之元素的內容。此功能最初由 Internet Explorer 提供,並在被所有主要瀏覽器採納之後,於 2016 年正式成為 HTML 標準。

+ +

{{domxref("Node.textContent")}} 屬性是一個相似的選擇,但兩者之間仍有非常不同的差異。

+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', 'dom.html#the-innertext-idl-attribute', 'innerText')}}{{Spec2('HTML WHATWG')}}Introduced, based on the draft of the innerText specification. See whatwg/html#465 and whatwg/compat#5 for history.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support4{{ CompatGeckoDesktop(45) }}69.6 (probably earlier)3
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support2.3 (probably earlier){{ CompatGeckoMobile(45) }}10 (probably earlier)124.1 (probably earlier)
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/node/insertbefore/index.html b/files/zh-tw/web/api/node/insertbefore/index.html new file mode 100644 index 0000000000..393cc88d80 --- /dev/null +++ b/files/zh-tw/web/api/node/insertbefore/index.html @@ -0,0 +1,167 @@ +--- +title: Node.insertBefore() +slug: Web/API/Node/insertBefore +translation_of: Web/API/Node/insertBefore +--- +
+
{{APIRef("DOM")}}
+
+ +

Node.insertBefore() 方法將一個節點安插在參考節點之前,作為某個特定父節點之子節點。If the given child is a reference to an existing node in the document, insertBefore() moves it from its current position to the new position (there is no requirement to remove the node from its parent node before appending it to some other node).

+ +

同一個節點並不會同時出現在兩個地方。所以當節點已經有父節點,它會先被移除,然後被插入在新的位置上。The {{domxref("Node.cloneNode()")}} can be used to make a copy of the node before appending it under the new parent. Note that the copies made with cloneNode will not be automatically kept in sync.

+ +

若參考節點為 null, 那需插入的節點就會成為特定父節點的最後一個子節點。

+ +

If the given child is a {{domxref("DocumentFragment")}}, the entire contents of the {{domxref("DocumentFragment")}} are moved into the child list of the specified parent node.

+ +

Syntax

+ +
var insertedNode = parentNode.insertBefore(newNode, referenceNode);
+
+ +

If referenceNode is null, the newNode is inserted at the end of the list of child nodes.

+ +
+

referenceNode 並非可選擇的參數 -- 一定要傳入一個節點或是   null。若是傳入失敗或不正確的參數,可能會依不同的瀏覽器版本而有不同的行為

+
+ +

Returns

+ +

會回傳新加入的子節點。若該值(newNode)是{{domxref("DocumentFragment")}}, 則回傳空的 {{domxref("DocumentFragment")}}。

+ +

Example

+ +
<div id="parentElement">
+   <span id="childElement">foo bar</span>
+</div>
+
+<script>
+// Create the new node to insert
+var newNode = document.createElement("span");
+
+// Get a reference to the parent node
+var parentDiv = document.getElementById("childElement").parentNode;
+
+// Begin test case [ 1 ] : Exist a childElement --> All working correctly
+var sp2 = document.getElementById("childElement");
+parentDiv.insertBefore(newNode, sp2);
+// End test case [ 1 ]
+
+// Begin test case [ 2 ] : childElement is of Type undefined
+var sp2 = undefined; // Not exist a node of id "childElement"
+parentDiv.insertBefore(newNode, sp2); // Implicit dynamic cast to type Node
+// End test case [ 2 ]
+
+// Begin test case [ 3 ] : childElement is of Type "undefined" ( string )
+var sp2 = "undefined"; // Not exist a node of id "childElement"
+parentDiv.insertBefore(newNode, sp2); // Generate "Type Error: Invalid Argument"
+// End test case [ 3 ]
+</script>
+ + + +

Example

+ +
<div id="parentElement">
+  <span id="childElement">foo bar</span>
+</div>
+
+<script>
+// Create a new, plain <span> element
+var sp1 = document.createElement("span");
+
+// Get a reference to the element, before we want to insert the element
+var sp2 = document.getElementById("childElement");
+// Get a reference to the parent element
+var parentDiv = sp2.parentNode;
+
+// Insert the new element into the DOM before sp2
+parentDiv.insertBefore(sp1, sp2);
+</script>
+
+ +

There is no insertAfter method. It can be emulated by combining the insertBefore method with nextSibling.

+ +

In the previous example, sp1 could be inserted after sp2 using:

+ +
parentDiv.insertBefore(sp1, sp2.nextSibling);
+ +

If sp2 does not have a next sibling, then it must be the last child — sp2.nextSibling returns null, and sp1 is inserted at the end of the child node list (immediately after sp2).

+ +

Example

+ +

Insert an element before the first child element, using the firstChild property.

+ +
// Get a reference to the element in which we want to insert a new node
+var parentElement = document.getElementById('parentElement');
+// Get a reference to the first child
+var theFirstChild = parentElement.firstChild;
+
+// Create a new element
+var newElement = document.createElement("div");
+
+// Insert the new element before the first child
+parentElement.insertBefore(newElement, theFirstChild);
+
+ +

When the element does not have a first child, then firstChild is null. The element is still appended to the parent, after the last child. Since the parent element did not have a first child, it did not have a last child either. Consequently, the new element is the only element, after insertion.

+ +

Browser compatibility

+ + + +

{{Compat("api.Node.insertBefore")}}

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG','#dom-node-insertbefore','Node.insertBefore')}}{{Spec2('DOM WHATWG')}}Fixes errors in the insertion algorithm
{{SpecName('DOM4','#dom-node-insertbefore','Node.insertBefore')}}{{Spec2('DOM4')}}Describes the algorithm in more detail
{{SpecName('DOM3 Core','core.html#ID-952280727','Node.insertBefore')}}{{Spec2('DOM3 Core')}}No notable changes
{{SpecName('DOM2 Core','core.html#ID-952280727','Node.insertBefore')}}{{Spec2('DOM2 Core')}}No notable changes
{{SpecName('DOM1','level-one-core.html#method-insertBefore','Node.insertBefore')}}{{Spec2('DOM1')}}Introduced
+ +

See also

+ + diff --git a/files/zh-tw/web/api/node/nodename/index.html b/files/zh-tw/web/api/node/nodename/index.html new file mode 100644 index 0000000000..b9c95b6e2f --- /dev/null +++ b/files/zh-tw/web/api/node/nodename/index.html @@ -0,0 +1,102 @@ +--- +title: Node.nodeName +slug: Web/API/Node/nodeName +translation_of: Web/API/Node/nodeName +--- +
+
{{APIRef("DOM")}}
+
+ +

Node.nodeName 唯讀屬性會回傳目前節點名稱的字串。

+ +

不同類型節點之回傳值:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
介面nodeName 值
{{domxref("Attr")}}The value of {{domxref("Attr.name")}}
{{domxref("CDATASection")}}"#cdata-section"
{{domxref("Comment")}}"#comment"
{{domxref("Document")}}"#document"
{{domxref("DocumentFragment")}}"#document-fragment"
{{domxref("DocumentType")}}The value of {{domxref("DocumentType.name")}}
{{domxref("Element")}}The value of {{domxref("Element.tagName")}}
{{domxref("Entity")}}The entity name
{{domxref("EntityReference")}}The name of entity reference
{{domxref("Notation")}}The notation name
{{domxref("ProcessingInstruction")}}The value of {{domxref("ProcessingInstruction.target")}}
{{domxref("Text")}}"#text"
+ +

語法

+ +
var str = node.nodeName;
+
+ +

範例

+ +

Given the following markup:

+ +
<div id="d1">hello world</div>
+<input type="text" id="t"/>
+
+ +

and the following script:

+ +
var div1 = document.getElementById("d1");
+var text_field = document.getElementById("t");
+
+text_field.value = div1.nodeName;
+
+ +

In XHTML (or any other XML format), text_field's value would read "div". However, in HTML, text_field's value would read "DIV", because nodeName and tagName return in upper case on HTML elements in DOMs flagged as HTML documents. Read more details on nodeName case sensitivity in different browsers.

+ +

Note that tagName property could have been used instead, since nodeName has the same value as tagName for an element. Bear in mind, however, that nodeName will return #text for text nodes while tagName will return undefined.

+ +

規範

+ + diff --git a/files/zh-tw/web/api/node/nodetype/index.html b/files/zh-tw/web/api/node/nodetype/index.html new file mode 100644 index 0000000000..606cbd1b94 --- /dev/null +++ b/files/zh-tw/web/api/node/nodetype/index.html @@ -0,0 +1,171 @@ +--- +title: Node.nodeType +slug: Web/API/Node/nodeType +translation_of: Web/API/Node/nodeType +--- +
+
{{APIRef("DOM")}}
+
+ +

Node.nodeType 唯讀屬性表示了節點物件的類型。

+ +

描述

+ +

The nodeType property can be used to distinguish different kind of nodes, such that {{domxref("Element", "elements")}}, {{domxref("Text", "text")}} and {{domxref("Comment", "comments")}}, from each other.

+ +

語法

+ +
var type = node.nodeType;
+
+ +

Returns an integer value which specifies the type of the node; possible values are listed in {{anch("Node type constants")}}.

+ +

常數

+ +

節點類型常數

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ConstantValueDescription
{{domxref("Node.ELEMENT_NODE")}} {{readonlyinline}}1表示元素的 {{domxref("Element")}} 節點,如 {{HTMLElement("body")}}、{{HTMLElement("a")}}、{{HTMLElement("p")}}、{{HTMLElement("script")}}、{{HTMLElement("style")}}、{{HTMLElement("html")}}、{{HTMLElement("h1")}} 或 {{HTMLElement("div")}}
{{domxref("Node.TEXT_NODE")}} {{readonlyinline}}3於表示元素的 {{domxref("Element")}} 節點或表示 {{Glossary("attribute", "HTML 元素屬性")}}的 {{domxref("Attr")}} 節點中,表示了實際文字字元的 {{domxref("Text")}} 節點,它包括了換行與空格。
{{domxref("Node.PROCESSING_INSTRUCTION_NODE")}} {{readonlyinline}}7A {{domxref("ProcessingInstruction")}} of an XML document such as <?xml-stylesheet ... ?> declaration.
{{domxref("Node.COMMENT_NODE")}} {{readonlyinline}}8表示註解的 {{domxref("Comment")}} 節點。
{{domxref("Node.DOCUMENT_NODE")}} {{readonlyinline}}9表示文件的 {{domxref("Document")}} 節點。
{{domxref("Node.DOCUMENT_TYPE_NODE")}} {{readonlyinline}}10表示文件類型的 {{domxref("DocumentType")}} 節點,例如 HTML5 的 <!DOCTYPE html>
{{domxref("Node.DOCUMENT_FRAGMENT_NODE")}} {{readonlyinline}}11A {{domxref("DocumentFragment")}} node.
+ +

已過時的節點類型常數 {{deprecated_inline()}}

+ +

The following constants have been deprecated and should not be used anymore.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ConstantValueDescription
Node.ATTRIBUTE_NODE2An {{domxref("Attr", "Attribute")}} of an {{domxref("Element")}}. The element attributes are no longer implementing the {{domxref("Node")}} interface in {{SpecName("DOM4")}} specification.
Node.CDATA_SECTION_NODE4A {{domxref("CDATASection")}}. Removed in {{SpecName("DOM4")}} specification.
Node.ENTITY_REFERENCE_NODE5An XML Entity Reference node. Removed in {{SpecName("DOM4")}} specification.
Node.ENTITY_NODE6An XML <!ENTITY ...> node. Removed in {{SpecName("DOM4")}} specification.
Node.NOTATION_NODE12An XML <!NOTATION ...> node. Removed in {{SpecName("DOM4")}} specification.
+ +

範例

+ +

Different types of nodes

+ +
document.nodeType === Node.DOCUMENT_NODE; // true
+document.doctype.nodeType === Node.DOCUMENT_TYPE_NODE; // true
+
+var fragment = document.createDocumentFragment();
+fragment.nodeType === Node.DOCUMENT_FRAGMENT_NODE; // true
+
+var p = document.createElement("p");
+p.textContent = "Once upon a time...";
+
+p.nodeType === Node.ELEMENT_NODE; // true
+p.firstChild.nodeType === Node.TEXT_NODE; // true
+
+ +

Comments

+ +

This example checks if the first node inside the document element is a comment node, and if it is not, displays a message.

+ +
var node = document.documentElement.firstChild;
+if (node.nodeType != Node.COMMENT_NODE)
+  console.log("You should comment your code well!");
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-node-nodetype', 'Node.nodeType')}}{{Spec2('DOM WHATWG')}}Deprecated ATTRIBUTE_NODE, CDATA_SECTION_NODE, ENTITY_REFERENCE_NODE and NOTATION_NODE types.
{{SpecName('DOM3 Core', 'core.html#ID-1950641247', 'Node.nodeType')}}{{Spec2('DOM3 Core')}}No changes.
{{SpecName('DOM2 Core', 'core.html#ID-111237558', 'Node.nodeType')}}{{Spec2('DOM2 Core')}}No changes.
{{SpecName('DOM1', 'level-one-core.html#ID-111237558', 'Node.nodeType')}}{{Spec2('DOM1')}}Initial definition.
diff --git a/files/zh-tw/web/api/node/ownerdocument/index.html b/files/zh-tw/web/api/node/ownerdocument/index.html new file mode 100644 index 0000000000..33e8e641e8 --- /dev/null +++ b/files/zh-tw/web/api/node/ownerdocument/index.html @@ -0,0 +1,111 @@ +--- +title: Node.ownerDocument +slug: Web/API/Node/ownerDocument +translation_of: Web/API/Node/ownerDocument +--- +
{{APIRef("DOM")}}
+ +

Node.ownerDocument 唯讀屬性會回傳一個此節點所屬的的頂層 document 物件。

+ +

語法

+ +
document = element.ownerDocument
+
+ + + +

範例

+ +
// given a node "p", get the top-level HTML child
+// of the document object
+
+var d = p.ownerDocument;
+var html = d.documentElement;
+
+ +

備註

+ +

The document object returned by this property is the main object with which all the child nodes in the actual HTML document are created. If this property is used on a node that is itself a document, the result is null.

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("DOM4", "#dom-node-ownerdocument", "Node.ownerDocument")}}{{Spec2("DOM4")}} 
{{SpecName("DOM3 Core", "core.html#node-ownerDoc", "Node.ownerDocument")}}{{Spec2("DOM3 Core")}}No change
{{SpecName("DOM2 Core", "core.html#node-ownerDoc", "Node.ownerDocument")}}{{Spec2("DOM2 Core")}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}[1]6.0[2]{{CompatVersionUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatVersionUnknown}}[1]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Starting in Gecko 9.0 {{geckoRelease("9.0")}}, the ownerDocument of doctype nodes (that is, nodes for which {{domxref("Node.nodeType")}} is Node.DOCUMENT_TYPE_NODE or 10) is no longer null. Instead, the ownerDocument is the document on which document.implementation.createDocumentType() was called.

+ +

[2] http://msdn.microsoft.com/en-us/library/ie/ms534315(v=vs.85).aspx

diff --git a/files/zh-tw/web/api/node/removechild/index.html b/files/zh-tw/web/api/node/removechild/index.html new file mode 100644 index 0000000000..d453835c0c --- /dev/null +++ b/files/zh-tw/web/api/node/removechild/index.html @@ -0,0 +1,133 @@ +--- +title: Node.removeChild() +slug: Web/API/Node/removeChild +translation_of: Web/API/Node/removeChild +--- +
{{APIRef("DOM")}}
+ +

Node.removeChild() 方法從 DOM 移除一個子節點,並傳回移除的節點。

+ +

語法

+ +
var oldChild = node.removeChild(child);
+
+node.removeChild(child);
+
+ + + +

被刪除的子節點仍然存於記憶體之中,只是不在 DOM 了。從上述的第一種語法形式中,我們知道,透過引用 oldChild 還是可以在程式中重新使用已經被移除的子節點。

+ +

而第二種語法形式,因為沒有保留 oldChild 引用,因此假設你並沒有在其他地方保留節點引用,則它會立即無法使用且不可挽回,而且通常會在短時間內從內存管理中被自動刪除。

+ +

如果 child 並非某 element 節點的子元素,則此方法會拋出異常。而如果調用此方法時,child 雖是某 element 的子元素,但在嘗試刪除它的過程中已被其他事件處理程序刪除,也會拋出異常(例如 {{Event("blur")}})。

+ +

會丟出的錯誤

+ +

兩種不同的方式拋出異常:

+ +
    +
  1. +

    如果 child 確實是 element 的子元素且確實存在於 DOM,但已被刪除,則會丟出以下異常:

    + +

    Uncaught NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

    +
  2. +
  3. +

    如果 child 不存在於頁面的 DOM,則會拋出下列的異常:
    +
    + Uncaught TypeError: Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'.

    +
  4. +
+ +

例子

+ +

簡單的例子

+ +

HTML:

+ +
<div id="top">
+  <div id="nested"></div>
+</div>
+
+ +

在知道父節點的情況下,刪除特定元素:

+ +
let d = document.getElementById("top");
+let d_nested = document.getElementById("nested");
+let throwawayNode = d.removeChild(d_nested);
+
+ +

沒有指定父節點的情況下,刪除特定元素:

+ +
let node = document.getElementById("nested");
+if (node.parentNode) {
+  node.parentNode.removeChild(node);
+}
+
+ +

從一個元素中移除所有子元素:

+ +
let element = document.getElementById("top");
+while (element.firstChild) {
+  element.removeChild(element.firstChild);
+}
+
+ +

造成一個TypeError

+ +
<!--Sample HTML code-->
+<div id="top"> </div>
+
+<script type="text/javascript">
+  let top = document.getElementById("top");
+  let nested = document.getElementById("nested");
+
+  // Throws Uncaught TypeError
+  let garbage = top.removeChild(nested);
+</script>
+
+ +

造成一個NotFoundError

+ +
<!--Sample HTML code-->
+<div id="top">
+  <div id="nested"></div>
+</div>
+
+<script type="text/javascript">
+  let top = document.getElementById("top");
+  let nested = document.getElementById("nested");
+
+  // This first call correctly removes the node
+  let garbage = top.removeChild(nested);
+
+  // Throws Uncaught NotFoundError
+  garbage = top.removeChild(nested);
+</script>
+
+ +

規範

+ + + +

瀏覽器相容性

+ + + +

{{Compat("api.Node.removeChild")}}

+ +

相關連結

+ + diff --git a/files/zh-tw/web/api/node/textcontent/index.html b/files/zh-tw/web/api/node/textcontent/index.html new file mode 100644 index 0000000000..9375396158 --- /dev/null +++ b/files/zh-tw/web/api/node/textcontent/index.html @@ -0,0 +1,158 @@ +--- +title: Node.textContent +slug: Web/API/Node/textContent +translation_of: Web/API/Node/textContent +--- +
{{APIRef("DOM")}}
+ +

Node.textContent 屬性表示了節點或其後代的文字內容。

+ +

語法

+ +
var text = element.textContent;
+element.textContent = "this is some sample text";
+
+ +

描述

+ + + +

與 innerText 的差異

+ +

Internet Explorer introduced element.innerText. The intention is similar but with the following differences:

+ + + +

innerHTML 的差異

+ +

innerHTML returns the HTML as its name indicates. Quite often, in order to retrieve or write text within an element, people use innerHTML. textContent should be used instead. Because the text is not parsed as HTML, it's likely to have better performance. Moreover, this avoids an XSS attack vector.

+ +

範例

+ +
// Given the following HTML fragment:
+//   <div id="divA">This is <span>some</span> text</div>
+
+// Get the text content:
+var text = document.getElementById("divA").textContent;
+// |text| is set to "This is some text".
+
+// Set the text content:
+document.getElementById("divA").textContent = "This is some text";
+// The HTML for divA is now:
+//   <div id="divA">This is some text</div>
+
+ +

Polyfill for IE8

+ +
if (Object.defineProperty
+  && Object.getOwnPropertyDescriptor
+  && Object.getOwnPropertyDescriptor(Element.prototype, "textContent")
+  && !Object.getOwnPropertyDescriptor(Element.prototype, "textContent").get) {
+  (function() {
+    var innerText = Object.getOwnPropertyDescriptor(Element.prototype, "innerText");
+    Object.defineProperty(Element.prototype, "textContent",
+     {
+       get: function() {
+         return innerText.get.call(this);
+       },
+       set: function(s) {
+         return innerText.set.call(this, s);
+       }
+     }
+   );
+  })();
+}
+
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1+299.64 (possibly earlier)3 (possibly earlier)
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG','#dom-node-textcontent','Node.textContent')}}{{Spec2('DOM WHATWG')}}No changes versus DOM4
{{SpecName('DOM4','#dom-node-textcontent','Node.textContent')}}{{Spec2('DOM4')}} 
{{SpecName('DOM3 Core','core.html#Node3-textContent','Node.textContent')}}{{Spec2('DOM3 Core')}}Introduced
+ +

參見

+ + diff --git a/files/zh-tw/web/api/nodelist/index.html b/files/zh-tw/web/api/nodelist/index.html new file mode 100644 index 0000000000..f431bd1761 --- /dev/null +++ b/files/zh-tw/web/api/nodelist/index.html @@ -0,0 +1,219 @@ +--- +title: NodeList +slug: Web/API/NodeList +translation_of: Web/API/NodeList +--- +
{{APIRef("DOM")}}
+ +

NodeList 物件是節點的集合,可藉由 {{domxref("Node.childNodes")}} 屬性以及 {{domxref("document.querySelectorAll()")}} 方法取得。

+ +
+

雖然 NodeList 不是 Array,但仍可以使用 forEach() 方法來進行迭代。一些老舊瀏覽器並未實作此方法。

+
+ +

在某些情況下,NodeList動態集合(live collection),意思是 DOM 的改變會反映於集合。例如,{{domxref("Node.childNodes")}} 便是即時更新(live)的:

+ +
var parent = document.getElementById('parent');
+var child_nodes = parent.childNodes;
+console.log(child_nodes.length); // let's assume "2"
+parent.appendChild(document.createElement('div'));
+console.log(child_nodes.length); // should output "3"
+
+ +

在其他的情況下,NodeList 是一個靜態的集合(static collection),代表任何之後的 DOM 變化都不會影響集合的內容。{{domxref("document.querySelectorAll()")}} 會回傳一個靜態的 NodeList

+ +

當你要選擇如何迭代 NodeList 中的項目時,最好能於心中區分動態與靜態集合,尤其是在取得集合長度(length of the list)的時候。

+ +

屬性

+ +
+
{{domxref("NodeList.length")}}
+
The number of nodes in the NodeList.
+
+ +

方法

+ +
+
{{domxref("NodeList.item()")}}
+
Returns an item in the list by its index, or null if the index is out-of-bounds; can be used as an alternative to simply accessing nodeList[idx] (which instead returns  undefined when idx is out-of-bounds).
+
{{domxref("NodeList.entries()")}}
+
Returns an {{jsxref("Iteration_protocols","iterator")}} allowing to go through all key/value pairs contained in this object.
+
{{domxref("NodeList.forEach()")}}
+
Executes a provided function once per NodeList element.
+
{{domxref("NodeList.keys()")}}
+
Returns an {{jsxref("Iteration_protocols", "iterator")}} allowing to go through all keys of the key/value pairs contained in this object.
+
{{domxref("NodeList.values()")}}
+
Returns an {{jsxref("Iteration_protocols", "iterator")}} allowing to go through all values of the key/value pairs contained in this object.
+
+ +

範例

+ +

It's possible to loop over the items in a NodeList using:

+ +
for (var i = 0; i < myNodeList.length; ++i) {
+  var item = myNodeList[i];  // Calling myNodeList.item(i) isn't necessary in JavaScript
+}
+
+ +

Don't be tempted to use for...in or for each...in to enumerate the items in the list, since that will also enumerate the length and item properties of the NodeList and cause errors if your script assumes it only has to deal with {{domxref("element")}} objects. Also, for..in is not guaranteed to visit the properties in any particular order.

+ +

for...of loops will loop over NodeList objects correctly:

+ +
var list = document.querySelectorAll( 'input[type=checkbox]' );
+for (var item of list) {
+  item.checked = true;
+}
+ +

Recent browsers also support iterator methods, {{domxref("NodeList.forEach()", "forEach()")}}, as well as {{domxref("NodeList.entries()", "entries()")}}, {{domxref("NodeList.values()", "values()")}}, and {{domxref("NodeList.keys()", "keys()")}}

+ +

There is also an Internet Explorer compatible way to use {{jsxref("Array.forEach()", "Array.prototype.forEach")}} for iteration.

+ +
var list = document.querySelectorAll( 'input[type=checkbox]' );
+Array.prototype.forEach.call(list, function (item) {
+  item.checked = true;
+});
+ +

NodeList 原型

+ +

You can also add prototypes to nodelist:

+ +
var elements = document.querySelectorAll(".suggestions");
+
+NodeList.prototype.addEventListener = function(event, func) {
+    this.forEach(function(content, item) {
+       content.addEventListener(event, func);
+    });
+}
+
+function log() {
+    console.log(this, " was clicked");
+}
+
+elements.addEventListener("click", log);
+//or
+elements.addEventListener("click", function() {
+    console.log(this, "  awas clicked");
+});
+// output from both will be element was clicked the element would be HTML Element
+ +

For information about forEach see Array.prototype.forEach()

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#interface-nodelist', 'NodeList')}}{{ Spec2('DOM WHATWG') }} 
{{SpecName('DOM4', '#interface-nodelist', 'NodeList')}}{{ Spec2('DOM4') }} 
{{SpecName('DOM3 Core', 'core.html#ID-536297177', 'NodeList')}}{{ Spec2('DOM3 Core') }} 
{{SpecName('DOM2 Core', 'core.html#ID-536297177', 'NodeList')}}{{ Spec2('DOM2 Core') }} 
{{SpecName('DOM1', 'level-one-core.html#ID-536297177', 'NodeList')}}{{ Spec2('DOM1') }}Initial definition.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
entries(), keys(), values(), forEach(){{CompatChrome(51)}}{{CompatNo}}{{CompatGeckoDesktop(50)}}{{CompatNo}}3810 (maybe prior)
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewEdgeFirefox Mobile (Gecko)Firefox OS (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
entries(), keys(), values(), forEach(){{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile(50)}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}10 (maybe prior){{CompatChrome(51)}}
+
diff --git a/files/zh-tw/web/api/nondocumenttypechildnode/index.html b/files/zh-tw/web/api/nondocumenttypechildnode/index.html new file mode 100644 index 0000000000..31fb8c91e5 --- /dev/null +++ b/files/zh-tw/web/api/nondocumenttypechildnode/index.html @@ -0,0 +1,125 @@ +--- +title: NonDocumentTypeChildNode +slug: Web/API/NonDocumentTypeChildNode +translation_of: Web/API/NonDocumentTypeChildNode +--- +
{{APIRef("DOM")}}
+ +

NonDocumentTypeChildNode 介面定義了可以擁有父節點但不適用 {{domxref("DocumentType")}} 之 {{domxref("Node")}} 物件的方法。

+ +

NonDocumentTypeChildNode 是一個原始的介面,且不能以此建立物件實體。{{domxref("Element")}} 及 {{domxref("CharacterData")}} 物件皆實作了 NonDocumentTypeChildNode

+ +

屬性

+ +

There is no inherited property.

+ +
+
{{domxref("NonDocumentTypeChildNode.previousElementSibling")}} {{readonlyInline}}
+
Returns the {{domxref("Element")}} immediately prior to this node in its parent's children list, or null if there is no {{domxref("Element")}} in the list prior to this node.
+
{{domxref("NonDocumentTypeChildNode.nextElementSibling")}} {{readonlyInline}}
+
Returns the {{domxref("Element")}} immediately following this node in its parent's children list, or null if there is no {{domxref("Element")}} in the list following this node.
+
+ +

方法

+ +

There is neither inherited, nor specific method.

+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#interface-childnode', 'NonDocumentTypeChildNode')}}{{Spec2('DOM WHATWG')}}Splitted the ElementTraversal interface in {{domxref("ParentNode")}}, {{domxref("ChildNode")}}, and NonDocumentTypeChildNode. The previousElementSibling and nextElementSibling are now defined on the latter.
+ The {{domxref("CharacterData")}} and {{domxref("Element")}} implemented the new interfaces.
{{SpecName('Element Traversal', '#interface-elementTraversal', 'ElementTraversal')}}{{Spec2('Element Traversal')}}Added the initial definition of its properties to the ElementTraversal pure interface and use it on {{domxref("Element")}}.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support (on {{domxref("Element")}})1.0{{CompatGeckoDesktop("1.9.1")}}9.010.04.0
Support (on {{domxref("CharacterData")}})1.0{{CompatGeckoDesktop("25.0")}} [1]9.010.04.0
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support (on {{domxref("Element")}}){{ CompatVersionUnknown() }}{{CompatGeckoDesktop("1.9.1")}}{{ CompatVersionUnknown() }}10.0{{ CompatVersionUnknown() }}
Support (on {{domxref("CharacterData")}}){{ CompatVersionUnknown() }}{{CompatGeckoDesktop("25.0")}}{{ CompatVersionUnknown() }}10.0{{ CompatVersionUnknown() }}
+
+ +

[1] Firefox 25 also added the two properties defined here on {{domxref("DocumentType")}}, this was removed in Firefox 28 due to compatibility problems, and led to the creation of this new pure interface.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/notification/index.html b/files/zh-tw/web/api/notification/index.html new file mode 100644 index 0000000000..fc1e0f9434 --- /dev/null +++ b/files/zh-tw/web/api/notification/index.html @@ -0,0 +1,355 @@ +--- +title: Notification +slug: Web/API/notification +tags: + - 待翻譯 +translation_of: Web/API/Notification +--- +

{{APIRef("Web Notifications")}}

+ +

Notifications API 的 Notification interface 是用來設置及顯示「桌面通知」給使用。

+ +

{{AvailableInWorkers}}

+ +

Constructor

+ +
+
{{domxref("Notification.Notification", "Notification()")}}
+
建立一個新的 {{domxref('Notification')}} 實例。
+
+ +

Properties

+ +

靜態屬性

+ +

以下的屬性僅適用於 Notification 實例。

+ +
+
{{domxref("Notification.permission")}} {{readonlyinline}}
+
一個表示允許通知顯示與否的權限的 string。可能的值有:「denied」(使用者不允許顯示 Notification )、「granted」(使用者允許顯示 Notification ),或者是「default」(還不知道使用者允許與否,預設行為與 denied 一致)。
+
+ +

實例屬性

+ +

以下屬應僅適用於 Notification 實例。

+ +
+
{{domxref("Notification.title")}} {{readonlyinline}}
+
在建構子的 options 參數中指定的 Notification 的標題。
+
{{domxref("Notification.dir")}} {{readonlyinline}}
+
在建構子的 options 參數中指定的 Notification 的文字顯示方向。
+
{{domxref("Notification.lang")}} {{readonlyinline}}
+
在建構子的 options 參數中指定的 Notification 的語言代號。
+
{{domxref("Notification.body")}} {{readonlyinline}}
+
在建構子的 options 參數中指定的 Notification 的內容。
+
{{domxref("Notification.tag")}} {{readonlyinline}}
+
The ID of the notification (if any) as specified in the options parameter of the constructor.
+
{{domxref("Notification.icon")}} {{readonlyinline}}
+
在建構子的 options 參數中指定的 Notification 的 icon 的網址。
+
{{domxref("Notification.data")}} {{readonlyinline}}
+
回傳結構化的 Notification 的資料。
+
{{domxref("Notification.requireInteraction")}} {{readonlyinline}}
+
一個 {{jsxref("Boolean")}} 指示在有充足大小的螢幕上的時候,Notfication 實例是否會持續顯示直到使用者點擊它或者 dismisses it。
+
{{domxref("Notification.silent")}} {{readonlyinline}}
+
表示 Notfication 是否設定要以較低調的方式呈現(比如不撥放通知音效、不震動)。這個設定與裝置本身的設定無關。
+
+ +
+
{{domxref("Notification.timestamp")}} {{readonlyinline}}
+
表示 Notification 的建立時間、或者可啟動的時間 (可能是過去、現在或未來)。
+
+ +
+
{{domxref("Notification.vibrate")}} {{readonlyinline}}
+
表示在可震動的裝置上的震動模式。
+
+ +

尚未支援的屬性

+ +

The following properties are listed in the most up-to-date spec, but are not supported in any browsers yet. It is advisable to keep checking back regularly to see if the status of these has updated, and let us know if you find any out of date information.

+ +
+
{{domxref("Notification.noscreen")}} {{readonlyinline}}
+
表示 Notification 顯示時是否要打開裝置的螢幕。
+
{{domxref("Notification.renotify")}} {{readonlyinline}}
+
表示使用者是否會在舊的 Notification 被新的 Notification 替換掉時通知。
+
{{domxref("Notification.sound")}} {{readonlyinline}}
+
表示當 Notification 顯示時要用來代替系統預設音效撥放的音訊資源。
+
{{domxref("Notification.sticky")}} {{readonlyinline}}
+
表示 Notification 是否「sticky」(比如使用者不太容易清除它)。
+
+ +

事件處理器

+ +
+
{{domxref("Notification.onclick")}}
+
一個 {{event("click")}} 事件的 handler。每次使用者點擊 Notification 都會被觸發。
+
{{domxref("Notification.onerror")}}
+
一個 {{event("error")}} 事件的 handler. 每次 Notification 發生 Error 都會被觸發。
+
+ +

停止支援的事件處理器

+ +

底下這些列在 {{anch("browser compatibility")}} 中的 event handlers 雖然還有支援,但已經從近期的 spec 中移除了。因為瀏覽器會在未來的版本逐漸停止支援,最好還是不要使用它們。

+ +
+
{{domxref("Notification.onclose")}}
+
A handler for the {{event("close")}} event. It is triggered when the user closes the notification.
+
{{domxref("Notification.onshow")}}
+
A handler for the {{event("show")}} event. It is triggered when the notification is displayed.
+
+ +

方法

+ +

靜態方法

+ +

這些方法只能在 Notification 實例上使用。

+ +
+
{{domxref("Notification.requestPermission()")}}
+
向使用者詢問是否開放顯示 Notification 的權限。
+
+ +

實例方法

+ +

These properties are available only on an instance of the Notification object or through its prototype. The Notification object also inherits from the {{domxref("EventTarget")}} interface.

+ +
+
{{domxref("Notification.close()")}}
+
透過這個方法關閉 Notification 。
+
+ +

範例

+ +

先看這段基本的 HTML:

+ +
<button onclick="notifyMe()">Notify me!</button>
+ +

用下面的程式碼我們可以送出通知: 底下的程式碼雖然略嫌冗長,但完整的示範了如何在送出通知之前,事先檢查了瀏覽器是否支援 Notification、使用者是否授權這個網域的網頁送出通知,以及在需要的時候向使用者詢問是否開放權限。

+ +
function notifyMe() {
+  // 首先讓我們確定瀏覽器支援 Notification
+  if (!("Notification" in window)) {
+    alert("這個瀏覽器不支援 Notification");
+  }
+
+  // 再檢查使用者是否已經授權執行 Notification
+  else if (Notification.permission === "granted") {
+    // 如果已經授權就可以直接新增 Notification 了!
+    var notification = new Notification("安安你好!");
+  }
+
+  // 否則,我們會需要詢問使用者是否開放權限
+  else if (Notification.permission !== 'denied') {
+    Notification.requestPermission(function (permission) {
+      // 如果使用者同意了就來新增一個 Notification 打聲招呼吧
+      if (permission === "granted") {
+        var notification = new Notification("安安~");
+      }
+    });
+  }
+
+  // 如果使用者還是不同意授權執行 Notification
+  // 最好還是進行適當的處理以避免繼續打擾使用者
+}
+ +

{{EmbedLiveSample('範例', '100%', 30)}}

+ +

在很多時候,你應該不會想要這麼冗長的程式碼。 比如說,在我們的 Emogotchi demo (see source code)  之中,我們只寫了 {{domxref("Notification.requestPermission")}} 而不用進一步檢查是否已經獲得了權限:

+ +
Notification.requestPermission();
+ +

然後我們只需要在要新增 Notfication 時執行這個 spawnNotification()  — 透過傳入指定的 body、icon、title,然後它就會產生我們所需的 options 參數並透過 {{domxref("Notification.Notification","Notification()")}} 建構子發送 Notification.

+ +
function spawnNotification(theBody,theIcon,theTitle) {
+  var options = {
+      body: theBody,
+      icon: theIcon
+  }
+  var n = new Notification(theTitle,options);
+}
+ +

規格

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Web Notifications')}}{{Spec2('Web Notifications')}}Living standard
+ +

瀏覽器支援度

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{property_prefix("webkit")}}[1]
+ 22
4.0 {{property_prefix("moz")}}[2]
+ 22
{{CompatNo}}256[3]
icon5{{property_prefix("webkit")}}[1]
+ 22
4.0 {{property_prefix("moz")}}[2]
+ 22
{{CompatNo}}25{{CompatNo}}
Available in workers{{CompatUnknown}}{{CompatGeckoDesktop("41.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
silent{{CompatChrome(43.0)}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
noscreen, renotify, sound, sticky{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatUnknown}} +

{{CompatVersionUnknown}}

+
4.0{{property_prefix("moz")}}[2]
+ 22
1.0.1{{property_prefix("moz")}}[2]
+ 1.2
{{CompatNo}}{{CompatUnknown}}{{CompatNo}} +

{{CompatVersionUnknown}}

+
icon{{CompatUnknown}}{{CompatVersionUnknown}}4.0{{property_prefix("moz")}}[2]
+ 22
1.0.1{{property_prefix("moz")}}[2]
+ 1.2
{{CompatNo}}{{CompatUnknown}}{{CompatNo}}{{CompatVersionUnknown}}
Available in workers{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("41.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
silent{{CompatNo}}{{CompatChrome(43.0)}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatChrome(43.0)}}
noscreen, renotify, sound, sticky{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

[1] Before Chrome 22, the support for notification followed an old prefixed version of the specification and used the {{domxref("window.navigator.webkitNotifications","navigator.webkitNotifications")}} object to instantiate a new notification.

+ +

Before Chrome 32, {{domxref("Notification.permission")}} was not supported.

+ +

Before Chrome 42, service worker additions were not supported.

+ +

[2] Prior to Firefox 22 (Firefox OS <1.2), the instantiation of a new notification must be done with the {{domxref("window.navigator.mozNotification", "navigator.mozNotification")}} object through its createNotification method.

+ +

Prior to Firefox 22 (Firefox OS <1.2), the Notification was displayed when calling the show method and supported only the click and close events.

+ +

Nick Desaulniers wrote a Notification shim to cover both newer and older implementations.

+ +

One particular Firefox OS issue is that you can pass a path to an icon to use in the notification, but if the app is packaged you cannot use a relative path like /my_icon.png. You also can't use window.location.origin + "/my_icon.png" because window.location.origin is null in packaged apps. The manifest origin field fixes this, but it is only available in Firefox OS 1.1+. A potential solution for supporting Firefox OS <1.1 is to pass an absolute URL to an externally hosted version of the icon. This is less than ideal as the notification is displayed immediately without the icon, then the icon is fetched, but it works on all versions of Firefox OS.

+ +

When using notifications  in a Firefox OS app, be sure to add the desktop-notification permission in your manifest file. Notifications can be used at any permission level, hosted or above: "permissions": { "desktop-notification": {} }

+ +

[3] Safari started to support notification with Safari 6, but only on Mac OSX 10.8+ (Mountain Lion).

+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/api/notifications_api/index.html b/files/zh-tw/web/api/notifications_api/index.html new file mode 100644 index 0000000000..8cf3276371 --- /dev/null +++ b/files/zh-tw/web/api/notifications_api/index.html @@ -0,0 +1,198 @@ +--- +title: Notifications API +slug: Web/API/Notifications_API +translation_of: Web/API/Notifications_API +--- +

{{DefaultAPISidebar("Web Notifications")}}

+ +

Notifications API允許網頁控制向終端用戶顯示系統通知 — 它在網頁瀏覽器的視圖之外,因此使用者切換顯示卡或移至不同的應用程式也能顯示。此 API 設計為在相容於不同平台與現有的通知系統相容。

+ +

概念與使用方法

+ +

在受到支持的平台上,顯示系統通知通常涉及兩件事。 首先,用戶需要授予當前的來源權限才能顯示系統通知,通常在應用程式或網站初始化完成後使用{{domxref("Notification.requestPermission()")}} 方法。

+ +
btn.addEventListener('click', function() {
+  let promise = Notification.requestPermission();
+  // wait for permission
+})
+ +

這不僅是最佳實踐 — 您不應向用戶發送他們不同意的通知,並且在未來瀏覽器將明確禁止沒有響應用戶請求允許通知對話框的通知。Firefox 72 開始已遵循這項約定。使用此方法將產生一個請求對話框,如下所示:

+ +

+ +

用戶可以從此處選擇允許、屏蔽來自此來源的通知,也可以不做選擇。 一旦選定,該設置通常將在當前會話中保持不變。

+ +
+

注意: 從 Firefox 44 開始,Notifications 和 Push 的權限已合併。如果授予通知權限則推送也將被啟用。

+
+ +

下一步,使用 {{domxref("Notification.Notification","Notification()")}} 構造函數創建一個新通知。 這必須要傳遞一個標題參數(title),並且可以選擇性的傳遞選擇物件指定諸如文字方向、正文、圖標、撥放通知的聲音等等。

+ +

{{AvailableInWorkers}}

+ +

另外,Notifications API規範指定了 ServiceWorker API 的許多附加功能,以允許服務人員觸發通知。

+ +
+

注意: 要了解有關在自己的應用程序中使用通知的更多信息,請閱讀 Using the Notifications API

+
+ +

Notifications 介面

+ +
+
{{domxref("Notification")}}
+
定義一個通知物件。
+
+ +

Service worker 附加功能

+ +
+
{{domxref("ServiceWorkerRegistration")}}
+
包含 {{domxref("ServiceWorkerRegistration.showNotification()")}} 和 {{domxref("ServiceWorkerRegistration.getNotifications()")}} 用於控制通知顯示的方法。
+
{{domxref("ServiceWorkerGlobalScope")}}
+
包含 {{domxref("ServiceWorkerGlobalScope.onnotificationclick")}} 點擊通知時觸發自定義函數的處理程序。
+
{{domxref("NotificationEvent")}}
+
基於 {{domxref("ExtendableEvent")}} 的特定類型的事件對象,它表示已觸發的通知。
+
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Web Notifications')}}{{Spec2('Web Notifications')}}Living standard
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{property_prefix("webkit")}}[1]
+ 22
{{CompatGeckoDesktop("2.0")}}{{property_prefix("moz")}}[2]
+ {{CompatGeckoDesktop("22.0")}}
{{CompatNo}}256[3]
Available in workers{{CompatUnknown}}{{CompatGeckoDesktop("41.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
Service worker additions +

{{CompatChrome(42.0)}}

+
{{CompatGeckoDesktop("42.0")}}[4]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatUnknown}} +

{{CompatVersionUnknown}}

+
{{CompatGeckoMobile(2.0)}}{{property_prefix("moz")}}[2]
+ {{CompatGeckoMobile(22.0)}}
1.0.1{{property_prefix("moz")}}[2]
+ 1.2
{{CompatNo}}{{CompatUnknown}}{{CompatNo}} +

{{CompatVersionUnknown}}

+
Available in workers{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile(41.0)}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
Service worker additions{{CompatNo}}{{CompatNo}}{{CompatGeckoMobile(42.0)}}[4]{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatChrome(42.0)}}
+
+ +

[1] Before Chrome 22, the support for notification followed an old prefixed version of the specification and used the {{domxref("window.navigator.webkitNotifications","navigator.webkitNotifications")}} object to instantiate a new notification. Before Chrome 32, {{domxref("Notification.permission")}} was not supported.

+ +

[2] Prior to Firefox 22 (Firefox OS <1.2), the instantiation of a new notification was done with the {{domxref("window.navigator.mozNotification", "navigator.mozNotification")}} object through its createNotification() method. In addition, the Notification was displayed when calling the show() method and supported only the click and close events (Nick Desaulniers wrote a Notification shim to cover both newer and older implementations.)

+ +

[3] Safari started to support notification with Safari 6, but only on Mac OSX 10.8+ (Mountain Lion).

+ +

[4] Firefox 42 has shipped with web notifications from Service Workers disabled.

+ +

Firefox OS permissions

+ +

When using notifications  in a Firefox OS app, be sure to add the desktop-notification permission in your manifest file. Notifications can be used at any permission level, hosted or above:

+ +
"permissions": {
+  "desktop-notification": {}
+}
+ +

參見

+ + diff --git a/files/zh-tw/web/api/notifications_api/using_the_notifications_api/index.html b/files/zh-tw/web/api/notifications_api/using_the_notifications_api/index.html new file mode 100644 index 0000000000..1a970509c2 --- /dev/null +++ b/files/zh-tw/web/api/notifications_api/using_the_notifications_api/index.html @@ -0,0 +1,236 @@ +--- +title: 使用 Web Notifications +slug: Web/API/Notifications_API/Using_the_Notifications_API +translation_of: Web/API/Notifications_API/Using_the_Notifications_API +--- +

{{SeeCompatTable}}

+ +

摘要

+ +

Web Notifications API 可將通知傳送至頁面以外的系統層級並顯示通知。因此即使 Web Apps 處於閒置狀態,亦可傳送資訊予使用者。絕佳範例之一,就是在使用其他 Apps 時,Web Mail App 同樣可通知使用者已接收到新郵件。

+ +

要求權限

+ +

網頁內容

+ +

在 Apps 傳送通知之前,使用者必須先許可 Apps 的動作。只要 APIs 嘗試予網頁之外的東西互動,均必須先獲得使用者的授權。如此可避免濫發通知而影響使用經驗。

+ +

透過 Notification.permission 唯讀屬性,要傳送通知的 Apps 將檢查目前的授權狀態。此屬性共有 3 組參數:

+ + + +
+

注意:Chrome 與 Safari 尚未建構 permission 屬性。

+
+ +

若使用者尚未給予權限,則 Apps 必須透過 Notification.requestPermission() 函式讓使用者選擇,接著由此函式接收 1 組回呼 (Callback) 函式作為參數;而該回呼函式則提供使用者是否授權的資訊。

+ +

以下為啟動 Apps 時要求權限的常用範例:

+ +
window.addEventListener('load', function () {
+  Notification.requestPermission(function (status) {
+    // This allows to use Notification.permission with Chrome/Safari
+    if (Notification.permission !== status) {
+      Notification.permission = status;
+    }
+  });
+});
+ +
+

注意:Chrome 不允許於載入事件中呼叫 Notification.requestPermission() (參閱 issue 274284)。

+
+ +

已安裝的 Apps

+ +

在安裝 Apps 之後,若於 Apps 的 manifest 檔案中直接添加權限,即可省去再次向使用者要求權限的動作。

+ +
permissions: {
+  "desktop-notification": {
+    "description: "Allows to display notifications on the user's desktop.
+  }
+}
+ +

建立通知

+ +

透過 Notification 建構子 (Constructor) 即可建立通知。此建構子包含 1 組標題,可於通知內顯示;另有如 icon 或文字 body數個選項,可強化通知的內容。

+ +

在建立實體 (Instantiated) 之後,就會儘快顯示通知。若要追蹤通知的目前狀態,必須在 Notification 的實體階層觸發 4 個事件:

+ + + +

而透過 onshowonclickonclose,或 onerror 等事件處理器 (Event handler),即可追蹤這些事件。由於 Notification 是繼承 EventTarget 而來,因此亦可使用 addEventListener() 函式。

+ +
+

注意:Firefox 與 Safari 並未遵守 close 事件的規格。此規格雖然規定「僅限使用者能關閉通知」,但 Firefox 與 Safari 卻可於數分鐘後自動關閉通知。因此不一定是由使用者關閉通知。

+ +

此規格並明確規定「應透過 Notification.close() 函式,於應用程式層級完成自動關閉通知」。範例程式碼如下:

+ +
var n = new Notification("Hi!");
+n.onshow = function () {
+  setTimeout(n.close, 5000);
+}
+
+
+ +

簡易範例

+ +

先假設下列基本 HTML:

+ +
<button>Notify me!</button>
+ +

則能以這種方法處理通知:

+ +
window.addEventListener('load', function () {
+  // At first, let's check if we have permission for notification
+  // If not, let's ask for it
+  if (Notification && Notification.permission !== "granted") {
+    Notification.requestPermission(function (status) {
+      if (Notification.permission !== status) {
+        Notification.permission = status;
+      }
+    });
+  }
+  var button = document.getElementsByTagName('button')[0];
+  button.addEventListener('click', function () {
+    // If the user agreed to get notified
+    if (Notification && Notification.permission === "granted") {
+      var n = new Notification("Hi!");
+    }
+    // If the user hasn't told if he wants to be notified or not
+    // Note: because of Chrome, we are not sure the permission property
+    // is set, therefore it's unsafe to check for the "default" value.
+    else if (Notification && Notification.permission !== "denied") {
+      Notification.requestPermission(function (status) {
+        if (Notification.permission !== status) {
+          Notification.permission = status;
+        }
+        // If the user said okay
+        if (status === "granted") {
+          var n = new Notification("Hi!");
+        }
+        // Otherwise, we can fallback to a regular modal alert
+        else {
+          alert("Hi!");
+        }
+      });
+    }
+    // If the user refuses to get notified
+    else {
+      // We can fallback to a regular modal alert
+      alert("Hi!");
+    }
+  });
+});
+ +

現場測試結果

+ +

若無法顯示,可至本文右上角「Language」切換回英文原文觀看。

+ +

{{ EmbedLiveSample('Simple_example', '100%', 30) }}

+ +

處理多筆通知

+ +

某些情況下 (如某個即時訊息 App 持續通知每一筆進來的訊息),使用者可能會接收大量的通知。為了避免太多非必要訊息擠爆使用者的桌面,則應該讓等待中的通知進入佇列。

+ +

將標籤添加至任何新的通知,即可達到佇列效果。若通知擁有相同的標籤且尚未顯示,則新通知就會取代先前的通知;反之,若已顯示了相同標籤的通知,就會關閉先前的通知而顯示新通知。

+ +

標籤範例

+ +

先假設下列基本 HTML:

+ +
<button>Notify me!</button>
+ +

則能以下列方式處理多筆通知:

+ +
window.addEventListener('load', function () {
+  // At first, let's check if we have permission for notification
+  // If not, let's ask for it
+  if (Notification && Notification.permission !== "granted") {
+    Notification.requestPermission(function (status) {
+      if (Notification.permission !== status) {
+        Notification.permission = status;
+      }
+    });
+  }
+  var button = document.getElementsByTagName('button')[0];
+  button.addEventListener('click', function () {
+    // If the user agreed to get notified
+    // Let's try to send ten notifications
+    if (Notification && Notification.permission === "granted") {
+      for (var i = 0; i < 10; i++) {
+        // Thanks to the tag, we should only see the "Hi! 10" notification
+        var n = new Notification("Hi! " + i, {tag: 'soManyNotification'});
+      }
+    }
+    // If the user hasn't told if he wants to be notified or not
+    // Note: because of Chrome, we are not sure the permission property
+    // is set, therefore it's unsafe to check for the "default" value.
+    else if (Notification && Notification.permission !== "denied") {
+      Notification.requestPermission(function (status) {
+        if (Notification.permission !== status) {
+          Notification.permission = status;
+        }
+        // If the user said okay
+        if (status === "granted") {
+          for (var i = 0; i < 10; i++) {
+            // Thanks to the tag, we should only see the "Hi! 10" notification
+            var n = new Notification("Hi! " + i, {tag: 'soManyNotification'});
+          }
+        }
+        // Otherwise, we can fallback to a regular modal alert
+        else {
+          alert(Hi!");
+        }
+      });
+    }
+    // If the user refuses to get notified
+    else {
+      // We can fallback to a regular modal alert
+      alert(Hi!");
+    }
+  });
+});
+ +

現場測試結果

+ +

若無法顯示,可至本文右上角「Language」切換回英文原文觀看。

+ +

{{ EmbedLiveSample('Tag_example', '100%', 30) }}

+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Web Notifications')}}{{Spec2('Web Notifications')}}Initial specification.
+ +

瀏覽器相容性

+ +

{{page("/en-US/Web/API/Notification","Browser compatibility")}}

+ +

另可參閱

+ + diff --git a/files/zh-tw/web/api/parentnode/children/index.html b/files/zh-tw/web/api/parentnode/children/index.html new file mode 100644 index 0000000000..f9f6c76115 --- /dev/null +++ b/files/zh-tw/web/api/parentnode/children/index.html @@ -0,0 +1,152 @@ +--- +title: ParentNode.children +slug: Web/API/ParentNode/children +translation_of: Web/API/ParentNode/children +--- +

{{ APIRef("DOM") }}

+ +

Node.children 唯讀屬性會回傳一個 Node 之子{{domxref("Element","元素")}}的動態(live){{domxref("HTMLCollection")}}。

+ +

語法

+ +
var children = node.children;
+ +

children 是一個 {{ domxref("HTMLCollection") }},為一個有順序性、由 node 中的 DOM 子元素所組成的集合。假如沒有子元素,則 children 內便不包含任何元素,且 length0

+ +

範例

+ +
var foo = document.getElementById('foo');
+for (var i = 0; i < foo.children.length; i++) {
+    console.log(foo.children[i].tagName);
+}
+
+ +

Polyfill

+ +
// Overwrites native 'children' prototype.
+// Adds Document & DocumentFragment support for IE9 & Safari.
+// Returns array instead of HTMLCollection.
+;(function(constructor) {
+    if (constructor &&
+        constructor.prototype &&
+        constructor.prototype.children == null) {
+        Object.defineProperty(constructor.prototype, 'children', {
+            get: function() {
+                var i = 0, node, nodes = this.childNodes, children = [];
+                while (node = nodes[i++]) {
+                    if (node.nodeType === 1) {
+                        children.push(node);
+                    }
+                }
+                return children;
+            }
+        });
+    }
+})(window.Node || window.Element);
+
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-parentnode-children', 'ParentNode.children')}}{{Spec2('DOM WHATWG')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerEdgeOperaSafari
Basic support (on {{domxref("Element")}})1.0{{CompatGeckoDesktop("1.9.1")}}9.0 [1]38.010.04.0
Support on {{domxref("Document")}} and {{domxref("DocumentFragment")}} {{experimental_inline}}29.0{{CompatGeckoDesktop("25.0")}}{{CompatNo}}{{CompatNo}}16.0{{CompatNo}}
Support on {{domxref("SVGElement")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatNo}}{{CompatUnknown}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support (on {{domxref("Element")}}){{ CompatVersionUnknown() }}{{CompatGeckoMobile("1.9.1")}}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Support on {{domxref("Document")}} and {{domxref("DocumentFragment")}} {{experimental_inline}}{{CompatVersionUnknown}}{{CompatGeckoMobile("25.0")}}{{CompatNo}}16.0{{CompatNo}}
+
+ +

[1] Internet Explorer 6, 7 and 8 supported it, but erroneously includes {{domxref("Comment")}} nodes.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/parentnode/firstelementchild/index.html b/files/zh-tw/web/api/parentnode/firstelementchild/index.html new file mode 100644 index 0000000000..4fa9722123 --- /dev/null +++ b/files/zh-tw/web/api/parentnode/firstelementchild/index.html @@ -0,0 +1,95 @@ +--- +title: ParentNode.firstElementChild +slug: Web/API/ParentNode/firstElementChild +translation_of: Web/API/ParentNode/firstElementChild +--- +

{{ APIRef("DOM") }}

+ +

ParentNode.firstElementChild 介面會會返回 ParentNode的第一個子元素(唯讀) ,如果該節點沒有子節點則返回null

+ +
+

This property was initially defined in the {{domxref("ElementTraversal")}} pure interface. As this interface contained two distinct set of properties, one aimed at {{domxref("Node")}} that have children, one at those that are children, they have been moved into two separate pure interfaces, {{domxref("ParentNode")}} and {{domxref("ChildNode")}}. In this case, firstElementChild moved to {{domxref("ParentNode")}}. This is a fairly technical change that shouldn't affect compatibility.

+
+ +

語法

+ +
var element = node.firstElementChild;
+
+ +

範例

+ +
<ul id="foo">
+  <li>First  (1)</li>
+  <li>Second (2)</li>
+  <li>Third  (3)</li>
+</ul>
+
+<script>
+var foo = document.getElementById('foo');
+// yields: First  (1)
+console.log(foo.firstElementChild.textContent);
+</script>
+
+ +

適用於IE8, IE9 和 Safari的Polyfill

+ +
// Overwrites native 'firstElementChild' prototype.
+// Adds Document & DocumentFragment support for IE9 & Safari.
+;(function(constructor) {
+    if (constructor &&
+        constructor.prototype &&
+        constructor.prototype.firstElementChild == null) {
+        Object.defineProperty(constructor.prototype, 'firstElementChild', {
+            get: function() {
+                var node, nodes = this.childNodes, i = 0;
+                while (node = nodes[i++]) {
+                    if (node.nodeType === 1) {
+                        return node;
+                    }
+                }
+                return null;
+            }
+        });
+    }
+})(window.Node || window.Element);
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-parentnode-firstelementchild', 'ParentNode.firstElementChild')}}{{Spec2('DOM WHATWG')}}Split the ElementTraversal interface in {{domxref("ChildNode")}} and ParentNode. This method is now defined on the latter.
+ The {{domxref("Document")}} and {{domxref("DocumentFragment")}} implemented the new interfaces.
{{SpecName('Element Traversal', '#attribute-firstElementChild', 'ElementTraversal.firstElementChild')}}{{Spec2('Element Traversal')}}Added its initial definition to the ElementTraversal pure interface and use it on {{domxref("Element")}}.
+ +

瀏覽器相容性

+ + + +

{{Compat("api.ParentNode.firstElementChild")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/parentnode/index.html b/files/zh-tw/web/api/parentnode/index.html new file mode 100644 index 0000000000..f3a37abb2f --- /dev/null +++ b/files/zh-tw/web/api/parentnode/index.html @@ -0,0 +1,166 @@ +--- +title: ParentNode +slug: Web/API/ParentNode +translation_of: Web/API/ParentNode +--- +
{{APIRef("DOM")}}
+ +

ParentNode 介面定義了可以擁有子節點之 {{domxref("Node")}} 物件的方法。

+ +

ParentNode 是一個原始的介面,且不能以此建立物件實體。{{domxref("Element")}}、{{domxref("Document")}} 及 {{domxref("DocumentFragment")}} 物件皆實作了 ParentNode

+ +

屬性

+ +
+
{{domxref("ParentNode.children")}} {{experimental_inline}} {{readonlyInline}}
+
該屬性會返回一個 {{domxref("HTMLCollection")}} 實例,包括 ParentNode的所有子元素節點,需要特別注意的是:該屬性為唯讀
+
{{domxref("ParentNode.firstElementChild")}} {{experimental_inline}} {{readonlyInline}}
+
該屬性會返回 ParentNode的第一個子元素 ,如果該節點沒有子節點則返回null
+
{{domxref("ParentNode.lastElementChild")}} {{experimental_inline}} {{readonlyInline}}
+
該屬性會返回 ParentNode的最後一個子元素 ,如果該節點沒有子節點則返回null
+
{{domxref("ParentNode.childElementCount")}} {{experimental_inline}} {{readonlyInline}}
+
該屬性會返回一個無符號長整數 ,該值表示了該節點的子節點數量。
+
+ +

方法

+ +
+
{{domxref("ParentNode.append()")}} {{experimental_inline}}
+
Inserts a set of {{domxref("Node")}} objects or {{domxref("DOMString")}} objects after the last child of the ParentNode. {{domxref("DOMString")}} objects are inserted as equivalent {{domxref("Text")}} nodes.
+
{{domxref("ParentNode.prepend()")}} {{experimental_inline}}
+
Inserts a set of {{domxref("Node")}} objects or {{domxref("DOMString")}} objects before the first child of the ParentNode. {{domxref("DOMString")}} objects are inserted as equivalent {{domxref("Text")}} nodes.
+
{{domxref("ParentNode.querySelector()")}}
+
Returns the first {{domxref("Element")}} with the current element as root that matches the specified group of selectors.
+
{{domxref("ParentNode.querySelectorAll()")}}
+
Returns a {{domxref("NodeList")}} representing a list of elements with the current element as root that matches the specified group of selectors.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#parentnode', 'ParentNode')}}{{Spec2('DOM WHATWG')}}Added the append() and prepend() methods.
{{SpecName('DOM4', '#parentnode', 'ParentNode')}}{{Spec2('DOM4')}}Splitted the ElementTraversal interface in {{domxref("ChildNode")}} and ParentNode. The firstElementChild, lastElementChild, and childElementCount properties are now defined on the latter.
+ The {{domxref("Document")}} and {{domxref("DocumentFragment")}} implemented the new interfaces.
+ Added the children property and the querySelector() and querySelectorAll() methods.
{{SpecName('Element Traversal', '#interface-elementTraversal', 'ElementTraversal')}}{{Spec2('Element Traversal')}}Added the initial definition of its properties to the ElementTraversal pure interface and used it on {{domxref("Element")}}.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support (on {{domxref("Element")}}){{CompatChrome(1.0)}}{{CompatGeckoDesktop("1.9.1")}}9.0 [1]10.04.0
Support on {{domxref("Document")}} and {{domxref("DocumentFragment")}} {{experimental_inline}}{{CompatChrome(29.0)}}{{CompatGeckoDesktop(25)}}{{CompatNo}}16.0{{CompatNo}}
append() and prepend() {{experimental_inline}}{{CompatChrome(54.0)}}{{CompatGeckoDesktop(49)}}{{CompatVersionUnknown}}{{CompatOpera(39)}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewFirefox Mobile (Gecko)IE MobileOpera MobileSafari MobileChrome for Mobile
Basic support (on {{domxref("Element")}}){{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("1.9.1")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
Support on {{domxref("Document")}} and {{domxref("DocumentFragment")}} {{experimental_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(25)}}{{CompatNo}}16.0{{CompatNo}}{{CompatVersionUnknown}}
append() and prepend() {{experimental_inline}}{{CompatNo}}{{CompatChrome(54.0)}}{{CompatGeckoMobile(49)}}{{CompatNo}}{{CompatOperaMobile(39)}}{{CompatNo}}{{CompatChrome(54.0)}}
+
+ +

[1] Internet Explorer 6, 7 and 8 supported it, but erroneously returns {{domxref("Comment")}} nodes as part of the results.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/payment_request_api/index.html b/files/zh-tw/web/api/payment_request_api/index.html new file mode 100644 index 0000000000..d9953e4cfd --- /dev/null +++ b/files/zh-tw/web/api/payment_request_api/index.html @@ -0,0 +1,117 @@ +--- +title: Payment Request API +slug: Web/API/Payment_Request_API +translation_of: Web/API/Payment_Request_API +--- +
{{DefaultAPISidebar("Payment Request API")}}{{securecontext_header}}
+ +

Payment Request API 提供商家與用戶雙方一致的用戶體驗。它並不是嶄新的支付方式、而是讓用戶選擇偏好的支付方式、並把該方式提供給商家。

+ +

Payment Request 的概念和用法

+ +

很多放棄線上購物的問題,與結帳表單的填寫有關:填寫這些東西既困難又耗時、步驟還極度繁雜。Payment Request API正是為減少、甚至擺脫要完成表單所需的填寫步驟而生。它藉由不假手 HTML 表單的情況下,記下要傳給商家的用戶資訊,來簡化結帳步驟。

+ +

針對信用卡付款,使用 Payment Request API 的好處有:

+ + + +

要請求支付的話,建立 {{domxref("PaymentRequest")}} 物件的網頁,將回應用戶發動付款的行為,像是點選「購物」按鈕。PaymentRequest 將允許網頁在用戶提供完成交易所需資訊時交換之。

+ +

你可以在 使用 Payment Request API 文章看到完整教學。

+ +
+

注意:此 API 只有在設定 {{htmlattrxref("allowpaymentrequest","iframe")}} 屬性下,才可支援跨域 {{htmlelement("iframe")}} 元素。

+
+ +

介面

+ +
+
{{domxref('PaymentAddress')}}
+
地址資訊物件,具體用途有付款與送達。
+
{{domxref('PaymentRequest')}}
+
提供 API 以便建立與管理{{Glossary("用戶代理")}}的付款介面物件。
+
{{domxref('PaymentRequestEvent')}}
+
建立 {{domxref("PaymentRequest")}} 時發送給付款處理器(payment handler)的事件。
+
{{domxref('PaymentRequestUpdateEvent')}}
+
允許網頁針對用戶行為,發動更新用戶付款資訊的請求。
+
{{domxref('PaymentMethodChangeEvent')}}
+
表示用戶更改付款工具(例如從信用卡轉為簽帳金融卡)。
+
{{domxref('PaymentResponse')}}
+
在用戶選取付款方法、並同意付款請求後,所回傳的物件。
+
{{domxref('MerchantValidationEvent')}}
+
表示商家(網站)要求使用特定支付方法的瀏覽器驗證處理器(例如:要不要放行 Apple Pay)
+
+ +

字詞(dictionary)

+ +
+
{{domxref("AddressErrors")}}
+
此字詞包含任何與 {{domxref("PaymentAddress")}} entry 錯誤相關的描述性解釋字串。
+
{{domxref("PayerErrors")}}
+
此字詞包含任何與 {{domxref("PaymentResponse")}} 的 email、電話、名字屬性(name attribute)錯誤相關之描述性解釋字串。
+
{{domxref("PaymentDetailsUpdate")}}
+
此物件描述伺服器在用戶開始互動前、實例化支付界面後,針對行為需要修改的付款資訊。
+
+ + + + +
+
{{domxref("BasicCardChangeDetails")}}
+
An object providing redacted address information that is provided as the {{domxref("PaymentMethodChangeEvent.methodDetails", "methodDetails")}} on the {{event("paymentmethodchange")}} event sent to the {{domxref("PaymentRequest")}} when the user changes payment information.
+
{{domxref("BasicCardErrors")}}
+
An object providing any error messages associated with the fields in the {{domxref("BasicCardResponse")}} object that are not valid. This is used as the value of the {{domxref("PaymentValidationErrors.paymentMethod", "paymentMethod")}} property on the {{domxref("PaymentValidationErrors")}} object sent to the {{domxref("PaymentRequest")}} when an error occurs.
+
{{domxref('BasicCardRequest')}}
+
Defines an object structure for containing payment request details such as card type.
+
{{domxref('BasicCardResponse')}}
+
Defines an object structure for payment response details such as the number/expiry date of the card used to make the payment, and the billing address.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('Payment')}}{{Spec2('Payment')}}初始定義。
{{SpecName('Basic Card Payment')}}{{Spec2('Basic Card Payment')}}定義 {{domxref("BasicCardRequest")}} 與 {{domxref("BasicCardResponse")}},提供處理信用卡付款所需的事務。
{{SpecName('Payment Method Identifiers')}}{{Spec2('Payment Method Identifiers')}}提供付款方法標識、驗證方法、還有 where applicable, minted and formally registered with the W3C。
+ +

瀏覽器相容性

+ +

PaymentRequest 介面

+ +

{{Compat("api.PaymentRequest", 0)}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/paymentrequest/index.html b/files/zh-tw/web/api/paymentrequest/index.html new file mode 100644 index 0000000000..033ce47312 --- /dev/null +++ b/files/zh-tw/web/api/paymentrequest/index.html @@ -0,0 +1,80 @@ +--- +title: PaymentRequest +slug: Web/API/PaymentRequest +translation_of: Web/API/PaymentRequest +--- +
{{securecontext_header}}{{APIRef("Payment Request API")}}
+ +

PaymentRequest 介面是 Payment Request API 的主要切入點,它能讓網頁或 app 接受終端用戶的付款。

+ +

建構子

+ +
+
{{domxref('PaymentRequest.PaymentRequest()','PaymentRequest()')}} {{securecontext_inline}}
+
建立新的 PaymentRequest 物件。
+
+ +

屬性

+ +
+
{{domxref('PaymentRequest.id')}} {{readonlyinline}}{{securecontext_inline}}
+
個別 PaymentRequest 的唯一標識符(unique identifier),可透過 details.id 設定之。若尚未指定,預設為 UUID。
+
{{domxref('PaymentRequest.shippingAddress')}} {{readonlyinline}} {{securecontext_inline}}
+
若透過付款設定(payment options)請求的話,回傳用戶指定的運送地址,以便計算運輸事宜。只有在呼叫的建構子 requestShipping flag 為 true 時,此屬性才能作動。另外,部份瀏覽器會出於隱私上的理由而只節錄部分地址,除非用戶表示交易手續即將完成(例如按下「付款」鈕)。
+
{{domxref('PaymentRequest.shippingOption')}} {{readonlyinline}} {{securecontext_inline}}
+
回傳的運送選項的標識符。只有在呼叫的建構子 requestShipping flag 為 true 時,此屬性才能作動。
+
{{domxref('PaymentRequest.shippingType')}} {{readonlyinline}} {{securecontext_inline}}
+
回傳用於完成交易的運送類型。可以是 shipping, delivery, pickup, 或在建構子未提供的情形下:null
+
+ +

事件處理器

+ +
+
{{domxref('PaymentRequest.onshippingaddresschange')}} {{securecontext_inline}}
+
用戶修改運送地址時觸發之。
+
{{domxref('PaymentRequest.onshippingoptionchange')}} {{securecontext_inline}}
+
用戶修改運送選項時觸發之。
+
{{domxref('PaymentRequest.onpaymentmethodchange')}} {{securecontext_inline}}
+
針對付款方法(如 Apple Pay),用戶修改支付方式時觸發之,比方說從信用卡改為簽帳卡。
+
{{domxref('PaymentRequest.onmerchantvalidation')}} {{securecontext_inline}}
+
針對付款方法(如 Apple Pay),本事件會呼叫 {{event("merchantvalidation")}} 事件,在用戶代理要求驗證付款商家或供應商是否合法時觸發之。
+
+ +

方法

+ +
+
{{domxref('PaymentRequest.canMakePayment()')}} {{securecontext_inline}}
+
在呼叫 show() 前告訴 PaymentRequest 物件能不能付款。
+
+ +
+
{{domxref('PaymentRequest.show()')}} {{securecontext_inline}}
+
讓用戶代理開始付款請求的用戶交互。
+
{{domxref('PaymentRequest.abort()')}} {{securecontext_inline}}
+
讓用戶代理結束付款請求並刪除可能顯示的任何用戶界面。
+
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('Payment','#paymentrequest-interface','PaymentRequest')}}{{Spec2('Payment')}}初始定義。
+ +

瀏覽器相容性

+ +
+ + +

{{Compat("api.PaymentRequest")}}

+
diff --git a/files/zh-tw/web/api/performance.timing/index.html b/files/zh-tw/web/api/performance.timing/index.html new file mode 100644 index 0000000000..33d0a54171 --- /dev/null +++ b/files/zh-tw/web/api/performance.timing/index.html @@ -0,0 +1,56 @@ +--- +title: Performance.timing +slug: Web/API/Performance.timing +tags: + - API + - Navigation Timing + - Performance + - Property + - Read-only + - 唯讀 + - 屬性 + - 效能 +translation_of: Web/API/Performance/timing +--- +

{{APIRef("Performance")}}

+ +

摘要

+ +

Performance.timing 是唯讀的屬性,傳回的 {{domxref("PerformanceTiming")}} 物件當中包含了效能與時間延遲相關的資訊。

+ +

語法

+ +
timingInfo = performance.timing;
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態備註
{{SpecName('Navigation Timing', '#sec-window.performance-attribute', 'Performance.timing')}}{{Spec2('Navigation Timing')}}初步定義
+ +

瀏覽器支援狀況

+ +
+
+ + +

{{Compat("api.Performance.timing")}}

+
+
+ +

參照

+ + diff --git a/files/zh-tw/web/api/performance/index.html b/files/zh-tw/web/api/performance/index.html new file mode 100644 index 0000000000..017efb71e1 --- /dev/null +++ b/files/zh-tw/web/api/performance/index.html @@ -0,0 +1,140 @@ +--- +title: Performance +slug: Web/API/Performance +tags: + - API + - Interface + - Navigation Timing + - NeedsTranslation + - Performance + - Reference + - TopicStub + - Web Performance +translation_of: Web/API/Performance +--- +
{{APIRef("High Resolution Time")}}
+ +

The Performance interface provides access to performance-related information for the current page. It's part of the High Resolution Time API, but is enhanced by the Performance Timeline API, the Navigation Timing API, the User Timing API, and the Resource Timing API.

+ +

An object of this type can be obtained by calling the {{domxref("Window.performance")}} read-only attribute.

+ +
+

Note: This interface and its members are available in Web Workers, except where indicated below. Also note that performance markers and measures are per context. If you create a mark on the main thread (or other worker), you cannot see it in a worker thread, and vice versa.

+
+ +

Properties

+ +

The Performance interface doesn't inherit any properties.

+ +
+
{{deprecated_inline}} {{domxref("Performance.navigation")}} {{readonlyInline}}
+
A {{domxref("PerformanceNavigation")}} object that provides useful context about the operations included in the times listed in timing, including whether the page was a load or a refresh, how many redirections occurred, and so forth.
+
{{deprecated_inline}}  {{domxref("Performance.timing")}} {{readonlyInline}}
+
A {{domxref("PerformanceTiming")}} object containing latency-related performance information. Not available in workers.
+
{{domxref("Performance.memory", "performance.memory")}} {{Non-standard_inline}}
+
A non-standard extension added in Chrome, this property provides an object with basic memory usage information. You should not use this non-standard API.
+
{{domxref("Performance.timeOrigin")}} {{readonlyInline}} {{Non-standard_inline}}
+
Returns the high resolution timestamp of the start time of the performance measurement.
+
+ +
+
+

Event handlers

+
+
{{domxref("Performance.onresourcetimingbufferfull")}}
+
An {{domxref("EventTarget")}} which is a callback that will be called when the {{event("resourcetimingbufferfull")}} event is fired.
+
+ +

Methods

+ +

The Performance interface doesn't inherit any methods.

+ +
+
{{domxref("Performance.clearMarks()")}}
+
Removes the given mark from the browser's performance entry buffer.
+
{{domxref("Performance.clearMeasures()")}}
+
Removes the given measure from the browser's performance entry buffer.
+
{{domxref("Performance.clearResourceTimings()")}}
+
Removes all {{domxref("PerformanceEntry","performance entries")}} with a {{domxref("PerformanceEntry.entryType","entryType")}} of "resource" from the browser's performance data buffer.
+
{{domxref("Performance.getEntries()")}}
+
Returns a list of {{domxref("PerformanceEntry")}} objects based on the given filter.
+
{{domxref("Performance.getEntriesByName()")}}
+
Returns a list of {{domxref("PerformanceEntry")}} objects based on the given name and entry type.
+
{{domxref("Performance.getEntriesByType()")}}
+
Returns a list of {{domxref("PerformanceEntry")}} objects of the given entry type.
+
{{domxref("Performance.mark()")}}
+
Creates a {{domxref("DOMHighResTimeStamp","timestamp")}} in the browser's performance entry buffer with the given name.
+
{{domxref("Performance.measure()")}}
+
Creates a named {{domxref("DOMHighResTimeStamp","timestamp")}} in the browser's performance entry buffer between two specified marks (known as the start mark and end mark, respectively).
+
{{domxref("Performance.now()")}}
+
Returns a {{domxref("DOMHighResTimeStamp")}} representing the number of milliseconds elapsed since a reference instant.
+
{{domxref("Performance.setResourceTimingBufferSize()")}}
+
Sets the browser's resource timing buffer size to the specified number of "resource" {{domxref("PerformanceEntry.entryType","type")}} {{domxref("PerformanceEntry","performance entry")}} objects.
+
{{domxref("Performance.toJSON()")}}
+
Is a jsonizer returning a json object representing the Performance object.
+
+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Highres Time Level 3', '#dom-performance-timeorigin','timeOrigin')}}{{Spec2('Highres Time Level 3')}}Defines timeOrigin property.
{{SpecName('Highres Time Level 2', '#the-performance-interface', 'toJSON()')}}{{Spec2('Highres Time Level 2')}}Defines toJson() method.
{{SpecName('Highres Time', '#the-performance-interface', 'Performance')}}{{Spec2('Highres Time')}}Defines now() method.
{{SpecName('Navigation Timing', '#sec-window.performance-attribute', 'Performance')}}{{Spec2('Navigation Timing')}}Defines timing and navigation properties.
{{SpecName('Performance Timeline Level 2', '#extensions-to-the-performance-interface', 'Performance extensions')}}{{Spec2('Performance Timeline Level 2')}}Changes getEntries() interface.
{{SpecName('Performance Timeline', '#sec-window.performance-attribute', 'Performance extensions')}}{{Spec2('Performance Timeline')}}Defines getEntries(), getEntriesByType() and getEntriesByName() methods.
{{SpecName('Resource Timing', '#extensions-performance-interface', 'Performance extensions')}}{{Spec2('Resource Timing')}}Defines clearResourceTimings() and setResourceTimingBufferSize() methods and the onresourcetimingbufferfull property.
{{SpecName('User Timing Level 2', '#extensions-performance-interface', 'Performance extensions')}}{{Spec2('User Timing Level 2')}}Clarifies mark(), clearMark(), measure() and clearMeasure() methods.
{{SpecName('User Timing', '#extensions-performance-interface', 'Performance extensions')}}{{Spec2('User Timing')}}Defines mark(), clearMark(), measure() and clearMeasure() methods.
+ +

Browser compatibility

+ +
+ + +

{{Compat("api.Performance")}}

+
diff --git a/files/zh-tw/web/api/pointer_lock_api/index.html b/files/zh-tw/web/api/pointer_lock_api/index.html new file mode 100644 index 0000000000..e37e5ceea5 --- /dev/null +++ b/files/zh-tw/web/api/pointer_lock_api/index.html @@ -0,0 +1,285 @@ +--- +title: Pointer Lock API +slug: Web/API/Pointer_Lock_API +translation_of: Web/API/Pointer_Lock_API +--- +

{{ SeeCompatTable() }}

+ +

Pointer lock (之前稱為 Mouse lock) 提供「隨時間經過所產生的滑鼠位移資訊 (即 deltas)」的輸入方法,而不只是滑鼠游標的絕對位置而已。此函式可存取基本的滑鼠位移、將滑鼠事件的目標鎖定至單一元素、讓滑鼠單一方向的位移距離不再受限、將游標移除到視點之外。

+ +

若 App 需要大量的滑鼠輸入以控制位移、旋轉物件、更改輸入項,那此 API 就特別有用。另對特別注重視覺效果的 App 尤其必要,如第一人稱視角、3D 視圖、模型建構等。

+ +

舉例來說,你可讓消費者不需點擊任何按鈕,只要透過滑鼠即可控制視角。而按鈕可用於其他動作。對於查看地圖、衛星圖像、第一人稱場景類 (如遊戲或虛擬實境影片) 的 App 來說,這種滑鼠輸入方式特別方便易用。

+ +

即使滑鼠游標移出瀏覽器或螢幕之外,Pointer lock 還是能讓你存取滑鼠事件。舉例來說,消費者還是可繼續移動滑鼠以旋轉或操作 3D 模型。若沒有 Pointer lock,則只要指標移出瀏覽器或螢幕之外,旋轉或操作隨即停止。遊戲玩家會特別喜歡此功能。他們現在可以隨便亂按按鈕並隨意滑動滑鼠;不再擔心滑鼠游標滑出遊戲區域而點到其他應用程式,結果退出遊戲發生慘案!

+ +

基本概念

+ +

Pointer lock 與 mouse capture 相關。在拖曳滑鼠時,Mouse capture 可持續向目標元素傳遞事件,且只要放開滑鼠按鈕隨即跟著停止。Pointer lock 與 mouse capture 不同之處在於:

+ + + +

範例

+ +

下列範例可讓你設定自己網頁上的 Pointer lock。

+ +
<button onclick="lockPointer();">Lock it!</button>
+<div id="pointer-lock-element"></div>
+<script>
+// Note: at the time of writing, only Mozilla and WebKit support Pointer Lock.
+
+// The element we'll make fullscreen and pointer locked.
+var elem;
+
+document.addEventListener("mousemove", function(e) {
+  var movementX = e.movementX       ||
+                  e.mozMovementX    ||
+                  e.webkitMovementX ||
+                  0,
+      movementY = e.movementY       ||
+                  e.mozMovementY    ||
+                  e.webkitMovementY ||
+                  0;
+
+  // Print the mouse movement delta values
+  console.log("movementX=" + movementX, "movementY=" + movementY);
+}, false);
+
+function fullscreenChange() {
+  if (document.webkitFullscreenElement === elem ||
+      document.mozFullscreenElement === elem ||
+      document.mozFullScreenElement === elem) { // Older API upper case 'S'.
+    // Element is fullscreen, now we can request pointer lock
+    elem.requestPointerLock = elem.requestPointerLock    ||
+                              elem.mozRequestPointerLock ||
+                              elem.webkitRequestPointerLock;
+    elem.requestPointerLock();
+  }
+}
+
+document.addEventListener('fullscreenchange', fullscreenChange, false);
+document.addEventListener('mozfullscreenchange', fullscreenChange, false);
+document.addEventListener('webkitfullscreenchange', fullscreenChange, false);
+
+function pointerLockChange() {
+  if (document.mozPointerLockElement === elem ||
+      document.webkitPointerLockElement === elem) {
+    console.log("Pointer Lock was successful.");
+  } else {
+    console.log("Pointer Lock was lost.");
+  }
+}
+
+document.addEventListener('pointerlockchange', pointerLockChange, false);
+document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+
+function pointerLockError() {
+  console.log("Error while locking pointer.");
+}
+
+document.addEventListener('pointerlockerror', pointerLockError, false);
+document.addEventListener('mozpointerlockerror', pointerLockError, false);
+document.addEventListener('webkitpointerlockerror', pointerLockError, false);
+
+function lockPointer() {
+  elem = document.getElementById("pointer-lock-element");
+  // Start by going fullscreen with the element. Current implementations
+  // require the element to be in fullscreen before requesting pointer
+  // lock--something that will likely change in the future.
+  elem.requestFullscreen = elem.requestFullscreen    ||
+                           elem.mozRequestFullscreen ||
+                           elem.mozRequestFullScreen || // Older API upper case 'S'.
+                           elem.webkitRequestFullscreen;
+  elem.requestFullscreen();
+}
+</script>
+
+ +

函式/屬性概述

+ +

Pointer lock API 與 Fullscreen API 類似,可添增 requestPointerLock 新函式 (目前尚未標準化) 而擴充 DOM 元素。可為下列:

+ +
element.webkitRequestPointerLock(); // Chrome
+element.mozRequestPointerLock(); // Firefox
+element.requestPointerLock(); // Standard
+ +

目前在建置 requestPointerLock 時,還是必須緊密結合 requestFullScreen 與 Fullscreen API。在指標鎖定某一元素之前,必須先進入全螢幕模式。如同上方的 Demo,指標鎖定屬於非同步程序,並透過 pointerlockchangepointerlockerror 事件,指出該請求是否成功。此與 Fullscreen API 的運作方式相同 (使用其 requestFullScreen 函式,另搭配 fullscreenchangefullscreenerror 事件)。

+ +

Pointer lock API 另擴充了 Document 介面,同時添增了新的屬性與函式。如果目前有鎖定的元素,則新的屬性可存取該所訂元素,並命名為 pointerLockElement (目前尚未標準化)。Document 上的新函式則為 exitPointerLock;顧名思義,此函式可退出 Pointer lock。

+ +

pointerLockElement 屬性可確定指標目前是否鎖定了任何元素 (例如進行 Boolean 檢查)。若確實有鎖定的元素,則可取得參考。以下為此二種用法的範例:

+ +
document.pointerLockElement = document.pointerLockElement    ||
+                              document.mozPointerLockElement ||
+                              document.webkitPointerLockElement;
+
+// 1) Used as a boolean check: are we pointer locked?
+if (!!document.pointerLockElement) {
+  // pointer is locked
+} else {
+  // pointer is not locked
+}
+
+// 2) Used to access the pointer locked element
+if (document.pointerLockElement === someElement) {
+  // someElement is currently pointer locked
+}
+
+ +

Document.exitPointerLock 函式則用以退出 Pointer lock。且和 requestPointerLock 一樣,Document.exitPointerLock 是使用 pointerlockchangepointerlockerror 事件,以非同步方式作業:

+ +
document.exitPointerLock = document.exitPointerLock    ||
+                           document.mozExitPointerLock ||
+                           document.webkitExitPointerLock;
+
+function pointerLockChange() {
+  document.pointerLockElement = document.pointerLockElement    ||
+                                document.mozPointerLockElement ||
+                                document.webkitPointerLockElement;
+
+  if (!!document.pointerLockElement) {
+    console.log("Still locked.");
+  } else {
+    console.log("Exited lock.");
+  }
+}
+
+document.addEventListener('pointerlockchange', pointerLockChange, false);
+document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+
+// Attempt to unlock
+document.exitPointerLock();
+
+ +

pointerlockchange 事件

+ +

若 Pointer lock 狀態改變,如呼叫 requestPointerLockexitPointerLock,或使用者按下 ESC 鍵等。則 pointerlockchange 事件隨即傳送至 document。此簡單事件不包含額外資料。

+ +
此事件目前在 Firefox 中的前綴為 mozpointerlockchange;在 Chrome 中的前綴為 webkitpointerlockchange
+ +

pointerlockerror 事件

+ +

當呼叫 requestPointerLockexitPointerLock 而發生錯誤時,隨即傳送 pointerlockerror 事件至 document。此簡單事件不包含額外資料。

+ +
此事件在 Firefox 中的前綴為 mozpointerlockerror;在 Chrome 中的前綴為 webkitpointerlockerror
+ +

擴充至滑鼠事件

+ +

Pointer lock API 可透過位移屬性而擴充標準的 MouseEvent 介面。

+ +
partial interface MouseEvent {
+    readonly attribute long movementX;
+    readonly attribute long movementY;
+};
+ +
位移屬性目前在 Firefox 中的前綴為 .mozMovementX.mozMovementY;在 Chrome 中的前綴為.webkitMovementX.webkitMovementY
+ +

滑鼠事件的二個新參數 (即 movementXmovementY) 將提供滑鼠位置的變化情形。此二項參數的值,等於 MouseEvent 屬性值 (即 screenXscreenY) 之間的變化;而 MouseEvent 屬性另儲存於二項連續的 mousemove 事件 (即 eNow 與 ePrevious) 之內。換句話說,Pointer lock 參數 movementX = eNow.screenX - ePrevious.screenX

+ +

鎖定狀態

+ +

在啟動 Pointer lock 之後,標準的 MouseEvent 屬性 clientXclientYscreenXscreenY 均維持不變,如同滑鼠沒有移動。movementXmovementY 屬性將持續提供滑鼠的位置變化。如果滑鼠朝單一方向持續移動,movementXmovementY 的值也就不受限。此時「滑鼠游標」的概念不存在,游標無法移出視窗之外,也不會受限於螢幕邊界。

+ +

未鎖定狀態

+ +

無論滑鼠的鎖定狀態為何,movementXmovementY 參數均保持有效;另為了方便起見,甚至在未鎖定狀態下仍可保持有效。

+ +

在解鎖滑鼠之後,系統游標可退出並重新進入瀏覽器視窗,且 movementXmovementY 此時可能設定為零。

+ +

iframe 限制

+ +

Pointer lock 一次僅能鎖定一組 iframe。在鎖定一組 iframe 之後,就無法鎖定另一組 iframe 並轉移目標至該 iframe 之上;Pointer lock 將發生錯誤。為擺脫此限制,必須先將鎖定的 iframe 解鎖,再鎖定另一組 iframe。

+ +

由於 iframes 是根據預設值運作,因此預設為「沙箱式 (sandboxed)」的 iframes 將阻擋 Pointer lock。為擺脫此限制,Chrome 應該很快就會推出 <iframe sandbox="allow-pointer-lock"> 的「屬性/值」整合形式。

+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Pointer Lock')}}{{Spec2('Pointer Lock')}}Initial specification.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support +

Targeting 23{{ property_prefix("webkit") }}*

+ +

See CR/72574

+
+

{{ CompatGeckoDesktop("14.0") }}

+ +

{{bug("633602") }}

+
{{ CompatNo() }}{{ CompatNo() }}{{ CompatNo() }}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{ CompatNo() }}{{ CompatNo() }}{{ CompatNo() }}{{ CompatNo() }}{{ CompatNo() }}
+
+ +

* 需啟動 about:flags 中的功能;或以 --enable-pointer-lock 旗標啟動 Chrome。

+ +

另可參閱

+ + diff --git a/files/zh-tw/web/api/positionoptions/enablehighaccuracy/index.html b/files/zh-tw/web/api/positionoptions/enablehighaccuracy/index.html new file mode 100644 index 0000000000..8437f37fe6 --- /dev/null +++ b/files/zh-tw/web/api/positionoptions/enablehighaccuracy/index.html @@ -0,0 +1,93 @@ +--- +title: PositionOptions.enableHighAccuracy +slug: Web/API/PositionOptions/enableHighAccuracy +translation_of: Web/API/PositionOptions/enableHighAccuracy +--- +
{{APIRef("Geolocation API")}}
+ +

PositionOptions.enableHighAccuracy 是一個 {{domxref("Boolean")}} 的值。此值指出方法是否需要回傳最佳的結果。如果值為真且該裝置是具備提供精準位置的能力,則方法會回傳最佳結果。必須注意的是最佳結果會導致較長的回應時間或者需要更多的電力耗損 (舉例來說擁有GPS晶片的手機)。相反來說,如果值為偽,機器會因為回應時間較短以及消耗較少的電力達到資源節省。預設值:偽。

+ +

語法

+ +
positionOptions.enableHighAccuracy = booleanValue
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#enablehighaccuracy', 'PositionOptions.enableHighAccuracy')}}{{Spec2('Geolocation')}}Initial definition
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/positionoptions/index.html b/files/zh-tw/web/api/positionoptions/index.html new file mode 100644 index 0000000000..fc27485e65 --- /dev/null +++ b/files/zh-tw/web/api/positionoptions/index.html @@ -0,0 +1,105 @@ +--- +title: PositionOptions +slug: Web/API/PositionOptions +translation_of: Web/API/PositionOptions +--- +
{{APIRef("Geolocation API")}}
+ +

PositionOptions 是一個當作 {{domxref("Geolocation.getCurrentPosition()")}} 以及 {{domxref("Geolocation.watchPosition()")}} 參數的物件,此物件含有幾種可以設定的屬性。

+ +

屬性

+ +

PositionOptions 介面沒有繼承任何屬性

+ +
+
{{domxref("PositionOptions.enableHighAccuracy")}}
+
是一個 {{domxref("Boolean")}} 的值。此值指出方法是否需要回傳最佳的結果。如果值為真且該裝置具備提供精準位置的能力,則方法會回傳最佳結果。必須注意的是最佳結果會導致較長的回應時間或者需要更多的電力耗損 (舉例來說擁有GPS晶片的手機)。相反來說,如果值為偽,機器會因為回應時間較短以及消耗較少的電力達到資源節省。預設值:偽。
+
{{domxref("PositionOptions.timeout")}}
+
這是一個正值,它代表機器能夠等待方法回傳位置的最長時間(單位是毫秒)。預設值是 Infinity,代表 getCurrentPosition() 此方法在沒有可用的位置前不會有任何回覆。
+
{{domxref("PositionOptions.maximumAge")}}
+
這是一個正值,它代表可以接受暫存位置的最長時限(單位是毫秒)。如果設定為 0,代表機器必須回傳實際的當前位置而不能使用暫存位置。如果設定為 Infinity,機器必定會回傳暫存位置而不考慮他的時限。預設值:0。
+
+ +

方法

+ +

PositionOptions 介面沒有實現也沒有繼承任何方法。

+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#positionoptions', 'PositionOptions')}}{{Spec2('Geolocation')}}Initial definition
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/positionoptions/maximumage/index.html b/files/zh-tw/web/api/positionoptions/maximumage/index.html new file mode 100644 index 0000000000..2f9d1cf48e --- /dev/null +++ b/files/zh-tw/web/api/positionoptions/maximumage/index.html @@ -0,0 +1,93 @@ +--- +title: PositionOptions.maximumAge +slug: Web/API/PositionOptions/maximumAge +translation_of: Web/API/PositionOptions/maximumAge +--- +
{{APIRef("Geolocation API")}}
+ +

PositionOptions.maximumAge 是一個正值,它代表可以接受暫存位置的最長期限(單位是毫秒)。如果設定為 0,代表機器必須回傳實際的當前位置而不能使用暫存位置。如果設定為 Infinity, 機器必定會回傳暫存位置而不考慮他的期限。預設值:0。

+ +

語法

+ +
positionOptions.maximumAge = timeLength
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#maximumage', 'PositionOptions.maximumAge')}}{{Spec2('Geolocation')}}Initial definition
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/positionoptions/timeout/index.html b/files/zh-tw/web/api/positionoptions/timeout/index.html new file mode 100644 index 0000000000..f963a28764 --- /dev/null +++ b/files/zh-tw/web/api/positionoptions/timeout/index.html @@ -0,0 +1,93 @@ +--- +title: PositionOptions.timeout +slug: Web/API/PositionOptions/timeout +translation_of: Web/API/PositionOptions/timeout +--- +
{{APIRef("Geolocation API")}}
+ +

是一個正值,它代表機器能夠等待方法回傳位置的最長時間(單位是毫秒)。預設值是Infinity,代表 getCurrentPosition() 此方法在沒有可用的位置前不會有任何回覆。

+ +

語法

+ +
positionOptions.timeout = timeLength
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Geolocation', '#timeout', 'PositionOptions.timeout')}}{{Spec2('Geolocation')}}Initial definition
+ +

瀏覽器的相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support5{{CompatGeckoDesktop("1.9.1")}}910.60
+ {{CompatNo}} 15.0
+ 16.0
5
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("4")}}{{CompatUnknown}}10.60{{CompatUnknown}}
+
+ +

請參考

+ + diff --git a/files/zh-tw/web/api/progressevent/index.html b/files/zh-tw/web/api/progressevent/index.html new file mode 100644 index 0000000000..250df9b338 --- /dev/null +++ b/files/zh-tw/web/api/progressevent/index.html @@ -0,0 +1,161 @@ +--- +title: ProgressEvent +slug: Web/API/ProgressEvent +translation_of: Web/API/ProgressEvent +--- +

{{APIRef("DOM Events")}}

+ +

The ProgressEvent interface represents events measuring progress of an underlying process, like an HTTP request (for an XMLHttpRequest, or the loading of the underlying resource of an {{HTMLElement("img")}}, {{HTMLElement("audio")}}, {{HTMLElement("video")}}, {{HTMLElement("style")}} or {{HTMLElement("link")}}).

+ +

建構式

+ +
+
{{domxref("ProgressEvent.ProgressEvent", "ProgressEvent()")}}
+
Creates a ProgressEvent event with the given parameters.
+
+ +

屬性

+ +

Also inherits properties from its parent {{domxref("Event")}}.

+ +
+
{{domxref("ProgressEvent.lengthComputable")}} {{readonlyInline}}
+
Is a {{domxref("Boolean")}} flag indicating if the total work to be done, and the amount of work already done, by the underlying process is calculable. In other words, it tells if the progress is measurable or not.
+
{{domxref("ProgressEvent.loaded")}} {{readonlyInline}}
+
Is an unsigned long long representing the amount of work already performed by the underlying process. The ratio of work done can be calculated with the property and ProgressEvent.total. When downloading a resource using HTTP, this only represent the part of the content itself, not headers and other overhead.
+
{{domxref("ProgressEvent.total")}} {{readonlyInline}}
+
Is an unsigned long long representing the total amount of work that the underlying process is in the progress of performing. When downloading a resource using HTTP, this only represent the content itself, not headers and other overhead.
+
+ +

方法

+ +
+
+ +

Also inherits methods from its parent {{domxref("Event")}}.

+ +
+
{{domxref("ProgressEvent.initProgressEvent()")}} {{deprecated_inline}}{{non-Standard_inline}}
+
Initializes a ProgressEvent created using the deprecated {{domxref("Document.createEvent()", "Document.createEvent(\"ProgressEvent\")")}} method.
+
+ +

範例

+ +

The following example adds a ProgressEvent to a new {{domxref("XMLHTTPRequest")}} and uses it to display the status of the request.

+ +
  var progressBar = document.getElementById("p"),
+      client = new XMLHttpRequest()
+  client.open("GET", "magical-unicorns")
+  client.onprogress = function(pe) {
+    if(pe.lengthComputable) {
+      progressBar.max = pe.total
+      progressBar.value = pe.loaded
+    }
+  }
+  client.onloadend = function(pe) {
+    progressBar.value = pe.loaded
+  }
+  client.send()
+ +

規格

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Progress Events', '#interface-progressevent', 'ProgressEvent')}}{{Spec2('Progress Events')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0{{CompatGeckoDesktop("1.9.1")}}10.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
initProgressEvent() {{non-standard_inline}}{{deprecated_inline}}{{CompatNo}}[1]{{CompatNo}}[2]10.0{{CompatNo}}[4]{{CompatNo}}[3]
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewFirefox Mobile (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("1.9.1")}}10.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
initProgressEvent() {{non-standard_inline}}{{deprecated_inline}}{{CompatNo}}[3]{{CompatNo}}{{CompatNo}}[2]10.0{{CompatNo}}[4]{{CompatNo}}[3]{{CompatNo}}
+
+ +

[1] This feature was implemented in Chrome 1.0, but removed in Chrome 17.0.

+ +

[2] This feature was implemented in Gecko 1.9.1 {{geckoRelease("1.9.1")}}, but removed in Gecko 22 {{geckoRelease("22")}}.

+ +

[3] This feature was removed at some point.

+ +

[4] This feature was removed in Opera 15.0.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/proximity_events/index.html b/files/zh-tw/web/api/proximity_events/index.html new file mode 100644 index 0000000000..f6464480f8 --- /dev/null +++ b/files/zh-tw/web/api/proximity_events/index.html @@ -0,0 +1,118 @@ +--- +title: Proximity +slug: Web/API/Proximity_Events +translation_of: Web/API/Proximity_Events +--- +

{{ SeeCompatTable }}

+

摘要

+

近距 (Proximity) 事件可迅速感測出使用者靠近裝置,並迅速做出反應。舉例來說,當使用者接通來電並將裝置靠近耳朵時,智慧型手機隨即關閉螢幕。

+
+

注意:顯然裝置必須具備近距感測器 (Proximity sensor),此 API 才能發揮作用。而目前幾乎只有行動裝置搭載接近感測器。若裝置並未搭載感測器,則雖同樣可支援,但永遠不會觸發此類事件。

+
+

近距事件

+

只要近距感測器測得「裝置」與「物體」之間的距離改變時,就會通知瀏覽器這項變化。而只要瀏覽器獲得通知,隨即啟動 DeviceProximityEvent 以因應任何變化;或啟動 UserProximityEvent 以因應簡單的變化。

+

透過 addEventListener 函式 (使用 {{event("deviceproximity")}} 或 {{event("userproximity")}} 事件名稱);或將事件處理器 (Event handler) 附掛至 window.ondeviceproximitywindow.onuserproximity 屬性,均可於 window 物件層級就擷取到此事件。

+

在擷取事件之後,事件物件將可存取不同的資訊:

+ +

範例

+
window.addEventListener('userproximity', function(event) {
+  if (event.near) {
+    // let's power off the screen
+    navigator.mozPower.screenEnabled = false;
+  } else {
+    // Otherwise, let's power on the screen
+    navigator.mozPower.screenEnabled = true;
+  }
+});
+

規格

+ + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('Proximity Events', '', 'Proximity Events') }}{{ Spec2('Proximity Events') }}Initial specification
+

瀏覽器相容性

+

{{ CompatibilityTable() }}

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
{{domxref("DeviceProximityEvent")}}{{CompatNo()}}{{CompatVersionUnknown()}}{{CompatNo()}}{{CompatNo()}}{{CompatNo()}}
{{domxref("UserProximityEvent")}}{{CompatNo()}}{{CompatVersionUnknown()}}{{CompatNo()}}{{CompatNo()}}{{CompatNo()}}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
{{domxref("DeviceProximityEvent")}}{{CompatNo()}}{{CompatNo()}}{{ CompatGeckoMobile("15.0") }}{{CompatNo()}}{{CompatNo()}}{{CompatNo()}}
{{domxref("UserProximityEvent")}}{{CompatNo()}}{{CompatNo()}}{{CompatVersionUnknown()}}{{CompatNo()}}{{CompatNo()}}{{CompatNo()}}
+
+

另可參閱

+ diff --git a/files/zh-tw/web/api/range/index.html b/files/zh-tw/web/api/range/index.html new file mode 100644 index 0000000000..35307c4628 --- /dev/null +++ b/files/zh-tw/web/api/range/index.html @@ -0,0 +1,249 @@ +--- +title: Range +slug: Web/API/Range +translation_of: Web/API/Range +--- +

{{ APIRef("DOM") }}

+ +

Range 介面代表一個文件的片段(fragment),可以包含節點及部分的文字節點。

+ +

A range can be created using the {{ domxref("Document.createRange", "createRange()") }} method of the {{ domxref("Document") }} object. Range objects can also be retrieved by using the {{ domxref("Selection/getRangeAt", "getRangeAt()") }} method of the {{ domxref("Selection") }} object or the {{domxref("Document/caretRangeFromPoint", "caretRangeFromPoint()")}} method of the {{domxref("Document")}} object.

+ +

There also is the {{domxref("Range.Range()", "Range()")}} constructor available.

+ +

屬性

+ +

There are no inherited properties.

+ +
+
{{domxref("Range.collapsed")}} {{readonlyInline}}
+
Returns a {{domxref("Boolean")}} indicating whether the range's start and end points are at the same position.
+
{{domxref("Range.commonAncestorContainer")}} {{readonlyInline}}
+
Returns the deepest {{ domxref("Node") }} that contains the startContainer and endContainer nodes.
+
{{domxref("Range.endContainer")}} {{readonlyInline}}
+
Returns the {{ domxref("Node") }} within which the Range ends.
+
{{domxref("Range.endOffset")}} {{readonlyInline}}
+
Returns a number representing where in the endContainer the Range ends.
+
{{domxref("Range.startContainer")}} {{readonlyInline}}
+
Returns the {{ domxref("Node") }} within which the Range starts.
+
{{domxref("Range.startOffset")}} {{readonlyInline}}
+
Returns a number representing where in the startContainer the Range starts.
+
+ +

建構式

+ +
+
{{ domxref("Range.Range()", "Range()") }} {{experimental_inline}}
+
Returns a Range object with the global {{domxref("Document")}} as its start and end.
+
+ +

方法

+ +

There are no inherited methods.

+ +
+
{{ domxref("Range.setStart()")}}
+
Sets the start position of a Range.
+
{{ domxref("Range.setEnd()")}}
+
Sets the end position of a Range.
+
{{ domxref("Range.setStartBefore()")}}
+
Sets the start position of a Range relative to another {{ domxref("Node") }}.
+
{{ domxref("Range.setStartAfter()")}}
+
Sets the start position of a Range relative to another {{ domxref("Node") }}.
+
{{ domxref("Range.setEndBefore()")}}
+
Sets the end position of a Range relative to another {{ domxref("Node") }}.
+
{{ domxref("Range.setEndAfter()")}}
+
Sets the end position of a Range relative to another {{ domxref("Node") }}.
+
{{ domxref("Range.selectNode()")}}
+
Sets the Range to contain the {{ domxref("Node") }} and its contents.
+
{{ domxref("Range.selectNodeContents()")}}
+
Sets the Range to contain the contents of a {{ domxref("Node") }}.
+
{{ domxref("Range.collapse()")}}
+
Collapses the Range to one of its boundary points.
+
{{ domxref("Range.cloneContents()")}}
+
Returns a {{ domxref("DocumentFragment") }} copying the nodes of a Range.
+
{{ domxref("Range.deleteContents()")}}
+
Removes the contents of a Range from the {{ domxref("Document") }}.
+
{{ domxref("Range.extractContents()")}}
+
Moves contents of a Range from the document tree into a {{ domxref("DocumentFragment") }}.
+
{{ domxref("Range.insertNode()")}}
+
Insert a {{ domxref("Node") }} at the start of a Range.
+
{{ domxref("Range.surroundContents()")}}
+
Moves content of a Range into a new {{ domxref("Node") }}.
+
{{ domxref("Range.compareBoundaryPoints()")}}
+
Compares the boundary points of the Range with another Range.
+
{{ domxref("Range.cloneRange()")}}
+
Returns a Range object with boundary points identical to the cloned Range.
+
{{ domxref("Range.detach()")}}
+
Releases the Range from use to improve performance.
+
{{ domxref("Range.toString()")}}
+
Returns the text of the Range.
+
{{ domxref("Range.compareNode()")}} {{ Obsolete_inline }}{{non-standard_inline}}
+
Returns a constant representing whether the {{domxref("Node")}} is before, after, inside, or surrounding the range.
+
{{ domxref("Range.comparePoint()")}} {{experimental_inline}}
+
Returns -1, 0, or 1 indicating whether the point occurs before, inside, or after the Range.
+
{{ domxref("Range.createContextualFragment()")}}{{experimental_inline}}
+
Returns a {{ domxref("DocumentFragment") }} created from a given string of code.
+
{{ domxref("Range.getBoundingClientRect()") }} {{experimental_inline}}
+
Returns a {{ domxref("DOMRect") }} object which bounds the entire contents of the Range; this would be the union of all the rectangles returned by {{ domxref("range.getClientRects()") }}.
+
{{ domxref("Range.getClientRects()") }} {{experimental_inline}}
+
Returns a list of {{ domxref("DOMRect") }} objects that aggregates the results of {{ domxref("Element.getClientRects()") }} for all the elements in the Range.
+
{{ domxref("Range.intersectsNode()")}} {{experimental_inline}}
+
Returns a boolean indicating whether the given node intersects the Range.
+
{{ domxref("Range.isPointInRange()")}} {{experimental_inline}}
+
Returns a boolean indicating whether the given point is in the Range.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#interface-range', 'Range')}}{{Spec2('DOM WHATWG')}}Do not use RangeException anymore, use DOMException instead.
+ Made the second parameter of collapse() optional.
+ Added the methods isPointInRange(), comparePoint(), and intersectsNode().
+ Added the constructor Range().
{{SpecName('DOM Parsing', '#extensions-to-the-range-interface', 'Extensions to Range')}}{{Spec2('DOM Parsing')}}Added the method createContextualFragment().
{{SpecName('CSSOM View', '#extensions-to-the-range-interface', 'Extensions to Range')}}{{Spec2('CSSOM View')}}Added the methods getClientRects() and getBoundingClientRect().
{{SpecName('DOM2 Traversal_Range', 'ranges.html#Level-2-Range-Interface', 'Range')}}{{Spec2('DOM2 Traversal_Range')}}Initial specification.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.0")}} [1]9.09.0{{CompatVersionUnknown}}
Range() constructor {{experimental_inline}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatGeckoDesktop("24.0")}}{{CompatNo}}15.0{{CompatVersionUnknown}}
compareNode() {{obsolete_inline}}{{non-standard_inline()}}{{CompatNo}}{{CompatUnknown}}{{CompatGeckoDesktop("1.0")}}
+ Removed in {{CompatGeckoDesktop("1.9")}}
{{CompatNo}}{{CompatNo}}{{CompatNo}}
isPointInRange(), and comparePoint(){{experimental_inline}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatNo}}15.0{{CompatUnknown}}
intersectsNode() {{experimental_inline}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatGeckoDesktop("17.0")}} [2]{{CompatNo}}15.0{{CompatUnknown}}
getClientRects() and getBoundingClientRect(){{experimental_inline}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("2.0")}}915.05
createContextualFragment(){{experimental_inline}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}1115.0{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("1.0")}} [1]9.09.0{{CompatVersionUnknown}}
+
+ +

[1] Starting with Gecko 13.0 {{ geckoRelease("13.0") }} the Range object throws a {{ domxref("DOMException") }} as defined in DOM 4, instead of a RangeException defined in prior specifications.

+ +

[2] Gecko supported it up to Gecko 1.9, then removed it until Gecko 17 where it was reimplemented, matching the spec.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/response/index.html b/files/zh-tw/web/api/response/index.html new file mode 100644 index 0000000000..8899c22fa5 --- /dev/null +++ b/files/zh-tw/web/api/response/index.html @@ -0,0 +1,120 @@ +--- +title: Response +slug: Web/API/Response +translation_of: Web/API/Response +--- +
{{APIRef("Fetch API")}}
+ +

Fetch API  的 Response 介面代表了一個請求會返回的回應。

+ +

你可以用 {{domxref("Response.Response()")}} 建構子創建一個新的 Response物件。但實務上碰到 Response 物件的時機,比較常出現在進行了一個 API 操作後,得到返回的 Response 物件。舉例而言,使用 service worker {{domxref("Fetchevent.respondWith")}} 或是使用單純的{{domxref("GlobalFetch.fetch()")}}。

+ +

建構子

+ +
+
{{domxref("Response.Response","Response()")}}
+
創建一個新的  Response 物件。
+
+ +

屬性

+ +
+
{{domxref("Response.headers")}} {{readonlyinline}}
+
包含與此 response 相關的 {{domxref("Headers")}} 物件。
+
{{domxref("Response.ok")}} {{readonlyinline}}
+
無論此 response 是不是成功 ( 狀態碼 200-299 ) 都會包含一個 boolean 狀態。
+
{{domxref("Response.redirected")}} {{ReadOnlyInline}}
+
指出此 response 是不是個重新導向的結果,如果是的話,代表此 URL 具有一個以上的入口。
+
{{domxref("Response.status")}} {{readonlyinline}}
+
包含此  response  的狀態碼(例如:成功時為 200 )。
+
{{domxref("Response.statusText")}} {{readonlyinline}}
+
包含狀態碼所對應的狀態文字 (例如: OK 對應 200)。
+
{{domxref("Response.type")}} {{readonlyinline}}
+
包含此 response 的類型 (例如: basic, cors)。
+
{{domxref("Response.url")}} {{readonlyinline}}
+
包含此 response 的 URL。
+
{{domxref("Response.useFinalURL")}}
+
包含一個 boolean 狀態,指出此 URL 是否為此 response 的最後一步。
+
+ +

Response 實做了{{domxref("Body")}}, 所以它另有以下可用的屬性:

+ +
+
{{domxref("Body.body")}} {{readonlyInline}}
+
A simple getter used to expose a {{domxref("ReadableStream")}} of the body contents.
+
{{domxref("Body.bodyUsed")}} {{readonlyInline}}
+
Stores a {{domxref("Boolean")}} that declares whether the body has been used in a response yet.
+
+ +

方法

+ +
+
{{domxref("Response.clone()")}}
+
建立一份  Response 的複製物件。
+
{{domxref("Response.error()")}}
+
Returns a new Response object associated with a network error.
+
{{domxref("Response.redirect()")}}
+
Creates a new response with a different URL.
+
+ +

Response implements {{domxref("Body")}}, so it also has the following methods available to it:

+ +
+
{{domxref("Body.arrayBuffer()")}}
+
Takes a {{domxref("Response")}} stream and reads it to completion. It returns a promise that resolves with an {{domxref("ArrayBuffer")}}.
+
{{domxref("Body.blob()")}}
+
Takes a {{domxref("Response")}} stream and reads it to completion. It returns a promise that resolves with a {{domxref("Blob")}}.
+
{{domxref("Body.formData()")}}
+
Takes a {{domxref("Response")}} stream and reads it to completion. It returns a promise that resolves with a {{domxref("FormData")}} object.
+
{{domxref("Body.json()")}}
+
Takes a {{domxref("Response")}} stream and reads it to completion. It returns a promise that resolves with the result of parsing the body text as {{jsxref("JSON")}}.
+
{{domxref("Body.text()")}}
+
Takes a {{domxref("Response")}} stream and reads it to completion. It returns a promise that resolves with a {{domxref("USVString")}} (text).
+
+ +

範例

+ +

基本 fetch 範例 (run example live) 中,我們使用 fetch() 呼叫來得到圖片,並使用 {{htmlelement("img")}} tag 顯示。 這裡的fetch() 呼叫返回了一個 promise,它使用與資源 fetch 操作有關的 Response 進行解析。你可能有發現,由於我們要求的是一張圖片,所以需要用 {{domxref("Body.blob")}} ({{domxref("Response")}} 時做了 body) 讓 response 有正確的 MIME 類型。

+ +
const image = document.querySelector('.my-image');
+fetch('flowers.jpg').then(function(response) {
+  return response.blob();
+}).then(function(blob) {
+  const objectURL = URL.createObjectURL(blob);
+  image.src = objectURL;
+});
+ +

除此之外,你也能用 {{domxref("Response.Response()")}} 建構子去建立自己的客製化 Response 物件:

+ +
const response = new Response();
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Fetch','#response-class','Response')}}{{Spec2('Fetch')}}Initial definition
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Response")}}

+ +

參考

+ + diff --git a/files/zh-tw/web/api/screen/index.html b/files/zh-tw/web/api/screen/index.html new file mode 100644 index 0000000000..089203003f --- /dev/null +++ b/files/zh-tw/web/api/screen/index.html @@ -0,0 +1,89 @@ +--- +title: Screen +slug: Web/API/Screen +translation_of: Web/API/Screen +--- +
{{APIRef("CSSOM View")}}
+ +

Screen 介面表示了一個用戶端螢幕,通常是指呈現目前頁面的視窗。

+ +

一般來說為顯示目前網頁的視窗,可以透過 window.screen 取得物件實體。

+ +

屬性

+ +
+
{{domxref("Screen.availTop")}}
+
Specifies the y-coordinate of the first pixel that is not allocated to permanent or semipermanent user interface features.
+
{{domxref("Screen.availLeft")}}
+
Returns the first available pixel available from the left side of the screen.
+
{{domxref("Screen.availHeight")}}
+
Specifies the height of the screen, in pixels, minus permanent or semipermanent user interface features displayed by the operating system, such as the Taskbar on Windows.
+
{{domxref("Screen.availWidth")}}
+
Returns the amount of horizontal space in pixels available to the window.
+
{{domxref("Screen.colorDepth")}}
+
Returns the color depth of the screen.
+
{{domxref("Screen.height")}}
+
Returns the height of the screen in pixels.
+
{{domxref("Screen.left")}}
+
Returns the distance in pixels from the left side of the main screen to the left side of the current screen.
+
{{domxref("Screen.orientation")}}
+
Returns the current orientation of the screen.
+
{{domxref("Screen.pixelDepth")}}
+
Gets the bit depth of the screen.
+
{{domxref("Screen.top")}}
+
Returns the distance in pixels from the top side of the current screen.
+
{{domxref("Screen.width")}}
+
Returns the width of the screen.
+
{{domxref("Screen.mozEnabled")}} {{gecko_minversion_inline("12.0")}}
+
Boolean. Setting to false will turn off the device's screen.
+
{{domxref("Screen.mozBrightness")}} {{gecko_minversion_inline("12.0")}}
+
Controls the brightness of a device's screen. A double between 0 and 1.0 is expected.
+
+ +

事件處理器

+ +
+
{{domxref("Screen.onorientationchange")}}
+
A handler for the {{event("orientationchange")}} events.
+
+ +

方法

+ +
+
{{domxref("Screen.lockOrientation")}}
+
Lock the screen orientation (only works in fullscreen or for installed apps)
+
{{domxref("Screen.unlockOrientation")}}
+
Unlock the screen orientation (only works in fullscreen or for installed apps)
+
+ +

Methods inherit from {{domxref("EventTarget")}}

+ +

{{page("/en-US/docs/Web/API/EventTarget","Methods")}}

+ +

範例

+ +
if (screen.pixelDepth < 8) {
+  // use low-color version of page
+} else {
+  // use regular, colorful page
+}
+
+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('CSSOM View', '#the-screen-interface', 'Screen') }}{{ Spec2('CSSOM View') }} 
diff --git a/files/zh-tw/web/api/screen/orientation/index.html b/files/zh-tw/web/api/screen/orientation/index.html new file mode 100644 index 0000000000..eafa89a703 --- /dev/null +++ b/files/zh-tw/web/api/screen/orientation/index.html @@ -0,0 +1,114 @@ +--- +title: Screen.orientation +slug: Web/API/Screen/orientation +translation_of: Web/API/Screen/orientation +--- +
{{APIRef("CSSOM View")}}{{SeeCompatTable}}
+ +

Screen.orientation 屬性可以取得螢幕目前的方向。

+ +

語法

+ +
var orientation = window.screen.orientation.type;
+
+ +

回傳值

+ +

回傳值為一個代表螢幕方向的字串,可能是 portrait-primaryportrait-secondarylandscape-primarylandscape-secondary(請參考 {{domxref("window.screen.lockOrientation","lockOrientation")}} 以瞭解更多資訊)。

+ +

範例

+ +
var orientation = screen.orientation || screen.mozOrientation || screen.msOrientation;
+
+if (orientation.type === "landscape-primary") {
+  console.log("That looks good.");
+} else if (orientation.type === "landscape-secondary") {
+  console.log("Mmmh... the screen is upside down!");
+} else if (orientation.type === "portrait-secondary" || orientation.type === "portrait-primary") {
+  console.log("Mmmh... you should rotate your device to landscape");
+}
+
+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Screen Orientation', '', 'Screen Orientation')}}{{Spec2('Screen Orientation')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support38{{CompatVersionUnknown}} {{property_prefix("moz")}}[1]11{{property_prefix("ms")}}[2]25{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatNo}}39{{CompatVersionUnknown}} {{property_prefix("moz")}}[1]{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

[1] This API is only implemented as a prefixed method (mozOrientation) in B2G and Firefox for Android.

+ +

[2] This API is implemented using a prefix (msOrientation) in Internet Explorer for Windows 8.1 and Windows RT 8.1. It is not supported on Windows 7.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/server-sent_events/index.html b/files/zh-tw/web/api/server-sent_events/index.html new file mode 100644 index 0000000000..bb72cb3f93 --- /dev/null +++ b/files/zh-tw/web/api/server-sent_events/index.html @@ -0,0 +1,115 @@ +--- +title: Server-sent events +slug: Web/API/Server-sent_events +translation_of: Web/API/Server-sent_events +--- +

網頁一般來說是由客戶端向伺服器請求資料. 藉由 server-sent 事件, 伺服器在任何時候都可以向客戶端推送資料. 即將推送進來的訊息可以自客戶端上做 Events + data 處理.

+ + + + + + + + +
+

文件

+ +
+
使用 server-sent events
+
有關如何在伺服器端和客戶端使用 server-sent 事件的教學文章.
+
參考 EventSource
+
關於客戶端的 EventSource API.
+
+ +

瀏覽全部...

+
+

工具

+ + + + + + +
+ +

參見

+ + + +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Server-sent events')}}{{Spec2('Server-sent events')}}Initial definition.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
EventSource support9{{CompatGeckoDesktop("6.0")}}{{CompatUnknown}}115
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
EventSource support{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
diff --git a/files/zh-tw/web/api/server-sent_events/using_server-sent_events/index.html b/files/zh-tw/web/api/server-sent_events/using_server-sent_events/index.html new file mode 100644 index 0000000000..92433f4f18 --- /dev/null +++ b/files/zh-tw/web/api/server-sent_events/using_server-sent_events/index.html @@ -0,0 +1,202 @@ +--- +title: 使用 server-sent 事件 +slug: Web/API/Server-sent_events/Using_server-sent_events +tags: + - Advanced + - Communication + - DOM + - EventSource + - Guide + - SSE + - Server Sent Events + - Server-Sent-Event +translation_of: Web/API/Server-sent_events/Using_server-sent_events +--- +

{{DefaultAPISidebar("Server Sent Events")}}

+ +
+

開發一個使用 server-sent 事件的網頁應用程式很簡單。在伺服器端只需要一些的程式碼與網頁串流事件,而客戶端這邊的處理進入事件的部分幾乎跟 websockets 一樣。這是一種單向的連線,所以你無法從客戶端向伺服器傳送事件。

+
+ +

從伺服器端接收事件

+ +

server-sent event API 包含在  {{domxref("EventSource")}} 介面;為了與伺服器端開啟連線並接收事件,需要建立帶有產生事件 script URL 的 {{domxref("EventSource")}} 物件。例如:

+ +
const evtSource = new EventSource("ssedemo.php");
+ +

如果事件產生的 script 在不同源的伺服器上,在建立 {{domxref("EventSource")}} 物件時需要同時提供 URL 和第二個參數作為選項設定。假設客戶端的 script 伺服於 example.com

+ +
const evtSource = new EventSource("//api.example.com/ssedemo.php", { withCredentials: true } );
+ +

當你完成初始化事件來源後,你就可以透過新增 {{event("message")}} 事件的處理器來開始監聽來自伺服器的訊息:

+ +
evtSource.onmessage = function(event) {
+  const newElement = document.createElement("li");
+  const eventList = document.getElementById("list");
+
+  newElement.innerHTML = "message: " + event.data;
+  eventList.appendChild(newElement);
+}
+
+ +

上述的程式碼會監聽進入的訊息(這裡來自伺服器的通知沒有指明 event 欄位,所以統一用 onmessage 處理即可)並且把訊息的文字附加到 document 的清單。

+ +

你也可以利用 addEventListener() 監聽事件:

+ +
evtSource.addEventListener("ping", function(event) {
+  const newElement = document.createElement("li");
+  const time = JSON.parse(event.data).time;
+  newElement.innerHTML = "ping at " + time;
+  eventList.appendChild(newElement);
+});
+
+ +

上述的程式碼大同小異,不同之處在於若伺服器傳送了 event 欄位值為「ping」的訊息時它就會把 data 欄位的值解析為 JSON 並輸出到畫面上。

+ +
+

當連線不是透過 HTTP/2 時,SSE 會受到最大連線數限制所苦,尤其當開啟多個分頁。每個瀏覽器有自己的限制數而且被限制在很低的數量(6)。這個問題已經被 ChromeFirefox 標註為「Won't fix」(不修復)。限制是基於每個瀏覽器 + 網域,也就是說你可以針對 www.example1.com 網域在所有的分頁中開啟六個 SSE 連線,另一個網域 www.example2.com 也可以開啟六個(根據 Stackoverflow)。當使用 HTTP/2 時最大同時 HTTP streams 連線數是由伺服器和客戶端之間協調(預設 100)。

+
+ +

從伺服器發送事件

+ +

由伺服器端所發送的事件需要使用 text/event-stream 的 MIME 類型回應。每一個通知皆由一組文字組成並由一對換行結尾。如何處理事件串流的格式,請參考 {{ anch("Event stream format") }} 。

+ +

下面是一個 {{Glossary("PHP")}} 範例:

+ +
date_default_timezone_set("America/New_York");
+header("Cache-Control: no-cache");
+header("Content-Type: text/event-stream");
+
+$counter = rand(1, 10);
+while (true) {
+  // Every second, send a "ping" event.
+
+  echo "event: ping\n";
+  $curDate = date(DATE_ISO8601);
+  echo 'data: {"time": "' . $curDate . '"}';
+  echo "\n\n";
+
+  // Send a simple message at random intervals.
+
+  $counter--;
+
+  if (!$counter) {
+    echo 'data: This is a message at time ' . $curDate . "\n\n";
+    $counter = rand(1, 10);
+  }
+
+  ob_end_flush();
+  flush();
+
+  // Break the loop if the client aborted the connection (closed the page)
+
+  if ( connection_aborted() ) break;
+
+  sleep(1);
+}
+
+ +

上述的程式碼會在每秒產生一個類型為「ping」的事件。每一個事件的資料是一個 JSON 物件,內容為事件產生時的 ISO 8601 時間戳。同時會隨機發送一個簡易訊息(沒有事件類型)。
+ 迴圈的執行會獨立於連線的狀態,,所以在迴圈裡必須檢查連線的狀態,若斷線了要關閉連線(譬如,客戶端關閉了網頁)。

+ +
+

備註: 你可以從下列的 Github 文章中找到包含本文所使用程式碼的完整範例 —— 參考 Simple SSE demo using PHP.

+
+ +

錯誤處理

+ +

當錯誤發生時(譬如網路逾時或有關存取控制的問題)會產生錯誤事件。你可以透過對 EventSource 物件實作 onerror 回呼的方式採取程式化的處理:

+ +
evtSource.onerror = function(err) {
+  console.error("EventSource failed:", err);
+};
+
+ +

關閉事件串流

+ +

預設的情況下,如果客戶端和伺服器的連線關閉則連線會被重啟。連線的關閉會伴隨著 .close() 方法的執行。

+ +
evtSource.close();
+ +

事件串流(Event Stream)格式

+ +

事件串流是個簡易的文字資料串流,內容必須以 UTF-8 格式編碼。在事件串流中,不同的訊息以一對換行符號做區隔。若要撰寫註解,則要在該行的開頭加上冒號(:)。

+ +
備註: 註解將有助於防止連線逾時;伺服器端可以定時發送註解以維持連線活著。
+ +

每一個訊息是由一到多列的欄位所組成的文字。每個欄位依序由欄位的名稱、冒號、該欄位的文字內容所組合而成。

+ +

欄位

+ +

每隔訊息皆可以由下列的欄位組合而成,每個欄位以換行做為區隔:

+ +
+
event
+
事件的類型。如果有指定則在瀏覽器端會對該事件名稱的監聽器發布事件;網頁的原始碼必須使用 addEventListener() 來監聽已命名的事件。 onmessage 處理器只有在訊息沒有指定事件名稱時才會被呼叫。
+
data
+
訊息的資料欄位。當 EventSource 連續接收到多列以 data: 開頭的內容;它會串接這些內容並為每一列插入一個換行字元。最後的換行會被移除。
+
id
+
{{domxref("EventSource")}} 物件的最新一個事件 ID 。
+
retry
+
當嘗試傳送事件時重新連線的時間。這個值必須是整數,單位是毫秒,作為重新連線的時間。若指定是非整數則這個欄位會被忽略。
+
+ +

除上述的幾個欄位,其他欄位均會被忽略。

+ +
備註:如果某列的內容沒有包含冒號,則該列的內容都會被視為欄位名稱及空字串的欄位值。
+ +

範例

+ +

Data-only 訊息

+ +

在下列的範例中,共發送了三個訊息。第一個是註解,因其以冒號開頭。如之前提到的,對不會持續發送訊息的情境下,這將有助於維持連線的存續。

+ +

第二則訊息包含了 data 欄位及「some text」的值。第三則訊息包含了 data 欄位及「another message\nwith two lines」。注意在內容所出現的換行符號。

+ +
: this is a test stream
+
+data: some text
+
+data: another message
+data: with two lines
+
+ +

命名事件

+ +

這個範例傳送了一些命名的事件。每一個事件都被指定了 event 欄位並且 data 欄位也有相應的 JSON 字串作為客戶端回應事件所需的資料。 data 欄位的內容可以是任何的字串;它並沒有強制必須以 JSON 的格式撰寫。

+ +
event: userconnect
+data: {"username": "bobby", "time": "02:33:48"}
+
+event: usermessage
+data: {"username": "bobby", "time": "02:34:11", "text": "Hi everyone."}
+
+event: userdisconnect
+data: {"username": "bobby", "time": "02:34:23"}
+
+event: usermessage
+data: {"username": "sean", "time": "02:34:36", "text": "Bye, bobby."}
+
+ +

混合及配對

+ +

你並非一定只能用未命名訊息或已分類的事件;實際上你可以在單一的事件中把它們混合在一起。

+ +
event: userconnect
+data: {"username": "bobby", "time": "02:33:48"}
+
+data: Here's a system message of some kind that will get used
+data: to accomplish some task.
+
+event: usermessage
+data: {"username": "bobby", "time": "02:34:11", "text": "Hi everyone."}
+ +
+

EventSource

+ +
+ + +

{{Compat("api.EventSource")}}

+
+
diff --git a/files/zh-tw/web/api/storage/index.html b/files/zh-tw/web/api/storage/index.html new file mode 100644 index 0000000000..b3990bf756 --- /dev/null +++ b/files/zh-tw/web/api/storage/index.html @@ -0,0 +1,106 @@ +--- +title: Storage +slug: Web/API/Storage +translation_of: Web/API/Storage +--- +
 
+ +
{{APIRef("Web Storage API")}}
+ +

Web Storage API 中的 Storage 介面提供了存取特定 domain session 及本機儲存的方法。舉例而言,它能夠對存取的資料進行新增、刪除、修改,

+ +

在操作上,如果是對象是 domain session storage ,會呼叫 {{domxref("Window.sessionStorage")}} 。而若是 local storage,則呼叫 {{domxref("Window.localStorage")}} 。

+ +

屬性

+ +
+
{{domxref("Storage.length")}} {{readonlyInline}}
+
返回一數字,代表儲存在 Storage 中的物件的數量。
+
+ +

方法

+ +
+
{{domxref("Storage.key()")}}
+
當傳入一數字 n, 會返回 storage 裡第 n 個值的 key 值。
+
+ +
+
{{domxref("Storage.getItem()")}}
+
當傳入一 key 值, 會返回 storage 裡此 key 值對應的 value 。
+
{{domxref("Storage.setItem()")}}
+
當傳入 key 及 value 的值, 會在 storage 裡新增此 key 及 value 值,若 key 已存在,則會把值更新成傳入的 value。
+
{{domxref("Storage.removeItem()")}}
+
當傳入一 key 值, 會把此 key 從 storage 裡刪除。
+
{{domxref("Storage.clear()")}}
+
執行此方法,會刪除所有在 storage 裡的 key。
+
+ +

範例

+ +

在這裡,我們藉由呼叫 localStorage 來存取 Storage 物件,首先使用 !localStorage.getItem('bgcolor') 來確認 storage 裡是否有項目存在。

+ +

如果有,則執行函示 setStyles() ,這個函示使用 {{domxref("Storage.getItem()")}} 取得 storage 的值,並且用這些值更新頁面樣式 。

+ +

如果沒有,便執行另一個函示 populateStorage(),他使用 {{domxref("Storage.setItem()")}} 先設定 storage 項目的值,然後才執行setStyles()

+ +
if(!localStorage.getItem('bgcolor')) {
+  populateStorage();
+}
+setStyles();
+
+function populateStorage() {
+  localStorage.setItem('bgcolor', document.getElementById('bgcolor').value);
+  localStorage.setItem('font', document.getElementById('font').value);
+  localStorage.setItem('image', document.getElementById('image').value);
+}
+
+function setStyles() {
+  var currentColor = localStorage.getItem('bgcolor');
+  var currentFont = localStorage.getItem('font');
+  var currentImage = localStorage.getItem('image');
+
+  document.getElementById('bgcolor').value = currentColor;
+  document.getElementById('font').value = currentFont;
+  document.getElementById('image').value = currentImage;
+
+  htmlElem.style.backgroundColor = '#' + currentColor;
+  pElem.style.fontFamily = currentFont;
+  imgElem.setAttribute('src', currentImage);
+}
+ +
+

注意: 想要看這個範例完整運行,可以參考我們的  Web Storage Demo.

+
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', 'webstorage.html#the-storage-interface', 'Storage')}}{{Spec2('HTML WHATWG')}} 
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Storage")}}

+ +

See also

+ + diff --git a/files/zh-tw/web/api/touch/index.html b/files/zh-tw/web/api/touch/index.html new file mode 100644 index 0000000000..3dc1a243b0 --- /dev/null +++ b/files/zh-tw/web/api/touch/index.html @@ -0,0 +1,207 @@ +--- +title: Touch +slug: Web/API/Touch +translation_of: Web/API/Touch +--- +

{{ APIRef("Touch Events") }}

+ +

Touch 介面表示了一個於觸控裝置上接觸的單一觸碰點。觸碰點通常是由手指或觸控筆所接觸,而裝置可能為觸控螢幕或觸控板。

+ +

{{ domxref("Touch.radiusX") }}、{{ domxref("Touch.radiusY") }} 及 {{ domxref("Touch.rotationAngle") }} 描述了使用者與螢幕之間接觸的區域—觸碰區(touch area),這對處理不精確的指向設備(如手指)來說相當有幫助。這些數值被用來描述一個盡可能與整個接觸面積相匹配的橢圓(如使用者的指尖)。{{experimental_inline}}

+ +
+

Note: Many of the properties' values are hardware-dependent; for example, if the device doesn't have a way to detect the amount of pressure placed on the surface, the force value will always be 0. This may also be the case for radiusX and radiusY; if the hardware reports only a single point, these values will be 1.

+
+ +

建構式

+ +
+
{{domxref("Touch.Touch", "Touch()")}} {{experimental_inline}}
+
Creates a Touch object.
+
+ +

屬性

+ +

This interface has no parent, and doesn't inherits or implements any other property.

+ +

基本屬性

+ +
+
{{ domxref("Touch.identifier") }} {{readonlyInline}}
+
Returns a unique identifier for this Touch object. A given touch point (say, by a finger) will have the same identifier for the duration of its movement around the surface. This lets you ensure that you're tracking the same touch all the time.
+
{{ domxref("Touch.screenX") }} {{readonlyInline}}
+
Returns the X coordinate of the touch point relative to the left edge of the screen.
+
{{ domxref("Touch.screenY") }} {{readonlyInline}}
+
Returns the Y coordinate of the touch point relative to the top edge of the screen.
+
{{ domxref("Touch.clientX") }} {{readonlyInline}}
+
Returns the X coordinate of the touch point relative to the left edge of the browser viewport, not including any scroll offset.
+
{{ domxref("Touch.clientY") }} {{readonlyInline}}
+
Returns the Y coordinate of the touch point relative to the top edge of the browser viewport, not including any scroll offset.
+
{{ domxref("Touch.pageX") }} {{readonlyInline}}
+
Returns the X coordinate of the touch point relative to the left edge of the document. Unlike clientX, this value includes the horizontal scroll offset, if any.
+
{{ domxref("Touch.pageY") }} {{readonlyInline}}
+
Returns the Y coordinate of the touch point relative to the top of the document. Unlike clientY, this value includes the vertical scroll offset, if any.
+
{{ domxref("Touch.target") }} {{readonlyInline}}
+
Returns the {{ domxref("Element")}} on which the touch point started when it was first placed on the surface, even if the touch point has since moved outside the interactive area of that element or even been removed from the document.
+
+ +

觸碰區(Touch area)

+ +

{{SeeCompatTable}}

+ +
+
{{ domxref("Touch.radiusX") }} {{readonlyInline}} {{experimental_inline}}
+
Returns the X radius of the ellipse that most closely circumscribes the area of contact with the screen. The value is in pixels of the same scale as screenX.
+
{{ domxref("Touch.radiusY") }} {{readonlyInline}} {{experimental_inline}}
+
Returns the Y radius of the ellipse that most closely circumscribes the area of contact with the screen. The value is in pixels of the same scale as screenY.
+
{{ domxref("Touch.rotationAngle") }} {{readonlyInline}} {{experimental_inline}}
+
Returns the angle (in degrees) that the ellipse described by radiusX and radiusY must be rotated, clockwise, to most accurately cover the area of contact between the user and the surface.
+
{{ domxref("Touch.force") }}{{readonlyInline}} {{experimental_inline}}
+
Returns the amount of pressure being applied to the surface by the user, as a float between 0.0 (no pressure) and 1.0 (maximum pressure).
+
+ +

方法

+ +

This interface has no method and no parent, and doesn't inherits or implements any method.

+ +
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Touch Events 2', '#touch-interface', 'Touch')}}{{Spec2('Touch Events 2')}}Added radiusX, radiusY, rotationAngle, force properties, as well as the Touch() constructor.
{{SpecName('Touch Events', '#touch-interface', 'Touch')}}{{Spec2('Touch Events')}}Initial definition.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome("22.0")}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("18.0")}}[1]
+ {{CompatGeckoDesktop("52.0")}}[2]
{{CompatNo}}{{CompatNo}}{{CompatNo}}
radiusX, radiusY, rotationAngle, force{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
Touch() constructor{{CompatUnknown}}{{CompatNo}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewChrome for AndroidEdgeFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("6.0")}}{{CompatVersionUnknown}}11{{CompatVersionUnknown}}{{CompatVersionUnknown}}
radiusX, radiusY, rotationAngle, force{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("6.0")}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
Touch() constructor{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatNo}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Touch events were implemented in Gecko 18.0, but removed again in 24.0 {{geckoRelease("24.0")}} on the desktop version of Firefox due to web compatibility issues ({{bug(888304)}}).

+ +

[2] As of Gecko 52.0, touch events support has been fixed and reenabled in Windows desktop platforms.

+ +

參見

+ + + +
+
diff --git a/files/zh-tw/web/api/touch_events/index.html b/files/zh-tw/web/api/touch_events/index.html new file mode 100644 index 0000000000..c12a14f49c --- /dev/null +++ b/files/zh-tw/web/api/touch_events/index.html @@ -0,0 +1,387 @@ +--- +title: 觸控事件 +slug: Web/API/Touch_events +translation_of: Web/API/Touch_events +--- +
{{DefaultAPISidebar("Touch Events")}}
+ +

為了支援基於觸碰的使用者介面,觸控事件提供了解釋手指或觸控筆於觸控螢幕或觸控板上活動的資訊。

+ +

觸控事件介面為相對低階的 API,可用來支援應用程式特定的多點觸控互動,例如兩指手勢。多點觸控互動起始於手指或觸控筆於平面的第一個觸碰,其它的手指可能於其後伴隨著移動才觸碰到平面。而互動則結束於手指自觸控平面離開。在此互動期間,應用程式會於開始、移動以及結束的階段接收到觸控事件。

+ +

觸控事件類似於滑鼠事件,但觸控事件支援同時間多個觸碰及其於觸控平面的每個不同點位置。{{domxref("TouchEvent")}} 介面封裝了所有當前作用中的觸碰點。{{domxref("Touch")}} 介面則表示個別的觸碰點,包括了如觸碰點於瀏覽器 viewport 中的相對位置資訊。

+ +

定義

+ +
+
平面(Surface)
+
The touch-sensitive surface. This may be a screen or trackpad.
+
+ +
+
觸碰點(Touch point)
+
A point of contact with the surface. This may be a finger (or elbow, ear, nose, whatever, but typically a finger) or stylus.
+
+ +

介面

+ +
+
{{domxref("TouchEvent")}}
+
Represents an event that occurs when the state of touches on the surface changes.
+
{{domxref("Touch")}}
+
Represents a single point of contact between the user and the touch surface.
+
{{domxref("TouchList")}}
+
Represents a group of touches; this is used when the user has, for example, multiple fingers on the surface at the same time.
+
+ +

範例

+ +

This example tracks multiple touch points at a time, allowing the user to draw in a {{HTMLElement("canvas")}} with more than one finger at a time. It will only work on a browser that supports touch events.

+ +
Note: The text below uses the term "finger" when describing the contact with the surface, but it could, of course, also be a stylus or other contact method.
+ +

Create a canvas

+ +
<canvas id="canvas" width="600" height="600" style="border:solid black 1px;">
+  Your browser does not support canvas element.
+</canvas>
+<br>
+<button onclick="startup()">Initialize</button>
+<br>
+Log: <pre id="log" style="border: 1px solid #ccc;"></pre>
+
+ +

Setting up the event handlers

+ +

When the page loads, the startup() function shown below should be called by our {{HTMLElement("body")}} element's onload attribute (but in the example we use a button to trigger it, due to limitations of the MDN live example system).

+ +
function startup() {
+  var el = document.getElementsByTagName("canvas")[0];
+  el.addEventListener("touchstart", handleStart, false);
+  el.addEventListener("touchend", handleEnd, false);
+  el.addEventListener("touchcancel", handleCancel, false);
+  el.addEventListener("touchmove", handleMove, false);
+  log("initialized.");
+}
+
+ +

This simply sets up all the event listeners for our {{HTMLElement("canvas")}} element so we can handle the touch events as they occur.

+ +

Tracking new touches

+ +

We'll keep track of the touches in-progress.

+ +
var ongoingTouches = [];
+
+ +

When a {{event("touchstart")}} event occurs, indicating that a new touch on the surface has occurred, the handleStart() function below is called.

+ +
function handleStart(evt) {
+  evt.preventDefault();
+  log("touchstart.");
+  var el = document.getElementsByTagName("canvas")[0];
+  var ctx = el.getContext("2d");
+  var touches = evt.changedTouches;
+
+  for (var i = 0; i < touches.length; i++) {
+    log("touchstart:" + i + "...");
+    ongoingTouches.push(copyTouch(touches[i]));
+    var color = colorForTouch(touches[i]);
+    ctx.beginPath();
+    ctx.arc(touches[i].pageX, touches[i].pageY, 4, 0, 2 * Math.PI, false);  // a circle at the start
+    ctx.fillStyle = color;
+    ctx.fill();
+    log("touchstart:" + i + ".");
+  }
+}
+
+ +

This calls {{domxref("event.preventDefault()")}} to keep the browser from continuing to process the touch event (this also prevents a mouse event from also being delivered). Then we get the context and pull the list of changed touch points out of the event's {{domxref("TouchEvent.changedTouches")}} property.

+ +

After that, we iterate over all the {{domxref("Touch")}} objects in the list, pushing them onto an array of active touch points and drawing the start point for the draw as a small circle; we're using a 4-pixel wide line, so a 4 pixel radius circle will show up neatly.

+ +

Drawing as the touches move

+ +

Each time one or more fingers moves, a {{event("touchmove")}} event is delivered, resulting in our handleMove() function being called. Its responsibility in this example is to update the cached touch information and to draw a line from the previous position to the current position of each touch.

+ +
function handleMove(evt) {
+  evt.preventDefault();
+  var el = document.getElementsByTagName("canvas")[0];
+  var ctx = el.getContext("2d");
+  var touches = evt.changedTouches;
+
+  for (var i = 0; i < touches.length; i++) {
+    var color = colorForTouch(touches[i]);
+    var idx = ongoingTouchIndexById(touches[i].identifier);
+
+    if (idx >= 0) {
+      log("continuing touch "+idx);
+      ctx.beginPath();
+      log("ctx.moveTo(" + ongoingTouches[idx].pageX + ", " + ongoingTouches[idx].pageY + ");");
+      ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY);
+      log("ctx.lineTo(" + touches[i].pageX + ", " + touches[i].pageY + ");");
+      ctx.lineTo(touches[i].pageX, touches[i].pageY);
+      ctx.lineWidth = 4;
+      ctx.strokeStyle = color;
+      ctx.stroke();
+
+      ongoingTouches.splice(idx, 1, copyTouch(touches[i]));  // swap in the new touch record
+      log(".");
+    } else {
+      log("can't figure out which touch to continue");
+    }
+  }
+}
+
+ +

This iterates over the changed touches as well, but it looks in our cached touch information array for the previous information about each touch in order to determine the starting point for each touch's new line segment to be drawn. This is done by looking at each touch's {{domxref("Touch.identifier")}} property. This property is a unique integer for each touch, and remains consistent for each event during the duration of each finger's contact with the surface.

+ +

This lets us get the coordinates of the previous position of each touch and use the appropriate context methods to draw a line segment joining the two positions together.

+ +

After drawing the line, we call Array.splice() to replace the previous information about the touch point with the current information in the ongoingTouches array.

+ +

Handling the end of a touch

+ +

When the user lifts a finger off the surface, a {{event("touchend")}} event is sent. We handle both of these the same way: by calling the handleEnd() function below. Its job is to draw the last line segment for each touch that ended and remove the touch point from the ongoing touch list.

+ +
function handleEnd(evt) {
+  evt.preventDefault();
+  log("touchend");
+  var el = document.getElementsByTagName("canvas")[0];
+  var ctx = el.getContext("2d");
+  var touches = evt.changedTouches;
+
+  for (var i = 0; i < touches.length; i++) {
+    var color = colorForTouch(touches[i]);
+    var idx = ongoingTouchIndexById(touches[i].identifier);
+
+    if (idx >= 0) {
+      ctx.lineWidth = 4;
+      ctx.fillStyle = color;
+      ctx.beginPath();
+      ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY);
+      ctx.lineTo(touches[i].pageX, touches[i].pageY);
+      ctx.fillRect(touches[i].pageX - 4, touches[i].pageY - 4, 8, 8);  // and a square at the end
+      ongoingTouches.splice(idx, 1);  // remove it; we're done
+    } else {
+      log("can't figure out which touch to end");
+    }
+  }
+}
+
+ +

This is very similar to the previous function; the only real differences are that we draw a small square to mark the end and that when we call Array.splice(), we simply remove the old entry from the ongoing touch list, without adding in the updated information. The result is that we stop tracking that touch point.

+ +

Handling canceled touches

+ +

If the user's finger wanders into browser UI, or the touch otherwise needs to be canceled, the {{event("touchcancel")}} event is sent, and we call the handleCancel() function below.

+ +
function handleCancel(evt) {
+  evt.preventDefault();
+  log("touchcancel.");
+  var touches = evt.changedTouches;
+
+  for (var i = 0; i < touches.length; i++) {
+    var idx = ongoingTouchIndexById(touches[i].identifier);
+    ongoingTouches.splice(idx, 1);  // remove it; we're done
+  }
+}
+
+ +

Since the idea is to immediately abort the touch, we simply remove it from the ongoing touch list without drawing a final line segment.

+ +

Convenience functions

+ +

This example uses two convenience functions that should be looked at briefly to help make the rest of the code more clear.

+ +

Selecting a color for each touch

+ +

In order to make each touch's drawing look different, the colorForTouch() function is used to pick a color based on the touch's unique identifier. This identifier is an opaque number, but we can at least rely on it differing between the currently-active touches.

+ +
function colorForTouch(touch) {
+  var r = touch.identifier % 16;
+  var g = Math.floor(touch.identifier / 3) % 16;
+  var b = Math.floor(touch.identifier / 7) % 16;
+  r = r.toString(16); // make it a hex digit
+  g = g.toString(16); // make it a hex digit
+  b = b.toString(16); // make it a hex digit
+  var color = "#" + r + g + b;
+  log("color for touch with identifier " + touch.identifier + " = " + color);
+  return color;
+}
+
+ +

The result from this function is a string that can be used when calling {{HTMLElement("canvas")}} functions to set drawing colors. For example, for a {{domxref("Touch.identifier")}} value of 10, the resulting string is "#aaa".

+ +

Copying a touch object

+ +

Some browsers (mobile Safari, for one) re-use touch objects between events, so it's best to copy the bits you care about, rather than referencing the entire object.

+ +
function copyTouch(touch) {
+  return { identifier: touch.identifier, pageX: touch.pageX, pageY: touch.pageY };
+}
+ +

Finding an ongoing touch

+ +

The ongoingTouchIndexById() function below scans through the ongoingTouches array to find the touch matching the given identifier, then returns that touch's index into the array.

+ +
function ongoingTouchIndexById(idToFind) {
+  for (var i = 0; i < ongoingTouches.length; i++) {
+    var id = ongoingTouches[i].identifier;
+
+    if (id == idToFind) {
+      return i;
+    }
+  }
+  return -1;    // not found
+}
+
+ +

Showing what's going on

+ +
function log(msg) {
+  var p = document.getElementById('log');
+  p.innerHTML = msg + "\n" + p.innerHTML;
+}
+ +

If your browser supports it, you can {{LiveSampleLink('Example', 'see it live')}}.

+ +

jsFiddle example

+ +

Additional tips

+ +

This section provides additional tips on how to handle touch events in your web application.

+ +

Handling clicks

+ +

Since calling preventDefault() on a {{event("touchstart")}} or the first {{event("touchmove")}} event of a series prevents the corresponding mouse events from firing, it's common to call preventDefault() on {{event("touchmove")}} rather than {{event("touchstart")}}. That way, mouse events can still fire and things like links will continue to work. Alternatively, some frameworks have taken to refiring touch events as mouse events for this same purpose. (This example is oversimplified and may result in strange behavior. It is only intended as a guide.)

+ +
function onTouch(evt) {
+  evt.preventDefault();
+  if (evt.touches.length > 1 || (evt.type == "touchend" && evt.touches.length > 0))
+    return;
+
+  var newEvt = document.createEvent("MouseEvents");
+  var type = null;
+  var touch = null;
+
+  switch (evt.type) {
+    case "touchstart":
+      type = "mousedown";
+      touch = evt.changedTouches[0];
+      break;
+    case "touchmove":
+      type = "mousemove";
+      touch = evt.changedTouches[0];
+      break;
+    case "touchend":
+      type = "mouseup";
+      touch = evt.changedTouches[0];
+      break;
+  }
+
+  newEvt.initMouseEvent(type, true, true, evt.originalTarget.ownerDocument.defaultView, 0,
+    touch.screenX, touch.screenY, touch.clientX, touch.clientY,
+    evt.ctrlKey, evt.altKey, evt.shiftKey, evt.metaKey, 0, null);
+  evt.originalTarget.dispatchEvent(newEvt);
+}
+
+ +

Calling preventDefault() only on a second touch

+ +

One technique for preventing things like pinchZoom on a page is to call preventDefault() on the second touch in a series. This behavior is not well defined in the touch events spec, and results in different behavior for different browsers (i.e., iOS will prevent zooming but still allow panning with both fingers; Android will allow zooming but not panning; Opera and Firefox currently prevent all panning and zooming.) Currently, it's not recommended to depend on any particular behavior in this case, but rather to depend on meta viewport to prevent zooming.

+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Touch Events 2', '#touch-interface', 'Touch')}}{{Spec2('Touch Events 2')}}Added radiusX, radiusY, rotationAngle, force properties
{{SpecName('Touch Events', '#touch-interface', 'Touch')}}{{Spec2('Touch Events')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +

Note that unfortunately touch events may not fire at all on laptops with touch functionality (test page).

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatChrome("22.0")}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("18.0")}}[1]
+ {{CompatGeckoDesktop("52.0")}}[2]
{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewChrome for AndroidEdgeFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("6.0")}}{{CompatVersionUnknown}}11{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

[1] The dom.w3c_touch_events.enabled tri-state preference can be used to disable (0), enable (1), and auto-detect (2) support for standard touch events; by default, they're on auto-detect (2).

+ +

As of Gecko 24.0 {{geckoRelease("24.0")}}, the touch events support introduced with Gecko 18.0 {{geckoRelease("18.0")}} has been disabled on the desktop version of Firefox ({{bug(888304)}}), as some popular sites including Google and Twitter were not working properly. Once the bug is fixed, the API will be enabled again. To enable it anyway, open about:config and set the dom.w3c_touch_events.enabled preference to 2. The mobile versions including Firefox for Android and Firefox OS are not affected by this change.

+ +

[2] As of Gecko 52.0, touch events support has been fixed and reenabled in Windows desktop platforms.

+ +
+

Note: Prior to Gecko 6.0 {{geckoRelease("6.0")}}, Gecko offered a proprietary touch event API. That API is now deprecated; you should switch to this one.

+
diff --git a/files/zh-tw/web/api/touchevent/index.html b/files/zh-tw/web/api/touchevent/index.html new file mode 100644 index 0000000000..5c435c008f --- /dev/null +++ b/files/zh-tw/web/api/touchevent/index.html @@ -0,0 +1,201 @@ +--- +title: TouchEvent +slug: Web/API/TouchEvent +translation_of: Web/API/TouchEvent +--- +

{{ APIRef("Touch Events") }}

+ +

TouchEvent 介面表示了一個由觸控平面因觸碰而改變狀態所發出的事件。平面可以是觸控螢幕或是觸控板,TouchEvent 能描述一或多個觸碰點,並且支援偵測其移動、增加或減少觸碰點等等功能。

+ +

觸碰點是由 {{ domxref("Touch") }} 物件表示;每一個觸碰點描述了其位置、大小與形狀、壓力值以及目標元素。觸碰點列表由 {{ domxref("TouchList") }} 所表示。

+ +

建構式

+ +
+
{{domxref("TouchEvent.TouchEvent", "TouchEvent()")}}
+
Creates a TouchEvent object.
+
+ +

屬性

+ +

此介面也繼承了其父介面 {{domxref("UIEvent")}} 與 {{domxref("Event")}} 的屬性

+ +
+
{{ domxref("TouchEvent.altKey") }} {{readonlyInline}}
+
A Boolean value indicating whether or not the alt key was down when the touch event was fired.
+
{{ domxref("TouchEvent.changedTouches") }} {{readonlyInline}}
+
A {{ domxref("TouchList") }} of all the {{ domxref("Touch") }} objects representing individual points of contact whose states changed between the previous touch event and this one.
+
{{ domxref("TouchEvent.ctrlKey") }} {{readonlyInline}}
+
A Boolean value indicating whether or not the control key was down when the touch event was fired.
+
{{ domxref("TouchEvent.metaKey") }} {{readonlyInline}}
+
A Boolean value indicating whether or not the meta key was down when the touch event was fired.
+
{{ domxref("TouchEvent.shiftKey") }} {{readonlyInline}}
+
A Boolean value indicating whether or not the shift key was down when the touch event was fired.
+
{{ domxref("TouchEvent.targetTouches") }}{{readonlyInline}}
+
A {{ domxref("TouchList") }} of all the {{ domxref("Touch") }} objects that are both currently in contact with the touch surface and were also started on the same element that is the target of the event.
+
{{ domxref("TouchEvent.touches") }} {{readonlyInline}}
+
A {{ domxref("TouchList") }} of all the {{ domxref("Touch") }} objects representing all current points of contact with the surface, regardless of target or changed status.
+
+ +

觸控事件類型

+ +

觸控事件有多個種類可以代表觸碰狀態發生了改變。可以藉由 {{ domxref("event.type", "TouchEvent.type") }} 屬性來確認是哪一個種類的觸控事件。

+ +

{{event("touchstart")}}

+ +

Sent when the user places a touch point on the touch surface. The event's target will be the {{ domxref("element") }} in which the touch occurred.

+ +

{{event("touchend")}}

+ +

Sent when the user removes a touch point from the surface (that is, when they lift a finger or stylus from the surface). This is also sent if the touch point moves off the edge of the surface; for example, if the user's finger slides off the edge of the screen.

+ +

The event's target is the same {{ domxref("element") }} that received the touchstart event corresponding to the touch point, even if the touch point has moved outside that element.

+ +

The touch point (or points) that were removed from the surface can be found in the {{ domxref("TouchList") }} specified by the changedTouches attribute.

+ +

{{event("touchmove")}}

+ +

Sent when the user moves a touch point along the surface. The event's target is the same {{ domxref("element") }} that received the touchstart event corresponding to the touch point, even if the touch point has moved outside that element.

+ +

This event is also sent if the values of the radius, rotation angle, or force attributes of a touch point change.

+ +
Note: The rate at which touchmove events is sent is browser-specific, and may also vary depending on the capability of the user's hardware. You must not rely on a specific granularity of these events.
+ +

{{event("touchcancel")}}

+ +

Sent when a touch point has been disrupted in some way. There are several possible reasons why this might happen (and the exact reasons will vary from device to device, as well as browser to browser):

+ + + +

Using with addEventListener() and preventDefault()

+ +

It's important to note that in many cases, both touch and mouse events get sent (in order to let non-touch-specific code still interact with the user). If you use touch events, you should call {{domxref("Event.preventDefault","preventDefault()")}} to keep the mouse event from being sent as well.

+ +

The exception to this is Chrome, starting with version 56 (desktop, Chrome for android, and android webview), where the default value for {{event("touchstart")}} and {{event("touchmove")}} is true and calls to {{domxref("Event.preventDefault","preventDefault()")}} are not needed. To override this behavior, you simply set the passive option to false as shown in the example below. This change prevents the listener from blocking page rendering while a user is scrolling. A demo is available on the Google Developer site.

+ +

GlobalEventHandlers

+ +

{{SeeCompatTable}}

+ +
+
{{ domxref("GlobalEventHandlers.ontouchstart") }} {{experimental_inline}}
+
A {{domxref("GlobalEventHandlers","global event handler")}} for the {{event("touchstart")}} event.
+
{{ domxref("GlobalEventHandlers.ontouchend") }} {{experimental_inline}}
+
A {{domxref("GlobalEventHandlers","global event handler")}} for the {{event("touchend")}} event.
+
{{ domxref("GlobalEventHandlers.ontouchmove") }} {{experimental_inline}}
+
A {{domxref("GlobalEventHandlers","global event handler")}} for the {{event("touchmove")}} event.
+
{{ domxref("GlobalEventHandlers.ontouchcancel") }} {{experimental_inline}}
+
A {{domxref("GlobalEventHandlers","global event handler")}} for the {{event("touchcancel")}} event.
+
+ +

範例

+ +

See the example on the main Touch events article.

+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Touch Events 2','#touchevent-interface', 'TouchEvent')}}{{Spec2('Touch Events 2')}}Added ontouchstart, ontouchend, ontouchmove, ontouchend global attribute handlers
{{SpecName('Touch Events', '#touchevent-interface', 'TouchEvent')}}{{Spec2('Touch Events')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome("22.0")}}{{CompatVersionUnknown}}{{CompatGeckoDesktop("18.0")}}[1]
+ {{CompatGeckoDesktop("52.0")}}[2]
{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroid WebviewChrome for AndroidEdgeFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("6.0")}}{{CompatVersionUnknown}}11{{CompatVersionUnknown}}{{CompatVersionUnknown}}
TouchEvent(){{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

[1] Touch events were implemented in Gecko 18.0, but removed again in 24.0 {{geckoRelease("24.0")}} on the desktop version of Firefox due to web compatibility issues ({{bug(888304)}}).

+ +

[2] As of Gecko 52.0, touch events support has been fixed and reenabled in Windows desktop platforms.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/touchlist/index.html b/files/zh-tw/web/api/touchlist/index.html new file mode 100644 index 0000000000..d106b9df7d --- /dev/null +++ b/files/zh-tw/web/api/touchlist/index.html @@ -0,0 +1,120 @@ +--- +title: TouchList +slug: Web/API/TouchList +translation_of: Web/API/TouchList +--- +
+

{{ APIRef("Touch Events") }}

+
+ +

TouchList 介面表示了一個觸控平面上所有觸碰點的列表;舉例來說,假如使用者有三隻手指於觸控平面(如觸控螢幕或是觸控板)上,則其相對應的 TouchList 物件中就會分別有三個 {{domxref("Touch")}} 物件各代表一個手指的觸碰。

+ +

屬性

+ +
+
{{domxref("TouchList.length")}} {{readonlyInline}}
+
The number of {{domxref("Touch")}} objects in the TouchList.
+
+ +

方法

+ +
+
{{domxref("TouchList.identifiedTouch()")}} {{obsolete_inline}}
+
Returns the first {{domxref("Touch")}} item in the list whose identifier matches a specified value.
+
{{domxref("TouchList.item()")}}
+
Returns the {{domxref("Touch")}} object at the specified index in the list.
+
+ +

範例

+ +

See the example on the main Touch events article.

+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Touch Events 2','#touchlist-interface')}}{{Spec2('Touch Events 2')}}Non-stable version.
{{SpecName('Touch Events', '#touchlist-interface')}}{{Spec2('Touch Events')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome("22.0")}}{{CompatGeckoDesktop("18.0")}}[1]
+ {{CompatGeckoDesktop("52.0")}}[2]
{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewChrome for AndroidFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("6.0")}}{{CompatVersionUnknown}}11{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

[1] Touch events were implemented in Gecko 18.0, but removed again in 24.0 {{geckoRelease("24.0")}} on the desktop version of Firefox due to web compatibility issues ({{bug(888304)}}).

+ +

[2] As of Gecko 52.0, touch events support has been fixed and reenabled in Windows desktop platforms.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/uievent/index.html b/files/zh-tw/web/api/uievent/index.html new file mode 100644 index 0000000000..a5a1228ec8 --- /dev/null +++ b/files/zh-tw/web/api/uievent/index.html @@ -0,0 +1,188 @@ +--- +title: UIEvent +slug: Web/API/UIEvent +tags: + - 待翻譯 +translation_of: Web/API/UIEvent +--- +

{{APIRef("DOM Events")}}

+ +

UIEvent 介面是使用者介面的事件的基本型態。

+ +

UIEvent 是從 {{domxref("Event")}} 衍伸過來。 雖然為了相容性,仍留著 {{domxref("UIEvent.initUIEvent()")}} 方法,建立 UIEvent 物件最好是選擇以 {{domxref("UIEvent.UIEvent", "UIEvent()")}} constructor 建立。

+ +

許多介面直接或間接繼承此介面,例如:{{domxref("MouseEvent")}}、{{domxref("TouchEvent")}}、{{domxref("FocusEvent")}}、{{domxref("KeyboardEvent")}}、{{domxref("WheelEvent")}}、{{domxref("InputEvent")}} 和 {{domxref("CompositionEvent")}}。

+ +

建構式

+ +
+
{{domxref("UIEvent.UIEvent()", "UIEvent()")}}
+
建立一個 UIEvent 物件 。
+
+ +

屬性

+ +

此介面亦繼承其父-- {{domxref("Event")}} 的屬性:

+ +
+
{{domxref("UIEvent.cancelBubble")}} {{Non-standard_inline}} {{Deprecated_inline}}
+
Is a {{jsxref("Boolean")}} indicating whether the bubbling of the event has been canceled or not.
+
+ +
+
{{domxref("UIEvent.detail")}}{{readonlyinline}}
+
Returns a long with details about the event, depending on the event type.
+
{{domxref("UIEvent.isChar")}} {{obsolete_inline}} {{readonlyinline}}
+
Returns a {{jsxref("Boolean")}} indicating whether the event produced a key character or not.
+
{{domxref("UIEvent.layerX")}} {{Non-standard_inline}} {{readonlyinline}}
+
Returns the horizontal coordinate of the event relative to the current layer.
+
{{domxref("UIEvent.layerY")}} {{Non-standard_inline}} {{readonlyinline}}
+
Returns the vertical coordinate of the event relative to the current layer.
+
{{domxref("UIEvent.pageX")}} {{Non-standard_inline}} {{readonlyinline}}
+
Returns the horizontal coordinate of the event relative to the whole document.
+
{{domxref("UIEvent.pageY")}} {{Non-standard_inline}} {{readonlyinline}}
+
Returns the vertical coordinate of the event relative to the whole document.
+
{{domxref("UIEvent.sourceCapabilities")}} {{non-standard_inline}} {{readonlyinline}}
+
Returns an instance of the InputDeviceCapabilities interface which provides information about the physical device responsible for generating a touch event.
+
{{domxref("UIEvent.view")}}{{readonlyinline}}
+
Returns a {{domxref("WindowProxy")}} that contains the view that generated the event.
+
{{domxref("UIEvent.which")}} {{Non-standard_inline}} {{readonlyinline}}
+
Returns the numeric keyCode of the key pressed, or the character code (charCode) for an alphanumeric key pressed.
+
+ +

方法

+ +

此介面亦繼承其父-- {{domxref("Event")}} 的方法:

+ +
+
{{domxref("UIEvent.initUIEvent()")}} {{deprecated_inline}}
+
初始化 UIEvent 物件。若該事件已經觸發的話,此方法就不會執行任何東西。
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('InputDeviceCapabilities')}}{{Spec2('InputDeviceCapabilities')}}Added sourceCapabilities property.
{{SpecName('DOM3 Events', '#interface-UIEvent', 'UIEvent')}}{{Spec2('DOM3 Events')}}Added the UIEvent() constructor, deprecated the initUIEvent() method and changed the type of view from AbstractView to WindowProxy.
{{SpecName('DOM2 Events', '#Events-UIEvent', 'UIEvent')}}{{Spec2('DOM2 Events')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}[2]{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}
UIEvent(){{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(11)}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}
cancelBubble defined on Event{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(53)}}[1]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}[2]{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}
UIEvent(){{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(11)}}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}
cancelBubble defined on Event{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile(53)}}[1]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] From Firefox 52, this property is now defined on the {{domxref("Event")}} interface instead. See {{bug(1298970)}} for more details.

+ +

[2] The {{domxref("UIEvent.isChar", "isChar")}} property has never been supported by any browser but Firefox, and even on Firefox it's never worked except on Mac OSX. For that reason, it's been removed in Firefox 55 to align with other browsers.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/uievent/uievent/index.html b/files/zh-tw/web/api/uievent/uievent/index.html new file mode 100644 index 0000000000..d18be6387f --- /dev/null +++ b/files/zh-tw/web/api/uievent/uievent/index.html @@ -0,0 +1,134 @@ +--- +title: UIEvent() +slug: Web/API/UIEvent/UIEvent +translation_of: Web/API/UIEvent/UIEvent +--- +

{{APIRef("DOM Events")}}

+ +

UIEvent() constructor 是用來建立新的 {{domxref("UIEvent")}}。

+ +

語法

+ +
 event = new UIEvent(typeArg, UIEventInit);
+ +

參數

+ +
+
typeArg
+
一個 {{domxref("DOMString")}} ,用來表示事件名稱
+
UIEventInit{{optional_inline}}
+
+ +
+
一個 UIEventInit dictionary ,能接受以下參數: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
參數可選默認值類型說明
"detail"0long定義事件意義的值。關於事件的意義於 {{domxref("UIEvent.detail")}} 已有較詳盡的列表。
"view"null{{domxref("WindowProxy")}}與事件相關的 {{domxref("Window")}} 。
+ +
+

UIEventInit dictionary 亦接受 {{domxref("Event.Event", "EventInit")}} dictionary 所接受的參數。

+
+
+
+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM3 Events','#interface-UIEvent','UIEvent()')}}{{Spec2('DOM3 Events')}}原始定義。
+ +

瀏覽器支援度

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{ CompatVersionUnknown() }}{{ CompatGeckoDesktop(11) }}{{ CompatUnknown() }}{{ CompatVersionUnknown() }}{{ CompatUnknown() }}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatGeckoMobile(11) }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/api/url/createobjecturl/index.html b/files/zh-tw/web/api/url/createobjecturl/index.html new file mode 100644 index 0000000000..8760dffaec --- /dev/null +++ b/files/zh-tw/web/api/url/createobjecturl/index.html @@ -0,0 +1,137 @@ +--- +title: URL.createObjectURL() +slug: Web/API/URL/createObjectURL +translation_of: Web/API/URL/createObjectURL +--- +
{{ApiRef("URL API")}}{{SeeCompatTable}}
+ +

摘要

+ +

靜態方法 URL.createObjectURL() 用於建立一個帶有URL的 {{domxref("DOMString")}} 以代表參數中所傳入的物件. 該URL的生命週期與創造它的window中的 {{domxref("document")}}一致. 這個新的物件URL 代表了所指定的 {{domxref("File")}} 物件 或是 {{domxref("Blob")}} 物件.

+ +

{{AvailableInWorkers}}

+ +

語法

+ +
objectURL = URL.createObjectURL(blob);
+
+ +

參數

+ +
+
blob
+
+ +
+
一個用以建立物件URL的 {{domxref("File")}} 物件 或是 {{domxref("Blob")}} 物件.
+
+ + + +

範例

+ +

參見 Using object URLs to display images.(藉由物件URL來顯示圖像)

+ +

注意事項

+ +

每次呼叫 createObjectURL() 都會產生一個新的URL, 不論是否曾以同一物件產生過. 當你不再需要它們的時候必須對每一個都呼叫 {{domxref("URL.revokeObjectURL()")}} 來釋放它們. 瀏覽器會在document被unload時自動釋放它們; 然而, 為了最佳化效能與記憶體用量, 當有安全的時機請務必手動釋放它們.

+ +

規範文件

+ + + + + + + + + + + + + + +
規範文件狀態附註
{{SpecName('File API', '#dfn-createObjectURL', 'URL')}}{{Spec2('File API')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能ChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support8 [1]
+ {{CompatChrome(23)}}
{{CompatGeckoDesktop(2)}}{{CompatIE(10)}}{{CompatOpera(15)}}{{CompatSafari(6)}} [1]
+ {{CompatSafari(7)}}
In a {{ domxref("Worker", "Web Worker") }}10 [1]
+ {{CompatChrome(23)}}
{{CompatGeckoDesktop(21)}}{{CompatIE(11)}}{{CompatOpera(15)}}{{CompatSafari(6)}} [1]
+ {{CompatSafari(7)}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChrome for AndroidAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support18 [1]4.0 [1]{{CompatGeckoMobile(14)}}{{CompatUnknown}}{{CompatOpera(15)}} [1]6.0 [1]
In a {{ domxref("Worker", "Web Worker") }}18 [1]{{CompatVersionUnknown}} [1]{{CompatGeckoMobile(14)}}{{CompatUnknown}}{{CompatOpera(15)}} [1]6.0 [1]
+
+ +

[1]  在該瀏覽器中必須使用 webkitURL 而非 URL

+ +

另見

+ + diff --git a/files/zh-tw/web/api/url/index.html b/files/zh-tw/web/api/url/index.html new file mode 100644 index 0000000000..0a7fdb670b --- /dev/null +++ b/files/zh-tw/web/api/url/index.html @@ -0,0 +1,212 @@ +--- +title: URL +slug: Web/API/URL +tags: + - API + - Experimental + - NeedsTranslation + - TopicStub + - URL API +translation_of: Web/API/URL +--- +
{{ApiRef("URL API")}} {{SeeCompatTable}}
+ +

URL 介面提供了建立 URL 物件的靜態方法。

+ +

使用尚未實作此物件的瀏覽器時,可以改用 {{domxref("Window.URL")}} 屬性來呼叫(基於 Webkit 或 Blink 引擎的瀏覽器可使用 Window.webkitURL)。

+ +

{{AvailableInWorkers}}

+ +

屬性

+ +
+
{{domxref("URL.href")}}
+
Is a {{domxref("DOMString")}} containing the whole URL.
+
{{domxref("URL.protocol")}}
+
Is a {{domxref("DOMString")}} containing the protocol scheme of the URL, including the final ':'.
+
{{domxref("URL.host")}}
+
Is a {{domxref("DOMString")}} containing the host, that is the hostname, a ':', and the port of the URL.
+
{{domxref("URL.hostname")}}
+
Is a {{domxref("DOMString")}} containing the domain of the URL.
+
{{domxref("URL.port")}}
+
Is a {{domxref("DOMString")}} containing the port number of the URL.
+
{{domxref("URL.pathname")}}
+
Is a {{domxref("DOMString")}} containing an initial '/' followed by the path of the URL.
+
{{domxref("URL.search")}}
+
Is a {{domxref("DOMString")}} containing a '?' followed by the parameters of the URL.
+
{{domxref("URL.hash")}}
+
Is a {{domxref("DOMString")}} containing a '#' followed by the fragment identifier of the URL.
+
{{domxref("URL.username")}}
+
Is a {{domxref("DOMString")}} containing the username specified before the domain name.
+
{{domxref("URL.password")}}
+
Is a {{domxref("DOMString")}} containing the password specified before the domain name.
+
{{domxref("URL.origin")}} {{readonlyInline}}
+
Returns a {{domxref("DOMString")}} containing the origin of the URL, that is its scheme, its domain and its port.
+
+ +
+
{{domxref("URL.searchParams")}}
+
Returns a {{domxref("URLSearchParams")}} object allowing to access the GET query arguments contained in the URL.
+
+ +

建構式

+ +
+
{{domxref("URL.URL", "URL()")}}
+
Creates and return a URL object composed from the given parameters.
+
+ +

方法

+ +

The URL interface implements methods defined in {{domxref("URLUtils")}}.

+ +
+
{{domxref("URLUtils.toString()")}}
+
Returns a {{domxref("DOMString")}} containing the whole URL. It is a synonym for {{domxref("URLUtils.href")}}, though it can't be used to modify the value.
+
+ +

靜態方法

+ +
+
{{domxref("URL.createObjectURL()")}}
+
Returns a {{domxref("DOMString")}} containing a unique blob URL, that is a URL with blob: as its scheme, followed by an opaque string uniquely identifying the object in the browser.
+
{{domxref("URL.revokeObjectURL()")}}
+
Revokes an object URL previously created using {{domxref("URL.createObjectURL()")}}.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('File API', '#creating-revoking', 'URL')}}{{Spec2('File API')}}Added the static methods URL.createObjectURL() and URL.revokeObjectURL().
{{SpecName('URL', '#api', 'Node')}}{{Spec2('URL')}}Initial definition (implements URLUtils).
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support8.0[2]
+ 32
{{CompatUnknown}}{{CompatGeckoDesktop("2.0")}}[1][3]
+ {{CompatGeckoDesktop("19.0")}}
10.015.0[2]
+ 19
6.0[2]
+ 7.0
username, password, and origin32{{CompatUnknown}}{{CompatGeckoDesktop("26.0")}}{{CompatUnknown}}19{{CompatVersionUnknown}}
searchParams{{CompatChrome(49)}}{{CompatUnknown}}{{CompatGeckoDesktop("29.0")}}{{CompatUnknown}}36{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support4[2]
+ 4.4
8.0[2]
+ 32
{{CompatGeckoMobile("14.0")}}[1][3]
+ {{CompatGeckoMobile("19.0")}}
{{CompatVersionUnknown}}15.0[2]6.0[2]
username, password, and origin4.432{{CompatGeckoDesktop("26.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
searchParams{{CompatNo}}{{CompatChrome(49)}}{{CompatGeckoMobile("29.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] From Gecko 2 (Firefox 4) to Gecko 18 included, Gecko supported this interface with the non-standard nsIDOMMozURLProperty internal type. As the only to access such an object was through {{domxref("window.URL")}}, in practice, this didn't make any difference.

+ +

[2] This feature is implemented under the non-standard name webkitURL.

+ +

[3] For Firefox, to use from chrome code, JSM and Bootstrap scope, you have to import it like this:

+ +
Cu.importGlobalProperties(['URL']);
+
+ +

URL is available in Worker scopes.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/validitystate/index.html b/files/zh-tw/web/api/validitystate/index.html new file mode 100644 index 0000000000..8cd2bdd738 --- /dev/null +++ b/files/zh-tw/web/api/validitystate/index.html @@ -0,0 +1,145 @@ +--- +title: ValidityState +slug: Web/API/ValidityState +translation_of: Web/API/ValidityState +--- +
{{APIRef("HTML DOM")}} {{gecko_minversion_header("2.0")}}
+ +

ValidityState 介面表示了一個元素目前在其檢核條件下驗證的正確性狀態(validity states)。同時,它們也可以協助解釋元素值檢核失敗的原因,如果元素值為不合法的。

+ +

屬性

+ +

For each of these Boolean properties, a value of true indicates that the specified reason validation may have failed is true, with the exception of the valid property, which is true if the element's value obeys all constraints.

+ +
+
{{domxref("ValidityState.badInput")}} {{ReadOnlyInline}}
+
Is a {{jsxref("Boolean")}} indicating the user has provided input that the browser is unable to convert.
+
{{domxref("ValidityState.customError")}} {{ReadOnlyInline}}
+
Is a {{jsxref("Boolean")}} indicating the element's custom validity message has been set to a non-empty string by calling the element's setCustomValidity() method.
+
{{domxref("ValidityState.patternMismatch")}} {{ReadOnlyInline}}
+
Is a {{jsxref("Boolean")}} indicating the value does not match the specified {{htmlattrxref("pattern", "input")}}.
+
{{domxref("ValidityState.rangeOverflow")}} {{ReadOnlyInline}}
+
Is a {{jsxref("Boolean")}} indicating the value is greater than the maximum specified by the {{htmlattrxref("max", "input")}} attribute.
+
{{domxref("ValidityState.rangeUnderflow")}} {{ReadOnlyInline}}
+
Is a {{jsxref("Boolean")}} indicating the value is less than the minimum specified by the {{htmlattrxref("min", "input")}} attribute.
+
{{domxref("ValidityState.stepMismatch")}} {{ReadOnlyInline}}
+
Is a {{jsxref("Boolean")}} indicating the value does not fit the rules determined by the {{htmlattrxref("step", "input")}} attribute (that is, it's not evenly divisible by the step value).
+
{{domxref("ValidityState.tooLong")}} {{ReadOnlyInline}}
+
Is a {{jsxref("Boolean")}} indicating the value exceeds the specified maxlength for {{domxref("HTMLInputElement")}} or {{domxref("HTMLTextAreaElement")}} objects. Note: This will never be true in Gecko, because elements' values are prevented from being longer than maxlength.
+
{{domxref("ValidityState.tooShort")}} {{ReadOnlyInline}}
+
Is a {{jsxref("Boolean")}} indicating the value fails to meet the specified minlength for {{domxref("HTMLInputElement")}} or {{domxref("HTMLTextAreaElement")}} objects.
+
{{domxref("ValidityState.typeMismatch")}} {{ReadOnlyInline}}
+
Is a {{jsxref("Boolean")}} indicating the value is not in the required syntax (when {{htmlattrxref("type", "input")}} is email or url).
+
{{domxref("ValidityState.valid")}} {{ReadOnlyInline}}
+
Is a {{jsxref("Boolean")}} indicating the element meets all constraint validations, and is therefore considered to be valid.
+
{{domxref("ValidityState.valueMissing")}} {{ReadOnlyInline}}
+
Is a {{jsxref("Boolean")}} indicating the element has a {{htmlattrxref("required", "input")}} attribute, but no value.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('HTML WHATWG', 'forms.html#the-constraint-validation-api', 'ValidityState') }}{{Spec2('HTML WHATWG')}}Live Standard
{{ SpecName('HTML5.1', '#the-constraint-validation-api', 'ValidityState') }}{{Spec2('HTML5.1')}}No change from the previous snapshot {{SpecName('HTML5 W3C')}}.
{{ SpecName('HTML5 W3C', 'forms.html#the-constraint-validation-api', 'ValidityState') }}{{Spec2('HTML5 W3C')}}First snapshot of  {{SpecName('HTML WHATWG')}} containing this interface.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{ CompatVersionUnknown() }}{{CompatVersionUnknown}}{{ CompatVersionUnknown }}10{{ CompatVersionUnknown() }}10.0.3
badInput{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatGeckoDesktop(29)}}{{CompatUnknown}}{{CompatUnknown}}10.0.3
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{CompatVersionUnknown}}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
badIndput{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile(29)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/vibration_api/index.html b/files/zh-tw/web/api/vibration_api/index.html new file mode 100644 index 0000000000..115020dbda --- /dev/null +++ b/files/zh-tw/web/api/vibration_api/index.html @@ -0,0 +1,113 @@ +--- +title: Vibration API +slug: Web/API/Vibration_API +translation_of: Web/API/Vibration_API +--- +

{{DefaultAPISidebar("Vibration API")}}

+ +

目前大多數的行動裝置均具備振動硬體以搖晃裝置,讓軟體程式碼能對使用者產生實際反饋。Vibration API 即可讓 Web Apps 存取振動硬體。當然,若裝置並未支援振動硬體,就不會產生任何效果。

+ +

振動說明

+ +

振動即如「on-off」脈衝的形式,且持續時間亦有不同的變化。可透過單一整數讓振動持續數個毫秒 (ms);或可由多個整數組成陣列,達到振動與暫停交錯的振動形式。只要單一 window.navigator.vibrate() 函式即可控制振動。

+ +

單次振動

+ +

你可指定單一數值,或用單一數值構成 1 組陣列,讓振動硬體動作 1 次:

+ +
window.navigator.vibrate(200);
+window.navigator.vibrate([200]);
+
+ +

上列 2 個範例均可使裝置振動達 200 ms。

+ +

振動形式

+ +

用數值構成陣列,敘述裝置在一段期間內振動與停止振動的情形。陣列中的所有值均轉換為整數,接著直譯 (Interprete) 成裝置振動與停止振動的毫秒數。範例如下:

+ +
window.navigator.vibrate([200, 100, 200]);
+
+ +

根據此陣列,裝置將振動 200 ms、暫停 100 ms,再振動 200 ms。

+ +

你可照自己喜好而指定多組振動/暫停的變化,且輸入項的數量為奇數或偶數均可。由於振動將在每個振動期間結束時停止,所以不一定要提供暫停數值作為最後 1 組輸入項。

+ +

取消目前振動

+ +

window.navigator.vibrate() 的值為「0」、空白陣列,或陣列全為「0」時呼叫此函式,即可取消目前執行中的振動作業。

+ +

規格

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Vibration API')}}{{Spec2('Vibration API')}}Initial specification.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}} {{property_prefix("webkit")}}11.0 {{property_prefix("moz")}}
+ 16 (no prefix)
{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}} {{property_prefix("webkit")}}11.0 {{property_prefix("moz")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

另可參閱

+ + diff --git a/files/zh-tw/web/api/web_audio_api/index.html b/files/zh-tw/web/api/web_audio_api/index.html new file mode 100644 index 0000000000..f2eef8f535 --- /dev/null +++ b/files/zh-tw/web/api/web_audio_api/index.html @@ -0,0 +1,119 @@ +--- +title: Web Audio API +slug: Web/API/Web_Audio_API +translation_of: Web/API/Web_Audio_API +--- +

{{SeeCompatTable}}

+

Show the ability of AudioNodes to connect via their inputs and outputs and the channels inside these inputs/outputs.Web Audio API 可於 Web App 或網頁上操作並播放音訊檔案。

+

Web Audio API 是根據模組化路由 (Modular routing) 的概念所設計。所謂的模組化路由,即是以「音訊節點 (Audio nodes)執行基本的音訊作業節點又互相連接而構成「音訊路由圖 (Audio routing graphs)」。在同一環境 (Audio context) 內,又可支援數個音源與多樣的聲道配置。此模組化設計可提供更高的靈活度,並能建立複雜的音訊函式與動態效果。

+

音訊節點均透過其輸出與輸入而相互連結。各個輸入/輸出均具備數個聲道 (Channel),以構成特定的音訊配置。但目前已可支援單聲道、立體聲、四聲道、5.1 聲道等配置,並支援其他的離散配置。

+

音訊有多種來源。可能由特定的音訊節點 (如震盪器、自訂函式,甚或簡易的資料陣列) 直接在 JavaScript 中產生。音源除了可連至 HTML 媒體元素 (如 <video><audio>),亦可能來自於 WebRTCMediaStream (本端裝置的相機或遠方電腦)。

+

特定音訊事件發生的時間點,均達到極高的精確度與極低的潛時,因此亦可用以詳細定義鼓類機器或音序器 (Sequencer) 所需的事件。

+

Web Audio API 亦可控制音訊的空間定位 (Spatialized) 作業:透過 source-listener 模型架構的系統,進而控制所要使用的左右相位 (Panning聲音放置於左右喇叭之間形成的立體音場中,以產生出空間感) 模,進而自動處理因距離遠近所產生的衰減,或是由於音源/聽者移動所發生的都卜勒移頻 (Doppler shift)。

+

參考

+
+ +
+

線上教學

+ +

規格

+ + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Web Audio API')}}{{Spec2('Web Audio API')}} 
+

瀏覽器相容性

+
+ {{CompatibilityTable}}
+
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support14 {{property_prefix("webkit")}}23{{CompatNo}}15 {{property_prefix("webkit")}}6 {{property_prefix("webkit")}}
+
+
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChromeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatNo}}28 {{property_prefix("webkit")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}6 {{property_prefix("webkit")}}
+
+

 

diff --git a/files/zh-tw/web/api/web_video_text_tracks_format/index.html b/files/zh-tw/web/api/web_video_text_tracks_format/index.html new file mode 100644 index 0000000000..e565d2d129 --- /dev/null +++ b/files/zh-tw/web/api/web_video_text_tracks_format/index.html @@ -0,0 +1,691 @@ +--- +title: WebVTT +slug: Web/API/Web_Video_Text_Tracks_Format +translation_of: Web/API/WebVTT_API +--- +

WebVTT 是一種 UTF-8 編碼的文字檔案格式,可藉由 {{ HTMLElement("track") }} 元素顯示加註時間資訊之文字軌,其主要設計目的是為 {{ HTMLElement("video") }} 顯示字幕。

+ +

WebVTT 當中可以採用空白或分隔字元(tab)。

+ +

WebVTT 的 MIME Type 為 text/vtt

+ +

 

+ +

WebVTT 文本

+ +

WebVTT 檔的結構中,有兩項必備資訊、四項選用資訊。

+ + + +
範例 1 - 最簡單的 WEBVTT 檔
+ +
  WEBVTT
+
+
+ +
範例 2 - 很簡單的 WebVTT 檔
+ +
  WEBVTT - 這個檔案沒有時間節點
+
+
+ +
範例 3 - 常見的 WebVTT 例子
+ +
  WEBVTT - 這個檔案有時間節點
+
+  14
+  00:01:14.815 --> 00:01:18.114
+  - What?
+  - Where are we now?
+
+  15
+  00:01:18.171 --> 00:01:20.991
+  - This is big bat country.
+
+  16
+  00:01:21.058 --> 00:01:23.868
+  - [ Bats Screeching ]
+  - They won't get in your hair. They're after the bugs.
+
+ +

 

+ +

WebVTT 註解

+ +

Comments are an optional component that can be used to add information to a WebVTT file. Comments are intended for those reading the file and are not seen by users. Comments may contain newlines but it cannot contain a blank line, which is equivalent to two consecutive newlines. A blank line signifies the end of a comment.

+ +

註解中不能包含「-->」字串、「&」符號或「<」符號。如欲使用後兩者,可採跳脫字串「&amp;」或「&lt;」。此外雖規格上允許使用「>」字元,仍然建議跳脫為「&gt;」以避免混淆。

+ +

註解由三個部分組成:

+ + + +
範例 4 - 常見 WebVTT 範例
+ +
  NOTE 這行是註解
+
+ +
範例 5 - 多行註解
+ +
  NOTE
+  這也是註解,
+  只是拆成多行。
+
+  NOTE 當然也可以像這樣
+  來分行寫註解。
+
+ +
範例 6 - 常見註解使用方式
+ +
  WEBVTT - 翻譯我喜歡的影片字幕
+
+  NOTE
+  本字幕由 Kyle 翻譯,
+  希望可以讓我的朋友跟家人一同觀賞。
+
+  1
+  00:02:15.000 --> 00:02:20.000
+  - Ta en kopp varmt te.
+  - Det är inte varmt.
+
+  2
+  00:02:20.000 --> 00:02:25.000
+  - Har en kopp te.
+  - Det smakar som te.
+
+  NOTE This last line may not translate well.
+
+  3
+  00:02:25.000 --> 00:02:30.000
+  -Ta en kopp.
+
+ +

 

+ +

WebVTT 時間節點

+ +

時間節點(cue)是具備單一開始時間、結束時間、文字內容的字幕區段。 Example 6 consists of the header, a blank line, and then five cues separated by blank lines. 時間節點由五個部分組成:

+ + + +
範例7 - Example of a cue
+ +
1 - Title Crawl
+00:00:5.000 --> 00:00:10.000 line:0 position:20% size:60% align:start
+Some time ago in a place rather distant....
+ +

 

+ +

節點 ID

+ +

此 ID 代表時間節點的名稱,可以用以在腳本語言中參照某段特定時間節點。ID 中禁用換行字元,也不可以包括「-->」字串。ID 最後必須以一個換行字元作為結束。

+ +

雖然通常都用數字(1, 2, 3...)作為 ID,但規格上並不要求每個 ID 都是為一值。

+ +
範例 8 - 範例 7 中的時間節點 ID
+ +
1 - Title Crawl
+ +
範例 9 - ID 常見用法
+ +
WEBVTT
+
+1
+00:00:22.230 --> 00:00:24.606
+This is the first subtitle.
+
+2
+00:00:30.739 --> 00:00:34.074
+This is the second.
+
+3
+00:00:34.159 --> 00:00:35.743
+Third
+
+ +

 

+ +

時間資訊

+ +

時間資訊標注了此段節點的出現時機,其中包括開始時間與結束時間。結束時間必須比開始時間晚,而開始時間必須比先前所有的開始時間晚,或至少是同一時間。

+ +

不同時間節點可以設定為同時顯示,但若 WebVTT 檔案是用在 chapters({{ HTMLElement("track") }} 的 {{ htmlattrxref("kind") }} 設定為 chapters),則不允許兩段節點同時出現。

+ +

每項時間資訊都由五個部分組成:

+ + + +

時間的表示方式,可以是以下兩種:

+ + + +

其中的各元素說明如下:

+ + + +
Example 10 - Basic cue timing examples
+ +
00:22.230 --> 00:24.606
+00:30.739 --> 00:00:34.074
+00:00:34.159 --> 00:35.743
+00:00:35.827 --> 00:00:40.122
+ +
Example 11 - Overlapping cue timing examples
+ +
00:00:00.000 --> 00:00:10.000
+00:00:05.000 --> 00:01:00.000
+00:00:30.000 --> 00:00:50.000
+ +
Example 12 - Non-overlapping cue timing examples
+ +
00:00:00.000 --> 00:00:10.000
+00:00:10.000 --> 00:01:00.581
+00:01:00.581 --> 00:02:00.100
+00:02:01.000 --> 00:02:01.000
+ +

 

+ +

Cue Settings

+ +

Cue settings are optional components used to position where the cue payload text will be displayed over the video. This includes whether the text is displayed horizontally or vertically. There can be zero or more of them, and they can be used in any order so long as each setting is used no more than once.

+ +

The cue settings are added to the right of the cue timings. There must be one or more spaces between the cue timing and the first setting and between each setting. A setting's name and value are separated by a colon. The settings are case sensitive so use lower case as shown. There are five cue settings:

+ + + +
Example 13 - Cue setting examples
+ +

The first line demonstrates no settings. The second line might be used to overlay text on a sign or label. The third line might be used for a title. The last line might be used for an Asian language.

+ +
00:00:5.000 --> 00:00:10.000
+00:00:5.000 --> 00:00:10.000 line:63% position:72% align:start
+00:00:5.000 --> 00:00:10.000 line:0 position:20% size:60% align:start
+00:00:5.000 --> 00:00:10.000 vertical:rt line:-1 align:end
+
+ +

 

+ +

文字內容

+ +

The payload is where the main information or content is located. In normal usage the payload contains the subtitles to be displayed. The payload text may contain newlines but it cannot contain a blank line, which is equivalent to two consecutive newlines. A blank line signifies the end of a cue.

+ +

文字內容中不能包含「-->」字串、「&」符號或「<」符號。如欲使用後兩者,可採跳脫字串「&amp;」或「&lt;」。此外雖規格上允許使用「>」字元,仍然建議跳脫為「&gt;」以避免混淆。若您使用 WebVTT 檔作為後設資料,則可不管這些限制。

+ +

除了上述的三個跳脫字串外,還有其他四種跳脫字串,分列如下

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 6 - 跳脫字串
名稱字元跳脫字串
「與」&&amp;
小於<&lt;
大於>&gt;
左到右標記 &lrm;
右到左標記 &rlm;
不斷行空白 &nbsp;
+ +

 

+ +

文字內容中的標籤

+ +

有很多標籤(例如 <bold>)可以用在文字內容中,但若 {{ HTMLElement("track") }} 的 {{ htmlattrxref("kind") }} 設定為 chapters 時,其中所用的 WebVTT  檔案裡就不能使用標籤。

+ + + +

 

+ +

以下則需要開頭標籤與結束標籤(例如 <b>text</b>)。

+ + + +

 

+ +

瀏覽器支援

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
基本支援18 以上24 (預設為關閉)10 以上15.0 以上 7 以上
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IChrome for MobileOpera MobileSafari Mobile
基本支援4.4 以上       目前尚不支援         35.0 以上   21.0 以上7 以上
+ +

 

+ +

 

+
+ +

規格

+ + diff --git a/files/zh-tw/web/api/web_workers_api/index.html b/files/zh-tw/web/api/web_workers_api/index.html new file mode 100644 index 0000000000..ba18e065dd --- /dev/null +++ b/files/zh-tw/web/api/web_workers_api/index.html @@ -0,0 +1,215 @@ +--- +title: Web Workers API +slug: Web/API/Web_Workers_API +translation_of: Web/API/Web_Workers_API +--- +

{{DefaultAPISidebar("Web Workers API")}}

+ +

Web Workers are a mechanism by which a script operation can be made to run in a background thread separate from the main execution thread of a web application. The advantage of this is that laborious processing can be performed in a separate thread, allowing the main (usually the UI) thread to run without being blocked/slowed down.

+ +

Web Workers concepts and usage

+ +

A worker is an object created using a constructor (e.g. {{domxref("Worker.Worker", "Worker()")}}) that runs a named JavaScript file — this file contains the code that will run in the worker thread; workers run in another global context that is different from the current {{domxref("window")}}. This context is represented by a {{domxref("DedicatedWorkerGlobalScope")}} object in the case of dedicated workers (standard workers that are utilized by a single script; shared workers use {{domxref("SharedWorkerGlobalScope")}}).

+ +

You can run whatever code you like inside the worker thread, with some exceptions. For example, you can't directly manipulate the DOM from inside a worker, or use some default methods and properties of the {{domxref("window")}} object. But you can use a large number of items available under window, including WebSockets, and data storage mechanisms like IndexedDB and the Firefox OS-only Data Store API.  See Functions and classes available to workers for more details.

+ +

Data is sent between workers and the main thread via a system of messages — both sides send their messages using the postMessage() method, and respond to messages via the onmessage event handler (the message is contained within the {{event("Message")}} event's data attribute.) The data is copied rather than shared.

+ +

Workers may in turn spawn new workers, as long as those workers are hosted within the same origin as the parent page.  In addition, workers may use XMLHttpRequest for network I/O, with the exception that the responseXML and channel attributes on XMLHttpRequest always return null.

+ +

In addition to dedicated workers, there are other types of worker:

+ + + +
+

Note: As per the Web workers Spec, worker error events should not bubble (see {{bug(1188141)}}. This has been implemented in Firefox 42.

+
+ +

Web Worker interfaces

+ +
+
{{domxref("AbstractWorker")}}
+
Abstracts properties and methods common to all kind of workers (i.e. {{domxref("Worker")}} or {{domxref("SharedWorker")}}).
+
{{domxref("Worker")}}
+
Represents a running worker thread, allowing you to pass messages to the running worker code.
+
{{domxref("SharedWorker")}}
+
Represents a specific kind of worker that can be accessed from several browsing contexts, being several windows, iframes or even workers.
+
{{domxref("WorkerGlobalScope")}}
+
Represents the generic scope of any worker (doing the same job as {{domxref("Window")}} does for normal web content). Different types of worker have scope objects that inherit from this interface and add more specific features.
+
{{domxref("DedicatedWorkerGlobalScope")}}
+
Represents the scope of a dedicated worker, inheriting from {{domxref("WorkerGlobalScope")}} and adding some dedicated features.
+
{{domxref("SharedWorkerGlobalScope")}}
+
Represents the scope of a shared worker, inheriting from {{domxref("WorkerGlobalScope")}} and adding some dedicated features.
+
{{domxref("WorkerNavigator")}}
+
Represents the identity and state of the user agent (the client):
+
+ +

Examples

+ +

We have created a couple of simple demos to show basic usage:

+ + + +

You can find out more information on how these demos work in Using web workers.

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#toc-workers')}}{{Spec2('HTML WHATWG')}}No change from {{SpecName("Web Workers")}}.
{{SpecName('Web Workers')}}{{Spec2('Web Workers')}}Initial definition.
+ +

Browser compatibility

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support4{{CompatGeckoDesktop(1.9.1)}}10.010.64
Shared workers4{{CompatGeckoDesktop(29)}}{{CompatNo}}10.64
Passing data using structured cloning13{{CompatGeckoDesktop(8)}}10.011.56
Passing data using  transferable objects17 {{property_prefix("webkit")}}
+ 21
{{CompatGeckoDesktop(18)}}{{CompatNo}}156
Global {{domxref("window.URL", "URL")}}10[1]
+ 23
{{CompatGeckoDesktop(21)}}11156[1]
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)Firefox OS (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support4.44{{CompatGeckoMobile(1.9.1)}}1.0.110.011.55.1
Shared workers{{CompatNo}}4291.4{{CompatNo}}{{CompatNo}}{{CompatNo}}
Passing data using structured cloning{{CompatNo}}481.0.1{{CompatNo}}{{CompatNo}}{{CompatNo}}
Passing data using  transferable objects{{CompatNo}}{{CompatNo}}181.0.1{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

[1] As webkitURL.

+ +

See also

+ + diff --git a/files/zh-tw/web/api/web_workers_api/using_web_workers/index.html b/files/zh-tw/web/api/web_workers_api/using_web_workers/index.html new file mode 100644 index 0000000000..82d484f6a2 --- /dev/null +++ b/files/zh-tw/web/api/web_workers_api/using_web_workers/index.html @@ -0,0 +1,791 @@ +--- +title: 使用 Web Workers +slug: Web/API/Web_Workers_API/Using_web_workers +translation_of: Web/API/Web_Workers_API/Using_web_workers +--- +
+

Web Workers 提供簡單的方法讓網頁在背景執行緒 (Thread) 中執行程式,而不干擾使用者介面運行另外,Worker也可以利用 XMLHttpRequest 執行輸出/輸入(但是responseXML 和channel這兩個屬性為null)一個worker可以藉由事件處理器來和 web worker 創造端互相傳送訊息,接下來本文會提供使用 web worker 的詳細說明。

+
+ +

Web Workers API

+ +

透過 worker 建構子 (如 {{domxref("Worker.Worker", "Worker()")}}) 便可以產生 worker 物件,並且執行 JavaScript 檔案。在 worker 中的 JavaScript 運行在不同於 {{domxref("window")}} 的執行緒環境,所以在 worker 中存取全域物件應該要透過 {{domxref("window.self","self")}},如果透過 {{domxref("window")}} 會導致錯誤發生。

+ +

Dedicated worker (專有 worker) 是一般 worker,只能被產生它的檔案存取,{{domxref("DedicatedWorkerGlobalScope")}} 物件代表其執行環境;而Shared worker (共享 worker) 則能夠被不同檔案存取,{{domxref("SharedWorkerGlobalScope")}}) 物件代表其執行環境。

+ +
+

Note: worker 其他文件說明請見 The Web Workers API landing page

+
+ +

基本上 worker 能夠執行任何事情,比如說 WebSocketsIndexedDB、和 Firefox OS 特有的 Data Store API ,然而直接存取 DOM 或是 {{domxref("window")}} 物件的一些方法和屬性則不被允許,更多細節請見 worker 可存取知函數和類別

+ +

主執行緒和 worker 執行緒之間用 postMessage() 方法發送訊息,然後透過 onmessage 事件接受訊息 (訊息存在 {{event("Message")}} 事件的 data 屬性之中),其中被傳送的資料並非共享而是複製一份後傳送。

+ +

worker 可以產生新 worker,只要新 worker 的來源 (origin) 和父頁面相同,也可以利用 XMLHttpRequest 執行輸出/輸入(但是responseXML 和channel這兩個屬性為null)。

+ +

Dedicated workers

+ +

dedicated worker 只能被產生它的檔案存取,下面我們先介紹簡單的 Basic dedicated worker example (run dedicated worker) 範例。這個範例會將兩個數字送入 worker 相乘,然後再於前端頁面顯示相乘結果。

+ +

偵測 Worker 功能

+ +

為了向下相容、避免錯誤,最好是確保 worker 存在後再取用之 (main.js):

+ +
if (window.Worker) {
+
+  ...
+
+}
+ +

產生 dedicated worker

+ +

只要呼叫 {{domxref("Worker.Worker", "Worker()")}} 建構子,傳入 JS 檔案的 URI,便可以生成一個 worker 執行緒 (main.js):

+ +
+
var myWorker = new Worker("worker.js");
+
+
+ +

和 dedicated worker 發送訊息

+ +

{{domxref("Worker.postMessage", "postMessage()")}} 方法以及 {{domxref("Worker.onmessage", "onmessage")}} 事件處理器就是和 worker 發送訊息的關鍵 (main.js):

+ +
first.onchange = function() {
+  myWorker.postMessage([first.value,second.value]);
+  console.log('Message posted to worker');
+}
+
+second.onchange = function() {
+  myWorker.postMessage([first.value,second.value]);
+  console.log('Message posted to worker');
+}
+ +

範例中有兩個 {{htmlelement("input")}} 元素,first 和 second,當元素值改變時,我們會利用 postMessage() 方法告訴 worker 改變的值 (這邊用陣列,也可以用其他類別)。

+ +

然後在 worker 裡我們從 onmessage 接收訊息 (worker.js):

+ +
onmessage = function(e) {
+  console.log('Message received from main script');
+  var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
+  console.log('Posting message back to main script');
+  postMessage(workerResult);
+}
+ +

onmessage 事件物件的 data 屬性存有傳送過來的訊息資料,也就是 input 值;worker 收到後將傳過來的兩個值相乘,再 postMessage 傳回去。

+ +

回到主執行,同樣透過 onmessage 事件,收到 worker 回傳還來的計算值 :

+ +
myWorker.onmessage = function(e) {
+  result.textContent = e.data;
+  console.log('Message received from worker');
+}
+ +

拿到存在事件 data 中的計算值後,我們接著將值以 textContent 顯示出來。

+ +
+

Note : 建構 Worker 的URI必須遵從 same-origin policy。目前各家瀏覽器在這方面存有歧異,Gecko 10.0 {{geckoRelease("10.0")}} 以後允許 data URI 而 Internet Explorer 10 不允許 Blob URI。

+
+ +
Note: 在主執行緒中存取 onmessage 與 postMessage 需要主動掛在 worker 物件上,在 worker 執行緒則不用,這是因為 worker 執行緒的全域物件便是 worker 物件。
+ +
Note: 和 worker 傳送的資料並非共享而是複製一份後傳送,詳細請參照 {{anch("Transferring data to and from workers: further details")}}。
+ +

結束 worker

+ +

在主執行緒裡呼叫 {{domxref("Worker", "terminate")}} 就可結束 worker :

+ +
myWorker.terminate();
+ +

請注意不論 worker 正在執行的運算完成與否,一但呼叫後 worker 便會立刻被終止。

+ +

而在 worker 執行緒裡,worker 可以呼叫自己的 {{domxref("WorkerGlobalScope", "close")}} 方法來結束 :

+ +
close();
+ +

錯誤處理

+ +

當執行時期錯誤發生時,onerror 事件處理器會被呼叫,onerror事件處理器會收到一名為 error 的事件物件 (實作 ErrorEvent Interface),該事件不會 bubble 且可取消,如果要避免事件預設行為,可以呼叫 preventDefault()

+ +

以下三個部分是錯誤事件較關鍵的地方:

+ +
+
message
+
供人閱讀的錯誤訊息
+
filename
+
錯誤發生所在的檔案名稱
+
lineno
+
錯誤發生所在的行數
+
+ +

產生 subworker

+ +

worker 可以產生其他 worker (subworker),subworker 的來源也必須和主頁相同,另外,subworker 的 URI 的解析是相對於父 worker 的位置而非所在頁面,這項特色有助於追蹤 worker 間的相依性。

+ +

引入程式腳本與函式庫 (library)

+ +

Worker執行緒能存取一個全域函數 (global function), importScripts()。importScripts() 可以讓 worker 端引入相同網域的程式碼腳本與 libraries,importScripts()可接收零到數個要被輸入資源的URI,底下為幾個範例:

+ +
importScripts();                        /* imports nothing */
+importScripts('foo.js');                /* imports just "foo.js" */
+importScripts('foo.js', 'bar.js');      /* imports two scripts */
+
+ +

瀏覽器會載入並執行每個程式碼腳本,然後 worker 能夠存取程式碼腳本內定義的全域變數,若是腳本無法載入,會產生一個 NETWORK_ERROR,後續的程式碼不會被執行,但是先前執行過的程式碼或用 window.setTimeout() 延遲執行的程式碼依然有效,而 importScripts() 之後宣告的函數也一樣存在,因為這些程式碼總是在其他程式碼之前就解析過了。

+ +
Note: 雖然程式碼腳本的下載順序不一定,但執行順序會遵照傳入importScripts()的順序,這是同步完成的,importScripts()不會回傳直到所有的程式碼都下載並執行完。
+ +

Shared workers

+ +

shared worker 能夠被多個程式腳本存取,縱使跨越不同 window、iframe 或 worker。這邊的 Basic shared worker example (run shared worker) 範例和 dedicated worker 範例類似,但多了兩個可以讓多個檔案存取的函數:數字相乘以及數字平方

+ +

請注意 dedicated worker 與 shared worker 間的差異處,範例裡會有兩份 HTML 頁面,各自都利用同一個 worker 處理運算。

+ +
+

Note: 所有的瀏覽環境都必需共享相同的來源(相同protocol, host 和 port),shared worker 才能讓不同瀏覽環境存取。

+
+ +
+

Note: 在 Firefox, shared worker 無法在一般和隱私模式間共享 ({{bug(1177621)}})。

+
+ +

產生 shared worker

+ +

和 dedicated worker 做法差不多,只是用另一個 SharedWorker 建構子來產生  shared worker,見 index.htmlindex2.html:

+ +
var myWorker = new SharedWorker("worker.js");
+ +

相當不 一樣的是和 shared worker 溝通必須要透過 port 物件,其實 dedicated worker 也是如此,只不過一切是在背景後自動完成。

+ +

開啟 port 連線一是在 onmessage 事件下背景完成,二是藉由主動呼叫 start() 好開始傳送訊息。範例 multiply.js 以及 worker.js 因為註冊了 onmessage 事件,所以其實可以省略呼叫 start(),然而若是 message 事件是經由 addEventListener()註冊,那麼便需要呼叫 start() 了。

+ +

當使用 start() 開啟 port 連線,那麼雙向溝通便需要主執行緒和 worker 兩端都呼叫 start()。

+ +
myWorker.port.start();  // called in parent thread
+ +
port.start();  // called in worker thread, assuming the port variable references a port
+ +

和 shared worker 發送訊息

+ +

如同前面,現在可以呼叫 postMessage() 發送訊息,只不過這次需要透過 port 物件 (一樣請參考 multiply.jssquare.js):

+ +
squareNumber.onchange = function() {
+  myWorker.port.postMessage([squareNumber.value,squareNumber.value]);
+  console.log('Message posted to worker');
+}
+ +

worker 方面也增加了一些程式碼 (worker.js):

+ +
onconnect = function(e) {
+  var port = e.ports[0];
+  port.onmessage = function(e) {
+    var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
+    port.postMessage(workerResult);
+  }
+  port.start();  // not necessary since onmessage event handler is being used
+}
+ +

首先,先監聽連線建立的 onconnect 事件,例如當主執行緒建立 onmessage 事件或呼叫 start()

+ +

然後從 onconnect 事件物件,我們可以取得 port 物件使用之。

+ +

取得 port 之後,我們註冊 port 上的 onmessage 事件,當有訊息進來便取回資料進行運算後回傳回去;註冊 onmessage 事件的同時也自動建立連線,所以說不需要呼叫start() 了。

+ +

最後在主執行緒端,我們同樣由 onmessage 事件取回回傳過來的訊息 (一樣請參考 multiply.jssquare.js):

+ +
myWorker.port.onmessage = function(e) {
+  result2.textContent = e.data[0];
+  console.log('Message received from worker');
+}
+ +

 

+ +

執行緒 (Thread) 安全

+ +

{{domxref("Worker")}} 會產生真正 OS 層級的執行緒,細心的開發者或許會擔心同步問題。

+ +

不過 worker 會十分注意和其他執行緒溝通的狀況,不會去存取非執行緒安全的元件,如 DOM ,而且資料的傳遞也都序列化 (serialized) ,所以說很難會發生同步問題。

+ +

和 workers 傳遞資料:更多細節

+ +

和 workers 傳遞的資料會先被複製一份,而非共享;經過序列化後 (serialized) 傳輸,然後在另一端反序列化 (de-serialized) 取出,大部份的瀏覽器都是以 結構化複製 (structured cloning) 實作這項特色.

+ +

下面的 emulateMessage() 會模擬和 worker 傳遞訊息時,複製資料的行為。

+ +
function emulateMessage (vVal) {
+    return eval("(" + JSON.stringify(vVal) + ")");
+}
+
+// Tests
+
+// test #1
+var example1 = new Number(3);
+console.log(typeof example1); // object
+console.log(typeof emulateMessage(example1)); // number
+
+// test #2
+var example2 = true;
+console.log(typeof example2); // boolean
+console.log(typeof emulateMessage(example2)); // boolean
+
+// test #3
+var example3 = new String("Hello World");
+console.log(typeof example3); // object
+console.log(typeof emulateMessage(example3)); // string
+
+// test #4
+var example4 = {
+    "name": "John Smith",
+    "age": 43
+};
+console.log(typeof example4); // object
+console.log(typeof emulateMessage(example4)); // object
+
+// test #5
+function Animal (sType, nAge) {
+    this.type = sType;
+    this.age = nAge;
+}
+var example5 = new Animal("Cat", 3);
+alert(example5.constructor); // Animal
+alert(emulateMessage(example5).constructor); // Object
+ +

所謂的訊息就是經過複製、非共享的資料,到這邊你應該已經知道 postMessage() 負責發送訊息,然後 message 事件 {{domxref("MessageEvent.data", "data")}} 的 attribute 則存有傳送的訊息資料。

+ +

example.html: (the main page):

+ +
var myWorker = new Worker("my_task.js");
+
+myWorker.onmessage = function (oEvent) {
+  console.log("Worker said : " + oEvent.data);
+};
+
+myWorker.postMessage("ali");
+ +

my_task.js (the worker):

+ +
postMessage("I\'m working before postMessage(\'ali\').");
+
+onmessage = function (oEvent) {
+  postMessage("Hi " + oEvent.data);
+};
+ +

結構化複製(structured cloning) 演算法支援 JSON 以及迴圈參照(circular references)。

+ +

資料傳遞範例

+ +

範例 1: 非同步 eval()

+ +

下面透過 data URLeval()示範如何在 worker 非同步執行允許的程式碼:

+ +
// Syntax: asyncEval(code[, listener])
+
+var asyncEval = (function () {
+  var aListeners = [], oParser = new Worker("data:text/javascript;charset=US-ASCII,onmessage%20%3D%20function%20%28oEvent%29%20%7B%0A%09postMessage%28%7B%0A%09%09%22id%22%3A%20oEvent.data.id%2C%0A%09%09%22evaluated%22%3A%20eval%28oEvent.data.code%29%0A%09%7D%29%3B%0A%7D");
+
+  oParser.onmessage = function (oEvent) {
+    if (aListeners[oEvent.data.id]) { aListeners[oEvent.data.id](oEvent.data.evaluated); }
+    delete aListeners[oEvent.data.id];
+  };
+
+  return function (sCode, fListener) {
+    aListeners.push(fListener || null);
+    oParser.postMessage({
+      "id": aListeners.length - 1,
+      "code": sCode
+    });
+  };
+})();
+ +

data URL 相當於網路請求,範例中的 data URL 會在 worker 執行下列程式碼回應訊息:

+ +
onmessage = function (oEvent) {
+  postMessage({
+    "id": oEvent.data.id,
+    "evaluated": eval(oEvent.data.code)
+  });
+}
+ +

應用範例:

+ +
// asynchronous alert message...
+asyncEval("3 + 2", function (sMessage) {
+    alert("3 + 2 = " + sMessage);
+});
+
+// asynchronous print message...
+asyncEval("\"Hello World!!!\"", function (sHTML) {
+    document.body.appendChild(document.createTextNode(sHTML));
+});
+
+// asynchronous void...
+asyncEval("(function () {\n\tvar oReq = new XMLHttpRequest();\n\toReq.open(\"get\", \"http://www.mozilla.org/\", false);\n\toReq.send(null);\n\treturn oReq.responseText;\n})()");
+ +

範例2: JSON 資料進階傳遞與呼叫系統

+ +

下面的範例系統適合需要在主頁面和 worker 傳遞複雜資料和呼叫多個函數的情境。

+ +

example.html (主頁面):

+ +
<!doctype html>
+<html>
+<head>
+<meta charset="UTF-8"  />
+<title>MDN Example - Queryable worker</title>
+<script type="text/javascript">
+  /*
+    QueryableWorker instances methods:
+     * sendQuery(queryable function name, argument to pass 1, argument to pass 2, etc. etc): calls a Worker's queryable function
+     * postMessage(string or JSON Data): see Worker.prototype.postMessage()
+     * terminate(): terminates the Worker
+     * addListener(name, function): adds a listener
+     * removeListener(name): removes a listener
+    QueryableWorker instances properties:
+     * defaultListener: the default listener executed only when the Worker calls the postMessage() function directly
+  */
+  function QueryableWorker (sURL, fDefListener, fOnError) {
+    var oInstance = this, oWorker = new Worker(sURL), oListeners = {};
+    this.defaultListener = fDefListener || function () {};
+    oWorker.onmessage = function (oEvent) {
+      if (oEvent.data instanceof Object && oEvent.data.hasOwnProperty("vo42t30") && oEvent.data.hasOwnProperty("rnb93qh")) {
+        oListeners[oEvent.data.vo42t30].apply(oInstance, oEvent.data.rnb93qh);
+      } else {
+        this.defaultListener.call(oInstance, oEvent.data);
+      }
+    };
+    if (fOnError) { oWorker.onerror = fOnError; }
+    this.sendQuery = function (/* queryable function name, argument to pass 1, argument to pass 2, etc. etc */) {
+      if (arguments.length < 1) { throw new TypeError("QueryableWorker.sendQuery - not enough arguments"); return; }
+      oWorker.postMessage({ "bk4e1h0": arguments[0], "ktp3fm1": Array.prototype.slice.call(arguments, 1) });
+    };
+    this.postMessage = function (vMsg) {
+      //I just think there is no need to use call() method
+      //how about just oWorker.postMessage(vMsg);
+      //the same situation with terminate
+      //well,just a little faster,no search up the prototye chain
+      Worker.prototype.postMessage.call(oWorker, vMsg);
+    };
+    this.terminate = function () {
+      Worker.prototype.terminate.call(oWorker);
+    };
+    this.addListener = function (sName, fListener) {
+      oListeners[sName] = fListener;
+    };
+    this.removeListener = function (sName) {
+      delete oListeners[sName];
+    };
+  };
+
+  // your custom "queryable" worker
+  var oMyTask = new QueryableWorker("my_task.js" /* , yourDefaultMessageListenerHere [optional], yourErrorListenerHere [optional] */);
+
+  // your custom "listeners"
+
+  oMyTask.addListener("printSomething", function (nResult) {
+    document.getElementById("firstLink").parentNode.appendChild(document.createTextNode(" The difference is " + nResult + "!"));
+  });
+
+  oMyTask.addListener("alertSomething", function (nDeltaT, sUnit) {
+    alert("Worker waited for " + nDeltaT + " " + sUnit + " :-)");
+  });
+</script>
+</head>
+<body>
+  <ul>
+    <li><a id="firstLink" href="javascript:oMyTask.sendQuery('getDifference', 5, 3);">What is the difference between 5 and 3?</a></li>
+    <li><a href="javascript:oMyTask.sendQuery('waitSomething');">Wait 3 seconds</a></li>
+    <li><a href="javascript:oMyTask.terminate();">terminate() the Worker</a></li>
+  </ul>
+</body>
+</html>
+ +

my_task.js (worker):

+ +
// your custom PRIVATE functions
+
+function myPrivateFunc1 () {
+  // do something
+}
+
+function myPrivateFunc2 () {
+  // do something
+}
+
+// etc. etc.
+
+// your custom PUBLIC functions (i.e. queryable from the main page)
+
+var queryableFunctions = {
+  // example #1: get the difference between two numbers:
+  getDifference: function (nMinuend, nSubtrahend) {
+      reply("printSomething", nMinuend - nSubtrahend);
+  },
+  // example #2: wait three seconds
+  waitSomething: function () {
+      setTimeout(function() { reply("alertSomething", 3, "seconds"); }, 3000);
+  }
+};
+
+// system functions
+
+function defaultQuery (vMsg) {
+  // your default PUBLIC function executed only when main page calls the queryableWorker.postMessage() method directly
+  // do something
+}
+
+function reply (/* listener name, argument to pass 1, argument to pass 2, etc. etc */) {
+  if (arguments.length < 1) { throw new TypeError("reply - not enough arguments"); return; }
+  postMessage({ "vo42t30": arguments[0], "rnb93qh": Array.prototype.slice.call(arguments, 1) });
+}
+
+onmessage = function (oEvent) {
+  if (oEvent.data instanceof Object && oEvent.data.hasOwnProperty("bk4e1h0") && oEvent.data.hasOwnProperty("ktp3fm1")) {
+    queryableFunctions[oEvent.data.bk4e1h0].apply(self, oEvent.data.ktp3fm1);
+  } else {
+    defaultQuery(oEvent.data);
+  }
+};
+
+ +

移轉資料所有權 - 可移轉物件 (transferable objects)

+ +

Google Chrome 17+ 以及 Firefox 18+ 能夠和 worker 高效能地傳送另外一種特定型態物件 (可移轉物件, transferable objects,這種物件實作了 {{domxref("Transferable")}} 介面),可移轉物件當被傳送到另一端時並不需要複製,因此可以大大提升傳送大型資料物件的效能;這好比像是 C/C++ 的 pass-by-reference,但是不同的是,一旦移轉後原先的環境便失去了持有資料,例如當主頁面傳送 {{domxref("ArrayBuffer")}} 後,主頁面便不再能夠使用這筆資料物件了,這筆資料物件的存取連結已經靜靜地移轉到 worker 端了。

+ +
// Create a 32MB "file" and fill it.
+var uInt8Array = new Uint8Array(1024*1024*32); // 32MB
+for (var i = 0; i < uInt8Array.length; ++i) {
+  uInt8Array[i] = i;
+}
+
+worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);
+
+ +
+

Note: 關於更多可移轉物件的資訊, 效能和功能偵測,請參考 HTML5 Rocks 上 Transferable Objects: Lightning Fast! 一文。

+
+ +

Embedded workers

+ +

不像 {{HTMLElement("script")}},並沒有一套正式標準的方法將 worker 的程式碼嵌入到頁面之中,不過沒有 src 屬性而且 mime-type 不屬於可執行程式碼的 {{HTMLElement("script")}} 元素會被視為 javascript 可以取用的資料區塊(data block),資料區塊是一項 HTML5 可用於攜帶文字資料的特色功能,利用資料區塊我們就有辦法嵌入 worker 的程式碼到頁面中:

+ +
<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8" />
+<title>MDN Example - Embedded worker</title>
+<script type="text/js-worker">
+  // This script WON'T be parsed by JS engines because its mime-type is text/js-worker.
+  var myVar = "Hello World!";
+  // Rest of your worker code goes here.
+</script>
+<script type="text/javascript">
+  // This script WILL be parsed by JS engines because its mime-type is text/javascript.
+  function pageLog (sMsg) {
+    // Use a fragment: browser will only render/reflow once.
+    var oFragm = document.createDocumentFragment();
+    oFragm.appendChild(document.createTextNode(sMsg));
+    oFragm.appendChild(document.createElement("br"));
+    document.querySelector("#logDisplay").appendChild(oFragm);
+  }
+</script>
+<script type="text/js-worker">
+  // This script WON'T be parsed by JS engines because its mime-type is text/js-worker.
+  onmessage = function (oEvent) {
+    postMessage(myVar);
+  };
+  // Rest of your worker code goes here.
+</script>
+<script type="text/javascript">
+  // This script WILL be parsed by JS engines because its mime-type is text/javascript.
+
+  // In the past...:
+  // blob builder existed
+  // ...but now we use Blob...:
+  var blob = new Blob(Array.prototype.map.call(document.querySelectorAll("script[type=\"text\/js-worker\"]"), function (oScript) { return oScript.textContent; }),{type: "text/javascript"});
+
+  // Creating a new document.worker property containing all our "text/js-worker" scripts.
+  document.worker = new Worker(window.URL.createObjectURL(blob));
+
+  document.worker.onmessage = function (oEvent) {
+    pageLog("Received: " + oEvent.data);
+  };
+
+  // Start the worker.
+  window.onload = function() { document.worker.postMessage(""); };
+</script>
+</head>
+<body><div id="logDisplay"></div></body>
+</html>
+ +

Embedded worker 在 document.worker 之中。

+ +

其他範例

+ +

下面介紹其他使用 worker 的範例。

+ +

在背景中執行運算

+ +

worker 主要的用處在避免重度 CPU 運算的任務阻礙到 UI 執行緒運行;這邊我們用 worker 來跑 Fibonacci 數列運算。

+ +

JavaScript

+ +

fibonacci.js 中的程式碼會被另一份 HTML 引用。

+ +
var results = [];
+
+function resultReceiver(event) {
+  results.push(parseInt(event.data));
+  if (results.length == 2) {
+    postMessage(results[0] + results[1]);
+  }
+}
+
+function errorReceiver(event) {
+  throw event.data;
+}
+
+onmessage = function(event) {
+  var n = parseInt(event.data);
+
+  if (n == 0 || n == 1) {
+    postMessage(n);
+    return;
+  }
+
+  for (var i = 1; i <= 2; i++) {
+    var worker = new Worker("fibonacci.js");
+    worker.onmessage = resultReceiver;
+    worker.onerror = errorReceiver;
+    worker.postMessage(n - i);
+  }
+ };
+ +

worker 程式碼中註冊了一個 onmessage 事件處理器用來接收另一端 postMessage 過來的訊息 (請注意這並非定義一個全域變數或函數,var onmessagefunction onmessage 會定義全域變數,但不會註冊事件處理器),然後開始進行遞迴運算。

+ +

HTML

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8"  />
+    <title>Test threads fibonacci</title>
+  </head>
+  <body>
+
+  <div id="result"></div>
+
+  <script language="javascript">
+
+    var worker = new Worker("fibonacci.js");
+
+    worker.onmessage = function(event) {
+      document.getElementById("result").textContent = event.data;
+      dump("Got: " + event.data + "\n");
+    };
+
+    worker.onerror = function(error) {
+      dump("Worker error: " + error.message + "\n");
+      throw error;
+    };
+
+    worker.postMessage("5");
+
+  </script>
+  </body>
+</html>
+
+ +

onmessage 事件處理器會接收 worker 回傳的運算結果,然後顯示在頁面上,如果有問題, onerror 事件處理器會 輸出 錯誤訊息。

+ +

和 worker 溝通則是利用 postMessage。

+ +

範例測試

+ +

在背景中執行 web I/O

+ +

範例請見 Using workers in extensions 。

+ +

分割任務到多個 workers

+ +

基於多核 cpu 的普及,分割複雜任務到多個 workers 將可能有助於利用多核心 cpu 的優勢。

+ +

其他類型的 worker

+ +

除了 dedicated 和 shared web workers,還有其他種類:

+ + + +

Worker 可存取之函數與介面

+ +

大多數 Javascript 的功能 workre 皆可以使用,包含:

+ + + +

worker 無法操作主頁面的物件與 DOM,如有相關需求,必須要間接透過 {{domxref("DedicatedWorkerGlobalScope.postMessage")}} 通知主頁面,讓主頁面執行需求。

+ +
+

Note: 所有 worker 可存取功能一覽表,請見 Functions and interfaces available to workers.

+
+ +

標準規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#toc-workers')}}{{Spec2('HTML WHATWG')}}No change from {{SpecName("Web Workers")}}.
{{SpecName('Web Workers')}}{{Spec2('Web Workers')}}Initial definition.
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support4[1]{{CompatGeckoDesktop("1.9.1")}}10.010.6[1]4[2]
Shared workers4[1]{{CompatGeckoDesktop(29)}}{{CompatNo}}10.64[2]
Passing data using structured cloning13{{CompatGeckoDesktop(8)}}10.011.56
Passing data using transferable objects17 {{property_prefix("webkit")}}
+ 21
{{CompatGeckoDesktop(18)}}{{CompatNo}}156
Global {{domxref("window.URL", "URL")}}10[3]
+ 23
{{CompatGeckoDesktop(21)}}11156[3]
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome MobileFirefox Mobile (Gecko)Firefox OS (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support4.44[1]3.51.0.110.011.5[1]5.1[2]
Shared workers{{CompatNo}}4[1]81.0.1{{CompatNo}}{{CompatNo}}{{CompatNo}}
Passing data using structured cloning{{CompatNo}}481.0.1{{CompatNo}}{{CompatNo}}{{CompatNo}}
Passing data using transferable objects{{CompatNo}}{{CompatNo}}181.0.1{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

[1] Chrome 和 Opera 會丟出錯誤:"Uncaught SecurityError: Failed to construct 'Worker': Script at 'file:///Path/to/worker.js' cannot be accessed from origin 'null'.",當從 local 端而非網域執行 worker。

+ +

[2] Safari 7.1.2 可以從 worker 呼叫 console.log,但並不會任何效果,而更早的版本則是不允許呼叫 console.log。

+ +

[3] 會有前綴 webkitURL.

+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/api/webgl_api/index.html b/files/zh-tw/web/api/webgl_api/index.html new file mode 100644 index 0000000000..561594474c --- /dev/null +++ b/files/zh-tw/web/api/webgl_api/index.html @@ -0,0 +1,255 @@ +--- +title: WebGL +slug: Web/API/WebGL_API +tags: + - WebGL +translation_of: Web/API/WebGL_API +--- +

{{WebGLSidebar}}

+ +

WebGL (Web Graphics Library) 是一個透過瀏覽器渲染3D及2D圖像的 JavaScript API ,且不需要安裝任何插件。 WebGL 透過與OpenGL ES 2.0緊密連結的API,將3D圖像帶入HTML5中,並可透過canvas元素呈現於瀏覽器中

+ +

Support for WebGL is present in Firefox 4+, Google Chrome 9+, Opera 12+, Safari 5.1+ 以及 Internet Explorer 11+; 然而,使用者的 GPU 也必須支援。

+ +
+
+

Development topics

+ +
+
從 WebGL 開始吧
+
如何設立一個 WebGL 環境。
+
增加 2D 的東西到 WebGL 環境
+
如何使用 WebGL 來呈現一個簡單的平面形狀。
+
Using shaders to apply color in WebGL
+
Demonstrates how to add color to shapes using shaders.
+
Animating objects with WebGL
+
Shows how to rotate and translate objects to create simple animations.
+
Creating 3D objects using WebGL
+
Shows how to create and animate a 3D object (in this case, a cube).
+
Using textures in WebGL
+
Demonstrates how to map textures onto the faces of an object.
+
Lighting in WebGL
+
How to simulate lighting effects in your WebGL context.
+
Animating textures in WebGL
+
Shows how to animate textures; in this case, by mapping an Ogg video onto the faces of a rotating cube.
+
WebGL best practices
+
Tips and suggestions to improve your WebGL content.
+
Cross-domain textures
+
Information about loading textures from domains other than the one from which your content was loaded.
+
Using extensions
+
How to use extensions that are available in WebGL.
+
+
+ +
+ + +
+
WebGL Specification
+
The WebGL specification.
+
Khronos WebGL site
+
The main web site for WebGL at the Khronos Group.
+
Learning WebGL
+
A site with tutorials on how to use WebGL.
+
WebGL Fundamentals
+
A basic tutorial with fundamentals of WebGL.
+
WebGL Matrices
+
An introduction to matrices' use in 2D WebGL. This series also goes on to explain the math behind perspective 3D.
+
The WebGL Cookbook
+
A web site with handy recipes for writing WebGL code.
+
Planet WebGL
+
A feed aggregator for people involved in the WebGL community.
+
ewgl-matrices
+
A blazing fast matrix library for WebGL
+
glMatrix
+
JavaScript Matrix and Vector library for High Performance WebGL apps
+
mjs
+
A JavaScript vector and matrix math library, optimized for WebGL usage.
+
Sylvester
+
An open source library for manipulating vectors and matrices. Not optimized for WebGL but extremely robust.
+
WebGL playground
+
An online tool for creating and sharing WebGL projects. Good for quick prototyping and experimenting.
+
WebGL Academy
+
An HTML/Javascript editor with tutorials to learn basics of webgl programming.
+
 
+
+
+
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox (Gecko)ChromeInternet ExplorerOperaSafari
基本支援{{CompatGeckoDesktop("2.0")}}91112 (experiment)5.1 (experiment)
OES_texture_float{{CompatGeckoDesktop("6.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
OES_standard_derivatives{{CompatGeckoDesktop("10.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
EXT_texture_filter_anisotropic{{CompatGeckoDesktop("13.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
WEBGL_compressed_texture_s3tc{{CompatGeckoDesktop("15.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
drawingBufferWidth and drawingBufferHeight attributes{{CompatGeckoDesktop("9.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox Mobile (Gecko)Chrome for AndroidIE MobileOpera MobileSafari Mobile
Basic support425 (experiment){{CompatNo}}12 (experiment){{CompatNo}}
drawingBufferWidth and drawingBufferHeight attributes{{CompatGeckoMobile("9.0")}}25{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
OES_texture_float{{CompatGeckoMobile("6.0")}}25{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
OES_standard_derivatives{{CompatGeckoMobile("10.0")}}25{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
EXT_texture_filter_anisotropic{{CompatGeckoMobile("13.0")}}25{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
OES_element_index_uint{{CompatUnknown}}25{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
OES_vertex_array_object{{CompatUnknown}}25{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
WEBGL_compressed_texture_s3tc{{CompatGeckoMobile("15.0")}}25
+ prefixed with WEBKIT_
{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
WEBKIT_EXT_texture_filter_nisotropic{{CompatNo}}25{{CompatNo}}{{CompatNo}}{{CompatUnknown}}
+
+ +

相容性小記

+ +

In addition to the browser, the GPU itself also needs to support the feature. So, for example, S3 Texture Compression (S3TC) is only available on Tegra-based tablets. Most browsers make the WebGL context available through the webgl context name, but older ones need experimental-webgl as well. In addition, the upcoming WebGL 2 is fully backwards-compatible and will have the context name experimental-webgl2 in the future for testing.

+ +

Gecko 小記

+ +

WebGL debugging and testing

+ +

Starting with Gecko 10.0 {{geckoRelease("10.0")}}, there are two preferences available which let you control the capabilities of WebGL for testing purposes:

+ +
+
webgl.min_capability_mode
+
A Boolean property that, when true, enables a minimum capability mode. When in this mode, WebGL is configured to only support the bare minimum feature set and capabilities required by the WebGL specification. This lets you ensure that your WebGL code will work on any device or browser, regardless of their capabilities. This is false by default.
+
webgl.disable_extensions
+
A Boolean property that, when true, disables all WebGL extensions. This is false by default.
+
+ +

你也可以看看

+ +

Raw WebGL: a talk by Nick Desaulniers:

+ +

{{EmbedYouTube("H4c8t6myAWU")}}

diff --git a/files/zh-tw/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html b/files/zh-tw/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html new file mode 100644 index 0000000000..45de8b801f --- /dev/null +++ b/files/zh-tw/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html @@ -0,0 +1,280 @@ +--- +title: 增加一個 2D 物件到 WebGL 環境 +slug: Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context +translation_of: Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context +--- +
{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL", "Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL")}}
+ +

當你建立了WebGL的context後,便可開始渲染。最簡單的例子就是加入一個普通的正方形。接下來,我們會介紹如何畫一個正方形。

+ +

畫場景

+ +

首先我們需要知道雖然這個範例只是要畫一個正方形,但我們還是在3D的空間裡作圖。基本上,我們就是畫一個正方形並把它放在相機前面,使正方形與使用者的視角垂直。我們要定義一個 shader,透過它來渲染我們的物件。接下來,我們會展示如何在螢幕前顯示一個正方形。

+ +

Shader

+ +

WebGL Shader使用 OpenGL ES Shading Language。 這邊不討論 shader 的細節的,但簡而言之,我們需要定義兩個shader (GPU上可執行的函數): vertex shader 和 fragment shader。這兩個 shader 會以字串的形式傳入WebGL,編譯後在GPU上執行。

+ +

Vertex shader

+ +

Vertex shader是用來定義一個變數 gl_Position 的值來控制畫布空間的值(-1到+1),下面的範例,我們設了一個變數aVertexPosition用來記錄 vertex 的位置。接下來我們將該位置乘上兩個4x4的矩陣(uProjectionMatrixuModelMatrix),並將結果設定為 gl_Position 的值。如果想要了解更多關於 Projection 和其他矩陣可以參閱這篇文件

+ +
  // Vertex shader program
+
+  const vsSource = `
+    attribute vec4 aVertexPosition;
+
+    uniform mat4 uModelViewMatrix;
+    uniform mat4 uProjectionMatrix;
+
+    void main() {
+      gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
+    }
+  `;
+
+ +

Fragment shader

+ +

每次 vertex shader 給 gl_Position 1到3個值的時候,它會分別畫出點、線、三角形。畫圖的時候,會呼叫 fragment shader 來詢問每個 pixel 的顏色。在這個範例中,我們對於每次詢問都回傳白色。

+ +

gl_FragColor 是GL預設的變數用來定義每個 fragment 的顏色,透過設定該變數的值來定義每個 pixel 的顏色,如下:

+ +
  const fsSource = `
+    void main() {
+      gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+    }
+  `;
+
+ +

初始化 shader

+ +

現在我們已經定義了兩個 shader ,我們接下來要將它們傳入WebGL,編譯並連結。下面的程式碼呼叫了 loadShader 來建立兩個shader。接下來,我們要新增一個程式,並將 shader 加入該程式,並將程式連結起來。如果編譯或連接失敗,程式碼會顯示錯誤訊息。

+ +

 

+ +
//
+// 初始化 shader 來告知WebGL怎麼畫
+//
+function initShaderProgram(gl, vsSource, fsSource) {
+  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
+  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
+
+  // 建立 shader 程式
+
+  const shaderProgram = gl.createProgram();
+  gl.attachShader(shaderProgram, vertexShader);
+  gl.attachShader(shaderProgram, fragmentShader);
+  gl.linkProgram(shaderProgram);
+
+  // 錯誤處理
+
+  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+    alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
+    return null;
+  }
+
+  return shaderProgram;
+}
+
+//
+// creates a shader of the given type, uploads the source and
+// compiles it.
+//
+function loadShader(gl, type, source) {
+  const shader = gl.createShader(type);
+
+  // Send the source to the shader object
+
+  gl.shaderSource(shader, source);
+
+  // Compile the shader program
+
+  gl.compileShader(shader);
+
+  // See if it compiled successfully
+
+  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+    alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
+    gl.deleteShader(shader);
+    return null;
+  }
+
+  return shader;
+}
+
+ +

 

+ +

我們可以透過呼叫 initShaderProgram 來建立 shader 程式

+ +
  const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
+
+ +

接下來我們需要找到 WebGL 生成出的位置。這個例子中我們有一個 attribute、兩個 uniform。 Attributes 從 buffer 獲得值。每次迭代時,vertex shader 從 buffer 得到下一個值並傳入到 attribute。 Uniform 則像是 Javascript 的全域變數。每次迭代,他們的值不會改變。為了之後方便,我們將 shader 程式與 attribute 和 uniform 存放在同一個物件中。

+ +
  const programInfo = {
+    program: shaderProgram,
+    attribLocations: {
+      vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
+    },
+    uniformLocations: {
+      projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
+      modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
+    },
+  };
+
+ +

建立正方形平面

+ +

在我們渲染前,我們要建立一個 buffer 用來儲存頂點的座標。在此我們宣告一個函數 initBuffers() ,隨著之後建立更多複雜的物件,這個動作會重複見到很多次。

+ +
function initBuffers(gl) {
+
+  // 建立一個 buffer 來儲存正方形的座標
+
+  const positionBuffer = gl.createBuffer();
+
+  // Select the positionBuffer as the one to apply buffer
+  // operations to from here out.
+
+  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+  // Now create an array of positions for the square.
+
+  const positions = [
+     1.0,  1.0,
+    -1.0,  1.0,
+     1.0, -1.0,
+    -1.0, -1.0,
+  ];
+
+  // Now pass the list of positions into WebGL to build the
+  // shape. We do this by creating a Float32Array from the
+  // JavaScript array, then use it to fill the current buffer.
+
+  gl.bufferData(gl.ARRAY_BUFFER,
+                new Float32Array(positions),
+                gl.STATIC_DRAW);
+
+  return {
+    position: positionBuffer,
+  };
+}
+
+ +

這個步驟非常簡單,一開始呼叫gl物件的函數 {{domxref("WebGLRenderingContext.createBuffer()", "createBuffer()")}} 來產生一個儲存座標的 buffer,並將將該 buffer 綁定 WebGL 的 context。

+ +

完成後,我們宣告一個陣列來儲存正方形平面各頂點的座標,並轉型為浮點數陣列並用{{domxref("WebGLRenderingContext.bufferData()", "bufferData()")}}函數傳入 gl 物件。

+ +

渲染場景

+ +

Shader 建立好了、位置也確定好了、正方形平面頂點的位置也已經放到 buffer後,我們就可以實際來渲染場景了。因為這個例子沒有任何的動畫,drawScene()函數非常單純。

+ +
function drawScene(gl, programInfo, buffers) {
+  gl.clearColor(0.0, 0.0, 0.0, 1.0);  // 設定為全黑
+  gl.clearDepth(1.0);                 // 清除所有東西
+  gl.enable(gl.DEPTH_TEST);           // Enable 深度測試
+  gl.depthFunc(gl.LEQUAL);            // Near things obscure far things
+
+  // 開始前先初始化畫布
+
+  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+  // Create a perspective matrix, a special matrix that is
+  // used to simulate the distortion of perspective in a camera.
+  // Our field of view is 45 degrees, with a width/height
+  // ratio that matches the display size of the canvas
+  // and we only want to see objects between 0.1 units
+  // and 100 units away from the camera.
+
+  const fieldOfView = 45 * Math.PI / 180;   // in radians
+  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
+  const zNear = 0.1;
+  const zFar = 100.0;
+  const projectionMatrix = mat4.create();
+
+  // note: glmatrix.js always has the first argument
+  // as the destination to receive the result.
+  mat4.perspective(projectionMatrix,
+                   fieldOfView,
+                   aspect,
+                   zNear,
+                   zFar);
+
+  // Set the drawing position to the "identity" point, which is
+  // the center of the scene.
+  const modelViewMatrix = mat4.create();
+
+  // Now move the drawing position a bit to where we want to
+  // start drawing the square.
+
+  mat4.translate(modelViewMatrix,     // destination matrix
+                 modelViewMatrix,     // matrix to translate
+                 [-0.0, 0.0, -6.0]);  // amount to translate
+
+  // Tell WebGL how to pull out the positions from the position
+  // buffer into the vertexPosition attribute.
+  {
+    const numComponents = 2;  // pull out 2 values per iteration
+    const type = gl.FLOAT;    // the data in the buffer is 32bit floats
+    const normalize = false;  // don't normalize
+    const stride = 0;         // how many bytes to get from one set of values to the next
+                              // 0 = use type and numComponents above
+    const offset = 0;         // how many bytes inside the buffer to start from
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
+    gl.vertexAttribPointer(
+        programInfo.attribLocations.vertexPosition,
+        numComponents,
+        type,
+        normalize,
+        stride,
+        offset);
+    gl.enableVertexAttribArray(
+        programInfo.attribLocations.vertexPosition);
+  }
+
+  // Tell WebGL to use our program when drawing
+
+  gl.useProgram(programInfo.program);
+
+  // Set the shader uniforms
+
+  gl.uniformMatrix4fv(
+      programInfo.uniformLocations.projectionMatrix,
+      false,
+      projectionMatrix);
+  gl.uniformMatrix4fv(
+      programInfo.uniformLocations.modelViewMatrix,
+      false,
+      modelViewMatrix);
+
+  {
+    const offset = 0;
+    const vertexCount = 4;
+    gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
+  }
+}
+
+
+ +

第一步,我們先將畫布背景設定為黑色,並設定相機的視角。我們將角度設為45°,並設定成與畫布的長寬比相同。另外我們指定我們只要渲染離相機 0.1 ~ 100 單位遠的物件。

+ +

接下來,我們讀入正方形的位置,並把它擺在離相機6單位遠的位置。然後我們將正方形頂點的 buffer 綁定到 gl 上。最後我們呼叫{{domxref("WebGLRenderingContext.drawArrays()", "drawArrays()")}}函數來渲染物件。

+ +

{{EmbedGHLiveSample('webgl-examples/tutorial/sample2/index.html', 670, 510) }}

+ +

檢視完整程式碼 | 開啟新頁面來檢視結果

+ +

矩陣運算

+ +

矩陣的運算看起來很複雜,但其實一步一步運算其實不會那麼困難。大部分使用者不會寫自己的運算函數,多半是使用現成的矩陣函數庫,這個例子中我們用的是 glMatrix library

+ +

可參考以下資料

+ + + +

{{PreviousNext("Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL", "Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL")}}

diff --git a/files/zh-tw/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html b/files/zh-tw/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html new file mode 100644 index 0000000000..cea74d65cf --- /dev/null +++ b/files/zh-tw/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html @@ -0,0 +1,55 @@ +--- +title: 利用 WebGL 產生動畫 +slug: Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL +translation_of: Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL +--- +

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL", "Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL") }}

+ +

這個章節中,我們將示範如何旋轉之前的正方形平面。

+ +

旋轉正方形

+ +

首先我們需要宣告一個變數來追蹤現在正方形旋轉的角度:

+ +
var squareRotation = 0.0;
+
+ +

Now we need to update the drawScene() function to apply the current rotation to the square when drawing it. After translating to the initial drawing position for the square, we apply the rotation like this:

+ +
  mat4.rotate(modelViewMatrix,  // destination matrix
+              modelViewMatrix,  // matrix to rotate
+              squareRotation,   // amount to rotate in radians
+              [0, 0, 1]);       // axis to rotate around
+
+ +

This rotates the modelViewMatrix by the current value of squareRotation, around the Z axis.

+ +

To actually animate, we need to add code that changes the value of squareRotation over time. We can do that by creating a new variable to track the time at which we last animated (let's call it then), then adding the following code to the end of the main function

+ +
  var then = 0;
+
+  // Draw the scene repeatedly
+  function render(now) {
+    now *= 0.001;  // convert to seconds
+    const deltaTime = now - then;
+    then = now;
+
+    drawScene(gl, programInfo, buffers, deltaTime);
+
+    requestAnimationFrame(render);
+  }
+  requestAnimationFrame(render);
+
+ +

This code uses requestAnimationFrame to ask the browser call the function "render" each frame. requestAnimationFrame passes us the time in milliseconds since the page loaded. We convert that to seconds and then subtract it from the last time to compute deltaTime which is the number of second since the last frame was rendered. At the end of drawscene we add the code to update squareRotation.

+ +
  squareRotation += deltaTime;
+
+ +

This code uses the amount of time that's passed since the last time we updated the value of squareRotation to determine how far to rotate the square.

+ +

{{EmbedGHLiveSample('webgl-examples/tutorial/sample4/index.html', 670, 510) }}

+ +

View the complete code | Open this demo on a new page

+ +

{{PreviousNext("Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL", "Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL") }}

diff --git a/files/zh-tw/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html b/files/zh-tw/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html new file mode 100644 index 0000000000..ef5e910f93 --- /dev/null +++ b/files/zh-tw/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html @@ -0,0 +1,73 @@ +--- +title: WebGL 入門 +slug: Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL +tags: + - WebGL + - 教學 +translation_of: Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL +--- +

{{WebGLSidebar("Tutorial")}} {{Next("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context")}}

+ +

WebGL 讓網頁內容能藉由一種基於 OpenGL ES 2.0 的 API 的幫助,於支援此 API 的瀏覽器環境中,不需使用外掛程式就能在HTML的 canvas 元素中實現二維及三維渲染。 WebGL 程式包含了由 JavaSrcipt 及著色器(GLSL)撰寫的控制碼以及在電腦的圖形處理器( GPU )上執行的特效程式碼(著色器程式碼)。WebGL 元素可以加入其他 HTML 元素之中並與網頁或網頁背景的其他部分混合。

+ +

這篇文章將會向您介紹 WebGL 的基礎。這篇文章假設您已經對於三維圖學涉及的數學有所了解,並且它將不會被佯裝為三維圖學的教材。在我們的學習區域內有初學者指南讓你完成編程任務:Learn WebGL for 2D and 3D graphics.

+ +

在此教學文件中的程式碼範例都能在 webgl-examples GitHub repository 之中找到。

+ +

準備三維渲染

+ +

首先你需要一個 canvas 元素讓WebGL進行渲染。下面的 HTML 定義的 canvas 元素供後續的範例繪製。

+ +
<body>
+  <canvas id="glCanvas" width="640" height="480"></canvas>
+</body>
+ +

準備 WebGL背景資料

+ +
+

背景資料為Context翻譯而來

+
+ +

在下面的JavaScript 程式碼,當指令完成讀取後會執行 main() 函式。目的是為了設定 WebGL 背景資料並且開始渲染內容。

+ +
main();
+
+// 從這開始
+function main() {
+  const canvas = document.querySelector("#glCanvas");
+  // 初始化 GL context
+  const gl = canvas.getContext("webgl");
+
+  // 當 WebGL 有效才繼續執行
+  if (gl === null) {
+    alert("無法初始化 WebGL,您的瀏覽器不支援。");
+    return;
+  }
+
+  // 設定清除色彩為黑色,完全不透明
+  gl.clearColor(0.0, 0.0, 0.0, 1.0);
+  // 透過清除色來清除色彩緩衝區
+  gl.clear(gl.COLOR_BUFFER_BIT);
+}
+ +

在此我們做的第一件事是取得 canvas 元素的參考,並存入 canvas 變數中。

+ +

一旦我們取得了 canvas ,我們透過呼叫 getContext 並傳入 "webgl" 字串來取得 WebGLRenderingContext。若瀏覽器不支援 webgl getContext 會回傳 null 同時會顯示訊息給使用者並且離開。

+ +

如果成功初始化, gl 就會成為一個 WebGL背景資料的參考。在這裡我們設置清除色為黑色,並透過該色清除 context (用背景色重新繪製 canvas )。

+ +

至此,您已經有足夠初始化 WebGL 背景資料的程式碼,並且準備好了等待接收內容的容器。

+ +

{{EmbedGHLiveSample('webgl-examples/tutorial/sample1/index.html', 670, 510) }}

+ +

檢視完整程式碼 | 開啟新頁面來檢視結果

+ +

亦可參考

+ + + +

{{Next("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context")}}

diff --git a/files/zh-tw/web/api/webgl_api/tutorial/index.html b/files/zh-tw/web/api/webgl_api/tutorial/index.html new file mode 100644 index 0000000000..549c3f40ba --- /dev/null +++ b/files/zh-tw/web/api/webgl_api/tutorial/index.html @@ -0,0 +1,41 @@ +--- +title: WebGL tutorial +slug: Web/API/WebGL_API/Tutorial +tags: + - TopicStub + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial +--- +
{{WebGLSidebar}}
+ +
+

WebGL 讓網頁內容可以使用一個基於 OpenGL ES 2.0 的API以在HTML {{HTMLElement("canvas")}}中執行3D渲染,且瀏覽器無需使用任何plug-in。WebGL programs 由JavaScript撰寫的指令碼以及透過電腦的Graphics Processing Unit (GPU)上運行的特殊效果程式碼(shader code)組成。WebGL元件可與其他HTML元件混合,並與該頁的其他部分或該頁背景組合使用。 

+
+ +

本教學描述如何使用 <canvas> 元件描繪 WebGL 圖像/圖形, 從基礎開始。提供的範例將讓你對於可以用WebGL做到什麼有清楚的概念,並提供程式碼片段讓你可以著手建立自己的內容。

+ +

開始之前

+ +

使用<canvas> 元件不會非常困難,但你需要有對HTML 與 JavaScript 的基礎認識。<canvas> 元件跟WebGL在某些舊瀏覽器中不支援,但近來的每個主流瀏覽器都有支援。我們用 JavaScript context object 在canvas繪製圖形,這樣圖形就能動態(on the fly)產生。

+ +

教學文件

+ +
+
WebGL新手上路
+
如何建置 WebGL 環境
+
加入2D內容至WebGL環境
+
如何用 WebGL 渲染簡單平面的形狀
+
使用 shaders 在 WebGL 上色
+
示範如何使用 shaders 在圖形上上色
+
WebGL 產生動畫
+
示範如何旋轉與移動物件以製作簡單的動畫
+
建立三維物件
+
示範如何創造並讓 3D 物件(立方體)有動畫
+
在物件表面貼上材質
+
示範如何在物件的表面上貼上材質圖
+
模擬打光
+
如何在 WebGL 環境模擬打光效果
+
讓材質產生動畫
+
如何移動材質圖,在範例中是將 Ogg 影片 貼到一個旋轉中的立方體
+
diff --git a/files/zh-tw/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html b/files/zh-tw/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html new file mode 100644 index 0000000000..b234bd013e --- /dev/null +++ b/files/zh-tw/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html @@ -0,0 +1,123 @@ +--- +title: 使用 shaders 在 WebGL 上色 +slug: Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL +translation_of: Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL +--- +

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context", "Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL")}}

+ +

上一篇我們建立了一個正方形平面,接下來我們要透過修改 shakder 來加入顏色。

+ +

指定頂點顏色

+ +

WebGL中物件是由許多頂點來組成,每個頂點有自己的座標、顏色。其他像素的屬性(顏色、位置)預設是透過計算多頂點的內差值來得到的。之前的例子,vertex shader 並沒有指定頂點任何顏色。

+ +

In WebGL, objects are built using sets of vertices, each of which has a position and a color; by default, all other pixels' colors (and all its other attributes, including position) are computed using interpolation, automatically creating smooth gradients. Previously, our vertex shader didn't apply any specific colors to the vertices; between this and the fragment shader assigning the fixed color of white to each pixel, the entire square was rendered as solid white.

+ +

Let's say we want to render a gradient in which each corner of the square is a different color: red, blue, green, and white. The first thing to do is to establish these colors for the four vertices. To do this, we first need to create an array of vertex colors, then store it into a WebGL buffer; we'll do that by adding the following code to our initBuffers() function:

+ +
  const colors = [
+    1.0,  1.0,  1.0,  1.0,    // white
+    1.0,  0.0,  0.0,  1.0,    // red
+    0.0,  1.0,  0.0,  1.0,    // green
+    0.0,  0.0,  1.0,  1.0,    // blue
+  ];
+
+  const colorBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
+
+  return {
+    position: positionBuffer,
+    color: colorBuffer,
+  };
+}
+
+ +

這段程式碼一開始先宣告一個陣列來存放四個四維向量,分別為四個頂點的顏色。接下來,將陣列轉型為浮點數並存入一個新的 WebGL buffer 。

+ +

為了使用這些顏色,我們需要修改 vertex shader,讓他可以從 buffer 中取得正確的顏色。

+ +
  const vsSource = `
+    attribute vec4 aVertexPosition;
+    attribute vec4 aVertexColor;
+
+    uniform mat4 uModelViewMatrix;
+    uniform mat4 uProjectionMatrix;
+
+    varying lowp vec4 vColor;
+
+    void main(void) {
+      gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
+      vColor = aVertexColor;
+    }
+  `;
+
+ +

The key difference here is that for each vertex, we pass its color using a varying to the fragment shader.

+ +

替 fragment 上色

+ +

我們重新回顧一下,之前我們的 fragment shader 如下:

+ +
  const fsSource = `
+    void main() {
+      gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+    }
+  `;
+
+ +

為了要讓每個 pixel 使用內插的顏色,我們讓 gl_FragColor 取得 vColor的值。

+ +
  const fsSource = `
+    varying lowp vec4 vColor;
+
+    void main(void) {
+      gl_FragColor = vColor;
+    }
+  `;
+
+ +

這樣的改變可以使每個 fragment 得到利用相對位置內插法所產生顏色,而不是得到一個固定的值。

+ +

畫出顏色

+ +

接下來我們要

+ +

Next, it's necessary to add the code look up the attribute location for the colors and setup that attribute for the shader program:

+ +
  const programInfo = {
+    program: shaderProgram,
+    attribLocations: {
+      vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
+      vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
+    },
+    ...
+ +

Then, drawScene() can be revised to actually use these colors when drawing the square:

+ +
  // Tell WebGL how to pull out the colors from the color buffer
+  // into the vertexColor attribute.
+  {
+    const numComponents = 4;
+    const type = gl.FLOAT;
+    const normalize = false;
+    const stride = 0;
+    const offset = 0;
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);
+    gl.vertexAttribPointer(
+        programInfo.attribLocations.vertexColor,
+        numComponents,
+        type,
+        normalize,
+        stride,
+        offset);
+    gl.enableVertexAttribArray(
+        programInfo.attribLocations.vertexColor);
+  }
+
+ +

{{EmbedGHLiveSample('webgl-examples/tutorial/sample3/index.html', 670, 510) }}

+ +

View the complete code | Open this demo on a new page

+ +

{{PreviousNext("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context", "Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL")}}

diff --git a/files/zh-tw/web/api/webrtc_api/index.html b/files/zh-tw/web/api/webrtc_api/index.html new file mode 100644 index 0000000000..1731f23739 --- /dev/null +++ b/files/zh-tw/web/api/webrtc_api/index.html @@ -0,0 +1,193 @@ +--- +title: WebRTC API +slug: Web/API/WebRTC_API +translation_of: Web/API/WebRTC_API +--- +
{{APIRef("WebRTC")}}
+ +

WebRTC(網路即時通訊技術)是一個提供 Web 應用程式及網站進行錄影或隨選播放串流音訊與影像的技術,可以直接使用瀏覽器進行資料交換而無須透過中介服務。作為一個標準規格,WebRTC 可以提供任何瀏覽器在不需要安裝外掛程式或第三方軟體下,分享應用程式的資料和進行電話會議。

+ +

WebRTC 由數個相關而互相協作的API以及網路協定組成。

+ +

這裡的技術文件會幫助你了解 :

+ +

WebRTC的基本構成,如何設置並同時使用其資料與媒體傳輸連線,以及更多有關資訊。

+ +

WebRTC 概念與使用

+ +

WebRTC 有許多服務目的,基本涵括了媒體獲取與串流API,他們為網頁提供了強大的多媒體功能,包括: 音視訊會議,檔案傳輸,身分識別管理,以及提供以傳輸{{Glossary("DTMF")}}訊號來與現存電話系統交互的介面。

+ +

建立端點與端點間的連線完全不需要特定驅動程式抑或者第三方插件,在通常情況下也不需要任何中介伺服器

+ +

WebRTC serves multiple purposes, and overlaps substantially with the Media Capture and Streams API. Together, they provide powerful multimedia capabilities to the Web, including support for audio and video conferencing, file exchange, identity management, and interfacing with legacy telephone systems by sending {{Glossary("DTMF")}} signals. Connections between peers can be made without requiring any special drivers or plug-ins, and can often be made without any intermediary servers.

+ +

Connections between two peers are created using—and represented by—the {{domxref("RTCPeerConnection")}} interface. Once a connection has been established and opened, media streams ({{domxref("MediaStream")}}s) and/or data channels ({{domxref("RTCDataChannel")}}s) can be added to the connection.

+ +

Media streams can consist of any number of tracks of media information; tracks, which are represented by objects based on the {{domxref("MediaStreamTrack")}} interface, may contain one of a number of types of media data, including audio, video, and text (such as subtitles or even chapter names). Most streams consist of at least one audio track and likely also a video track, and can be used to send and receive both live media or stored media information (such as a streamed movie).

+ +

You can also use the connection between two peers to exchange arbitrary binary data using the {{domxref("RTCDataChannel")}} interface. This can be used for back-channel information, metadata exchange, game status packets, file transfers, or even as a primary channel for data transfer.

+ +

more details and links to relevant guides and tutorials needed

+ +

WebRTC interfaces

+ +

Because WebRTC provides interfaces that work together to accomplish a variety of tasks, we have divided up the interfaces in the list below by category. Please see the sidebar for an alphabetical list.

+ +

Connection setup and management

+ +

These interfaces are used to set up, open, and manage WebRTC connections.

+ +
+
{{domxref("RTCPeerConnection")}}
+
Represents a WebRTC connection between the local computer and a remote peer. It is used to handle efficient streaming of data between the two peers.
+
{{domxref("RTCDataChannel")}}
+
Represents a bi-directional data channel between two peers of a connection.
+
{{domxref("RTCDataChannelEvent")}}
+
Represents events that occur while attaching a {{domxref("RTCDataChannel")}} to a {{domxref("RTCPeerConnection")}}. The only event sent with this interface is {{event("datachannel")}}.
+
{{domxref("RTCSessionDescription")}}
+
Represents the parameters of a session. Each RTCSessionDescription consists of a description type indicating which part of the offer/answer negotiation process it describes and of the SDP descriptor of the session.
+
{{domxref("RTCStatsReport")}}
+
Provides information detailing statistics for a connection or for an individual track on the connection; the report can be obtained by calling {{domxref("RTCPeerConnection.getStats()")}}.
+
{{domxref("RTCIceCandidate")}}
+
Represents a candidate internet connectivity establishment (ICE) server for establishing an {{domxref("RTCPeerConnection")}}.
+
{{domxref("RTCIceTransport")}}
+
Represents information about an internet connectivity establishment (ICE) transport.
+
{{domxref("RTCPeerConnectionIceEvent")}}
+
Represents events that occurs in relation to ICE candidates with the target, usually an {{domxref("RTCPeerConnection")}}. Only one event is of this type: {{event("icecandidate")}}.
+
{{domxref("RTCRtpSender")}}
+
Manages the encoding and transmission of data for a {{domxref("MediaStreamTrack")}} on an {{domxref("RTCPeerConnection")}}.
+
{{domxref("RTCRtpReceiver")}}
+
Manages the reception and decoding of data for a {{domxref("MediaStreamTrack")}} on an {{domxref("RTCPeerConnection")}}.
+
{{domxref("RTCTrackEvent")}}
+
Indicates that a new incoming {{domxref("MediaStreamTrack")}} was created and an associated {{domxref("RTCRtpReceiver")}} object was added to the {{domxref("RTCPeerConnection")}} object.
+
+ +

Identity and security

+ +

The WebRTC API includes a number of interfaces to manage security and identity.

+ +
+
{{domxref("RTCIdentityProvider")}}
+
Enables a user agent is able to request that an identity assertion be generated or validated.
+
{{domxref("RTCIdentityAssertion")}}
+
Represents the identity of the a remote peer of the current connection. If no peer has yet been set and verified this interface returns null. Once set it can't be changed.
+
{{domxref("RTCIdentityProviderRegistrar")}}
+
Registers an  identity provider (idP).
+
{{domxref("RTCIdentityEvent")}}
+
Represents an identity assertion generated by an identity provider (idP). This is usually for an {{domxref("RTCPeerConnection")}}. The only event sent with this type is {{event("identityresult")}}.
+
{{domxref("RTCIdentityErrorEvent")}}
+
Represents an error associated with the identity provider (idP). This is usually for an {{domxref("RTCPeerConnection")}}. Two events are sent with this type: {{event("idpassertionerror")}} and {{event("idpvalidationerror")}}.
+
{{domxref("RTCCertificate")}}
+
Represents a certificate that an {{domxref("RTCPeerConnection")}} uses to authenticate.
+
+ +

Telephony

+ +

These interfaces are related to interactivity with public-switched telephone networks (PTSNs).

+ +
+
{{domxref("RTCDTMFSender")}}
+
Manages the encoding and transmission of dual-tone multi-frequency (DTMF) signaling for an {{domxref("RTCPeerConnection")}}.
+
{{domxref("RTCDTMFToneChangeEvent")}}
+
Indicates an occurrence of a of dual-tone multi-frequency (DTMF). This event does not bubble (except where otherwise stated) and is not cancelable (except where otherwise stated).
+
+ +

Guides

+ +
+
Introduction to WebRTC protocols
+
This article introduces the protocols on top of which the WebRTC API is built.
+
WebRTC connectivity
+
A guide to how WebRTC connections work and how the various protocols and interfaces can be used together to build powerful communication apps.
+
Lifetime of a WebRTC session
+
WebRTC lets you build peer-to-peer communication of arbitrary data, audio, or video—or any combination thereof—into a browser application. In this article, we'll look at the lifetime of a WebRTC session, from establishing the connection all the way through closing the connection when it's no longer needed.
+
Signaling and two-way video calling
+
A tutorial and example which turbs a WebSocket-based chat system created for a previous example and adds support for opening video calls among participants. The chat server's WebSocket connection is used for WebRTC signaling.
+
Using WebRTC data channels
+
This guide covers how you can use a peer connection and an associated {{domxref("RTCDataChannel")}} to exchange arbitrary data between two peers.
+
Using DTMF with WebRTC
+
WebRTC's support for interacting with gateways that link to old-school telephone systems includes support for sending DTMF tones using the {{domxref("RTCDTMFSender")}} interface. This guide shows how to do so.
+
+ +

教學

+ +
+
Improving compatibility using WebRTC adapter.js
+
The WebRTC organization provides on GitHub the WebRTC adapter to work around compatibility issues in different browsers' WebRTC implementations. The adapter is a JavaScript shim which lets your code to be written to the specification so that it will "just work" in all browsers with WebRTC support.
+
Taking still photos with WebRTC
+
This article shows how to use WebRTC to access the camera on a computer or mobile phone with WebRTC support and take a photo with it.
+
一個簡單的 RTCDataChannel 範例
+
{{domxref("RTCDataChannel")}} 介面用於讓兩端點間建立起資料的通道,你可以利用通道來收發資料。這組 API 被設計成與 WebSocket API 相似,所以可以利用同樣的程式模型套用在這兩套 API 之上。
+
+ +

資源

+ +

Protocols

+ +

WebRTC-proper protocols

+ + + + + + + +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('WebRTC 1.0')}}{{Spec2('WebRTC 1.0')}}The initial definition of the API of WebRTC.
{{SpecName('Media Capture')}}{{Spec2('Media Capture')}}The initial definition of the object conveying the stream of media content.
{{SpecName('Media Capture DOM Elements')}}{{Spec2('Media Capture DOM Elements')}}The initial definition on how to obtain stream of content from DOM Elements
+ +

In additions to these specifications defining the API needed to use WebRTC, there are several protocols, listed under resources.

+ + + + diff --git a/files/zh-tw/web/api/webvr_api/index.html b/files/zh-tw/web/api/webvr_api/index.html new file mode 100644 index 0000000000..926a1c3b25 --- /dev/null +++ b/files/zh-tw/web/api/webvr_api/index.html @@ -0,0 +1,246 @@ +--- +title: WebVR API +slug: Web/API/WebVR_API +translation_of: Web/API/WebVR_API +--- +
{{SeeCompatTable}}{{APIRef("WebVR API")}}
+ +

WebVR 可以讓穿戴的VR裝置 (如頭戴裝置 Oculus Rift 或 HTC Vive) 與 web 應用程式結合。開發人員可以將VR裝置所提供的位置與動作資訊轉移到3D的場景中。利用 WebVR可以創造出很多有趣的應用程式: 包含虛擬導覽、互動訓練軟體等等。

+ +

用法與基本觀念

+ +

透過呼叫 {{domxref("Navigator.getVRDisplays()")}} 函數可以得到與電腦連接的VR裝置,每個裝置會回傳一個 {{domxref("VRDisplay")}} 物件

+ +

Sketch of a person in a chair with wearing goggles labelled "Head mounted display (HMD)" facing a monitor with a webcam labelled "Position sensor"

+ +

{{domxref("VRDisplay")}} 是 WebVR API 的核心,提供以下功能:

+ + + +

A typical (simple) WebVR app would work like so:

+ +
    +
  1. 呼叫 {{domxref("Navigator.getVRDisplays()")}} 來取得 VR 顯示器的 reference。
  2. +
  3. 呼叫 {{domxref("VRDisplay.requestPresent()")}} 來啟動 VR顯示器。
  4. +
  5. WebVR's dedicated {{domxref("VRDisplay.requestAnimationFrame()")}} method is used to run the app's rendering loop at the correct refresh rate for the display.
  6. +
  7. Inside the rendering loop, you grab the data required to display the current frame ({{domxref("VRDisplay.getFrameData()")}}), draw the displayed scene twice — once for the view in each eye, then submit the rendered view to the display to show to the user ({{domxref("VRDisplay.submitFrame()")}}).
  8. +
+ +

In addition, WebVR 1.1 adds a number of events on the {{domxref("Window")}} object to allow JavaScript to respond to changes to the status of the display.

+ +
+

Note: You can find a lot more out about how the API works in our Using the WebVR API and WebVR Concepts articles.

+
+ +

Using controllers: Combining WebVR with the Gamepad API

+ +

Many WebVR hardware setups feature controllers that go along with the headset. These can be used in WebVR apps via the Gamepad API, and specifically the Gamepad Extensions API that adds API features for accessing controller pose, haptic actuators, and more.

+ +
+

Note: Our Using VR controllers with WebVR article explains the basics of how to use VR controllers with WebVR apps.

+
+ +

WebVR Interfaces

+ +
+
{{domxref("VRDisplay")}}
+
Represents any VR device supported by this API. It includes generic information such as device IDs and descriptions, as well as methods for starting to present a VR scene, retrieving eye parameters and display capabilities, and other important functionality.
+
{{domxref("VRDisplayCapabilities")}}
+
Describes the capabilities of a {{domxref("VRDisplay")}} — it's features can be used to perform VR device capability tests, for example can it return position information.
+
{{domxref("VRDisplayEvent")}}
+
Represents the event object of WebVR-related events (see the {{anch("Window", "window object extensions")}} listed below).
+
{{domxref("VRFrameData")}}
+
Represents all the information needed to render a single frame of a VR scene; constructed by {{domxref("VRDisplay.getFrameData()")}}.
+
{{domxref("VRPose")}}
+
Represents the position state at a given timestamp (which includes orientation, position, velocity, and acceleration.)
+
{{domxref("VREyeParameters")}}
+
Provides access to all the information required to correctly render a scene for each given eye, including field of view information.
+
{{domxref("VRFieldOfView")}}
+
Represents a field of view defined by 4 different degree values describing the view from a center point.
+
{{domxref("VRLayerInit")}}
+
Represents a layer to be presented in a {{domxref("VRDisplay")}}.
+
{{domxref("VRStageParameters")}}
+
Represents the values describing the the stage area for devices that support room-scale experiences.
+
+ +

Extensions to other interfaces

+ +

The WebVR API extends the following APIs, adding the listed features.

+ +

Gamepad

+ +
+
{{domxref("Gamepad.displayId")}} {{readonlyInline}}
+
Returns the {{domxref("VRDisplay.displayId")}} of the associated {{domxref("VRDisplay")}} — the VRDisplay that the gamepad is controlling the displayed scene of.
+
+ + + +
+
{{domxref("Navigator.activeVRDisplays")}} {{readonlyInline}}
+
Returns an array containing every {{domxref("VRDisplay")}} object that is currently presenting ({{domxref("VRDisplay.ispresenting")}} is true).
+
{{domxref("Navigator.getVRDisplays()")}}
+
Returns a promise that resolves to an array of {{domxref("VRDisplay")}} objects representing any available VR displays connected to the computer.
+
+ +

Window events

+ +
+
{{domxref("Window.onvrdisplaypresentchange")}}
+
Represents an event handler that will run when the presenting state of a VR display changes — i.e. goes from presenting to not presenting, or vice versa (when the {{event("vrdisplaypresentchange")}} event fires).
+
{{domxref("Window.onvrdisplayconnect")}}
+
Represents an event handler that will run when a compatible VR display has been connected to the computer (when the {{event("vrdisplayconnect")}} event fires).
+
{{domxref("Window.onvrdisplaydisconnect")}}
+
Represents an event handler that will run when a compatible VR display has been disconnected from the computer (when the {{event("vrdisplaydisconnect")}} event fires).
+
{{domxref("Window.onvrdisplayactivate")}}
+
Represents an event handler that will run when a display is able to be presented to (when the {{event("vrdisplayactivate")}} event fires), for example if an HMD has been moved to bring it out of standby, or woken up by being put on.
+
{{domxref("Window.onvrdisplaydeactivate")}}
+
Represents an event handler that will run when a display can no longer be presented to (when the {{event("vrdisplaydeactivate")}} event fires), for example if an HMD has gone into standby or sleep mode due to a period of inactivity.
+
+ +

Unimplemented window events

+ +

The following events are listed in the spec, but do not currently seem to be implemented anywhere as yet.

+ +
+
{{domxref("Window.onvrdisplayblur")}}
+
Represents an event handler that will run when presentation to a display has been paused for some reason by the browser, OS, or VR hardware (when the {{event("vrdisplayblur")}} event fires) — for example, while the user is interacting with a system menu or browser, to prevent tracking or loss of experience.
+
{{domxref("Window.onvrdisplayfocus")}}
+
Represents an event handler that will run when presentation to a display has resumed after being blurred (when the {{event("vrdisplayfocus")}} event fires).
+
+ +

Examples

+ +

You can find a number of examples at these locations:

+ + + +

Specifications

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("GamepadExtensions")}}{{Spec2("GamepadExtensions")}}Defines the Experimental Gamepad extensions.
{{SpecName('WebVR 1.1')}}{{Spec2('WebVR 1.1')}}Initial definition
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatNo}}[1]{{CompatVersionUnknown}}{{CompatGeckoDesktop(55)}}[2]{{CompatNo}}{{CompatNo}}{{CompatNo}}
Gamepad extensions{{CompatNo}}{{CompatNo}}{{CompatNo}}[4]{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari MobileChrome for AndroidSamsung Internet for GearVR
Basic support{{CompatNo}}{{CompatNo}}{{CompatGeckoMobile(55)}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatVersionUnknown}}[3]{{CompatVersionUnknown}}
+  
Gamepad extensions{{CompatNo}}{{CompatNo}}{{CompatNo}}[4]{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
+
+ +

[1] API Available on all platforms behind a flag, but currently only works on desktop in an experimental version of Chrome (other builds won't return any devices when {{domxref("Navigator.getVRDisplays()")}} is invoked).

+ +

[2] Currently only Windows support is enabled by default. Mac support is available in Firefox Nightly.

+ +

[3] Currently supported only by Google Daydream.

+ +

[4] Enabled in Firefox Nightly and Beta, versions 55 and above. Enabled/disabled by the dom.gamepad-extensions.enabled pref.

+ +

See also

+ + diff --git a/files/zh-tw/web/api/wheelevent/index.html b/files/zh-tw/web/api/wheelevent/index.html new file mode 100644 index 0000000000..e7446cc044 --- /dev/null +++ b/files/zh-tw/web/api/wheelevent/index.html @@ -0,0 +1,196 @@ +--- +title: WheelEvent +slug: Web/API/WheelEvent +translation_of: Web/API/WheelEvent +--- +

{{APIRef("DOM Events")}}

+ +

WheelEvent DOM事件會在用戶滚动滑鼠滚轮或操作其它類似滑鼠的設備時觸發。

+ +
該事件爲標準規定的事件介面。早期的瀏覽器實現過{{ domxref("MouseWheelEvent") }}和{{domxref("MouseScrollEvent")}}兩種滾輪事件介面,但這兩種介面皆非標準,加之各瀏覽器間對其相容性極差。因而開發者應用該標準事件介面取代這兩個非標準介面。
+ +
注意事項: 請勿想當然依據滾輪方向(即該事件的各delta屬性值)來推斷文檔內容的滾動方向,因標準未定義滾輪事件具體會引發什麼樣的行爲,引發的行爲實際上是各瀏覽器自行定義的。即便滾輪事件引發了文檔內容的滾動行爲,也不表示滾輪方向和文檔內容的滾動方向一定相同。因而通過該滾輪事件獲知文檔內容滾動方向的方法並不可靠。要獲取文檔內容的滾動方向,可在文檔內容滾動事件({{event("scroll")}})中監視{{domxref("Element.scrollLeft", "scrollLeft")}}和{{domxref("Element.scrollTop", "scrollTop")}}二值變化情況,即可推斷出滾動方向了。
+ +

{{InheritanceDiagram}}

+ +

建構式

+ +
+
{{domxref("WheelEvent.WheelEvent", "WheelEvent()")}}
+
建立一個WheelEvent物件。
+
+ +

屬性

+ +

該介面繼承了父介面{{domxref("MouseEvent")}}、{{domxref("UIEvent")}}、{{domxref("Event")}}的屬性。

+ +
+
{{domxref("WheelEvent.deltaX")}} {{readonlyinline}}
+
返回double值,該值表示滾輪的橫向滾動量。
+
{{domxref("WheelEvent.deltaY")}} {{readonlyinline}}
+
返回double值,該值表示滾輪的縱向滾動量。
+
{{domxref("WheelEvent.deltaZ")}} {{readonlyinline}}
+
返回double值,該值表示滾輪的z軸方向上的滾動量。
+
{{domxref("WheelEvent.deltaMode")}} {{readonlyinline}}
+
返回unsigned long值,該值表示上述各delta的值的單位。該值及所表示的單位如下: + + + + + + + + + + + + + + + + + + + + + + + +
常數描述
DOM_DELTA_PIXEL0x00滾動量單位爲像素。
DOM_DELTA_LINE0x01滾動量單位爲行。
DOM_DELTA_PAGE0x02滾動量單位爲頁。
+
+
+ +

方法

+ +

該介面本身未定義方法,但繼承了父介面{{domxref("MouseEvent")}}、{{domxref("UIEvent")}}、{{domxref("Event")}}的方法。

+ +

規範

+ + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('DOM3 Events','#interface-wheelevent','WheelEvent')}}{{Spec2('DOM3 Events')}}Initial definition.
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能ChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
基本功能31{{ CompatVersionUnknown }}{{ CompatGeckoDesktop("17.0") }}{{ CompatIE("9.0") }}187.0
window.WheelEvent{{CompatVersionUnknown}}{{ CompatVersionUnknown }}{{ CompatGeckoDesktop("17.0") }}{{ CompatIE("9.0") }}{{CompatVersionUnknown}}{{CompatVersionUnknown}} [1]
WheelEvent + Ctrl[2]實現按住縮放功能{{CompatVersionUnknown}}{{CompatUnknown}}{{ CompatGeckoDesktop("55.0") }}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能AndroidAndroid WebviewEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari MobileChrome for Android
基本功能{{CompatNo}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{ CompatGeckoMobile("17.0") }}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatNo}}{{CompatVersionUnknown}}
window.WheelEvent{{CompatNo}}{{CompatVersionUnknown}}{{CompatUnknown}}{{ CompatGeckoMobile("17.0") }}{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
WheelEvent + Ctrl[2]實現按住縮放功能{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{ CompatGeckoMobile("55.0") }}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}
+
+ +

[1] 嚴格說,Safari並非真正支援WheelEvent,只不過會返回window.WheelEvent物件。

+ +

[2] 這樣在觸控平面上,比如觸控螢幕或是觸控板上,開發者就可根據用戶按住縮放手勢來實現簡單的縮放功能 (滑鼠滾輪 + Ctrl 習慣上用於縮放)。

+ +

參見

+ + diff --git a/files/zh-tw/web/api/window.history/index.html b/files/zh-tw/web/api/window.history/index.html new file mode 100644 index 0000000000..67b79c5f82 --- /dev/null +++ b/files/zh-tw/web/api/window.history/index.html @@ -0,0 +1,51 @@ +--- +title: Window.history +slug: Web/API/Window.history +translation_of: Web/API/Window/history +--- +

{{ APIRef }}

+ +

Window.history 唯讀屬性會回傳一個 {{domxref("History")}} 物件,其提供了一個介面來操控瀏覽器的 session history 紀錄(為當前面頁所在分頁中訪問、或於當前面頁中透過頁面框架(frame)所載入的頁面)。

+ +

相關範例及細節請參考操控瀏覽器歷史紀錄一文。文章中解釋了在使用 pushState()replaceState() 方法前應該要知道的安全性功能。

+ +

語法

+ +
var historyObj = window.history;
+
+ +

範例

+ +
history.back();     // 相當於按下上一頁按鈕
+history.go(-1);     // 相當於 history.back();
+
+ +

備註

+ +

For top-level pages you can see the list of pages in the session history, accessible via the History object, in the browser's dropdowns next to the back and forward buttons.

+ +

For security reasons the History object doesn't allow the non-privileged code to access the URLs of other pages in the session history, but it does allow it to navigate the session history.

+ +

There is no way to clear the session history or to disable the back/forward navigation from unprivileged code. The closest available solution is the location.replace() method, which replaces the current item of the session history with the provided URL.

+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', 'browsers.html#the-history-interface', 'The History interface')}}{{Spec2('HTML WHATWG')}} 
{{SpecName('HTML5 W3C', 'browsers.html#the-history-interface', 'The History interface')}}{{Spec2('HTML5 W3C')}} 
diff --git a/files/zh-tw/web/api/window.onpopstate/index.html b/files/zh-tw/web/api/window.onpopstate/index.html new file mode 100644 index 0000000000..d98464d356 --- /dev/null +++ b/files/zh-tw/web/api/window.onpopstate/index.html @@ -0,0 +1,57 @@ +--- +title: window.onpopstate +slug: Web/API/Window.onpopstate +translation_of: Web/API/WindowEventHandlers/onpopstate +--- +
{{ApiRef}} {{gecko_minversion_header("2")}}
+ +

摘要

+ +

視窗上 popstate 事件的事件處理器。

+ +

在同一文件的當前歷史紀錄變動時,如果其變動介於兩個歷史紀錄間,popstate 就會被呼叫。如果當前的歷史紀錄是藉由呼叫 history.pushState() 建立,或曾被 history.replaceState() 修改過,popstate 事件的 state 屬性,將包含一份歷史紀錄的 state 物件。

+ +

請注意:直接呼叫 history.pushState()history.replaceState() 不會驅動 popstate 事件。popstate 事件只會被瀏覽器的行為驅動,例如點擊上一頁按鈕(或透過 JavaScript 呼叫 history.back())。且此事件只會在用戶於同文件的兩個歷史紀錄間瀏覽時作動。

+ +

在頁面載入時,不同瀏覽器具有不同的 popstate 行為。Chrome 與 Safari 會在頁面載入時觸發 popstate 事件,但 Firefox 則不會。

+ +

語法

+ +
window.onpopstate = funcRef;
+
+ + + +

popstate 事件

+ +

以下範例,位於 http://example.com/example.html 並執行下列程式的頁面,將會產生如標示的對話框:

+ +
window.onpopstate = function(event) {
+  alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
+};
+
+history.pushState({page: 1}, "title 1", "?page=1");
+history.pushState({page: 2}, "title 2", "?page=2");
+history.replaceState({page: 3}, "title 3", "?page=3");
+history.back(); // 跳出 "location: http://example.com/example.html?page=1, state: {"page":1}"
+history.back(); // 跳出 "location: http://example.com/example.html, state: null
+history.go(2);  // 跳出 "location: http://example.com/example.html?page=3, state: {"page":3}
+
+ +

請注意,雖然原始的歷史紀錄(http://example.com/example.html)沒有關聯的 state 物件,在我們第二次呼叫 hitsory.back() 時仍然會觸發 popstate 事件

+ +

標準

+ + + +

請參照

+ + diff --git a/files/zh-tw/web/api/window.requestanimationframe/index.html b/files/zh-tw/web/api/window.requestanimationframe/index.html new file mode 100644 index 0000000000..55aa85d292 --- /dev/null +++ b/files/zh-tw/web/api/window.requestanimationframe/index.html @@ -0,0 +1,94 @@ +--- +title: Window.requestAnimationFrame() +slug: Web/API/Window.requestAnimationFrame +translation_of: Web/API/window/requestAnimationFrame +--- +
{{APIRef}}
+ +

window.requestAnimationFrame()方法通知瀏覽器我們想要產生動畫,並且要求瀏覽器在下次重繪畫面前呼叫特定函數更新動畫。這個方法接受一個引數作為下次重繪前調用的回呼函數。

+ +
Note: 若是想要在下次重繪時產生另一個動畫,這個回呼函數內必須自行呼叫 requestAnimationFrame()。
+ +

當準備好更新頁面上的動畫時應當呼叫這個方法。這表示向瀏覽器請求在下次重繪前呼叫這個動畫函數。回呼的次數通常落在每秒 60 次,但通常會根據 W3C 的建議符合多數瀏覽器重新整理的頻率。當頁面處於背景或隱藏狀態時 {{ HTMLElement("iframe") }} ,多數的瀏覽器會暫停 requestAnimationFrame() 的呼叫,從而改善效能表現及電池壽命。

+ +

回呼方法會得到一個 {{domxref("DOMHighResTimeStamp")}} 的引數,作為指示目前的時間(基於 time origin 之後經過的毫秒數)。當 requestAnimationFrame() 佇列了數個回呼並且在同一幀開始觸發多個回呼時,儘管每一個之前的回呼在運作時會消耗一定的時間,但它們都會取得同樣的時間戳記。時間戳記是由十進位數字表示的毫秒且最小的精準度為 1 毫秒(1000 µs)。

+ +

語法

+ +
window.requestAnimationFrame(callback);
+
+ +

參數

+ +
+
回呼
+
當下次重新繪製時用於呼叫並更新動畫。回呼函數會得到一個引數—— {{domxref("DOMHighResTimeStamp")}} ——類似於由 {{domxref('performance.now()')}} 回傳的結果,其用於指示當 requestAnimationFrame() 開始執行回呼函數的時間。
+
+ +

回傳值

+ +

long 型別的整數值表示請求的 id,作為其進入回呼清單中的唯一識別。雖然回傳值是一個非零值,但不應該對其有其他任何的假設。將這個值傳遞給 {{domxref("window.cancelAnimationFrame()")}} 可以取消重新整理頁面回呼的請求

+ +

範例

+ +
var start = null;
+var element = document.getElementById('SomeElementYouWantToAnimate');
+
+function step(timestamp) {
+  if (!start) start = timestamp;
+  var progress = timestamp - start;
+  element.style.transform = 'translateX(' + Math.min(progress / 10, 200) + 'px)';
+  if (progress < 2000) {
+    window.requestAnimationFrame(step);
+  }
+}
+
+window.requestAnimationFrame(step);
+
+ +

備註

+ +

Edge 低於 17 的版本和 Internet Explorer 無法保證在繪製循環前觸發 requestAnimationFrame

+ +

規格

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#animation-frames', 'requestAnimationFrame')}}{{Spec2('HTML WHATWG')}}No change, supersedes the previous one.
{{SpecName('RequestAnimationFrame', '#dom-windowanimationtiming-requestanimationframe', 'requestAnimationFrame')}}{{Spec2('RequestAnimationFrame')}}Initial definition
+ +

瀏覽器相容性

+ +
+

{{Compat("api.Window.requestAnimationFrame")}}

+
+ +

其他參考

+ + diff --git a/files/zh-tw/web/api/window/getcomputedstyle/index.html b/files/zh-tw/web/api/window/getcomputedstyle/index.html new file mode 100644 index 0000000000..8dd0f24bad --- /dev/null +++ b/files/zh-tw/web/api/window/getcomputedstyle/index.html @@ -0,0 +1,200 @@ +--- +title: Window.getComputedStyle() +slug: Web/API/Window/getComputedStyle +translation_of: Web/API/Window/getComputedStyle +--- +

{{APIRef()}}

+ +

概要

+ +

Window.getComputedStyle() 方法可以得到元素於套用啟用之樣式表以及解析其中可能包含的任何基本運算後的所有 CSS 屬性值。

+ +

語法

+ +
var style = window.getComputedStyle(element[, pseudoElt]);
+
+ +
+
element
+
The {{domxref("Element")}} for which to get the computed style.
+
pseudoElt {{optional_inline}}
+
A string specifying the pseudo-element to match. Must be omitted (or null) for regular elements.
+
+ +
Note: Prior to Gecko 2.0 {{geckoRelease("2.0")}}, the pseudoElt parameter was required. No other major browser required this parameter be specified if null. Gecko has been changed to match the behavior of other browsers.
+ +

The returned style is a live {{domxref("CSSStyleDeclaration")}} object, which updates itself automatically when the element's style is changed.

+ +

範例

+ +
var elem1 = document.getElementById("elemId");
+var style = window.getComputedStyle(elem1, null);
+
+// this is equivalent:
+// var style = document.defaultView.getComputedStyle(elem1, null);
+
+ +
<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(){
+    var elem = document.getElementById("elem-container");
+    var theCSSprop = window.getComputedStyle(elem,null).getPropertyValue("height");
+    document.getElementById("output").innerHTML = theCSSprop;
+   }
+  getTheStyle();
+</script>
+
+ +
function dumpComputedStyles(elem,prop) {
+
+  var cs = window.getComputedStyle(elem,null);
+  if (prop) {
+    console.log(prop+" : "+cs.getPropertyValue(prop));
+    return;
+  }
+  var len = cs.length;
+  for (var i=0;i<len;i++) {
+
+    var style = cs[i];
+    console.log(style+" : "+cs.getPropertyValue(style));
+  }
+
+}
+
+ +

說明

+ +

The returned object is of the same type that the object returned from the element's {{domxref("HTMLElement.style", "style")}} property; however, the two objects have different purposes. The object returned from getComputedStyle is read-only and can be used to inspect the element's style (including those set by a <style> element or an external stylesheet). The elt.style object should be used to set styles on a specific element.

+ +

The first argument must be an Element (passing a non-Element Node, like a #text Node, will throw an error). Starting in Gecko 1.9.2 {{geckoRelease("1.9.2")}}, returned URL values now have quotes around the URL, like this: url("http://foo.com/bar.jpg").

+ +

defaultView

+ +

In many code samples online, getComputedStyle is used from the document.defaultView object. In nearly all cases, this is needless, as getComputedStyle exists on the window object as well. It's likely the defaultView pattern was some combination of (1) folks not wanting to write a spec for window and (2) making an API that was also usable in Java. However, there is a single case where the defaultView's method must be used: when using Firefox 3.6 to access framed styles.

+ +

Use with pseudo-elements

+ +

getComputedStyle can pull style info from pseudo-elements (for example, ::after, ::before, ::marker, ::line-marker—see spec here).

+ +
<style>
+ h3::after {
+   content: ' rocks!';
+ }
+</style>
+
+<h3>generated content</h3>
+
+<script>
+  var h3       = document.querySelector('h3'),
+      result   = getComputedStyle(h3, ':after').content;
+
+  console.log('the generated content is: ', result); // returns ' rocks!'
+</script>
+
+ +

備註

+ +

The values returned by getComputedStyle are known as {{cssxref("resolved_value", "resolved values")}}. These are usually the same as the CSS 2.1 {{cssxref("computed_value","computed values")}}, but for some older properties like width, height or padding, they are instead the {{cssxref("used_value","used values")}}. Originally, CSS 2.0 defined the computed values to be the "ready to be used" final values of properties after cascading and inheritance, but CSS 2.1 redefined computed values as pre-layout, and used values as post-layout. For CSS 2.0 properties, the getComputedStyle function returns the old meaning of computed values, now called used values. An example of difference between pre- and post-layout values includes the resolution of percentages that represent the width or the height of an element (also known as its layout), as those will be replaced by their pixel equivalent only in the used value case.

+ +

The returned value is, in certain known cases, expressly inaccurate by deliberate intent. In particular, to avoid the so called CSS History Leak security issue, browsers may expressly "lie" about the used value for a link and always return values as if a user has never visited the linked site. See http://blog.mozilla.com/security/2010/03/31/plugging-the-css-history-leak/ and http://hacks.mozilla.org/2010/03/privacy-related-changes-coming-to-css-vistited/ for details of the examples of how this is implemented. Most other modern browsers have applied similar changes to the application of pseudo-selector styles and the values returned by getComputedStyle.

+ +

During a CSS transition, getComputedStyle returns the original property value in Firefox, but the final property value in WebKit.

+ +

In Firefox, properties with the value auto return the used value, not the value auto. So if you apply top:auto; and bottom:0; on an element with height:30px and its containing block is height:100px;, upon requesting the computed style for top, Firefox will return top:70px, as 100px-30px=70px.

+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}9{{CompatVersionUnknown}}{{CompatVersionUnknown}}
pseudo-element support{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}915{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}WP7 Mango{{CompatVersionUnknown}}{{CompatVersionUnknown}}
pseudo-element support{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatNo}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

規範

+ + + +

參見

+ + diff --git a/files/zh-tw/web/api/window/index.html b/files/zh-tw/web/api/window/index.html new file mode 100644 index 0000000000..276dcc96e2 --- /dev/null +++ b/files/zh-tw/web/api/window/index.html @@ -0,0 +1,468 @@ +--- +title: Window +slug: Web/API/Window +translation_of: Web/API/Window +--- +

{{APIRef}}

+ +

window 物件代表了一個包含 DOM 文件的視窗,其中的 document 屬性指向了視窗中載入的 {{domxref("Document")}} 物件。而使用 document {{Domxref("Document.defaultView", "defaultView")}} 屬性,則可取得該 Document 物件所在的視窗 window 物件。

+ +

本節提供了 DOM window 物件的所有方法、屬性以及事件的說明。window 物件實作了 Window 介面,而 Window 介面則繼承自 AbstractView 介面。一些額外、與 window 物件沒有直接關係,但卻置於 window 物件中的全域函式、命名空間、物件、介面以及建構式,將會在 JavaScript 參考文件文件物件模型(DOM)中說明。

+ +

在支援分頁的瀏覽器中(如 Firefox),每一個分頁標籤都擁有自己的 window 物件(如果你正在撰寫瀏覽器附加元件,瀏覽器視窗本身也是一個個別的 window-請參閱 Working with windows in chrome code),分頁不會於同一個瀏覽器視窗中共享 window 物件。但有部分的方法,如 {{Domxref("window.resizeTo()")}} 或 {{Domxref("window.resizeBy()")}} 會套用至整個視窗,而不只是該 window 物件所屬的分頁標籤。一般來說,若無法適當的應用於分頁,便會套用至瀏覽器視窗。

+ +

{{InheritanceDiagram}}

+ +

屬性

+ +

This interface inherits properties from the {{domxref("EventTarget")}} interface and implements properties from the {{domxref("WindowOrWorkerGlobalScope")}} and {{domxref("WindowEventHandlers")}} mixins.

+ +

請注意,指向物件的屬性(例如覆蓋了內建物件原型的元素)會在另外的列表中說明。

+ +
+
{{domxref("Window.applicationCache")}} {{readOnlyInline}} {{gecko_minversion_inline("1.9")}}
+
指向 {{domxref("OfflineResourceList")}} 物件,此物件提供了視窗的離線資源。
+
{{domxref("Window.closed")}} {{Non-standard_inline}}{{readOnlyInline}}
+
This property indicates whether the current window is closed or not.
+
{{domxref("Window.Components")}} {{Non-standard_inline}}
+
The entry point to many XPCOM features. Some properties, e.g. classes, are only available to sufficiently privileged code. Web code should not use this property.
+
{{domxref("Window.console")}} {{ReadOnlyInline}}
+
Returns a reference to the console object which provides access to the browser's debugging console.
+
{{domxref("Window.content")}} and Window._content {{Non-standard_inline}} {{obsolete_inline}}{{ReadOnlyInline}}
+
Returns a reference to the content element in the current window. The obsolete variant with underscore is no longer available from Web content.
+
{{domxref("Window.controllers")}}{{non-standard_inline}}{{ReadOnlyInline}}
+
Returns the XUL controller objects for the current chrome window.
+
{{domxref("Window.crypto")}} {{readOnlyInline}}
+
Returns the browser crypto object.
+
{{domxref("Window.defaultStatus")}} {{Obsolete_inline("gecko23")}}
+
Gets/sets the status bar text for the given window.
+
{{domxref("Window.devicePixelRatio")}} {{non-standard_inline}}{{ReadOnlyInline}}
+
Returns the ratio between physical pixels and device independent pixels in the current display.
+
{{domxref("Window.dialogArguments")}} {{Fx_minversion_inline(3)}} {{ReadOnlyInline}}
+
Gets the arguments passed to the window (if it's a dialog box) at the time {{domxref("window.showModalDialog()")}} was called. This is an {{Interface("nsIArray")}}.
+
{{domxref("Window.directories")}} {{obsolete_inline}}
+
Synonym of {{domxref("window.personalbar")}}
+
{{domxref("Window.document")}} {{ReadOnlyInline}}
+
指向此 window 中的 document 物件。
+
{{domxref("Window.frameElement")}} {{readOnlyInline}}
+
Returns the element in which the window is embedded, or null if the window is not embedded.
+
{{domxref("Window.frames")}} {{readOnlyInline}}
+
Returns an array of the subframes in the current window.
+
{{domxref("Window.fullScreen")}} {{gecko_minversion_inline("1.9")}}
+
此屬性表示目前視窗是否為全螢幕顯示。
+
{{domxref("Window.globalStorage")}} {{gecko_minversion_inline("1.8.1")}} {{Non-standard_inline}} {{Obsolete_inline("gecko13")}}
+
Unsupported since Gecko 13 (Firefox 13). Use {{domxref("Window.localStorage")}} instead.
+ Was: Multiple storage objects that are used for storing data across multiple pages.
+
{{domxref("Window.history")}} {{ReadOnlyInline}}
+
指向 history 物件。
+
{{domxref("Window.innerHeight")}} {{readOnlyInline}}
+
取得視窗內的網頁內容高度,包含水平捲軸。
+
{{domxref("Window.innerWidth")}} {{readOnlyInline}}
+
取得視窗內的網頁內容寬度,包含垂直捲軸。
+
{{domxref("Window.isSecureContext")}} {{readOnlyInline}}
+
Indicates whether a context is capable of using features that require secure contexts.
+
{{domxref("Window.length")}} {{readOnlyInline}}
+
Returns the number of frames in the window. See also {{domxref("window.frames")}}.
+
{{domxref("Window.location")}}
+
Gets/sets the location, or current URL, of the window object.
+
{{domxref("Window.locationbar")}} {{ReadOnlyInline}}
+
Returns the locationbar object, whose visibility can be toggled in the window.
+
{{domxref("Window.localStorage")}} {{readOnlyInline}}{{gecko_minversion_inline("1.9.1")}}
+
Returns a reference to the local storage object used to store data that may only be accessed by the origin that created it.
+
{{domxref("Window.menubar")}} {{ReadOnlyInline}}
+
Returns the menubar object, whose visibility can be toggled in the window.
+
{{domxref("Window.messageManager")}} {{gecko_minversion_inline("2.0")}}
+
Returns the message manager object for this window.
+
{{domxref("Window.mozAnimationStartTime")}} {{ReadOnlyInline}}{{gecko_minversion_inline("2.0")}} {{Deprecated_inline}}
+
The time in milliseconds since epoch at which the current animation cycle began.
+
{{domxref("Window.mozInnerScreenX")}} {{ReadOnlyInline}}{{non-standard_inline}}{{gecko_minversion_inline("1.9.2")}}
+
Returns the horizontal (X) coordinate of the top-left corner of the window's viewport, in screen coordinates. This value is reported in CSS pixels. See mozScreenPixelsPerCSSPixel in {{interface("nsIDOMWindowUtils")}} for a conversion factor to adapt to screen pixels if needed.
+
{{domxref("Window.mozInnerScreenY")}} {{ReadOnlyInline}} {{non-standard_inline}}{{gecko_minversion_inline("1.9.2")}}
+
Returns the vertical (Y) coordinate of the top-left corner of the window's viewport, in screen coordinates. This value is reported in CSS pixels. See mozScreenPixelsPerCSSPixel for a conversion factor to adapt to screen pixels if needed.
+
{{domxref("Window.mozPaintCount")}} {{non-standard_inline}}{{ReadOnlyInline}} {{gecko_minversion_inline("2.0")}}
+
Returns the number of times the current document has been rendered to the screen in this window. This can be used to compute rendering performance.
+
{{domxref("Window.name")}}
+
Gets/sets the name of the window.
+
{{domxref("Window.navigator")}} {{readOnlyInline}}
+
Returns a reference to the navigator object.
+
{{domxref("Window.opener")}}
+
Returns a reference to the window that opened this current window.
+
{{domxref("Window.orientation")}}{{non-standard_inline}}{{deprecated_inline}}{{readOnlyInline}}
+
Returns the orientation in degrees (in 90 degree increments) of the viewport relative to the device's natural orientation.
+
{{domxref("Window.outerHeight")}} {{readOnlyInline}}
+
取得瀏覽器視窗的高度。
+
{{domxref("Window.outerWidth")}} {{readOnlyInline}}
+
取得瀏覽器視窗的寬度。
+
{{domxref("Window.scrollX","Window.pageXOffset")}} {{readOnlyInline}}
+
An alias for {{domxref("window.scrollX")}}.
+
{{domxref("Window.scrollY","Window.pageYOffset")}}{{readOnlyInline}}
+
An alias for {{domxref("window.scrollY")}}
+
{{domxref("Window.sessionStorage")}} {{readOnlyInline}}
+
Returns a reference to the session storage object used to store data that may only be accessed by the origin that created it.
+
{{domxref("Window.parent")}} {{readOnlyInline}}
+
Returns a reference to the parent of the current window or subframe.
+
{{domxref("Window.performance")}} {{readOnlyInline}}
+
Returns a {{domxref("Performance")}} object, which includes the {{domxref("Performance.timing", "timing")}} and {{domxref("Performance.navigation", "navigation")}} attributes, each of which is an object providing performance-related data. See also Using Navigation Timing for additional information and examples.
+
{{domxref("Window.personalbar")}} {{readOnlyInline}}
+
Returns the personalbar object, whose visibility can be toggled in the window.
+
{{domxref("Window.pkcs11")}} {{obsolete_inline(29)}}
+
Formerly provided access to install and remove PKCS11 modules.
+
{{domxref("Window.returnValue")}} {{Fx_minversion_inline(3)}}
+
The return value to be returned to the function that called {{domxref("window.showModalDialog()")}} to display the window as a modal dialog.
+
{{domxref("Window.screen")}} {{readOnlyInline}}
+
回傳一個與 window 關聯的 screen 物件。
+
{{domxref("Window.screenX")}} {{readOnlyInline}}
+
Returns the horizontal distance of the left border of the user's browser from the left side of the screen.
+
{{domxref("Window.screenY")}} {{readOnlyInline}}
+
Returns the vertical distance of the top border of the user's browser from the top side of the screen.
+
{{domxref("Window.scrollbars")}} {{readOnlyInline}}
+
Returns the scrollbars object, whose visibility can be toggled in the window.
+
{{domxref("Window.scrollMaxX")}}{{non-standard_inline}}{{ReadOnlyInline}}
+
The maximum offset that the window can be scrolled to horizontally, that is the document width minus the viewport width.
+
{{domxref("Window.scrollMaxY")}}{{non-standard_inline}}{{ReadOnlyInline}}
+
The maximum offset that the window can be scrolled to vertically (i.e., the document height minus the viewport height).
+
{{domxref("Window.scrollX")}} {{readOnlyInline}}
+
Returns the number of pixels that the document has already been scrolled horizontally.
+
{{domxref("Window.scrollY")}} {{readOnlyInline}}
+
Returns the number of pixels that the document has already been scrolled vertically.
+
{{domxref("Window.self")}} {{ReadOnlyInline}}
+
Returns an object reference to the window object itself.
+
{{domxref("Window.sessionStorage")}} {{Fx_minversion_inline("2.0")}}
+
Returns a storage object for storing data within a single page session.
+
{{domxref("Window.sidebar")}} {{non-standard_inline}}{{ReadOnlyInline}}
+
Returns a reference to the window object of the sidebar.
+
{{domxref("Window.speechSynthesis")}} {{ReadOnlyInline}}
+
Returns a {{domxref("SpeechSynthesis")}} object, which is the entry point into using Web Speech API speech synthesis functionality.
+
{{domxref("Window.status")}}
+
Gets/sets the text in the statusbar at the bottom of the browser.
+
{{domxref("Window.statusbar")}} {{readOnlyInline}}
+
Returns the statusbar object, whose visibility can be toggled in the window.
+
{{domxref("Window.toolbar")}} {{readOnlyInline}}
+
Returns the toolbar object, whose visibility can be toggled in the window.
+
{{domxref("Window.top")}} {{readOnlyInline}}
+
Returns a reference to the topmost window in the window hierarchy. This property is read only.
+
{{domxref("Window.window")}} {{ReadOnlyInline}}
+
Returns a reference to the current window.
+
window[0], window[1], etc.
+
Returns a reference to the window object in the frames. See {{domxref("Window.frames")}} for more details.
+
+ +

Properties implemented from elsewhere

+ +
+
{{domxref("WindowOrWorkerGlobalScope.caches")}} {{readOnlyinline}}
+
Returns the {{domxref("CacheStorage")}} object associated with the current context. This object enables functionality such as storing assets for offline use, and generating custom responses to requests.
+
{{domxref("WindowOrWorkerGlobalScope.indexedDB")}} {{readonlyInline}}
+
Provides a mechanism for applications to asynchronously access capabilities of indexed databases; returns an {{domxref("IDBFactory")}} object.
+
{{domxref("WindowOrWorkerGlobalScope.isSecureContext")}} {{readOnlyinline}}
+
Returns a boolean indicating whether the current context is secure (true) or not (false).
+
{{domxref("WindowOrWorkerGlobalScope.origin")}} {{readOnlyinline}}
+
Returns the global object's origin, serialized as a string. (This does not yet appear to be implemented in any browser.)
+
+ +

方法

+ +

This interface inherits methods from the {{domxref("EventTarget")}} interface and implements methods from {{domxref("WindowOrWorkerGlobalScope")}} and {{domxref("EventTarget")}}.

+ +
+
{{domxref("Window.alert()")}}
+
Displays an alert dialog.
+
{{domxref("Window.back()")}} {{Non-standard_inline}} {{obsolete_inline}}
+
Moves back one in the window history.
+
{{domxref("Window.blur()")}}
+
Sets focus away from the window.
+
{{domxref("Window.cancelAnimationFrame()")}} {{experimental_inline}}
+
Enables you to cancel a callback previously scheduled with {{domxref("Window.requestAnimationFrame")}}.
+
{{domxref("Window.cancelIdleCallback()")}} {{experimental_inline}}
+
Enables you to cancel a callback previously scheduled with {{domxref("Window.requestIdleCallback")}}.
+
{{domxref("Window.captureEvents()")}} {{Deprecated_inline}}
+
Registers the window to capture all events of the specified type.
+
{{domxref("Window.clearImmediate()")}}
+
Cancels the repeated execution set using setImmediate.
+
{{domxref("Window.close()")}}
+
Closes the current window.
+
{{domxref("Window.confirm()")}}
+
Displays a dialog with a message that the user needs to respond to.
+
{{domxref("Window.disableExternalCapture()")}} {{obsolete_inline(24)}}
+
{{todo("NeedsContents")}}
+
{{domxref("Window.dispatchEvent()")}}
+
Used to trigger an event.
+
{{domxref("Window.dump()")}} {{Non-standard_inline}}
+
Writes a message to the console.
+
{{domxref("Window.enableExternalCapture()")}} {{obsolete_inline(24)}}
+
{{todo("NeedsContents")}}
+
{{domxref("Window.find()")}}
+
Searches for a given string in a window.
+
{{domxref("Window.focus()")}}
+
Sets focus on the current window.
+
{{domxref("Window.forward()")}} {{Non-standard_inline}} {{obsolete_inline}}
+
Moves the window one document forward in the history.
+
{{domxref("Window.getAttention()")}} {{Non-standard_inline}} {{obsolete_inline}}
+
Flashes the application icon.
+
{{domxref("Window.getAttentionWithCycleCount()")}}
+
{{todo("NeedsContents")}}
+
{{domxref("Window.getComputedStyle()")}}
+
Gets computed style for the specified element. Computed style indicates the computed values of all CSS properties of the element.
+
{{domxref("Window.getDefaultComputedStyle()")}} {{Non-standard_inline}}
+
Gets default computed style for the specified element, ignoring author stylesheets.
+
{{domxref("Window.getSelection()")}}
+
Returns the selection object representing the selected item(s).
+
{{domxref("Window.home()")}} {{Non-standard_inline}} {{obsolete_inline}}
+
Returns the browser to the home page.
+
{{domxref("Window.matchMedia()")}} {{gecko_minversion_inline("6.0")}}
+
Returns a {{domxref("MediaQueryList")}} object representing the specified media query string.
+
{{domxref("Window.maximize()")}}
+
{{todo("NeedsContents")}}
+
{{domxref("Window.minimize()")}} (top-level XUL windows only)
+
Minimizes the window.
+
{{domxref("Window.moveBy()")}}
+
Moves the current window by a specified amount.
+
{{domxref("Window.moveTo()")}}
+
Moves the window to the specified coordinates.
+
{{domxref("Window.open()")}}
+
Opens a new window.
+
{{domxref("Window.openDialog()")}} {{Non-standard_inline}} {{obsolete_inline}}
+
Opens a new dialog window.
+
{{domxref("Window.postMessage()")}} {{Fx_minversion_inline(3)}}
+
Provides a secure means for one window to send a string of data to another window, which need not be within the same domain as the first.
+
{{domxref("Window.print()")}}
+
Opens the Print Dialog to print the current document.
+
{{domxref("Window.prompt()")}}
+
Returns the text entered by the user in a prompt dialog.
+
{{domxref("Window.releaseEvents()")}} {{Non-standard_inline}} {{Deprecated_inline}}
+
Releases the window from trapping events of a specific type.
+
{{domxref("Window.requestAnimationFrame()")}} {{gecko_minversion_inline("2.0")}}
+
Tells the browser that an animation is in progress, requesting that the browser schedule a repaint of the window for the next animation frame.
+
{{domxref("Window.requestIdleCallback()")}} {{experimental_inline}}
+
Enables the scheduling of tasks during a browser's idle periods.
+
{{domxref("Window.resizeBy()")}}
+
Resizes the current window by a certain amount.
+
{{domxref("Window.resizeTo()")}}
+
Dynamically resizes window.
+
{{domxref("Window.restore()")}} {{Non-standard_inline}} {{obsolete_inline}}
+
{{todo("NeedsContents")}}
+
{{domxref("Window.routeEvent()")}} {{obsolete_inline(24)}}
+
{{todo("NeedsContents")}}
+
{{domxref("Window.scroll()")}}
+
Scrolls the window to a particular place in the document.
+
{{domxref("Window.scrollBy()")}}
+
Scrolls the document in the window by the given amount.
+
{{domxref("Window.scrollByLines()")}} {{Non-standard_inline}}
+
Scrolls the document by the given number of lines.
+
{{domxref("Window.scrollByPages()")}} {{Non-standard_inline}}
+
Scrolls the current document by the specified number of pages.
+
{{domxref("Window.scrollTo()")}}
+
Scrolls to a particular set of coordinates in the document.
+
{{domxref("Window.setCursor()")}} {{Non-standard_inline}} (top-level XUL windows only)
+
Changes the cursor for the current window
+
{{domxref("Window.setImmediate()")}}
+
Executes a function after the browser has finished other heavy tasks
+
{{domxref("Window.setResizable()")}} {{Non-standard_inline}}
+
Toggles a user's ability to resize a window.
+
{{domxref("Window.sizeToContent()")}} {{Non-standard_inline}}
+
Sizes the window according to its content.
+
{{domxref("Window.stop()")}}
+
This method stops window loading.
+
{{domxref("Window.updateCommands()")}} {{Non-standard_inline}}
+
Updates the state of commands of the current chrome window (UI).
+
+ +

Methods implemented from elsewhere

+ +
+
{{domxref("EventTarget.addEventListener()")}}
+
Register an event handler to a specific event type on the window.
+
{{domxref("WindowOrWorkerGlobalScope.atob()")}}
+
Decodes a string of data which has been encoded using base-64 encoding.
+
{{domxref("WindowOrWorkerGlobalScope.btoa()")}}
+
Creates a base-64 encoded ASCII string from a string of binary data.
+
{{domxref("WindowOrWorkerGlobalScope.clearInterval()")}}
+
Cancels the repeated execution set using {{domxref("WindowOrWorkerGlobalScope.setInterval()")}}.
+
{{domxref("WindowOrWorkerGlobalScope.clearTimeout()")}}
+
Cancels the delayed execution set using {{domxref("WindowOrWorkerGlobalScope.setTimeout()")}}.
+
{{domxref("WindowOrWorkerGlobalScope.createImageBitmap()")}}
+
Accepts a variety of different image sources, and returns a {{domxref("Promise")}} which resolves to an {{domxref("ImageBitmap")}}. Optionally the source is cropped to the rectangle of pixels originating at (sx, sy) with width sw, and height sh.
+
{{domxref("WindowOrWorkerGlobalScope.fetch()")}}
+
Starts the process of fetching a resource from the network.
+
{{domxref("EventTarget.removeEventListener")}}
+
Removes an event listener from the window.
+
{{domxref("WindowOrWorkerGlobalScope.setInterval()")}}
+
Schedules a function to execute every time a given number of milliseconds elapses.
+
{{domxref("WindowOrWorkerGlobalScope.setTimeout()")}}
+
Schedules a function to execute in a given amount of time.
+
+ +

Obsolete methods

+ +
+
{{domxref("Window.showModalDialog()")}} {{obsolete_inline}}
+
Displays a modal dialog. This method was removed completely in Chrome 43, and Firefox 55.
+
+ +

事件處理器

+ +

These are properties of the window object that can be set to establish event handlers for the various things that can happen in the window that might be of interest.

+ +

This interface inherits event handlers from the {{domxref("EventTarget")}} interface and implements event handlers from {{domxref("WindowEventHandlers")}}.

+ +
+

Note: Starting in {{Gecko("9.0")}}, you can now use the syntax if ("onabort" in window) to determine whether or not a given event handler property exists. This is because event handler interfaces have been updated to be proper web IDL interfaces. See DOM event handlers for details.

+
+ +
+
{{domxref("GlobalEventHandlers.onabort")}}
+
Called when the loading of a resource has been aborted, such as by a user canceling the load while it is still in progress
+
{{domxref("WindowEventHandlers.onafterprint")}}
+
Called when the print dialog box is closed. See {{event("afterprint")}} event.
+
{{domxref("WindowEventHandlers.onbeforeprint")}}
+
Called when the print dialog box is opened. See {{event("beforeprint")}} event.
+
{{domxref("Window.onbeforeinstallprompt")}}
+
An event handler property dispatched before a user is prompted to save a web site to a home screen on mobile.
+
{{domxref("WindowEventHandlers.onbeforeunload")}}
+
An event handler property for before-unload events on the window.
+
{{domxref("GlobalEventHandlers.onblur")}}
+
Called after the window loses focus, such as due to a popup.
+
{{domxref("GlobalEventHandlers.onchange")}}
+
An event handler property for change events on the window.
+
{{domxref("GlobalEventHandlers.onclick")}}
+
Called after the ANY mouse button is pressed & released
+
{{domxref("GlobalEventHandlers.ondblclick")}}
+
Called when a double click is made with ANY mouse button.
+
{{domxref("GlobalEventHandlers.onclose")}}
+
Called after the window is closed
+
{{domxref("GlobalEventHandlers.oncontextmenu")}}
+
Called when the RIGHT mouse button is pressed
+
{{domxref("Window.ondevicelight")}}
+
An event handler property for any ambient light levels changes
+
{{domxref("Window.ondevicemotion")}} {{gecko_minversion_inline("6.0")}}
+
Called if accelerometer detects a change (For mobile devices)
+
{{domxref("Window.ondeviceorientation")}} {{gecko_minversion_inline("6.0")}}
+
Called when the orientation is changed (For mobile devices)
+
{{domxref("Window.ondeviceorientationabsolute")}} {{non-standard_inline}} Chrome only
+
An event handler property for any device orientation changes.
+
{{domxref("Window.ondeviceproximity")}}
+
An event handler property for device proximity event
+
{{domxref("GlobalEventHandlers.onerror")}}
+
Called when a resource fails to load OR when an error occurs at runtime. See {{event("error")}} event.
+
{{domxref("GlobalEventHandlers.onfocus")}}
+
Called after the window receives or regains focus. See {{event("focus")}} events.
+
{{domxref("WindowEventHandlers.onhashchange")}} {{gecko_minversion_inline("1.9.2")}}
+
An event handler property for {{event('hashchange')}} events on the window; called when the part of the URL after the hash mark ("#") changes.
+
{{domxref("Window.onappinstalled")}}
+
Called when the page is installed as a webapp. See {{event('appinstalled')}} event.
+
{{domxref("Window.ongamepadconnected")}}
+
Represents an event handler that will run when a gamepad is connected (when the {{event('gamepadconnected')}} event fires).
+
{{domxref("Window.ongamepaddisconnected")}}
+
Represents an event handler that will run when a gamepad is disconnected (when the {{event('gamepaddisconnected')}} event fires).
+
{{domxref("Window.oninput")}}
+
Called when the value of an <input> element changes
+
{{domxref("GlobalEventHandlers.onkeydown")}}
+
Called when you begin pressing ANY key. See {{event("keydown")}} event.
+
{{domxref("GlobalEventHandlers.onkeypress")}}
+
Called when a key (except Shift, Fn, and CapsLock) is in pressed position. See {{event("keypress")}} event.
+
{{domxref("GlobalEventHandlers.onkeyup")}}
+
Called when you finish releasing ANY key. See {{event("keyup")}} event.
+
{{domxref("WindowEventHandlers.onlanguagechange")}}
+
An event handler property for {{event("languagechange")}} events on the window.
+
{{domxref("GlobalEventHandlers.onload")}}
+
Called after all resources and the DOM are fully loaded. WILL NOT get called when the page is loaded from cache, such as with back button.
+
{{domxref("WindowEventHandlers.onmessage")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("message")}} event is raised.
+
{{domxref("GlobalEventHandlers.onmousedown")}}
+
Called when ANY mouse button is pressed.
+
{{domxref("GlobalEventHandlers.onmousemove")}}
+
Called continously when the mouse is moved inside the window.
+
{{domxref("GlobalEventHandlers.onmouseout")}}
+
Called when the pointer leaves the window.
+
{{domxref("GlobalEventHandlers.onmouseover")}}
+
Called when the pointer enters the window
+
{{domxref("GlobalEventHandlers.onmouseup")}}
+
Called when ANY mouse button is released
+
{{domxref("Window.onmozbeforepaint")}} {{gecko_minversion_inline("2.0")}}
+
An event handler property for the MozBeforePaint event, which is sent before repainting the window if the event has been requested by a call to the {{domxref("Window.mozRequestAnimationFrame()")}} method.
+
{{domxref("WindowEventHandlers.onoffline")}}
+
Called when network connection is lost. See {{event("offline")}} event.
+
{{domxref("WindowEventHandlers.ononline")}}
+
Called when network connection is established. See {{event("online")}} event.
+
{{domxref("WindowEventHandlers.onpagehide")}}
+
Called when the user navigates away from the page, before the onunload event. See {{event("pagehide")}} event.
+
{{domxref("WindowEventHandlers.onpageshow")}}
+
Called after all resources and the DOM are fully loaded. See {{event("pageshow")}} event.
+
{{domxref("Window.onpaint")}}
+
An event handler property for paint events on the window.
+
{{domxref("WindowEventHandlers.onpopstate")}} {{gecko_minversion_inline("2.0")}}
+
Called when a back putton is pressed.
+
{{domxref("Window.onrejectionhandled")}} {{experimental_inline}}
+
An event handler for handled {{jsxref("Promise")}} rejection events.
+
{{domxref("GlobalEventHandlers.onreset")}}
+
Called when a form is reset
+
{{domxref("GlobalEventHandlers.onresize")}}
+
Called continuously as you are resizing the window.
+
{{domxref("GlobalEventHandlers.onscroll")}}
+
Called when the scroll bar is moved via ANY means. If the resource fully fits in the window, then this event cannot be invoked
+
{{domxref("GlobalEventHandlers.onwheel")}}
+
Called when the mouse wheel is rotated around any axis
+
{{domxref("GlobalEventHandlers.onselect")}}
+
Called after text in an input field is selected
+
{{domxref("GlobalEventHandlers.onselectionchange")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("selectionchange")}} event is raised.
+
{{domxref("WindowEventHandlers.onstorage")}}
+
Called when there is a change in session storage or local storage. See {{event("storage")}} event
+
{{domxref("GlobalEventHandlers.onsubmit")}}
+
Called when a form is submitted
+
{{domxref("WindowEventHandlers.onunhandledrejection")}} {{experimental_inline}}
+
An event handler for unhandled {{jsxref("Promise")}} rejection events.
+
{{domxref("WindowEventHandlers.onunload")}}
+
Called when the user navigates away from the page.
+
{{domxref("Window.onuserproximity")}}
+
An event handler property for user proximity events.
+
{{domxref("Window.onvrdisplayconnect")}}
+
Represents an event handler that will run when a compatible VR device has been connected to the computer (when the {{event("vrdisplayconnected")}} event fires).
+
{{domxref("Window.onvrdisplaydisconnect")}}
+
Represents an event handler that will run when a compatible VR device has been disconnected from the computer (when the {{event("vrdisplaydisconnected")}} event fires).
+
{{domxref("Window.onvrdisplayactivate")}}
+
Represents an event handler that will run when a display is able to be presented to (when the {{event("vrdisplayactivate")}} event fires), for example if an HMD has been moved to bring it out of standby, or woken up by being put on.
+
{{domxref("Window.onvrdisplaydeactivate")}}
+
Represents an event handler that will run when a display can no longer be presented to (when the {{event("vrdisplaydeactivate")}} event fires), for example if an HMD has gone into standby or sleep mode due to a period of inactivity.
+
{{domxref("Window.onvrdisplayblur")}}
+
Represents an event handler that will run when presentation to a display has been paused for some reason by the browser, OS, or VR hardware (when the {{event("vrdisplayblur")}} event fires) — for example, while the user is interacting with a system menu or browser, to prevent tracking or loss of experience.
+
{{domxref("Window.onvrdisplayfocus")}}
+
Represents an event handler that will run when presentation to a display has resumed after being blurred (when the {{event("vrdisplayfocus")}} event fires).
+
{{domxref("Window.onvrdisplaypresentchange")}}
+
represents an event handler that will run when the presenting state of a VR device changes — i.e. goes from presenting to not presenting, or vice versa (when the {{event("vrdisplaypresentchange")}} event fires).
+
+ +

建構式

+ +

See also the DOM Interfaces.

+ +
+
{{domxref("DOMParser")}}
+
DOMParser can parse XML or HTML source stored in a string into a DOM Document. DOMParser is specified in DOM Parsing and Serialization.
+
{{domxref("Window.GeckoActiveXObject")}}
+
{{todo("NeedsContents")}}
+
{{domxref("Image")}}
+
Used for creating an {{domxref("HTMLImageElement")}}.
+
{{domxref("Option")}}
+
Used for creating an {{domxref("HTMLOptionElement")}}
+
{{domxref("Window.QueryInterface")}}
+
{{todo("NeedsContents")}}
+
{{domxref("Window.XMLSerializer")}}
+
{{todo("NeedsContents")}}
+
{{domxref("Worker")}}
+
Used for creating a Web worker
+
{{domxref("Window.XPCNativeWrapper")}}
+
{{todo("NeedsContents")}}
+
{{domxref("Window.XPCSafeJSObjectWrapper")}}
+
{{todo("NeedsContents")}}
+
+ +

相關介面

+ +

請參閱 {{domxref("Document_Object_Model", "DOM Reference")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/window/localstorage/index.html b/files/zh-tw/web/api/window/localstorage/index.html new file mode 100644 index 0000000000..1733a325bd --- /dev/null +++ b/files/zh-tw/web/api/window/localstorage/index.html @@ -0,0 +1,82 @@ +--- +title: Window.localStorage +slug: Web/API/Window/localStorage +translation_of: Web/API/Window/localStorage +--- +

{{APIRef("Web Storage API")}}

+ +

localStorage 為一唯讀屬性, 此屬性允許您存取目前文件({{DOMxRef("Document")}})隸屬網域來源的 {{DOMxRef("Storage")}} 物件; 與 sessionStorage 不同的是其儲存資料的可存取範圍為跨瀏覽頁狀態(Browser Sessions). localStorage 的應用與 {{DOMxRef("Window.sessionStorage", "sessionStorage")}} 相似, 除了 localStorage 的儲存資料並無到期的限制, 而 sessionStorage 的儲存資料於目前瀏覽頁狀態結束的同時將一併被清除 — 也就是目前瀏覽器頁面被關閉的同時.

+ +

值得注意的是不論 localStorage 或者 sessionStorage 皆為專屬於目前瀏覽器頁面的通訊協定(Protocol).

+ +

鍵值名稱和值皆為字串型式(請留意, 當其為物件, 整數等將自動轉換為字串型式).

+ +

Syntax

+ +
myStorage = window.localStorage;
+ +

Value

+ +

{{DOMxRef("Storage")}} 物件 which can be used to access the current origin's local storage space.

+ +

Exceptions

+ +
+
SecurityError
+
The request violates a policy decision, or the origin is not a valid scheme/host/port tuple (this can happen if the origin uses the file: or data: scheme, for example). 舉例來說,使用者 may have their browser configured to deny permission to persist data for the specified origin.
+
+ +

Example

+ +

下列的程式碼片段讀取了目前域名內的 local {{DOMxRef("Storage")}} 物件 ,並用{{DOMxRef("Storage.setItem()")}},增加一個資料物件 item 到其中

+ +
localStorage.setItem('myCat', 'Tom');
+ +

讀取 localStorage 內物件的語法如下:

+ +
var cat = localStorage.getItem('myCat');
+ +

移除 localStorage 內物件的語法如下:

+ +
localStorage.removeItem('myCat');
+ +

刪除 localStorage 內所有物件的語法如下:

+ +
// Clear all items
+localStorage.clear();
+
+ +
+

Note: Please refer to the Using the Web Storage API article for a full example.

+
+ +

Specifications

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("HTML WHATWG", "webstorage.html#dom-localstorage", "localStorage")}}{{Spec2("HTML WHATWG")}}
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Window.localStorage")}}

+ +

See also

+ + diff --git a/files/zh-tw/web/api/window/location/index.html b/files/zh-tw/web/api/window/location/index.html new file mode 100644 index 0000000000..a887f88ee0 --- /dev/null +++ b/files/zh-tw/web/api/window/location/index.html @@ -0,0 +1,373 @@ +--- +title: window.location +slug: Web/API/Window/location +translation_of: Web/API/Window/location +--- +

{{ ApiRef() }}

+

Summary

+

Returns a Location object, which contains information about the URL of the document and provides methods for changing that URL. You can also assign to this property to load another URL.

+

語法

+
var locationObj = window.location;
+window.location = newLocation;
+
+

where

+ +

Location object

+

This section describes the properties and methods of the location object.

+

Use as a string

+

Location objects have a toString method returning the current URL. You can also assign a string to window.location. This means that you can work with window.location as if it were a string in most cases. Sometimes, for example when you need to call a String method on it, you have to explicitly call toString:

+
alert(window.location.toString().charAt(17));
+
+

Properties

+

All of the following properties are strings. You can read them to get information about the current URL or set them to navigate to another URL.

+

The "Example" column contains the values of the properties of the following URL:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyDescriptionExample
hashthe part of the URL that follows the # symbol, including the # symbol.
+ You can listen for the hashchange event to get notified of changes to the hash in supporting browsers.
#test
hostthe host name and port number.[www.example.com]:80
hostnamethe host name (without the port number or square brackets).www.example.com
hrefthe entire URL.http://[www.example.com]:80/search?q=devmo#test
pathnamethe path (relative to the host)./search
portthe port number of the URL.80
protocolthe protocol of the URL.http:
searchthe part of the URL that follows the ? symbol, including the ? symbol.?q=devmo
+

If the hash part of the URL contains encoded characters (see Core_JavaScript_1.5_Reference:Global_Functions:encodeURIComponent), hash returns the decoded URL part. This is a bug in Firefox. href, search and pathname return the correct, encoded URL parts. For example:

+ +

results in:

+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
assign(url)Load the document at the provided URL.
reload(forceget)Reload the document from the current URL. forceget is a boolean, which, when it is true, causes the page to always be reloaded from the server. If it is false or not specified, the browser may reload the page from its cache.
replace(url)Replace the current document with the one at the provided URL. The difference from the assign() method is that after using replace() the current page will not be saved in session history, meaning the user won't be able to use the Back button to navigate to it.
toString()Returns the string representation of the Location object's URL. See the JavaScript reference for details.
+

Examples

+

Whenever a property of the location object is modified, a document will be loaded using the URL as if window.location.assign() had been called with the modified URL.

+
Replace the current document with the one at the given URL:
+
function goMoz() {
+   window.location = "http://www.mozilla.org";
+}
+
+// in html: <button onclick="goMoz();">Mozilla</button>
+
+
+
+ Note: The example above works in situations where window.location.hash does not need to be retained. However, in Gecko-based browsers, setting window.location.pathname in this manner will erase any information in window.location.hash, whereas in WebKit (and possibly other browsers), setting the pathname will not alter the the hash. If you need to change pathname but keep the hash as is, use the replace() method instead, which should work consistently across browsers.
+


+ Consider the following example, which will reload the page by using the replace() method to insert the value of window.location.pathname into the hash (similar to Twitter's reload of http://twitter.com/username to http://twitter.com/#!/username):

+
function reloadPageWithHash() {
+  var initialPage = window.location.pathname;
+  window.location.replace('http://example.com/#' + initialPage);
+}
+
+
Display the properties of the current URL in an alert dialog:
+
function showLoc() {
+  var oLocation = window.location, aLog = ["Property (Typeof): Value", "window.location (" + (typeof oLocation) + "): " + oLocation ];
+  for (var sProp in oLocation){
+    aLog.push(sProp + " (" + (typeof oLocation[sProp]) + "): " +  (oLocation[sProp] || "n/a"));
+  }
+  alert(aLog.join("\n"));
+}
+
+// in html: <button onclick="showLoc();">Show location properties</button>
+
+
Send a string of data to the server by modifying the search property:
+
function sendData (sData) {
+  window.location.search = sData;
+}
+
+// in html: <button onclick="sendData('Some data');">Send data</button>
+
+
+

The current URL with "?Some%20data" appended is sent to the server (if no action is taken by the server, the current document is reloaded with the modified search string).

+
Get the value of a single window.location.search key:
+
function loadPageVar (sVar) {
+  return unescape(window.location.search.replace(new RegExp("^(?:.*[&\\?]" + escape(sVar).replace(/[\.\+\*]/g, "\\$&") + "(?:\\=([^&]*))?)?.*$", "i"), "$1"));
+}
+
+alert(loadPageVar("name"));
+
+
Nestle the variables obtained through the window.location.search string in an object named oGetVars:
+
var oGetVars = {};
+
+if (window.location.search.length > 1) {
+  for (var aItKey, nKeyId = 0, aCouples = window.location.search.substr(1).split("&"); nKeyId < aCouples.length; nKeyId++) {
+    aItKey = aCouples[nKeyId].split("=");
+    oGetVars[unescape(aItKey[0])] = aItKey.length > 1 ? unescape(aItKey[1]) : "";
+  }
+}
+
+// alert(oGetVars.yourVar);
+
+

…the same thing obtained by an anonymous constructor – useful for a global variable declaration:

+
var oGetVars = new (function (sSearch) {
+  if (sSearch.length > 1) {
+    for (var aItKey, nKeyId = 0, aCouples = sSearch.substr(1).split("&"); nKeyId < aCouples.length; nKeyId++) {
+      aItKey = aCouples[nKeyId].split("=");
+      this[unescape(aItKey[0])] = aItKey.length > 1 ? unescape(aItKey[1]) : "";
+    }
+  }
+})(window.location.search);
+
+// alert(oGetVars.yourVar);
+
+
Nestle the variables obtained through the window.location.search string in an object named oGetVars, also attempting to recognize their typeof:
+
var oGetVars = {};
+
+function buildValue(sValue) {
+  if (/^\s*$/.test(sValue)) { return null; }
+  if (/^(true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; }
+  if (isFinite(sValue)) { return parseFloat(sValue); }
+  if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
+  return sValue;
+}
+
+if (window.location.search.length > 1) {
+  for (var aItKey, nKeyId = 0, aCouples = window.location.search.substr(1).split("&"); nKeyId < aCouples.length; nKeyId++) {
+    aItKey = aCouples[nKeyId].split("=");
+    oGetVars[unescape(aItKey[0])] = aItKey.length > 1 ? buildValue(unescape(aItKey[1])) : null;
+  }
+}
+
+// alert(oGetVars.yourVar);
+
+

…the same thing obtained by an anonymous constructor – useful for a global variable declaration:

+
var oGetVars = new (function (sSearch) {
+  var rNull = /^\s*$/, rBool = /^(true|false)$/i;
+  function buildValue(sValue) {
+    if (rNull.test(sValue)) { return null; }
+    if (rBool.test(sValue)) { return sValue.toLowerCase() === "true"; }
+    if (isFinite(sValue)) { return parseFloat(sValue); }
+    if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
+    return sValue;
+  }
+  if (sSearch.length > 1) {
+    for (var aItKey, nKeyId = 0, aCouples = sSearch.substr(1).split("&"); nKeyId < aCouples.length; nKeyId++) {
+      aItKey = aCouples[nKeyId].split("=");
+      this[unescape(aItKey[0])] = aItKey.length > 1 ? buildValue(unescape(aItKey[1])) : null;
+    }
+  }
+})(window.location.search);
+
+// alert(oGetVars.yourVar);
+
+
Using bookmars without changing the window.location.hash property:
+
<!doctype html>
+<html>
+<head>
+<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
+<title>MDN Example</title>
+<script type="text/javascript">
+function showNode (oNode) {
+  var nLeft = 0, nTop = 0;
+  for (var oItNode = oNode; oItNode; nLeft += oItNode.offsetLeft, nTop += oItNode.offsetTop, oItNode = oItNode.offsetParent);
+  document.documentElement.scrollTop = nTop;
+  document.documentElement.scrollLeft = nLeft;
+}
+
+function showBookmark (sBookmark, bUseHash) {
+  if (arguments.length === 1 || bUseHash) { window.location.hash = sBookmark; return; }
+  var oBookmark = document.querySelector(sBookmark);
+  if (oBookmark) { showNode(oBookmark); }
+}
+</script>
+<style type="text/css">
+span.intLink {
+    cursor: pointer;
+    color: #0000ff;
+    text-decoration: underline;
+}
+</style>
+</head>
+
+<body>
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices dolor ac dolor imperdiet ullamcorper. Suspendisse quam libero, luctus auctor mollis sed, malesuada condimentum magna. Quisque in ante tellus, in placerat est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec a mi magna, quis mattis dolor. Etiam sit amet ligula quis urna auctor imperdiet nec faucibus ante. Mauris vel consectetur dolor. Nunc eget elit eget velit pulvinar fringilla consectetur aliquam purus. Curabitur convallis, justo posuere porta egestas, velit erat ornare tortor, non viverra justo diam eget arcu. Phasellus adipiscing fermentum nibh ac commodo. Nam turpis nunc, suscipit a hendrerit vitae, volutpat non ipsum.</p>
+<p>Duis lobortis sapien quis nisl luctus porttitor. In tempor semper libero, eu tincidunt dolor eleifend sit amet. Ut nec velit in dolor tincidunt rhoncus non non diam. Morbi auctor ornare orci, non euismod felis gravida nec. Curabitur elementum nisi a eros rutrum nec blandit diam placerat. Aenean tincidunt risus ut nisi consectetur cursus. Ut vitae quam elit. Donec dignissim est in quam tempor consequat. Aliquam aliquam diam non felis convallis suscipit. Nulla facilisi. Donec lacus risus, dignissim et fringilla et, egestas vel eros. Duis malesuada accumsan dui, at fringilla mauris bibendum quis. Cras adipiscing ultricies fermentum. Praesent bibendum condimentum feugiat.</p>
+<p id="myBookmark1">[&nbsp;<span class="intLink" onclick="showBookmark('#myBookmark2');">Go to bookmark #2</span>&nbsp;]</p>
+<p>Vivamus blandit massa ut metus mattis in fringilla lectus imperdiet. Proin ac ante a felis ornare vehicula. Fusce pellentesque lacus vitae eros convallis ut mollis magna pellentesque. Pellentesque placerat enim at lacus ultricies vitae facilisis nisi fringilla. In tincidunt tincidunt tincidunt. Nulla vitae tempor nisl. Etiam congue, elit vitae egestas mollis, ipsum nisi malesuada turpis, a volutpat arcu arcu id risus.</p>
+<p>Nam faucibus, ligula eu fringilla pulvinar, lectus tellus iaculis nunc, vitae scelerisque metus leo non metus. Proin mattis lobortis lobortis. Quisque accumsan faucibus erat, vel varius tortor ultricies ac. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec libero nunc. Nullam tortor nunc, elementum a consectetur et, ultrices eu orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque a nisl eu sem vehicula egestas.</p>
+<p>Aenean viverra varius mauris, sed elementum lacus interdum non. Phasellus sit amet lectus vitae eros egestas pellentesque fermentum eget magna. Quisque mauris nisl, gravida vitae placerat et, condimentum id metus. Nulla eu est dictum dolor pulvinar volutpat. Pellentesque vitae sollicitudin nunc. Donec neque magna, lobortis id egestas nec, sodales quis lectus. Fusce cursus sollicitudin porta. Suspendisse ut tortor in mauris tincidunt rhoncus. Maecenas tincidunt fermentum facilisis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>
+<p>Suspendisse turpis nisl, consectetur in lacinia ut, ornare vel mi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin non lectus eu turpis vulputate cursus. Mauris interdum tincidunt erat id pharetra. Nullam in libero elit, sed consequat lectus. Morbi odio nisi, porta vitae molestie ut, gravida ut nunc. Ut non est dui, id ullamcorper orci. Praesent vel elementum felis. Maecenas ornare, dui quis auctor hendrerit, turpis sem ullamcorper odio, in auctor magna metus quis leo. Morbi at odio ante.</p>
+<p>Curabitur est ipsum, porta ac viverra faucibus, eleifend sed eros. In sit amet vehicula tortor. Vestibulum viverra pellentesque erat a elementum. Integer commodo ultricies lorem, eget tincidunt risus viverra et. In enim turpis, porttitor ac ornare et, suscipit sit amet nisl. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque vel ultrices nibh. Sed commodo aliquam aliquam. Nulla euismod, odio ut eleifend mollis, nisi dui gravida nibh, vitae laoreet turpis purus id ipsum. Donec convallis, velit non scelerisque bibendum, diam nulla auctor nunc, vel dictum risus ipsum sit amet est. Praesent ut nibh sit amet nibh congue pulvinar. Suspendisse dictum porttitor tempor.</p>
+<p>Vestibulum dignissim erat vitae lectus auctor ac bibendum eros semper. Integer aliquet, leo non ornare faucibus, risus arcu tristique dolor, a aliquet massa mauris quis arcu. In porttitor, lectus ac semper egestas, ligula magna laoreet libero, eu commodo mauris odio id ante. In hac habitasse platea dictumst. In pretium erat diam, nec consequat eros. Praesent augue mi, consequat sed porttitor at, volutpat vitae eros. Sed pretium pharetra dapibus. Donec auctor interdum erat, lacinia molestie nibh commodo ut. Maecenas vestibulum vulputate felis, ut ullamcorper arcu faucibus in. Curabitur id arcu est. In semper mollis lorem at pellentesque. Sed lectus nisl, vestibulum id scelerisque eu, feugiat et tortor. Pellentesque porttitor facilisis ultricies.</p>
+<p id="myBookmark2">[&nbsp;<span class="intLink" onclick="showBookmark('#myBookmark1');">Go to bookmark #1</span> | <span class="intLink" onclick="showBookmark('#myBookmark1', false);">Go to bookmark #1 without using location.hash</span> | <span class="intLink" onclick="showBookmark('#myBookmark3');">Go to bookmark #3</span>&nbsp;]</p>
+<p>Phasellus tempus fringilla nunc, eget sagittis orci molestie vel. Nulla sollicitudin diam non quam iaculis ac porta justo venenatis. Quisque tellus urna, molestie vitae egestas sit amet, suscipit sed sem. Quisque nec lorem eu velit faucibus tristique ut ut dolor. Cras eu tortor ut libero placerat venenatis ut ut massa. Sed quis libero augue, et consequat libero. Morbi rutrum augue sed turpis elementum sed luctus nisl molestie. Aenean vitae purus risus, a semper nisl. Pellentesque malesuada, est id sagittis consequat, libero mauris tincidunt tellus, eu sagittis arcu purus rutrum eros. Quisque eget eleifend mi. Duis pharetra mi ac eros mattis lacinia rutrum ipsum varius.</p>
+<p>Fusce cursus pulvinar aliquam. Duis justo enim, ornare vitae elementum sed, porta a quam. Aliquam eu enim eu libero mollis tempus. Morbi ornare aliquam posuere. Proin faucibus luctus libero, sed ultrices lorem sagittis et. Vestibulum malesuada, ante nec molestie vehicula, quam diam mollis ipsum, rhoncus posuere mauris lectus in eros. Nullam feugiat ultrices augue, ac sodales sem mollis in.</p>
+<p id="myBookmark3"><em>Here is the bookmark #3</em></p>
+<p>Proin vitae sem non lorem pellentesque molestie. Nam tempus massa et turpis placerat sit amet sollicitudin orci sodales. Pellentesque enim enim, sagittis a lobortis ut, tempus sed arcu. Aliquam augue turpis, varius vel bibendum ut, aliquam at diam. Nam lobortis, dui eu hendrerit pellentesque, sem neque porttitor erat, non dapibus velit lectus in metus. Vestibulum sit amet felis enim. In quis est vitae nunc malesuada consequat nec nec sapien. Suspendisse aliquam massa placerat dui lacinia luctus sed vitae risus. Fusce tempus, neque id ultrices volutpat, mi urna auctor arcu, viverra semper libero sem vel enim. Mauris dictum, elit non placerat malesuada, libero elit euismod nibh, nec posuere massa arcu eu risus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer urna velit, dapibus eget varius feugiat, pellentesque sit amet ligula. Maecenas nulla nisl, facilisis eu egestas scelerisque, mollis eget metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi sed congue mi.</p>
+<p>Fusce metus velit, pharetra at vestibulum nec, facilisis porttitor mi. Curabitur ligula sapien, fermentum vel porttitor id, rutrum sit amet magna. Sed sit amet sollicitudin turpis. Aenean luctus rhoncus dolor, et pulvinar ante egestas et. Donec ac massa orci, quis dapibus augue. Vivamus consectetur auctor pellentesque. Praesent vestibulum tincidunt ante sed consectetur. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce purus metus, imperdiet vitae iaculis convallis, bibendum vitae turpis.</p>
+<p>Fusce aliquet molestie dolor, in ornare dui sodales nec. In molestie sollicitudin felis a porta. Mauris nec orci sit amet orci blandit tristique congue nec nunc. Praesent et tellus sollicitudin mauris accumsan fringilla. Morbi sodales, justo eu sollicitudin lacinia, lectus sapien ullamcorper eros, quis molestie urna elit bibendum risus. Proin eget tincidunt quam. Nam luctus commodo mauris, eu posuere nunc luctus non. Nulla facilisi. Vivamus eget leo rhoncus quam accumsan fringilla. Aliquam sit amet lorem est. Nullam vel tellus nibh, id imperdiet orci. Integer egestas leo eu turpis blandit scelerisque.</p>
+<p>Etiam in blandit tellus. Integer sed varius quam. Vestibulum dapibus mi gravida arcu viverra blandit. Praesent tristique augue id sem adipiscing pellentesque. Sed sollicitudin, leo sed interdum elementum, nisi ante condimentum leo, eget ornare libero diam semper quam. Vivamus augue urna, porta eget ultrices et, dapibus ut ligula. Ut laoreet consequat faucibus. Praesent at lectus ut lectus malesuada mollis. Nam interdum adipiscing eros, nec sodales mi porta nec. Proin et quam vitae sem interdum aliquet. Proin vel odio at lacus vehicula aliquet.</p>
+<p>Etiam placerat dui ut sem ornare vel vestibulum augue mattis. Sed semper malesuada mi, eu bibendum lacus lobortis nec. Etiam fringilla elementum risus, eget consequat urna laoreet nec. Etiam mollis quam non sem convallis vel consectetur lectus ullamcorper. Aenean mattis lacus quis ligula mattis eget vestibulum diam hendrerit. In non placerat mauris. Praesent faucibus nunc quis eros sagittis viverra. In hac habitasse platea dictumst. Suspendisse eget nisl erat, ac molestie massa. Praesent mollis vestibulum tincidunt. Fusce suscipit laoreet malesuada. Aliquam erat volutpat. Aliquam dictum elementum rhoncus. Praesent in est massa, pulvinar sodales nunc. Pellentesque gravida euismod mi ac convallis.</p>
+<p>Mauris vel odio vel nulla facilisis lacinia. Aliquam ultrices est at leo blandit tincidunt. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse porttitor adipiscing facilisis. Duis cursus quam iaculis augue interdum porttitor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis vulputate magna ac metus pretium condimentum. In tempus, est eget vestibulum blandit, velit massa dignissim nisl, ut scelerisque lorem neque vel velit. Maecenas fermentum commodo viverra. Curabitur a nibh non velit aliquam cursus. Integer semper condimentum tortor a pellentesque. Pellentesque semper, nisl id porttitor vehicula, sem dui feugiat lacus, vitae consequat augue urna vel odio.</p>
+<p>Vestibulum id neque nec turpis iaculis pulvinar et a massa. Vestibulum sed nibh vitae arcu eleifend egestas. Mauris fermentum ultrices blandit. Suspendisse vitae lorem libero. Aenean et pellentesque tellus. Morbi quis neque orci, eu dignissim dui. Fusce sollicitudin mauris ac arcu vestibulum imperdiet. Proin ultricies nisl sit amet enim imperdiet eu ornare dui tempus. Maecenas lobortis nisi a tortor vestibulum vel eleifend tellus vestibulum. Donec metus sapien, hendrerit a fermentum id, dictum quis libero.</p>
+<p>Pellentesque a lorem nulla, in tempor justo. Duis odio nisl, dignissim sed consequat sit amet, hendrerit ac neque. Nunc ac augue nec massa tempor rhoncus. Nam feugiat, tellus a varius euismod, justo nisl faucibus velit, ut vulputate justo massa eu nibh. Sed bibendum urna quis magna facilisis in accumsan dolor malesuada. Morbi sit amet nunc risus, in faucibus sem. Nullam sollicitudin magna sed sem mollis id commodo libero condimentum. Duis eu massa et lacus semper molestie ut adipiscing sem.</p>
+<p>Sed id nulla mi, eget suscipit eros. Aliquam tempus molestie rutrum. In quis varius elit. Nullam dignissim neque nec velit vulputate porttitor. Mauris ac ligula sit amet elit fermentum rhoncus. In tellus urna, pulvinar quis condimentum ut, porta nec justo. In hac habitasse platea dictumst. Proin volutpat elit id quam molestie ac commodo lacus sagittis. Quisque placerat, augue tempor placerat pulvinar, nisi nisi venenatis urna, eget convallis eros velit quis magna. Suspendisse volutpat iaculis quam, ut tristique lacus luctus quis.</p>
+<p>Nullam commodo suscipit lacus non aliquet. Phasellus ac nisl lorem, sed facilisis ligula. Nam cursus lobortis placerat. Sed dui nisi, elementum eu sodales ac, placerat sit amet mauris. Pellentesque dapibus tellus ut ipsum aliquam eu auctor dui vehicula. Quisque ultrices laoreet erat, at ultrices tortor sodales non. Sed venenatis luctus magna, ultricies ultricies nunc fringilla eget. Praesent scelerisque urna vitae nibh tristique varius consequat neque luctus. Integer ornare, erat a porta tempus, velit justo fermentum elit, a fermentum metus nisi eu ipsum. Vivamus eget augue vel dui viverra adipiscing congue ut massa. Praesent vitae eros erat, pulvinar laoreet magna. Maecenas vestibulum mollis nunc in posuere. Pellentesque sit amet metus a turpis lobortis tempor eu vel tortor. Cras sodales eleifend interdum.</p>
+</body>
+</html>
+
+
+ Note: The function showNode is also an example of the use of the for cycle without a statement section. In this case a semicolon is always put immediately after the declaration of the cycle.
+

…the same thing but with a dynamic page scroll:

+
var showBookmark = (function () {
+  var  _useHash, _scrollX, _scrollY, _nodeX, _nodeY, _itFrame, _scrollId = -1, _bookMark,
+       /*
+       * nDuration: the duration in milliseconds of each frame
+       * nFrames: number of frames for each scroll
+       */
+       nDuration = 200, nFrames = 10;
+
+  function _next () {
+    if (_itFrame > nFrames) { clearInterval(_scrollId); _scrollId = -1; return; }
+    _isBot = true;
+    document.documentElement.scrollTop = Math.round(_scrollY + (_nodeY - _scrollY) * _itFrame / nFrames);
+    document.documentElement.scrollLeft = Math.round(_scrollX + (_nodeX - _scrollX) * _itFrame / nFrames);
+    if (_useHash && _itFrame === nFrames) { location.hash = _bookMark; }
+    _itFrame++;
+  }
+
+  function _chkOwner () {
+    if (_isBot) { _isBot = false; return; }
+    if (_scrollId > -1) { clearInterval(_scrollId); _scrollId = -1; }
+  }
+
+  if (window.addEventListener) { window.addEventListener("scroll", _chkOwner, false); }
+  else if (window.attachEvent) { window.attachEvent("onscroll", _chkOwner); }
+
+  return function (sBookmark, bUseHash) {
+    _scrollY = document.documentElement.scrollTop;
+    _scrollX = document.documentElement.scrollLeft;
+    _bookMark = sBookmark;
+    _useHash = arguments.length === 1 || bUseHash;
+    for (
+      var nLeft = 0, nTop = 0, oNode = document.querySelector(sBookmark);
+      oNode;
+      nLeft += oNode.offsetLeft, nTop += oNode.offsetTop, oNode = oNode.offsetParent
+    );
+    _nodeX = nLeft, _nodeY = nTop, _itFrame = 1;
+    if (_scrollId === -1) { _scrollId = setInterval(_next, Math.round(nDuration / nFrames)); }
+  };
+})();
+
+

See also

+

Manipulating the browser history

+

Browser compatibility

+

{{ CompatibilityTable() }}

+
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+

Specification

+

HTML Specification: window . location

+

{{ languages( { "fr": "fr/DOM/window.location", "ja": "ja/DOM/window.location" } ) }}

diff --git a/files/zh-tw/web/api/window/navigator/index.html b/files/zh-tw/web/api/window/navigator/index.html new file mode 100644 index 0000000000..f729c810a9 --- /dev/null +++ b/files/zh-tw/web/api/window/navigator/index.html @@ -0,0 +1,58 @@ +--- +title: Window.navigator +slug: Web/API/Window/navigator +translation_of: Web/API/Window/navigator +--- +
{{APIRef}}
+ +

The Window.navigator read-only property returns a reference to the {{domxref("Navigator")}} object, which can be queried for information about the application running the script.

+ +

語法

+ +
navigatorObject = window.navigator
+ +

範例

+ +

Example #1: Browser detect and return a string

+ +
var sBrowser, sUsrAg = navigator.userAgent;
+
+if(sUsrAg.indexOf("Chrome") > -1) {
+    sBrowser = "Google Chrome";
+} else if (sUsrAg.indexOf("Safari") > -1) {
+    sBrowser = "Apple Safari";
+} else if (sUsrAg.indexOf("Opera") > -1) {
+    sBrowser = "Opera";
+} else if (sUsrAg.indexOf("Firefox") > -1) {
+    sBrowser = "Mozilla Firefox";
+} else if (sUsrAg.indexOf("MSIE") > -1) {
+    sBrowser = "Microsoft Internet Explorer";
+}
+
+alert("You are using: " + sBrowser);
+ +

Example #2: Browser detect and return an index

+ +
function getBrowserId () {
+
+    var
+        aKeys = ["MSIE", "Firefox", "Safari", "Chrome", "Opera"],
+        sUsrAg = navigator.userAgent, nIdx = aKeys.length - 1;
+
+    for (nIdx; nIdx > -1 && sUsrAg.indexOf(aKeys[nIdx]) === -1; nIdx--);
+
+    return nIdx
+
+}
+
+console.log(getBrowserId());
+ +

規範

+ + + +

參見

diff --git a/files/zh-tw/web/api/window/opener/index.html b/files/zh-tw/web/api/window/opener/index.html new file mode 100644 index 0000000000..e7ddb3e8c1 --- /dev/null +++ b/files/zh-tw/web/api/window/opener/index.html @@ -0,0 +1,30 @@ +--- +title: Window.opener +slug: Web/API/Window/opener +translation_of: Web/API/Window/opener +--- +
{{APIRef}}
+ +

概要

+ +

回傳一個開啟目前視窗(window)之視窗的參考(reference)。

+ +

語法

+ +
objRef = window.opener;
+
+ +

範例

+ +
if (window.opener != indexWin) {
+  referToTop(window.opener);
+}
+
+ +

備註

+ +

當一個視窗是由另一個視窗所開啟(使用 {{domxref("Window.open")}} 或一個帶有 target 屬性設定的連結),被開啟的這個視窗會於 window.opener 保留開啟它的第一個視窗之參考。假如目前的視窗沒有開啟它的視窗,則會回傳 NULL。

+ +

Windows Phone 瀏覽器不支援 window.opener(測試版本為 Microsoft Edge 25.10586.36.0)。若 window.opener 為不同的安全區域(security zone),則 IE 也不支援此屬性。

+ +

某些瀏覽器中,在發起連結的標籤中加入 rel="noopener" 屬性,可以阻止設定 window.opener 視窗參考。

diff --git a/files/zh-tw/web/api/window/orientationchange_event/index.html b/files/zh-tw/web/api/window/orientationchange_event/index.html new file mode 100644 index 0000000000..fe5264163c --- /dev/null +++ b/files/zh-tw/web/api/window/orientationchange_event/index.html @@ -0,0 +1,69 @@ +--- +title: 'Window: orientationchange event' +slug: Web/API/Window/orientationchange_event +tags: + - Sensors +translation_of: Web/API/Window/orientationchange_event +--- +
{{APIRef}}
+ +

orientationchange 事件在設備方向改變時被觸發。

+ + + + + + + + + + + + + + + + + + + + +
冒泡No
可取消No
介面{{domxref("Event")}}
事件處理器onorientationchange
+ +

範例

+ +

可於 addEventListener 方法中使用 abort 事件:

+ +
window.addEventListener("orientationchange", function() {
+  console.log("the orientation of the device is now " + screen.orientation.angle);
+});
+
+ +

或使用 onorientationchange 事件處理器屬性:

+ +
window.onorientationchange = function() {
+  console.log("the orientation of the device is now " + screen.orientation.angle);
+};
+ +

規範

+ + + + + + + + + + + + +
SpecificationStatus
{{SpecName('Compat', '#event-orientationchange', 'orientationchange')}}{{Spec2('Compat')}}
+ +

瀏覽器相容性

+ + + +

{{Compat("api.Window.orientationchange_event")}}

diff --git a/files/zh-tw/web/api/window/print/index.html b/files/zh-tw/web/api/window/print/index.html new file mode 100644 index 0000000000..4e2a543cf5 --- /dev/null +++ b/files/zh-tw/web/api/window/print/index.html @@ -0,0 +1,46 @@ +--- +title: Window.print() +slug: Web/API/Window/print +translation_of: Web/API/Window/print +--- +

{{ ApiRef() }}

+ +

摘要

+ +

打開列印視窗來列印當前的文件。

+ +

語法

+ +
window.print()
+
+ +

注釋

+ +

Starting with Chrome {{CompatChrome(46.0)}} this method is blocked inside an {{htmlelement("iframe")}} unless its sandbox attribute has the value allow-modals.

+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', 'timers-and-user-prompts.html#printing', 'print()')}}{{Spec2('HTML WHATWG')}} 
+ +

參見

+ + + +

{{ languages( { "ja": "ja/DOM/window.print", "it": "it/DOM/window.print" , "zh-cn": "zh-cn/DOM/window.print" } ) }}

diff --git a/files/zh-tw/web/api/window/requestidlecallback/index.html b/files/zh-tw/web/api/window/requestidlecallback/index.html new file mode 100644 index 0000000000..743e7b2a39 --- /dev/null +++ b/files/zh-tw/web/api/window/requestidlecallback/index.html @@ -0,0 +1,119 @@ +--- +title: window.requestIdleCallback() +slug: Web/API/Window/requestIdleCallback +translation_of: Web/API/Window/requestIdleCallback +--- +
{{APIRef("HTML DOM")}}{{SeeCompatTable}}
+ +

The window.requestIdleCallback() method queues a function to be called during a browser's idle periods. This enables developers to perform background and low priority work on the main event loop, without impacting latency-critical events such as animation and input response. Functions are generally called in first-in-first-out order; however, callbacks which have a timeout specified may be called out-of-order if necessary in order to run them before the timeout elapses.

+ +
+

You can call requestIdleCallback() within an idle callback function to schedule another callback to take place no sooner than the next pass through the event loop.

+
+ +

Syntax

+ +
var handle = window.requestIdleCallback(callback[, options])
+ +

Return value

+ +

An ID which can be used to cancel the callback by passing it into the {{domxref("window.cancelIdleCallback()")}} method.

+ +

Parameters

+ +
+
callback
+
A reference to a function that should be called in the near future, when the event loop is idle. The callback function is passed a {{domxref("IdleDeadline")}} object describing the amount of time available and whether or not the callback has been run because the timeout period expired.
+
options {{optional_inline}}
+
Contains optional configuration parameters. Currently only one property is defined: +
    +
  • timeout: If timeout is specified and has a positive value, and the callback has not already been called by the time timeout milliseconds have passed, the timeout will be called during the next idle period, even if doing so risks causing a negative performance impact.
  • +
+
+
+ +

Example

+ +

See our complete example in the article Cooperative Scheduling of Background Tasks API.

+ +

Specifications

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Background Tasks')}}{{Spec2('Background Tasks')}}Initial definition.
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome(47)}}{{CompatGeckoDesktop(53)}} [1]{{CompatNo}}{{CompatOpera(34)}}{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroid WebviewChrome for AndroidFirefox Mobile (Gecko)Firefox OSIE MobileOpera MobileSafari Mobile
Basic support{{CompatChrome(47)}}{{CompatChrome(47)}}{{CompatGeckoMobile(53)}} [1]{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] requestIdleCallback() is implemented in Firefox 53 but is disabled by default; to enable it, set the preference dom.requestIdleCallback.enabled to true. It is enabled by default starting in Firefox 55.

+ +

See also

+ + diff --git a/files/zh-tw/web/api/window/sessionstorage/index.html b/files/zh-tw/web/api/window/sessionstorage/index.html new file mode 100644 index 0000000000..696367e872 --- /dev/null +++ b/files/zh-tw/web/api/window/sessionstorage/index.html @@ -0,0 +1,94 @@ +--- +title: Window.sessionStorage +slug: Web/API/Window/sessionStorage +tags: + - API + - Property + - Storage + - WindowSessionStorage + - localStorage +translation_of: Web/API/Window/sessionStorage +--- +

{{APIRef()}}

+ +

sessionStorage 屬性能讓開發人員訪問當前 origin 的 {{DOMxRef("Storage")}} 物件。sessionStorage 跟 {{DOMxRef("Window.localStorage", "localStorage")}} 很相似:唯一不同的地方是存放在 localStorage 的資料並沒有過期的時效;而存放在 sessionStorage 的資料則會在頁面 session 結束時清空。只要該頁面頁面(頁籤)沒被關閉或者有還原(restore)該頁面,資料就會保存。開啟新頁籤或視窗會產生一個新的sessionStorage,跟Session與Cookies的做法不大一樣。 + +

+ +

另應該注意:不論資料放在 sessionStorage 還是 localStorage,都被限制在該網站的規範內,其他網站無法存取

+ +

語法

+ +
// 將資料存到sessionStorage
+sessionStorage.setItem('key', 'value');
+
+// 從sessionStorage取得之前存的資料
+var data = sessionStorage.getItem('key');
+
+// 從sessionStorage移除之前存的資料
+sessionStorage.removeItem('key');
+
+// 從sessionStorage移除之前存的所有資料
+sessionStorage.clear();
+
+ +

回傳值

+ +

一個 {{DOMxRef("Storage")}} 物件.

+ +

範例

+ +

下面簡短的程式碼,訪問了當前域名下的 session {{DOMxRef("Storage")}} 物件,並使用 {{DOMxRef("Storage.setItem()")}} 添加了資料單元。

+ +
sessionStorage.setItem('myCat', 'Tom');
+ +

以下提供的範例為將文字輸入元件的內容自動保存,如果瀏覽器不小心重新整理,在頁面恢復後,會自動將內容還原,不會造成尚未送出的資料被清空。

+ +
// 取得我們要保留內容的text field元件
+var field = document.getElementById("field");
+
+// 檢查是否有之前的autosave的內容
+// 這段程式碼會在瀏覽器進入該頁面時被執行
+if (sessionStorage.getItem("autosave")) {
+  // 還原先前的內容到指定的text field
+  field.value = sessionStorage.getItem("autosave");
+}
+
+// 註冊事件監聽text field內容的變化
+field.addEventListener("change", function() {
+  // 並儲存變化後的內容至sessionStorage的物件裡
+  sessionStorage.setItem("autosave", field.value);
+});
+ +
+

備註: 完整的範例可參考這篇文章: Using the Web Storage API

+
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態註解
{{SpecName('HTML WHATWG', 'webstorage.html#dom-sessionstorage', 'sessionStorage')}}{{Spec2('HTML WHATWG')}} 
+ +

瀏覽器相容性

+ +

{{Compat("api.Window.sessionStorage")}}

+ + +

相關內容

+ + diff --git a/files/zh-tw/web/api/window/sidebar/adding_search_engines_from_web_pages/index.html b/files/zh-tw/web/api/window/sidebar/adding_search_engines_from_web_pages/index.html new file mode 100644 index 0000000000..020f1be65e --- /dev/null +++ b/files/zh-tw/web/api/window/sidebar/adding_search_engines_from_web_pages/index.html @@ -0,0 +1,35 @@ +--- +title: 自網頁添加搜尋引擎 +slug: Web/API/Window/sidebar/Adding_search_engines_from_Web_pages +tags: + - 搜尋模組 +translation_of: Web/OpenSearch +--- +

Firefox 可以用 JavaScript 安裝搜尋引擎模組,且支援 OpenSearch 及 Sherlock 兩種模組格式。 +

+
註: 自 Firefox 2 起,偏好的模組格式為 OpenSearch。
+

當 JavaScript 程式碼要安裝新的搜尋模組時,Firefox 會詢問使用者是否允許安裝。 +

+

安裝 OpenSearch 模組

+

要安裝 OpenSearch 模組,必須使用 window.external.AddSearchProvider() DOM 方法。此方法的語法為: +

+
window.external.AddSearchProvider(搜尋模組 URL);
+
+

其中 搜尋模組 URL 為搜尋引擎模組之 XML 檔的絕對連結 URL。 +

+
注意: OpenSearch 自 Firefox 2 起的版本才支援。
+

安裝 Sherlock 模組

+

要安裝 Sherlock 模組,必須叫用 window.sidebar.addSearchEngine() 方法,語法為: +

+
window.sidebar.addSearchEngine(搜尋模組 URL, 圖示 URL, 建議名稱, 建議分類);
+
+ +

Sherlock 的相關資訊可參考 http://developer.apple.com/macosx/sherlock/ +

+
+
+{{ languages( { "ca": "ca/Addici\u00f3_de_motors_de_cerca_a_les_p\u00e0gines_web", "en": "en/Adding_search_engines_from_web_pages", "es": "es/A\u00f1adir_motores_de_b\u00fasqueda_desde_p\u00e1ginas_web", "fr": "fr/Ajout_de_moteurs_de_recherche_depuis_des_pages_Web", "it": "it/Installare_plugin_di_ricerca_dalle_pagine_web", "ja": "ja/Adding_search_engines_from_web_pages", "pl": "pl/Dodawanie_wyszukiwarek_z_poziomu_stron_WWW" } ) }} diff --git a/files/zh-tw/web/api/window/sidebar/index.html b/files/zh-tw/web/api/window/sidebar/index.html new file mode 100644 index 0000000000..280b5dcce3 --- /dev/null +++ b/files/zh-tw/web/api/window/sidebar/index.html @@ -0,0 +1,56 @@ +--- +title: Window.sidebar +slug: Web/API/Window/sidebar +tags: + - DOM + - NeedsTranslation + - Non-standard + - Property + - Reference + - TopicStub + - Window +translation_of: Web/API/Window/sidebar +--- +
{{APIRef}} {{Non-standard_header}}
+ +

Returns a sidebar object, which contains several methods for registering add-ons with the browser.

+ +

Notes

+ +

The sidebar object returned has the following methods:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription (SeaMonkey)Description (Firefox)
addPanel(title, contentURL, "")Adds a sidebar panel.Obsolete since Firefox 23 (only present in SeaMonkey).
+ End users can use the "load this bookmark in the sidebar" option instead. Also see Creating a Firefox sidebar.
addPersistentPanel(title, contentURL, "")Adds a sidebar panel, which is able to work in the background.
AddSearchProvider(descriptionURL)Installs a search provider (OpenSearch). Adding OpenSearch search engines contains more details. Added in Firefox 2.
addSearchEngine(engineURL, iconURL, suggestedTitle, suggestedCategory) {{Obsolete_inline(44)}}Installs a search engine (Sherlock). Adding Sherlock search engines contains more details.
IsSearchProviderInstalled(descriptionURL)Indicates if a specific search provider (OpenSearch) is installed.
+ +

Specification

+ +

Mozilla-specific. Not part of any standard.

diff --git a/files/zh-tw/web/api/windowbase64/index.html b/files/zh-tw/web/api/windowbase64/index.html new file mode 100644 index 0000000000..804f10ab1a --- /dev/null +++ b/files/zh-tw/web/api/windowbase64/index.html @@ -0,0 +1,113 @@ +--- +title: WindowBase64 +slug: Web/API/WindowBase64 +translation_of: Web/API/WindowOrWorkerGlobalScope +--- +

{{APIRef("HTML DOM")}}

+ +

The WindowBase64 helper contains utility methods to convert data to and from base64, a binary-to-text encoding scheme. For example it is used in data URIs.

+ +

There is no object of this type, though the context object, either the {{domxref("Window")}} for regular browsing scope, or the {{domxref("WorkerGlobalScope")}}  for workers, implements it.

+ +

屬性

+ +

This helper neither defines nor inherits any properties.

+ +

方法

+ +

This helper does not inherit any methods.

+ +
+
{{domxref("WindowBase64.atob()")}}
+
Decodes a string of data which has been encoded using base-64 encoding.
+
{{domxref("WindowBase64.btoa()")}}
+
Creates a base-64 encoded ASCII string from a string of binary data.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#windowbase64', 'WindowBase64')}}{{Spec2('HTML WHATWG')}}No change since the latest snapshot, {{SpecName("HTML5.1")}}.
{{SpecName('HTML5.1', '#windowbase64', 'WindowBase64')}}{{Spec2('HTML5.1')}}Snapshot of {{SpecName("HTML WHATWG")}}. No change.
{{SpecName("HTML5 W3C", "#windowbase64", "WindowBase64")}}{{Spec2('HTML5 W3C')}}Snapshot of {{SpecName("HTML WHATWG")}}. Creation of WindowBase64 (properties where on the target before it).
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureFirefox (Gecko)ChromeInternet ExplorerOperaSafari
Basic support{{CompatGeckoDesktop(1)}} [1]{{CompatVersionUnknown}}10.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureFirefox Mobile (Gecko)AndroidIE MobileOpera MobileSafari Mobile
Basic support{{CompatGeckoMobile(1)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

[1]  atob() is also available to XPCOM components implemented in JavaScript, even though {{domxref("Window")}} is not the global object in components.

+ +

參見

+ + diff --git a/files/zh-tw/web/api/windoweventhandlers/index.html b/files/zh-tw/web/api/windoweventhandlers/index.html new file mode 100644 index 0000000000..d3d29ddb63 --- /dev/null +++ b/files/zh-tw/web/api/windoweventhandlers/index.html @@ -0,0 +1,182 @@ +--- +title: WindowEventHandlers +slug: Web/API/WindowEventHandlers +translation_of: Web/API/WindowEventHandlers +--- +
{{APIRef("HTML DOM")}}
+ +

WindowEventHandlers mixin describes the event handlers common to several interfaces like {{domxref("Window")}}, or {{domxref("HTMLBodyElement")}} and  {{domxref("HTMLFrameSetElement")}}. Each of these interfaces can implement additional specific event handlers.

+ +

WindowEventHandlers is a not an interface and no object of this type can be created.

+ +

屬性

+ +

The events properties, of the form onXYZ, are defined on the {{domxref("WindowEventHandlers")}}, and implemented by {{domxref("Window")}}, and {{domxref("WorkerGlobalScope")}} for Web Workers.

+ +
+
{{domxref("WindowEventHandlers.onafterprint")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("afterprint")}} event is raised.
+
{{domxref("WindowEventHandlers.onbeforeprint")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("beforeprint")}} event is raised.
+
{{domxref("WindowEventHandlers.onbeforeunload")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("beforeunload")}} event is raised.
+
{{domxref("WindowEventHandlers.onhashchange")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("hashchange")}} event is raised.
+
{{domxref("WindowEventHandlers.onlanguagechange")}} {{experimental_inline}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("languagechange")}} event is raised.
+
{{domxref("WindowEventHandlers.onmessage")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("message")}} event is raised.
+
{{domxref("WindowEventHandlers.onoffline")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("offline")}} event is raised.
+
{{domxref("WindowEventHandlers.ononline")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("online")}} event is raised.
+
{{domxref("WindowEventHandlers.onpagehide")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pagehide")}} event is raised.
+
{{domxref("WindowEventHandlers.onpageshow")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("pageshow")}} event is raised.
+
{{domxref("WindowEventHandlers.onpopstate")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("popstate")}} event is raised.
+
{{domxref("WindowEventHandlers.onstorage")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("storage")}} event is raised.
+
{{domxref("WindowEventHandlers.onunhandledrejection")}} {{experimental_inline}}
+
An event handler for unhandled {{jsxref("Promise")}} rejection events.
+
{{domxref("WindowEventHandlers.onunload")}}
+
Is an {{domxref("EventHandler")}} representing the code to be called when the {{event("unload")}} event is raised.
+
+ +

方法

+ +

This interface defines no method.

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#windoweventhandlers', 'GlobalEventHandlers')}}{{Spec2('HTML WHATWG')}}No change since the latest snapshot, {{SpecName("HTML5.1")}}.
{{SpecName('HTML5.1', '#windoweventhandlers', 'GlobalEventHandlers')}}{{Spec2('HTML5.1')}}Snapshot of {{SpecName("HTML WHATWG")}}. Added onlanguage since the {{SpecName("HTML5 W3C")}} snapshot.
{{SpecName("HTML5 W3C", "#windoweventhandlers", "GlobalEventHandlers")}}{{Spec2('HTML5 W3C')}}Snapshot of {{SpecName("HTML WHATWG")}}. Creation of WindowEventHandlers (properties where on the target before it).
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox (Gecko)ChromeInternet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onhashchange{{CompatGeckoDesktop(1.9.2)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onlanguage{{experimental_inline}}{{CompatGeckoDesktop(32)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onstorage{{CompatGeckoDesktop(45)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox Mobile (Gecko)AndroidIE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onhashchange{{CompatGeckoMobile(1.9.2)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onlanguage{{experimental_inline}}{{CompatGeckoMobile(32)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
onstorage{{CompatGeckoDesktop(45)}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/windoweventhandlers/onbeforeunload/index.html b/files/zh-tw/web/api/windoweventhandlers/onbeforeunload/index.html new file mode 100644 index 0000000000..66ba170df5 --- /dev/null +++ b/files/zh-tw/web/api/windoweventhandlers/onbeforeunload/index.html @@ -0,0 +1,153 @@ +--- +title: WindowEventHandlers.onbeforeunload +slug: Web/API/WindowEventHandlers/onbeforeunload +translation_of: Web/API/WindowEventHandlers/onbeforeunload +--- +
+
{{APIRef("HTML DOM")}}
+
+ +
 
+ +

WindowEventHandlers.onbeforeunload 事件处理函数包含的代码将在 {{event("beforeunload")}} 发出时被执行。当 window 准备释放它的资源时,该事件被触发。此时 document 仍然可见,且事件是仍然可被取消的。

+ +
+

注意: 为了避免不必要的弹出窗口,除非页面已经有过互动,否则可能不会显示beforeunload创建的询问窗口。对于特定的浏览器列表,请参阅浏览器兼容性部分。

+
+ +

语法

+ +
window.onbeforeunload = funcRef
+ + + +

示例

+ +
window.onbeforeunload = function(e) {
+  var dialogText = 'Dialog text here';
+  e.returnValue = dialogText;
+  return dialogText;
+};
+
+ +

注意

+ +

当事件返回了一个非空值时,将需要用户确认是否 unload 页面。在大部分浏览器中,事件的返回值将在对话框中显示。在 Firefox 4 及以后,返回值将不会显示给用户。作为替代,Firefox将会显示"This page is asking you to confirm that you want to leave - data you have entered may not be saved." 请查看{{bug("588292")}}.

+ +

Since 25 May 2011, the HTML5 specification states that calls to {{domxref("window.alert()")}}, {{domxref("window.confirm()")}}, and {{domxref("window.prompt()")}} methods may be ignored during this event. See the HTML5 specification for more details.

+ +

Note also that various mobile browsers ignore the result of the event (that is, they do not ask the user for confirmation). Firefox has a hidden preference in about:config to do the same. In essence this means the user always confirms that the document may be unloaded.

+ +

You can and should handle this event through {{domxref("EventTarget.addEventListener","window.addEventListener()")}} and the {{event("beforeunload")}} event. More documentation is available there.

+ +

Specifications

+ +

The event was originally introduced by Microsoft in Internet Explorer 4 and standardized in the HTML5 specification.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#windoweventhandlers', 'GlobalEventHandlers')}}{{Spec2('HTML WHATWG')}} 
{{SpecName('HTML5.1', '#windoweventhandlers', 'GlobalEventHandlers')}}{{Spec2('HTML5.1')}} 
{{SpecName("HTML5 W3C", "#windoweventhandlers", "GlobalEventHandlers")}}{{Spec2('HTML5 W3C')}} 
+ +

Browser compatibility

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome(1.0)}}14123
Custom text support removed{{CompatChrome(51.0)}}{{CompatGeckoMobile("44.0")}} 389.1
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewFirefox Mobile (Gecko)IE PhoneOpera MobileSafari MobileChrome for Android
Basic support{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}(no) defect{{CompatVersionUnknown}}
Custom text support removed{{CompatUnknown}}{{CompatChrome(51.0)}}{{CompatGeckoMobile("44.0")}}   {{CompatChrome(51.0)}}
+
+ +

See also

+ + diff --git a/files/zh-tw/web/api/windoworworkerglobalscope/btoa/index.html b/files/zh-tw/web/api/windoworworkerglobalscope/btoa/index.html new file mode 100644 index 0000000000..93d63b6010 --- /dev/null +++ b/files/zh-tw/web/api/windoworworkerglobalscope/btoa/index.html @@ -0,0 +1,136 @@ +--- +title: WindowOrWorkerGlobalScope.btoa() +slug: Web/API/WindowOrWorkerGlobalScope/btoa +translation_of: Web/API/WindowOrWorkerGlobalScope/btoa +--- +

{{APIRef("HTML DOM")}}

+ +

The WindowOrWorkerGlobalScope.btoa() method creates a {{glossary("Base64")}}-encoded ASCII string from a binary string (i.e., a {{jsxref("String")}} object in which each character in the string is treated as a byte of binary data).

+ +

You can use this method to encode data which may otherwise cause communication problems, transmit it, then use the {{domxref("WindowOrWorkerGlobalScope.atob", "atob()")}} method to decode the data again. For example, you can encode control characters such as ASCII values 0 through 31.

+ +

Syntax

+ +
var encodedData = scope.btoa(stringToEncode);
+ +

Parameters

+ +
+
stringToEncode
+
The binary string to encode.
+
+ +

Return value

+ +

An ASCII string containing the Base64 representation of stringToEncode.

+ +

Exceptions

+ +
+
InvalidCharacterError
+
The string contained a character that did not fit in a single byte. See "Unicode strings" below for more detail.
+
+ +

Example

+ +
const encodedData = window.btoa('Hello, world'); // encode a string
+const decodedData = window.atob(encodedData); // decode the string
+
+ +

Unicode strings

+ +

The btoa() function takes a JavaScript string as a parameter. In JavaScript strings are represented using the UTF-16 character encoding: in this encoding, strings are represented as a sequence of 16-bit (2 byte) units. Every ASCII character fits into the first byte of one of these units, but many other characters don't.

+ +

Base64, by design, expects binary data as its input. In terms of JavaScript strings, this means strings in which each character occupies only one byte. So if you pass a string into btoa() containing characters that occupy more than one byte, you will get an error, because this is not considered binary data:

+ +
const ok = "a";
+console.log(ok.codePointAt(0).toString(16)); //   61: occupies < 1 byte
+
+const notOK = "✓"
+console.log(notOK.codePointAt(0).toString(16)); // 2713: occupies > 1 byte
+
+console.log(btoa(ok));    // YQ==
+console.log(btoa(notOK)); // error
+ +

If you need to encode Unicode text as ASCII using btoa(), one option is to convert the string such that each 16-bit unit occupies only one byte. For example:

+ +
// convert a Unicode string to a string in which
+// each 16-bit unit occupies only one byte
+function toBinary(string) {
+  const codeUnits = new Uint16Array(string.length);
+  for (let i = 0; i < codeUnits.length; i++) {
+    codeUnits[i] = string.charCodeAt(i);
+  }
+  return String.fromCharCode(...new Uint8Array(codeUnits.buffer));
+}
+
+// a string that contains characters occupying > 1 byte
+const myString = "☸☹☺☻☼☾☿";
+
+const converted = toBinary(myString);
+const encoded = btoa(converted);
+console.log(encoded);                 // OCY5JjomOyY8Jj4mPyY=
+
+ +

If you do this, of course you'll have to reverse the conversion on the decoded string:

+ +
function fromBinary(binary) {
+  const bytes = new Uint8Array(binary.length);
+  for (let i = 0; i < bytes.length; i++) {
+    bytes[i] = binary.charCodeAt(i);
+  }
+  return String.fromCharCode(...new Uint16Array(bytes.buffer));
+}
+
+const decoded = atob(encoded);
+const original = fromBinary(decoded);
+console.log(original);                // ☸☹☺☻☼☾☿
+
+ +

Polyfill

+ +

You can use a polyfill from https://github.com/MaxArt2501/base64-js/blob/master/base64.js for browsers that don't support it.

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#dom-btoa', 'WindowOrWorkerGlobalScope.btoa()')}}{{Spec2('HTML WHATWG')}}Method moved to the WindowOrWorkerGlobalScope mixin in the latest spec.
{{SpecName('HTML5.1', '#dom-windowbase64-btoa', 'WindowBase64.btoa()')}}{{Spec2('HTML5.1')}}Snapshot of {{SpecName("HTML WHATWG")}}. No change.
{{SpecName("HTML5 W3C", "#dom-windowbase64-btoa", "WindowBase64.btoa()")}}{{Spec2('HTML5 W3C')}}Snapshot of {{SpecName("HTML WHATWG")}}. Creation of WindowBase64 (properties where on the target before it).
+ +

Browser compatibility

+ +
+ + +

{{Compat("api.WindowOrWorkerGlobalScope.btoa")}}

+
+ +

See also

+ + diff --git a/files/zh-tw/web/api/windoworworkerglobalscope/index.html b/files/zh-tw/web/api/windoworworkerglobalscope/index.html new file mode 100644 index 0000000000..9fb46d21d5 --- /dev/null +++ b/files/zh-tw/web/api/windoworworkerglobalscope/index.html @@ -0,0 +1,98 @@ +--- +title: WindowOrWorkerGlobalScope +slug: Web/API/WindowOrWorkerGlobalScope +tags: + - API + - HTML DOM + - NeedsTranslation + - Service Worker + - TopicStub + - Window + - WindowOrWorkerGlobalScope + - Worker + - WorkerGlobalScope +translation_of: Web/API/WindowOrWorkerGlobalScope +--- +
{{ApiRef()}}
+ +

The WindowOrWorkerGlobalScope mixin describes several features common to the {{domxref("Window")}} and {{domxref("WorkerGlobalScope")}} interfaces. Each of these interfaces can, of course, add more features in addition to the ones listed below.

+ +
+

Note: WindowOrWorkerGlobalScope is a mixin and not an interface; you can't actually create an object of type WindowOrWorkerGlobalScope.

+
+ +

Properties

+ +

These properties are defined on the {{domxref("WindowOrWorkerGlobalScope")}} mixin, and implemented by {{domxref("Window")}} and {{domxref("WorkerGlobalScope")}}.

+ +
+
+
{{domxref("WindowOrWorkerGlobalScope.caches")}} {{readOnlyinline}}
+
Returns the {{domxref("CacheStorage")}} object associated with the current context. This object enables functionality such as storing assets for offline use, and generating custom responses to requests.
+
{{domxref("WindowOrWorkerGlobalScope.crossOriginIsolated")}} {{readOnlyinline}}
+
Returns a boolean value that indicates whether a {{jsxref("SharedArrayBuffer")}} can be sent via a {{domxref("Window.postMessage()")}} call.
+
{{domxref("WindowOrWorkerGlobalScope.indexedDB")}} {{readonlyInline}}
+
Provides a mechanism for applications to asynchronously access capabilities of indexed databases; returns an {{domxref("IDBFactory")}} object.
+
{{domxref("WindowOrWorkerGlobalScope.isSecureContext")}} {{readOnlyinline}}
+
Returns a boolean indicating whether the current context is secure (true) or not (false).
+
{{domxref("WindowOrWorkerGlobalScope.origin")}} {{readOnlyinline}}
+
Returns the origin of the global scope, serialized as a string.
+
+
+ +

Methods

+ +

These methods are defined on the {{domxref("WindowOrWorkerGlobalScope")}} mixin, and implemented by {{domxref("Window")}} and {{domxref("WorkerGlobalScope")}}.

+ +
+
{{domxref("WindowOrWorkerGlobalScope.atob()")}}
+
Decodes a string of data which has been encoded using base-64 encoding.
+
{{domxref("WindowOrWorkerGlobalScope.btoa()")}}
+
Creates a base-64 encoded ASCII string from a string of binary data.
+
{{domxref("WindowOrWorkerGlobalScope.clearInterval()")}}
+
Cancels the repeated execution set using {{domxref("WindowOrWorkerGlobalScope.setInterval()")}}.
+
{{domxref("WindowOrWorkerGlobalScope.clearTimeout()")}}
+
Cancels the delayed execution set using {{domxref("WindowOrWorkerGlobalScope.setTimeout()")}}.
+
{{domxref("WindowOrWorkerGlobalScope.createImageBitmap()")}}
+
Accepts a variety of different image sources, and returns a {{domxref("Promise")}} which resolves to an {{domxref("ImageBitmap")}}. Optionally the source is cropped to the rectangle of pixels originating at (sx, sy) with width sw, and height sh.
+
{{domxref("WindowOrWorkerGlobalScope.fetch()")}}
+
Starts the process of fetching a resource from the network.
+
{{domxref("WindowOrWorkerGlobalScope.queueMicrotask()")}}
+
Enqueues a microtask—a short function to be executed after execution of the JavaScript code completes and control isn't being returned to a JavaScript caller, but before handling callbacks and other tasks. This lets your code run without interfering with other, possibly higher priority, code, but before the browser runtime regains control, potentially depending upon the work you need to complete.
+
{{domxref("WindowOrWorkerGlobalScope.setInterval()")}}
+
Schedules a function to execute every time a given number of milliseconds elapses.
+
{{domxref("WindowOrWorkerGlobalScope.setTimeout()")}}
+
Schedules a function to execute in a given amount of time.
+
+ +

Specifications

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("HTML WHATWG",'webappapis.html#windoworworkerglobalscope-mixin', 'WindowOrWorkerGlobalScope mixin')}}{{Spec2('HTML WHATWG')}}This is where the main mixin is defined.
+ +

Browser compatibility

+ + + +

{{Compat("api.WindowOrWorkerGlobalScope")}}

+ +

See also

+ + diff --git a/files/zh-tw/web/api/windoworworkerglobalscope/setinterval/index.html b/files/zh-tw/web/api/windoworworkerglobalscope/setinterval/index.html new file mode 100644 index 0000000000..7685a8f754 --- /dev/null +++ b/files/zh-tw/web/api/windoworworkerglobalscope/setinterval/index.html @@ -0,0 +1,627 @@ +--- +title: WindowOrWorkerGlobalScope.setInterval() +slug: Web/API/WindowOrWorkerGlobalScope/setInterval +translation_of: Web/API/WindowOrWorkerGlobalScope/setInterval +--- +
{{APIRef("HTML DOM")}}
+ +

setInterval() 函式, {{domxref("Window")}} 與 {{domxref("Worker")}} 介面皆提供此一函式, 此函式作用為重複地執行一個函式呼叫或一個程式碼片斷, 每一次執行間隔固定的延遲時間. 此函式呼叫時將傳回一個間隔代碼(Interval ID)用以識別該間隔程序, 因此後續您可以呼叫 {{domxref("WindowOrWorkerGlobalScope.clearInterval", "clearInterval()")}} 函式移除該間隔程序. 此函式為由 {{domxref("WindowOrWorkerGlobalScope")}} 混合定義.

+ +

Syntax

+ +
var intervalID = scope.setInterval(func, [delay, arg1, arg2, ...]);
+var intervalID = scope.setInterval(code, [delay]);
+
+ +

Parameters

+ +
+
func
+
A {{jsxref("function")}} to be executed every delay milliseconds. The function is not passed any arguments, and no return value is expected.
+
code
+
An optional syntax allows you to include a string instead of a function, which is compiled and executed every delay milliseconds. This syntax is not recommended for the same reasons that make using {{jsxref("eval", "eval()")}} a security risk.
+
delay{{optional_inline}}
+
The time, in milliseconds (thousandths of a second), the timer should delay in between executions of the specified function or code. See {{anch("Delay restrictions")}} below for details on the permitted range of delay values.
+
arg1, ..., argN {{optional_inline}}
+
Additional arguments which are passed through to the function specified by func once the timer expires.
+
+ +
+

Note: Passing additional arguments to setInterval() in the first syntax does not work in Internet Explorer 9 and earlier. If you want to enable this functionality on that browser, you must use a polyfill (see the Callback arguments section).

+
+ +

Return value

+ +

The returned intervalID is a numeric, non-zero value which identifies the timer created by the call to setInterval(); this value can be passed to {{domxref("WindowOrWorkerGlobalScope.clearInterval()")}} to cancel the timeout.

+ +

It may be helpful to be aware that setInterval() and {{domxref("WindowOrWorkerGlobalScope.setTimeout", "setTimeout()")}} share the same pool of IDs, and that clearInterval() and {{domxref("WindowOrWorkerGlobalScope.clearTimeout", "clearTimeout()")}} can technically be used interchangeably. For clarity, however, you should try to always match them to avoid confusion when maintaining your code.

+ +
Note: The delay argument is converted to a signed 32-bit integer. This effectively limits delay to 2147483647 ms, since it's specified as a signed integer in the IDL.
+ +

Examples

+ +

Example 1: Basic syntax

+ +

The following example demonstrates setInterval()'s basic syntax.

+ +
var intervalID = window.setInterval(myCallback, 500, 'Parameter 1', 'Parameter 2');
+
+function myCallback(a, b)
+{
+ // Your code here
+ // Parameters are purely optional.
+ console.log(a);
+ console.log(b);
+}
+
+ +

Example 2: Alternating two colors

+ +

The following example calls the flashtext() function once a second until the Stop button is pressed.

+ +
<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="UTF-8" />
+  <title>setInterval/clearInterval example</title>
+
+  <script>
+    var nIntervId;
+
+    function changeColor() {
+      nIntervId = setInterval(flashText, 1000);
+    }
+
+    function flashText() {
+      var oElem = document.getElementById('my_box');
+      oElem.style.color = oElem.style.color == 'red' ? 'blue' : 'red';
+      // oElem.style.color == 'red' ? 'blue' : 'red' is a ternary operator.
+    }
+
+    function stopTextColor() {
+      clearInterval(nIntervId);
+    }
+  </script>
+</head>
+
+<body onload="changeColor();">
+  <div id="my_box">
+    <p>Hello World</p>
+  </div>
+
+  <button onclick="stopTextColor();">Stop</button>
+</body>
+</html>
+
+ +

Example 3: Typewriter simulation

+ +

The following example simulates typewriter by first clearing and then slowly typing content into the NodeList that matches a specified group of selectors.

+ +
<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8" />
+<title>JavaScript Typewriter - MDN Example</title>
+<script>
+  function Typewriter (sSelector, nRate) {
+
+  function clean () {
+    clearInterval(nIntervId);
+    bTyping = false;
+    bStart = true;
+    oCurrent = null;
+    aSheets.length = nIdx = 0;
+  }
+
+  function scroll (oSheet, nPos, bEraseAndStop) {
+    if (!oSheet.hasOwnProperty('parts') || aMap.length < nPos) { return true; }
+
+    var oRel, bExit = false;
+
+    if (aMap.length === nPos) { aMap.push(0); }
+
+    while (aMap[nPos] < oSheet.parts.length) {
+      oRel = oSheet.parts[aMap[nPos]];
+
+      scroll(oRel, nPos + 1, bEraseAndStop) ? aMap[nPos]++ : bExit = true;
+
+      if (bEraseAndStop && (oRel.ref.nodeType - 1 | 1) === 3 && oRel.ref.nodeValue) {
+        bExit = true;
+        oCurrent = oRel.ref;
+        sPart = oCurrent.nodeValue;
+        oCurrent.nodeValue = '';
+      }
+
+      oSheet.ref.appendChild(oRel.ref);
+      if (bExit) { return false; }
+    }
+
+    aMap.length--;
+    return true;
+  }
+
+  function typewrite () {
+    if (sPart.length === 0 && scroll(aSheets[nIdx], 0, true) && nIdx++ === aSheets.length - 1) { clean(); return; }
+
+    oCurrent.nodeValue += sPart.charAt(0);
+    sPart = sPart.slice(1);
+  }
+
+  function Sheet (oNode) {
+    this.ref = oNode;
+    if (!oNode.hasChildNodes()) { return; }
+    this.parts = Array.prototype.slice.call(oNode.childNodes);
+
+    for (var nChild = 0; nChild < this.parts.length; nChild++) {
+      oNode.removeChild(this.parts[nChild]);
+      this.parts[nChild] = new Sheet(this.parts[nChild]);
+    }
+  }
+
+  var
+    nIntervId, oCurrent = null, bTyping = false, bStart = true,
+    nIdx = 0, sPart = "", aSheets = [], aMap = [];
+
+  this.rate = nRate || 100;
+
+  this.play = function () {
+    if (bTyping) { return; }
+    if (bStart) {
+      var aItems = document.querySelectorAll(sSelector);
+
+      if (aItems.length === 0) { return; }
+      for (var nItem = 0; nItem < aItems.length; nItem++) {
+        aSheets.push(new Sheet(aItems[nItem]));
+        /* Uncomment the following line if you have previously hidden your elements via CSS: */
+        // aItems[nItem].style.visibility = "visible";
+      }
+
+      bStart = false;
+    }
+
+    nIntervId = setInterval(typewrite, this.rate);
+    bTyping = true;
+  };
+
+  this.pause = function () {
+    clearInterval(nIntervId);
+    bTyping = false;
+  };
+
+  this.terminate = function () {
+    oCurrent.nodeValue += sPart;
+    sPart = "";
+    for (nIdx; nIdx < aSheets.length; scroll(aSheets[nIdx++], 0, false));
+    clean();
+  };
+}
+
+/* usage: */
+var oTWExample1 = new Typewriter(/* elements: */ '#article, h1, #info, #copyleft', /* frame rate (optional): */ 15);
+
+/* default frame rate is 100: */
+var oTWExample2 = new Typewriter('#controls');
+
+/* you can also change the frame rate value modifying the "rate" property; for example: */
+// oTWExample2.rate = 150;
+
+onload = function () {
+  oTWExample1.play();
+  oTWExample2.play();
+};
+</script>
+<style type="text/css">
+span.intLink, a, a:visited {
+  cursor: pointer;
+  color: #000000;
+  text-decoration: underline;
+}
+
+#info {
+  width: 180px;
+  height: 150px;
+  float: right;
+  background-color: #eeeeff;
+  padding: 4px;
+  overflow: auto;
+  font-size: 12px;
+  margin: 4px;
+  border-radius: 5px;
+  /* visibility: hidden; */
+}
+</style>
+</head>
+
+<body>
+
+<p id="copyleft" style="font-style: italic; font-size: 12px; text-align: center;">CopyLeft 2012 by <a href="https://developer.mozilla.org/" target="_blank">Mozilla Developer Network</a></p>
+<p id="controls" style="text-align: center;">[&nbsp;<span class="intLink" onclick="oTWExample1.play();">Play</span> | <span class="intLink" onclick="oTWExample1.pause();">Pause</span> | <span class="intLink" onclick="oTWExample1.terminate();">Terminate</span>&nbsp;]</p>
+<div id="info">
+Vivamus blandit massa ut metus mattis in fringilla lectus imperdiet. Proin ac ante a felis ornare vehicula. Fusce pellentesque lacus vitae eros convallis ut mollis magna pellentesque. Pellentesque placerat enim at lacus ultricies vitae facilisis nisi fringilla. In tincidunt tincidunt tincidunt.
+</div>
+<h1>JavaScript Typewriter</h1>
+
+<div id="article">
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices dolor ac dolor imperdiet ullamcorper. Suspendisse quam libero, luctus auctor mollis sed, malesuada condimentum magna. Quisque in ante tellus, in placerat est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec a mi magna, quis mattis dolor. Etiam sit amet ligula quis urna auctor imperdiet nec faucibus ante. Mauris vel consectetur dolor. Nunc eget elit eget velit pulvinar fringilla consectetur aliquam purus. Curabitur convallis, justo posuere porta egestas, velit erat ornare tortor, non viverra justo diam eget arcu. Phasellus adipiscing fermentum nibh ac commodo. Nam turpis nunc, suscipit a hendrerit vitae, volutpat non ipsum.</p>
+<form>
+<p>Phasellus ac nisl lorem: <input type="text" /><br />
+<textarea style="width: 400px; height: 200px;">Nullam commodo suscipit lacus non aliquet. Phasellus ac nisl lorem, sed facilisis ligula. Nam cursus lobortis placerat. Sed dui nisi, elementum eu sodales ac, placerat sit amet mauris. Pellentesque dapibus tellus ut ipsum aliquam eu auctor dui vehicula. Quisque ultrices laoreet erat, at ultrices tortor sodales non. Sed venenatis luctus magna, ultricies ultricies nunc fringilla eget. Praesent scelerisque urna vitae nibh tristique varius consequat neque luctus. Integer ornare, erat a porta tempus, velit justo fermentum elit, a fermentum metus nisi eu ipsum. Vivamus eget augue vel dui viverra adipiscing congue ut massa. Praesent vitae eros erat, pulvinar laoreet magna. Maecenas vestibulum mollis nunc in posuere. Pellentesque sit amet metus a turpis lobortis tempor eu vel tortor. Cras sodales eleifend interdum.</textarea></p>
+<p><input type="submit" value="Send" />
+</form>
+<p>Duis lobortis sapien quis nisl luctus porttitor. In tempor semper libero, eu tincidunt dolor eleifend sit amet. Ut nec velit in dolor tincidunt rhoncus non non diam. Morbi auctor ornare orci, non euismod felis gravida nec. Curabitur elementum nisi a eros rutrum nec blandit diam placerat. Aenean tincidunt risus ut nisi consectetur cursus. Ut vitae quam elit. Donec dignissim est in quam tempor consequat. Aliquam aliquam diam non felis convallis suscipit. Nulla facilisi. Donec lacus risus, dignissim et fringilla et, egestas vel eros. Duis malesuada accumsan dui, at fringilla mauris bibStartum quis. Cras adipiscing ultricies fermentum. Praesent bibStartum condimentum feugiat.</p>
+<p>Nam faucibus, ligula eu fringilla pulvinar, lectus tellus iaculis nunc, vitae scelerisque metus leo non metus. Proin mattis lobortis lobortis. Quisque accumsan faucibus erat, vel varius tortor ultricies ac. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec libero nunc. Nullam tortor nunc, elementum a consectetur et, ultrices eu orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque a nisl eu sem vehicula egestas.</p>
+</div>
+</body>
+</html>
+ +

View this demo in action. See also: clearInterval().

+ +

Callback arguments

+ +

As previously discussed, Internet Explorer versions 9 and below do not support the passing of arguments to the callback function in either setTimeout() or setInterval(). The following IE-specific code demonstrates a method for overcoming this limitation.  To use, simply add the following code to the top of your script.

+ +
/*\
+|*|
+|*|  IE-specific polyfill that enables the passage of arbitrary arguments to the
+|*|  callback functions of javascript timers (HTML5 standard syntax).
+|*|
+|*|  https://developer.mozilla.org/en-US/docs/Web/API/window.setInterval
+|*|  https://developer.mozilla.org/User:fusionchess
+|*|
+|*|  Syntax:
+|*|  var timeoutID = window.setTimeout(func, delay[, arg1, arg2, ...]);
+|*|  var timeoutID = window.setTimeout(code, delay);
+|*|  var intervalID = window.setInterval(func, delay[, arg1, arg2, ...]);
+|*|  var intervalID = window.setInterval(code, delay);
+|*|
+\*/
+
+if (document.all && !window.setTimeout.isPolyfill) {
+  var __nativeST__ = window.setTimeout;
+  window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
+    var aArgs = Array.prototype.slice.call(arguments, 2);
+    return __nativeST__(vCallback instanceof Function ? function () {
+      vCallback.apply(null, aArgs);
+    } : vCallback, nDelay);
+  };
+  window.setTimeout.isPolyfill = true;
+}
+
+if (document.all && !window.setInterval.isPolyfill) {
+  var __nativeSI__ = window.setInterval;
+  window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
+    var aArgs = Array.prototype.slice.call(arguments, 2);
+    return __nativeSI__(vCallback instanceof Function ? function () {
+      vCallback.apply(null, aArgs);
+    } : vCallback, nDelay);
+  };
+  window.setInterval.isPolyfill = true;
+}
+
+ +

Another possibility is to use an anonymous function to call your callback, although this solution is a bit more expensive. Example:

+ +
var intervalID = setInterval(function() { myFunc('one', 'two', 'three'); }, 1000);
+ +

Another possibility is to use function's bind. Example:

+ +
var intervalID = setInterval(function(arg1) {}.bind(undefined, 10), 1000);
+ +

{{h3_gecko_minversion("Inactive tabs", "5.0")}}

+ +

Starting in Gecko 5.0 {{geckoRelease("5.0")}}, intervals are clamped to fire no more often than once per second in inactive tabs.

+ +

The "this" problem

+ +

When you pass a method to setInterval() or any other function, it is invoked with the wrong this value. This problem is explained in detail in the JavaScript reference.

+ +

Explanation

+ +

Code executed by setInterval() runs in a separate execution context than the function from which it was called. As a consequence, the this keyword for the called function is set to the window (or global) object, it is not the same as the this value for the function that called setTimeout. See the following example (which uses setTimeout() instead of setInterval() – the problem, in fact, is the same for both timers):

+ +
myArray = ['zero', 'one', 'two'];
+
+myArray.myMethod = function (sProperty) {
+    alert(arguments.length > 0 ? this[sProperty] : this);
+};
+
+myArray.myMethod(); // prints "zero,one,two"
+myArray.myMethod(1); // prints "one"
+setTimeout(myArray.myMethod, 1000); // prints "[object Window]" after 1 second
+setTimeout(myArray.myMethod, 1500, "1"); // prints "undefined" after 1,5 seconds
+// passing the 'this' object with .call won't work
+// because this will change the value of this inside setTimeout itself
+// while we want to change the value of this inside myArray.myMethod
+// in fact, it will be an error because setTimeout code expects this to be the window object:
+setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object"
+setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error
+
+ +

As you can see there are no ways to pass the this object to the callback function in the legacy JavaScript.

+ +

A possible solution

+ +

A possible way to solve the "this" problem is to replace the two native setTimeout() or setInterval() global functions with two non-native ones that enable their invocation through the Function.prototype.call method. The following example shows a possible replacement:

+ +
// Enable the passage of the 'this' object through the JavaScript timers
+
+var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval;
+
+window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
+  var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2);
+  return __nativeST__(vCallback instanceof Function ? function () {
+    vCallback.apply(oThis, aArgs);
+  } : vCallback, nDelay);
+};
+
+window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
+  var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2);
+  return __nativeSI__(vCallback instanceof Function ? function () {
+    vCallback.apply(oThis, aArgs);
+  } : vCallback, nDelay);
+};
+ +
These two replacements also enable the HTML5 standard passage of arbitrary arguments to the callback functions of timers in IE. So they can be used as non-standard-compliant polyfills also. See the callback arguments paragraph for a standard-compliant polyfill.
+ +

New feature test:

+ +
myArray = ['zero', 'one', 'two'];
+
+myArray.myMethod = function (sProperty) {
+    alert(arguments.length > 0 ? this[sProperty] : this);
+};
+
+setTimeout(alert, 1500, 'Hello world!'); // the standard use of setTimeout and setInterval is preserved, but...
+setTimeout.call(myArray, myArray.myMethod, 2000); // prints "zero,one,two" after 2 seconds
+setTimeout.call(myArray, myArray.myMethod, 2500, 2); // prints "two" after 2,5 seconds
+
+ +

Another, more complex, solution for the this problem is the following framework.

+ +
JavaScript 1.8.5 introduces the Function.prototype.bind() method, which lets you specify the value that should be used as this for all calls to a given function. This lets you easily bypass problems where it's unclear what this will be, depending on the context from which your function was called. Also, ES2015 supports arrow functions, with lexical this allowing us to write setInterval( () => this.myMethod) if we're inside myArray method.
+ +

MiniDaemon - A framework for managing timers

+ +

In pages requiring many timers, it can often be difficult to keep track of all of the running timer events. One approach to solving this problem is to store information about the state of a timer in an object. Following is a minimal example of such an abstraction. The constructor architecture explicitly avoids the use of closures. It also offers an alternative way to pass the this object to the callback function (see The "this" problem for details). The following code is also available on GitHub.

+ +
For a more complex but still modular version of it (Daemon) see JavaScript Daemons Management. This more complex version is nothing but a big and scalable collection of methods for the Daemon constructor. However, the Daemon constructor itself is nothing but a clone of MiniDaemon with an added support for init and onstart functions declarable during the instantiation of the daemon. So the MiniDaemon framework remains the recommended way for simple animations, because Daemon without its collection of methods is essentially a clone of it.
+ +

minidaemon.js

+ +
/*\
+|*|
+|*|  :: MiniDaemon ::
+|*|
+|*|  Revision #2 - September 26, 2014
+|*|
+|*|  https://developer.mozilla.org/en-US/docs/Web/API/window.setInterval
+|*|  https://developer.mozilla.org/User:fusionchess
+|*|  https://github.com/madmurphy/minidaemon.js
+|*|
+|*|  This framework is released under the GNU Lesser General Public License, version 3 or later.
+|*|  http://www.gnu.org/licenses/lgpl-3.0.html
+|*|
+\*/
+
+function MiniDaemon (oOwner, fTask, nRate, nLen) {
+  if (!(this && this instanceof MiniDaemon)) { return; }
+  if (arguments.length < 2) { throw new TypeError('MiniDaemon - not enough arguments'); }
+  if (oOwner) { this.owner = oOwner; }
+  this.task = fTask;
+  if (isFinite(nRate) && nRate > 0) { this.rate = Math.floor(nRate); }
+  if (nLen > 0) { this.length = Math.floor(nLen); }
+}
+
+MiniDaemon.prototype.owner = null;
+MiniDaemon.prototype.task = null;
+MiniDaemon.prototype.rate = 100;
+MiniDaemon.prototype.length = Infinity;
+
+  /* These properties should be read-only */
+
+MiniDaemon.prototype.SESSION = -1;
+MiniDaemon.prototype.INDEX = 0;
+MiniDaemon.prototype.PAUSED = true;
+MiniDaemon.prototype.BACKW = true;
+
+  /* Global methods */
+
+MiniDaemon.forceCall = function (oDmn) {
+  oDmn.INDEX += oDmn.BACKW ? -1 : 1;
+  if (oDmn.task.call(oDmn.owner, oDmn.INDEX, oDmn.length, oDmn.BACKW) === false || oDmn.isAtEnd()) { oDmn.pause(); return false; }
+  return true;
+};
+
+  /* Instances methods */
+
+MiniDaemon.prototype.isAtEnd = function () {
+  return this.BACKW ? isFinite(this.length) && this.INDEX < 1 : this.INDEX + 1 > this.length;
+};
+
+MiniDaemon.prototype.synchronize = function () {
+  if (this.PAUSED) { return; }
+  clearInterval(this.SESSION);
+  this.SESSION = setInterval(MiniDaemon.forceCall, this.rate, this);
+};
+
+MiniDaemon.prototype.pause = function () {
+  clearInterval(this.SESSION);
+  this.PAUSED = true;
+};
+
+MiniDaemon.prototype.start = function (bReverse) {
+  var bBackw = Boolean(bReverse);
+  if (this.BACKW === bBackw && (this.isAtEnd() || !this.PAUSED)) { return; }
+  this.BACKW = bBackw;
+  this.PAUSED = false;
+  this.synchronize();
+};
+
+ +
MiniDaemon passes arguments to the callback function. If you want to work on it with browsers that natively do not support this feature, use one of the methods proposed above.
+ +

Syntax

+ +

var myDaemon = new MiniDaemon(thisObject, callback[, rate[, length]]);

+ +

Description

+ +

Returns a JavaScript Object containing all information needed by an animation (like the this object, the callback function, the length, the frame-rate).

+ +

Arguments

+ +
+
thisObject
+
The this object on which the callback function is called. It can be an object or null.
+
callback
+
The function that is repeatedly invoked . It is called with three arguments: index (the iterative index of each invocation), length (the number of total invocations assigned to the daemon - finite or Infinity) and backwards (a boolean expressing whether the index is increasing or decreasing). It is something like callback.call(thisObject, index, length, backwards). If the callback function returns a false value the daemon is paused.
+
rate (optional)
+
The time lapse (in number of milliseconds) between each invocation. The default value is 100.
+
length (optional)
+
The total number of invocations. It can be a positive integer or Infinity. The default value is Infinity.
+
+ +

MiniDaemon instances properties

+ +
+
myDaemon.owner
+
The this object on which is executed the daemon (read/write). It can be an object or null.
+
myDaemon.task
+
The function that is repeatedly invoked (read/write). It is called with three arguments: index (the iterative index of each invocation), length (the number of total invocations assigned to the daemon - finite or Infinity) and backwards (a boolean expressing whether the index is decreasing or not) – see above. If the myDaemon.task function returns a false value the daemon is paused.
+
myDaemon.rate
+
The time lapse (in number of milliseconds) between each invocation (read/write).
+
myDaemon.length
+
The total number of invocations. It can be a positive integer or Infinity (read/write).
+
+ +

MiniDaemon instances methods

+ +
+
myDaemon.isAtEnd()
+
Returns a boolean expressing whether the daemon is at the start/end position or not.
+
myDaemon.synchronize()
+
Synchronize the timer of a started daemon with the time of its invocation.
+
myDaemon.pause()
+
Pauses the daemon.
+
myDaemon.start([reverse])
+
Starts the daemon forward (index of each invocation increasing) or backwards (index decreasing).
+
+ +

MiniDaemon global object methods

+ +
+
MiniDaemon.forceCall(minidaemon)
+
Forces a single callback to the minidaemon.task function regardless of the fact that the end has been reached or not. In any case the internal INDEX property is increased/decreased (depending on the actual direction of the process).
+
+ +

Example usage

+ +

Your HTML page:

+ +
<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="UTF-8" />
+  <title>MiniDaemin Example - MDN</title>
+  <script type="text/javascript" src="minidaemon.js"></script>
+  <style type="text/css">
+    #sample_div {
+      visibility: hidden;
+    }
+  </style>
+</head>
+
+<body>
+  <p>
+    <input type="button" onclick="fadeInOut.start(false /* optional */);" value="fade in" />
+    <input type="button" onclick="fadeInOut.start(true);" value="fade out">
+    <input type="button" onclick="fadeInOut.pause();" value="pause" />
+  </p>
+
+  <div id="sample_div">Some text here</div>
+
+  <script type="text/javascript">
+    function opacity (nIndex, nLength, bBackwards) {
+      this.style.opacity = nIndex / nLength;
+      if (bBackwards ? nIndex === 0 : nIndex === 1) {
+        this.style.visibility = bBackwards ? 'hidden' : 'visible';
+      }
+    }
+
+    var fadeInOut = new MiniDaemon(document.getElementById('sample_div'), opacity, 300, 8);
+  </script>
+</body>
+</html>
+ +

View this example in action

+ +

Usage notes

+ +

The setInterval() function is commonly used to set a delay for functions that are executed again and again, such as animations. You can cancel the interval using {{domxref("WindowOrWorkerGlobalScope.clearInterval()")}}.

+ +

If you wish to have your function called once after the specified delay, use {{domxref("WindowOrWorkerGlobalScope.setTimeout()")}}.

+ +

Delay restrictions

+ +

It's possible for intervals to be nested; that is, the callback for setInterval() can in turn call setInterval() to start another interval running, even though the first one is still going. To mitigate the potential impact this can have on performance, once intervals are nested beyond five levels deep, the browser will automatically enforce a 4 ms minimum value for the interval. Attempts to specify a value less than 4 ms in deeply-nested calls to setInterval() will be pinned to 4 ms.

+ +

Browsers may enforce even more stringent minimum values for the interval under some circumstances, although these should not be common. Note also that the actual amount of time that elapses between calls to the callback may be longer than the given delay; see {{SectionOnPage("/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout", "Reasons for delays longer than specified")}} for examples.

+ +

Ensure that execution duration is shorter than interval frequency

+ +

If there is a possibility that your logic could take longer to execute than the interval time, it is recommended that you recursively call a named function using {{domxref("WindowOrWorkerGlobalScope.setTimeout", "setTimeout()")}}. For example, if using setInterval() to poll a remote server every 5 seconds, network latency, an unresponsive server, and a host of other issues could prevent the request from completing in its allotted time. As such, you may find yourself with queued up XHR requests that won't necessarily return in order.

+ +

In these cases, a recursive setTimeout() pattern is preferred:

+ +
(function loop(){
+   setTimeout(function() {
+      // Your logic here
+
+      loop();
+  }, delay);
+})();
+
+ +

In the above snippet, a named function loop() is declared and is immediately executed. loop() is recursively called inside setTimeout() after the logic has completed executing. While this pattern does not guarantee execution on a fixed interval, it does guarantee that the previous interval has completed before recursing.

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', 'webappapis.html#dom-setinterval', 'WindowOrWorkerGlobalScope.setInterval()')}}{{Spec2("HTML WHATWG")}}Method moved to the WindowOrWorkerGlobalScope mixin in the latest spec.
{{SpecName("HTML WHATWG", "webappapis.html#dom-setinterval", "WindowTimers.setInterval()")}}{{Spec2("HTML WHATWG")}}Initial definition (DOM Level 0)
+ +

Browser compatibility

+ +
+ + +

{{Compat("api.WindowOrWorkerGlobalScope.setInterval")}}

+
+ +

See also

+ + diff --git a/files/zh-tw/web/api/windowtimers/index.html b/files/zh-tw/web/api/windowtimers/index.html new file mode 100644 index 0000000000..0b26118e10 --- /dev/null +++ b/files/zh-tw/web/api/windowtimers/index.html @@ -0,0 +1,114 @@ +--- +title: WindowTimers +slug: Web/API/WindowTimers +translation_of: Web/API/WindowOrWorkerGlobalScope +--- +
{{APIRef("HTML DOM")}}
+ +

WindowTimers is a mixin used to provide utility methods which set and clear timers. No objects of this type exist; instead, its methods are available on {{domxref("Window")}} for the standard browsing scope, or on {{domxref("WorkerGlobalScope")}} for workers.

+ +

屬性

+ +

WindowTimers 介面沒有繼承也沒有定義任何屬性。

+ +

方法

+ +

除以下自身方法外,WindowTimers 介面提沒有任何繼承方法。

+ +
+
{{domxref("WindowTimers.clearInterval()")}}
+
Cancels the repeated execution set using {{domxref("WindowTimers.setInterval()")}}.
+
{{domxref("WindowTimers.clearTimeout()")}}
+
Cancels the delayed execution set using {{domxref("WindowTimers.setTimeout()")}}.
+
{{domxref("WindowTimers.setInterval()")}}
+
Schedules a function to execute every time a given number of milliseconds elapses.
+
{{domxref("WindowTimers.setTimeout()")}}
+
Schedules a function to execute in a given amount of time.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', '#windowtimers', 'WindowTimers')}}{{Spec2('HTML WHATWG')}}No change since the latest snapshot, {{SpecName("HTML5.1")}}.
{{SpecName('HTML5.1', '#windowtimers', 'WindowTimers')}}{{Spec2('HTML5.1')}}Snapshot of {{SpecName("HTML WHATWG")}}. No change.
{{SpecName("HTML5 W3C", "#windowtimers", "WindowTimers")}}{{Spec2('HTML5 W3C')}}Snapshot of {{SpecName("HTML WHATWG")}}. Creation of WindowBase64 (properties where on the target before it).
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureFirefox (Gecko)ChromeInternet ExplorerOperaSafari
Basic support{{CompatGeckoDesktop(1)}}1.04.04.01.0
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureFirefox Mobile (Gecko)AndroidIE MobileOpera MobileSafari Mobile
Basic support{{CompatGeckoMobile(1)}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

 

+ +

參見

+ + diff --git a/files/zh-tw/web/api/xmlhttprequest/index.html b/files/zh-tw/web/api/xmlhttprequest/index.html new file mode 100644 index 0000000000..3258579e62 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/index.html @@ -0,0 +1,177 @@ +--- +title: XMLHttpRequest +slug: Web/API/XMLHttpRequest +tags: + - AJAX + - Fixit + - HTTP + - MakeBrowserAgnostic + - NeedsCleanup + - NeedsMobileBrowserCompatibility + - NeedsTranslation + - TopicStub + - XMLHttpRequest +translation_of: Web/API/XMLHttpRequest +--- +
{{DefaultAPISidebar("XMLHttpRequest")}}
+ +

藉由 XMLHttpRequest(XHR)物件的方式來存取伺服器端的資料,可以讓你直接經由指定的 URL 擷取資料卻不用刷新整個網頁。這樣一來當想要更新網頁中的部分資料時,不再需要藉由刷新整個頁面的方法而中斷使用者的操作。在{{Glossary("AJAX")}}應用中 XMLHttpRequest 被大量的使用。

+ +

{{InheritanceDiagram(650, 150)}}

+ +

雖然 XMLHttpRequest 這個物件的命名包含了 XML 與 HTTP 等字眼,但實際上 XMLHttpRequest 可用來接收任何類型的資料,不限於 XML 類型而已。

+ +

如果在資料交換的時候,需要接收從伺服器端傳來的事件或訊息:可以考慮透過{{domxref("EventSource")}}介面使用server-sent 事件。對於和伺服器全雙工的資訊交換,WebSockets 可能是較佳的選擇。

+ +

建構式

+ +
+
{{domxref("XMLHttpRequest.XMLHttpRequest", "XMLHttpRequest()")}}
+
建構式用來初始化一個 XMLHttpRequest 物件。必須在其他任何所屬方法被呼叫之前被呼叫。
+
+ +

屬性

+ +

此介面也繼承了 {{domxref("XMLHttpRequestEventTarget")}} 及 {{domxref("EventTarget")}} 的屬性。

+ +
+
{{domxref("XMLHttpRequest.onreadystatechange")}}
+
一個 {{domxref("EventHandler")}}(事件處理器)函式,會於 readyState 屬性之狀態改變時被呼叫。
+
{{domxref("XMLHttpRequest.readyState")}} {{readonlyinline}}
+
回傳一個無符號短整數(unsigned short)代表請求之狀態。
+
{{domxref("XMLHttpRequest.response")}} {{readonlyinline}}
+
回傳的內容可能是 {{domxref("ArrayBuffer")}}、{{domxref("Blob")}}、{{domxref("Document")}}、JavaScript 物件或 {{domxref("DOMString")}}。完全根據 {{domxref("XMLHttpRequest.responseType")}} 的值決定回傳的內容為何種型態,資料為回應實體中的內容(response entity body)。
+
{{domxref("XMLHttpRequest.responseText")}} {{readonlyinline}}
+
回傳一個 {{domxref("DOMString")}},其內容為請求之回應的文字內容。如請求失敗或尚未發送,則為 null
+
{{domxref("XMLHttpRequest.responseType")}}
+
為一可列舉(enumerated)值,定義回應內容的資料類型(response type)。
+
{{domxref("XMLHttpRequest.responseURL")}} {{readonlyinline}}
+
回傳一個回應(response)的序列化 URL,如 URL 為 null 則回傳空字串。
+
{{domxref("XMLHttpRequest.responseXML")}} {{readonlyinline}}
+
回傳一個 {{domxref("Document")}},其內容為請求之回應內容所解析成的文件物件。如請求失敗或尚未發送,又或是無法解析成 XML、HTML,則為 null。Not available in workers.
+
{{domxref("XMLHttpRequest.status")}} {{readonlyinline}}
+
回傳一個無符號短整數(unsigned short)表示已發送請求之回應的狀態。
+
{{domxref("XMLHttpRequest.statusText")}} {{readonlyinline}}
+
回傳一個 {{domxref("DOMString")}} 表示 HTTP 伺服器回應之字串。和 {{domxref("XMLHTTPRequest.status")}} 不同的是,XMLHttpRequest.statusText 包含了回應的整個文字訊息(如 "200 OK")。
+
+ +
+

Note: The HTTP/2 specification (8.1.2.4 Response Pseudo-Header Fields), HTTP/2 does not define a way to carry the version or reason phrase that is included in an HTTP/1.1 status line.

+
+ +
+
{{domxref("XMLHttpRequest.timeout")}}
+
為一無符號長整數(unsigned long),代表一個請求在逾時而被自動中止前的可等待時間(毫秒)。
+
{{domxref("XMLHttpRequestEventTarget.ontimeout")}}
+
為一 {{domxref("EventHandler")}} 物件,會於請求逾時時被呼叫。{{gecko_minversion_inline("12.0")}}
+
{{domxref("XMLHttpRequest.upload")}} {{readonlyinline}}
+
為一 {{domxref("XMLHttpRequestUpload")}} 物件,代表上傳的進度。
+
{{domxref("XMLHttpRequest.withCredentials")}}
+
{{domxref("Boolean","布林值")}}。表示是否允許在跨站存取(cross-site Access-Control)之請求當中,發送如 cookies 或 authorization headers 等憑證資訊(credentials)。
+
+ +

非標準屬性

+ +
+
{{domxref("XMLHttpRequest.channel")}}{{ReadOnlyInline}}
+
是一個 {{Interface("nsIChannel")}}。當執行要求時,物件使用的頻道(Channel)。
+
{{domxref("XMLHttpRequest.mozAnon")}}{{ReadOnlyInline}}
+
為一個布林值。如果為真,請求就會以沒有cookie及authentication headers的方式送出。
+
{{domxref("XMLHttpRequest.mozSystem")}}{{ReadOnlyInline}}
+
這是一個布林值。If true, the same origin policy will not be enforced on the request.
+
{{domxref("XMLHttpRequest.mozBackgroundRequest")}}
+
這是一個布林值。指出該物件是否為一個背景型態的服務要求。
+
{{domxref("XMLHttpRequest.mozResponseArrayBuffer")}}{{gecko_minversion_inline("2.0")}} {{obsolete_inline("6")}} {{ReadOnlyInline}}
+
Is an ArrayBuffer. The response to the request, as a JavaScript typed array.
+
{{domxref("XMLHttpRequest.multipart")}}{{obsolete_inline("22")}}
+
This Gecko-only feature, a boolean, was removed in Firefox/Gecko 22. Please use Server-Sent Events, Web Sockets, or responseText from progress events instead.
+
+ +

事件處理器

+ +

所有瀏覽器都支援 XMLHttpRequest 物件實體的 onreadystatechange 屬性。

+ +

之後,各個瀏覽器實作了多種額外的事件處理器(如 onloadonerroronprogress 等)。請參考使用 XMLHttpRequest

+ +

除了以 on* 屬性來設定事件處理函式,更多現代覽瀏器(包括 Firefox)也支援使用標準的 addEventListener() API 註冊監聽 XMLHttpRequest 的事件。

+ +
+
+ +

方法

+ +
+
{{domxref("XMLHttpRequest.abort()")}}
+
中止已發出的請求。
+
{{domxref("XMLHttpRequest.getAllResponseHeaders()")}}
+
回傳所有的回應標頭(response headers),為一以斷行字元(CRLF)分行的字串,如未接收到回應則為 null
+
{{domxref("XMLHttpRequest.getResponseHeader()")}}
+
回傳指定標頭文字之字串,假如回應尚未被接收或是標頭不存在於回應中則為 null
+
{{domxref("XMLHttpRequest.open()")}}
+
初始化一個請求。此方法用於 JavaScript 中;若要在 native code 中初始化請求,請以 openRequest() 作為替代。
+
{{domxref("XMLHttpRequest.overrideMimeType()")}}
+
覆寫伺服器回傳的 MIME type。
+
{{domxref("XMLHttpRequest.send()")}}
+
發送請求。如果為非同步請求(預設值),此方法將在發出請求後便立即回傳(return)。
+
{{domxref("XMLHttpRequest.setRequestHeader()")}}
+
設定 HTTP 請求標頭(request header)值。setRequestHeader() 可被呼叫的時間點必須於 open() 之後、在 send() 之前。
+
+ +

非標準方法

+ +
+
{{domxref("XMLHttpRequest.init()")}}
+
使用 C++ 程式時,用來初始化這個物件。
+
+ +
注意: 請勿在 JavaScript 中呼叫這個方法。
+ +
+
{{domxref("XMLHttpRequest.openRequest()")}}
+
初始化請求。這方法是用於原生程式,若想在 JavaScript 中初始化一個請求,請使用 open() 這個方法來代替。請參照 open() 的相關文件。
+
{{domxref("XMLHttpRequest.sendAsBinary()")}}{{deprecated_inline()}}
+
另一種 send() 方法,用來送出二進位資料。
+
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('XMLHttpRequest')}}{{Spec2('XMLHttpRequest')}}Live standard, latest version
+ +

瀏覽器相容性

+ + + +
{{Compat("api.XMLHttpRequest")}}
+ +

參見

+ + diff --git a/files/zh-tw/web/api/xmlhttprequest/onreadystatechange/index.html b/files/zh-tw/web/api/xmlhttprequest/onreadystatechange/index.html new file mode 100644 index 0000000000..817daf0efa --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/onreadystatechange/index.html @@ -0,0 +1,113 @@ +--- +title: XMLHttpRequest.onreadystatechange +slug: Web/API/XMLHttpRequest/onreadystatechange +translation_of: Web/API/XMLHttpRequest/onreadystatechange +--- +
{{APIRef}}
+ +

An EventHandler that is called whenever the readyState attribute changes. The callback is called from the user interface thread. The XMLHttpRequest.onreadystatechange property contains the event handler to be called when the {{event("readystatechange")}} event is fired, that is every time the {{domxref("XMLHttpRequest.readyState", "readyState")}} property of the {{domxref("XMLHttpRequest")}} changes.

+ +
+

Warning: This should not be used with synchronous requests and must not be used from native code.

+
+ +

The readystatechange event will not be fired when an XMLHttpRequest request is cancelled with the abort() method.

+ +
+

UPDATE: it's firing in the latest version of browsers (Firefox 51.0.1, Opera 43.0.2442.991, Safari 10.0.3 (12602.4.8), Chrome 54.0.2840.71, Edge, IE11). Example here - just reaload page few times.

+
+ +

語法

+ +
XMLHttpRequest.onreadystatechange = callback;
+ +

+ + + +

範例

+ +
var xhr = new XMLHttpRequest(),
+    method = "GET",
+    url = "https://developer.mozilla.org/";
+
+xhr.open(method, url, true);
+xhr.onreadystatechange = function () {
+        if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
+            console.log(xhr.responseText);
+        }
+    };
+xhr.send();
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('XMLHttpRequest', '#handler-xhr-onreadystatechange')}}{{Spec2('XMLHttpRequest')}}WHATWG living standard
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatChrome(1)}}{{CompatGeckoDesktop(1.0)}}{{CompatIe(7)}}[1]{{CompatVersionUnknown}}{{CompatSafari(1.2)}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}1.0{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Internet Explorer version 5 and 6 supported ajax calls using ActiveXObject().

diff --git a/files/zh-tw/web/api/xmlhttprequest/readystate/index.html b/files/zh-tw/web/api/xmlhttprequest/readystate/index.html new file mode 100644 index 0000000000..3f7e909fe0 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/readystate/index.html @@ -0,0 +1,148 @@ +--- +title: XMLHttpRequest.readyState +slug: Web/API/XMLHttpRequest/readyState +translation_of: Web/API/XMLHttpRequest/readyState +--- +

{{APIRef('XMLHttpRequest')}}

+ +

XMLHttpRequest.readyState 屬性會回傳一個 XMLHttpRequest 客戶端物件目前的狀態。一個 XHR 客戶端可以為下列其中一種狀態:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
狀態說明
0UNSENT客戶端已被建立,但 open() 方法尚未被呼叫。
1OPENEDopen() 方法已被呼叫。
2HEADERS_RECEIVEDsend() 方法已被呼叫,而且可取得 header 與狀態。
3LOADING回應資料下載中,此時 responseText 會擁有部分資料。
4DONE完成下載操作。
+ +
+
UNSENT
+
XMLHttpRequest 客戶端物件已被建立,但 open() 方法尚未被呼叫。
+
OPENED
+
open() 方法已被呼叫。於此狀態時,可以使用 setRequestHeader() 方法設定請求標頭(request headers),並可呼叫 send() 方法來發送請求。
+
HEADERS_RECEIVED
+
send() 方法已被呼叫,並且已接收到回應標頭(response header)。
+
LOADING
+
正在接收回應內容(response's body)。如 responseType 屬性為 "text" 或空字串,則 responseText 屬性將會在載入的過程中擁有已載入部分之回應(response)內容中的文字。
+
DONE
+
請求操作已完成。這意味著資料傳輸可能已成功完成或是已失敗。
+
+ +
+

這些狀態名稱在 Internet Explorer 中略有不同。其中 UNSENT, OPENED, HEADERS_RECEIVED, LOADING 和 DONE 變成了 READYSTATE_UNINITIALIZED (0), READYSTATE_LOADING (1), READYSTATE_LOADED (2), READYSTATE_INTERACTIVE (3) 和READYSTATE_COMPLETE (4)。

+
+ +

範例

+ +
var xhr = new XMLHttpRequest();
+console.log('UNSENT', xhr.readyState); // readyState will be 0
+
+xhr.open('GET', '/api', true);
+console.log('OPENED', xhr.readyState); // readyState will be 1
+
+xhr.onprogress = function () {
+    console.log('LOADING', xhr.readyState); // readyState will be 3
+};
+
+xhr.onload = function () {
+    console.log('DONE', xhr.readyState); // readyState will be 4
+};
+
+xhr.send(null);
+
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('XMLHttpRequest', '#states')}}{{Spec2('XMLHttpRequest')}}WHATWG living standard
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
功能ChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
基本支援{{CompatChrome(1)}}{{CompatGeckoDesktop("1.0")}}[1]{{CompatIe(7)}}{{CompatVersionUnknown}}{{CompatSafari("1.2")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
功能AndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
基本支援{{CompatUnknown}}1.0{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
diff --git a/files/zh-tw/web/api/xmlhttprequest/setrequestheader/index.html b/files/zh-tw/web/api/xmlhttprequest/setrequestheader/index.html new file mode 100644 index 0000000000..a8219e7240 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/setrequestheader/index.html @@ -0,0 +1,66 @@ +--- +title: XMLHttpRequest.setRequestHeader() +slug: Web/API/XMLHttpRequest/setRequestHeader +translation_of: Web/API/XMLHttpRequest/setRequestHeader +--- +
{{APIRef('XMLHttpRequest')}}
+ +

{{domxref("XMLHttpRequest")}} 物件中的 setRequestHeader() 方法用來設定 HTTP 的表頭請求。當使用 setRequestHeader() 的時候,必須在 {{domxref("XMLHttpRequest.open", "open()")}} 之後呼叫,同時也必須在 {{domxref("XMLHttpRequest.send", "send()")}} 之前呼叫。如果這個方法被呼叫了許多次,且設定的表頭是一樣的,那所有設定的值會被合併成一個單一的表頭請求。

+ +

在第一次呼叫 setRequestHeader() 之後的每一次的呼叫,都會把給定的文字附加在已存在的表頭內容之後。

+ +

If no {{HTTPHeader("Accept")}} header has been set using this, an Accept header with the type "*/*" is sent with the request when {{domxref("XMLHttpRequest.send", "send()")}} is called.

+ +

基於安全的理由,有些表頭只有使用者代理器可以使用。這些表頭包含了: {{Glossary("Forbidden_header_name", "forbidden header names", 1)}}  和 {{Glossary("Forbidden_response_header_name", "forbidden response header names", 1)}}.

+ +
+

Note: For your custom fields, you may encounter a "not allowed by Access-Control-Allow-Headers in preflight response" exception when you send requests across domains. In this situation, you need to set up the {{HTTPHeader("Access-Control-Allow-Headers")}} in your response header at server side.

+
+ +

語法

+ +
XMLHttpRequest.setRequestHeader(header, value)
+
+ +

參數

+ +
+
header
+
想要設定所屬值的表頭名稱。
+
value
+
用來設定表頭本身的值。
+
+ +

回傳值

+ +

未定義

+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('XMLHttpRequest', '#the-setrequestheader()-method', 'setRequestHeader()')}}{{Spec2('XMLHttpRequest')}}WHATWG living standard
+ +

瀏覽器相容性

+ + + +

{{Compat("api.XMLHttpRequest.setRequestHeader")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/xmlhttprequest/status/index.html b/files/zh-tw/web/api/xmlhttprequest/status/index.html new file mode 100644 index 0000000000..c54ece9939 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/status/index.html @@ -0,0 +1,115 @@ +--- +title: XMLHttpRequest.status +slug: Web/API/XMLHttpRequest/status +translation_of: Web/API/XMLHttpRequest/status +--- +
{{APIRef('XMLHttpRequest')}}
+ +

XMLHttpRequest.status 屬性根據XMLHttpRequest的回應傳回數值化的狀況編碼。狀況編碼為一正短整數(unsigned short)。Before the request is complete, the value of status will be 0. It is worth noting that browsers report a status of 0 in case of XMLHttpRequest errors too.

+ +

The status codes returned are the standard HTTP status codes. For example, status 200 denotes a successful request. If the server response doesn't explicitly specify a status code, XMLHttpRequest.status will assume the default value of 200.

+ +

Example

+ +
var xhr = new XMLHttpRequest();
+console.log('UNSENT', xhr.status);
+
+xhr.open('GET', '/server', true);
+console.log('OPENED', xhr.status);
+
+xhr.onprogress = function () {
+  console.log('LOADING', xhr.status);
+};
+
+xhr.onload = function () {
+  console.log('DONE', xhr.status);
+};
+
+xhr.send(null);
+
+/**
+ * Outputs the following:
+ *
+ * UNSENT 0
+ * OPENED 0
+ * LOADING 200
+ * DONE 200
+ */
+
+ +

Specifications

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('XMLHttpRequest', '#the-status-attribute')}}{{Spec2('XMLHttpRequest')}}WHATWG living standard
+ +

Browser compatibility

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome(1)}}{{CompatGeckoDesktop("1.0")}}[1]{{CompatIe(7)}}[1]{{CompatVersionUnknown}}{{CompatSafari("1.2")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}1.0{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Internet Explorer versions 5 and 6 lacked the XMLHttpRequest object, but provided a way to make AJAX requests using ActiveXObject.

+ +

See also

+ + diff --git a/files/zh-tw/web/api/xmlhttprequest/synchronous_and_asynchronous_requests/index.html b/files/zh-tw/web/api/xmlhttprequest/synchronous_and_asynchronous_requests/index.html new file mode 100644 index 0000000000..e8a148b5a9 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/synchronous_and_asynchronous_requests/index.html @@ -0,0 +1,260 @@ +--- +title: Synchronous and asynchronous requests +slug: Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests +translation_of: Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests +--- +

XMLHttpRequest 支持同步和非同步請求,一般來說,建議使用非同步請求。

+ +

In short, synchronous requests block the execution of code which creates "freezing" on the screen and an unresponsive user experience. 

+ +

非同步請求

+ +

If you use XMLHttpRequest from an extension, you should use it asynchronously.  In this case, you receive a callback when the data has been received, which lets the browser continue to work as normal while your request is being handled.

+ +

範例: send a file to the console log

+ +

這是使用非同步XMLHttpRequest的基本方式

+ +
var xhr = new XMLHttpRequest();
+xhr.open("GET", "/bar/foo.txt", true);
+xhr.onload = function (e) {
+  if (xhr.readyState === 4) {
+    if (xhr.status === 200) {
+      console.log(xhr.responseText);
+    } else {
+      console.error(xhr.statusText);
+    }
+  }
+};
+xhr.onerror = function (e) {
+  console.error(xhr.statusText);
+};
+xhr.send(null); 
+ +

Line 2第3個參數為布林值,true表示非同步請求。

+ +

Line 3 creates an event handler function object and assigns it to the request's onload attribute.  This handler looks at the request's readyState to see if the transaction is complete in line 4, and if it is, and the HTTP status is 200, dumps the received content.  If an error occurred, an error message is displayed.

+ +

Line 15 actually initiates the request.  The callback routine is called whenever the state of the request changes.

+ +

Example: creating a standard function to read external files

+ +

In some cases you must read many external files. This is a standard function which uses the XMLHttpRequest object asynchronously in order to switch the content of the read file to a specified listener.

+ +
function xhrSuccess () { this.callback.apply(this, this.arguments); }
+
+function xhrError () { console.error(this.statusText); }
+
+function loadFile (sURL, fCallback /*, argumentToPass1, argumentToPass2, etc. */) {
+  var oReq = new XMLHttpRequest();
+  oReq.callback = fCallback;
+  oReq.arguments = Array.prototype.slice.call(arguments, 2);
+  oReq.onload = xhrSuccess;
+  oReq.onerror = xhrError;
+  oReq.open("get", sURL, true);
+  oReq.send(null);
+}
+
+ +

Usage:

+ +
function showMessage (sMsg) {
+  alert(sMsg + this.responseText);
+}
+
+loadFile("message.txt", showMessage, "New message!\n\n");
+
+ +

Line 1 declares a function which will pass all arguments after the third to the callback function when the file has been loaded.

+ +

Line 4 creates an event handler function object and assigns it to the request's onload attribute.  This handler looks at the request's readyState to see if the transaction is complete in line 5, and if it is, and the HTTP status is 200, calls the callback function.  If an error occurred, an error message is displayed.

+ +

Line 13 specifies true for its third parameter to indicate that the request should be handled asynchronously.

+ +

Line 14 actually initiates the request.

+ +

Example: using a timeout

+ +

You can use a timeout to prevent hanging your code forever while waiting for a read to occur. This is done by setting the value of the timeout property on the XMLHttpRequest object, as shown in the code below:

+ +
  var args = arguments.slice(2);
+  var xhr = new XMLHttpRequest();
+  xhr.ontimeout = function () {
+    console.error("The request for " + url + " timed out.");
+  };
+  xhr.onload = function() {
+    if (xhr.readyState === 4) {
+      if (xhr.status === 200) {
+        callback.apply(xhr, args);
+      } else {
+        console.error(xhr.statusText);
+      }
+    }
+  };
+  xhr.open("GET", url, true);
+  xhr.timeout = timeout;
+  xhr.send(null);
+}
+
+ +

Notice the addition of code to handle the "timeout" event by setting the ontimeout handler.

+ +

Usage:

+ +
function showMessage (sMsg) {
+  alert(sMsg + this.responseText);
+}
+
+loadFile("message.txt", 2000, showMessage, "New message!\n");
+
+ +

Here, we're specifying a timeout of 2000 ms.

+ +
+

Note: Support for timeout was added in {{Gecko("12.0")}}.

+
+ +

Synchronous request

+ +
Note: Starting with Gecko 30.0 {{ geckoRelease("30.0") }}, synchronous requests on the main thread have been deprecated due to the negative effects to the user experience.
+ +

In rare cases, the use of a synchronous method is preferable to an asynchronous one.

+ +

Example: HTTP synchronous request

+ +

This example demonstrates how to make a simple synchronous request.

+ +
var request = new XMLHttpRequest();
+request.open('GET', '/bar/foo.txt', false);  // `false` makes the request synchronous
+request.send(null);
+
+if (request.status === 200) {
+  console.log(request.responseText);
+}
+
+ +

Line 3 sends the request.  The null parameter indicates that no body content is needed for the GET request.

+ +

Line 5 checks the status code after the transaction is completed.  If the result is 200 -- HTTP's "OK" result -- the document's text content is output to the console.

+ +

Example: Synchronous HTTP request from a Worker

+ +

One of the few cases in which a synchronous request does not usually block execution is the use of XMLHttpRequest within a Worker.

+ +

example.html (the main page):

+ +
<!doctype html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>MDN Example</title>
+<script type="text/javascript">
+  var worker = new Worker("myTask.js");
+  worker.onmessage = function(event) {
+    alert("Worker said: " + event.data);
+  };
+
+  worker.postMessage("Hello");
+</script>
+</head>
+<body></body>
+</html>
+
+ +

myFile.txt (the target of the synchronous XMLHttpRequest invocation):

+ +
Hello World!!
+
+ +

myTask.js (the Worker):

+ +
self.onmessage = function (event) {
+  if (event.data === "Hello") {
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", "myFile.txt", false);  // synchronous request
+    xhr.send(null);
+    self.postMessage(xhr.responseText);
+  }
+};
+
+ +
Note: The effect, because of the use of the Worker, is however asynchronous.
+ +

It could be useful in order to interact in background with the server or to preload some content. See Using web workers for examples and details.

+ +

Irreplaceability of the synchronous use

+ +

There are some few cases in which the synchronous usage of XMLHttpRequest is not replaceable. This happens for example during the window.onunload and window.onbeforeunload events (see also below).

+ +

Sending the usual XMLHttpRequest when the page unloaded poses a problem with the asynchronous response from the server: by the time the response comes back, the page has unloaded and the callback function won’t exist anymore. This generates a JavaScript “function is not defined” error.

+ +

+ +

A possible solution is to make sure that any AJAX requests that you make on unload are make synchronously instead of asynchronously. This will ensure that the page doesn’t finish unloading before the server response comes back.

+ +

Example #1: Automatic logout before exit

+ +
window.onbeforeunload = function () {
+  var xhr = new XMLHttpRequest();
+  xhr.open("GET", "logout.php?nick=" + escape(myName), false);  // synchronous request
+  xhr.send(null);
+  if (xhr.responseText.trim() !== "logout done"); {  // "logout done" is the expected response text
+    return "Logout has failed. Do you want to complete it manually?";
+  }
+};
+
+ + + +
<!doctype html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>MDN Example</title>
+<script type="text/javascript">
+(function () {
+
+  function dontPanic () {
+    bForsake = false;
+    return true;
+  }
+
+  onload = function () {
+    for (
+      var aLinks = document.links, nLen = aLinks.length, nIdx = 0;
+      nIdx < nLen;
+      aLinks[nIdx++].onclick = dontPanic
+    );
+  };
+
+  onbeforeunload = function () {
+    if (bForsake) {
+      /* silent synchronous request */
+      var oReq = new XMLHttpRequest();
+      oReq.open("GET", "exit.php?leave=" + escape(location.href), false);
+      oReq.send(null);
+    }
+  };
+
+  var bForsake = true;
+
+})();
+</script>
+</head>
+
+<body>
+
+<p><a href="https://developer.mozilla.org/">Example link</a></p>
+
+</body>
+</html>
+ +

See also

+ + + +

{{ languages( {"zh-cn": "zh-cn/DOM/XMLHttpRequest/Synchronous_and_Asynchronous_Requests" } ) }}

diff --git a/files/zh-tw/web/api/xmlhttprequest/using_xmlhttprequest/index.html b/files/zh-tw/web/api/xmlhttprequest/using_xmlhttprequest/index.html new file mode 100644 index 0000000000..97b03c21d1 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/using_xmlhttprequest/index.html @@ -0,0 +1,766 @@ +--- +title: 使用 XMLHttpRequest +slug: Web/API/XMLHttpRequest/Using_XMLHttpRequest +tags: + - AJAX + - AJAXfile + - Advanced + - DOM + - JXON + - MakeBrowserAgnostic + - NeedsCompatTable + - XML + - XMLHttpRequest +translation_of: Web/API/XMLHttpRequest/Using_XMLHttpRequest +--- +

要送出一個 HTTP 請求,需要建立一個 {{domxref("XMLHttpRequest")}} 物件、開啟一個 URL,並發起一個請求。在交易(transaction)完成後,XMLHttpRequest 物件將會包含如回應內容(response body)及 HTTP 狀態等等請求結果中的有用資訊。本頁概述了一些常見的、甚至略為難理解的 XMLHttpRequest 物件使用案例。

+ +
function reqListener () {
+  console.log(this.responseText);
+}
+
+var oReq = new XMLHttpRequest();
+oReq.addEventListener("load", reqListener);
+oReq.open("GET", "http://www.example.org/example.txt");
+oReq.send();
+ +

請求類型

+ +

透過 XMLHttpRequest 建立的請求,其取得資料的方式可以為非同步(asynchronously)或同步(synchronously)兩種之一。請求的種類是由 {{domxref("XMLHttpRequest.open()")}} 方法的選擇性參數 async(第三個參數)決定。若 async 參數為 true 或是未指定,XMLHttpRequest 會被設定為非同步,相反的若為 false 則會被設定為同步。這兩種請求類型的細節討論與示範可以在同步與非同步請求頁面中找到。一般來說,很少會使用到同步請求。

+ +
備註:自 Gecko 30.0 {{ geckoRelease("30.0") }} 開始,在主執行緒上的同步請求因其差勁的使用者體驗已被棄用。
+ +

處理回應

+ +

XMLHttpRequest 的活動標準規範(living standard specification)定義了數個 XMLHttpRequest 建構出之物件的回應屬性。這些回應屬性告訴客戶端關於 XMLHttpRequest 回應狀態的重要資訊。一些處理非文字類型回應的案例可能會需要一些在下面小節所說明的分析和操作。

+ +

分析及操作 responseXML 屬性

+ +

透過 XMLHttpRequest 取得一個遠端的 XML 文件內容時,responseXML 屬性({{Glossary("property/JavaScript", "property")}})將會是一個由 XML 文件解析而來的 DOM 物件。這可能會造成分析和操作上的一些困難,以下有四種主要的 XML 文件分析方式:

+ +
    +
  1. 利用 XPath 指向需要部份。
  2. +
  3. 手動的解析與序列化 XML 成字串或物件。
  4. +
  5. 利用 {{domxref("XMLSerializer")}} 來序列化 DOM 樹成字串或檔案
  6. +
  7. 如果事先知道 XML 文件內容,可利用 {{jsxref("RegExp")}}。如果換行符號會影響 RegExp 掃描結果,則需要移除換行符號。然而,這項方式應該是「最後不得已的手段(last resort)」,因為一旦 XML 文件內容稍有變動,此方式就可能會失敗。
  8. +
+ +

分析及操作含有 HTML 文件的 responseText 屬性

+ +
備註:W3C 的XMLHttpRequest 規範允許透過 XMLHttpRequest.responseXML 屬性({{Glossary("property/JavaScript", "property")}})來解析 HTML。相關細節請參考 HTML in XMLHttpRequest 一文。
+ +

若透過 XMLHttpRequest 來取得一個遠端的 HTML 網頁內容,則 responseText 屬性({{Glossary("property/JavaScript", "property")}})會是「一串(soup)」包含所有 HTML 標籤的字串。這可能使得在分析和操作上造成困難,以下有三種主要分析此一大串 HTML 字串的方式:

+ +
    +
  1. 利用 XMLHttpRequest.responseXML 屬性。
  2. +
  3. 將內容透過 fragment.body.innerHTML 注入文件片段(document fragment)body 中,並遍歷(traverse)文件片段的 DOM。
  4. +
  5. 如果事先知道 HTML 之 responseText 內容,可利用 {{jsxref("RegExp")}}。如果換行符號會影響 RegExp 掃描結果,則需要移除換行符號。然而,這項方式應該是「最後不得已的手段(last resort)」,因為一旦 HTML 程式碼稍有變動,此方式就可能會失敗。
  6. +
+ +

處理二進位資料

+ +

僅管 XMLHttpRequest 最常被用在傳送及接收文字資料,但它其實也可以傳送及接收二進位內容。有幾種經過良好測試的方法可以用來強制使用 XMLHttpRequest 發送二進位資料。透過使用 XMLHttpRequest 物件的 .overrideMimeType() 方法是一個可行的解決方案。

+ +
var oReq = new XMLHttpRequest();
+oReq.open("GET", url);
+// retrieve data unprocessed as a binary string
+oReq.overrideMimeType("text/plain; charset=x-user-defined");
+/* ... */
+
+ +

XMLHttpRequest Level 2 規範加入了新的 responseType 屬性,讓收發二進位資料變得容易許多。

+ +
var oReq = new XMLHttpRequest();
+
+oReq.onload = function(e) {
+  var arraybuffer = oReq.response; // not responseText
+  /* ... */
+}
+oReq.open("GET", url);
+oReq.responseType = "arraybuffer";
+oReq.send();
+ +

更多的範例可參考傳送及接收二進位資料頁面。

+ +

監視進度

+ +

XMLHttpRequest 提供了監聽請求於處理過程中所發生的各項事件之能力。包括了定期進度通知、錯誤通知等等。

+ +

XMLHttpRequest 支援可監視其傳輸進度的 DOM 進度事件,此事件遵循進度事件規範:這些事件實作了 {{domxref("ProgressEvent")}} 介面。

+ +
var oReq = new XMLHttpRequest();
+
+oReq.addEventListener("progress", updateProgress);
+oReq.addEventListener("load", transferComplete);
+oReq.addEventListener("error", transferFailed);
+oReq.addEventListener("abort", transferCanceled);
+
+oReq.open();
+
+// ...
+
+// progress on transfers from the server to the client (downloads)
+function updateProgress (oEvent) {
+  if (oEvent.lengthComputable) {
+    var percentComplete = oEvent.loaded / oEvent.total;
+    // ...
+  } else {
+    // Unable to compute progress information since the total size is unknown
+  }
+}
+
+function transferComplete(evt) {
+  console.log("The transfer is complete.");
+}
+
+function transferFailed(evt) {
+  console.log("An error occurred while transferring the file.");
+}
+
+function transferCanceled(evt) {
+  console.log("The transfer has been canceled by the user.");
+}
+ +

第 3-6 行加入了事件監聽器來處理使用 XMLHttpRequest 執行資料收發過程中的各類事件。

+ +
備註:必須在呼叫 open() 方法開啟請求連線之前就註冊好事件監聽器,否則 progress 事件將不會被觸發。
+ +

在這個例子中,指定了 updateProgress() 函式作為 progress 事件處理器,progress 事件處理器會於 progress 事件物件的 totalloaded 屬性分別接收到要傳輸的總位元數及已送出的位元數。然而,假如 lengthComputable 屬性值為假,則代表要傳輸的總位元數是未知且 total 屬性值將會為零。

+ +

progress 事件同時存在於上傳及下載傳輸中。下載的相關事件會於 XMLHttpRequest 物件自己身上被觸發,如上面的範例。而上傳相關事件則在 XMLHttpRequest.upload 物件上被觸發,如以下範例:

+ +
var oReq = new XMLHttpRequest();
+
+oReq.upload.addEventListener("progress", updateProgress);
+oReq.upload.addEventListener("load", transferComplete);
+oReq.upload.addEventListener("error", transferFailed);
+oReq.upload.addEventListener("abort", transferCanceled);
+
+oReq.open();
+
+ +
備註:progress 事件無法用於 file: 通訊協定。
+ +
+

備註:自 {{Gecko("9.0")}} 開始,接收到每一個資料的區塊(chunk)時,progress 事件都會被觸發。包括在 progress 事件被觸發前,就已經接收到含有最後一個資料區塊的最後一個封包並且關閉連線的狀況下,在載入此封包時仍會自動觸發 progress 事件。這代表我們可以僅關注 progress 事件即能夠可靠的監視進度。

+
+ +
+

備註:在 {{Gecko("12.0")}} 中,如果 XMLHttpRequestresponseType 屬性為「moz-blob」,那麼 progress 事件觸發時的 XMLHttpRequest.response 值會是一個目前包含了所接收資料的 {{domxref("Blob")}}。

+
+ +

我們也可以透過 loadend 事件來偵測到所有之三種下載結束狀況(abortloaderror):

+ +
req.addEventListener("loadend", loadEnd);
+
+function loadEnd(e) {
+  console.log("The transfer finished (although we don't know if it succeeded or not).");
+}
+
+ +

請注意由 loadend 事件中接收到的資訊並無法確定是由何種結束狀況所觸發。不過還是可以用 loadend 事件來處理所有傳輸結束情況下需要執行的任務。

+ +

提交表單與上傳檔案

+ +

XMLHttpRequest 物件實體有兩種方式來提交表單:

+ + + +

使用 FormData API 是最簡單、快速的方式,但不利於將資料集合進行字串化
+ 只使用 AJAX 的方式較為複雜,但也更加靈活、強大。

+ +

僅使用 XMLHttpRequest

+ +

以不透過 FormData API 提交表單的方式在大多數的情況下都不需要使用其他額外的 API。唯一的例外是要上傳一或多個檔案時,會需要用到 {{domxref("FileReader")}} API。

+ +

提交方法簡介

+ +

一個 HTML {{HTMLElement("form", "表單(form)")}}有以下四種提交方式:

+ + + +

現在,假設要提交一個只包含兩個欄位的表單,欄位名稱為 foobaz。若是使用 POST 方法,伺服器將會收到一個如以下三個例子之一的字串,這取決於所使用的編碼類型(encoding type):

+ + + +

如果是使用 GET 方法,一個如下方的字串會被直接附加入到 URL 上:

+ +
?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.
+ +

小型原生框架

+ +

在我們提交 {{HTMLElement("form")}} 時,瀏覽器自動幫我們做了上面這些工作。假如要使用 JavaScript 達到同樣的效果就必須告訴直譯器(interpreter)要處理的所有事。然而,如何透過純粹的 AJAX 來傳送表單複雜到難以在本頁解釋所有細節。基於這個理由,我們改為在這此提供一組完整(教學用)的框架,可用於上述四種的每一種提交(submit),並包括上傳檔案

+ +
+
<!doctype html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>Sending forms with pure AJAX &ndash; MDN</title>
+<script type="text/javascript">
+
+"use strict";
+
+/*\
+|*|
+|*|  :: XMLHttpRequest.prototype.sendAsBinary() Polyfill ::
+|*|
+|*|  https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#sendAsBinary()
+\*/
+
+if (!XMLHttpRequest.prototype.sendAsBinary) {
+  XMLHttpRequest.prototype.sendAsBinary = function(sData) {
+    var nBytes = sData.length, ui8Data = new Uint8Array(nBytes);
+    for (var nIdx = 0; nIdx < nBytes; nIdx++) {
+      ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff;
+    }
+    /* send as ArrayBufferView...: */
+    this.send(ui8Data);
+    /* ...or as ArrayBuffer (legacy)...: this.send(ui8Data.buffer); */
+  };
+}
+
+/*\
+|*|
+|*|  :: AJAX Form Submit Framework ::
+|*|
+|*|  https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest
+|*|
+|*|  This framework is released under the GNU Public License, version 3 or later.
+|*|  https://www.gnu.org/licenses/gpl-3.0-standalone.html
+|*|
+|*|  Syntax:
+|*|
+|*|   AJAXSubmit(HTMLFormElement);
+\*/
+
+var AJAXSubmit = (function () {
+
+  function ajaxSuccess () {
+    /* console.log("AJAXSubmit - Success!"); */
+    console.log(this.responseText);
+    /* you can get the serialized data through the "submittedData" custom property: */
+    /* console.log(JSON.stringify(this.submittedData)); */
+  }
+
+  function submitData (oData) {
+    /* the AJAX request... */
+    var oAjaxReq = new XMLHttpRequest();
+    oAjaxReq.submittedData = oData;
+    oAjaxReq.onload = ajaxSuccess;
+    if (oData.technique === 0) {
+      /* method is GET */
+      oAjaxReq.open("get", oData.receiver.replace(/(?:\?.*)?$/,
+          oData.segments.length > 0 ? "?" + oData.segments.join("&") : ""), true);
+      oAjaxReq.send(null);
+    } else {
+      /* method is POST */
+      oAjaxReq.open("post", oData.receiver, true);
+      if (oData.technique === 3) {
+        /* enctype is multipart/form-data */
+        var sBoundary = "---------------------------" + Date.now().toString(16);
+        oAjaxReq.setRequestHeader("Content-Type", "multipart\/form-data; boundary=" + sBoundary);
+        oAjaxReq.sendAsBinary("--" + sBoundary + "\r\n" +
+            oData.segments.join("--" + sBoundary + "\r\n") + "--" + sBoundary + "--\r\n");
+      } else {
+        /* enctype is application/x-www-form-urlencoded or text/plain */
+        oAjaxReq.setRequestHeader("Content-Type", oData.contentType);
+        oAjaxReq.send(oData.segments.join(oData.technique === 2 ? "\r\n" : "&"));
+      }
+    }
+  }
+
+  function processStatus (oData) {
+    if (oData.status > 0) { return; }
+    /* the form is now totally serialized! do something before sending it to the server... */
+    /* doSomething(oData); */
+    /* console.log("AJAXSubmit - The form is now serialized. Submitting..."); */
+    submitData (oData);
+  }
+
+  function pushSegment (oFREvt) {
+    this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n";
+    this.owner.status--;
+    processStatus(this.owner);
+  }
+
+  function plainEscape (sText) {
+    /* How should I treat a text/plain form encoding?
+       What characters are not allowed? this is what I suppose...: */
+    /* "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2" */
+    return sText.replace(/[\s\=\\]/g, "\\$&");
+  }
+
+  function SubmitRequest (oTarget) {
+    var nFile, sFieldType, oField, oSegmReq, oFile, bIsPost = oTarget.method.toLowerCase() === "post";
+    /* console.log("AJAXSubmit - Serializing form..."); */
+    this.contentType = bIsPost && oTarget.enctype ? oTarget.enctype : "application\/x-www-form-urlencoded";
+    this.technique = bIsPost ?
+        this.contentType === "multipart\/form-data" ? 3 : this.contentType === "text\/plain" ? 2 : 1 : 0;
+    this.receiver = oTarget.action;
+    this.status = 0;
+    this.segments = [];
+    var fFilter = this.technique === 2 ? plainEscape : escape;
+    for (var nItem = 0; nItem < oTarget.elements.length; nItem++) {
+      oField = oTarget.elements[nItem];
+      if (!oField.hasAttribute("name")) { continue; }
+      sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT";
+      if (sFieldType === "FILE" && oField.files.length > 0) {
+        if (this.technique === 3) {
+          /* enctype is multipart/form-data */
+          for (nFile = 0; nFile < oField.files.length; nFile++) {
+            oFile = oField.files[nFile];
+            oSegmReq = new FileReader();
+            /* (custom properties:) */
+            oSegmReq.segmentIdx = this.segments.length;
+            oSegmReq.owner = this;
+            /* (end of custom properties) */
+            oSegmReq.onload = pushSegment;
+            this.segments.push("Content-Disposition: form-data; name=\"" +
+                oField.name + "\"; filename=\"" + oFile.name +
+                "\"\r\nContent-Type: " + oFile.type + "\r\n\r\n");
+            this.status++;
+            oSegmReq.readAsBinaryString(oFile);
+          }
+        } else {
+          /* enctype is application/x-www-form-urlencoded or text/plain or
+             method is GET: files will not be sent! */
+          for (nFile = 0; nFile < oField.files.length;
+              this.segments.push(fFilter(oField.name) + "=" + fFilter(oField.files[nFile++].name)));
+        }
+      } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {
+        /* NOTE: this will submit _all_ submit buttons. Detecting the correct one is non-trivial. */
+        /* field type is not FILE or is FILE but is empty */
+        this.segments.push(
+          this.technique === 3 ? /* enctype is multipart/form-data */
+            "Content-Disposition: form-data; name=\"" + oField.name + "\"\r\n\r\n" + oField.value + "\r\n"
+          : /* enctype is application/x-www-form-urlencoded or text/plain or method is GET */
+            fFilter(oField.name) + "=" + fFilter(oField.value)
+        );
+      }
+    }
+    processStatus(this);
+  }
+
+  return function (oFormElement) {
+    if (!oFormElement.action) { return; }
+    new SubmitRequest(oFormElement);
+  };
+
+})();
+
+</script>
+</head>
+<body>
+
+<h1>Sending forms with pure AJAX</h1>
+
+<h2>Using the GET method</h2>
+
+<form action="register.php" method="get" onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Registration example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" />
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+<h2>Using the POST method</h2>
+<h3>Enctype: application/x-www-form-urlencoded (default)</h3>
+
+<form action="register.php" method="post" onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Registration example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" />
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+<h3>Enctype: text/plain</h3>
+
+<form action="register.php" method="post" enctype="text/plain"
+    onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Registration example</legend>
+    <p>
+      Your name: <input type="text" name="user" />
+    </p>
+    <p>
+      Your message:<br />
+      <textarea name="message" cols="40" rows="8"></textarea>
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+<h3>Enctype: multipart/form-data</h3>
+
+<form action="register.php" method="post" enctype="multipart/form-data"
+    onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Upload example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" /><br />
+      Sex:
+      <input id="sex_male" type="radio" name="sex" value="male" />
+      <label for="sex_male">Male</label>
+      <input id="sex_female" type="radio" name="sex" value="female" />
+      <label for="sex_female">Female</label><br />
+      Password: <input type="password" name="secret" /><br />
+      What do you prefer:
+      <select name="image_type">
+        <option>Books</option>
+        <option>Cinema</option>
+        <option>TV</option>
+      </select>
+    </p>
+    <p>
+      Post your photos:
+      <input type="file" multiple name="photos[]">
+    </p>
+    <p>
+      <input id="vehicle_bike" type="checkbox" name="vehicle[]" value="Bike" />
+      <label for="vehicle_bike">I have a bike</label><br />
+      <input id="vehicle_car" type="checkbox" name="vehicle[]" value="Car" />
+      <label for="vehicle_car">I have a car</label>
+    </p>
+    <p>
+      Describe yourself:<br />
+      <textarea name="description" cols="50" rows="8"></textarea>
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+</body>
+</html>
+
+ +

為了進行測試,建立一個名為 register.php 的 PHP 頁面(即為上面範例表單之 action 屬性({{Glossary("attribute")}})所指向的位置),並輸入以下最簡化的內容:

+ +
<?php
+/* register.php */
+
+header("Content-type: text/plain");
+
+/*
+NOTE: You should never use `print_r()` in production scripts, or
+otherwise output client-submitted data without sanitizing it first.
+Failing to sanitize can lead to cross-site scripting vulnerabilities.
+*/
+
+echo ":: data received via GET ::\n\n";
+print_r($_GET);
+
+echo "\n\n:: Data received via POST ::\n\n";
+print_r($_POST);
+
+echo "\n\n:: Data received as \"raw\" (text/plain encoding) ::\n\n";
+if (isset($HTTP_RAW_POST_DATA)) { echo $HTTP_RAW_POST_DATA; }
+
+echo "\n\n:: Files received ::\n\n";
+print_r($_FILES);
+
+
+ +

使用這個框架的語法簡單如下:

+ +
AJAXSubmit(myForm);
+ +
備註:此框架使用了 {{domxref("FileReader")}} API 來發送檔案上傳。這是個較新的 API,且 IE9 或其先前版本並未實作。因為這個理由,AJAX-only 上傳被認為是一項實驗性技術。若沒有需要上傳二進位檔案,此框架可於大部分瀏覽器中運作良好。
+ +
備註:傳送二進位檔案的最佳方式是藉由 {{jsxref("ArrayBuffer", "ArrayBuffers")}} 或 {{domxref("Blob", "Blobs")}} 結合 {{domxref("XMLHttpRequest.send()", "send()")}} 方法來送出,如果可以也能搭配 FileReader API 的 {{domxref("FileReader.readAsArrayBuffer()", "readAsArrayBuffer()")}} 方法先進行讀取。但因為這段程式指令碼(script)的目的是要處理可字串化的原始資料,所以使用 {{domxref("XMLHttpRequest.sendAsBinary()", "sendAsBinary()")}} 方法結合 FileReader API 的 {{domxref("FileReader.readAsBinaryString()", "readAsBinaryString()")}} 方法。就其本身來看,以上的指令碼只有在處理小型檔案時才有意義。假如不打算上傳二進位內容,請考慮使用 FormData API。
+ +
備註:非標準的 sendAsBinary 方法在 Gecko 31 {{geckoRelease(31)}} 已被認為是棄用的(deprecated),並且即將被移除。而標準的 send(Blob data) 方法可以作為替代。
+ +

使用 FormData 物件

+ +

{{domxref("XMLHttpRequest.FormData", "FormData")}} 建構式可以讓我們收集一連串名/值對資料並透過 XMLHttpRequest 送出。其主要用於傳送表單資料,但也能夠單獨的由表單建立來傳輸使用者輸入的資料。若表單的編碼類型(encoding type)被設定為「multipart/form-data」,則由 FormData 所發送的資料格式和表單用來傳送資料的 submit() 方法相同。FormData 物件可以搭配 XMLHttpRequest 以多種方式使用。相關的範例,以及可以怎麼利用 FormData 配合 XMLHttpRequest 的說明,請參考使用 FormData 物件頁面。為了教學使用,下方為一個利用 FormData API 來改寫先前範例翻譯版本。注意這段精簡後的程式碼:

+ +
+
<!doctype html>
+<html>
+<head>
+<meta http-equiv="Content-Type" charset="UTF-8" />
+<title>Sending forms with FormData &ndash; MDN</title>
+<script>
+"use strict";
+
+function ajaxSuccess () {
+  console.log(this.responseText);
+}
+
+function AJAXSubmit (oFormElement) {
+  if (!oFormElement.action) { return; }
+  var oReq = new XMLHttpRequest();
+  oReq.onload = ajaxSuccess;
+  if (oFormElement.method.toLowerCase() === "post") {
+    oReq.open("post", oFormElement.action);
+    oReq.send(new FormData(oFormElement));
+  } else {
+    var oField, sFieldType, nFile, sSearch = "";
+    for (var nItem = 0; nItem < oFormElement.elements.length; nItem++) {
+      oField = oFormElement.elements[nItem];
+      if (!oField.hasAttribute("name")) { continue; }
+      sFieldType = oField.nodeName.toUpperCase() === "INPUT" ?
+          oField.getAttribute("type").toUpperCase() : "TEXT";
+      if (sFieldType === "FILE") {
+        for (nFile = 0; nFile < oField.files.length;
+            sSearch += "&" + escape(oField.name) + "=" + escape(oField.files[nFile++].name));
+      } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {
+        sSearch += "&" + escape(oField.name) + "=" + escape(oField.value);
+      }
+    }
+    oReq.open("get", oFormElement.action.replace(/(?:\?.*)?$/, sSearch.replace(/^&/, "?")), true);
+    oReq.send(null);
+  }
+}
+</script>
+</head>
+<body>
+
+<h1>Sending forms with FormData</h1>
+
+<h2>Using the GET method</h2>
+
+<form action="register.php" method="get" onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Registration example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" />
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+<h2>Using the POST method</h2>
+<h3>Enctype: application/x-www-form-urlencoded (default)</h3>
+
+<form action="register.php" method="post" onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Registration example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" />
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+<h3>Enctype: text/plain</h3>
+
+<p>The text/plain encoding is not supported by the FormData API.</p>
+
+<h3>Enctype: multipart/form-data</h3>
+
+<form action="register.php" method="post" enctype="multipart/form-data"
+    onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Upload example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" /><br />
+      Sex:
+      <input id="sex_male" type="radio" name="sex" value="male" />
+      <label for="sex_male">Male</label>
+      <input id="sex_female" type="radio" name="sex" value="female" />
+      <label for="sex_female">Female</label><br />
+      Password: <input type="password" name="secret" /><br />
+      What do you prefer:
+      <select name="image_type">
+        <option>Books</option>
+        <option>Cinema</option>
+        <option>TV</option>
+      </select>
+    </p>
+    <p>
+      Post your photos:
+      <input type="file" multiple name="photos[]">
+    </p>
+    <p>
+      <input id="vehicle_bike" type="checkbox" name="vehicle[]" value="Bike" />
+      <label for="vehicle_bike">I have a bike</label><br />
+      <input id="vehicle_car" type="checkbox" name="vehicle[]" value="Car" />
+      <label for="vehicle_car">I have a car</label>
+    </p>
+    <p>
+      Describe yourself:<br />
+      <textarea name="description" cols="50" rows="8"></textarea>
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+</body>
+</html>
+
+ +
備註:如同之前所說,{{domxref("FormData")}} 物件是不能被字串化的物件。若想要字串化一個被提交的資料,請使用先前的 AJAX 範例。還要注意的是,雖然在這個例子中有一些 file {{ HTMLElement("input") }} 欄位,當你透過 FormData API 來提交表單便也不需要使用 {{domxref("FileReader")}} API:檔案會自動地載入並上傳。
+ +

取得最後修改日期

+ +
function getHeaderTime () {
+  console.log(this.getResponseHeader("Last-Modified"));  /* A valid GMTString date or null */
+}
+
+var oReq = new XMLHttpRequest();
+oReq.open("HEAD" /* use HEAD if you only need the headers! */, "yourpage.html");
+oReq.onload = getHeaderTime;
+oReq.send();
+ +

當最後修改日期改變時做一些事

+ +

先建立兩個函式:

+ +
function getHeaderTime () {
+  var nLastVisit = parseFloat(window.localStorage.getItem('lm_' + this.filepath));
+  var nLastModif = Date.parse(this.getResponseHeader("Last-Modified"));
+
+  if (isNaN(nLastVisit) || nLastModif > nLastVisit) {
+    window.localStorage.setItem('lm_' + this.filepath, Date.now());
+    isFinite(nLastVisit) && this.callback(nLastModif, nLastVisit);
+  }
+}
+
+function ifHasChanged(sURL, fCallback) {
+  var oReq = new XMLHttpRequest();
+  oReq.open("HEAD" /* use HEAD - we only need the headers! */, sURL);
+  oReq.callback = fCallback;
+  oReq.filepath = sURL;
+  oReq.onload = getHeaderTime;
+  oReq.send();
+}
+ +

並進行測試:

+ +
/* Let's test the file "yourpage.html"... */
+
+ifHasChanged("yourpage.html", function (nModif, nVisit) {
+  console.log("The page '" + this.filepath + "' has been changed on " + (new Date(nModif)).toLocaleString() + "!");
+});
+ +

如果想要知道目前頁面是否已變更,請參考 {{domxref("document.lastModified")}} 一文。

+ +

跨網域 XMLHttpRequest

+ +

現代瀏覽器支援跨網域(cross-site)請求並實作了網路應用程式工作小組(Web Applications (WebApps) Working Group)提出的跨網域請求存取控制標準。只要伺服器被設定為允許來自你的網路應用程式來源(origin)網域之請求,XMLHttpRequest 便能正常運作。否則,將會拋出一個 INVALID_ACCESS_ERR 例外。

+ +

避開快取

+ +

有一個跨瀏覽器相容的避開快取方法,便是將時間戳記(timestamp)附加於 URL 後方,請確保加上了適當的「?」或「&」。例如:

+ +
http://foo.com/bar.html -> http://foo.com/bar.html?12345
+http://foo.com/bar.html?foobar=baz -> http://foo.com/bar.html?foobar=baz&12345
+
+ +

由於本地快取的索引是基於 URL,加入時間戳記會導致每一個請求都會是唯一的,藉此避開快取。

+ +

可以使用以下的程式碼來自動的調整 URL:

+ +
var oReq = new XMLHttpRequest();
+
+oReq.open("GET", url + ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime());
+oReq.send(null);
+ +

安全性

+ +

{{fx_minversion_note(3, "Firefox 3 之前的版本允許在偏好設定中設定 capability.policy.<policyname>.XMLHttpRequest.open</policyname>allAccess 來讓指定的網域能夠跨網域存取。現已不再支援。")}}

+ +

{{fx_minversion_note(5, "Firefox 5 之前的版本可以使用 netscape.security.PrivilegeManager.enablePrivilege(\"UniversalBrowserRead\"); 來發送跨網域存取請求。現已不再支援,即使它不會有警告並且依然會顯示允許請求的權限對話框。")}}

+ +

開啟跨網域指令碼(script)的建議方式是於 XMLHttpRequest 的回應中使用 Access-Control-Allow-Origin HTTP 標頭。

+ +

被中止的 XMLHttpRequest

+ +

如果你發現 XMLHttpRequeststatus=0statusText=null,這代表請求並不被允許執行,其狀態為 UNSENT(未送出)。被中止的原因可能是因為 XMLHttpRequest 物件所關聯的 origin(來源網域)值(於 XMLHttpRequest 物件建立時自 window.origin 取得)在呼叫 open() 方法之前就已經被改變。這是可能發生的,例如在 windowonunload 事件觸發時送出 XMLHttpRequest 請求,預期的情況為:XMLHttpRequest 物件剛被建立,而目前的視窗尚未關閉,而最後發送請求(即呼叫了 open() 方法)的時間點是在此視窗失去了焦點並且另外的視窗取得焦點之間。要避開這個問題的最有效方法是在要被終止的(terminated)window 觸發 unload 事件時,於新的 window 的上註冊一個新的 activate 事件監聽器來發送請求。

+ +

使用 JavaScript 模組/XPCOM 元件中的 XMLHttpRequest

+ +

JavaScript 模組 或 XPCOM 元件實體化一個 XMLHttpRequest 物件在做法上會有些許不同;我們無法用 XMLHttpRequest() 建構式,因為此建構式並未在元件中定義,並會導致程式產生錯誤。較佳的方式是使用 XPCOM 元件的建構式。

+ +
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1",
+    "nsIXMLHttpRequest");
+
+ +

在 Gecko 16 之前,存在著一個透過這種方式發送的請求會被無條件取消的臭蟲。若程式需要在 Gecko 15 或更早的版本上運作,可以從隱藏的 DOM window 中取得 XMLHttpRequest() 建構式。

+ +
const { XMLHttpRequest } = Components.classes["@mozilla.org/appshell/appShellService;1"]
+                                     .getService(Components.interfaces.nsIAppShellService)
+                                     .hiddenDOMWindow;
+var oReq = new XMLHttpRequest();
+ +

參見

+ +
    +
  1. MDN AJAX 介紹
  2. +
  3. HTTP 存取控制
  4. +
  5. How to check the security state of an XMLHTTPRequest over SSL
  6. +
  7. XMLHttpRequest - REST and the Rich User Experience
  8. +
  9. Microsoft documentation
  10. +
  11. Apple developers' reference
  12. +
  13. "Using the XMLHttpRequest Object" (jibbering.com)
  14. +
  15. The XMLHttpRequest object: WHATWG specification
  16. +
diff --git a/files/zh-tw/web/api/xmlhttprequest/withcredentials/index.html b/files/zh-tw/web/api/xmlhttprequest/withcredentials/index.html new file mode 100644 index 0000000000..e70f611ece --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/withcredentials/index.html @@ -0,0 +1,48 @@ +--- +title: XMLHttpRequest.withCredentials +slug: Web/API/XMLHttpRequest/withCredentials +translation_of: Web/API/XMLHttpRequest/withCredentials +--- +
{{APIRef('XMLHttpRequest')}}
+ +

XMLHttpRequest.withCredentials 屬性是一個 {{jsxref("Boolean")}} 型別,它指出無論是否使用 Access-Control 標頭在跨站的要求上,都應該使用像 Cookies、Authorization 標頭或 TLS 用戶端憑證來進行驗證。在相同來源的要求設定 withCredentials 沒有任何效果。

+ +

In addition, this flag is also used to indicate when cookies are to be ignored in the response. The default is false. XMLHttpRequest from a different domain cannot set cookie values for their own domain unless withCredentials is set to true before making the request. The third-party cookies obtained by setting withCredentials to true will still honor same-origin policy and hence can not be accessed by the requesting script through document.cookie or from response headers.

+ +
+

Note: 永遠不會影響到同源請求。

+
+ +
+

Note: XMLHttpRequest responses from a different domain cannot set cookie values for their own domain unless withCredentials is set to true before making the request, regardless of Access-Control- header values. 

+
+ +

範例

+ +
var xhr = new XMLHttpRequest();
+xhr.open('GET', 'http://example.com/', true);
+xhr.withCredentials = true;
+xhr.send(null);
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態備註
{{SpecName('XMLHttpRequest', '#the-withcredentials-attribute')}}{{Spec2('XMLHttpRequest')}}WHATWG living standard
+ +

瀏覽器相容性

+ + + +

{{Compat("api.XMLHttpRequest.withCredentials")}}

diff --git a/files/zh-tw/web/api/xmlhttprequest/xmlhttprequest/index.html b/files/zh-tw/web/api/xmlhttprequest/xmlhttprequest/index.html new file mode 100644 index 0000000000..6459ef0c2a --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/xmlhttprequest/index.html @@ -0,0 +1,50 @@ +--- +title: XMLHttpRequest() +slug: Web/API/XMLHttpRequest/XMLHttpRequest +translation_of: Web/API/XMLHttpRequest/XMLHttpRequest +--- +
{{draft}}{{APIRef('XMLHttpRequest')}}
+ +

XMLHttpRequest() 建構式會建立一個新的 {{domxref("XMLHttpRequest")}} 物件。

+ +

關於如何使用 XMLHttpRequest 物件的細節,請參照: Using XMLHttpRequest.

+ +

語法

+ +
const request = new XMLHttpRequest();
+
+ +

參數

+ +

無。

+ +

回傳值 

+ +

將回傳一個新的 {{domxref("XMLHttpRequest")}} 物件。{{domxref("XMLHttpRequest")}} 物件在呼叫{{domxref("XMLHttpRequest.send", "send()")}} 送出要求到伺服器之前,至少要藉著呼叫 {{domxref("XMLHttpRequest.open", "open()")}} 來準備好必需的設定。

+ +

非標準的 Firefox 語法

+ +

Firefox 16 added a non-standard parameter to the constructor that can enable anonymous mode (see {{Bug("692677")}}). Setting the mozAnon flag to true effectively resembles the AnonXMLHttpRequest() constructor described in older versions of the XMLHttpRequest specification.

+ +
const request = new XMLHttpRequest(paramsDictionary);
+ +

Parameters (non-standard)

+ +
+
objParameters {{gecko_minversion_inline("16.0")}}
+
There are two flags you can set: +
+
mozAnon
+
Boolean: Setting this flag to true will cause the browser not to expose the {{Glossary("origin")}} and user credentials when fetching resources. Most important, this means that {{Glossary("Cookie", "cookies")}} will not be sent unless explicitly added using setRequestHeader.
+
mozSystem
+
Boolean: Setting this flag to true allows making cross-site connections without requiring the server to opt-in using {{Glossary("CORS")}}. Requires setting mozAnon: true, i.e. this can't be combined with sending cookies or other user credentials. This only works in privileged (reviewed) apps ({{Bug("692677")}}); it does not work on arbitrary webpages loaded in Firefox
+
+
+
+ +

參見

+ + diff --git a/files/zh-tw/web/api/xmlhttprequesteventtarget/index.html b/files/zh-tw/web/api/xmlhttprequesteventtarget/index.html new file mode 100644 index 0000000000..41045ab17f --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequesteventtarget/index.html @@ -0,0 +1,111 @@ +--- +title: XMLHttpRequestEventTarget +slug: Web/API/XMLHttpRequestEventTarget +translation_of: Web/API/XMLHttpRequestEventTarget +--- +

{{APIRef("XMLHttpRequest")}}

+ +

XMLHttpRequestEventTarget 介面描述了一個 {{ domxref("XMLHttpRequest") }} 物件實體當中,所有可註冊事件處理器的屬性。

+ +

{{InheritanceDiagram}}

+ +

屬性

+ +
+
{{ domxref("XMLHttpRequestEventTarget.onabort") }}
+
Contains the function to call when a request is aborted and the {{event('abort')}} event is received by this object.
+
{{ domxref("XMLHttpRequestEventTarget.onerror") }}
+
Contains the function to call when a request encounters an error and the {{event('error')}} event is received by this object.
+
{{ domxref("XMLHttpRequestEventTarget.onload") }}
+
Contains the function to call when an HTTP request returns after successfully fetching content and the {{event('load')}} event is received by this object.
+
{{ domxref("XMLHttpRequestEventTarget.onloadstart") }}
+
Contains the function that gets called when the HTTP request first begins loading data and the {{event('loadstart')}} event is received by this object.
+
{{ domxref("XMLHttpRequestEventTarget.onprogress") }}
+
Contains the function that is called periodically with information about the progress of the request and the {{event('progress')}} event is received by this object.
+
{{ domxref("XMLHttpRequestEventTarget.ontimeout") }}
+
Contains the function that is called if the event times out and the {{event("timeout")}} event is received by this object; this only happens if a timeout has been previously established by setting the value of the XMLHttpRequest object's timeout attribute.
+
{{ domxref("XMLHttpRequestEventTarget.onloadend") }}
+
Contains the function that is called when the load is completed, even if the request failed, and the {{event('loadend')}} event is received by this object.
+
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('XMLHttpRequest')}}{{Spec2('XMLHttpRequest')}}WHATWG living standard
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.0")}}7{{CompatVersionUnknown}}1.2
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatUnknown}}1.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

 

+ +

參見

+ + diff --git a/files/zh-tw/web/css/@font-face/index.html b/files/zh-tw/web/css/@font-face/index.html new file mode 100644 index 0000000000..ca045e5dab --- /dev/null +++ b/files/zh-tw/web/css/@font-face/index.html @@ -0,0 +1,247 @@ +--- +title: '@font-face' +slug: Web/CSS/@font-face +tags: + - CSS + - CSS Reference + - CSS 參考 + - Fonts + - WOFF + - 字型 +translation_of: Web/CSS/@font-face +--- +
{{CSSRef}}
+ +

摘要

+ +

The @font-face CSS at-rule allows authors to specify online fonts to display text on their web pages. By allowing authors to provide their own fonts, @font-face eliminates the need to depend on the limited number of fonts users have installed on their computers. The @font-face at-rule may be used not only at the top level of a CSS, but also inside any CSS conditional-group at-rule.

+ +

{{seeCompatTable}}

+ +

語法

+ +
@font-face {
+  [font-family: <family-name>;]?
+  [src: [ <uri> [format(<string>#)]? | <font-face-name> ]#;]?
+  [unicode-range: <urange>#;]?
+  [font-variant: <font-variant>;]?
+  [font-feature-settings: normal|<feature-tag-value>#;]?
+  [font-stretch: <font-stretch>;]?
+  [font-weight: <weight>];
+  [font-style: <style>];
+}
+
+ +

參數值

+ +
+
<family-name>
+
Specifies a font name that will be used as font face value for font properties.
+
<uri>
+
URL for the remote font file location, or the name of a font on the user's computer in the form local("Font Name").
+
<font-variant>
+
A {{cssxref("font-variant")}} value.
+
<font-stretch>
+
A {{cssxref("font-stretch")}} value.
+
<weight>
+
A font weight value.
+
<style>
+
A font style value.
+
+ +

You can specify a font on the user's local computer by name using the local() syntax. If that font isn't found, other sources will be tried until one is found.

+ +

範例

+ +

這個範例指定一個可供下載的字型,並套用至 document 的整個 body。

+ +

檢視線上範例

+ +
<html>
+<head>
+  <title>Web Font Sample</title>
+  <style type="text/css" media="screen, print">
+    @font-face {
+      font-family: "Bitstream Vera Serif Bold";
+      src: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");
+    }
+
+    body { font-family: "Bitstream Vera Serif Bold", serif }
+  </style>
+</head>
+<body>
+  This is Bitstream Vera Serif Bold.
+</body>
+</html>
+
+ +

這個範例會套用使用者本地的 "Helvetica Neue Bold" 字型,只有當使用者未安裝該字型(兩種名稱都試過了),才會下載 "MgOpenModernaBold.ttf" 字型:

+ +
@font-face {
+  font-family: MyHelvetica;
+  src: local("Helvetica Neue Bold"),
+  local("HelveticaNeue-Bold"),
+  url(MgOpenModernaBold.ttf);
+  font-weight: bold;
+}
+
+ +

注意事項

+ + + +

規格文件

+ + + + + + + + + + + + + + + + + + + + + +
規格文件狀態註解
{{SpecName('WOFF1.0', '', 'WOFF font format')}}{{Spec2('WOFF1.0')}}字型格式規格文件
{{SpecName('CSS3 Fonts', '#font-face-rule', '@font-face')}}{{Spec2('CSS3 Fonts')}} 
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能特色Firefox (Gecko)ChromeInternet ExplorerOperaSafari
基本支援{{CompatGeckoDesktop("1.9.1")}}4.04.010.03.1
WOFF{{CompatGeckoDesktop("1.9.1")}}6.09.011.105.1
SVG 字型{{CompatNo}}
+ {{unimplemented_inline(119490)}}
{{CompatNo}}
unicode-range +

yes ({{bug(443976)}})

+
9.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能特色AndroidFirefox 行動版 (Gecko)IE 行動版Opera MiniOpera 行動版Safari 行動版
基本支援{{CompatVersionUnknown}}{{CompatGeckoMobile("1.9.1")}}{{CompatUnknown}}{{CompatNo}}10.0{{CompatVersionUnknown}}
WOFF{{CompatNo}}{{CompatGeckoMobile("5.0")}}{{CompatUnknown}}{{CompatNo}}11.0{{CompatNo}}
SVG 字型{{CompatNo}}{{CompatNo}}
+ {{unimplemented_inline(119490)}}
{{CompatUnknown}}{{CompatNo}}10.0{{CompatVersionUnknown}}
unicode-range     {{CompatVersionUnknown}}
+
+ +

注意事項

+ + + +

詳見

+ + diff --git a/files/zh-tw/web/css/@media/height/index.html b/files/zh-tw/web/css/@media/height/index.html new file mode 100644 index 0000000000..cb15e99e80 --- /dev/null +++ b/files/zh-tw/web/css/@media/height/index.html @@ -0,0 +1,77 @@ +--- +title: height +slug: Web/CSS/@media/height +translation_of: Web/CSS/@media/height +--- +

height 屬於 CSS 的媒體功能之一,其值為可視區域 (viewport) 的高度,像是 CSS 的 <length>

+ +

規格

+ + + + + + + + + + + + + + + + +
規格狀態註釋
{{SpecName('CSS3 Media Queries', '#height', 'height')}}{{Spec2('CSS3 Media Queries')}}初始定義。
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +

 

diff --git a/files/zh-tw/web/css/@media/index.html b/files/zh-tw/web/css/@media/index.html new file mode 100644 index 0000000000..11f39d07b6 --- /dev/null +++ b/files/zh-tw/web/css/@media/index.html @@ -0,0 +1,377 @@ +--- +title: '@media' +slug: Web/CSS/@media +tags: + - At-rule + - CSS + - NeedsTranslation + - Reference + - TopicStub +translation_of: Web/CSS/@media +--- +

{{CSSRef}}

+ +

概要

+ +

@media CSS at-rule 與一組被大括弧隔開、並由 media query 條件定義的 CSS 巢狀區塊有關。@media at-rule 不只能用在最頂層的 CSS 區塊,也能在任何 CSS conditional-group at-rule 使用。

+ +

@media at-rule 能透過 CSS object model 介面 {{domxref("CSSMediaRule")}} 通行。

+ +

語法

+ +
{{csssyntax}}
+ +

A <media-query> is composed of a optional media type and/or a number of media features.

+ +

Media types

+ +
+
all
+
Suitable for all devices.
+
print
+
Intended for paged material and for documents viewed on screen in print preview mode. Please consult the section on paged media, and the media section of the Getting Started tutorial for information about formatting issues that are specific to paged media.
+
screen
+
Intended primarily for color computer screens.
+
speech
+
Intended for speech synthesizers. Note: CSS2 had a similar media type called 'aural' for this purpose. See the appendix on aural style sheets for details.
+
+ +
Note: CSS2.1 and Media Queries 3 defined several additional media types (tty, tv, projection, handheld, braille, embossed, aural), but they were deprecated in Media Queries 4 and shouldn't be used.
+ +

Media Features

+ +

Each media feature tests for one specific feature of the browser or device.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameSummaryNotes
widthViewport width
heightViewport height
aspect-ratioWidth-to-height aspect ratio of the viewport
orientationOrientation of the viewport
resolutionPixel density of the output device
scanScanning process of the output device
gridIs the device a grid or bitmap?
update-frequencyHow quickly (if at all) can the output device modify the appearance of the contentAdded in Media Queries Level 4
overflow-blockHow does the output device handle content that overflows the viewport along the block axis?Added in Media Queries Level 4
overflow-inlineCan content that overflows the viewport along the inline axis be scrolled?Added in Media Queries Level 4
colorNumber of bits per color component of the output device, or zero if the device isn't color.
color-indexNumber of entries in the output device's color lookup table, or zero if the device does not use such a table.
display-modeThe display mode of the application, as specified in the web app manifest's display member.Defined in the Web App Manifest spec.
monochromeBits per pixel in the output device's monochrome frame buffer, or 0 if the device is not monochrome.
inverted-colorsIs the user agent or underlying OS inverting colors?Added in Media Queries Level 4
pointerIs the primary input mechanism a pointing device, and if so, how accurate is it?Added in Media Queries Level 4
hoverDoes the primary input mechanism allow the user to hover over elements?Added in Media Queries Level 4
any-pointerIs any available input mechanism a pointing device, and if so, how accurate is it?Added in Media Queries Level 4
any-hoverDoes any available input mechanism allow the user to hover over elements?Added in Media Queries Level 4
light-levelCurrent ambient light levelAdded in Media Queries Level 4
scriptingIs scripting (e.g. JavaScript) available?Added in Media Queries Level 4
device-width {{obsolete_inline}}Width of the rendering surface of the output deviceDeprecated in Media Queries Level 4
device-height {{obsolete_inline}}Height of the rendering surface of the output deviceDeprecated in Media Queries Level 4
device-aspect-ratio {{obsolete_inline}}Width-to-height aspect ratio of the output deviceDeprecated in Media Queries Level 4
-webkit-device-pixel-ratio {{non-standard_inline}}Number of physical device pixels per CSS pixelNonstandard; WebKit/Blink-specific. If possible, use the resolution media feature instead.
-webkit-transform-3d {{non-standard_inline}}Are CSS 3D {{cssxref("transform")}}s supported?Nonstandard; WebKit/Blink-specific
-webkit-transform-2d {{non-standard_inline}}Are CSS 2D {{cssxref("transform")}}s supported?Nonstandard; WebKit-specific
-webkit-transition {{non-standard_inline}}Are CSS {{cssxref("transition")}}s supported?Nonstandard; WebKit-specific
-webkit-animation {{non-standard_inline}}Are CSS {{cssxref("animation")}}s supported?Nonstandard; WebKit-specific
+ +

Examples

+ +
@media print {
+  body { font-size: 10pt }
+}
+@media screen {
+  body { font-size: 13px }
+}
+@media screen, print {
+  body { line-height: 1.2 }
+}
+@media only screen
+  and (min-device-width: 320px)
+  and (max-device-width: 480px)
+  and (-webkit-min-device-pixel-ratio: 2) {
+    body { line-height: 1.4 }
+}
+
+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Compat', '#css-media-queries', 'CSS Media Queries')}}{{Spec2('Compat')}}Standardizes the -webkit-device-pixel-ratio and -webkit-transform-3d media features.
{{SpecName('CSS3 Conditional', '#at-media', '@media')}}{{Spec2('CSS3 Conditional')}}Defines the basic syntax of the @media rule.
{{SpecName('CSS4 Media Queries', '#media', '@media')}}{{Spec2('CSS4 Media Queries')}} +

Added scripting, pointer, hover, light-level, update-frequency, overflow-block, and overflow-inline media features.
+ Deprecated all media types except for screen, print, speech, and all.
+ Made the syntax more flexible by adding, among other things, the or keyword.

+
{{SpecName('CSS3 Media Queries', '#media0', '@media')}}{{Spec2('CSS3 Media Queries')}}No change.
{{SpecName('CSS2.1', 'media.html#at-media-rule', '@media')}}{{Spec2('CSS2.1')}}Initial definition.
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support (all, print, screen)1.0{{CompatVersionUnknown}}{{ CompatGeckoDesktop(1.7) }}6.09.21.3
speech{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}9.2{{CompatNo}}
Media features1.0{{CompatVersionUnknown}}{{ CompatGeckoDesktop(1.7) }}9.09.21.3
display-mode media feature{{CompatUnknown}}{{CompatNo}}{{ CompatGeckoDesktop(47) }}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support (all, print, screen)1.0{{CompatVersionUnknown}}{{ CompatGeckoMobile(1.7) }}{{CompatVersionUnknown}}9.03.1
speech{{CompatNo}}{{CompatNo}}{{CompatNo}}{{CompatNo}}9.0{{CompatNo}}
Media features1.0{{CompatVersionUnknown}}{{ CompatGeckoMobile(1.7) }}{{CompatVersionUnknown}}9.03.1
display-mode media feature{{CompatUnknown}}{{CompatNo}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

See also

+ + diff --git a/files/zh-tw/web/css/@viewport/height/index.html b/files/zh-tw/web/css/@viewport/height/index.html new file mode 100644 index 0000000000..e883d44041 --- /dev/null +++ b/files/zh-tw/web/css/@viewport/height/index.html @@ -0,0 +1,120 @@ +--- +title: height +slug: Web/CSS/@viewport/height +translation_of: Web/CSS/@viewport +--- +
{{CSSRef}}
+ +

概要

+ +

高度 的 CSS 描述符是用於設定兩者的簡易描述符 {{cssxref("@viewport/min-height", "min-height")}} 與 {{cssxref("@viewport/max-height", "max-height")}} 的可視區域(viewport)。提供一個可視區域的長度值,將設定兩者的最小高度與最大高度的值。

+ +

如果提供了兩個可視區域(viewport),第一個值將設定為最小高度,而第二個值將設定為最大高度。

+ +

語法

+ +
/* One value */
+height: auto;
+height: 320px;
+height: 15em;
+
+/* Two values */
+height: 320px 200px;
+
+ +

+ +
+
auto
+
使用 CSS 描述符來進行值的計算。
+
<length>
+
非負絕對值或相對長度。
+
<percentage>
+
初始可視區域的相對寬度或相對高度百分比的縮放係數為 1.0,且必須是非負數。
+
+ +

正式語法

+ +
{{csssyntax}}
+
+ +

舉例

+ +
@viewport {
+  height: 500px;
+}
+ +

格式

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Device', '#descdef-viewport-height', '"height" descriptor')}}{{Spec2('CSS3 Device')}}Initial definition
+ +

瀏覽器兼容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support29 (behind a flag){{CompatNo}}10 {{property_prefix("-ms")}}11.10
+ Removed in 15
+ Reintroduced behind a flag in 16
{{CompatNo}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support4.429{{CompatNo}}10{{property_prefix("-ms")}}11.10
+ Removed in 15
+ Reintroduced behind a flag in 16
{{CompatNo}}
+
diff --git a/files/zh-tw/web/css/@viewport/index.html b/files/zh-tw/web/css/@viewport/index.html new file mode 100644 index 0000000000..f03aaee77b --- /dev/null +++ b/files/zh-tw/web/css/@viewport/index.html @@ -0,0 +1,159 @@ +--- +title: '@viewport' +slug: Web/CSS/@viewport +tags: + - Adaptation + - At-rule + - CSS + - Device + - NeedsContent + - NeedsTranslation + - Reference + - TopicStub +translation_of: Web/CSS/@viewport +--- +

{{CSSRef}}

+ +

Summary

+ +

The @viewport CSS at-rule contains a set of nested descriptors in a CSS block that is delimited by curly braces. These descriptors control viewport settings, primarily on mobile devices.

+ +

Syntax

+ +

A zoom factor of 1.0 or 100% corresponds to no zooming. Larger values zoom in. Smaller values zoom out.

+ +

Descriptors

+ +

Browsers are supposed to ignore unrecognized descriptors.

+ +
+
min-width
+
Used in the determination of the width of the viewport when the document is first displayed.
+
max-width
+
Used in the determination of the width of the viewport when the document is first displayed.
+
width
+
A shorthand descriptor for setting both min-width and max-width
+
min-height
+
Used in the determination of the height of the viewport when the document is first displayed.
+
max-height
+
Used in the determination of the height of the viewport when the document is first displayed.
+
height
+
A shorthand descriptor for setting both min-height and max-height
+
zoom
+
Sets the initial zoom factor.
+
min-zoom
+
Sets the minimum zoom factor.
+
max-zoom
+
Sets the maximum zoom factor.
+
user-zoom
+
Controls whether or not the user should be able to change the zoom factor.
+
orientation
+
Controls the document's orientation.
+
+ +

Formal syntax

+ +
{{csssyntax}}
+ +

Examples

+ +
@viewport {
+  min-width: 640px;
+  max-width: 800px;
+}
+@viewport {
+  zoom: 0.75;
+  min-zoom: 0.5;
+  max-zoom: 0.9;
+}
+@viewport {
+  orientation: landscape;
+}
+ +

Specifications

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Device', '#the-atviewport-rule', '@viewport')}}{{Spec2('CSS3 Device')}}Initial definition
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support29 (behind a flag) [4]{{CompatNo()}} [2]10 {{property_prefix("-ms")}}11.10
+ Removed in 15
+ Reintroduced behind a flag in 16
{{CompatNo}} [3]
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support4.429{{CompatNo}} [2]10{{property_prefix("-ms")}}[1]11.10
+ Removed in 15
+ Reintroduced behind a flag in 16
{{CompatNo}} [3]
+
+ +

[1] There is a bug in IE Mobile 10 on older versions of Windows Phone 8, where device-width, when used within @-ms-viewport, evaluates to the screen width in physical pixels rather than normalized CSS pixels, which is wrong according to the specification. However, when used within a viewport {{HTMLElement("meta")}} tag, device-width evaluates correctly. According to Microsoft, this bug was fixed in Windows Phone 8 Update 3 (a.k.a. GDR3), although there are some reports that the Lumia Black GDR3 update did not fix the bug (at least on the Lumia 920). For more details and a workaround, see Tim Kadlec's blog post "Windows Phone 8 and Device-Width".

+ +

[2]: See {{bug(747754, 'summary')}}

+ +

[3]: See {{webkitbug(95959)}}

+

[4]: See Chromium issue #235457: Enable @viewport on all platforms

+

See also

+ + diff --git a/files/zh-tw/web/css/_colon_first-child/index.html b/files/zh-tw/web/css/_colon_first-child/index.html new file mode 100644 index 0000000000..195449ca3d --- /dev/null +++ b/files/zh-tw/web/css/_colon_first-child/index.html @@ -0,0 +1,154 @@ +--- +title: ':first-child' +slug: 'Web/CSS/:first-child' +tags: + - CSS + - CSS Pseudo-class + - Layout + - Reference + - Web +translation_of: 'Web/CSS/:first-child' +--- +
{{CSSRef}}
+ +

:first-childCSS當中的一種偽類別(pseudo-class),代表任何身為長子的元素(親元素的第一個子元素)。

+ +

語法

+ +
{{csssyntax}}
+
+ +

範例

+ +

範例 1

+ +

HTML 內文

+ +
<div>
+  <span>This span is limed!</span>
+  <span>This span is not. :(</span>
+</div>
+
+ +

CSS 內文

+ +
span:first-child {
+    background-color: lime;
+}
+
+ +

呈現效果如下:

+ +

{{EmbedLiveSample('範例_1',300,50)}}

+ +

範例 2 - 使用 UL

+ +

HTML 內文

+ +
<ul>
+  <li>List 1</li>
+  <li>List 2</li>
+  <li>List 3</li>
+</ul>
+ +

CSS 內文

+ +
li{
+  color:red;
+}
+li:first-child{
+  color:green;
+}
+ +

呈現效果如下:

+ +

{{EmbedLiveSample('範例_2_-_使用_UL',300,100)}}

+ +

規格

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
規格狀態註解
{{SpecName('CSS4 Selectors', '#first-child-pseudo', ':first-child')}}{{Spec2('CSS4 Selectors')}}無變更
{{SpecName('CSS3 Selectors', '#first-child-pseudo', ':first-child')}}{{Spec2('CSS3 Selectors')}}無變更
{{SpecName('CSS2.1', 'selector.html#first-child', ':first-child')}}{{Spec2('CSS2.1')}}初始定義
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
功能ChromeFirefox (Gecko)Internet ExplorerOperaSafari
基礎支援4.0{{CompatGeckoDesktop("1.9")}}7[1]9.54
+
+ +
+ + + + + + + + + + + + + + + + + + + +
功能AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
基礎支援1.0{{CompatGeckoMobile("1.9.1")}}7[1]10.03.1
+
+ +

[1] 在不重新載入網頁的情況下,Internet Explorer 7 的樣式表並不會套用在動態新增的元素上。在 Internet Explorer 8,若元素是以點擊連結而形成的,則 first-child 在該連結不被選取後才有作用。

+ +

參見

+ + diff --git a/files/zh-tw/web/css/_colon_first-of-type/index.html b/files/zh-tw/web/css/_colon_first-of-type/index.html new file mode 100644 index 0000000000..93a524c4b7 --- /dev/null +++ b/files/zh-tw/web/css/_colon_first-of-type/index.html @@ -0,0 +1,162 @@ +--- +title: ':first-of-type' +slug: 'Web/CSS/:first-of-type' +tags: + - CSS + - CSS 虛擬類別 + - 參考 + - 外觀 + - 網頁 +translation_of: 'Web/CSS/:first-of-type' +--- +
{{CSSRef}}
+ +

在 CSS 虛擬類別(pseudo-class)中,:first-of-type 代表本節點為兄弟節點中第一個此類型節點。

+ +
/* 選取第一個出現在父節點下的<p>,不考慮其在所有子節點中的位置。 */
+p:first-of-type {
+  color: red;
+}
+ +
+

附註: 在初始定義中,被選取的節點必須擁有父節點。從選取器層級4(Selectors Level 4)開始已經不再有這個限制了。

+
+ +

語法

+ +
{{csssyntax}}
+
+ +

範例

+ +

例一:選取第一段文章

+ +

來考慮以下 HTML:

+ +
<h2>Heading</h2>
+
+<p>Paragraph</p>
+
+<p>Paragraph</p>
+ +

及 CSS:

+ +
p:first-of-type {
+  color: red;
+}
+ +

會有這樣的效果 - 只有第一段文章變為紅色,因為它是 body 中第一個文章節點:

+ +

{{EmbedLiveSample('Example_1_Simple_first_paragraph')}}

+ +

例二:預定通用選擇器(Assumed universal selector)

+ +

這個範例展示了當沒有指定一般選擇器(simple selector)時,通用選擇器是如何被預判。

+ +

首先來看 HTML:

+ +
<div>
+  <span>This `span` is first!</span>
+  <span>But this `span` isn't.</span>
+  <span>This <em>nested `em` is</em>!</span>
+  <span>And so is this <span>nested `span`</span>!</span>
+  <b>This `b` qualifies!</b>
+  <span>This final `span` does not.</span>
+</div>
+
+ +

接著是 CSS:

+ +
div :first-of-type {
+  background-color: lime;
+}
+ +

會有這樣的效果:

+ +

{{EmbedLiveSample('Example_2_Assumed_universal_selector','100%', '120')}}

+ +

特定規格

+ + + + + + + + + + + + + + + + + + + + + +
規格狀態附註
{{SpecName('CSS4 Selectors', '#first-of-type-pseudo', ':first-of-type')}}{{Spec2('CSS4 Selectors')}}配對節點不需要具有父節點。
{{SpecName('CSS3 Selectors', '#first-of-type-pseudo', ':first-of-type')}}{{Spec2('CSS3 Selectors')}}初始定義。
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9.1")}}9.09.53.2
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support2.1{{CompatVersionUnknown}}{{CompatGeckoMobile("1.9.1")}}9.010.03.2
+
+ +

參見

+ + diff --git a/files/zh-tw/web/css/_colon_lang/index.html b/files/zh-tw/web/css/_colon_lang/index.html new file mode 100644 index 0000000000..f79d142f09 --- /dev/null +++ b/files/zh-tw/web/css/_colon_lang/index.html @@ -0,0 +1,98 @@ +--- +title: ':lang()' +slug: 'Web/CSS/:lang' +translation_of: 'Web/CSS/:lang' +--- +
{{CSSRef}}
+ +

:lang() 是一種 CSS 偽類 ( pseudo-class )。它會根據括號中指定的語系,來選擇使用的元素。

+ +
/* 選取任何語言屬性為英文 (en) 的 <p> */
+p:lang(en) {
+  quotes: '\201C' '\201D' '\2018' '\2019';
+}
+ +
+

注意: 在 HTML 中,語言是通過 {{htmlattrxref("lang")}} 屬性和 {{HTMLElement("meta")}} 元素的組合來決定的, 也可能是通過協議的信息來確定 (例如 HTTP 表頭). 對於其他文檔類型,也可能存在其他用於確定語言的方法。

+
+ +

語法 Syntax

+ +

語法格式 Formal syntax

+ +
{{csssyntax}}
+ +

參數 Parameter

+ +
+
<language-code>
+
{{cssxref("<string>")}} 代表你要指定的語言。可接受的值為 HTML 規範中指定的值。
+
+ +

範例 Example

+ +

在此例中,:lang() 偽類 會依據 “引用元素 quote” ({{htmlElement("q")}}) 的父層來選擇 子組合子 ( child combinators )。 請注意,此處演示的方法並不是唯一的,並且最好的方式,是依據文檔類型來確定。還要注意的是, {{glossary("Unicode")}} 的值,有明確指定到那些你要使用的字符。

+ +

HTML

+ +
<div lang="en"><q>This English quote has a <q>nested</q> quote inside.</q></div>
+<div lang="fr"><q>This French quote has a <q>nested</q> quote inside.</q></div>
+<div lang="de"><q>This German quote has a <q>nested</q> quote inside.</q></div>
+
+ +

CSS

+ +
:lang(en) > q { quotes: '\201C' '\201D' '\2018' '\2019'; }
+:lang(fr) > q { quotes: '« ' ' »'; }
+:lang(de) > q { quotes: '»' '«' '\2039' '\203A'; }
+
+ +

結果 Result

+ +

{{EmbedLiveSample('Example', 350)}}

+ +

技術規格 Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
規格 Specification狀態 Status註 Comment
{{SpecName('CSS4 Selectors', '#lang-pseudo', ':lang()')}}{{Spec2('CSS4 Selectors')}}Adds wildcard language matching and comma-separated list of languages.
+ 添加萬用字符語言匹配,且逗號分隔語言列表。
{{SpecName('CSS3 Selectors', '#lang-pseudo', ':lang()')}}{{Spec2('CSS3 Selectors')}}沒有重大變化。
{{SpecName('CSS2.1', 'selector.html#lang', ':lang()')}}{{Spec2('CSS2.1')}}初步定義。
+ +

瀏覽器兼容性 Browser compatibility

+ +
+ + +

{{Compat("css.selectors.lang")}}

+
+ +

其他參考 See also

+ + diff --git a/files/zh-tw/web/css/_colon_target/index.html b/files/zh-tw/web/css/_colon_target/index.html new file mode 100644 index 0000000000..74d1767fb9 --- /dev/null +++ b/files/zh-tw/web/css/_colon_target/index.html @@ -0,0 +1,275 @@ +--- +title: ':target' +slug: 'Web/CSS/:target' +translation_of: 'Web/CSS/:target' +--- +
{{CSSRef}}
+ +

The :target pseudo-class represents the unique element, if any, with an id matching the fragment identifier of the URI of the document..

+ +

URIs with fragment identifiers link to a certain element within the document, known as the target element. For instance, here is a URI pointing to an anchor named section2:
+ http://example.com/folder/document.html#section2
+ The anchor can be any element with an id attribute, e.g. <h1 id="section2"> in our example. The target element h1 can be represented by the :target pseudo-class.

+ +
Note: The id attribute was new in HTML 4 (December 1997).  In old-style HTML <a> is a target element.  The :target pseudo-class applies to those targets as well.
+ +

範例

+ +
:target { outline: solid red }  /* draw a red, solid line around the target element */
+
+ +
/* example code for userContent.css or any web pages;
+   a red/yellow arrow indicates the target element */
+
+:target {
+ -webkit-box-shadow: 0.2em 0.2em 0.3em #888;
+    -moz-box-shadow: 0.2em 0.2em 0.3em #888;
+         box-shadow: 0.2em 0.2em 0.3em #888;
+}
+
+:target:before {
+  font:           70% Arial,"Nimbus Sans L",sans-serif !important;
+  content:        "\25ba";  /* ► */
+  color:          red;
+  background:     gold;
+  border:         solid thin;
+  padding-left:   1px;
+  display:        inline-block;
+  margin-right:   0.13em;
+  vertical-align: 20%;
+}
+
+ +

Working with display: none elements…

+ +

The :target pseudo-class also works fine with undisplayed elements:

+ +
<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>:target pseudoclass example</title>
+<style>
+#newcomment {
+  display: none;
+}
+
+#newcomment:target {
+  display: block;
+}
+</style>
+
+</head>
+<body>
+ <p><a href="#newcomment">Add a comment</a></p>
+ <div id="newcomment">
+  <form>
+  <p>Write your comment:<br />
+  <textarea></textarea></p>
+  </form>
+ </div>
+</body>
+</html>
+
+ +

Creating a pure CSS "lightbox"

+ +

The :target pseudo-class is useful to switch on/off some invisible elements. In this way you can create a pure-CSS lightbox (live demo).

+ +
+
<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8" />
+<title>MDN Example &ndash; CSS Lightbox</title>
+<style type="text/css">
+div.lightbox {
+  display: none;
+  position: fixed;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+}
+
+div.lightbox:target {
+  display: table;
+}
+
+div.lightbox figure {
+  display: table-cell;
+  margin: 0;
+  padding: 0;
+  width: 100%;
+  height: 100%;
+  vertical-align: middle;
+}
+
+div.lightbox figure figcaption {
+  display: block;
+  margin: auto;
+  padding: 8px;
+  background-color: #ddbbff;
+  height: 250px;
+  position: relative;
+  overflow: auto;
+  border: 1px #000000 solid;
+  border-radius: 10px;
+  text-align: justify;
+  font-size: 14px;
+}
+
+div.lightbox figure .closemsg {
+  display: block;
+  margin: auto;
+  height: 0;
+  overflow: visible;
+  text-align: right;
+  z-index: 2;
+  cursor: default;
+}
+
+div.lightbox figure .closemsg, div.lightbox figure figcaption {
+  width: 300px;
+}
+
+.closemsg::after {
+  content: "\00D7";
+  display: inline-block;
+  position: relative;
+  right: -20px;
+  top: -10px;
+  z-index: 3;
+  color: #ffffff;
+  border: 1px #ffffff solid;
+  border-radius: 10px;
+  width: 20px;
+  height: 20px;
+  line-height: 18px;
+  text-align: center;
+  margin: 0;
+  background-color: #000000;
+  font-weight: bold;
+  cursor: pointer;
+}
+
+.closemsg::before {
+  content: "";
+  display: block;
+  position: fixed;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  background-color: #000000;
+  opacity: 0.85;
+}
+</style>
+</head>
+
+<body>
+
+<h1>Pure CSS Lightbox</h1>
+
+<p>Some sample text&hellip;</p>
+
+<p>[ <a href="#example1">Open example #1</a> | <a href="#example2">Open example #2</a> ]</p>
+
+<p>Another sample text&hellip;</p>
+
+<div class="lightbox" id="example1">
+  <figure>
+    <a href="#" class="closemsg"></a>
+    <figcaption>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec felis enim, placerat id eleifend eu, semper vel sem. Sed interdum commodo enim venenatis pulvinar. Proin mattis lorem vitae diam scelerisque hendrerit. Fusce cursus imperdiet mauris, vitae hendrerit velit dignissim a. Suspendisse potenti. Aenean feugiat facilisis diam, in posuere sapien mattis vel. Proin molestie rutrum diam, pharetra feugiat ligula sollicitudin sed. Etiam cursus diam quis tellus aliquam gravida. Aliquam erat volutpat.<br />
+    Etiam varius adipiscing mi eget imperdiet. Nulla quis vestibulum leo. Integer molestie massa ut massa commodo in blandit purus aliquam. Mauris sit amet posuere massa. Ut a eleifend augue. Proin sodales mauris nec tellus pharetra dictum.</figcaption>
+  </figure>
+</div>
+
+<div class="lightbox" id="example2">
+  <figure>
+    <a href="#" class="closemsg"></a>
+    <figcaption>Cras risus odio, pharetra nec ultricies et, mollis ac augue. Nunc et diam quis sapien dignissim auctor. Quisque quis neque arcu, nec gravida magna. Etiam ullamcorper augue quis orci posuere et tincidunt augue semper. Maecenas varius augue eu orci auctor bibendum tristique ligula egestas. Morbi pharetra tortor iaculis erat porta id aliquam leo cursus. Ut nec elit vel mauris dapibus lacinia eget sed odio.</figcaption>
+  </figure>
+</div>
+
+</body>
+</html>
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("CSS4 Selectors", "#the-target-pseudo", ":target")}}{{Spec2("CSS4 Selectors")}}No changes
{{SpecName("CSS3 Selectors", "#target-pseudo", ":target")}}{{Spec2("CSS3 Selectors")}}Initial definition
+ +

瀏覽器兼容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0{{CompatGeckoDesktop("1.3")}}99.51.3
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support2.1{{CompatGeckoMobile("1.3")}}9.09.52.0
+
+ +

參見

+ + diff --git a/files/zh-tw/web/css/_doublecolon_first-letter/index.html b/files/zh-tw/web/css/_doublecolon_first-letter/index.html new file mode 100644 index 0000000000..b9d4c7a6f9 --- /dev/null +++ b/files/zh-tw/web/css/_doublecolon_first-letter/index.html @@ -0,0 +1,206 @@ +--- +title: '::first-letter (:first-letter)' +slug: 'Web/CSS/::first-letter' +translation_of: 'Web/CSS/::first-letter' +--- +

{{ CSSRef() }}

+ +

概要

+ +

::first-letter CSS 虛擬元素選取了一個區塊第一行的第一個字母,如果那一行前面沒有其他內容(例如圖片或是行內表格)。

+ +

The first letter of an element is not necessarily trivial to identify:

+ + + +

A first line has meaning only in a block-container box, therefore the ::first-letter pseudo-element has an effect only on elements with a {{ cssxref("display") }} value of block, inline-block, table-cell, list-item or table-caption. In all other cases, ::first-letter has no effect.

+ +

Only a small subset of all CSS properties can be used inside a declaration block of a CSS ruleset containing a selector using the ::first-letter pseudo-element:

+ + + +

As this list will be extended in the future, it is recommended that you not use any other properties inside the declaration block, in order to keep the CSS future-proof.

+ +
+

In CSS 2, pseudo-elements were prefixed with a single colon character. As pseudo-classes were also following the same convention, they were indistinguishable. To solve this, CSS 2.1 changed the convention for pseudo-elements. Now a pseudo-element is prefixed with two colon characters, and a pseudo-class is still prefixed with a single colon.

+ +

As several browsers already implemented the CSS 2 version in a release version, all browsers supporting the two-colon syntax also support the old one-colon syntax.

+ +

If legacy browsers must be supported, :first-letter is the only viable choice; if not, ::first-letter is preferred.

+
+ +

Example

+ +

Make the first letter of every paragraph red and big.

+ +

HTML Content

+ +
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt
+  ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
+  dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor
+  sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy amet.</p>
+<p>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat.</p>
+<p>Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut
+  aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit
+  esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et
+  iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait
+  nulla facilisi.</p>
+<p>-The beginning of a special punctuation mark.</p>
+<p>_The beginning of a special punctuation mark.</p>
+<p>"The beginning of a special punctuation mark.</p>
+<p>'The beginning of a special punctuation mark.</p>
+<p>*The beginning of a special punctuation mark.</p>
+<p>#The beginning of a special punctuation mark.</p>
+<p>「特殊的汉字标点符号开头。</p>
+<p>《特殊的汉字标点符号开头。</p>
+<p>“特殊的汉字标点符号开头。</p>
+ +

CSS Content

+ +
p::first-letter { /* Use :first-letter if support for IE 8 or earlier is needed */
+  color: red;
+  font-size: 130%;
+}
+ +

Output

+ +

{{ EmbedLiveSample('Example', 679, 390) }}

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態註解
{{ SpecName('CSS4 Pseudo-Elements', '#first-letter-pseudo', '::first-letter')}}{{ Spec2('CSS4 Pseudo-Elements')}}Generalized allowed properties to typesetting, text decoration and inline layout properties, {{ cssxref("opacity") }} and {{ cssxref("box-shadow") }}.
{{ SpecName('CSS3 Text Decoration', '#text-shadow', 'text-shadow with ::first-letter')}}{{ Spec2('CSS3 Text Decoration')}}Allowed the usage of {{cssxref("text-shadow")}} with ::first-letter.
{{ SpecName('CSS3 Selectors', '#first-letter', '::first-letter') }}{{ Spec2('CSS3 Selectors') }}Defined edge-case behavior like in list items, or with language specific behavior (like the Dutch digraph IJ). The two-colon syntax for pseudo-elements has been introduced.
{{ SpecName('CSS2.1', 'selector.html#first-letter', '::first-letter') }}{{ Spec2('CSS2.1') }}No significant change, though CSS Level 2 still used the one-colon syntax.
{{ SpecName('CSS1', '#the-first-letter-pseudo-element', '::first-letter') }}{{ Spec2('CSS1') }}The initial definition used the one-colon syntax.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1.0{{ CompatGeckoDesktop("1") }}9.07.01.0 (85)
Old one-colon syntax (:first-letter)1.0{{ CompatGeckoDesktop("1") }}5.53.51.0 (85)
Support for the Dutch digraph IJ{{ CompatNo() }}{{ CompatNo() }} {{ bug("92176") }} {{ CompatNo() }}{{ CompatNo() }}{{ CompatNo() }}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{ CompatUnknown() }}{{ CompatGeckoMobile("1") }}{{ CompatNo() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
Old one-colon syntax (:first-letter){{ CompatUnknown() }}{{ CompatGeckoMobile("1") }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
Support for the Dutch digraph IJ{{ CompatUnknown() }}{{ CompatNo() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/css/animation-fill-mode/index.html b/files/zh-tw/web/css/animation-fill-mode/index.html new file mode 100644 index 0000000000..9ac0552304 --- /dev/null +++ b/files/zh-tw/web/css/animation-fill-mode/index.html @@ -0,0 +1,158 @@ +--- +title: animation-fill-mode +slug: Web/CSS/animation-fill-mode +translation_of: Web/CSS/animation-fill-mode +--- +
 
+ +

animation-fill-mode  CSS 属性指定CSS动画应该如何在其执行前后的样式展示情况。

+ +
/* Single animation */
+animation-fill-mode: none;
+animation-fill-mode: forwards;
+animation-fill-mode: backwards;
+animation-fill-mode: both;
+
+/* Multiple animations */
+animation-fill-mode: none, backwards;
+animation-fill-mode: both, forwards, none;
+
+ +

使用提示 animation 来一次设置所有动画属性通常很方便。

+ +

语法

+ +

属性值

+ +
+
none
+
不执行动画时,动画不会应用任何样式。该元素会使用其keyframes关键动画帧规则来显示动画。这是默认值。
+
forwards
+
动画执行后停留到最后一个关键帧动画的计算值,简单来说执行结束动画会停留到结束时候的状态,不会是动画执行之前的效果。比如一个元素从左往右运动,添加当前属性值 forwards 元素会停留到动画执行结束后的右边而不是最初的左边。可以看以下图
+
+
当然最后动画停留显示的关键帧会取决于 "animation-direction" 和 "animation-iteration-count"这两个属性 运行方向和运行次数: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
animation-directionanimation-iteration-countlast keyframe encountered
normal偶数或奇数值100% 或 to
reverse偶数或奇数值0%from
alternate偶数值0%from
alternate奇数值100%to
alternate-reverse偶数值100%to
alternate-reverse奇数值0%from
+
+
backwards
+
与上面 forwards 值效果相反,动画执行后停留到第一个关键帧动画,准确说是没有执行动画之前的初始状态
+
【(the animation will apply the values defined in the first relevant keyframe as soon as it is applied to the target, and retain this during the "animation-delay" period.)原文大概意思是会停留第一个关键帧,并会保留 "animation-delay" 延迟属性的所设定周期。】
+
会在延迟之后才开始执行关键帧动画,而不是一开始使用第一帧进行停留,具体可以结合both的例子进行尝试。
+
+
第一个相关关键帧会取决于 "animation-direction" 方向属性: + + + + + + + + + + + + + + + + + +
animation-directionfirst relevant keyframe
normal 或 alternate0%from
reversealternate-reverse100%to
+
+
+ +
+
both
+
动画将遵循开始和结束后的帧动画进行停留,也就是说会从第一帧开始停留显示,动画执行之后会停留到动画结束时的状态。
+
+
与上面两个值的差别是,如果元素使用 forwardsbackwards 两个值会在没有添加动画之前的展示状态进行停留,执行动画的时候才会开始执行关键帧,有这么一些细小的差别。
+
+ +
+

PS: 当您在一个animation-*属性上指定多个逗号分隔的值时,它们将被分配给 "animationname" 属性中指定的动画,这取决于有多少动画。有关更多信息,请参见设置多个动画属性值

+
+ +

Example

+ +

You can see the effect of animation-fill-mode in the following example. It demonstrates how, for an animation that runs for an infinite time, you can cause it to remain in its final state rather than reverting to the original state (which is the default).

+ +

HTML

+ +
<p>Move your mouse over the gray box!</p>
+<div class="demo">
+ <div class="growsandstays">This grows and stays big.</div>
+  <div class="grows">This just grows.</div>
+</div>
+ +

CSS

+ +
.demo {
+  border-top: 100px solid #ccc;
+  height: 300px;
+}
+
+@keyframes grow {
+  0% { font-size: 0; }
+  100% { font-size: 40px; }
+}
+
+.demo:hover .grows {
+  animation-name: grow;
+  animation-duration: 3s;
+}
+
+.demo:hover .growsandstays {
+  animation-name: grow;
+  animation-duration: 3s;
+  animation-fill-mode: forwards;
+}
+ +

 

+ +

查看 CSS animations 更多有關的例子

+ +

相關鏈接

+ + diff --git a/files/zh-tw/web/css/attr()/index.html b/files/zh-tw/web/css/attr()/index.html new file mode 100644 index 0000000000..7cce14ec01 --- /dev/null +++ b/files/zh-tw/web/css/attr()/index.html @@ -0,0 +1,200 @@ +--- +title: attr +slug: Web/CSS/attr() +translation_of: Web/CSS/attr() +--- +
{{CSSRef}}
+ +

概要

+ +

attr() CSS 函數使用於樣式取得被選取之元素中特定屬性的值。它也可以用在擬元素選取項(Pseudo-element),在此情形下,其屬性值來自於擬元素選取項相依的原始元素。

+ +

attr() 函數可以被用在任何 CSS 屬性,但除了 content 以外的屬性皆屬於實驗階段。

+ +

語法

+ +
/* Simple usage */
+attr(data-count);
+attr(title);
+
+/* With type */
+attr(src url);
+attr(data-count number);
+attr(data-width px);
+
+/* With fallback */
+attr(data-count number, 0);
+attr(src url, '');
+attr(data-width px, inherit);
+attr(data-something, 'default');
+
+ +

+ +
+
attribute-name
+
在 CSS 中參考之 HTML 元素的屬性名稱。
+
<type-or-unit> {{experimental_inline}}
+
Is a keyword representing either the type of the attribute's value, or its unit, as in HTML some attributes have implicit units. If the use of <type-or-unit> as a value for the given attribute is invalid, the attr() expression will be invalid too. If omitted, it defaults to string. The list of valid values are: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeywordAssociated typeCommentDefault value
string{{cssxref("<string>")}}The attribute value is treated as a CSS {{cssxref("<string>")}}.  It is NOT reparsed, and in particular the characters are used as-is instead of CSS escapes being turned into different characters.An empty string
color {{experimental_inline}}{{cssxref("<color>")}}The attribute value is parsed as a hash (3- or 6-value hash) or a keyword. It must be a valid CSS {{cssxref("<string>")}} value.
+ Leading and trailing spaces are stripped.
currentColor
url {{experimental_inline}}{{cssxref("<uri>")}}The attribute value is parsed as a string that is used inside a CSS url()function.
+ Relative URL are resolved relatively to the original document, not relatively to the style sheet.
+ Leading and trailing spaces are stripped.
The url about:invalid that points to a non-existent document with a generic error condition.
integer {{experimental_inline}}{{cssxref("<integer>")}}The attribute value is parsed as a CSS {{cssxref("<integer>")}}. If it is not valid, that is not an integer or out of the range accepted by the CSS property, the default value is used.
+ Leading and trailing spaces are stripped.
0, or, if 0 is not a valid value for the property, the property's minimum value.
number {{experimental_inline}}{{cssxref("<number>")}}The attribute value is parsed as a CSS {{cssxref("<number>")}}. If it is not valid, that is not a number or out of the range accepted by the CSS property, the default value is used.
+ Leading and trailing spaces are stripped.
0, or, if 0 is not a valid value for the property, the property's minimum value.
length {{experimental_inline}}{{cssxref("<length>")}}The attribute value is parsed as a CSS {{cssxref("<length>")}} dimension, that is including the unit (e.g. 12.5em). If it is not valid, that is not a length or out of the range accepted by the CSS property, the default value is used.
+ If the given unit is a relative length, attr()computes it to an absolute length.
+ Leading and trailing spaces are stripped.
0, or, if 0 is not a valid value for the property, the property's minimum value.
em, ex, px, rem, vw, vh, vmin, vmax, mm, cm, in, pt, or pc {{experimental_inline}}{{cssxref("<length>")}}The attribute value is parsed as a CSS {{cssxref("<number>")}}, that is without the unit (e.g. 12.5), and interpreted as a {{cssxref("<length>")}} with the specified unit. If it is not valid, that is not a number or out of the range accepted by the CSS property, the default value is used.
+ If the given unit is a relative length, attr()computes it to an absolute length.
+ Leading and trailing spaces are stripped.
0, or, if 0 is not a valid value for the property, the property's minimum value.
angle {{experimental_inline}}{{cssxref("<angle>")}}The attribute value is parsed as a CSS {{cssxref("<angle>")}} dimension, that is including the unit (e.g. 30.5deg). If it is not valid, that is not an angle or out of the range accepted by the CSS property, the default value is used.
+ Leading and trailing spaces are stripped.
0deg, or, if 0deg is not a valid value for the property, the property's minimum value.
deg, grad, rad {{experimental_inline}}{{cssxref("<angle>")}}The attribute value is parsed as a CSS {{cssxref("<number>")}}, that is without the unit (e.g. 12.5), and interpreted as an {{cssxref("<angle>")}} with the specified unit. If it is not valid, that is not a number or out of the range accepted by the CSS property, the default value is used.
+ Leading and trailing spaces are stripped.
0deg, or, if 0deg is not a valid value for the property, the property's minimum value.
time {{experimental_inline}}{{cssxref("<time>")}}The attribute value is parsed as a CSS {{cssxref("<time>")}} dimension, that is including the unit (e.g. 30.5ms). If it is not valid, that is not a time or out of the range accepted by the CSS property, the default value is used.
+ Leading and trailing spaces are stripped.
0s, or, if 0s is not a valid value for the property, the property's minimum value.
s, ms {{experimental_inline}}{{cssxref("<time>")}}The attribute value is parsed as a CSS {{cssxref("<number>")}}, that is without the unit (e.g. 12.5), and interpreted as an{{cssxref("<time>")}} with the specified unit. If it is not valid, that is not a number or out of the range accepted by the CSS property, the default value is used.
+ Leading and trailing spaces are stripped.
0s, or, if 0s is not a valid value for the property, the property's minimum value.
frequency {{experimental_inline}}{{cssxref("<frequency>")}}The attribute value is parsed as a CSS {{cssxref("<frequency>")}} dimension, that is including the unit (e.g. 30.5kHz). If it is not valid, that is not a frequency or out of the range accepted by the CSS property, the default value is used.0Hz, or, if 0Hz is not a valid value for the property, the property's minimum value.
Hz, kHz {{experimental_inline}}{{cssxref("<frequency>")}}The attribute value is parsed as a CSS {{cssxref("<number>")}}, that is without the unit (e.g. 12.5), and interpreted as a {{cssxref("<frequency>")}} with the specified unit. If it is not valid, that is not a number or out of the range accepted by the CSS property, the default value is used.
+ Leading and trailing spaces are stripped.
0Hz, or, if 0Hz is not a valid value for the property, the property's minimum value.
% {{experimental_inline}}{{cssxref("<percentage>")}}The attribute value is parsed as a CSS {{cssxref("<number>")}}, that is without the unit (e.g. 12.5), and interpreted as a {{cssxref("<percentage>")}}. If it is not valid, that is not a number or out of the range accepted by the CSS property, the default value is used.
+ If the given value is used as a length, attr()computes it to an absolute length.
+ Leading and trailing spaces are stripped.
0%, or, if 0% is not a valid value for the property, the property's minimum value.
+
+
<fallback> {{experimental_inline}}
+
The value to be used if the associated attribute is missing or contains an invalid value. The fallback value must be valid where attr() is used, even if it is not used, and must not contain another attr() expression. If attr() is not the sole component value of a property, its <fallback> value must be of the type defined by <type-or-unit>. If not set, CSS will use the default value defined for each <type-or-unit>.
+
+ +

形式語法

+ +
{{csssyntax}}
+ +

範例

+ +
p::before {
+  content: attr(data-foo) " ";
+}
+
+ +
<p data-foo="hello">world</p>
+
+ +

結果

+ +

{{EmbedLiveSample("Examples", '100%', '80')}}

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('CSS3 Values', '#attr-notation', 'attr()')}}{{Spec2('CSS3 Values')}}Added two optional parameters; can be used on all properties; may return other values than {{cssxref("<string>")}}. These changes are experimental and may be dropped during the CR phase if browser support is too small.
{{SpecName('CSS2.1', 'generate.html#x18', 'attr()')}}{{Spec2('CSS2.1')}}Limited to the {{cssxref("content")}} property; always return a {{cssxref("<string>")}}.
+ +

瀏覽器相容性

+ +

{{Compat("css.types.attr")}}

diff --git a/files/zh-tw/web/css/background-attachment/index.html b/files/zh-tw/web/css/background-attachment/index.html new file mode 100644 index 0000000000..138623a543 --- /dev/null +++ b/files/zh-tw/web/css/background-attachment/index.html @@ -0,0 +1,151 @@ +--- +title: background-attachment +slug: Web/CSS/background-attachment +tags: + - CSS + - CSS Background + - CSS Property + - Reference +translation_of: Web/CSS/background-attachment +--- +
{{CSSRef}}
+ +

background-attachment 這個 CSS 屬性能夠設定,背景圖片的位置是否要固定在 {{glossary("viewport")}}(視圖)上,還是背景圖片會隨著它的 containing block(外層容器)一起滾動。

+ +
{{EmbedInteractiveExample("pages/css/background-attachment.html")}}
+ + + +

語法

+ +
/* Keyword values */
+background-attachment: scroll;
+background-attachment: fixed;
+background-attachment: local;
+
+/* Global values */
+background-attachment: inherit;
+background-attachment: initial;
+background-attachment: unset;
+
+ +

background-attachment 屬性的值,可以是下方清單中的其中之一。

+ +

Values

+ +
+
fixed
+
讓背景相對於 viewport(視圖)的移動是固定的。即便元素中的內容是可滾動的,背景也不會在滾動元素內容時跟著移動。(這個屬性與 {{cssxref("background-clip", "background-clip: text", "#text")}} 不相容。)
+
local
+
讓背景相對於元素的內容是固定的,且背景在滾動元素的內容時會跟著移動。另外,背景的繪製與定位區域是相對於元素的可滾動區域,而不是包裹著它們的邊框。
+
scroll
+
讓背景相對於元素本身是固定的,使背景在滾動元素的內容時不會跟著移動。(It is effectively attached to the element's border.)
+
+ +

Formal syntax

+ +
{{csssyntax}}
+
+ +

例子

+ +

Simple example

+ +

HTML

+ +
<p>
+  There were doors all round the hall, but they were all locked; and when
+  Alice had been all the way down one side and up the other, trying every
+  door, she walked sadly down the middle, wondering how she was ever to
+  get out again.
+</p>
+ +

CSS

+ +
p {
+  background-image: url("https://mdn.mozillademos.org/files/12057/starsolid.gif");
+  background-attachment: fixed;
+}
+
+ +

Result

+ +

{{EmbedLiveSample("Simple_example")}}

+ +

Multiple background images

+ +

這個屬性支援多個背景圖片。你可以對每個背景設定不同的 <attachment>。每個背景圖片會依序對應在 <attachment> 設定的類型。

+ +

HTML

+ +
<p>
+  There were doors all round the hall, but they were all locked; and when
+  Alice had been all the way down one side and up the other, trying every
+  door, she walked sadly down the middle, wondering how she was ever to
+  get out again.
+
+  Suddenly she came upon a little three-legged table, all made of solid
+  glass; there was nothing on it except a tiny golden key, and Alice's
+  first thought was that it might belong to one of the doors of the hall;
+  but, alas! either the locks were too large, or the key was too small,
+  but at any rate it would not open any of them. However, on the second
+  time round, she came upon a low curtain she had not noticed before, and
+  behind it was a little door about fifteen inches high: she tried the
+  little golden key in the lock, and to her great delight it fitted!
+</p>
+ +

CSS

+ +
p {
+  background-image: url("https://mdn.mozillademos.org/files/12057/starsolid.gif"),
+      url("https://mdn.mozillademos.org/files/12059/startransparent.gif");
+  background-attachment: fixed, scroll;
+  background-repeat: no-repeat, repeat-y;
+}
+ +

Result

+ +

{{EmbedLiveSample("Multiple_background_images")}}

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Backgrounds', '#the-background-attachment', 'background-attachment')}}{{Spec2('CSS3 Backgrounds')}}The shorthand property has been extended to support multiple backgrounds and the local value.
{{SpecName('CSS2.1', 'colors.html#propdef-background-attachment', 'background-attachment')}}{{Spec2('CSS2.1')}}No significant change.
{{SpecName('CSS1', '#background-attachment', 'background-attachment')}}{{Spec2('CSS1')}}No significant change.
+ +

{{cssinfo}}

+ +

Browser compatibility

+ + + +

{{Compat("css.properties.background-attachment")}}

+ +

See also

+ + diff --git a/files/zh-tw/web/css/background-color/index.html b/files/zh-tw/web/css/background-color/index.html new file mode 100644 index 0000000000..3c5cea28b3 --- /dev/null +++ b/files/zh-tw/web/css/background-color/index.html @@ -0,0 +1,115 @@ +--- +title: background-color +slug: Web/CSS/background-color +translation_of: Web/CSS/background-color +--- +
{{CSSRef}}
+ +

background-color CSS property 是用來設定HTML元素的背景顏色,值可以是顏色亦可以是特定關鍵字-- transparent.

+ +

語法

+ +
background-color: red;
+background-color: rgb(255, 255, 128);
+background-color: hsla(50, 33%, 25%, 0.75);
+background-color: currentColor;
+background-color: transparent;
+background-color: #bbff00;
+
+background-color: inherit;
+
+ +

參數

+ +
+
<color>
+
一個 CSS {{cssxref("<color>")}} 用來表示一致的背景顏色。即便設定了一個或多個 {{cssxref("background-image")}} ,背景渲染上依舊會渲染這顏色,若是圖片並非不透明圖,在透明區域就能看見。在 CSS 中, transparent 是一種顏色
+
+ +

正式語法

+ +
{{csssyntax}}
+ +

範例

+ +

HTML

+ +
<div class="exampleone">
+ Lorem ipsum dolor sit amet, consectetuer
+</div>
+
+<div class="exampletwo">
+  Lorem ipsum dolor sit amet, consectetuer
+</div>
+
+<div class="examplethree">
+  Lorem ipsum dolor sit amet, consectetuer
+</div>
+ +

CSS

+ +
.exampleone {
+  background-color: teal;
+  color: white;
+}
+
+.exampletwo {
+  background-color: rgb(153,102,153);
+  color: rgb(255,255,204);
+}
+
+.examplethree {
+  background-color: #777799;
+  color: #FFFFFF;
+}
+
+ +

Result

+ +

{{EmbedLiveSample("範例","200","150")}}

+ +

規格定義

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Backgrounds', '#background-color', 'background-color')}}{{Spec2('CSS3 Backgrounds')}}技術上來說,移除了 transparent 關鍵字,但實際上並未發生任何改變,因為它被列入至正式的 {{cssxref("<color>")}}
{{SpecName('CSS2.1', 'colors.html#propdef-background-color', 'background-color')}}{{Spec2('CSS2.1')}}無變動
{{SpecName('CSS1', '#background-color', 'background-color')}}{{Spec2('CSS1')}}原始定義。
+ +

{{cssinfo}}

+ +

Browser compatibility

+ + + + + +

{{Compat("css.properties.background-color")}}

+

延伸閱讀

+ + diff --git a/files/zh-tw/web/css/border-image/border-image/index.html b/files/zh-tw/web/css/border-image/border-image/index.html new file mode 100644 index 0000000000..210a2663eb --- /dev/null +++ b/files/zh-tw/web/css/border-image/border-image/index.html @@ -0,0 +1,111 @@ +--- +title: border-image +slug: Web/CSS/border-image/border-image +tags: + - CSS +--- +

摘要

+ +

CSS 屬性 border-image 可以讓你在元素的邊框上擺上圖片。這讓呈現看似很複雜的一個網頁的小單元簡單很多,它可以省最多九個元素。

+ +
緊告:官方的 CSS3 規範描述的 border-image 屬性在這個功能被凍結並出現在 Gecko 1.9.1 的釋出版之後改變很多。因此,這項功能的語法跟呈現方法很可能在未來 Gecko 的釋出版改變。特別是選擇性的 border-width 參數,它覆蓋既有 border-width 取值的這項特性已經從規範移除了,因此勢必也會在未來的 Gecko 被拿掉。
+ +

瀏覽器會顯示 border-image 指定的圖片而不是 {{ cssxref("border-style") }} 給的邊框樣式,但是若它的取值是 none 或是因某些理由無法顯示該圖片,瀏覽器就會顯示邊框樣式。border-image 會畫一個額外的背景圖片在原來 {{ cssxref("background-image") }} 指 定的背景圖片之上。

+ + + +

語法

+ +
none |
+  [ <圖片> [ <數字> | <百分比> ]{1,4} [/ <邊框寬度>{1,4}]? ] && [ stretch | repeat | round ]{0,2} 
+ +

取值

+ +
+
none
+
不顯示圖片,使用邊框樣式。
+
<圖片> (必填)
+
圖片值是一個 {{cssxref("<uri>")}},例: url(http://example.org/image.png)
+
<數> | <百分比> (必填)
+
一個、兩個、三個、四個分別代表從頂邊、右邊、底邊、左邊從圖片外圍到切圖線的距離,將圖片切為九塊:四個角、四個邊跟一個中間部份。
+
+ 一個值的話,該值用於圖片的全部四個邊。
+ 兩個值得話,值用於:一、頂邊與底邊 二、右邊與左邊。
+ 三個值的話,值用於:一、頂邊 二、右邊與左邊 三、底邊。
+ 四個值的情況,四個值分邊用在圖片的頂邊、右邊、底邊、左邊。
+
+ 在 Gecko 1.9.1 (Firefox 3.5) 圖片的中間那個部份會被當做元素的背景。這在未來的版本可能會改變。
+
+ 百分比 由圖片的長度/寬度計算。
+ 但表圖片的像素(若為點陣圖)或向量座標(若為 SVG)。
+
<邊框寬度> (選擇性)
+
如果斜線 / 出現在屬性值的話,一個、兩個、三個或是四個在它之後的取值會被當成是 {{ cssxref("border-width") }} 的取值使用。取值的順序如同 {{ cssxref("border-width") }} 。
+
stretch | round | repeat (選擇性)
+
一個或兩個關鍵字,指定邊上的圖片跟中間部份要如何縮放及鋪擺。
+ stretch (預設值)縮放該圖片,使其與配置大小相等。
+ round 鋪擺該圖片,但也縮放它使得被配置範圍鋪滿整數張該圖片。
+ repeat   直接鋪擺該圖片。
+ 第一個關鍵字的對象是頂邊,中間跟底邊的圖片,而第二個關鍵字的對象是左邊跟右邊的邊框。如果第二個不存在,則沿用第一個關鍵字的設定。如果兩者皆不存在,預設值為 stretch
+
+ +

範例

+ +

[這裡還需要一些活範例]

+ +
#header  { -moz-border-image: url(border.png) 27 27 27 27 round round; }
+
+.button  { -moz-border-image: url(button.png) 0 5 0 5; }
+
+.example { -moz-border-image: url(example.jpg) 3 4 6 8 / 10px 12px 14px 22px; }
+
+ +
/* 鮮見例,在 Firefox 3.5 下看起來像是完全伸展的 background-image */
+
+ div     { -moz-border-image: url(bgimage.png) 0; }
+
+ +

瀏覽器兼容性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
瀏覽器最小版本支援
Internet Explorer------
Firefox (Gecko)3.5 (1.9.1)-moz-border-image
Opera10.5border-image
Safari (WebKit)3.0 (522)-webkit-border-image
+ +

規範

+ + + +

{{ languages( { "en": "en/CSS/-moz-border-image"} ) }}

diff --git a/files/zh-tw/web/css/border-image/index.html b/files/zh-tw/web/css/border-image/index.html new file mode 100644 index 0000000000..bd553c7d6e --- /dev/null +++ b/files/zh-tw/web/css/border-image/index.html @@ -0,0 +1,9 @@ +--- +title: border-image +slug: Web/CSS/border-image +--- +

 

+ +

This page was auto-generated because a user created a sub-page to this page.

+ +

 

diff --git a/files/zh-tw/web/css/border/index.html b/files/zh-tw/web/css/border/index.html new file mode 100644 index 0000000000..b7a8d098e3 --- /dev/null +++ b/files/zh-tw/web/css/border/index.html @@ -0,0 +1,134 @@ +--- +title: border +slug: Web/CSS/border +tags: + - CSS + - CSS Borders + - CSS Property + - Layout + - Reference +translation_of: Web/CSS/border +--- +
{{CSSRef("CSS Borders")}}
+ +

border shorthand CSS 屬性可用來設定元素的邊框。它可以設定以下的值 {{Cssxref("border-width")}}、{{Cssxref("border-style")}} 以及 {{Cssxref("border-color")}}。

+ +
{{EmbedInteractiveExample("pages/css/border.html")}}
+ + + +

As with all shorthand properties, any omitted sub-values will be set to their initial value. Importantly, border cannot be used to specify a custom value for {{cssxref("border-image")}}, but instead sets it to its initial value, i.e., none.

+ +

The border shorthand is especially useful when you want all four borders to be the same. To make them different from each other, however, you can use the longhand {{Cssxref("border-width")}}, {{Cssxref("border-style")}}, and {{Cssxref("border-color")}} properties, which accept different values for each side. Alternatively, you can target one border at a time with the physical (e.g., {{Cssxref("border-top")}} ) and logical (e.g., {{Cssxref("border-block-start")}}) border properties.

+ +

Borders vs. outlines

+ +

Borders and outlines are very similar. However, outlines differ from borders in the following ways:

+ + + +

Syntax

+ +
/* style */
+border: solid;
+
+/* width | style */
+border: 2px dotted;
+
+/* style | color */
+border: outset #f33;
+
+/* width | style | color */
+border: medium dashed green;
+
+/* Global values */
+border: inherit;
+border: initial;
+border: unset;
+
+ +

The border property may be specified using one, two, or three of the values listed below. The order of the values does not matter.

+ +
+

Note: The border will be invisible if its style is not defined. This is because the style defaults to none.

+
+ +

Values

+ +
+
<line-width>
+
Sets the thickness of the border. Defaults to medium if absent. See {{Cssxref("border-width")}}.
+
<line-style>
+
Sets the style of the border. Defaults to none if absent. See {{Cssxref("border-style")}}.
+
{{cssxref("<color>")}}
+
Sets the color of the border. Defaults to currentcolor if absent. See {{Cssxref("border-color")}}.
+
+ +

Formal syntax

+ +
{{csssyntax}}
+ +

Example

+ +

HTML

+ +
<div>I have a border, an outline, AND a box shadow! Amazing, isn't it?</div>
+
+ +

CSS

+ +
div {
+  border: 0.5rem outset pink;
+  outline: 0.5rem solid khaki;
+  box-shadow: 0 0 0 2rem skyblue;
+  border-radius: 12px;
+  font: bold 1rem sans-serif;
+  margin: 2rem;
+  padding: 1rem;
+  outline-offset: 0.5rem;
+}
+ +

Result

+ +

{{EmbedLiveSample('Example')}}

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Backgrounds', '#the-border-shorthands', 'border')}}{{Spec2('CSS3 Backgrounds')}}Removes specific support for transparent, as it is now a valid {{cssxref("<color>")}}; this has no practical impact.
+ Though it cannot be set to a custom value using the shorthand, border now resets {{cssxref("border-image")}} to its initial value (none).
{{SpecName('CSS2.1', 'box.html#border-shorthand-properties', 'border')}}{{Spec2('CSS2.1')}}Accepts the inherit keyword. Also accepts transparent as a valid color.
{{SpecName('CSS1', '#border', 'border')}}{{Spec2('CSS1')}}Initial definition.
+ +

{{cssinfo}}

+ +

Browser compatibility

+ + + +

{{Compat("css.properties.border")}}

diff --git a/files/zh-tw/web/css/box-shadow/index.html b/files/zh-tw/web/css/box-shadow/index.html new file mode 100644 index 0000000000..4d23dc2d13 --- /dev/null +++ b/files/zh-tw/web/css/box-shadow/index.html @@ -0,0 +1,228 @@ +--- +title: box-shadow +slug: Web/CSS/box-shadow +tags: + - CSS + - CSS Backgrounds and Borders + - CSS Property + - CSS Styles + - HTML Colors + - Reference + - Shadows + - Styles + - Styling HTML + - box-shadow +translation_of: Web/CSS/box-shadow +--- +

{{CSSRef}}

+ +

box-shadow 屬性為一個逗號分隔的列表描述一個或多個的陰影效果. 這使的你能夠從幾乎任何元素的框架放入陰影. 如果一個標記了 {{cssxref("border-radius")}} 的元素也標記了 box shadow, 這將使得他們有相同的圓邊. 多重 box shadows 的 z-index 排序跟多重 text shadows 一樣(第一個備標記的陰影在最上面).

+ +

{{cssinfo}}

+ +

Box-shadow 產生器

+ +

Interactive tool 可以產生 box-shadow.

+ +

表達式

+ +
/* offset-x | offset-y | color */
+box-shadow: 60px -16px teal;
+
+/* offset-x | offset-y | blur-radius | color */
+box-shadow: 10px 5px 5px black;
+
+/* offset-x | offset-y | blur-radius | spread-radius | color */
+box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);
+
+/* inset | offset-x | offset-y | color */
+box-shadow: inset 5em 1em gold;
+
+/* Any number of shadows, separated by commas */
+box-shadow: 3px 3px red, -1em 0 0.4em olive;
+
+ +

參數

+ +
+

+ inset
+ 如果未指定(默認),則假定陰影為陰影(就好像該框被提升到內容之上)。 inset關鍵字的存在將陰影更改為幀內的陰影(就好像內容在框內被壓下)。在邊框內部(甚至是透明的)繪製插入陰影,在背景上方,但在內容下方。
+
+ <offset-x> <offset-y>
+ 這兩個 {{cssxref("<length>")}} 值用於設置陰影偏移量。 <offset-x>指定水平距離。負值將陰影置於元素的左側。 <offset-y>指定垂直距離。負值將陰影置於元素上方。有關可能的單位,請參見 {{cssxref("<length>")}}。 如果兩個值均為0,則陰影位於元素後面(如果設置了<blur-radius>和/或<spread-radius>,則可能會生成模糊效果)。
+
+ <blur-radius>
+ 這是第三個 {{cssxref("<length>")}} 值。此值越大,模糊越大,陰影變得越來越大。不允許使用負值。如果未指定,則為0(陰影邊緣清晰)。
+
+ <spread-radius>
+ 這是第四個 {{cssxref("<length>")}} 值。正值將導致陰影擴大並變大,負值將導致陰影縮小。如果未指定,則為0(陰影將與元素的大小相同)。
+
+ <color>
+ 有關可能的關鍵字和符號,請參閱 {{cssxref("<color>")}} 值。 如果未指定,則使用的顏色取決於瀏覽器 - 它通常是 {{cssxref("color")}} 屬性的值,但請注意,Safari在此情況下當前繪製透明陰影。
+
+ +

語法

+ +
{{csssyntax}}
+ +

範例

+ + + +
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
+
+ +
box-shadow: 60px -16px teal;
+ +
box-shadow: 10px 5px 5px black;
+ +
box-shadow: 3px 3px red, -1em 0 0.4em olive;
+ +
box-shadow: inset 5em 1em gold;
+ +
box-shadow: 0 0 1em gold;
+ +
box-shadow: inset 0 0 1em gold;
+ +
box-shadow: inset 0 0 1em gold, 0 0 1em red;
+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Backgrounds', '#box-shadow', 'box-shadow')}}{{Spec2('CSS3 Backgrounds')}}Initial definition
+ +

瀏覽相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support10.0[1]
+ 1.0{{property_prefix("-webkit")}}
{{CompatGeckoDesktop("2.0")}}[3]
+ {{CompatGeckoDesktop("1.9.1")}}{{property_prefix("-moz")}}
9.0[2]10.5[1]5.1[1]
+ 3.0 {{property_prefix("-webkit")}}
Multiple shadows10.0
+ 1.0{{property_prefix("-webkit")}}
{{CompatGeckoDesktop("2.0")}}
+ {{CompatGeckoDesktop("1.9.1")}}{{property_prefix("-moz")}}
9.010.55.1
+ 3.0 {{property_prefix("-webkit")}}
inset keyword10.0
+ 4.0{{property_prefix("-webkit")}}
{{CompatGeckoDesktop("2.0")}}
+ {{CompatGeckoDesktop("1.9.1")}}{{property_prefix("-moz")}}
9.010.55.1
+ 5.0 {{property_prefix("-webkit")}}
Spread radius10.0
+ 4.0{{property_prefix("-webkit")}}
{{CompatGeckoDesktop("2.0")}}
+ {{CompatGeckoDesktop("1.9.1")}}{{property_prefix("-moz")}}
9.010.55.1
+ 5.0 {{property_prefix("-webkit")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureSafari MobileOpera MiniOpera MobileAndroid
Basic support +

5.0[1]
+ {{CompatVersionUnknown }}{{ property_prefix("-webkit")}}

+
{{CompatUnknown}}{{CompatVersionUnknown }}[1]{{CompatVersionUnknown }}{{property_prefix("-webkit")}}[1]
Multiple shadows5.0
+ {{CompatVersionUnknown }}{{ property_prefix("-webkit")}}
{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
inset keyword5.0
+ {{CompatVersionUnknown }}{{ property_prefix("-webkit")}}
{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
Spread radius5.0
+ {{CompatVersionUnknown }}{{ property_prefix("-webkit")}}
{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Shadows affect layout in older Gecko, Presto, and WebKit; e.g. if you cast an outer shadow to a box with a width of 100%, you'll see a scrollbar.

+ +

[2] Since version 5.5, Internet Explorer supports Microsoft's DropShadow and Shadow Filter. You can use this proprietary extension to cast a drop shadow (though the syntax and the effect are different from CSS3). In order to get box-shadow in IE9 or later, you need to set {{cssxref("border-collapse")}} to separate.

+ +

[3] Gecko 13 {{geckoRelease(13)}} removed support for -moz-box-shadow. Since then, only the unprefixed version is supported. Shadows affect layout in older Gecko, Presto, and WebKit; e.g. if you cast an outer shadow to a box with a width of 100%, you'll see a scrollbar.

diff --git a/files/zh-tw/web/css/box-sizing/index.html b/files/zh-tw/web/css/box-sizing/index.html new file mode 100644 index 0000000000..058f179918 --- /dev/null +++ b/files/zh-tw/web/css/box-sizing/index.html @@ -0,0 +1,94 @@ +--- +title: box-sizing +slug: Web/CSS/box-sizing +tags: + - CSS + - CSS Box Model + - CSS Property + - Experimental + - Reference + - border-box + - box model + - content-box +translation_of: Web/CSS/box-sizing +--- +
{{CSSRef}}{{SeeCompatTable}}
+ +

概要

+ +

The box-sizing property is used to alter the default CSS box model used to calculate width and height of the elements. It is possible to use this property to emulate the behavior of browsers that do not correctly support the CSS box model specification.

+ +

box-sizing  屬性 用於更改預設 CSS 盒子模型 中所計算的寬度和高度。可以使用此屬性來模擬不正確支持CSS盒子模型規範的瀏覽器的行為。

+ +

{{cssinfo}}

+ +

句法

+ +
/* Keyword values */
+box-sizing: content-box;
+box-sizing: border-box;
+
+/* Global values */
+box-sizing: inherit;
+box-sizing: initial;
+box-sizing: unset;
+
+ +

+ +
+
content-box
+
這是根據 CSS 標準的起始值和預設值。 {{Cssxref("width")}}  與  {{Cssxref("height")}} 只包括內容本身的寬和高, 不包括邊框(border)、內邊距(padding)、外邊距(margin)。注意:內邊距、邊框和外邊距都在這個盒子的外部。例如,如果 .box {width: 350px}; 而且 {border: 10px solid black;} ,那麼在瀏覽器中的渲染該容器的實際寬度將是370px,;
+
+ 簡單來說,尺寸計算公式:width = 內容的寬度,height = 內容的高度。寬度和高度都不包含內容的邊框(border)和內邊距(padding)。
+
border-box
+
 {{Cssxref("width")}} 和 {{Cssxref("height")}} 屬性包括內容(content),內邊距(padding)和邊框(border),但不包括外邊距(margin)。這是當文檔處於 Quirks 模式時 Internet Explorer 所使用的盒模型。注意,內邊距和邊框都將在盒子內 ,例如,.box {width: 350px; border: 10px solid black;} ,渲染出的容器寬度會固定在 350px,而內容(content)的寬度就會變成 330px, 因為邊框(border)佔了20px。內容框不能為負,並且進位到 0,使得不可能使用 border-box 使元素消失。
+
+ 這裡的維度計算為:
+
width = border + padding + 內容的  width
+
height = border + padding + 內容的 height
+
padding-box {{non-standard_inline}} {{deprecated_inline}}
+
The {{Cssxref("width")}} and {{Cssxref("height")}} properties include the content, the padding but neither the border, nor the margin. Only Firefox implemented this value, and it was removed in Firefox 50.
+
+ +

Formal syntax

+ +
{{csssyntax}}
+ +

Examples

+ +
/* support Firefox, Chrome, Safari, Opera, IE8+ and old Android */
+
+.example {
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+ +

Specifications

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Basic UI', '#box-sizing', 'box-sizing')}}{{Spec2('CSS3 Basic UI')}}Initial definition
+ +

Browser compatibility

+ +

{{Compat("css.properties.box-sizing")}}

+ +

See also

+ + diff --git a/files/zh-tw/web/css/clip/index.html b/files/zh-tw/web/css/clip/index.html new file mode 100644 index 0000000000..900be65c41 --- /dev/null +++ b/files/zh-tw/web/css/clip/index.html @@ -0,0 +1,174 @@ +--- +title: clip +slug: Web/CSS/clip +translation_of: Web/CSS/clip +--- +
{{CSSRef}}{{deprecated_header}}
+ +

總結

+ +

這個 clip CSS 屬性用來定義元素的哪一個部分是可見的. clip 屬性只能被賦予在絕對位置的元素(element)上, 像是帶有這些的CSS屬性的元素 {{cssxref("position","position:absolute")}} or {{cssxref("position","position:fixed")}}.

+ +
+

警告: 這個屬性被遺棄了. 請改用 {{cssxref("clip-path")}} .

+
+ +

{{cssinfo}}

+ +

Syntax

+ +
/* Keyword value */
+clip: auto;
+
+/* <shape> values */
+clip: rect(1px 10em 3rem 2ch);
+clip: rect(1px, 10em, 3rem, 2ch);
+
+/* Global values */
+clip: inherit;
+clip: initial;
+clip: unset;
+
+ +

Values

+ +
+
<shape>
+
A rectangular {{cssxref("<shape>")}} of the form rect(<top>, <right>, <bottom>, <left>) or of the form rect(<top> <right> <bottom> <left>) (which is a more backwards compatible syntax) <top> and <bottom> specify offsets from the inside top border edge of the box, and <right>, and <left> specify offsets from the inside left border edge of the box — that is, the extent of the padding box.
+
<top>, <right>, <bottom>, and <left> may either have a {{cssxref("<length>")}} value or auto. If any side's value is auto, the element is clipped to that side's inside border edge.
+
auto
+
The element does not clip (default value). Note that this is distinct from rect(auto, auto, auto, auto), which does clip to the inside border edges of the element.
+
+ +

Formal syntax

+ +
{{csssyntax}}
+
+ +

Examples

+ +
.dotted-border {
+   border: dotted;
+   position: relative;
+   width: 536px;
+   height: 350px;
+}
+
+#top-left, #middle, #bottom-right {
+   position: absolute;
+   top: 0px;
+}
+
+#top-left {
+   left: 360px;
+   clip: rect(0px, 175px, 113px, 0px);
+}
+
+
+#middle {
+   left: 280px;
+   clip: rect(119px, 255px, 229px, 80px);
+   /* standard syntax, unsupported by Internet Explorer 4-7 */
+}
+
+#bottom-right {
+   left: 200px;
+   clip: rect(235px 335px 345px 160px);
+   /* non-standard syntax, but supported by all major browsers*/
+}
+ +
<p class="dotted-border">
+   <img src="https://developer.mozilla.org/@api/deki/files/3613/=hut.jpg" title="Original Graphic" />
+   <img id="top-left" src="https://developer.mozilla.org/@api/deki/files/3613/=hut.jpg" title="Graphic clipped to upper left">
+   <img id="middle" src="https://developer.mozilla.org/@api/deki/files/3613/=hut.jpg" title="Graphic clipped towards middle">
+   <img id="bottom-right" src="https://developer.mozilla.org/@api/deki/files/3613/=hut.jpg" title="Graphic clipped to bottom right">
+</p>
+ +

{{EmbedLiveSample('Examples', '689px', '410px')}}

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS Masks', '#clip-property', 'clip')}}{{Spec2('CSS Masks')}}Deprecates clip property, suggests {{cssxref("clip-path")}} as replacement.
{{SpecName('CSS3 Transitions', '#animatable-css', 'clip')}}{{Spec2('CSS3 Transitions')}}Defines clip as animatable.
{{SpecName('CSS2.1', 'visufx.html#clipping', 'clip')}}{{Spec2('CSS2.1')}}Initial definition
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1.01.0 (1.0)4.0[1]7.01.0 (85)[1]
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Internet Explorer up to version 7.0 and Safari up to at least 5.1.7 incorrectly interpret clip: auto as clip: rect(auto, auto, auto, auto).

+ +

See also

+ + diff --git a/files/zh-tw/web/css/common_css_questions/index.html b/files/zh-tw/web/css/common_css_questions/index.html new file mode 100644 index 0000000000..b824c671c4 --- /dev/null +++ b/files/zh-tw/web/css/common_css_questions/index.html @@ -0,0 +1,165 @@ +--- +title: CSS 一般問題 +slug: Web/CSS/Common_CSS_Questions +tags: + - CSS + - 待審閱技術 + - 待審閱文字 + - 所有類別 +translation_of: Learn/CSS/Howto/CSS_FAQ +--- +

+

+

我的 CSS 合乎規格,但繪出的版面有誤

+

如果想讓大部分的瀏覽器都能正確繪製標準 HTML/CSS 頁面,便須於 HTML 檔案中放上完整的正確 DOCTYPE。 +

新近瀏覽器都有兩種佈局模式: +

+ +

以 Gecko 為核心的瀏覽器都有第三種近乎標準模式,其中只有一些些不合規範的地方。 +

如果你宣告的 DTD 不合標準或過期了,那麼瀏覽器就會進入 Quirks 模式。 +

以下是常用的 DTD 列表,可以讓瀏覽器進入標準或近乎標準模式。 +

+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+"http://www.w3.org/TR/html4/strict.dtd">
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+

idclass 之間的差別

+

HTML 元素都可有 idclass 屬性。id 屬性是讓你為元素命名的,整個頁面中的元素名稱也不應有重複;class 屬性則可將元素歸為某特定類別,通常也會有很多元素屬於同一種類別 (意即 class 屬性值相同。) CSS 可以讓你以 idclass 來決定某元素的樣式。 +

如果你想指定某特定單一元素的樣式,則應使用 id。 +

+
+

若有很多個元素皆有相同樣式,則可使用 class。 +

這方面的資訊亦可參考 CSS 選取符。 +

+
+

恢復某特性的預設值

+

CSS2 並不提供任何指定某特性預設值的方法,所以要恢復某特性預設值的唯一方法就是重新指定此值。此外你自己得知道預設值是什麼,因為 CSS 也沒有所謂 default 的關鍵字。 +

所以,以選取符撰寫樣式時須特別注意 (例如以標籤名稱 p 作為選取符),或許可以用更明確的選取符 (例如 ID 或 class)。以標籤名稱作選取符茲事體大,一旦使用便將影響整個網頁,而且沒有自動恢復預設值的方法。 +

此外,由於 CSS 具串聯特性,指定選取符時通常越明確越好,以免把不相干的元素都牽扯進來。 +

+

相依樣式

+

CSS 並不支援「以另一個樣式規則為基準」的樣式設定法。 (參考 Eric Meyer 所寫、關於 CSS 工作小組的說明。) 不過,你可以為某單一元素套上多重樣式,製作出類似效果。 +

+

套用多重類別

+

你可以在 HTML 元素的 class 屬性裡以空白字元分隔填上多個樣式類別名稱,便能同時套用多重類別。 +

+
<style type="text/css">
+.firstclass { background: black; color: white; }
+.secondclass { font-weight: bold; }
+</style>
+
+<div class="firstclass secondclass">
+... content ...
+... content ...
+... content ...
+</div>
+
+

若是這些規則中設定了同一種特性值,則會依序以明確性(specificity)、定義位置先後決定顯示方式,與class 屬性中的次序無關。 +

+

無用樣式

+

即使樣式規則已經正確設定完畢,還是可能為瀏覽器所忽略,此時通常是經過語法及優先權法則判斷後的正常現象。 +

以下是導致樣式被略過的常見情形: +

+ +

你可以使用 DOM 觀察器CSS Style Rules 來檢查上述問題。 +

HTML 元素層次問題 +

此時 CSS 樣式套用與否與元素的層次大有相關,請留意:套用到子元素的樣式必定會蓋過母元素的樣式,跟明確性或 CSS 規則的優先權無關。 +

+
#section { font-weight: bold; }
+.redtext { font-weight: normal; color: red; }
+
+<div id="section">
+   粗體、
+   <span class="redtext">正常紅字、</span>
+   又見粗體
+</div>
+
+

如果你的 HTML 層級錯綜複雜,發生規則意外被忽略的情形時,請檢查元素層級問題。可能有某個子元素套上了不該用的樣式。 +

樣式規則重新定義 +

在 CSS 樣式表中,先後次序非常重要。如果你定義了某規則後又重新定義一次,則晚定義的才算數。 +

+
#section { font-weight: bold; }
+.redtext { color: red; }
+/* 其他規則 */
+/* 其他規則 */
+/* 其他規則 */
+.redtext { color: green; }
+
+<div id="section">
+粗體、
+<span class="redtext">正常紅字?</span>
+又見粗體
+</div>
+
+

為避免此類錯誤發生,每個特定選取符請僅定義一次樣式,集中特性一次定義也便於管理些。 +


+特性的簡寫法 +

使用簡寫法來定義樣式簡明扼要,是個不錯的方法。你也可以用簡寫法設定某組特性中的部分特性值,但須留意其他沒寫到的部分會自動採用預設值。這表示之前的規則中為某單一特性定義的值可能失效。 +

+
#section { font-size: 12px; font-family: Verdana; font-weight: bold; }
+.redtext { font: 14px Arial; color: red; }
+
+<div id="section">
+   採用 Verdana 粗體的 12px 字樣;
+   <span class="redtext">採用 Arial 正常字體的 14px 紅字;</span>
+   還是採用 Verdana 粗體的 12px 字樣。
+</div>
+
+

前一個例子中,套用到不同元素範圍的同族特性是問題所在,但就算特性都寫在同一條規則裡也可能出問題,因為順序真的很重要。 +

+
#section {
+   font-weight: bold;
+   font: 12px Verdana;  /* 有了這行,font-weight 又回到預設的 normal 了 */
+}
+
+


+使用 * 選取符 +

* 選取符表示任何元素皆符合,但使用上應多加小心。 +

+
body * { font-weight: normal; }
+#section { font: 12px Verdana; }
+.boldtext { font-weight: bold; }
+.redtext { color: red; }
+
+<div id="section">
+   正常、
+   <span class="boldtext">
+      <span class="redtext">正常紅字、</span>
+   </span>
+   又見正常。
+</div>
+
+

在此例中,選取符為 body * 的規則會套用到所有 body 內的元素,也包括 redtext,所以原先套用到 boldtextfont-weight: bold; 就被覆蓋為 font-weight: normal; 了。 +


+CSS 明確性 +

如果某元素會套用好幾條規則,則相衝突的特性就要靠規則的明確性來分高下。行內樣式(放在 HTML 各標籤的 style 屬性中)優先權最高,其次是以 id 做選取符的規則,再其次是以 class 套用的類別,最後則是單純以元素名稱當選取符的規則。 +

+
div { color: black; }
+#orange { color: orange; }
+.green { color: green; }
+
+<div id="orange" class="green" style="color: red;">是紅的!</div>
+
+

如果樣式規則的選取符分成好幾段,計算方式就更為複雜一些。需要瞭解完整資訊者,請參考 CSS 2.1 規格書的 6.4.3 一節。 +

+

-moz-* 特性是什麼玩意?

+

請見 Mozilla 擴充的 CSS。由於這些擴充規格不是 W3C 標準的一部分,因此並不建議使用。 +

+
+
+{{ languages( { "en": "en/Common_CSS_Questions", "pl": "pl/Cz\u0119ste_pytania_o_CSS" } ) }} diff --git a/files/zh-tw/web/css/css_animations/index.html b/files/zh-tw/web/css/css_animations/index.html new file mode 100644 index 0000000000..7c953b2359 --- /dev/null +++ b/files/zh-tw/web/css/css_animations/index.html @@ -0,0 +1,136 @@ +--- +title: CSS Animations +slug: Web/CSS/CSS_Animations +tags: + - CSS + - CSS Animations + - Experimental + - Overview + - Reference +translation_of: Web/CSS/CSS_Animations +--- +

{{CSSRef}}{{SeeCompatTable}}

+ +

CSS Animations is a module of CSS that defines how to animate the values of CSS properties over time, using keyframes. The behavior of these keyframe animations can be controlled by specifying their duration, their number of repetitions, and how they repeat.

+ +

Reference

+ +

CSS Properties

+ +
+ +
+ +

CSS At-rules

+ +
+ +
+ +

Guides

+ +
+
Detecting CSS animation support
+
Describes a technique for detecting if the browser supports CSS animations.
+
Using CSS animations
+
Step-by-step tutorial about how to create animations using CSS, this article describes each relevant CSS property and at-rule and explains how they interact.
+
+ +

Specifications

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('CSS3 Animations') }}{{ Spec2('CSS3 Animations') }}Initial definition.
+ +

Browser compatibility

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatVersionUnknown}}{{property_prefix("-webkit")}}
+ 43.0
{{CompatGeckoDesktop("5.0")}}{{property_prefix("-moz")}}
+ {{CompatGeckoDesktop("16.0")}}
1012{{property_prefix("-o")}}
+ 12.10[2]
4.0{{property_prefix("-webkit")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support2.1 {{property_prefix("-webkit")}} [1]
+ 4.0 {{property_prefix("-webkit")}}
{{CompatGeckoMobile("5.0")}}{{property_prefix("-moz")}}
+ {{CompatGeckoMobile("16.0")}}
{{CompatUnknown}}{{CompatUnknown}}{{CompatVersionUnknown}}{{property_prefix("-webkit")}}
+
+ +

[1] Partial support: {{cssxref("animation-fill-mode")}} property is not supported in Android browser below 2.3.

+ +

[2] See the release notes to Opera 12.50.

+ +

See also

+ + + +

 

diff --git a/files/zh-tw/web/css/css_animations/using_css_animations/index.html b/files/zh-tw/web/css/css_animations/using_css_animations/index.html new file mode 100644 index 0000000000..82acb8ac6e --- /dev/null +++ b/files/zh-tw/web/css/css_animations/using_css_animations/index.html @@ -0,0 +1,334 @@ +--- +title: CSS 動畫 +slug: Web/CSS/CSS_Animations/Using_CSS_animations +tags: + - Advanced + - CSS animation + - CSS 動畫 + - Example + - Experimental + - Guide +translation_of: Web/CSS/CSS_Animations/Using_CSS_animations +--- +

{{SeeCompatTable}}{{CSSRef}}

+ +
+

 CSS animations 使 CSS style configuration 的轉變變得可行。在這種動畫的運作上,你只需要定義兩個部份:1. 動畫的最初及結尾 2. 動畫轉變的方式。

+ +

  相較於傳統 script-driven 的動畫技術,CSS animations 有三種好處:

+ +
    +
  1. 對於不複雜的動畫來說,CSS animation 是好選擇。你甚至不必懂得  JavaScript。
  2. +
  3. 在資源消耗上,CSS animation 有優勢,即使在系統負載超過 50% 仍可有效運作。在 JavaScript 上要達到一樣的目的有賴於你寫出品質非常好的  code。事實上,CSS animation 在運作上可以適時的減少 frame 量或以其它技術減少資源消耗。
  4. +
  5. CSS animation 讓瀏覽器來負責動畫的產生過程,如此可以擁有較好的優化。
  6. +
+ +

CSS animation 設定

+ +

  你可以使用 {{ cssxref("animation") }} property 或其 sub-properties 來創建 CSS 動畫的細節(諸如轉化時間等)。但這並不能決定動畫的外觀,外觀的部份我們將在下面的 {{ anch("使用關鍵影格定義動畫流程") }} 介紹。

+ +

  這裡是 {{ cssxref("animation") }} property 的 sub-properties:

+ +
+
{{ cssxref("animation-delay") }}
+
定義元素讀取完畢到動畫開始的間隔時間。
+
{{ cssxref("animation-direction") }}
+
定義是否動畫播放完畢後將會反向播放。
+
{{ cssxref("animation-duration") }}
+
定義動畫完成一次週期的時間。
+
{{ cssxref("animation-iteration-count") }}
+
定義動畫重複的次數。你可以用 infinite 來讓動畫永遠重複播放。
+
{{ cssxref("animation-name") }}
+
定義關鍵影格 {{ cssxref("@keyframes") }} 的名字。
+
{{ cssxref("animation-play-state") }}
+
控制動畫的播放狀態。有 pause 和 running 兩種值,後者為預設值。
+
{{ cssxref("animation-timing-function") }}
+
定義動畫轉變時時間的加速曲線 (例如 linear)。
+
{{ cssxref("animation-fill-mode") }}
+
定義元素在動畫播放外(動畫開始前及結束後)的狀態。
+
+ +

使用關鍵影格定義動畫流程

+ +

  在你設定了動畫的時間資訊之後,你必須要設定動畫漸變的過程。這可以藉由建造兩個或更多的關鍵影格來達到目的 (使用 {{ cssxref("@keyframes") }} )。關鍵影格描述了該元素在漸變過程中的外觀。

+ +

  因為動畫漸變時間已經在 CSS style 中被定義(見上節),所以關鍵影格使用 {{ cssxref("percentage") }} 來指出他們會在整個漸變流程中的哪個時間點出現。 0% 代表他是整個動畫的起點,而 100% 指出他是整個動畫的結束點。這兩個特殊時間點一定要被定義,如此一來瀏覽器材知道該如何產生你的動畫。也因為他們是如此重要,所以這兩個時間點有特殊的別名: from 和 to。

+ +

  當然你也可以在動畫轉變過程中增加更多的關鍵影格。

+ +

範例

+ +
注意: 為了簡潔起見,以下的範例中我們只列出前綴為 -moz- 的部份。當你查看 Live Sample 的原始碼時,可以看到前綴為 -webkit- 的部份。
+ +

使文字滑過畫面

+ +

  這是一個簡單的範例,他展示了 {{ HTMLElement("p") }} element 從畫面右方滑向左方。

+ +
<style type="text/css">
+  p {
+    -moz-animation-duration: 3s;
+    -moz-animation-name: slidein;
+  }
+
+  @-moz-keyframes slidein {
+    from {
+      margin-left: 100%;
+      width: 300%
+    }
+
+    to {
+      margin-left: 0%;
+      width: 100%;
+    }
+  }
+</style>
+
+ +

  這裡用 {{ cssxref("animation-duration") }} property 定義 {{ HTMLElement("p") }} element 的變動自開始到結束共花 3 秒。而關鍵影格的名稱由 {{ cssxref("@keyframes") }} 指定 - 叫做 slidein。

+ +

  傳統的 {{ HTMLElement("p") }} element 尚有其他性質可供設定,但假設這些性質並不支援 CSS animation,則我們不能期待他們會被瀏覽器顯示。

+ +

  這裡的關鍵影格我們定義了兩個 (以 {{ cssxref("@keyframes") }} 定義),開始 (0%)和結束 (100%)。開始的影格在 from 中,而結束在 to 中。由程式中我們可以看到,整個動畫由最一開始處於最右方且 width 為 300% 轉變為處於最左方且 width 為 100%。如此一來你就可以看到 {{ HTMLElement("p") }} element 由右而左的滑過畫面。

+ +

  結束影格描述 width 為 100% 可以確保 {{ HTMLElement("p") }} element 在可視範圍內。

+ +
<p>The Caterpillar and Alice looked at each other for some time in silence:
+at last the Caterpillar took the hookah out of its mouth, and addressed
+her in a languid, sleepy voice.</p>
+
+ +

{{EmbedLiveSample("使文字滑過畫面","100%","250")}}

+ +

在開頭和結束間加入關鍵影格

+ +

  現在我們試著多加入新的關鍵影格。在這個範例中,我們希望做到在文字在移動時字體先變大而後恢復正常。程式碼如下:

+ +
75% {
+  font-size: 300%;
+  margin-left: 25%;
+  width: 150%;
+}
+
+ + + + + +

  這段程式碼告訴瀏覽器在開始後過了 75% 的時間後字體增大到三倍,且位置在離左側 25 % 處,此時總寬度為 150%。

+ +

{{EmbedLiveSample("在開頭和結束間加入關鍵影格","100%","250")}}

+ +

重複播放

+ +

  為了達到重複播放的目的,我們使用 {{ cssxref("animation-iteration-count") }} property。讓我們把它設定成 infinite :

+ +
p {
+  -moz-animation-duration: 3s;
+  -moz-animation-name: slidein;
+  -moz-animation-iteration-count: infinite;
+} 
+ + + + + +

{{EmbedLiveSample("重複播放","100%","250")}}

+ +

播放完畢後反向播放

+ +

  由上個例子我們知道該如何永久性播放動畫。但這個顯示結果有些突兀,是以我們試著讓他播放完畢後倒帶執行。這需要用到 {{ cssxref("animation-direction") }},賦予 alternate 的值:

+ +
p {
+  -moz-animation-duration: 3s;
+  -moz-animation-name: slidein;
+  -moz-animation-iteration-count: infinite;
+  -moz-animation-direction: alternate;
+} 
+ + + + + +

{{EmbedLiveSample("播放完畢後反向播放","100%","250")}}

+ +

使用動畫的事件

+ +

  你可以藉由 animation event 來對 CSS animation 做更進階的控制,這需要用到 {{ domxref("event/AnimationEvent", "AnimationEvent") }} 物件。他可以用來偵測動畫所處的時間點等資訊。每個 event 包含發生的時間以及觸發 event 的動畫名字。

+ +

  我們將修改剛剛的範例來展示 animation event 的能力。

+ +
.slidein {
+  -moz-animation-duration: 3s;
+  -webkit-animation-duration: 3s;
+  animation-duration: 3s;
+  -moz-animation-name: slidein;
+  -webkit-animation-name: slidein;
+  animation-name: slidein;
+  -moz-animation-iteration-count: 3;
+  -webkit-animation-iteration-count: 3;
+  animation-iteration-count: 3;
+  -moz-animation-direction: alternate;
+  -webkit-animation-direction: alternate;
+  animation-direction: alternate;
+}
+
+@-moz-keyframes slidein {
+  from {
+    margin-left:100%;
+    width:300%
+  }
+
+  to {
+    margin-left:0%;
+    width:100%;
+  }
+}
+
+@-webkit-keyframes slidein {
+  from {
+    margin-left:100%;
+    width:300%
+  }
+
+  to {
+   margin-left:0%;
+   width:100%;
+ }
+}
+
+@keyframes slidein {
+  from {
+    margin-left:100%;
+    width:300%
+  }
+
+  to {
+   margin-left:0%;
+   width:100%;
+ }
+}
+ +

設定 animation event listeners

+ +

  我們使用 JavaScript 來監控所有可能的 animation events。下面的 setup() 函式設定我們的 event listeners,並且在文件第一次被載入時執行他:

+ +
function setup() {
+  var e = document.getElementById("watchme");
+  e.addEventListener("animationstart", listener, false);
+  e.addEventListener("animationend", listener, false);
+  e.addEventListener("animationiteration", listener, false);
+
+  var e = document.getElementById("watchme");
+  e.className = "slidein";
+}
+
+ +

  這是非常簡單的程式,你可以從其它相關文件中取得 {{ domxref("element.addEventListener()") }} 的更多細節。setup() 函式所做的最後一件事是設定這個 element 的 class name 為 slidein,此時,我們啟動了這個動畫。

+ +

  這麼做的原因是 animationstart event 會在被動畫執行時立刻被觸發,所以我們只好在最後才設定 class name。

+ +

接收 events

+ +

  這些 events 會被發送到 listener() 函式,如下所示:

+ +
function listener(e) {
+  var l = document.createElement("li");
+  switch(e.type) {
+    case "animationstart":
+      l.innerHTML = "Started: elapsed time is " + e.elapsedTime;
+      break;
+    case "animationend":
+      l.innerHTML = "Ended: elapsed time is " + e.elapsedTime;
+      break;
+    case "animationiteration":
+      l.innerHTML = "New loop started at time " + e.elapsedTime;
+      break;
+  }
+  document.getElementById("output").appendChild(l);
+}
+
+ +

  這段程式檢查藉由檢查 {{ domxref("event.type") }} 得知現在收到了哪種 animation event,並且以一個 {{ HTMLElement("ul") }} (unordered list) 形式的記錄下他。

+ +

  程式執行結果看起來會是這樣子的:

+ + + +

  注意這裡的時間是一個範例,你自己執行可能會取得不一樣的結果(但應該會近似)。此外,在動畫的最後,event 會是 animationend 而非  animationiteration 。

+ +

完整的 HTML 程式碼

+ +

  這裡是完整的 HTML 程式碼:

+ +
<body onload="setup()">
+  <h1 id="watchme">Watch me move</h1>
+  <p>This example shows how to use CSS animations to make <code>h1</code> elements
+  move across the page.</p>
+  <p>In addition, we output some text each time an animation event fires, so you can see them in action.</p>
+  <ul id="output">
+  </ul>
+</body> 
+ +

{{EmbedLiveSample('使用動畫的事件', '600', '300')}}

+ +

更多資訊

+ + +
+ +

 

diff --git a/files/zh-tw/web/css/css_background_and_borders/index.html b/files/zh-tw/web/css/css_background_and_borders/index.html new file mode 100644 index 0000000000..dcfeef033a --- /dev/null +++ b/files/zh-tw/web/css/css_background_and_borders/index.html @@ -0,0 +1,152 @@ +--- +title: CSS Background and Borders +slug: Web/CSS/CSS_Background_and_Borders +tags: + - CSS + - CSS Background and Borders + - CSS Reference + - Overview +translation_of: Web/CSS/CSS_Backgrounds_and_Borders +--- +

{{CSSRef}}

+ +

CSS Background and Borders is a module of CSS that defines how background and borders of elements are described. Borders can be lines or images, boxes can have one or multiple backgrounds, have rounded corners, and shadows.

+ +

Reference

+ +

CSS Properties

+ +
+ +
+ +

Guides

+ +
+
Using CSS multiple backgrounds
+
Explains how to set backgrounds on elements and how they will interact with it.
+
Scaling background images
+
Describes how to change the appearance of the background images, by stretching them or repeating them, to cover the whole background of the element, or not.
+
+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('CSS3 Backgrounds') }}{{ Spec2('CSS3 Backgrounds') }} 
{{SpecName('CSS2.1', 'box.html')}}{{Spec2('CSS2.1')}} 
{{SpecName('CSS1', '#border')}}{{Spec2('CSS1')}} 
+ +

Browser compatibility

+ +

{{CompatibilityTable()}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0{{CompatGeckoDesktop("1.0")}}4.03.51.0 (85)
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown()}}{{CompatGeckoMobile("1.9.2")}}{{CompatVersionUnknown()}}{{CompatVersionUnknown()}}1.0
+
diff --git a/files/zh-tw/web/css/css_background_and_borders/using_css_multiple_backgrounds/index.html b/files/zh-tw/web/css/css_background_and_borders/using_css_multiple_backgrounds/index.html new file mode 100644 index 0000000000..244234b839 --- /dev/null +++ b/files/zh-tw/web/css/css_background_and_borders/using_css_multiple_backgrounds/index.html @@ -0,0 +1,84 @@ +--- +title: 使用 CSS 多重背景 +slug: Web/CSS/CSS_Background_and_Borders/Using_CSS_multiple_backgrounds +tags: + - CSS + - CSS Background + - Example + - Guide + - Intermediate +translation_of: Web/CSS/CSS_Backgrounds_and_Borders/Using_multiple_backgrounds +--- +

{{CSSRef}}

+ +

藉由 CSS3 我們可以對元素使用 多重背景。每個設定的背景被一個個分層,第一個背景在最上面,最後一個背景是在最下面一層。 記得只有最後一個背景可以設定 background color。

+ +

簡易的表達方式:

+ +
.myclass {
+  background:
+      background 1, //第一層
+      background 2,
+      ...,
+      background N;  //最後一層
+}
+
+ +

可以使用縮寫的方式 {{ cssxref("background") }} 和個別標記的方式設定多重背景,但是部分屬性無法設置多重背景,例如 {{ cssxref("background-color") }}。下面是能設置為多重背景的背景屬性: 

+ + + +

範例

+ +

下面的範例中,重疊三個背景:Firefox logo、線性漸層、一張泡泡的圖片

+ +
.multi_bg_example {
+  background-image   : url(https://mdn.mozillademos.org/files/11305/firefox.png),
+                       url(https://mdn.mozillademos.org/files/11307/bubbles.png),
+                       linear-gradient(to right, rgba(30, 75, 115, 1),  rgba(255, 255, 255, 0));
+
+  background-repeat  : no-repeat,
+                       no-repeat,
+                       no-repeat;
+
+  background-position: bottom right,
+                       left,
+                       right;
+}
+
+ + + +

結果

+ +

{{EmbedLiveSample('範例','100%','400')}}

+ +

如你所見,Firefox logo(列表第一個選項)在最上面,接著是漸層。每個隨後的子屬性({{ cssxref("background-repeat") }} 和 {{ cssxref("background-position") }})應用相對的背景上。所以第一個 {{ cssxref("background-repeat") }} 的值應用在第一個(最前面)背景。

+ +

參見

+ + diff --git a/files/zh-tw/web/css/css_box_model/index.html b/files/zh-tw/web/css/css_box_model/index.html new file mode 100644 index 0000000000..cb4dd91343 --- /dev/null +++ b/files/zh-tw/web/css/css_box_model/index.html @@ -0,0 +1,167 @@ +--- +title: CSS Box Model +slug: Web/CSS/CSS_Box_Model +tags: + - CSS + - CSS Box Model + - CSS Reference + - NeedsTranslation + - Overview + - TopicStub +translation_of: Web/CSS/CSS_Box_Model +--- +
{{CSSRef}}
+ +

CSS Box Model is a CSS module that defines the rectangular boxes, including their padding and margin, that are generated for elements and laid out according to the visual formatting model.

+ +

Reference

+ +

Properties

+ +

Properties controlling the flow of content in a box

+ +
+ +
+ +

Properties controlling the size of a box

+ +
+ +
+ +

Properties controlling the margins of a box

+ +
+ +
+ +

Properties controlling the paddings of a box

+ +
+ +
+ +

Other properties

+ +
+ +
+ +

Guides and tools

+ +
+
Introduction to the CSS box model
+
Explains one of the fundamental concept of CSS, the box model: describes the meaning of the margin, padding, as well as the different areas of a box.
+
Mastering margin collapsing
+
In several cases, two adjacent margins are collapsed into one. This article describes when this is happening and how to control it.
+
Box-shadow generator
+
An interactive tool that allows to visually create shadows and to generate the needed syntax for the {{cssxref("box-shadow")}} property.
+
+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("CSS3 Box")}}{{Spec2("CSS3 Box")}} 
{{SpecName("CSS2.1", "box.html")}}{{Spec2("CSS2.1")}} 
{{SpecName("CSS1")}}{{Spec2("CSS1")}}Initial definition
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1.0{{CompatGeckoDesktop("1")}}3.03.51.0 (85)
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support1.0{{CompatGeckoMobile("1")}}6.06.01.0
+
diff --git a/files/zh-tw/web/css/css_box_model/mastering_margin_collapsing/index.html b/files/zh-tw/web/css/css_box_model/mastering_margin_collapsing/index.html new file mode 100644 index 0000000000..be8ea00259 --- /dev/null +++ b/files/zh-tw/web/css/css_box_model/mastering_margin_collapsing/index.html @@ -0,0 +1,107 @@ +--- +title: 理解邊界重疊的原因 +slug: Web/CSS/CSS_Box_Model/Mastering_margin_collapsing +translation_of: Web/CSS/CSS_Box_Model/Mastering_margin_collapsing +--- +
{{CSSRef}}
+ +
當一個 Block 的 下邊界範圍 ( margin-bottom ) 和一個 Block 的 上邊界範圍 ( margin-top ) 都有設定時只會留下最大那個,這種情況我們稱為邊界重疊 ( margin collapsing )。請留意設定了 float 或絕對定位的元件並不會產生邊界重疊。
+ + + +

有三個標準情況會形成邊界重疊:

+ +
+
同一層的相鄰
+
兩個相鄰的元素邊界就會發生重疊,除非後者有加上clear-fix。例如: +
<style>
+  p:nth-child(1){
+    margin-bottom: 13px;
+  }
+  p:nth-child(2){
+    margin-top: 87px;
+  }
+</style>
+
+ <p>下邊界範圍會...</p>
+ <p>...跟這個元素的上邊界範圍重疊。</p>
+
+
+
如果邊界會合併的的話,理所當然會認為上例中的上下兩個元素會合成一個 100px 的邊界範圍。
+ 但其實會發生重疊,而且只會留下最大的邊界範圍,以此例子來說,邊界範圍就是 87px。
+
+
父元素與第一個/最後一個子元素
+
如果第一個子元素跟父元素的上邊界範圍 ( margin-top ) 貼在一起,也會發生邊界重疊的情況。除非父元素有設定邊框 ( border ) 、 內距 ( padding )、內容設定為 inline 或是有加上 clear-fix,這些都會隔開子元素和父元素的屬性。
+ 最後一個子元素也是,但是與父元素的下邊界範圍 ( margin-bottom ) 更容易被隔開,因為父元素可以設定這些屬性。例如:
+
+
<style type="text/css">
+    section    {
+        margin-top: 13px;
+        margin-bottom: 87px;
+    }
+
+    header {
+        margin-top: 87px;
+    }
+
+    footer {
+        margin-bottom: 13px;
+    }
+</style>
+
+<section>
+    <header>上邊界重疊是 87</header>
+    <footer>下邊界重疊還是 87 不能再高了</footer>
+</section>
+
+
空的元素
+
當同一個元素上邊界範圍可以直接貼到下邊界範圍時,也會發生邊界重疊。這種情況會發生在一個元素完全沒有設定邊框 ( border ) 、 內距 ( padding )、高度 ( height )​ 、最小高度 ( min-height ) 、最大高度 ( max-height )​ 、內容設定為 inline 或是加上 clear-fix 的時候。例如:
+
+
<style>
+  p {
+    margin: 0px;
+  }
+  div {
+    margin-top: 13px;
+    margin-bottom: 87px;
+  }
+</style>
+
+<p>下邊界範圍是 87</p>
+<div></div>
+<p>...上邊界範圍也是 87。</p>
+
+
+
+ +

上面這些情況是會同時發生的,那時邊界重疊的原因又更複雜了。

+ +

比較特別的是,當計算的時候某些邊界範圍是負數,邊界重疊的結果會取最大值和最小值相加。舉例來說如果 -13px、8px 和 100px 疊在一起,邊界範圍的計算方法會是 100px - 13px 也就是 87px。

+ +

以上這些內容都是發生在 Block-Level 的元素,設定 floating 和 absolutely positioned 的元素完全不用擔心邊界重疊的計算。

+ +

標準文件

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("CSS2.1", "box.html#collapsing-margins", "margin collapsing")}}{{Spec2("CSS2.1")}}Initial definition
+ +

參考

+ + diff --git a/files/zh-tw/web/css/css_colors/color_picker_tool/index.html b/files/zh-tw/web/css/css_colors/color_picker_tool/index.html new file mode 100644 index 0000000000..367e58ce23 --- /dev/null +++ b/files/zh-tw/web/css/css_colors/color_picker_tool/index.html @@ -0,0 +1,3221 @@ +--- +title: 色彩選擇工具 +slug: Web/CSS/CSS_Colors/Color_picker_tool +tags: + - CSS + - Tools +translation_of: Web/CSS/CSS_Colors/Color_picker_tool +--- +
+

ColorPicker tool

+ +

HTML Content

+ +
    <div id="container">
+        <div id="palette" class="block">
+            <div id="color-palette"></div>
+            <div id="color-info">
+                <div class="title"> CSS Color </div>
+            </div>
+        </div>
+
+        <div id="picker" class="block">
+            <div class="ui-color-picker" data-topic="picker" data-mode="HSL"></div>
+            <div id="picker-samples" sample-id="master"></div>
+            <div id="controls">
+                <div id="delete">
+                    <div id="trash-can"></div>
+                </div>
+                <div id="void-sample" class="icon"></div>
+            </div>
+        </div>
+
+        <div id="canvas" data-tutorial="drop">
+            <div id="zindex" class="ui-input-slider" data-topic="z-index" data-info="z-index"
+                data-max="20" data-sensivity="10"></div>
+        </div>
+    </div>
+
+
+ +

CSS Content

+ +
/*
+ * COLOR PICKER TOOL
+ */
+
+.ui-color-picker {
+	width: 420px;
+	margin: 0;
+	border: 1px solid #DDD;
+	background-color: #FFF;
+	display: table;
+
+	-moz-user-select: none;
+	-webkit-user-select: none;
+	-ms-user-select: none;
+	user-select: none;
+}
+
+.ui-color-picker .picking-area {
+	width: 198px;
+	height: 198px;
+	margin: 5px;
+	border: 1px solid #DDD;
+	position: relative;
+	float: left;
+	display: table;
+}
+
+.ui-color-picker .picking-area:hover {
+	cursor: default;
+}
+
+/* HSV format - Hue-Saturation-Value(Brightness) */
+.ui-color-picker .picking-area {
+	background: url('https://mdn.mozillademos.org/files/5707/picker_mask_200.png') center center;
+
+	background: -moz-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
+				-moz-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
+	background: -webkit-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
+				-webkit-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
+	background: -ms-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
+				-ms-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
+	background: -o-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
+				-o-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
+
+	background-color: #F00;
+}
+
+/* HSL format - Hue-Saturation-Lightness */
+.ui-color-picker[data-mode='HSL'] .picking-area {
+	background: -moz-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
+									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
+				-moz-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
+	background: -webkit-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
+									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
+				-webkit-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
+	background: -ms-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
+									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
+				-ms-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
+	background: -o-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
+									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
+				-o-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
+	background-color: #F00;
+}
+
+.ui-color-picker .picker {
+	width: 10px;
+	height: 10px;
+	border-radius: 50%;
+	border: 1px solid #FFF;
+	position: absolute;
+	top: 45%;
+	left: 45%;
+}
+
+.ui-color-picker .picker:before {
+	width: 8px;
+	height: 8px;
+	content: "";
+	position: absolute;
+	border: 1px solid #999;
+	border-radius: 50%;
+}
+
+.ui-color-picker .hue,
+.ui-color-picker .alpha {
+	width: 198px;
+	height: 28px;
+	margin: 5px;
+	border: 1px solid #FFF;
+	float: left;
+}
+
+.ui-color-picker .hue {
+	background: url("https://mdn.mozillademos.org/files/5701/hue.png") center;
+	background: -moz-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
+				#00F 66.66%, #F0F 83.33%, #F00 100%);
+	background: -webkit-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
+				#00F 66.66%, #F0F 83.33%, #F00 100%);
+	background: -ms-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
+				#00F 66.66%, #F0F 83.33%, #F00 100%);
+	background: -o-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
+				#00F 66.66%, #F0F 83.33%, #F00 100%);
+}
+
+.ui-color-picker .alpha {
+	border: 1px solid #CCC;
+	background: url("https://mdn.mozillademos.org/files/5705/alpha.png");
+}
+
+.ui-color-picker .alpha-mask {
+	width: 100%;
+	height: 100%;
+	background: url("https://mdn.mozillademos.org/files/6089/alpha_mask.png");
+}
+
+.ui-color-picker .slider-picker {
+	width: 2px;
+	height: 100%;
+	border: 1px solid #777;
+	background-color: #FFF;
+	position: relative;
+	top: -1px;
+}
+
+/* input HSV and RGB */
+
+.ui-color-picker .info {
+	width: 200px;
+	margin: 5px;
+	float: left;
+}
+
+.ui-color-picker .info * {
+	float: left;
+}
+
+.ui-color-picker .input {
+	width: 64px;
+	margin: 5px 2px;
+	float: left;
+}
+
+.ui-color-picker .input .name {
+	height: 20px;
+	width: 30px;
+	text-align: center;
+	font-size: 14px;
+	line-height: 18px;
+	float: left;
+}
+
+.ui-color-picker .input input {
+	width: 30px;
+	height: 18px;
+	margin: 0;
+	padding: 0;
+	border: 1px solid #DDD;
+	text-align: center;
+	float: right;
+
+	-moz-user-select: text;
+	-webkit-user-select: text;
+	-ms-user-select: text;
+}
+
+.ui-color-picker .input[data-topic="lightness"] {
+	display: none;
+}
+
+.ui-color-picker[data-mode='HSL'] .input[data-topic="value"] {
+	display: none;
+}
+
+.ui-color-picker[data-mode='HSL'] .input[data-topic="lightness"] {
+	display: block;
+}
+
+.ui-color-picker .input[data-topic="alpha"] {
+	margin-top: 10px;
+	width: 93px;
+}
+
+.ui-color-picker .input[data-topic="alpha"] > .name {
+	width: 60px;
+}
+
+.ui-color-picker .input[data-topic="alpha"] > input {
+	float: right;
+}
+
+.ui-color-picker .input[data-topic="hexa"] {
+	width: auto;
+	float: right;
+	margin: 6px 8px 0 0;
+}
+
+.ui-color-picker .input[data-topic="hexa"] > .name {
+	display: none;
+}
+
+.ui-color-picker .input[data-topic="hexa"] > input {
+	width: 90px;
+	height: 24px;
+	padding: 2px 0;
+	-moz-box-sizing: border-box;
+	-webkit-box-sizing: border-box;
+	box-sizing: border-box;
+}
+
+/* Preview color */
+.ui-color-picker .preview {
+	width: 95px;
+	height: 53px;
+	margin: 5px;
+	margin-top: 10px;
+	border: 1px solid #DDD;
+	background-image: url("https://mdn.mozillademos.org/files/5705/alpha.png");
+	float: left;
+	position: relative;
+}
+
+.ui-color-picker .preview:before {
+	height: 100%;
+	width: 50%;
+	left: 50%;
+	top: 0;
+	content: "";
+	background: #FFF;
+	position: absolute;
+	z-index: 1;
+}
+
+.ui-color-picker .preview-color {
+	width: 100%;
+	height: 100%;
+	background-color: rgba(255, 0, 0, 0.5);
+	position: absolute;
+	z-index: 1;
+}
+
+.ui-color-picker .switch_mode {
+	width: 10px;
+	height: 20px;
+	position: relative;
+	border-radius: 5px 0 0 5px;
+	border: 1px solid #DDD;
+	background-color: #EEE;
+	left: -12px;
+	top: -1px;
+	z-index: 1;
+	transition: all 0.5s;
+}
+
+.ui-color-picker .switch_mode:hover {
+	background-color: #CCC;
+	cursor: pointer;
+}
+
+/*
+ * UI Component
+ */
+
+.ui-input-slider {
+	height: 20px;
+	font-family: "Segoe UI", Arial, Helvetica, sans-serif;
+	-moz-user-select: none;
+	user-select: none;
+}
+
+.ui-input-slider * {
+	float: left;
+	height: 100%;
+	line-height: 100%;
+}
+
+/* Input Slider */
+
+.ui-input-slider > input {
+	margin: 0;
+	padding: 0;
+	width: 50px;
+	text-align: center;
+
+	-moz-box-sizing: border-box;
+	-webkit-box-sizing: border-box;
+	box-sizing: border-box;
+}
+
+.ui-input-slider-info {
+	width: 90px;
+	padding: 0px 10px 0px 0px;
+	text-align: right;
+	text-transform: lowercase;
+}
+
+.ui-input-slider-left, .ui-input-slider-right {
+	width: 16px;
+	cursor: pointer;
+	background: url("https://mdn.mozillademos.org/files/5679/arrows.png") center left no-repeat;
+}
+
+.ui-input-slider-right {
+	background: url("https://mdn.mozillademos.org/files/5679/arrows.png") center right no-repeat;
+}
+
+.ui-input-slider-name {
+	width: 90px;
+	padding: 0 10px 0 0;
+	text-align: right;
+	text-transform: lowercase;
+}
+
+.ui-input-slider-btn-set {
+	width: 25px;
+	background-color: #2C9FC9;
+	border-radius: 5px;
+	color: #FFF;
+	font-weight: bold;
+	line-height: 14px;
+	text-align: center;
+}
+
+.ui-input-slider-btn-set:hover {
+	background-color: #379B4A;
+	cursor: pointer;
+}
+
+/*
+ * COLOR PICKER TOOL
+ */
+
+body {
+	max-width: 1000px;
+	margin: 0 auto;
+
+	font-family: "Segoe UI", Arial, Helvetica, sans-serif;
+
+	box-shadow: 0 0 5px 0 #999;
+
+	-moz-box-sizing: border-box;
+	-webkit-box-sizing: border-box;
+	box-sizing: border-box;
+
+	-moz-user-select: none;
+	-webkit-user-select: none;
+	-ms-user-select: none;
+	user-select: none;
+
+}
+
+/**
+ * Resize Handle
+ */
+.resize-handle {
+	width: 10px;
+	height: 10px;
+	background: url('https://mdn.mozillademos.org/files/6083/resize.png') center center no-repeat;
+	position: absolute;
+	bottom: 0;
+	right: 0;
+}
+
+[data-resize='both']:hover {
+	cursor: nw-resize !important;
+}
+
+[data-resize='width']:hover {
+	cursor: w-resize !important;
+}
+
+[data-resize='height']:hover {
+	cursor: n-resize !important;
+}
+
+[data-hidden='true'] {
+	display: none;
+}
+
+[data-collapsed='true'] {
+	height: 0 !important;
+}
+
+.block {
+	display: table;
+}
+
+
+/**
+ * 	Container
+ */
+#container {
+	width: 100%;
+
+	-moz-box-sizing: border-box;
+	-webkit-box-sizing: border-box;
+	box-sizing: border-box;
+
+	display: table;
+}
+
+/**
+ * 	Picker Zone
+ */
+
+#picker {
+	padding: 10px;
+	width: 980px;
+}
+
+.ui-color-picker {
+	padding: 3px 5px;
+	float: left;
+	border-color: #FFF;
+}
+
+.ui-color-picker .switch_mode {
+	display: none;
+}
+
+.ui-color-picker .preview-color:hover {
+	cursor: move;
+}
+
+/**
+ * Picker Container
+ */
+
+#picker-samples {
+	width: 375px;
+	height: 114px;
+	max-height: 218px;
+	margin: 0 10px 0 30px;
+	overflow: hidden;
+	position: relative;
+	float: left;
+
+	transition: all 0.2s;
+}
+
+#picker-samples .sample {
+	width: 40px;
+	height: 40px;
+	margin: 5px;
+	border: 1px solid #DDD;
+	position: absolute;
+	float: left;
+	transition: all 0.2s;
+}
+
+#picker-samples .sample:hover {
+	cursor: pointer;
+	border-color: #BBB;
+	transform: scale(1.15);
+	border-radius: 3px;
+}
+
+#picker-samples .sample[data-active='true'] {
+	border-color: #999;
+}
+
+#picker-samples .sample[data-active='true']:after {
+	content: "";
+	position: absolute;
+	background: url('https://mdn.mozillademos.org/files/6065/arrow.png') center no-repeat;
+	width: 100%;
+	height: 12px;
+	top: -12px;
+	z-index: 2;
+}
+
+#picker-samples #add-icon {
+	width: 100%;
+	height: 100%;
+	position: relative;
+	box-shadow: inset 0px 0px 2px 0px #DDD;
+}
+
+#picker-samples #add-icon:hover {
+	cursor: pointer;
+	border-color: #DDD;
+	box-shadow: inset 0px 0px 5px 0px #CCC;
+}
+
+#picker-samples #add-icon:before,
+#picker-samples #add-icon:after {
+	content: "";
+	position: absolute;
+	background-color: #EEE;
+	box-shadow: 0 0 1px 0 #EEE;
+}
+
+#picker-samples #add-icon:before {
+	width: 70%;
+	height: 16%;
+	top: 42%;
+	left: 15%;
+}
+
+#picker-samples #add-icon:after {
+	width: 16%;
+	height: 70%;
+	top: 15%;
+	left: 42%;
+}
+
+#picker-samples #add-icon:hover:before,
+#picker-samples #add-icon:hover:after {
+	background-color: #DDD;
+	box-shadow: 0 0 1px 0 #DDD;
+}
+
+/**
+ * 	Controls
+ */
+
+#controls {
+	width: 110px;
+	padding: 10px;
+	float: right;
+}
+
+#controls #picker-switch {
+	text-align: center;
+	float: left;
+}
+
+#controls .icon {
+	width: 48px;
+	height: 48px;
+	margin: 10px 0;
+	background-repeat: no-repeat;
+	background-position: center;
+	border: 1px solid #DDD;
+	display: table;
+	float: left;
+}
+
+#controls .icon:hover {
+	cursor: pointer;
+}
+
+#controls .picker-icon {
+	background-image: url('https://mdn.mozillademos.org/files/6081/picker.png');
+}
+
+#controls #void-sample {
+	margin-right: 10px;
+	background-image: url('https://mdn.mozillademos.org/files/6087/void.png');
+	background-position: center left;
+}
+
+#controls #void-sample[data-active='true'] {
+	border-color: #CCC;
+	background-position: center right;
+}
+
+#controls .switch {
+	width: 106px;
+	padding: 1px;
+	border: 1px solid #CCC;
+	font-size: 14px;
+	text-align: center;
+	line-height: 24px;
+	overflow: hidden;
+	float: left;
+}
+
+#controls .switch:hover {
+	cursor: pointer;
+}
+
+#controls .switch > * {
+	width: 50%;
+	padding: 2px 0;
+	background-color: #EEE;
+	float: left;
+}
+
+#controls .switch [data-active='true'] {
+	color: #FFF;
+	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
+	background-color: #777;
+}
+
+/**
+ * 	Trash Can
+ */
+
+#delete {
+	width: 100%;
+	height: 94px;
+	background-color: #DDD;
+	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
+	background-repeat: repeat;
+
+	text-align: center;
+	color: #777;
+
+	position: relative;
+	float: right;
+}
+
+#delete #trash-can {
+	width: 80%;
+	height: 80%;
+	border: 2px dashed #FFF;
+	border-radius: 5px;
+	background: url('https://mdn.mozillademos.org/files/6085/trash-can.png') no-repeat center;
+
+	position: absolute;
+	top: 10%;
+	left: 10%;
+
+	-moz-box-sizing: border-box;
+	-webkit-box-sizing: border-box;
+	box-sizing: border-box;
+
+	transition: all 0.2s;
+}
+
+#delete[drag-state='enter'] {
+	background-color: #999;
+}
+
+/**
+ * 	Color Theme
+ */
+
+#color-theme {
+	margin: 0 8px 0 0;
+	border: 1px solid #EEE;
+	display: inline-block;
+	float: right;
+}
+
+#color-theme .box {
+	width: 80px;
+	height: 92px;
+	float: left;
+}
+
+/**
+ * Color info box
+ */
+#color-info {
+	width: 360px;
+	float: left;
+}
+
+#color-info .title {
+	width: 100%;
+	padding: 15px;
+	font-size: 18px;
+	text-align: center;
+	background-image: url('https://mdn.mozillademos.org/files/6071/color-wheel.png');
+	background-repeat:no-repeat;
+	background-position: center left 30%;
+}
+
+#color-info .copy-container {
+	position: absolute;
+	top: -100%;
+}
+
+#color-info .property {
+	min-width: 280px;
+	height: 30px;
+	margin: 10px 0;
+	text-align: center;
+	line-height: 30px;
+}
+
+#color-info .property > * {
+	float: left;
+}
+
+#color-info .property .type {
+	width: 60px;
+	height: 100%;
+	padding: 0 16px 0 0;
+	text-align: right;
+}
+
+#color-info .property .value {
+	width: 200px;
+	height: 100%;
+	padding: 0 10px;
+	font-family: "Segoe UI", Arial, Helvetica, sans-serif;
+	font-size: 16px;
+	color: #777;
+	text-align: center;
+	background-color: #FFF;
+	border: none;
+}
+
+#color-info .property .value:hover {
+	color: #37994A;
+}
+
+#color-info .property .value:hover + .copy {
+	background-position: center right;
+}
+
+#color-info .property .copy {
+	width: 24px;
+	height: 100%;
+	padding: 0 5px;
+	background-color: #FFF;
+	background-image: url('https://mdn.mozillademos.org/files/6073/copy.png');
+	background-repeat: no-repeat;
+	background-position: center left;
+	border-left: 1px solid #EEE;
+	text-align: right;
+	float: left;
+}
+
+#color-info .property .copy:hover {
+	background-position: center right;
+}
+
+
+/**
+ * 	Color Palette
+ */
+
+#palette {
+	width: 1000px;
+	padding: 10px 0;
+	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
+	background-repeat: repeat;
+	background-color: #EEE;
+	color: #777;
+
+	-moz-box-sizing: border-box;
+	-webkit-box-sizing: border-box;
+	box-sizing: border-box;
+}
+
+#color-palette {
+	width: 640px;
+	font-family: Arial, Helvetica, sans-serif;
+	color: #777;
+	float: left;
+}
+
+#color-palette .container {
+	width: 100%;
+	height: 50px;
+	line-height: 50px;
+	overflow: hidden;
+	float: left;
+	transition: all 0.5s;
+}
+
+#color-palette .container > * {
+	float: left;
+}
+
+#color-palette .title {
+	width: 100px;
+	padding: 0 10px;
+	text-align: right;
+	line-height: inherit;
+}
+
+#color-palette .palette {
+	width: 456px;
+	height: 38px;
+	margin: 3px;
+	padding: 3px;
+	display: table;
+	background-color: #FFF;
+}
+
+#color-palette .palette .sample {
+	width: 30px;
+	height: 30px;
+	margin: 3px;
+	position: relative;
+	border: 1px solid #DDD;
+	float: left;
+	transition: all 0.2s;
+}
+
+#color-palette .palette .sample:hover {
+	cursor: pointer;
+	border-color: #BBB;
+	transform: scale(1.15);
+	border-radius: 3px;
+}
+
+#color-palette .controls {
+}
+
+#color-palette .controls > * {
+	float: left;
+}
+
+#color-palette .controls > *:hover {
+	cursor: pointer;
+}
+
+#color-palette .controls .lock {
+	width: 24px;
+	height: 24px;
+	margin: 10px;
+	padding: 3px;
+	background-image: url('https://mdn.mozillademos.org/files/6077/lock.png');
+	background-repeat: no-repeat;
+	background-position: bottom right;
+}
+
+#color-palette .controls .lock:hover {
+	/*background-image: url('images/unlocked-hover.png');*/
+	background-position: bottom left;
+}
+
+#color-palette .controls .lock[locked-state='true'] {
+	/*background-image: url('images/locked.png');*/
+	background-position: top left ;
+}
+
+#color-palette .controls .lock[locked-state='true']:hover {
+	/*background-image: url('images/lock-hover.png');*/
+	background-position: top right;
+}
+
+/**
+ * Canvas
+ */
+
+#canvas {
+	width: 100%;
+	height: 300px;
+	min-height: 250px;
+	border-top: 1px solid #DDD;
+	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
+	background-repeat: repeat;
+	position: relative;
+	float: left;
+}
+
+#canvas[data-tutorial='drop'] {
+	text-align: center;
+	font-size: 30px;
+	color: #777;
+}
+
+#canvas[data-tutorial='drop']:before {
+	content: "Drop colors here to compare";
+	width: 40%;
+	padding: 30px 9% 70px 11%;
+
+	background-image: url('https://mdn.mozillademos.org/files/6075/drop.png');
+	background-repeat: no-repeat;
+	background-position: left 35px top 60%;
+
+	text-align: right;
+
+	border: 3px dashed rgb(221, 221, 221);
+	border-radius: 15px;
+
+	position: absolute;
+	top: 50px;
+	left: 20%;
+}
+
+#canvas[data-tutorial='drop']:after {
+	content: "adjust, change or modify";
+	width: 40%;
+	font-size: 24px;
+	position: absolute;
+	top: 130px;
+	left: 32%;
+	z-index: 2;
+}
+
+#canvas [data-tutorial='dblclick'] {
+	background-color: #999 !important;
+}
+
+#canvas [data-tutorial='dblclick']:before {
+	content: "double click to activate";
+	width: 80px;
+	color: #FFF;
+	position: absolute;
+	top: 10%;
+	left: 20%;
+	z-index: 2;
+}
+
+#canvas .sample {
+	width: 100px;
+	height: 100px;
+	min-width: 20px;
+	min-height: 20px;
+	position: absolute;
+	border: 1px solid rgba(255, 255, 255, 0.3);
+}
+
+#canvas .sample:hover {
+	cursor: move;
+}
+
+#canvas .sample[data-active='true']:after {
+	content: "";
+	position: absolute;
+	background: url('https://mdn.mozillademos.org/files/6065/arrow.png') center no-repeat;
+	width: 100%;
+	height: 12px;
+	top: -12px;
+	z-index: 2;
+}
+
+#canvas .sample:hover > * {
+	cursor: pointer;
+	display: block !important;
+}
+
+#canvas .sample .resize-handle {
+	display: none;
+}
+
+#canvas .sample .pick {
+	width: 10px;
+	height: 10px;
+	margin: 5px;
+	background: url('https://mdn.mozillademos.org/files/6079/pick.png') center no-repeat;
+	position: absolute;
+	top: 0;
+	left: 0;
+	display: none;
+}
+
+#canvas .sample .delete {
+	width: 10px;
+	height: 10px;
+	margin: 5px;
+	background: url('https://mdn.mozillademos.org/files/6069/close.png') center no-repeat;
+	position: absolute;
+	top: 0;
+	right: 0;
+	display: none;
+}
+
+
+/**
+ * Canvas controls
+ */
+
+#canvas .toggle-bg {
+	width: 16px;
+	height: 16px;
+	margin: 5px;
+	background: url("images/canvas-controls.png") center left no-repeat;
+	position: absolute;
+	top: 0;
+	right: 0;
+}
+
+#canvas .toggle-bg:hover {
+	cursor: pointer;
+}
+
+#canvas[data-bg='true'] {
+	background: none;
+}
+
+#canvas[data-bg='true'] .toggle-bg {
+	background: url('https://mdn.mozillademos.org/files/6067/canvas-controls.png') center right no-repeat;
+}
+
+#zindex {
+	height: 20px;
+	margin: 5px;
+	font-size: 16px;
+	position: absolute;
+	opacity: 0;
+	top: -10000px;
+	left: 0;
+	color: #777;
+	float: left;
+	transition: opacity 1s;
+}
+
+#zindex input {
+	border: 1px solid #DDD;
+	font-size: 16px;
+	color: #777;
+}
+
+#zindex .ui-input-slider-info {
+	width: 60px;
+}
+
+#zindex[data-active='true'] {
+	top: 0;
+	opacity: 1;
+}
+
+
+ +

JavaScript Content

+ +
'use strict';
+
+var UIColorPicker = (function UIColorPicker() {
+
+	function getElemById(id) {
+		return document.getElementById(id);
+	}
+
+	var subscribers = [];
+	var pickers = [];
+
+	/**
+	 * RGBA Color class
+	 *
+	 * HSV/HSB and HSL (hue, saturation, value / brightness, lightness)
+	 * @param hue			0-360
+	 * @param saturation	0-100
+	 * @param value 		0-100
+	 * @param lightness		0-100
+	 */
+
+	function Color(color) {
+
+		if(color instanceof Color === true) {
+			this.copy(color);
+			return;
+		}
+
+		this.r = 0;
+		this.g = 0;
+		this.b = 0;
+		this.a = 1;
+		this.hue = 0;
+		this.saturation = 0;
+		this.value = 0;
+		this.lightness = 0;
+		this.format = 'HSV';
+	}
+
+	function RGBColor(r, g, b) {
+		var color = new Color();
+		color.setRGBA(r, g, b, 1);
+		return color;
+	}
+
+	function RGBAColor(r, g, b, a) {
+		var color = new Color();
+		color.setRGBA(r, g, b, a);
+		return color;
+	}
+
+	function HSVColor(h, s, v) {
+		var color = new Color();
+		color.setHSV(h, s, v);
+		return color;
+	}
+
+	function HSVAColor(h, s, v, a) {
+		var color = new Color();
+		color.setHSV(h, s, v);
+		color.a = a;
+		return color;
+	}
+
+	function HSLColor(h, s, l) {
+		var color = new Color();
+		color.setHSL(h, s, l);
+		return color;
+	}
+
+	function HSLAColor(h, s, l, a) {
+		var color = new Color();
+		color.setHSL(h, s, l);
+		color.a = a;
+		return color;
+	}
+
+	Color.prototype.copy = function copy(obj) {
+		if(obj instanceof Color !== true) {
+			console.log('Typeof parameter not Color');
+			return;
+		}
+
+		this.r = obj.r;
+		this.g = obj.g;
+		this.b = obj.b;
+		this.a = obj.a;
+		this.hue = obj.hue;
+		this.saturation = obj.saturation;
+		this.value = obj.value;
+		this.format = '' + obj.format;
+		this.lightness = obj.lightness;
+	};
+
+	Color.prototype.setFormat = function setFormat(format) {
+		if (format === 'HSV')
+			this.format = 'HSV';
+		if (format === 'HSL')
+			this.format = 'HSL';
+	};
+
+	/*========== Methods to set Color Properties ==========*/
+
+	Color.prototype.isValidRGBValue = function isValidRGBValue(value) {
+		return (typeof(value) === 'number' && isNaN(value) === false &&
+			value >= 0 && value <= 255);
+	};
+
+	Color.prototype.setRGBA = function setRGBA(red, green, blue, alpha) {
+		if (this.isValidRGBValue(red) === false ||
+			this.isValidRGBValue(green) === false ||
+			this.isValidRGBValue(blue) === false)
+			return;
+
+			this.r = red | 0;
+			this.g = green | 0;
+			this.b = blue | 0;
+
+		if (this.isValidRGBValue(alpha) === true)
+			this.a = alpha | 0;
+	};
+
+	Color.prototype.setByName = function setByName(name, value) {
+		if (name === 'r' || name === 'g' || name === 'b') {
+			if(this.isValidRGBValue(value) === false)
+				return;
+
+			this[name] = value;
+			this.updateHSX();
+		}
+	};
+
+	Color.prototype.setHSV = function setHSV(hue, saturation, value) {
+		this.hue = hue;
+		this.saturation = saturation;
+		this.value = value;
+		this.HSVtoRGB();
+	};
+
+	Color.prototype.setHSL = function setHSL(hue, saturation, lightness) {
+		this.hue = hue;
+		this.saturation = saturation;
+		this.lightness = lightness;
+		this.HSLtoRGB();
+	};
+
+	Color.prototype.setHue = function setHue(value) {
+		if (typeof(value) !== 'number' || isNaN(value) === true ||
+			value < 0 || value > 359)
+			return;
+		this.hue = value;
+		this.updateRGB();
+	};
+
+	Color.prototype.setSaturation = function setSaturation(value) {
+		if (typeof(value) !== 'number' || isNaN(value) === true ||
+			value < 0 || value > 100)
+			return;
+		this.saturation = value;
+		this.updateRGB();
+	};
+
+	Color.prototype.setValue = function setValue(value) {
+		if (typeof(value) !== 'number' || isNaN(value) === true ||
+			value < 0 || value > 100)
+			return;
+		this.value = value;
+		this.HSVtoRGB();
+	};
+
+	Color.prototype.setLightness = function setLightness(value) {
+		if (typeof(value) !== 'number' || isNaN(value) === true ||
+			value < 0 || value > 100)
+			return;
+		this.lightness = value;
+		this.HSLtoRGB();
+	};
+
+	Color.prototype.setHexa = function setHexa(value) {
+		var valid  = /(^#{0,1}[0-9A-F]{6}$)|(^#{0,1}[0-9A-F]{3}$)/i.test(value);
+
+		if (valid !== true)
+			return;
+
+		if (value[0] === '#')
+			value = value.slice(1, value.length);
+
+		if (value.length === 3)
+			value = value.replace(/([0-9A-F])([0-9A-F])([0-9A-F])/i,'$1$1$2$2$3$3');
+
+		this.r = parseInt(value.substr(0, 2), 16);
+		this.g = parseInt(value.substr(2, 2), 16);
+		this.b = parseInt(value.substr(4, 2), 16);
+
+		this.alpha	= 1;
+		this.RGBtoHSV();
+	};
+
+	/*========== Conversion Methods ==========*/
+
+	Color.prototype.convertToHSL = function convertToHSL() {
+		if (this.format === 'HSL')
+			return;
+
+		this.setFormat('HSL');
+		this.RGBtoHSL();
+	};
+
+	Color.prototype.convertToHSV = function convertToHSV() {
+		if (this.format === 'HSV')
+			return;
+
+		this.setFormat('HSV');
+		this.RGBtoHSV();
+	};
+
+	/*========== Update Methods ==========*/
+
+	Color.prototype.updateRGB = function updateRGB() {
+		if (this.format === 'HSV') {
+			this.HSVtoRGB();
+			return;
+		}
+
+		if (this.format === 'HSL') {
+			this.HSLtoRGB();
+			return;
+		}
+	};
+
+	Color.prototype.updateHSX = function updateHSX() {
+		if (this.format === 'HSV') {
+			this.RGBtoHSV();
+			return;
+		}
+
+		if (this.format === 'HSL') {
+			this.RGBtoHSL();
+			return;
+		}
+	};
+
+	Color.prototype.HSVtoRGB = function HSVtoRGB() {
+		var sat = this.saturation / 100;
+		var value = this.value / 100;
+		var C = sat * value;
+		var H = this.hue / 60;
+		var X = C * (1 - Math.abs(H % 2 - 1));
+		var m = value - C;
+		var precision = 255;
+
+		C = (C + m) * precision | 0;
+		X = (X + m) * precision | 0;
+		m = m * precision | 0;
+
+		if (H >= 0 && H < 1) {	this.setRGBA(C, X, m);	return; }
+		if (H >= 1 && H < 2) {	this.setRGBA(X, C, m);	return; }
+		if (H >= 2 && H < 3) {	this.setRGBA(m, C, X);	return; }
+		if (H >= 3 && H < 4) {	this.setRGBA(m, X, C);	return; }
+		if (H >= 4 && H < 5) {	this.setRGBA(X, m, C);	return; }
+		if (H >= 5 && H < 6) {	this.setRGBA(C, m, X);	return; }
+	};
+
+	Color.prototype.HSLtoRGB = function HSLtoRGB() {
+		var sat = this.saturation / 100;
+		var light = this.lightness / 100;
+		var C = sat * (1 - Math.abs(2 * light - 1));
+		var H = this.hue / 60;
+		var X = C * (1 - Math.abs(H % 2 - 1));
+		var m = light - C/2;
+		var precision = 255;
+
+		C = (C + m) * precision | 0;
+		X = (X + m) * precision | 0;
+		m = m * precision | 0;
+
+		if (H >= 0 && H < 1) {	this.setRGBA(C, X, m);	return; }
+		if (H >= 1 && H < 2) {	this.setRGBA(X, C, m);	return; }
+		if (H >= 2 && H < 3) {	this.setRGBA(m, C, X);	return; }
+		if (H >= 3 && H < 4) {	this.setRGBA(m, X, C);	return; }
+		if (H >= 4 && H < 5) {	this.setRGBA(X, m, C);	return; }
+		if (H >= 5 && H < 6) {	this.setRGBA(C, m, X);	return; }
+	};
+
+	Color.prototype.RGBtoHSV = function RGBtoHSV() {
+		var red		= this.r / 255;
+		var green	= this.g / 255;
+		var blue	= this.b / 255;
+
+		var cmax = Math.max(red, green, blue);
+		var cmin = Math.min(red, green, blue);
+		var delta = cmax - cmin;
+		var hue = 0;
+		var saturation = 0;
+
+		if (delta) {
+			if (cmax === red ) { hue = ((green - blue) / delta); }
+			if (cmax === green ) { hue = 2 + (blue - red) / delta; }
+			if (cmax === blue ) { hue = 4 + (red - green) / delta; }
+			if (cmax) saturation = delta / cmax;
+		}
+
+		this.hue = 60 * hue | 0;
+		if (this.hue < 0) this.hue += 360;
+		this.saturation = (saturation * 100) | 0;
+		this.value = (cmax * 100) | 0;
+	};
+
+	Color.prototype.RGBtoHSL = function RGBtoHSL() {
+		var red		= this.r / 255;
+		var green	= this.g / 255;
+		var blue	= this.b / 255;
+
+		var cmax = Math.max(red, green, blue);
+		var cmin = Math.min(red, green, blue);
+		var delta = cmax - cmin;
+		var hue = 0;
+		var saturation = 0;
+		var lightness = (cmax + cmin) / 2;
+		var X = (1 - Math.abs(2 * lightness - 1));
+
+		if (delta) {
+			if (cmax === red ) { hue = ((green - blue) / delta); }
+			if (cmax === green ) { hue = 2 + (blue - red) / delta; }
+			if (cmax === blue ) { hue = 4 + (red - green) / delta; }
+			if (cmax) saturation = delta / X;
+		}
+
+		this.hue = 60 * hue | 0;
+		if (this.hue < 0) this.hue += 360;
+		this.saturation = (saturation * 100) | 0;
+		this.lightness = (lightness * 100) | 0;
+	};
+
+	/*========== Get Methods ==========*/
+
+	Color.prototype.getHexa = function getHexa() {
+		var r = this.r.toString(16);
+		var g = this.g.toString(16);
+		var b = this.b.toString(16);
+		if (this.r < 16) r = '0' + r;
+		if (this.g < 16) g = '0' + g;
+		if (this.b < 16) b = '0' + b;
+		var value = '#' + r + g + b;
+		return value.toUpperCase();
+	};
+
+	Color.prototype.getRGBA = function getRGBA() {
+
+		var rgb = '(' + this.r + ', ' + this.g + ', ' + this.b;
+		var a = '';
+		var v = '';
+		var x = parseFloat(this.a);
+		if (x !== 1) {
+			a = 'a';
+			v = ', ' + x;
+		}
+
+		var value = 'rgb' + a + rgb + v + ')';
+		return value;
+	};
+
+	Color.prototype.getHSLA = function getHSLA() {
+		if (this.format === 'HSV') {
+			var color = new Color(this);
+			color.setFormat('HSL');
+			color.updateHSX();
+			return color.getHSLA();
+		}
+
+		var a = '';
+		var v = '';
+		var hsl = '(' + this.hue + ', ' + this.saturation + '%, ' + this.lightness +'%';
+		var x = parseFloat(this.a);
+		if (x !== 1) {
+			a = 'a';
+			v = ', ' + x;
+		}
+
+		var value = 'hsl' + a + hsl + v + ')';
+		return value;
+	};
+
+	Color.prototype.getColor = function getColor() {
+		if (this.a | 0 === 1)
+			return this.getHexa();
+		return this.getRGBA();
+	};
+
+	/*=======================================================================*/
+	/*=======================================================================*/
+
+	/*========== Capture Mouse Movement ==========*/
+
+	var setMouseTracking = function setMouseTracking(elem, callback) {
+		elem.addEventListener('mousedown', function(e) {
+			callback(e);
+			document.addEventListener('mousemove', callback);
+		});
+
+		document.addEventListener('mouseup', function(e) {
+			document.removeEventListener('mousemove', callback);
+		});
+	};
+
+	/*====================*/
+	// Color Picker Class
+	/*====================*/
+
+	function ColorPicker(node) {
+		this.color = new Color();
+		this.node = node;
+		this.subscribers = [];
+
+		var type = this.node.getAttribute('data-mode');
+		var topic = this.node.getAttribute('data-topic');
+
+		this.topic = topic;
+		this.picker_mode = (type === 'HSL') ? 'HSL' : 'HSV';
+		this.color.setFormat(this.picker_mode);
+
+		this.createPickingArea();
+		this.createHueArea();
+
+		this.newInputComponent('H', 'hue', this.inputChangeHue.bind(this));
+		this.newInputComponent('S', 'saturation', this.inputChangeSaturation.bind(this));
+		this.newInputComponent('V', 'value', this.inputChangeValue.bind(this));
+		this.newInputComponent('L', 'lightness', this.inputChangeLightness.bind(this));
+
+		this.createAlphaArea();
+
+		this.newInputComponent('R', 'red', this.inputChangeRed.bind(this));
+		this.newInputComponent('G', 'green', this.inputChangeGreen.bind(this));
+		this.newInputComponent('B', 'blue', this.inputChangeBlue.bind(this));
+
+		this.createPreviewBox();
+		this.createChangeModeButton();
+
+		this.newInputComponent('alpha', 'alpha', this.inputChangeAlpha.bind(this));
+		this.newInputComponent('hexa', 'hexa', this.inputChangeHexa.bind(this));
+
+		this.setColor(this.color);
+		pickers[topic] = this;
+	}
+
+	/*************************************************************************/
+	//				Function for generating the color-picker
+	/*************************************************************************/
+
+	ColorPicker.prototype.createPickingArea = function createPickingArea() {
+		var area = document.createElement('div');
+		var picker = document.createElement('div');
+
+		area.className = 'picking-area';
+		picker.className = 'picker';
+
+		this.picking_area = area;
+		this.color_picker = picker;
+		setMouseTracking(area, this.updateColor.bind(this));
+
+		area.appendChild(picker);
+		this.node.appendChild(area);
+	};
+
+	ColorPicker.prototype.createHueArea = function createHueArea() {
+		var area = document.createElement('div');
+		var picker = document.createElement('div');
+
+		area.className = 'hue';
+		picker.className ='slider-picker';
+
+		this.hue_area = area;
+		this.hue_picker = picker;
+		setMouseTracking(area, this.updateHueSlider.bind(this));
+
+		area.appendChild(picker);
+		this.node.appendChild(area);
+	};
+
+	ColorPicker.prototype.createAlphaArea = function createAlphaArea() {
+		var area = document.createElement('div');
+		var mask = document.createElement('div');
+		var picker = document.createElement('div');
+
+		area.className = 'alpha';
+		mask.className = 'alpha-mask';
+		picker.className = 'slider-picker';
+
+		this.alpha_area = area;
+		this.alpha_mask = mask;
+		this.alpha_picker = picker;
+		setMouseTracking(area, this.updateAlphaSlider.bind(this));
+
+		area.appendChild(mask);
+		mask.appendChild(picker);
+		this.node.appendChild(area);
+	};
+
+	ColorPicker.prototype.createPreviewBox = function createPreviewBox(e) {
+		var preview_box = document.createElement('div');
+		var preview_color = document.createElement('div');
+
+		preview_box.className = 'preview';
+		preview_color.className = 'preview-color';
+
+		this.preview_color = preview_color;
+
+		preview_box.appendChild(preview_color);
+		this.node.appendChild(preview_box);
+	};
+
+	ColorPicker.prototype.newInputComponent = function newInputComponent(title, topic, onChangeFunc) {
+		var wrapper = document.createElement('div');
+		var input = document.createElement('input');
+		var info = document.createElement('span');
+
+		wrapper.className = 'input';
+		wrapper.setAttribute('data-topic', topic);
+		info.textContent = title;
+		info.className = 'name';
+		input.setAttribute('type', 'text');
+
+		wrapper.appendChild(info);
+		wrapper.appendChild(input);
+		this.node.appendChild(wrapper);
+
+		input.addEventListener('change', onChangeFunc);
+		input.addEventListener('click', function() {
+			this.select();
+		});
+
+		this.subscribe(topic, function(value) {
+			input.value = value;
+		});
+	};
+
+	ColorPicker.prototype.createChangeModeButton = function createChangeModeButton() {
+
+		var button = document.createElement('div');
+		button.className = 'switch_mode';
+		button.addEventListener('click', function() {
+			if (this.picker_mode === 'HSV')
+				this.setPickerMode('HSL');
+			else
+				this.setPickerMode('HSV');
+
+		}.bind(this));
+
+		this.node.appendChild(button);
+	};
+
+	/*************************************************************************/
+	//					Updates properties of UI elements
+	/*************************************************************************/
+
+	ColorPicker.prototype.updateColor = function updateColor(e) {
+		var x = e.pageX - this.picking_area.offsetLeft;
+		var y = e.pageY - this.picking_area.offsetTop;
+		var picker_offset = 5;
+
+		// width and height should be the same
+		var size = this.picking_area.clientWidth;
+
+		if (x > size) x = size;
+		if (y > size) y = size;
+		if (x < 0) x = 0;
+		if (y < 0) y = 0;
+
+		var value = 100 - (y * 100 / size) | 0;
+		var saturation = x * 100 / size | 0;
+
+		if (this.picker_mode === 'HSV')
+			this.color.setHSV(this.color.hue, saturation, value);
+		if (this.picker_mode === 'HSL')
+			this.color.setHSL(this.color.hue, saturation, value);
+
+		this.color_picker.style.left = x - picker_offset + 'px';
+		this.color_picker.style.top = y - picker_offset + 'px';
+
+		this.updateAlphaGradient();
+		this.updatePreviewColor();
+
+		this.notify('value', value);
+		this.notify('lightness', value);
+		this.notify('saturation', saturation);
+
+		this.notify('red', this.color.r);
+		this.notify('green', this.color.g);
+		this.notify('blue', this.color.b);
+		this.notify('hexa', this.color.getHexa());
+
+		notify(this.topic, this.color);
+	};
+
+	ColorPicker.prototype.updateHueSlider = function updateHueSlider(e) {
+		var x = e.pageX - this.hue_area.offsetLeft;
+		var width = this.hue_area.clientWidth;
+
+		if (x < 0) x = 0;
+		if (x > width) x = width;
+
+		// TODO 360 => 359
+		var hue = ((359 * x) / width) | 0;
+		// if (hue === 360) hue = 359;
+
+		this.updateSliderPosition(this.hue_picker, x);
+		this.setHue(hue);
+	};
+
+	ColorPicker.prototype.updateAlphaSlider = function updateAlphaSlider(e) {
+		var x = e.pageX - this.alpha_area.offsetLeft;
+		var width = this.alpha_area.clientWidth;
+
+		if (x < 0) x = 0;
+		if (x > width) x = width;
+
+		this.color.a = (x / width).toFixed(2);
+
+		this.updateSliderPosition(this.alpha_picker, x);
+		this.updatePreviewColor();
+
+		this.notify('alpha', this.color.a);
+		notify(this.topic, this.color);
+	};
+
+	ColorPicker.prototype.setHue = function setHue(value) {
+		this.color.setHue(value);
+
+		this.updatePickerBackground();
+		this.updateAlphaGradient();
+		this.updatePreviewColor();
+
+		this.notify('red', this.color.r);
+		this.notify('green', this.color.g);
+		this.notify('blue', this.color.b);
+		this.notify('hexa', this.color.getHexa());
+		this.notify('hue', this.color.hue);
+
+		notify(this.topic, this.color);
+	};
+
+	// Updates when one of Saturation/Value/Lightness changes
+	ColorPicker.prototype.updateSLV = function updateSLV() {
+		this.updatePickerPosition();
+		this.updateAlphaGradient();
+		this.updatePreviewColor();
+
+		this.notify('red', this.color.r);
+		this.notify('green', this.color.g);
+		this.notify('blue', this.color.b);
+		this.notify('hexa', this.color.getHexa());
+
+		notify(this.topic, this.color);
+	};
+
+	/*************************************************************************/
+	//				Update positions of various UI elements
+	/*************************************************************************/
+
+	ColorPicker.prototype.updatePickerPosition = function updatePickerPosition() {
+		var size = this.picking_area.clientWidth;
+		var value = 0;
+		var offset = 5;
+
+		if (this.picker_mode === 'HSV')
+			value = this.color.value;
+		if (this.picker_mode === 'HSL')
+			value = this.color.lightness;
+
+		var x = (this.color.saturation * size / 100) | 0;
+		var y = size - (value * size / 100) | 0;
+
+		this.color_picker.style.left = x - offset + 'px';
+		this.color_picker.style.top = y - offset + 'px';
+	};
+
+	ColorPicker.prototype.updateSliderPosition = function updateSliderPosition(elem, pos) {
+		elem.style.left = Math.max(pos - 3, -2) + 'px';
+	};
+
+	ColorPicker.prototype.updateHuePicker = function updateHuePicker() {
+		var size = this.hue_area.clientWidth;
+		var offset = 1;
+		var pos = (this.color.hue * size / 360 ) | 0;
+		this.hue_picker.style.left = pos - offset + 'px';
+	};
+
+	ColorPicker.prototype.updateAlphaPicker = function updateAlphaPicker() {
+		var size = this.alpha_area.clientWidth;
+		var offset = 1;
+		var pos = (this.color.a * size) | 0;
+		this.alpha_picker.style.left = pos - offset + 'px';
+	};
+
+	/*************************************************************************/
+	//						Update background colors
+	/*************************************************************************/
+
+	ColorPicker.prototype.updatePickerBackground = function updatePickerBackground() {
+		var nc = new Color(this.color);
+		nc.setHSV(nc.hue, 100, 100);
+		this.picking_area.style.backgroundColor = nc.getHexa();
+	};
+
+	ColorPicker.prototype.updateAlphaGradient = function updateAlphaGradient() {
+		this.alpha_mask.style.backgroundColor = this.color.getHexa();
+	};
+
+	ColorPicker.prototype.updatePreviewColor = function updatePreviewColor() {
+		this.preview_color.style.backgroundColor = this.color.getColor();
+	};
+
+	/*************************************************************************/
+	//						Update input elements
+	/*************************************************************************/
+
+	ColorPicker.prototype.inputChangeHue = function inputChangeHue(e) {
+		var value = parseInt(e.target.value);
+		this.setHue(value);
+		this.updateHuePicker();
+	};
+
+	ColorPicker.prototype.inputChangeSaturation = function inputChangeSaturation(e) {
+		var value = parseInt(e.target.value);
+		this.color.setSaturation(value);
+		e.target.value = this.color.saturation;
+		this.updateSLV();
+	};
+
+	ColorPicker.prototype.inputChangeValue = function inputChangeValue(e) {
+		var value = parseInt(e.target.value);
+		this.color.setValue(value);
+		e.target.value = this.color.value;
+		this.updateSLV();
+	};
+
+	ColorPicker.prototype.inputChangeLightness = function inputChangeLightness(e) {
+		var value = parseInt(e.target.value);
+		this.color.setLightness(value);
+		e.target.value = this.color.lightness;
+		this.updateSLV();
+	};
+
+	ColorPicker.prototype.inputChangeRed = function inputChangeRed(e) {
+		var value = parseInt(e.target.value);
+		this.color.setByName('r', value);
+		e.target.value = this.color.r;
+		this.setColor(this.color);
+	};
+
+	ColorPicker.prototype.inputChangeGreen = function inputChangeGreen(e) {
+		var value = parseInt(e.target.value);
+		this.color.setByName('g', value);
+		e.target.value = this.color.g;
+		this.setColor(this.color);
+	};
+
+	ColorPicker.prototype.inputChangeBlue = function inputChangeBlue(e) {
+		var value = parseInt(e.target.value);
+		this.color.setByName('b', value);
+		e.target.value = this.color.b;
+		this.setColor(this.color);
+	};
+
+	ColorPicker.prototype.inputChangeAlpha = function inputChangeAlpha(e) {
+		var value = parseFloat(e.target.value);
+
+		if (typeof value === 'number' && isNaN(value) === false &&
+			value >= 0 && value <= 1)
+			this.color.a = value.toFixed(2);
+
+		e.target.value = this.color.a;
+		this.updateAlphaPicker();
+	};
+
+	ColorPicker.prototype.inputChangeHexa = function inputChangeHexa(e) {
+		var value = e.target.value;
+		this.color.setHexa(value);
+		this.setColor(this.color);
+	};
+
+	/*************************************************************************/
+	//							Internal Pub/Sub
+	/*************************************************************************/
+
+	ColorPicker.prototype.subscribe = function subscribe(topic, callback) {
+		this.subscribers[topic] = callback;
+	};
+
+	ColorPicker.prototype.notify = function notify(topic, value) {
+		if (this.subscribers[topic])
+			this.subscribers[topic](value);
+	};
+
+	/*************************************************************************/
+	//							Set Picker Properties
+	/*************************************************************************/
+
+	ColorPicker.prototype.setColor = function setColor(color) {
+		if(color instanceof Color !== true) {
+			console.log('Typeof parameter not Color');
+			return;
+		}
+
+		if (color.format !== this.picker_mode) {
+			color.setFormat(this.picker_mode);
+			color.updateHSX();
+		}
+
+		this.color.copy(color);
+		this.updateHuePicker();
+		this.updatePickerPosition();
+		this.updatePickerBackground();
+		this.updateAlphaPicker();
+		this.updateAlphaGradient();
+		this.updatePreviewColor();
+
+		this.notify('red', this.color.r);
+		this.notify('green', this.color.g);
+		this.notify('blue', this.color.b);
+
+		this.notify('hue', this.color.hue);
+		this.notify('saturation', this.color.saturation);
+		this.notify('value', this.color.value);
+		this.notify('lightness', this.color.lightness);
+
+		this.notify('alpha', this.color.a);
+		this.notify('hexa', this.color.getHexa());
+		notify(this.topic, this.color);
+	};
+
+	ColorPicker.prototype.setPickerMode = function setPickerMode(mode) {
+		if (mode !== 'HSV' && mode !== 'HSL')
+			return;
+
+		this.picker_mode = mode;
+		this.node.setAttribute('data-mode', this.picker_mode);
+		this.setColor(this.color);
+	};
+
+	/*************************************************************************/
+	//								UNUSED
+	/*************************************************************************/
+
+	var setPickerMode = function setPickerMode(topic, mode) {
+		if (pickers[topic])
+			pickers[topic].setPickerMode(mode);
+	};
+
+	var setColor = function setColor(topic, color) {
+		if (pickers[topic])
+			pickers[topic].setColor(color);
+	};
+
+	var getColor = function getColor(topic) {
+		if (pickers[topic])
+			return new Color(pickers[topic].color);
+	};
+
+	var subscribe = function subscribe(topic, callback) {
+		if (subscribers[topic] === undefined)
+			subscribers[topic] = [];
+
+		subscribers[topic].push(callback);
+	};
+
+	var unsubscribe = function unsubscribe(callback) {
+		subscribers.indexOf(callback);
+		subscribers.splice(index, 1);
+	};
+
+	var notify = function notify(topic, value) {
+		if (subscribers[topic] === undefined || subscribers[topic].length === 0)
+			return;
+
+		var color = new Color(value);
+		for (var i in subscribers[topic])
+			subscribers[topic][i](color);
+	};
+
+	var init = function init() {
+		var elem = document.querySelectorAll('.ui-color-picker');
+		var size = elem.length;
+		for (var i = 0; i < size; i++)
+			new ColorPicker(elem[i]);
+	};
+
+	return {
+		init : init,
+		Color : Color,
+		RGBColor : RGBColor,
+		RGBAColor : RGBAColor,
+		HSVColor : HSVColor,
+		HSVAColor : HSVAColor,
+		HSLColor : HSLColor,
+		HSLAColor : HSLAColor,
+		setColor : setColor,
+		getColor : getColor,
+		subscribe : subscribe,
+		unsubscribe : unsubscribe,
+		setPickerMode : setPickerMode
+	};
+
+})();
+
+
+
+/**
+ * UI-SlidersManager
+ */
+
+var InputSliderManager = (function InputSliderManager() {
+
+	var subscribers = {};
+	var sliders = [];
+
+	var InputComponent = function InputComponent(obj) {
+		var input = document.createElement('input');
+		input.setAttribute('type', 'text');
+		input.style.width = 50 + obj.precision * 10 + 'px';
+
+		input.addEventListener('click', function(e) {
+			this.select();
+		});
+
+		input.addEventListener('change', function(e) {
+			var value = parseFloat(e.target.value);
+
+			if (isNaN(value) === true)
+				setValue(obj.topic, obj.value);
+			else
+				setValue(obj.topic, value);
+		});
+
+		return input;
+	};
+
+	var SliderComponent = function SliderComponent(obj, sign) {
+		var slider = document.createElement('div');
+		var startX = null;
+		var start_value = 0;
+
+		slider.addEventListener("click", function(e) {
+			document.removeEventListener("mousemove", sliderMotion);
+			setValue(obj.topic, obj.value + obj.step * sign);
+		});
+
+		slider.addEventListener("mousedown", function(e) {
+			startX = e.clientX;
+			start_value = obj.value;
+			document.body.style.cursor = "e-resize";
+
+			document.addEventListener("mouseup", slideEnd);
+			document.addEventListener("mousemove", sliderMotion);
+		});
+
+		var slideEnd = function slideEnd(e) {
+			document.removeEventListener("mousemove", sliderMotion);
+			document.body.style.cursor = "auto";
+			slider.style.cursor = "pointer";
+		};
+
+		var sliderMotion = function sliderMotion(e) {
+			slider.style.cursor = "e-resize";
+			var delta = (e.clientX - startX) / obj.sensivity | 0;
+			var value = delta * obj.step + start_value;
+			setValue(obj.topic, value);
+		};
+
+		return slider;
+	};
+
+	var InputSlider = function(node) {
+		var min		= parseFloat(node.getAttribute('data-min'));
+		var max		= parseFloat(node.getAttribute('data-max'));
+		var step	= parseFloat(node.getAttribute('data-step'));
+		var value	= parseFloat(node.getAttribute('data-value'));
+		var topic	= node.getAttribute('data-topic');
+		var unit	= node.getAttribute('data-unit');
+		var name 	= node.getAttribute('data-info');
+		var sensivity = node.getAttribute('data-sensivity') | 0;
+		var precision = node.getAttribute('data-precision') | 0;
+
+		this.min = isNaN(min) ? 0 : min;
+		this.max = isNaN(max) ? 100 : max;
+		this.precision = precision >= 0 ? precision : 0;
+		this.step = step < 0 || isNaN(step) ? 1 : step.toFixed(precision);
+		this.topic = topic;
+		this.node = node;
+		this.unit = unit === null ? '' : unit;
+		this.sensivity = sensivity > 0 ? sensivity : 5;
+		value = isNaN(value) ? this.min : value;
+
+		var input = new InputComponent(this);
+		var slider_left  = new SliderComponent(this, -1);
+		var slider_right = new SliderComponent(this,  1);
+
+		slider_left.className = 'ui-input-slider-left';
+		slider_right.className = 'ui-input-slider-right';
+
+		if (name) {
+			var info = document.createElement('span');
+			info.className = 'ui-input-slider-info';
+			info.textContent = name;
+			node.appendChild(info);
+		}
+
+		node.appendChild(slider_left);
+		node.appendChild(input);
+		node.appendChild(slider_right);
+
+		this.input = input;
+		sliders[topic] = this;
+		setValue(topic, value);
+	};
+
+	InputSlider.prototype.setInputValue = function setInputValue() {
+		this.input.value = this.value.toFixed(this.precision) + this.unit;
+	};
+
+	var setValue = function setValue(topic, value, send_notify) {
+		var slider = sliders[topic];
+		if (slider === undefined)
+			return;
+
+		value = parseFloat(value.toFixed(slider.precision));
+
+		if (value > slider.max) value = slider.max;
+		if (value < slider.min)	value = slider.min;
+
+		slider.value = value;
+		slider.node.setAttribute('data-value', value);
+
+		slider.setInputValue();
+
+		if (send_notify === false)
+			return;
+
+		notify.call(slider);
+	};
+
+	var setMax = function setMax(topic, value) {
+		var slider = sliders[topic];
+		if (slider === undefined)
+			return;
+
+		slider.max = value;
+		setValue(topic, slider.value);
+	};
+
+	var setMin = function setMin(topic, value) {
+		var slider = sliders[topic];
+		if (slider === undefined)
+			return;
+
+		slider.min = value;
+		setValue(topic, slider.value);
+	};
+
+	var setUnit = function setUnit(topic, unit) {
+		var slider = sliders[topic];
+		if (slider === undefined)
+			return;
+
+		slider.unit = unit;
+		setValue(topic, slider.value);
+	};
+
+	var setStep = function setStep(topic, value) {
+		var slider = sliders[topic];
+		if (slider === undefined)
+			return;
+
+		slider.step = parseFloat(value);
+		setValue(topic, slider.value);
+	};
+
+	var setPrecision = function setPrecision(topic, value) {
+		var slider = sliders[topic];
+		if (slider === undefined)
+			return;
+
+		value = value | 0;
+		slider.precision = value;
+
+		var step = parseFloat(slider.step.toFixed(value));
+		if (step === 0)
+			slider.step = 1 / Math.pow(10, value);
+
+		setValue(topic, slider.value);
+	};
+
+	var setSensivity = function setSensivity(topic, value) {
+		var slider = sliders[topic];
+		if (slider === undefined)
+			return;
+
+		value = value | 0;
+
+		slider.sensivity = value > 0 ? value : 5;
+	};
+
+	var getNode =  function getNode(topic) {
+		return sliders[topic].node;
+	};
+
+	var getPrecision =  function getPrecision(topic) {
+		return sliders[topic].precision;
+	};
+
+	var getStep =  function getStep(topic) {
+		return sliders[topic].step;
+	};
+
+	var subscribe = function subscribe(topic, callback) {
+		if (subscribers[topic] === undefined)
+			subscribers[topic] = [];
+		subscribers[topic].push(callback);
+	};
+
+	var unsubscribe = function unsubscribe(topic, callback) {
+		subscribers[topic].indexOf(callback);
+		subscribers[topic].splice(index, 1);
+	};
+
+	var notify = function notify() {
+		if (subscribers[this.topic] === undefined)
+			return;
+		for (var i = 0; i < subscribers[this.topic].length; i++)
+			subscribers[this.topic][i](this.value);
+	};
+
+	var createSlider = function createSlider(topic, label) {
+		var slider = document.createElement('div');
+		slider.className = 'ui-input-slider';
+		slider.setAttribute('data-topic', topic);
+
+		if (label !== undefined)
+			slider.setAttribute('data-info', label);
+
+		new InputSlider(slider);
+		return slider;
+	};
+
+	var init = function init() {
+		var elem = document.querySelectorAll('.ui-input-slider');
+		var size = elem.length;
+		for (var i = 0; i < size; i++)
+			new InputSlider(elem[i]);
+	};
+
+	return {
+		init : init,
+		setMax : setMax,
+		setMin : setMin,
+		setUnit : setUnit,
+		setStep : setStep,
+		getNode : getNode,
+		getStep : getStep,
+		setValue : setValue,
+		subscribe : subscribe,
+		unsubscribe : unsubscribe,
+		setPrecision : setPrecision,
+		setSensivity : setSensivity,
+		getPrecision : getPrecision,
+		createSlider : createSlider,
+	};
+
+})();
+
+
+'use strict';
+
+window.addEventListener("load", function() {
+	ColorPickerTool.init();
+});
+
+var ColorPickerTool = (function ColorPickerTool() {
+
+	/*========== Get DOM Element By ID ==========*/
+
+	function getElemById(id) {
+		return document.getElementById(id);
+	}
+
+	function allowDropEvent(e) {
+		e.preventDefault();
+	}
+
+	/*========== Make an element resizable relative to it's parent ==========*/
+
+	var UIComponent = (function UIComponent() {
+
+		function makeResizable(elem, axis) {
+			var valueX = 0;
+			var valueY = 0;
+			var action = 0;
+
+			var resizeStart = function resizeStart(e) {
+				e.stopPropagation();
+				e.preventDefault();
+				if (e.button !== 0)
+					return;
+
+				valueX = e.clientX - elem.clientWidth;
+				valueY = e.clientY - elem.clientHeight;
+
+				document.body.setAttribute('data-resize', axis);
+				document.addEventListener('mousemove', mouseMove);
+				document.addEventListener('mouseup', resizeEnd);
+			};
+
+			var mouseMove = function mouseMove(e) {
+				if (action >= 0)
+					elem.style.width = e.clientX - valueX + 'px';
+				if (action <= 0)
+					elem.style.height = e.clientY - valueY + 'px';
+			};
+
+			var resizeEnd = function resizeEnd(e) {
+				if (e.button !== 0)
+					return;
+
+				document.body.removeAttribute('data-resize', axis);
+				document.removeEventListener('mousemove', mouseMove);
+				document.removeEventListener('mouseup', resizeEnd);
+			};
+
+			var handle = document.createElement('div');
+			handle.className = 'resize-handle';
+
+			if (axis === 'width') action = 1;
+			else if (axis === 'height') action = -1;
+			else axis = 'both';
+
+			handle.className = 'resize-handle';
+			handle.setAttribute('data-resize', axis);
+			handle.addEventListener('mousedown', resizeStart);
+			elem.appendChild(handle);
+		};
+
+		/*========== Make an element draggable relative to it's parent ==========*/
+
+		var makeDraggable = function makeDraggable(elem, endFunction) {
+
+			var offsetTop;
+			var offsetLeft;
+
+			elem.setAttribute('data-draggable', 'true');
+
+			var dragStart = function dragStart(e) {
+				e.preventDefault();
+				e.stopPropagation();
+
+				if (e.target.getAttribute('data-draggable') !== 'true' ||
+					e.target !== elem || e.button !== 0)
+					return;
+
+				offsetLeft = e.clientX - elem.offsetLeft;
+				offsetTop = e.clientY - elem.offsetTop;
+
+				document.addEventListener('mousemove', mouseDrag);
+				document.addEventListener('mouseup', dragEnd);
+			};
+
+			var dragEnd = function dragEnd(e) {
+				if (e.button !== 0)
+					return;
+
+				document.removeEventListener('mousemove', mouseDrag);
+				document.removeEventListener('mouseup', dragEnd);
+			};
+
+			var mouseDrag = function mouseDrag(e) {
+				elem.style.left = e.clientX - offsetLeft + 'px';
+				elem.style.top = e.clientY - offsetTop + 'px';
+			};
+
+			elem.addEventListener('mousedown', dragStart, false);
+		};
+
+		return {
+			makeResizable : makeResizable,
+			makeDraggable : makeDraggable
+		};
+
+	})();
+
+	/*========== Color Class ==========*/
+
+	var Color = UIColorPicker.Color;
+	var HSLColor = UIColorPicker.HSLColor;
+
+	/**
+	 * ColorPalette
+	 */
+	var ColorPalette = (function ColorPalette() {
+
+		var samples = [];
+		var color_palette;
+		var complementary;
+
+		var hideNode = function(node) {
+			node.setAttribute('data-hidden', 'true');
+		};
+
+		var ColorSample = function ColorSample(id) {
+			var node = document.createElement('div');
+			node.className = 'sample';
+
+			this.uid = samples.length;
+			this.node = node;
+			this.color = new Color();
+
+			node.setAttribute('sample-id', this.uid);
+			node.setAttribute('draggable', 'true');
+			node.addEventListener('dragstart', this.dragStart.bind(this));
+			node.addEventListener('click', this.pickColor.bind(this));
+
+			samples.push(this);
+		};
+
+		ColorSample.prototype.updateBgColor = function updateBgColor() {
+			this.node.style.backgroundColor = this.color.getColor();
+		};
+
+		ColorSample.prototype.updateColor = function updateColor(color) {
+			this.color.copy(color);
+			this.updateBgColor();
+		};
+
+		ColorSample.prototype.updateHue = function updateHue(color, degree, steps) {
+			this.color.copy(color);
+			var hue = (steps * degree + this.color.hue) % 360;
+			if (hue < 0) hue += 360;
+			this.color.setHue(hue);
+			this.updateBgColor();
+		};
+
+		ColorSample.prototype.updateSaturation = function updateSaturation(color, value, steps) {
+			var saturation = color.saturation + value * steps;
+			if (saturation <= 0) {
+				this.node.setAttribute('data-hidden', 'true');
+				return;
+			}
+
+			this.node.removeAttribute('data-hidden');
+			this.color.copy(color);
+			this.color.setSaturation(saturation);
+			this.updateBgColor();
+		};
+
+		ColorSample.prototype.updateLightness = function updateLightness(color, value, steps) {
+			var lightness = color.lightness + value * steps;
+			if (lightness <= 0) {
+				this.node.setAttribute('data-hidden', 'true');
+				return;
+			}
+			this.node.removeAttribute('data-hidden');
+			this.color.copy(color);
+			this.color.setLightness(lightness);
+			this.updateBgColor();
+		};
+
+		ColorSample.prototype.updateBrightness = function updateBrightness(color, value, steps) {
+			var brightness = color.value + value * steps;
+			if (brightness <= 0) {
+				this.node.setAttribute('data-hidden', 'true');
+				return;
+			}
+			this.node.removeAttribute('data-hidden');
+			this.color.copy(color);
+			this.color.setValue(brightness);
+			this.updateBgColor();
+		};
+
+		ColorSample.prototype.updateAlpha = function updateAlpha(color, value, steps) {
+			var alpha = parseFloat(color.a) + value * steps;
+			if (alpha <= 0) {
+				this.node.setAttribute('data-hidden', 'true');
+				return;
+			}
+			this.node.removeAttribute('data-hidden');
+			this.color.copy(color);
+			this.color.a = parseFloat(alpha.toFixed(2));
+			this.updateBgColor();
+		};
+
+		ColorSample.prototype.pickColor = function pickColor() {
+			UIColorPicker.setColor('picker', this.color);
+		};
+
+		ColorSample.prototype.dragStart = function dragStart(e) {
+			e.dataTransfer.setData('sampleID', this.uid);
+			e.dataTransfer.setData('location', 'palette-samples');
+		};
+
+		var Palette = function Palette(text, size) {
+			this.samples = [];
+			this.locked = false;
+
+			var palette = document.createElement('div');
+			var title = document.createElement('div');
+			var controls = document.createElement('div');
+			var container = document.createElement('div');
+			var lock = document.createElement('div');
+
+			container.className = 'container';
+			title.className = 'title';
+			palette.className = 'palette';
+			controls.className = 'controls';
+			lock.className = 'lock';
+			title.textContent = text;
+
+			controls.appendChild(lock);
+			container.appendChild(title);
+			container.appendChild(controls);
+			container.appendChild(palette);
+
+			lock.addEventListener('click', function () {
+				this.locked = !this.locked;
+				lock.setAttribute('locked-state', this.locked);
+			}.bind(this));
+
+			for(var i = 0; i < size; i++) {
+				var sample = new ColorSample();
+				this.samples.push(sample);
+				palette.appendChild(sample.node);
+			}
+
+			this.container = container;
+			this.title = title;
+		};
+
+		var createHuePalette = function createHuePalette() {
+			var palette = new Palette('Hue', 12);
+
+			UIColorPicker.subscribe('picker', function(color) {
+				if (palette.locked === true)
+					return;
+
+				for(var i = 0; i < 12; i++) {
+					palette.samples[i].updateHue(color, 30, i);
+				}
+			});
+
+			color_palette.appendChild(palette.container);
+		};
+
+		var createSaturationPalette = function createSaturationPalette() {
+			var palette = new Palette('Saturation', 11);
+
+			UIColorPicker.subscribe('picker', function(color) {
+				if (palette.locked === true)
+					return;
+
+				for(var i = 0; i < 11; i++) {
+					palette.samples[i].updateSaturation(color, -10, i);
+				}
+			});
+
+			color_palette.appendChild(palette.container);
+		};
+
+		/* Brightness or Lightness - depends on the picker mode */
+		var createVLPalette = function createSaturationPalette() {
+			var palette = new Palette('Lightness', 11);
+
+			UIColorPicker.subscribe('picker', function(color) {
+				if (palette.locked === true)
+					return;
+
+				if(color.format === 'HSL') {
+					palette.title.textContent = 'Lightness';
+					for(var i = 0; i < 11; i++)
+						palette.samples[i].updateLightness(color, -10, i);
+				}
+				else {
+					palette.title.textContent = 'Value';
+					for(var i = 0; i < 11; i++)
+						palette.samples[i].updateBrightness(color, -10, i);
+				}
+			});
+
+			color_palette.appendChild(palette.container);
+		};
+
+		var isBlankPalette = function isBlankPalette(container, value) {
+			if (value === 0) {
+				container.setAttribute('data-collapsed', 'true');
+				return true;
+			}
+
+			container.removeAttribute('data-collapsed');
+			return false;
+		};
+
+		var createAlphaPalette = function createAlphaPalette() {
+			var palette = new Palette('Alpha', 10);
+
+			UIColorPicker.subscribe('picker', function(color) {
+				if (palette.locked === true)
+					return;
+
+				for(var i = 0; i < 10; i++) {
+					palette.samples[i].updateAlpha(color, -0.1, i);
+				}
+			});
+
+			color_palette.appendChild(palette.container);
+		};
+
+		var getSampleColor = function getSampleColor(id) {
+			if (samples[id] !== undefined && samples[id]!== null)
+				return new Color(samples[id].color);
+		};
+
+		var init = function init() {
+			color_palette = getElemById('color-palette');
+
+			createHuePalette();
+			createSaturationPalette();
+			createVLPalette();
+			createAlphaPalette();
+
+		};
+
+		return {
+			init : init,
+			getSampleColor : getSampleColor
+		};
+
+	})();
+
+	/**
+	 * ColorInfo
+	 */
+	var ColorInfo = (function ColorInfo() {
+
+		var info_box;
+		var select;
+		var RGBA;
+		var HEXA;
+		var HSLA;
+
+		var updateInfo = function updateInfo(color) {
+			if (color.a | 0 === 1) {
+				RGBA.info.textContent = 'RGB';
+				HSLA.info.textContent = 'HSL';
+			}
+			else {
+				RGBA.info.textContent = 'RGBA';
+				HSLA.info.textContent = 'HSLA';
+			}
+
+			RGBA.value.value = color.getRGBA();
+			HSLA.value.value = color.getHSLA();
+			HEXA.value.value = color.getHexa();
+		};
+
+		var InfoProperty = function InfoProperty(info) {
+
+			var node = document.createElement('div');
+			var title = document.createElement('div');
+			var value = document.createElement('input');
+			var copy = document.createElement('div');
+
+			node.className = 'property';
+			title.className = 'type';
+			value.className = 'value';
+			copy.className = 'copy';
+
+			title.textContent = info;
+			value.setAttribute('type', 'text');
+
+			copy.addEventListener('click', function() {
+				value.select();
+			});
+
+			node.appendChild(title);
+			node.appendChild(value);
+			node.appendChild(copy);
+
+			this.node = node;
+			this.value = value;
+			this.info = title;
+
+			info_box.appendChild(node);
+		};
+
+		var init = function init() {
+
+			info_box = getElemById('color-info');
+
+			RGBA = new InfoProperty('RGBA');
+			HSLA = new InfoProperty('HSLA');
+			HEXA = new InfoProperty('HEXA');
+
+			UIColorPicker.subscribe('picker', updateInfo);
+
+		};
+
+		return {
+			init: init
+		};
+
+	})();
+
+	/**
+	 * ColorPicker Samples
+	 */
+	var ColorPickerSamples = (function ColorPickerSamples() {
+
+		var samples = [];
+		var nr_samples = 0;
+		var active = null;
+		var container = null;
+		var	samples_per_line = 10;
+		var trash_can = null;
+		var base_color = new HSLColor(0, 50, 100);
+		var add_btn;
+		var add_btn_pos;
+
+		var ColorSample = function ColorSample() {
+			var node = document.createElement('div');
+			node.className = 'sample';
+
+			this.uid = samples.length;
+			this.index = nr_samples++;
+			this.node = node;
+			this.color = new Color(base_color);
+
+			node.setAttribute('sample-id', this.uid);
+			node.setAttribute('draggable', 'true');
+
+			node.addEventListener('dragstart', this.dragStart.bind(this));
+			node.addEventListener('dragover' , allowDropEvent);
+			node.addEventListener('drop'     , this.dragDrop.bind(this));
+
+			this.updatePosition(this.index);
+			this.updateBgColor();
+			samples.push(this);
+		};
+
+		ColorSample.prototype.updateBgColor = function updateBgColor() {
+			this.node.style.backgroundColor = this.color.getColor();
+		};
+
+		ColorSample.prototype.updatePosition = function updatePosition(index) {
+			this.index = index;
+			this.posY = 5 + ((index / samples_per_line) | 0) * 52;
+			this.posX = 5 + ((index % samples_per_line) | 0) * 52;
+			this.node.style.top  = this.posY + 'px';
+			this.node.style.left = this.posX + 'px';
+		};
+
+		ColorSample.prototype.updateColor = function updateColor(color) {
+			this.color.copy(color);
+			this.updateBgColor();
+		};
+
+		ColorSample.prototype.activate = function activate() {
+			UIColorPicker.setColor('picker', this.color);
+			this.node.setAttribute('data-active', 'true');
+		};
+
+		ColorSample.prototype.deactivate = function deactivate() {
+			this.node.removeAttribute('data-active');
+		};
+
+		ColorSample.prototype.dragStart = function dragStart(e) {
+			e.dataTransfer.setData('sampleID', this.uid);
+			e.dataTransfer.setData('location', 'picker-samples');
+		};
+
+		ColorSample.prototype.dragDrop = function dragDrop(e) {
+			e.stopPropagation();
+			this.color = Tool.getSampleColorFrom(e);
+			this.updateBgColor();
+		};
+
+		ColorSample.prototype.deleteSample = function deleteSample() {
+			container.removeChild(this.node);
+			samples[this.uid] = null;
+			nr_samples--;
+		};
+
+		var updateUI = function updateUI() {
+			updateContainerProp();
+
+			var index = 0;
+			var nr = samples.length;
+			for (var i=0; i < nr; i++)
+				if (samples[i] !== null) {
+					samples[i].updatePosition(index);
+					index++;
+				}
+
+			AddSampleButton.updatePosition(index);
+		};
+
+		var deleteSample = function deleteSample(e) {
+			trash_can.parentElement.setAttribute('drag-state', 'none');
+
+			var location = e.dataTransfer.getData('location');
+			if (location !== 'picker-samples')
+				return;
+
+			var sampleID = e.dataTransfer.getData('sampleID');
+			samples[sampleID].deleteSample();
+			console.log(samples);
+
+			updateUI();
+		};
+
+		var createDropSample = function createDropSample() {
+			var sample = document.createElement('div');
+			sample.id = 'drop-effect-sample';
+			sample.className = 'sample';
+			container.appendChild(sample);
+		};
+
+		var setActivateSample = function setActivateSample(e) {
+			if (e.target.className !== 'sample')
+				return;
+
+			unsetActiveSample(active);
+			Tool.unsetVoidSample();
+			CanvasSamples.unsetActiveSample();
+			active = samples[e.target.getAttribute('sample-id')];
+			active.activate();
+		};
+
+		var unsetActiveSample = function unsetActiveSample() {
+			if (active)
+				active.deactivate();
+			active = null;
+		};
+
+		var getSampleColor = function getSampleColor(id) {
+			if (samples[id] !== undefined && samples[id]!== null)
+				return new Color(samples[id].color);
+		};
+
+		var updateContainerProp = function updateContainerProp() {
+			samples_per_line = ((container.clientWidth - 5) / 52) | 0;
+			var height = 52 * (1 + (nr_samples / samples_per_line) | 0);
+			container.style.height = height + 10 + 'px';
+		};
+
+		var AddSampleButton = (function AddSampleButton() {
+			var node;
+			var _index = 0;
+			var _posX;
+			var _posY;
+
+			var updatePosition = function updatePosition(index) {
+				_index = index;
+				_posY = 5 + ((index / samples_per_line) | 0) * 52;
+				_posX = 5 + ((index % samples_per_line) | 0) * 52;
+
+				node.style.top  = _posY + 'px';
+				node.style.left = _posX + 'px';
+			};
+
+			var addButtonClick = function addButtonClick() {
+				var sample = new ColorSample();
+				container.appendChild(sample.node);
+				updatePosition(_index + 1);
+				updateUI();
+			};
+
+			var init = function init() {
+				node = document.createElement('div');
+				var icon = document.createElement('div');
+
+				node.className = 'sample';
+				icon.id = 'add-icon';
+				node.appendChild(icon);
+				node.addEventListener('click', addButtonClick);
+
+				updatePosition(0);
+				container.appendChild(node);
+			};
+
+			return {
+				init : init,
+				updatePosition : updatePosition
+			};
+		})();
+
+		var init = function init() {
+			container = getElemById('picker-samples');
+			trash_can = getElemById('trash-can');
+
+			AddSampleButton.init();
+
+			for (var i=0; i<16; i++) {
+				var sample = new ColorSample();
+				container.appendChild(sample.node);
+			}
+
+			AddSampleButton.updatePosition(samples.length);
+			updateUI();
+
+			active = samples[0];
+			active.activate();
+
+			container.addEventListener('click', setActivateSample);
+
+			trash_can.addEventListener('dragover', allowDropEvent);
+			trash_can.addEventListener('dragenter', function() {
+				this.parentElement.setAttribute('drag-state', 'enter');
+			});
+			trash_can.addEventListener('dragleave', function(e) {
+				this.parentElement.setAttribute('drag-state', 'none');
+			});
+			trash_can.addEventListener('drop', deleteSample);
+
+			UIColorPicker.subscribe('picker', function(color) {
+				if (active)
+					active.updateColor(color);
+			});
+
+		};
+
+		return {
+			init : init,
+			getSampleColor : getSampleColor,
+			unsetActiveSample : unsetActiveSample
+		};
+
+	})();
+
+	/**
+	 * Canvas Samples
+	 */
+	var CanvasSamples = (function CanvasSamples() {
+
+		var active = null;
+		var canvas = null;
+		var samples = [];
+		var zindex = null;
+		var tutorial = true;
+
+		var CanvasSample = function CanvasSample(color, posX, posY) {
+
+			var node = document.createElement('div');
+			var pick = document.createElement('div');
+			var delete_btn = document.createElement('div');
+			node.className = 'sample';
+			pick.className = 'pick';
+			delete_btn.className = 'delete';
+
+			this.uid = samples.length;
+			this.node = node;
+			this.color = color;
+			this.updateBgColor();
+			this.zIndex = 1;
+
+			node.style.top = posY - 50 + 'px';
+			node.style.left = posX - 50 + 'px';
+			node.setAttribute('sample-id', this.uid);
+
+			node.appendChild(pick);
+			node.appendChild(delete_btn);
+
+			var activate = function activate() {
+				setActiveSample(this);
+			}.bind(this);
+
+			node.addEventListener('dblclick', activate);
+			pick.addEventListener('click', activate);
+			delete_btn.addEventListener('click', this.deleteSample.bind(this));
+
+			UIComponent.makeDraggable(node);
+			UIComponent.makeResizable(node);
+
+			samples.push(this);
+			canvas.appendChild(node);
+			return this;
+		};
+
+		CanvasSample.prototype.updateBgColor = function updateBgColor() {
+			this.node.style.backgroundColor = this.color.getColor();
+		};
+
+		CanvasSample.prototype.updateColor = function updateColor(color) {
+			this.color.copy(color);
+			this.updateBgColor();
+		};
+
+		CanvasSample.prototype.updateZIndex = function updateZIndex(value) {
+			this.zIndex = value;
+			this.node.style.zIndex = value;
+		};
+
+		CanvasSample.prototype.activate = function activate() {
+			this.node.setAttribute('data-active', 'true');
+			zindex.setAttribute('data-active', 'true');
+
+			UIColorPicker.setColor('picker', this.color);
+			InputSliderManager.setValue('z-index', this.zIndex);
+		};
+
+		CanvasSample.prototype.deactivate = function deactivate() {
+			this.node.removeAttribute('data-active');
+			zindex.removeAttribute('data-active');
+		};
+
+		CanvasSample.prototype.deleteSample = function deleteSample() {
+			if (active === this)
+				unsetActiveSample();
+			canvas.removeChild(this.node);
+			samples[this.uid] = null;
+		};
+
+		CanvasSample.prototype.updatePosition = function updatePosition(posX, posY) {
+			this.node.style.top = posY - this.startY + 'px';
+			this.node.style.left = posX - this.startX + 'px';
+		};
+
+		var canvasDropEvent = function canvasDropEvent(e) {
+			var color = Tool.getSampleColorFrom(e);
+
+			if (color) {
+				var offsetX = e.pageX - canvas.offsetLeft;
+				var offsetY = e.pageY - canvas.offsetTop;
+				var sample = new CanvasSample(color, offsetX, offsetY);
+				if (tutorial) {
+					tutorial = false;
+					canvas.removeAttribute('data-tutorial');
+					var info = new CanvasSample(new Color(), 100, 100);
+					info.node.setAttribute('data-tutorial', 'dblclick');
+				}
+			}
+
+		};
+
+		var setActiveSample = function setActiveSample(sample) {
+			ColorPickerSamples.unsetActiveSample();
+			Tool.unsetVoidSample();
+			unsetActiveSample();
+			active = sample;
+			active.activate();
+		};
+
+		var unsetActiveSample = function unsetActiveSample() {
+			if (active)
+				active.deactivate();
+			active = null;
+		};
+
+		var createToggleBgButton = function createToggleBgButton() {
+			var button = document.createElement('div');
+			var state = false;
+			button.className = 'toggle-bg';
+			canvas.appendChild(button);
+
+			button.addEventListener('click', function() {
+				console.log(state);
+				state = !state;
+				canvas.setAttribute('data-bg', state);
+			});
+		};
+
+		var init = function init() {
+			canvas = getElemById('canvas');
+			zindex = getElemById('zindex');
+
+			canvas.addEventListener('dragover', allowDropEvent);
+			canvas.addEventListener('drop', canvasDropEvent);
+
+			createToggleBgButton();
+
+			UIColorPicker.subscribe('picker', function(color) {
+				if (active)	active.updateColor(color);
+			});
+
+			InputSliderManager.subscribe('z-index', function (value) {
+				if (active)	active.updateZIndex(value);
+			});
+
+			UIComponent.makeResizable(canvas, 'height');
+		};
+
+		return {
+			init : init,
+			unsetActiveSample : unsetActiveSample
+		};
+
+	})();
+
+	var StateButton = function StateButton(node, state) {
+		this.state = false;
+		this.callback = null;
+
+		node.addEventListener('click', function() {
+			this.state = !this.state;
+			if (typeof this.callback === "function")
+				this.callback(this.state);
+		}.bind(this));
+	};
+
+	StateButton.prototype.set = function set() {
+		this.state = true;
+		if (typeof this.callback === "function")
+			this.callback(this.state);
+	};
+
+	StateButton.prototype.unset = function unset() {
+		this.state = false;
+		if (typeof this.callback === "function")
+			this.callback(this.state);
+	};
+
+	StateButton.prototype.subscribe = function subscribe(func) {
+		this.callback = func;
+	};
+
+
+	/**
+	 * Tool
+	 */
+	var Tool = (function Tool() {
+
+		var samples = [];
+		var controls = null;
+		var void_sw;
+
+		var createPickerModeSwitch = function createPickerModeSwitch() {
+			var parent = getElemById('controls');
+			var icon = document.createElement('div');
+			var button = document.createElement('div');
+			var hsv = document.createElement('div');
+			var hsl = document.createElement('div');
+			var active = null;
+
+			icon.className = 'icon picker-icon';
+			button.className = 'switch';
+			button.appendChild(hsv);
+			button.appendChild(hsl);
+
+			hsv.textContent = 'HSV';
+			hsl.textContent = 'HSL';
+
+			active = hsl;
+			active.setAttribute('data-active', 'true');
+
+			function switchPickingModeTo(elem) {
+				active.removeAttribute('data-active');
+				active = elem;
+				active.setAttribute('data-active', 'true');
+				UIColorPicker.setPickerMode('picker', active.textContent);
+			};
+
+			var picker_sw = new StateButton(icon);
+			picker_sw.subscribe(function() {
+				if (active === hsv)
+					switchPickingModeTo(hsl);
+				else
+					switchPickingModeTo(hsv);
+			});
+
+			hsv.addEventListener('click', function() {
+				switchPickingModeTo(hsv);
+			});
+			hsl.addEventListener('click', function() {
+				switchPickingModeTo(hsl);
+			});
+
+			parent.appendChild(icon);
+			parent.appendChild(button);
+		};
+
+		var setPickerDragAndDrop = function setPickerDragAndDrop() {
+			var preview = document.querySelector('#picker .preview-color');
+			var picking_area = document.querySelector('#picker .picking-area');
+
+			preview.setAttribute('draggable', 'true');
+			preview.addEventListener('drop', drop);
+			preview.addEventListener('dragstart', dragStart);
+			preview.addEventListener('dragover', allowDropEvent);
+
+			picking_area.addEventListener('drop', drop);
+			picking_area.addEventListener('dragover', allowDropEvent);
+
+			function drop(e) {
+				var color = getSampleColorFrom(e);
+				UIColorPicker.setColor('picker', color);
+			};
+
+			function dragStart(e) {
+				e.dataTransfer.setData('sampleID', 'picker');
+				e.dataTransfer.setData('location', 'picker');
+			};
+		};
+
+		var getSampleColorFrom = function getSampleColorFrom(e) {
+			var sampleID = e.dataTransfer.getData('sampleID');
+			var location = e.dataTransfer.getData('location');
+
+			if (location === 'picker')
+				return UIColorPicker.getColor(sampleID);
+			if (location === 'picker-samples')
+				return ColorPickerSamples.getSampleColor(sampleID);
+			if (location === 'palette-samples')
+				return ColorPalette.getSampleColor(sampleID);
+		};
+
+		var setVoidSwitch = function setVoidSwitch() {
+			var void_sample = getElemById('void-sample');
+			void_sw = new StateButton(void_sample);
+			void_sw.subscribe( function (state) {
+				void_sample.setAttribute('data-active', state);
+				if (state === true) {
+					ColorPickerSamples.unsetActiveSample();
+					CanvasSamples.unsetActiveSample();
+				}
+			});
+		};
+
+		var unsetVoidSample = function unsetVoidSample() {
+			void_sw.unset();
+		};
+
+		var init = function init() {
+			controls = getElemById('controls');
+
+			var color = new Color();
+			color.setHSL(0, 51, 51);
+			UIColorPicker.setColor('picker', color);
+
+			setPickerDragAndDrop();
+			createPickerModeSwitch();
+			setVoidSwitch();
+		};
+
+		return {
+			init : init,
+			unsetVoidSample : unsetVoidSample,
+			getSampleColorFrom : getSampleColorFrom
+		};
+
+	})();
+
+	var init = function init() {
+		UIColorPicker.init();
+		InputSliderManager.init();
+		ColorInfo.init();
+		ColorPalette.init();
+		ColorPickerSamples.init();
+		CanvasSamples.init();
+		Tool.init();
+	};
+
+	return {
+		init : init
+	};
+
+})();
+
+
+
+ + +

{{CSSRef}}

+ +

這是個可以讓人新增、調整和測試網頁顏色的工具。藉由這個工具讓人可以輕鬆將顏色轉換成各種 CSS 支援的格式,包含:HEXA、RGB(Red/Green/Blue)和 HSL (Hue/Staturation/Lightness)。在 RGB(rgba)和 HSL(hsla)格式也支援控制阿爾法通道(alpha channel)

+ +

隨著調整每個顏色都會顯示成三種 CSS 的標準格式;此外,基於目前選擇的顏色,一個調色板 HSL 和 HSV、還有 alpha, 被創建。滴管風格的色彩選擇器對話框可以在 HSL 或 HSV 格式中切換。

+ +

{{ EmbedLiveSample('ColorPicker_Tool', '100%', '900') }}

+ +

 

diff --git a/files/zh-tw/web/css/css_colors/index.html b/files/zh-tw/web/css/css_colors/index.html new file mode 100644 index 0000000000..607d1790af --- /dev/null +++ b/files/zh-tw/web/css/css_colors/index.html @@ -0,0 +1,119 @@ +--- +title: CSS Colors +slug: Web/CSS/CSS_Colors +tags: + - CSS + - CSS Colors + - NeedsTranslation + - Overview + - Reference + - TopicStub +translation_of: Web/CSS/CSS_Color +--- +

{{CSSRef}}

+ +

CSS Colors is a module of CSS that deals with colors, color types and transparency.

+ +

Reference

+ +

Properties

+ +
+ +
+ +

CSS Data Types

+ +

{{cssxref("<color>")}}

+ +

Guides

+ +

None.

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Colors')}}{{Spec2('CSS3 Colors')}} 
{{SpecName('CSS2.1', 'colors.html')}}{{Spec2('CSS2.1')}} 
{{SpecName('CSS1')}}{{Spec2('CSS1')}} 
+ +

Browser compatibility

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0{{CompatGeckoDesktop("1")}}3.03.51.0
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support1.0{{CompatGeckoMobile("1")}}6.06.01.0
+
+ +

See also

+ + diff --git a/files/zh-tw/web/css/css_flexible_box_layout/index.html b/files/zh-tw/web/css/css_flexible_box_layout/index.html new file mode 100644 index 0000000000..f26fcfb2e8 --- /dev/null +++ b/files/zh-tw/web/css/css_flexible_box_layout/index.html @@ -0,0 +1,118 @@ +--- +title: CSS 彈性盒子排版 +slug: Web/CSS/CSS_Flexible_Box_Layout +tags: + - CSS + - CSS Flexible Boxes + - CSS Reference + - NeedsTranslation + - Overview + - TopicStub +translation_of: Web/CSS/CSS_Flexible_Box_Layout +--- +
{{CSSRef}}
+ +

CSS 彈性盒子排版(CSS Flexible Box Layout)是 CSS 的模組。它為了最佳化 CSS 盒子模型的使用者介面設計而來、並把項目都配置在一個維度之內。在彈性盒子排版中,彈性容器的子項目們可以伸展到任何方向、並讓他們的尺寸更加「彈性」、或者持續增大,以填補未使用的空間,抑或縮小,以避免父元素溢出。子項目橫向或縱向對齊都很容易操作。

+ +

基本範例

+ +

下例的容器已經設為 display: flex、意味著三個子元素變成了彈性項目(flex item)。justify-content 值也設成了 space-between 以便將項目均勻地分佈在主軸上。每個物品之間放置相等數量的空間,左右項目與彈性容器(flex container)的邊緣齊平。你可能也發現到各項目在切軸(cross axis)上伸展。那是因為 align-items 的值是 stretch。項目伸展為彈性容器的高度、令它們看起来都如同最高的項目一般高。

+ +

{{EmbedGHLiveSample("css-examples/flexbox/basics/simple-example.html", '100%', 500)}}

+ +

參考

+ +

CSS 屬性

+ +
+ +
+ +

對齊屬性

+ +

The properties align-content, align-self, align-items and justify-content initially appeared in the Flexbox specification, but are now defined in Box Alignment and the Flexbox spec refers to the Box Alignment Specification for up to date definitions. Additional alignment properties are also defined in Box Alignment.

+ +
+ +
+ +

短詞

+ +
+ +
+ +

教學

+ +
+
彈性盒子的基本概念
+
彈性盒子的概述
+
彈性盒子與其他排版的關係
+
彈性盒子如何與其他排版和 CSS 規範相關連
+
在彈性容器內對齊
+
彈性盒子的 Box Alignment 屬性如何做動。
+
給彈性項目排序
+
解釋改變彈性項目順序和方向的不同方法,並講到潛在的問題。
+
控制彈性項目與主軸的比例
+
將解釋 flex-grow、flex-shrink、flex-basis 屬性。
+
掌握彈性項目 wrapping
+
如何使用多行建立彈性容器,並控制這些行中項目的顯示。
+
彈性盒子的典型用例
+
彈性盒子常見的設計範式。
+
彈性盒子的向下相容
+
彈性盒子的瀏覽器相容性、互操作性問題、支持舊版瀏覽器和規範的版本
+
+ +

規範

+ + + + + + + + + + + + + + + + +
規範狀態註解
{{ SpecName('CSS3 Flexbox') }}{{ Spec2('CSS3 Flexbox') }}初期定義。
+ +

參見

+ +
+
Flexbugs
+
a community-curated list of flexbox browser bugs and workarounds
+
Cross-browser Flexbox mixins
+
This article provides a set of mixins for those who want to create cross-browser flexbox experiences that even work in older browser that don't support the modern flexbox syntax
+
diff --git a/files/zh-tw/web/css/css_flexible_box_layout/using_css_flexible_boxes/index.html b/files/zh-tw/web/css/css_flexible_box_layout/using_css_flexible_boxes/index.html new file mode 100644 index 0000000000..19ca6226ec --- /dev/null +++ b/files/zh-tw/web/css/css_flexible_box_layout/using_css_flexible_boxes/index.html @@ -0,0 +1,382 @@ +--- +title: CSS彈性盒子用法 +slug: Web/CSS/CSS_Flexible_Box_Layout/Using_CSS_flexible_boxes +tags: + - '#RWD' + - CSS + - Web + - 例子 + - 先进的 + - 入门 + - 灵活 + - 盒 +translation_of: Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox +--- +
{{CSSRef}}
+ +

CSS3 彈性盒子,又稱flexbox,是為了適應不同螢幕尺寸和顯示設備而生的佈局模式針對許多應用而言,不用 floats 的彈性盒子模型會比塊狀模型(block model)易用,彈性容器的邊緣也不會與內容的邊緣重疊。

+ +

多數設計師會發現 flexbox 用起來比 box 簡單得多。像是不多注意 div 的話,它就會經常違反設計師意願地,跑到頁頂去──令 footer 附著在頁底,也因此變得很棘手。flexbox 的寬高能改變以適應顯示空間,將較低的元件固定住。Flexbox 邏輯也能讓你確實令 div 壓在頁面的右方或底部。Flexbox 元素的顯示順序,與原始碼的顯示順序相互獨立。

+ +

一些時髦的佈局,也能因而透過更簡潔的程式碼完成。這種有意的獨立性只影響視覺渲染,基於 HTML 原始碼的語意順序及瀏覽不會受到影響。

+ +
注:儘管 CSS 彈性盒子佈局規範還處於最終徵求意見稿(Last Call Working Draft)階段(參見最新編輯草案)、也不是所有瀏覽器都實做彈性盒子的所有功能。但這麼說好了,現在主流的瀏覽器,都對 flexbox 有著良好的支持。請參見相容性表格的具體屬性,以獲取最新的相容狀態。
+ +

彈性盒子的概念

+ +

Flex 排版的大致定義,是能更改該項目的長與(或)高,以便貼合任何顯示設備的空間。Flex container 能針對該元件擴張以便填補可用的空間、或收縮以便阻止空間溢出。

+ +

塊狀佈局(Block layout)以垂直方向為準、行內佈局(Inline layout)以水平方向為準、而彈性佈局(Flexbox layout)則同時允許這兩種。塊狀佈局雖適於頁面顯示,但在程式元件(application component)需要在用戶代理(user agent)變更、手機從垂直方向翻轉到水平方向……等變更定位、大小、拉伸、收縮的情形下,這種佈局就很難用了。彈性盒子佈局長於小規模佈局、而剛剛流行的格線佈局(Grid layout)則長於大規模佈局。二者皆為 CSS 工作小組為在不同用戶代理、書寫模式、和其他要求下的 Web 應用程式,提供良好互通性的一部分。

+ +

彈性盒子的字彙

+ +

在彈性盒子的世界,我們不會稱水平(inline)或垂直(block),而是主軸(main axis)與切軸(cross axis)。如果 flex-directioncolumn,主軸就會充當垂直、而切軸則充當水平。請參考下面的圖,它展示了一個 flex-directionrow 的彈性容器,意味著該彈性項目會基於主軸,作水平排列。

+ +

flex_terms.png

+ +
+
彈性容器(Flex container)
+
包住彈性項目(Flex item)的父元素。在 {{Cssxref("display")}} 屬性用上 flexinline-flex 值的,就是彈性容器。
+
彈性項目(Flex item)
+
+

所有彈性容器的子元素都會變成彈性項目。直接包含在彈性容器的文字,會被包裝成匿名的 Flex 項目。

+
+
軸(Axes)
+
+

所有彈性盒子布局都有兩個軸。主軸(main axis)是跟隨著彈性項目順序的軸、而切軸(cross axis)是垂直於主軸的軸。

+ +
    +
  • flex-direction 屬性啟用主軸。
  • +
  • justify-content 屬性定義目前彈性項目的主軸如何擺放。
  • +
  • align-items 屬性定義目前彈性項目的切軸如何擺放。
  • +
  • align-self 屬性定義目前單一彈性項目如何對齊。這個設定會覆蓋 align-items 的預設值。
  • +
+
+
方向(Directions)
+
+

彈性容器的 main start/main endcross start/cross end sides 描述了彈性項目流的起點與終點。它們跟隨著由 writing-mode 所建立的向量中,彈性容器的主軸與切軸排列(左至右或右至左……等等)。

+ +
    +
  • order assigns elements to ordinal groups and determines which elements appear first.
  • +
  • flex-flow 屬性是 flex-directionflex-wrap 屬性的簡寫,描述了彈性項目的整體布局。
  • +
+
+
Lines
+
+

Flex items can be laid out on either a single line or on several lines according to the flex-wrap property, which controls the direction of the cross axis and the direction in which new lines are stacked.

+
+
Dimensions
+
+

The flex items' agnostic equivalents of height and width are main size and cross size, which respectively follow the main axis and cross axis of the flex container.

+ + +
+
+ +

設計一個彈性盒子

+ +

要設計基於這種風格的 CSS 元素,請把 display 屬性設為:

+ +
display: flex;
+ +

或:

+ +
display: inline-flex;
+ +

這樣一來,元素就會變成彈性容器,而它的子元素們就會變成彈性項目。flex 值會讓彈性容器變成塊級元素(block-level element)、inline-flex 則會讓彈性容器成為單一的行內元素(atomic inline-level element)。

+ +
注意:如果需要支援較舊的瀏覽器,請把廠商前輟標記(vendor prefix tag)寫在 display 屬性(property),而不是屬性值(attribute)。例如:display: -webkit-flex
+ +

彈性項目需要留心……

+ +

Text that is directly contained inside a flex container is automatically wrapped in an anonymous flex item. However, an anonymous flex item that contains only white space is not rendered, as if it were designated display: none.

+ +

Absolutely positioned children of a flex container are positioned so that their static position is determined in reference to the main start content-box corner of their flex container.

+ +

The margins of adjacent flex items do not collapse. Using auto margins absorbs extra space in the vertical or horizontal direction and can be used for alignment or to separate adjacent flex items. See Aligning with 'auto' margins in the W3C CSS Flexible Box Layout Module specification for more details.

+ +

Flexbox's alignment properties do "true" centering, unlike other centering methods in CSS. This means that the flex items will stay centered, even if they overflow the flex container. This can sometimes be problematic, however, if they overflow past the top edge of the page, or the left edge (in LTR languages like English; the problem occurs on the right edge in RTL languages like Arabic), as you can't scroll to that area, even if there is content there! In a future release, the alignment properties will be extended to have a "safe" option as well. For now, if this is a concern, you can instead use margins to achieve centering, as they'll respond in a "safe" way and stop centering if they overflow. Instead of using the align- properties, just put auto margins on the flex items you wish to center. Instead of the justify- properties, put auto margins on the outside edges of the first and last flex items in the flex container. The auto margins will "flex" and assume the leftover space, centering the flex items when there is leftover space, and switching to normal alignment when not. However, if you're trying to replace justify-content with margin-based centering in a multi-line flexbox, you're probably out of luck, as you need to put the margins on the first and last flex item on each line. Unless you can predict ahead of time which items will end up on which line, you can't reliably use margin-based centering in the main axis to replace the justify-content property.

+ +

Recall that while the display order of the elements is independent of their order in the source code, this independence affects only the visual rendering, leaving speech order and navigation based on the source order. Even the {{cssxref("order")}} property does not affect speech or navigation sequence. Thus developers must take care to order elements properly in the source so as not to damage the document's accessibility.

+ +

彈性盒子的屬性

+ +

不對彈性盒子生效的屬性

+ +

由於彈性盒子使用不同的排版演算法,所以有些屬性不太適合用在彈性容器內:

+ + + +

示例

+ +

基本彈性排版示例

+ +

這個基本彈性將展示如何把「彈性化」引至某個元素、並在彈性狀態下相鄰該元素的表現。

+ +
​<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <style>
+    .flex {
+        /* basic styling */
+        width: 350px;
+        height: 200px;
+        border: 1px solid #555;
+        font: 14px Arial;
+
+        /* flexbox setup */
+        display: flex;
+        flex-direction: row;
+    }
+
+    .flex > div {
+        flex: 1 1 auto;
+        width: 30px; /* To make the transition work nicely. (Transitions to/from
+                        "width:auto" are buggy in Gecko and Webkit, at least.
+                        See http://bugzil.la/731886 for more info.) */
+        transition: width 0.7s ease-out;
+    }
+
+    /* colors */
+    .flex > div:nth-child(1){ background: #009246; }
+    .flex > div:nth-child(2){ background: #F1F2F1; }
+    .flex > div:nth-child(3){ background: #CE2B37; }
+
+    .flex > div:hover {
+        width: 200px;
+    }
+
+    </style>
+  </head>
+  <body>
+    <p>Flexbox nuovo</p>
+    <div class="flex">
+      <div>uno</div>
+      <div>due</div>
+      <div>tre</div>
+    </div>
+  </body>
+</html>
+ +

聖杯排版示例

+ +

本示例將示範彈性盒子在不同的解析度之下,如何提供動態變更的能力。下圖將說明轉換。

+ +

HolyGrailLayout.png

+ +

這裡展示了貼合了瀏覽器視窗的排版,必須為智慧型手機視窗最佳化的情況。不僅尺寸要縮減,呈現順序也要改變。彈性盒子把這件事變得相當簡單。

+ +
​<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <style>
+    body {
+        font: 24px Helvetica;
+        background: #999999;
+    }
+
+    #main {
+        min-height: 800px;
+        margin: 0;
+        padding: 0;
+        display: flex;
+        flex-flow: row;
+    }
+
+    #main > article {
+        margin: 4px;
+        padding: 5px;
+        border: 1px solid #cccc33;
+        border-radius: 7pt;
+        background: #dddd88;
+        flex: 3 1 60%;
+        order: 2;
+    }
+
+    #main > nav {
+        margin: 4px;
+        padding: 5px;
+        border: 1px solid #8888bb;
+        border-radius: 7pt;
+        background: #ccccff;
+        flex: 1 6 20%;
+        order: 1;
+    }
+
+    #main > aside {
+        margin: 4px;
+        padding: 5px;
+        border: 1px solid #8888bb;
+        border-radius: 7pt;
+        background: #ccccff;
+        flex: 1 6 20%;
+        order: 3;
+    }
+
+    header, footer {
+        display: block;
+        margin: 4px;
+        padding: 5px;
+        min-height: 100px;
+        border: 1px solid #eebb55;
+        border-radius: 7pt;
+        background: #ffeebb;
+    }
+
+    /* Too narrow to support three columns */
+    @media all and (max-width: 640px) {
+        #main, #page {
+            flex-direction: column;
+        }
+
+        #main > article, #main > nav, #main > aside {
+        /* Return them to document order */
+            order: 0;
+        }
+
+        #main > nav, #main > aside, header, footer {
+            min-height: 50px;
+            max-height: 50px;
+        }
+    }
+    </style>
+  </head>
+  <body>
+    <header>header</header>
+    <div id='main'>
+      <article>article</article>
+      <nav>nav</nav>
+      <aside>aside</aside>
+    </div>
+    <footer>footer</footer>
+  </body>
+</html>
+ +

遊樂場

+ +

以下提供一些與彈性盒子相關的網站讓你親手操作:

+ + + +

要注意的事情

+ +

有時候配置 Flex item 的演算法會有點難以理解。因此,在設計 Flexible box 時有一些指引,能讓你避免負面意義上的驚嘆。

+ +

Flexible box 通常會盡量貼合 writing mode 的配置,這意味著 main startmain end 會基於 startend 的位置來配置。

+ +

cross startcross end 依賴 startbefore 的定義的位置,其依賴 direction 的值

+ +

Page breaks are possible in flexible boxes layout as long as break- property allows it. CSS3 break-after, break-before, and break-inside as well as CSS 2.1 page-break-before, page-break-after, and page-break-inside properties are accepted on a flex container, flex items, and inside flex items.

+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox (Gecko)ChromeInternet ExplorerOperaSafari
Basic support (single-line flexbox){{CompatGeckoDesktop("18.0")}}[6]{{property_prefix("-moz")}}[2]
+ {{CompatGeckoDesktop("22.0")}}
21.0{{property_prefix("-webkit")}}
+ 29.0
11[3]12.10{{property_prefix("-webkit")}}[5]6.1{{property_prefix("-webkit")}}[1]
Multi-line flexbox{{CompatGeckoDesktop("28.0")}}21.0{{property_prefix("-webkit")}}
+ 29.0
11[3]12.10[5]
+ 15 {{property_prefix("-webkit")}}
6.1{{property_prefix("-webkit")}}[1]
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureFirefox Mobile (Gecko)Firefox OSAndroidIE PhoneOpera MobileSafari Mobile
Basic support (single-line flexbox){{CompatGeckoMobile("18.0")}}{{property_prefix("-moz")}}[2]
+ {{CompatGeckoMobile("22.0")}}
+

1.0{{property_prefix("-moz")}}[2]
+ 1.1

+
2.1{{property_prefix("-webkit")}}[4]
+ 4.4
1112.10[5]
+ 15{{property_prefix("-webkit")}}
7{{property_prefix("-webkit")}}[1]
Multi-line flexbox{{CompatGeckoMobile("28.0")}}1.32.1{{property_prefix("-webkit")}}[4]
+ 4.4
1112.10[5]
+ 15{{property_prefix("-webkit")}}
7{{property_prefix("-webkit")}}[1]
+
+ +

[1] Safari up to version 6.0 (iOS.1) supported an old incompatible draft version of the specification. Safari 6.1 (and Safari on iOS 7) has been updated to support the final version.

+ +

[2] Up to Firefox 22, to activate flexbox support, the user has to change the about:config preference layout.css.flexbox.enabled to true. From Firefox 22 to Firefox 27, the preference is true by default, but the preference has been removed in Firefox 28.

+ +

[3] Internet Explorer 10 supports an old incompatible draft version of the specification; Internet Explorer 11 has been updated to support the final version.

+ +

[4] Android browser up to 4.3 supported an old incompatible draft version of the specification. Android 4.4 has been updated to support the final version.

+ +

[5] While in the initial implementation in Opera 12.10 flexbox was not prefixed, it got prefixed in versions 15 to 16 of Opera and 15 to 19 of Opera Mobile with {{property_prefix("-webkit")}}. The prefix was removed again in Opera 17 and Opera Mobile 24.

+ +

[6] Up to Firefox 29, specifying visibility: collapse on a flex item causes it to be treated as if it were display: none instead of the intended behavior, treating it as if it were visibility: hidden. The suggested workaround is to use visibility:hidden for flex items that should behave as if they were designated visibility:collapse. For more information, see {{bug(783470)}}.

+ +

參見

+ + diff --git a/files/zh-tw/web/css/css_grid_layout/basic_concepts_of_grid_layout/index.html b/files/zh-tw/web/css/css_grid_layout/basic_concepts_of_grid_layout/index.html new file mode 100644 index 0000000000..2c6c9685cc --- /dev/null +++ b/files/zh-tw/web/css/css_grid_layout/basic_concepts_of_grid_layout/index.html @@ -0,0 +1,715 @@ +--- +title: 格線佈局的基本概念 +slug: Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout +translation_of: Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout +--- +

CSS 格線佈局介紹了二維的 CSS 格線系統。格線可以用來佈置頁面的主要區域、或小型用戶介面。本文介紹 CSS 格線 Level 1 規範的其中一部份。這份概觀顯示的某些功能,將在教學的其他部份詳細解釋。

+ +

什麽是格線?

+ +

格線是一組水平線和垂直線的交叉集合(intersecting set):一個定義為行(row),另一個定義為列(column)。你可以讓各元素依照行列的規則放到各格線上。CSS 格線佈局具有以下特點:

+ +

固定和靈活的軌道尺寸

+ +

你可以給各格線指定一個固定的軌道大小,例如像素(pixel)。這樣就能把格線設為指定的像素,以貼近你期望的排版。也可以創建一個使用百分比、或是新的 fr 單位之格線。fr 單位就是為了格線布局而生。

+ +

單元佈置

+ +

你可以在格線使用行號、名字、目標區域,讓各單元放到精確的位置。格線也有控制非明式(explicit)單元的布局演算法。

+ +

Creation of additional tracks to hold content

+ +

你可以按照需求,定義明式格線、也可以處理沒有指定的格線、還可以增加額外的行(row)與列(column)。如果需要「盡可能地放進容器容得了的列」之類的也辦得到。

+ +

控制對齊

+ +

格線也包含了依序對齊的功能,以便控制各格線內的各單元、還有整個格線要如何對齊。

+ +

Control of overlapping content

+ +

數個單位也能被放進 grid cell、或是區域的一部分相互重疊。我們可以透過 {{cssxref("z-index")}} 控制該分層。

+ +

格線是個強大的規範、它在與諸如彈性盒子之類的 CSS 結合時,也有助於用 CSS 建立前所尚未有的排版。一切都建立要從建立格線容器(grid container)開始。

+ +

格線容器

+ +

我們會宣告 display: griddisplay: inline-grid 來給一個元素建立格線容器(grid container)。宣告以後,該元素的所有直接子元素會變成格線單位(grid item)

+ +

本例中,我有個稱作 wrapper class 的 div,裡面有五個元素。

+ +
<div class="wrapper">
+   <div>One</div>
+   <div>Two</div>
+   <div>Three</div>
+   <div>Four</div>
+   <div>Five</div>
+</div>
+
+ +

接著我讓 .wrapper 變成格線容器(grid container)。

+ +
.wrapper {
+  display: grid;
+}
+
+ + + +

{{ EmbedLiveSample('The_Grid_container', '200', '330') }}

+ +

在它下面的直接子元素,現在都是格線單元了。從網路瀏覽器來看,各單元變成格線的前後,似乎沒什麼不同,因為目前格線只有建立一個格線列,來放所有的格線單元。這時候,你會發現格線檢測器相當好用。如果在 Firefox 檢查這個示例的格線,你會發現在 grid 值旁邊,有一個小圖標。點選這個小圖標,瀏覽器視窗的元素,就會被一個圖層覆蓋。

+ +

Using the Grid Highlighter in DevTools to view a grid

+ +

在理解並與 CSS 格線共事時,這個工具能幫你視覺化理解,格線到底怎麼做動的。

+ +

如果要開始把做得更像格線,我們還需要多寫個 column track。

+ +

格線軌道(Grid Track)

+ +

我們在格線裡透過 {{cssxref("grid-template-columns")}} 與 {{cssxref("grid-template-rows")}} 屬性定義了行與列。它們也定義了格線軌道。格線軌道是在格線的兩個欄位之間的空隙。下圖就會看到軌道的高亮:就在格線裡面的第一行。

+ +

+ +

I can add to our earlier example by adding the grid-template-columns property, then defining the size of the column tracks.

+ +

I have now created a grid with three 200-pixel-wide column tracks. The child items will be laid out on this grid one in each grid cell.

+ +
+
<div class="wrapper">
+   <div>One</div>
+   <div>Two</div>
+   <div>Three</div>
+   <div>Four</div>
+   <div>Five</div>
+</div>
+
+ +
.wrapper {
+  display: grid;
+  grid-template-columns: 200px 200px 200px;
+}
+
+ + + +

{{ EmbedLiveSample('grid_first', '610', '200') }}

+
+ +

fr 單位

+ +

格線軌道可以使用任何單位定義,不過格線引入了額外的單位,以助於建立有彈性的格線軌道。新的單位 fr 代表格線容器內,可用空間的分塊(fraction)。接下來的格線定義,會建立三個同等、且能依照可用空間縮放的長度軌道。

+ +
+
<div class="wrapper">
+   <div>One</div>
+   <div>Two</div>
+   <div>Three</div>
+   <div>Four</div>
+   <div>Five</div>
+</div>
+
+ +
.wrapper {
+  display: grid;
+  grid-template-columns: 1fr 1fr 1fr;
+}
+
+ + + +

{{ EmbedLiveSample('fr_unit_ls', '220', '180') }}

+
+ +

接著下例將創建有一個 2fr 的軌道,接著還有兩個 1fr 的軌道。可用空間會因此被分為四塊:其中兩塊給第一個軌道、剩下兩塊給兩個軌道各一個。

+ +
.wrapper {
+  display: grid;
+  grid-template-columns: 2fr 1fr 1fr;
+}
+
+ +

最後,我們會把分塊與絕對大小做結合。第一個軌道有 500 像素,這個固定的寬度,會因此從可用空間先割一塊出去。接下來的空間會被劃分為三塊,並按比例指派給剩下的彈性軌道。

+ +
.wrapper {
+  display: grid;
+  grid-template-columns: 500px 1fr 2fr;
+}
+
+ +

Track listings with repeat() notation

+ +

含有許多軌道的格線能用 repeat() 標記,以使軌道透過迴圈表列數次。以下面為例:

+ +
.wrapper {
+  display: grid;
+  grid-template-columns: 1fr 1fr 1fr;
+}
+
+ +

這可以寫成:

+ +
.wrapper {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+}
+
+ +

重複標記是軌道表列一部分。下例中,我們建立了有 20 像素的軌道,接著重複 1fr 軌道六次,最後以 20 像素的軌道做結。

+ +
.wrapper {
+  display: grid;
+  grid-template-columns: 20px repeat(6, 1fr) 20px;
+}
+
+ +

重複標記使用軌道表列,因此可以用它來建立重複的模式。下個例子的格線,會包含十個軌道:也就是 1fr 後面有 2fr 的軌道,並重複五次。

+ +
.wrapper {
+  display: grid;
+  grid-template-columns: repeat(5, 1fr 2fr);
+}
+
+ +

明式與暗式格線

+ +

在建立上例格線的時候,我們用 {{cssxref("grid-template-columns")}} 屬性指定了列軌道,但格線自己也建立了一行。相較於使用 {{cssxref("grid-template-columns")}} 或 {{cssxref("grid-template-rows")}} 屬性的明式格線(explicit grid),這幾行就屬於暗式格線(implicit grid)。

+ +

你也能在暗式格線內透過 {{cssxref("grid-auto-rows")}} 與 {{cssxref("grid-auto-columns")}} 屬性,給軌道定義一套大小。

+ +

下例將使用 grid-auto-rows 以確保由暗式格線建立的軌道,高度都會是 200 像素。

+ +
<div class="wrapper">
+   <div>One</div>
+   <div>Two</div>
+   <div>Three</div>
+   <div>Four</div>
+   <div>Five</div>
+</div>
+
+ +
.wrapper {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  grid-auto-rows: 200px;
+}
+
+ + + +

{{ EmbedLiveSample('The_implicit_and_explicit_grid', '210', '410') }}

+ +

軌道縮放與 minmax()

+ +

在設定顯式格線或希望自動給軌道一個最小尺寸,但也要確保它們擴展以適應任何添加的內容——像是希望某行不能小於 100 像素以避免跑版,但如果內容高度超過 300 像素,該行就要拉到那麼高。

+ +

針對這個情境,格線提供了 {{cssxref("minmax", "minmax()")}} 函式。本例中,我針對 {{cssxref("grid-auto-rows")}} 指定了 minmax() 的數值。它會指定高度最小要 100 像素,最大則是 autoauto 意味著大小會檢查內容大小,並適配這一行 cell 內最高項目的高度。

+ +
.wrapper {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  grid-auto-rows: minmax(100px, auto);
+}
+
+ + + +
<div class="wrapper">
+  <div>One</div>
+  <div>Two
+  <p>I have some more content in.</p>
+  <p>This makes me taller than 100 pixels.</p>
+</div>
+  <div>Three</div>
+  <div>Four</div>
+  <div>Five</div>
+</div>
+
+ +

{{ EmbedLiveSample('Track_sizing_and_minmax()', '230', '490') }}

+ +

Grid Lines

+ +

It should be noted that when we define a grid we define the grid tracks, not the lines. Grid then gives us numbered lines to use when positioning items. In our three column, two row grid we have four column lines.

+ +

Diagram showing numbered grid lines.

+ +

Lines are numbered according to the writing mode of the document. In a left-to-right language, line 1 is on the left-hand side of the grid. In a right-to-left language, it is on the right-hand side of the grid. Lines can also be named, and we will look at how to do this in a later guide in this series.

+ +

Positioning items against lines

+ +

We will be exploring line based placement in full detail in a later article, the following example demonstrates doing this in a simple way. When placing an item we target the line – rather than the track.

+ +

In the following example I am placing the first two items on our three column track grid, using the {{cssxref("grid-column-start")}}, {{cssxref("grid-column-end")}}, {{cssxref("grid-row-start")}} and {{cssxref("grid-row-end")}} properties. Working from left to right, the first item is placed against column line 1, and spans to column line 4, which in our case is the far right line on the grid. It begins at row line 1 and ends at row line 3, therefore spanning two row tracks.

+ +

The second item starts on grid column line 1, and spans one track. This is the default so I do not need to specify the end line. It also spans two row tracks from row line 3 to row line 5. The other items will place themselves into empty spaces on the grid.

+ +
<div class="wrapper">
+   <div class="box1">One</div>
+   <div class="box2">Two</div>
+   <div class="box3">Three</div>
+   <div class="box4">Four</div>
+   <div class="box5">Five</div>
+</div>
+
+ +
.wrapper {
+    display: grid;
+    grid-template-columns: repeat(3, 1fr);
+    grid-auto-rows: 100px;
+}
+.box1 {
+    grid-column-start: 1;
+    grid-column-end: 4;
+    grid-row-start: 1;
+    grid-row-end: 3;
+}
+.box2 {
+    grid-column-start: 1;
+    grid-row-start: 3;
+    grid-row-end: 5;
+}
+
+ + + +

{{ EmbedLiveSample('Positioning_items_against_lines', '220', '410') }}

+ +

Don't forget that you can use the Grid Inspector in Firefox Developer Tools to see how the items are positioned against the lines of the grid.

+ +

Grid Cells

+ +

A grid cell is the smallest unit on a grid, conceptually it is like a table cell. As we saw in our earlier examples, once a grid is defined on a parent the child items will lay themselves out once in each cell of the defined grid. In the below image I have highlighted the first cell of the grid.

+ +

The first cell of the grid highlighted

+ +

Grid areas

+ +

Items can span one or more cells both by row or by column, and this creates a grid area. Grid areas have to be rectangular – it isn’t possible to create an L-shaped area for example. The highlighted grid area spans two row and two column tracks.

+ +

A grid area

+ +

Gutters

+ +

Gutters or alleys between grid cells can be created using the {{cssxref("grid-column-gap")}} and {{cssxref("grid-row-gap")}} properties, or the shorthand {{cssxref("grid-gap")}}. In the below example I am creating a 10-pixel gap between columns and a 1em gap between rows.

+ +
.wrapper {
+   display: grid;
+   grid-template-columns: repeat(3, 1fr);
+   grid-column-gap: 10px;
+   grid-row-gap: 1em;
+}
+
+ +
<div class="wrapper">
+   <div>One</div>
+   <div>Two</div>
+   <div>Three</div>
+   <div>Four</div>
+   <div>Five</div>
+</div>
+
+ + + +

{{ EmbedLiveSample('Gutters') }}

+ +

Any space used by gaps will be accounted for before space is assigned to flexible length fr tracks, and gaps act for sizing purposes like a regular grid track, however you cannot place anything into a gap. In terms of line-based positioning, the gap acts like a fat line.

+ +

Nesting grids

+ +

A grid item can become a grid container. In the following example I have the three-column grid created earlier, with our two positioned items. In this case the first item has some sub-items. As these items are not direct children of the grid they do not participate in grid layout and so display in normal document flow.

+ +
+
<div class="wrapper">
+   <div class="box box1">
+       <div class="nested">a</div>
+       <div class="nested">b</div>
+        <div class="nested">c</div>
+    </div>
+    <div class="box box2">Two</div>
+    <div class="box box3">Three</div>
+    <div class="box box4">Four</div>
+    <div class="box box5">Five</div>
+</div>
+
+ +

Nested grid in flow

+ +

If I set box1 to display: grid I can give it a track definition and it too will become a grid, the items then lay out on this new grid.

+ +
.box1 {
+   grid-column-start: 1;
+   grid-column-end: 4;
+   grid-row-start: 1;
+   grid-row-end: 3;
+   display: grid;
+   grid-template-columns: repeat(3, 1fr);
+}
+
+ + +
+ +

{{ EmbedLiveSample('nesting', '600', '410') }}

+ +

In this case the nested grid has no relationship to the parent. As you can see in the example it has not inherited the {{cssxref("grid-gap")}} of the parent and the lines in the nested grid do not align to the lines in the parent grid.

+ +

Subgrid

+ +

In the level 1 grid specification there is a feature called subgrid which would let us create nested grids that use the track definition of the parent grid.

+ +
+

Subgrids are not yet implemented in any browsers, and the specification is subject to change.

+
+ +

In the current specification, we would edit the above nested grid example to use display: subgrid rather than display: grid, then remove the track definition. The nested grid will use the parent grid tracks to lay out items.

+ +

It should be noted that the nested grid is in both dimensions—rows and columns. There is no concept of the implicit grid working with subgrids. This means you need to ensure that the parent grid has enough row and column tracks for all the subitems.

+ +
.box1 {
+   grid-column-start: 1;
+   grid-column-end: 4;
+   grid-row-start: 1;
+   grid-row-end: 3;
+   display: subgrid;
+}
+
+ +

Layering items with z-index

+ +

Grid items can occupy the same cell. If we return to our example with items positioned by line number, we can change this to make two items overlap.

+ +
+
<div class="wrapper">
+   <div class="box box1">One</div>
+   <div class="box box2">Two</div>
+   <div class="box box3">Three</div>
+   <div class="box box4">Four</div>
+   <div class="box box5">Five</div>
+</div>
+
+ +
.wrapper {
+   display: grid;
+   grid-template-columns: repeat(3, 1fr);
+   grid-auto-rows: 100px;
+}
+.box1 {
+   grid-column-start: 1;
+   grid-column-end: 4;
+   grid-row-start: 1;
+   grid-row-end: 3;
+}
+.box2 {
+   grid-column-start: 1;
+   grid-row-start: 2;
+   grid-row-end: 4;
+}
+
+ + +
+ +

{{ EmbedLiveSample('l_ex', '210', '410') }}

+ +

The item box2 is now overlapping box1, it displays on top as it comes later in the source order.

+ +

Controlling the order

+ +

We can control the order in which items stack up by using the z-index property - just as with positioned items. If we give box2 a lower z-index than box1 it will display below box1 in the stack.

+ +
.wrapper {
+   display: grid;
+   grid-template-columns: repeat(3, 1fr);
+   grid-auto-rows: 100px;
+}
+.box1 {
+   grid-column-start: 1;
+   grid-column-end: 4;
+   grid-row-start: 1;
+   grid-row-end: 3;
+   z-index: 2;
+}
+.box2 {
+   grid-column-start: 1;
+   grid-row-start: 2;
+   grid-row-end: 4;
+   z-index: 1;
+}
+
+ + + +

{{ EmbedLiveSample('Controlling_the_order', '210', '410') }}

+ +

下一步

+ +

In this article we have had a very quick look through the Grid Layout Specification. Have a play with the code examples, and then move onto the next part of this guide where we will really start to dig into the detail of CSS Grid Layout.

+ + diff --git a/files/zh-tw/web/css/css_grid_layout/index.html b/files/zh-tw/web/css/css_grid_layout/index.html new file mode 100644 index 0000000000..0fd5616848 --- /dev/null +++ b/files/zh-tw/web/css/css_grid_layout/index.html @@ -0,0 +1,252 @@ +--- +title: CSS格線布局 +slug: Web/CSS/CSS_Grid_Layout +tags: + - CSS + - 參考 + - 布局 + - 柵格 + - 示列 + - 網格布局 +translation_of: Web/CSS/CSS_Grid_Layout +--- +

CSS 格線佈局長於把頁面的主要區域分離、或是在 HTML 原生語法構建的區域間,定義大小、位置、層次等方面的關聯。

+ +

格線佈局使作者能夠對齊元素為行和列,就像表格一樣,。然而,格線佈局可以更輕易的達成比一般表格更多元化的排版。例如,一個網格容器的子元素可以定位自己和層重疊,類似於CSS定位元素。

+ +

基本示例

+ +

以下示例展示了一個三列軌道格線,其中創建的行數最小為 100 像素,最大為 auto。Items 已經使用基於線放置在網格的位置上。

+ +
+ + +

HTML

+ +
<div class="wrapper">
+  <div class="one">One</div>
+  <div class="two">Two</div>
+  <div class="three">Three</div>
+  <div class="four">Four</div>
+  <div class="five">Five</div>
+  <div class="six">Six</div>
+</div>
+ +

CSS

+ +
.wrapper {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  grid-gap: 10px;
+  grid-auto-rows: minmax(100px, auto);
+}
+.one {
+  grid-column: 1 / 3;
+  grid-row: 1;
+}
+.two {
+  grid-column: 2 / 4;
+  grid-row: 1 / 3;
+}
+.three {
+  grid-row: 2 / 5;
+  grid-column: 1;
+}
+.four {
+  grid-column: 3;
+  grid-row: 3;
+}
+.five {
+  grid-column: 2;
+  grid-row: 4;
+}
+.six {
+  grid-column: 3;
+  grid-row: 4;
+}
+
+ +

{{ EmbedLiveSample('example', '500', '440') }}

+
+ +

參考

+ +

CSS 屬性

+ +
+ +
+ +

CSS 函式

+ +
+ +
+ +

CSS 資料型別

+ +
+ +
+ +

詞匯表條目

+ +
+ +
+ +

指引

+ +
+ +
+ +

外部資源

+ + + +

規範

+ + + + + + + + + + + + + + + + +
格式狀態意見
{{ SpecName('CSS3 Grid') }}{{ Spec2('CSS3 Grid') }}初始定義
+ + diff --git a/files/zh-tw/web/css/css_lists_and_counters/consistent_list_indentation/index.html b/files/zh-tw/web/css/css_lists_and_counters/consistent_list_indentation/index.html new file mode 100644 index 0000000000..cdde84086c --- /dev/null +++ b/files/zh-tw/web/css/css_lists_and_counters/consistent_list_indentation/index.html @@ -0,0 +1,67 @@ +--- +title: 調整列表縮排 +slug: Web/CSS/CSS_Lists_and_Counters/Consistent_list_indentation +tags: + - CSS + - list indent + - 列表 + - 縮排 +translation_of: Web/CSS/CSS_Lists_and_Counters/Consistent_list_indentation +--- +

原文 : Consistent List Indentation

+ + +

  使用 CSS 來協助縮排列表看來簡單實則卻否,原因很簡單 - 各大瀏覽器其實作方式不盡相同。一個很大的原因來自於對距離的掌握,但這很讓人喪志,因為瀏覽器沒有一致的排版方式。舉例來說,倘若你宣告一個 list 沒有 left margin,在 IE 中他可以被移動,但在 Gecko-based 的瀏覽器中他們將很固執的固定在那。

+ +

  為了更徹底明白為何有這種情況發生,了解列表是怎樣被創造的至關重要。

+

創建列表

+

  首先,我們考慮一個最簡單的 list item。他並不屬於任何一個 list 中,並且也沒有項目符號 (意思就是沒有 bullet )。如 Figure 1 所示:

+

Figure 1

+

  這裡的紅點線框是 list 內容的外框。在這裡的例子中, list item 並沒有設定 padding 或 borders。現在我們加上兩個 list item,如圖二:

+

Figure 2

+

  接著我們加上 parent element,這裡我們以 unordered list (i.e., <ul>)為例。根據 CSS box model,這些 list item 都會被包裹在 parent element 的範圍中。如下圖中的紫色外框,他包住了三個 list item 的外圍:

+

Figure 3

+

  然後我們加上 list item markers。因為我們用的是 unordered list,因此使用預設的 filled-circle "bullets"。結果如下:

+

Figure 4

+

  好的,現在看出來了,這些 marker 在 <ul> 空間之外。但更重要的是,這些 marker 其實是在 <li> 之外!這個結果使得 list item 看起來像是附加在 marker 之上。

+

  結論出來了,在瀏覽器(除了 windows 下的 IE)處理列表時, marker 是在 <li> element 的外頭。所以這些個對 list item 的設定並不會對 marker 造成影響,影響的是其後附加的內容。

+

二次縮排

+

  所以我們該如何設定其外觀?現在讓我們來分析一下下們這組設定:

+
ul, li {margin-left: 0; padding-left: 0;}
+

  當套用了這組設定, marker 將會很悲劇的落到畫面之外。

+

  為了避免這種慘劇發生,瀏覽器有三種不同的實作方式來避免:

+
    +
  1. 幫每一個 <li> element 設定 left margin
  2. +
  3. 幫 <ul> element 設定 left margin
  4. +
  5. 幫 <ul> element 設定一些 left padding
  6. +
+

  事後檢視,沒有瀏覽器採用第一種作法。Windows and Macintosh 上的 Internet Explorer 和 Opera 採用第二種作法。Gecko 相關的瀏覽器則使用第三種設計。

+

  現在讓我們來瞧瞧後兩種作法的差異。在 Internet Explorer 及 Opera 中,<ul> element 為了縮排需要被設定了 40 pixel 的 left margin。假如我們此時在 <ul> element 設定背景顏色,其結果如下:

+

Figure 5

+

  Gecko 則不太一樣,他為 <ul> element 設定了 40 pixel 的 left padding。因此造成上圖的程式碼會在 Gecko 中變成下圖:

+

Figure 6

+

  從結果來說,marker 都很好的附著在 <li> element 之前並未消失。唯一的不同點是發生在你替 <ul> element 設定背景顏色時。

+

不變的是 ...

+

  現在我們知道,若你希望在 Gecko, Internet Explorer 和 Opera 都有一樣的 list 外觀, <ul> element 的 left margin 和 left padding 都要設定。你大可不必理會 <li> 的設定。

+

  假如你想要有 Netscape 6.x 的預設風格,寫法如下:

+
ul {margin-left: 0; padding-left: 40px;}
+

  若你對 Explorer/Opera 風格有興趣,可以寫成:

+
ul {margin-left: 40px; padding-left: 0;}
+

  當然啦,你可以不用 pixel 來表示長度,取而代之的可以使用類似 1.25em 的寫法。現在若你想要重設列表,而不打算有任何縮排,可以這樣寫:

+
ul {margin-left: 0; padding-left: 0;}
+

  請注意,這樣的寫法將造成 bullet 被扔在整個列表及其 parent element 之外。當你在 body 中這樣寫,很顯然的你的 bullet 將不會出現在你的視窗內。

+

結論

+

  在這篇文章中我們並未指出哪個瀏覽器對 list 縮排的處理是正確的。之所以會有不同的排版方式只是因為他們採用了不同的排版方法。確定你設定了 list 的 left padding 和 left margin,這樣你比較能寫出跨瀏覽器良好縮排程式。

+

建議

+ +
+

關於此文件

+ +
diff --git a/files/zh-tw/web/css/css_lists_and_counters/index.html b/files/zh-tw/web/css/css_lists_and_counters/index.html new file mode 100644 index 0000000000..08b7fc4bcf --- /dev/null +++ b/files/zh-tw/web/css/css_lists_and_counters/index.html @@ -0,0 +1,127 @@ +--- +title: CSS Lists and Counters +slug: Web/CSS/CSS_Lists_and_Counters +translation_of: Web/CSS/CSS_Lists_and_Counters +--- +
{{CSSRef}}
+ +

CSS Lists and Counters is a module of CSS that defines how lists are laid out, how the list marker can be styled and how authors can create new counters.

+ +

參考

+ +

屬性

+ +
+ +
+ +

At-rules

+ +
+
{{cssxref("@counter-style")}}
+
+
+
    +
  • {{cssxref("@counter-style/system","system")}}
  • +
  • {{cssxref("@counter-style/additive-symbols", "additive-symbols")}}
  • +
  • {{cssxref("@counter-style/negative", "negative")}}
  • +
  • {{cssxref("@counter-style/prefix", "prefix")}}
  • +
  • {{cssxref("@counter-style/suffix", "suffix")}}
  • +
  • {{cssxref("@counter-style/range", "range")}}
  • +
  • {{cssxref("@counter-style/pad", "pad")}}
  • +
  • {{cssxref("@counter-style/speak-as", "speak-as")}}
  • +
  • {{cssxref("@counter-style/fallback", "fallback")}}
  • +
+
+
+
+ +

指南

+ +
+
Consistent list indentation
+
Explains how to reach a consistent indentation between different browsers.
+
Using CSS counters
+
Describes how to use counters to be able to use numbering outside of traditional list elements or to perform complex counting.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Lists')}}{{Spec2('CSS3 Lists')}} 
{{SpecName('CSS2.1', 'generate.html')}}{{Spec2('CSS2.1')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1.0{{CompatGeckoDesktop("1")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support1.0{{CompatGeckoMobile("1")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
diff --git a/files/zh-tw/web/css/css_positioning/index.html b/files/zh-tw/web/css/css_positioning/index.html new file mode 100644 index 0000000000..0fe6fd55d0 --- /dev/null +++ b/files/zh-tw/web/css/css_positioning/index.html @@ -0,0 +1,108 @@ +--- +title: CSS Positioning +slug: Web/CSS/CSS_Positioning +translation_of: Web/CSS/CSS_Positioning +--- +

{{CSSRef}}

+ +

CSS Positioning is a module of CSS that defines how to absolutely and relavitely position elements on the page.

+ +

參考

+ +

CSS 屬性

+ +
+ +
+ +

指南

+ +
+
Understanding CSS z-index
+
Presents the notion of stacking context and explain how z-ordering works, with several examples.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('CSS3 Positioning') }}{{ Spec2('CSS3 Positioning') }} 
{{ SpecName('CSS2.1', 'visuren.html') }}{{ Spec2('CSS2.1') }} 
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1.0{{ CompatGeckoDesktop("1") }}5.06.01.0 (85)
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support1.0{{ CompatGeckoMobile("1") }}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
diff --git a/files/zh-tw/web/css/css_positioning/understanding_z_index/index.html b/files/zh-tw/web/css/css_positioning/understanding_z_index/index.html new file mode 100644 index 0000000000..8bfd77a677 --- /dev/null +++ b/files/zh-tw/web/css/css_positioning/understanding_z_index/index.html @@ -0,0 +1,40 @@ +--- +title: Understanding CSS z-index +slug: Web/CSS/CSS_Positioning/Understanding_z_index +tags: + - Advanced + - CSS + - Guide + - NeedsTranslation + - TopicStub + - Understanding_CSS_z-index + - Web +translation_of: Web/CSS/CSS_Positioning/Understanding_z_index +--- +

Usually HTML pages can be considered two-dimensional, because text, images and other elements are arranged on the page without overlapping. There is a single rendering flow, and all elements are aware of the space taken by others. The {{cssxref("z-index")}} attribute lets you adjust the order of the layering of objects when rendering content.

+
+

In CSS 2.1, each box has a position in three dimensions. In addition to their horizontal and vertical positions, boxes lie along a "z-axis" and are formatted one on top of the other. Z-axis positions are particularly relevant when boxes overlap visually.

+
+

(from CSS 2.1 Section 9.9.1 - Layered presentation)

+

It means that CSS style rules allow you to position boxes on layers in addition to the normal rendering layer (layer 0). The Z position of each layer is expressed as an integer representing the stacking order for rendering. Greater numbers mean closer to the observer. Z position can be controlled with the CSS {{ cssxref("z-index") }} property.

+

Using z-index appears extremely easy: a single property, assigned a single integer number, with an easy-to-understand behaviour. However, when z-index is applied to complex hierarchies of HTML elements, its behaviour can be hard to understand or even unpredictable. This is due to complex stacking rules. In fact a dedicated section has been reserved in the CSS specification CSS-2.1 Appendix E to explain these rules better.

+

This article will try to explain those rules, with some simplification and several examples.

+
    +
  1. Stacking without z-index : Default stacking rules
  2. +
  3. Stacking and float : How floating elements are handled
  4. +
  5. Adding z-index : Using z-index to change default stacking
  6. +
  7. The stacking context : Notes on the stacking context
  8. +
  9. Stacking context example 1 : 2-level HTML hierarchy, z-index on the last level
  10. +
  11. Stacking context example 2 : 2-level HTML hierarchy, z-index on all levels
  12. +
  13. Stacking context example 3 : 3-level HTML hierarchy, z-index on the second level
  14. +
+

Note of the author: Thanks to Wladimir Palant and Rod Whiteley for the review.

+
+

Original Document Information

+ +
+

 

diff --git a/files/zh-tw/web/css/css_positioning/understanding_z_index/stacking_context_example_1/index.html b/files/zh-tw/web/css/css_positioning/understanding_z_index/stacking_context_example_1/index.html new file mode 100644 index 0000000000..26771f0fbb --- /dev/null +++ b/files/zh-tw/web/css/css_positioning/understanding_z_index/stacking_context_example_1/index.html @@ -0,0 +1,139 @@ +--- +title: Stacking context example 1 +slug: Web/CSS/CSS_Positioning/Understanding_z_index/Stacking_context_example_1 +translation_of: Web/CSS/CSS_Positioning/Understanding_z_index/Stacking_context_example_1 +--- +

« CSS « 理解CSS的z-index

+ +

堆疊環境範例1

+ +

讓我們先從一個基本的例子。根堆疊情況下,我們有兩個div(DIV#1和#DIV 3),兩種相對定位的,但是如果沒有的z-index屬性。裡面DIV#1有一個絕對定位的div#2,而在DIV#3有一個絕對定位的div#4,雙方沒有的z-index屬性。

+ +

唯一的堆疊上下文是根上下文。如果沒有Z-指標,要素依次層疊的發生。

+ +

堆疊環境範例1

+ +

如果DIV#2被分配一個正的(非零和非自動)z索引值,它是上述所有其他的DIV呈現。

+ +

堆疊環境範例1

+ +

然後,如果DIV#4也被分配比DIV#2的Z指數正z指數越大,它上面的所有其他的DIV DIV,包括2#呈現。

+ +

堆疊環境範例1

+ +

在最後的例子,你可以看到,DIV#2和#DIV 4不兄弟姐妹,因為它們屬於不同的家長在HTML元素的層次結構。即便如此,DIV#4堆疊相的DIV#2可以通過z索引來控制。碰巧的是,由於DIV#1和#DIV 3不指定任何的z-index值,他們不創造一個堆疊環境。這意味著,所有的內容,包括DIV#2和DIV#4屬於相同根堆疊環境。

+ +

在堆疊上下文而言,DIV#1和DIV#3簡單地同化到根元素,將得到的層次結構如下:

+ + + +
注: DIV#1和#DIV 3不適透亮。重要的是要記住,分配的不透明度小於1到定位的元素隱式創建一個疊加的背景下,就像一個加入的z-index值是非常重要的。這個例子顯示,當父元素不會創建一個堆疊環境會發生什麼。
+ +

示例源代碼

+ +
<!DOCTYPE HTML PUBLIC“ -  // W3C // DTD XHTML 1.0過渡// EN”
+“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
+<HTML>
+<HEAD> <風格類型=“文本/ CSS”>
+
+DIV {字體:12px的宋體; }
+
+span.bold {字體重量:大膽的; }
+
+#DIV1,#{DIV3
+   高度:80px;
+   位置:親屬;
+   邊界:1px的虛線#669966;
+   背景色:#ccffcc;
+   填充左:5px的;
+}
+
+#{DIV2
+   不透明度:0.8;
+   的z-index:1;
+   位置:絕對的;
+   寬度:150像素;
+   高度:200像素;
+   頂:20像素;
+   左:170px;
+   邊界:1px的虛線#990000;
+   背景色:#ffdddd;
+   文本對齊:中心;
+}
+
+#{DIV4
+   不透明度:0.8;
+   的z-index:2;
+   位置:絕對的;
+   寬度:200像素;
+   高度:70px;
+   頂部:65px;
+   左:50像素;
+   邊界:1px的虛線#000099;
+   背景色:#ddddff;
+   文本對齊:左;
+   填充左:10px的;
+}
+
+
+</風格> </ HEAD>
+
+<BODY>
+
+<br />
+
+<DIV ID =“DIV1”>
+<br />的<span class =“黑體”> DIV#1 </ SPAN>
+<br />位置:親屬;
+   <DIV ID =“DIV2”>
+   <br />的<span class =“黑體”> DIV#2 </ SPAN>
+   <br />位置:絕對的;
+   <br />的z-index:1;
+   </ DIV>
+</ DIV>
+
+<br />
+
+<DIV ID =“DIV3”>
+<br />的<span class =“黑體”> DIV#3 </ SPAN>
+<br />位置:親屬;
+   <DIV ID =“DIV4”>
+   <br />的<span class =“黑體”> DIV#4 </ SPAN>
+   <br />位置:絕對的;
+   <br />的z-index:2;
+   </ DIV>
+</ DIV>
+
+</ BODY> </ HTML>
+
+ +

另請參見

+ + + +
+

原始文檔信息

+ + +
+ +

 

diff --git a/files/zh-tw/web/css/css_properties_reference/index.html b/files/zh-tw/web/css/css_properties_reference/index.html new file mode 100644 index 0000000000..74d192427e --- /dev/null +++ b/files/zh-tw/web/css/css_properties_reference/index.html @@ -0,0 +1,317 @@ +--- +title: CSS 屬性參考 +slug: Web/CSS/CSS_Properties_Reference +translation_of: Web/CSS/CSS_Properties_Reference +--- +

常見 CSS 屬性參考

+ +

下列為最為常見的 CSS 屬性基本清單及其對應的 文件物件模型(DOM)屬性——通常由 JavaScript 進行存取:

+ +
備註:  此清單並不完整, 更多屬性請見  CSS 參考文件 與  Mozilla CSS extensions。 CSS參考文件也包含屬性使用範例。
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CSSJavaScript
backgroundbackground
background-attachmentbackgroundAttachment
background-colorbackgroundColor
background-imagebackgroundImage
background-positionbackgroundPosition
background-repeatbackgroundRepeat
borderborder
border-bottomborderBottom
border-bottom-colorborderBottomColor
border-bottom-styleborderBottomStyle
border-bottom-widthborderBottomWidth
border-colorborderColor
border-leftborderLeft
border-left-colorborderLeftColor
border-left-styleborderLeftStyle
border-left-widthborderLeftWidth
border-rightborderRight
border-right-colorborderRightColor
border-right-styleborderRightStyle
border-right-widthborderRightWidth
border-styleborderStyle
border-topborderTop
border-top-colorborderTopColor
border-top-styleborderTopStyle
border-top-widthborderTopWidth
border-widthborderWidth
clearclear
clipclip
colorcolor
cursorcursor
displaydisplay
filterfilter
fontfont
font-familyfontFamily
font-sizefontSize
font-variantfontVariant
font-weightfontWeight
heightheight
leftleft
letter-spacingletterSpacing
line-heightlineHeight
list-stylelistStyle
list-style-imagelistStyleImage
list-style-positionlistStylePosition
list-style-typelistStyleType
marginmargin
margin-bottommarginBottom
margin-leftmarginLeft
margin-rightmarginRight
margin-topmarginTop
overflowoverflow
paddingpadding
padding-bottompaddingBottom
padding-leftpaddingLeft
padding-rightpaddingRight
padding-toppaddingTop
page-break-afterpageBreakAfter
page-break-beforepageBreakBefore
positionposition
floatcssFloat
text-aligntextAlign
text-decorationtextDecoration
text-decoration: blinktextDecorationBlink
text-decoration: line-throughtextDecorationLineThrough
text-decoration: nonetextDecorationNone
text-decoration: overlinetextDecorationOverline
text-decoration: underlinetextDecorationUnderline
text-indenttextIndent
text-transformtextTransform
toptop
vertical-alignverticalAlign
visibilityvisibility
widthwidth
z-indexzIndex
diff --git a/files/zh-tw/web/css/css_selectors/index.html b/files/zh-tw/web/css/css_selectors/index.html new file mode 100644 index 0000000000..5f52beea02 --- /dev/null +++ b/files/zh-tw/web/css/css_selectors/index.html @@ -0,0 +1,123 @@ +--- +title: CSS Selectors +slug: Web/CSS/CSS_Selectors +translation_of: Web/CSS/CSS_Selectors +--- +
{{CSSRef}}
+ +

選擇器可以定義某組 CSS 樣式要套用到哪些元素上。

+ +

基本選擇器

+ +
+
通用選擇器Universal selector
+
用以選擇所有元素。(可選)可以將其限制為特定的名稱空間或所有名稱空間。
+ 語法: * ns|* *|*
+ 範例: * 套用文檔中所有元素。
+
標籤選擇器Type selector
+
用以選擇所有符合指定標籤的元素。
+ 語法: elementname
+ 範例: input 可選出任一 <input> 元素。
+
類別選擇器Class selector
+
用以選擇所有符合指定 class 屬性值的元素。
+ 語法: .classname
+ 範例: .index 可選出任一含有 index 的 class 屬性值之元素。
+
ID選擇器ID selector
+
用以選擇指定 id 屬性值的元素。(一個文件中,每個ID屬性都是唯一的。)
+ 語法: #idname
+ 範例: #toc 會比對含有 ID 是 toc 的元素(可以定義成 id="toc" 或其他類似的定義)。
+
屬性選擇器Attribute selector
+
用以選擇所有符合指定屬性的元素。
+ 語法: [attr] [attr=value] [attr~=value] [attr|=value] [attr^=value] [attr$=value] [attr*=value]
+ 範例: [autoplay] 將會套用含有 autoplay 屬性的元素。(不論這個屬性的值是什麼)。
+
+ +

分組選擇器

+ +
+
選擇器列表(Selector list
+
, 用以將不同的選擇器組合起來的一種方法。
+ 語法: AB
+ 範例: div, span 將同時選擇 <div><span> 元素。
+
+ +

組合選擇器

+ +
+
+
後代選擇器Descendant combinator
+
  (空格) 用以選擇某個元素後代的元素。
+ 語法: A B
+ 範例: div span 套用所有  <div> 元素內部的所有 <span> 元素。
+
子代選擇器Child combinator
+
> 用以選擇某個元素後代的元素。
+ 語法: A > B(B元素不可在A元素的其他元素裡)
+ 範例: ul > li 套用所有 <li> 元素內部的 <ul> 子元素。
+
一般兄弟選擇器General sibling combinator
+
~ combinator selects siblings. This means that the second element follows the first (though not necessarily immediately), and both share the same parent.
+ 語法: A ~ B
+ 範例: p ~ span will match all {{HTMLElement("span")}} elements that follow a {{HTMLElement("p")}}, immediately or not.
+
相鄰兄弟選擇器Adjacent sibling combinator
+
+ 選擇緊接在後的元素,並共享父元素。
+ 語法: A + B
+ 範例: h2 + p 套用所有 緊接在 <h2> 元素後的 <p> 元素,並擁有 <h2> 的父元素。
+
Column combinator {{Experimental_Inline}}
+
The || combinator selects nodes which belong to a column.
+ 語法: A || B
+ 範例: col || td will match all {{HTMLElement("td")}} elements that belong to the scope of the {{HTMLElement("col")}}.
+
+ +

偽選擇器

+ +
+
Pseudo classes
+
The : pseudo allow the selection of elements based on state information that is not contained in the document tree.
+ 範例: a:visited will match all {{HTMLElement("a")}} elements that have been visited by the user.
+
Pseudo elements
+
The :: pseudo represent entities that are not included in HTML.
+ 範例: p::first-line will match the first line of all {{HTMLElement("p")}} elements.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("CSS4 Selectors")}}{{Spec2("CSS4 Selectors")}}Added the || column combinator, grid structural selectors, logical combinators, location, time-demensional, resource state, linguistic and UI pseudo-classes, modifier for ASCII case-sensitive and case-insensitive attribute value selection.
{{SpecName("CSS3 Selectors")}}{{Spec2("CSS3 Selectors")}}Added the ~ general sibling combinator and tree-structural pseudo-classes.
+ Made pseudo-elements use a :: double-colon prefix. Additional attribute selectors
{{SpecName("CSS2.1", "selector.html")}}{{Spec2("CSS2.1")}}Added the > child and + adjacent sibling combinators.
+ Added the universal and attribute selectors.
{{SpecName("CSS1")}}{{Spec2("CSS1")}}Initial definition.
+ +

See the pseudo-class and pseudo-element specification tables for details on those.

+ +

參見

+ + diff --git a/files/zh-tw/web/css/css_selectors/using_the__colon_target_pseudo-class_in_selectors/index.html b/files/zh-tw/web/css/css_selectors/using_the__colon_target_pseudo-class_in_selectors/index.html new file mode 100644 index 0000000000..e21ca62c5f --- /dev/null +++ b/files/zh-tw/web/css/css_selectors/using_the__colon_target_pseudo-class_in_selectors/index.html @@ -0,0 +1,62 @@ +--- +title: '使用 :target' +slug: 'Web/CSS/CSS_Selectors/Using_the_:target_pseudo-class_in_selectors' +translation_of: 'Web/CSS/CSS_Selectors/Using_the_:target_pseudo-class_in_selectors' +--- +

When a URL points at a specific piece of a document, it can be difficult to ascertain. Find out how you can use some simple CSS to draw attention to the target of a URL and improve the user's experience. As an aid to identifying the destination of a link that points to a specific portion of a document, CSS3 Selectors introduces the {{ Cssxref(":target") }} pseudo-class. Netscape 7.1 introduced support for this pseudo-class into the Netscape family, giving authors a new way to assist users keep oriented within large documents.

+ +

挑選目標

+ +

The pseudo-class {{ Cssxref(":target") }} is used to style the target element of a URI containing a fragment identifier. For example, the URI http://developer.mozilla.org/en/docs/Using_the_:target_selector#Example contains the fragment identifier #Example. In HTML, identifiers are found as the values of either id or name attributes, since the two share the same namespace. Thus, the example URI would point to the heading "Example" in this document.

+ +

Suppose you wish to style any h2 element that is the target of a URI, but do not want any other kind of element to get a target style. This is simple enough:

+ +
h2:target {font-weight: bold;}
+ +

It's also possible to create styles that are specific to a particular fragment of the document. This is done using the same identifying value that is found in the URI. Thus, to add a border to the #Example fragment, we would write:

+ +
#Example:target {border: 1px solid black;}
+ +

選擇所有元素

+ +

If the intent is to create a "blanket" style that will apply to all targeted elements, then the universal selector comes in handy:

+ +
:target {color: red;}
+
+ +

範例

+ +

In the following example, there are five links that point to elements in the same document. Selecting the "First" link, for example, will cause <h1 id="one"> to become the target element. Note that the document may jump to a new scroll position, since target elements are placed on the top of the browser window if possible.

+ +
+
<h4 id="one">...</h4> <p id="two">...</p>
+<div id="three">...</div> <a id="four">...</a> <em id="five">...</em>
+
+<a href="#one">First</a>
+<a href="#two">Second</a>
+<a href="#three">Third</a>
+<a href="#four">Fourth</a>
+<a href="#five">Fifth</a>
+
+ +

結論

+ +

In cases where a fragment identifier points to a portion of the document, readers may become confused about which part of the document they're supposed to be reading. By styling the target of a URI, reader confusion can be reduced or eliminated.

+ + + + + +
+

文檔訊息

+ + +
diff --git a/files/zh-tw/web/css/css_transitions/index.html b/files/zh-tw/web/css/css_transitions/index.html new file mode 100644 index 0000000000..30fb2738c2 --- /dev/null +++ b/files/zh-tw/web/css/css_transitions/index.html @@ -0,0 +1,110 @@ +--- +title: CSS Transitions +slug: Web/CSS/CSS_Transitions +translation_of: Web/CSS/CSS_Transitions +--- +
{{CSSRef}}{{SeeCompatTable}}
+ +

CSS Transitions is a module of CSS that defines how to create smooth transitions between values of given CSS properties. It allows to create them but also to define their evolution, using timing functions.

+ +

參考

+ +

屬性

+ +
+ +
+ +

指南

+ +
+
Using CSS transitions
+
Step-by-step tutorial about how to create smooth transitions using CSS. This article describes each relevant CSS property and explains how they interact.
+
+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Transitions')}}{{Spec2('CSS3 Transitions')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0 {{property_prefix("-webkit")}}
+ 26.0
{{CompatGeckoDesktop("2.0")}} {{property_prefix("-moz")}}
+ {{CompatGeckoDesktop("16.0")}}
10.011.6 {{property_prefix("-o")}}
+ 12.10 #
3.0 {{property_prefix("-webkit")}}
+ 6.1
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support2.1 {{property_prefix("-webkit")}}{{CompatGeckoMobile("2.0")}} {{property_prefix("-moz")}}
+ {{CompatGeckoMobile("16.0")}}
{{CompatUnknown}}10.0 {{property_prefix("-o")}}
+ 12.10 #
3.2 {{property_prefix("-webkit")}}
+
+ +

參見

+ + diff --git a/files/zh-tw/web/css/css_transitions/using_css_transitions/index.html b/files/zh-tw/web/css/css_transitions/using_css_transitions/index.html new file mode 100644 index 0000000000..ecbdf92487 --- /dev/null +++ b/files/zh-tw/web/css/css_transitions/using_css_transitions/index.html @@ -0,0 +1,384 @@ +--- +title: CSS 轉場 +slug: Web/CSS/CSS_Transitions/Using_CSS_transitions +tags: + - CSS animation + - CSS transition + - CSS 轉場 + - CSS 過渡 +translation_of: Web/CSS/CSS_Transitions/Using_CSS_transitions +--- +

   

+
+

原文 : https://developer.mozilla.org/en/CSS/CSS_transitions

+

 

+
+

{{ SeeCompatTable() }}

+

   CSS transitions 是 CSS3 specification 草案的一部分,他可以用來調整 CSS animation 變動的速度。舉例來說,倘若你設計了一個 element 會由白轉紅,你可以透過 CSS transitions 來控制轉變的時間及變化曲線。

+
+ 注意: CSS transitions specification 目前仍舊以草案形式存在,所以當你要在 Gecko 的系統中使用時,記得加上 "-moz-" 的前綴。此外,為了更好的相容,你還得加上 "-webkit-" 前綴 (給基於 Webkit 技術的瀏覽器)以及 "-o-" (Opera 使用)。舉例來說,你可能會寫出包含有 -moz-transition-webkit-transition 及 -o-transition 的程式。
+

可供調整的 CSS property 清單

+

  CSS transitions 和 CSS animations 中可以用來修改的屬性在 CSS animatable properties 可以看到。這裡頭同時包含了 SVG properties。

+
+ 注意: 這些列出 properties 可能都還會改變,所以請使用已經被支援的那些,以免造成無法預期的結果。
+

CSS transition properties

+

  我們可以透過 {{ cssxref("transition") }} property 來控制 CSS transitions。這可有效避免使用過長的參數來控制你的 transitions,這樣亦減少了 debug 的難度。

+

  下列的 sub-properties 可以協助你控制轉場的性質:

+
+
+ {{ cssxref("transition-property") }}
+
+  定義哪些 CSS properties 會被轉場效果影響。除了這些被你特別指出的 property 名單,其他的轉場一如以往的會在瞬間完成。
+
+ {{ cssxref("transition-duration") }}
+
+ 定義轉場所花費的時間。你可以只定義一個時間給所有 property 使用,也可以給定多組不同時間。
+
+ {{ cssxref("transition-timing-function") }}
+
+ 設定轉場時所依據的貝茲曲線。
+
+ {{ cssxref("transition-delay") }}
+
+ 定義多久之後開始發生轉場。
+
+

使用漸變函式 (transition timing function)

+

  漸變函式可用來定義轉場發生的時間曲線。其規範方式是以四個參數的貝茲曲線代表:

+

+

  CSS transition function manipulator 是一個可以讓你非常容易以視覺化方式了解轉場流程的工具。

+

  除了自行定義之外,尚有幾個已經預先定義好的函式:

+
    +
  • ease, 等同於 cubic-bezier(0.25, 0.1, 0.25, 1.0)
  • +
  • linear, 等同於 cubic-bezier(0.0, 0.0, 1.0, 1.0)
  • +
  • ease-in, 等同於 cubic-bezier(0.42, 0, 1.0, 1.0)
  • +
  • ease-out, 等同於 cubic-bezier(0, 0, 0.58, 1.0)
  • +
  • ease-in-out, 等同於 cubic-bezier(0.42, 0, 0.58, 1.0)
  • +
+

一個 transition timing effect 範例

+

  我們在這直接用範例來說明。

+

  在看程式碼之前,或許你會想先看看實際的執行效果。請挑個有支援 transitions 的瀏覽器,然後看看這個 (而這裡有這個範例的相關 CSS 程式碼)。

+

  首先,先以 HTML 創建這個範例的主要外殼:

+
<ul>
+  <li id="long1">Long, gradual transition...</li>
+  <li id="fast1">Very fast transition...</li>
+  <li id="delay1">Long transition with a 2-second delay...</li>
+  <li id="easeout">Using ease-out timing...</li>
+  <li id="linear">Using linear timing...</li>
+  <li id="cubic1">Using cubic-bezier(0.2, 0.4, 0.7, 0.8)...</li>
+</ul>
+
+

  如你所見,每個 item 都有自己的 ID。剩下的部份交由 CSS 來處理。

+

使用延遲機制

+

  這個範例會在使用者滑鼠移過 element 後兩秒開始四秒的字體大小變化:

+
#delay1 {
+  position: relative;
+  transition-property: font-size;
+  transition-duration: 4s;
+  transition-delay: 2s;
+  font-size: 14px;
+}
+
+#delay1:hover {
+  transition-property: font-size;
+  transition-duration: 4s;
+  transition-delay: 2s;
+  font-size: 36px;
+}
+
+

使用線性轉場函式 (linear transition timing function)

+

  如果你希望動畫的變動是以線性的速率,那你可以寫成:

+
transition-timing-function: linear;
+
+

  此外,還有許多不同的 timing functions 供你選擇,請見 {{ cssxref("transition-timing-function") }}。

+

用貝茲曲線定義 timing function

+

  你可以定義自己想要的 timing function,這要用貝茲曲線 (cubic bezier curve) 的形式定義之:

+
  transition-timing-function: cubic-bezier(0.2, 0.4, 0.7, 0.8);
+
+

  上例中我們定義了一個以 (0.0, 0.0), (0.2, 0.4), (0.7, 0.8) 和 (1.0, 1.0) 描述的貝茲曲線。

+

偵測 transition 的完成

+

  在設計上,當 transition 完成時會觸發一個 event。在 Firefox 中,他是 transitionend ; 在 Opera 中,他是 oTransitionEnd ; 而在 WebKit 中,他是  webkitTransitionEnd。請注意相容性的問題(參閱本頁最下方)。

+

  transitionend event 提供了兩個 properties:

+
+
+ propertyName
+
+ 這指出哪個 CSS property 的 transition 已經完成。
+
+ elapsedTime
+
+ 指出 transition 花費了幾秒。注意,他不受 {{ cssxref("transition-delay") }} 影響。
+
+

  在平常使用上,你可以使用 {{ domxref("element.addEventListener()") }} method 來監控:

+
el.addEventListener("transitionend", updateTransition, true);
+
+
+ 注意: "transitionend" event 若 transition 在執行中被中斷(意指 transition 沒有真正完成)則不會觸發。
+

當 property value list 之間並不等長時 ... ?

+

  如果某個 property 的 list 長度比其他短時,他將會被重複,直到等長。例如:

+
div {
+  transition-property: opacity, left, top, height;
+  transition-duration: 3s, 5s;
+}
+
+

  他會被瀏覽器解釋成:

+
div {
+  transition-property: opacity, left, top, height;
+  transition-duration: 3s, 5s, 3s, 5s;
+}
+

  可以預期地,倘若列出的 value 過多,他會被切斷。例如:

+
div {
+  transition-property: opacity, left;
+  transition-duration: 3s, 5s, 2s, 1s;
+}
+

  那麼他等同於:

+
div {
+  transition-property: opacity, left;
+  transition-duration: 3s, 5s;
+}
+

使用 transitions 來強調選單中的選項

+

  一個使用 CSS 的好時機是用來強調目前使用者滑鼠經過的選單位置。使用 transitions 可以使效果變得更吸引人。

+

  在看實際的程式碼之前,你可以先看實際的範例 (當然你的瀏覽器要能支援 transitions)。相關的 CSS 程式在這裡。 

+

  我們先用 HTML 構建外殼:

+
<div class="sidebar">
+  <p><a class="menuButton" href="home">Home</a></p>
+  <p><a class="menuButton" href="about">About</a></p>
+  <p><a class="menuButton" href="contact">Contact Us</a></p>
+  <p><a class="menuButton" href="links">Links</a></p>
+</div>
+
+

  接著用 CSS 來產生特效:

+
.menuButton {
+  position: relative;
+  transition-property: background-color, color;
+  transition-duration: 1s;
+  transition-timing-function: ease-out;
+  -webkit-transition-property: background-color, color;
+  -webkit-transition-duration: 1s;
+  -o-transition-property: background-color, color;
+  -o-transition-duration: 1s;
+  text-align: left;
+  background-color: grey;
+  left: 5px;
+  top: 5px;
+  height: 26px;
+  color: white;
+  border-color: black;
+  font-family: sans-serif;
+  font-size: 20px;
+  text-decoration: none;
+  -moz-box-shadow: 2px 2px 1px black;
+  padding: 2px 4px;
+  border: solid 1px black;
+}
+
+.menuButton:hover {
+  position: relative;
+  transition-property: background-color, color;
+  transition-duration: 1s;
+  transition-timing-function: ease-out;
+  -webkit-transition-property: background-color, color;
+  -webkit-transition-duration: 1s;
+  -o-transition-property: background-color, color;
+  -o-transition-duration: 1s;
+  background-color:white;
+  color:black;
+  -moz-box-shadow: 2px 2px 1px black;
+}
+
+

  這些 CSS 程式使滑鼠滑過時 (在該 element 的 {{ cssxref(":hover") }} state) 造成背景及文字顏色的改變。

+

使用 transitions 來使 JavaScript 運作的更順暢

+

  Transition 是一種很好的工具,他可以幫助你的 JavaScript 執行結果看起來的更為順暢。舉例來說:

+
<p>Click anywhere to move the ball</p>
+<div id="foo"></div>
+
+

  當你使用 JavaScript 可以將 ball 移動到特定位置:

+
var f = document.getElementById('foo');
+document.addEventListener('click', function(ev){
+    f.style.left = (ev.clientX-25)+'px';
+    f.style.top = (ev.clientY-25)+'px';
+},false);    
+
+

  藉由 CSS,你可以使執行結果更為流暢。我們加入了:

+
p{
+  padding-left:60px;
+}
+#foo{
+  border-radius:50px;
+  width:50px;
+  height:50px;
+  background:#c00;
+  position:absolute;
+  top:0;
+  left:0;
+  -moz-transition: all 1s; 
+  -webkit-transition: all 1s;  
+  -ms-transition: all 1s;  
+  -o-transition: all 1s;  
+  transition: all 1s;  
+}
+
+

  你可以到 http://jsfiddle.net/RwtHn/5/ 看範例。

+

使用 transition events 來替 object 製作動畫

+

  這裡讓我們看個例子,一個內含文字的方塊左右來回移動,並且會在兩種顏色之間做轉變:

+

 

+ +

  在我們仔細研究程式碼之前可以先看範例。同樣地,可以到看其 CSS 的寫法。

+

HTML 程式碼

+

  搭配上面範例的 HTML 程式碼並不複雜:

+
<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Transition Demo</title>
+    <link rel="stylesheet" href="transitions.css" type="text/css">
+    <script src="transitions.js" type="text/javascript"></script>
+  </head>
+  <body onload="runDemo()">
+    <div class="slideRight">This is a box!</div>
+  </body>
+</html>
+
+

  這裡唯一要注意的地方是我們用 slideRight 來修飾 "This is a box!"。此外,在這個文件被讀取時,就會觸發 runDemo() function。

+

CSS 程式碼

+

  我們使用 slideRight 和 slideLeft 這兩個 CSS class 來建構動畫 (請參閱 transitions.css )。這裡列出部分:

+
.slideRight {
+  position: absolute;
+  -moz-transition-property: background-color, color, left;
+  -moz-transition-duration: 5s;
+  -webkit-transition-property: background-color, color, left;
+  -webkit-transition-duration: 5s;
+  -o-transition-property: background-color, color, left;
+  -o-transition-duration: 5s;
+  background-color: red;
+  left: 0%;
+  color: black;
+}
+
+

  我們再這明確定義了 position property。這是一件必要的事情,不然動畫將不知道如何開始。

+

  {{ cssxref("transition-property") }} property 指出哪些 CSS properties 會被包含在動畫效果中。在這個例子中是 {{ cssxref("background-color") }}, {{ cssxref("color") }} 以及 {{ cssxref("left") }}。 {{ cssxref("transition-duration") }} property 則說明了整個動畫將歷時 5 秒。

+

  為了相容於 WebKit 及 Opera,當中還定了一些以 "-webkit-" 和 "-o-" 起始的 property。

+

  總的來說, "slideRight" class 定義了最左端點時的狀態 (準備向右滑動)。所以你可以看到 {{ cssxref("left") }} property 是 0% 。

+

  下面我們定義了 "slideLeft" class,他表示最右端時的狀態 (準備向左滑動):

+
.slideLeft {
+  position: absolute;
+  -moz-transition-property: background-color, color, left;
+  -moz-transition-duration: 5s;
+  -webkit-transition-property: background-color, color, left;
+  -webkit-transition-duration: 5s;
+  -o-transition-property: background-color, color, left;
+  -o-transition-duration: 5s;
+  text-align: center;
+  background-color: blue;
+  left: 90%;
+  color: white;
+  width: 100px;
+  height: 100px;
+}
+

JavaScript 程式碼

+

  在定義了左右兩端點的狀態後,現在我們可以準備來描述 animation 了。這可以簡單的透過 JavaScript 達成。

+
+ 注意: 在這裡,倘若 CSS animations 被使用者的瀏覽器支援,那就未必要使用 JavaScript 了。
+

  首先定義 runDemo() function,他將在文件被讀取後立刻執行:

+
function runDemo() {
+  var el = updateTransition();
+
+  // Set up an event handler to reverse the direction
+  // when the transition finishes.
+
+  el.addEventListener("transitionend", updateTransition, true);
+}
+
+

  他呼叫了 updateTransition() function (這待會會定義),並且他捕捉了 "transitionend" event,這使我們能夠知道動畫結束了。

+

  updateTransition() function 內容如下:

+
function updateTransition() {
+  var el = document.querySelector("div.slideLeft");
+
+  if (el) {
+    el.className = "slideRight";
+  } else {
+    el = document.querySelector("div.slideRight");
+    el.className = "slideLeft";
+  }
+
+  return el;
+}
+
+

  這裡的機制很簡單,我們找到 "slideLeft" 而後將他改變成 "slideRight",接著動畫便結束。倘若此時並沒有 "slideLeft",就表示已在右端點,於是執行反向動作。

+

瀏覽器的支援情形

+

{{ CompatibilityTable() }}

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support1.0{{ CompatGeckoDesktop("2") }}1010.53.2
Property-webkit-transition-moz-transition-ms-transition-o-transition-webkit-transition
Transition ended eventwebkitTransitionEndtransitionendMSTransitionEndoTransitionEndwebkitTransitionEnd
+
+
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support2.1{{ CompatGeckoMobile("2") }}{{ CompatUnknown() }}103.2
+
+

更多資訊

+ +

{{ HTML5ArticleTOC() }}

+

{{ languages( { "es": "es/CSS/Transiciones_de_CSS", "ja": "ja/CSS/CSS_transitions" } ) }}

+
+
+

 

diff --git a/files/zh-tw/web/css/cursor/index.html b/files/zh-tw/web/css/cursor/index.html new file mode 100644 index 0000000000..6e20cbbb43 --- /dev/null +++ b/files/zh-tw/web/css/cursor/index.html @@ -0,0 +1,306 @@ +--- +title: cursor +slug: Web/CSS/cursor +translation_of: Web/CSS/cursor +--- +
{{CSSRef}}
+ +

此 cursor CSS 屬性可以指定當滑鼠指標指向哪個物件時,顯示不同的游標.

+ +
{{EmbedInteractiveExample("pages/css/cursor.html")}}
+ + + +

語法

+ +
/* 關鍵字值 */
+cursor: pointer;
+cursor: auto;
+
+/* URL, with a keyword fallback */
+cursor: url(hand.cur), pointer;
+
+/* URL and coordinates, with a keyword fallback */
+cursor: url(cursor1.png) 4 12, auto;
+cursor: url(cursor2.png) 2 2, pointer;
+
+/* 全域值 */
+cursor: inherit;
+cursor: initial;
+cursor: unset;
+
+ +

The cursor property is specified as zero or more <url> values, separated by commas, followed by a single mandatory keyword value. Each <url> should point to an image file. The browser will try to load the first image specified, falling back to the next if it can't, and falling back to the keyword value if no images could be loaded (or if none were specified).

+ +

Each <url> may be optionally followed by a pair of space-separated numbers, which represent <x><y> coordinates. These will set the cursor's hotspot, relative to the top-left corner of the image.

+ +

For example, this specifies two images using <url> values, providing <x><y> coordinates for the second one, and falling back to the progress keyword value if neither image can be loaded:

+ +
cursor: url(one.svg), url(two.svg) 5 5, progress;
+ +

數值

+ +
+
<url>
+
A url(…) or a comma separated list url(…), url(…), …, pointing to an image file. More than one {{cssxref("<url>")}} may be provided as fallbacks, in case some cursor image types are not supported. A non-URL fallback (one or more of the keyword values) must be at the end of the fallback list. See Using URL values for the cursor property for more details.
+
<x> <y> {{experimental_inline}}
+
Optional x- and y-coordinates. Two unitless nonnegative numbers less than 32.
+
關鍵字值
+
+

Move your mouse over values to see their live appearance in your browser:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
分類CSS 值範例備註說明
一般auto The UA will determine the cursor to display based on the current context. E.g., equivalent to text when hovering text.
defaultdefault.gifThe platform-dependent default cursor. Typically an arrow.
none No cursor is rendered.
連結與狀態context-menucontext-menu.pngA context menu is available.
helphelp.gifHelp information is available.
pointerpointer.gifThe cursor is a pointer that indicates a link. Typically an image of a pointing hand.
progressprogress.gifThe program is busy in the background, but the user can still interact with the interface (in contrast to wait).
waitwait.gifThe program is busy, and the user can't interact with the interface (in contrast to progress). Sometimes an image of an hourglass or a watch.
選取cellcell.gifThe table cell or set of cells can be selected.
crosshaircrosshair.gifCross cursor, often used to indicate selection in a bitmap.
texttext.gifThe text can be selected. Typically the shape of an I-beam.
vertical-textvertical-text.gifThe vertical text can be selected. Typically the shape of a sideways I-beam.
拖曳aliasalias.gifAn alias or shortcut is to be created.
copycopy.gifSomething is to be copied.
movemove.gifSomething is to be moved.
no-dropno-drop.gifAn item may not be dropped at the current location.
+ {{bug("275173")}}: On Windows and Mac OS X, no-drop is the same as not-allowed.
not-allowednot-allowed.gifThe requested action will not be carried out.
grabgrab.gifSomething can be grabbed (dragged to be moved).
grabbinggrabbing.gifSomething is being grabbed (dragged to be moved).
改變尺寸與捲軸尺all-scrollall-scroll.gifSomething can be scrolled in any direction (panned).
+ {{bug("275174")}}: On Windows, all-scroll is the same as move.
col-resizecol-resize.gifThe item/column can be resized horizontally. Often rendered as arrows pointing left and right with a vertical bar separating them.
row-resizerow-resize.gifThe item/row can be resized vertically. Often rendered as arrows pointing up and down with a horizontal bar separating them.
n-resizeExample of a resize towards the top cursorSome edge is to be moved. For example, the se-resize cursor is used when the movement starts from the south-east corner of the box.
+ In some environments, an equivalent bidirectional resize cursor is shown. For example, n-resize and s-resize are the same as ns-resize.
e-resizeExample of a resize towards the right cursor
s-resizeExample of a resize towards the bottom cursor
w-resizeExample of a resize towards the left cursor
ne-resizeExample of a resize towards the top-right corner cursor
nw-resizeExample of a resize towards the top-left corner cursor
se-resizeExample of a resize towards the bottom-right corner cursor
sw-resizeExample of a resize towards the bottom-left corner cursor
ew-resize3-resize.gifBidirectional resize cursor.
ns-resize6-resize.gif
nesw-resize1-resize.gif
nwse-resize4-resize.gif
縮放zoom-inzoom-in.gif +

Something can be zoomed (magnified) in or out.

+
zoom-outzoom-out.gif
+
+
+ +

公式語法

+ +
{{csssyntax}}
+
+ +

範例

+ +
.foo {
+  cursor: crosshair;
+}
+
+.bar {
+  cursor: zoom-in;
+}
+
+/* A fallback keyword value is required when using a URL */
+.baz {
+  cursor: url("hyper.cur"), auto;
+}
+
+ +

規格

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Basic UI', '#cursor', 'cursor')}}{{Spec2('CSS3 Basic UI')}}Addition of several keywords and the positioning syntax for url().
{{SpecName('CSS2.1', 'ui.html#cursor-props', 'cursor')}}{{Spec2('CSS2.1')}}Initial definition.
+ +

{{cssinfo}}

+ +

瀏覽器相容性

+ + + +

{{Compat("css.properties.cursor")}}

+ +

參照

+ + diff --git a/files/zh-tw/web/css/descendant_combinator/index.html b/files/zh-tw/web/css/descendant_combinator/index.html new file mode 100644 index 0000000000..6fe82cfc8d --- /dev/null +++ b/files/zh-tw/web/css/descendant_combinator/index.html @@ -0,0 +1,121 @@ +--- +title: 後裔選擇器 +slug: Web/CSS/Descendant_combinator +tags: + - CSS + - CSS參考 + - Selectors + - 初學者 + - 選擇器 +translation_of: Web/CSS/Descendant_combinator +--- +

{{CSSRef("Selectors")}}

+ +

簡介

+ +

組合符號 (代表空白, 或更精準地說,代表一或多個空白字元) 結合了兩種選擇器,選擇了只有當第二個選擇器的目標為第一個選擇器目標的後裔時的元素,後裔選擇器跟子選擇器相似,但是不要求披對的元素要是嚴格是父子關係。

+ +

語法

+ +
selector1 selector2 { style properties }
+
+ +

範例

+ +
span { background-color: white; }
+div span { background-color: DodgerBlue; }
+
+ +
<div>
+  <span>Span 1.
+    <span>Span 2.</span>
+  </span>
+</div>
+<span>Span 3.</span>
+
+ +

{{ EmbedLiveSample('Example', 200, 50) }}

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('CSS4 Selectors', '#descendant-combinators', 'descendant combinator') }}{{ Spec2('CSS4 Selectors') }} 
{{ SpecName('CSS3 Selectors', '#descendant-combinators', 'descendant combinator') }}{{ Spec2('CSS3 Selectors') }} 
{{ SpecName('CSS2.1', 'selector.html#descendant-selectors', 'descendant selectors') }}{{ Spec2('CSS2.1') }} 
{{ SpecName('CSS1', '#contextual-selectors', 'contextual selectors') }}{{ Spec2('CSS1') }}Initial definition
+ +

Browser compatibility

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}
+
diff --git a/files/zh-tw/web/css/grid-row/index.html b/files/zh-tw/web/css/grid-row/index.html new file mode 100644 index 0000000000..d7c3ed1543 --- /dev/null +++ b/files/zh-tw/web/css/grid-row/index.html @@ -0,0 +1,194 @@ +--- +title: grid-row +slug: Web/CSS/grid-row +translation_of: Web/CSS/grid-row +--- +

Summary 

+ +

The grid-row CSS property is a shorthand property for {{cssxref("grid-row-start")}} and {{cssxref("grid-row-end")}} specifying a grid item’s size and location within the grid row by contributing a line, a span, or nothing (automatic) to its grid placement, thereby specifying the inline-start and inline-end edge of its {{glossary("grid areas", "grid area")}}.

+ +

If two <grid-line> values are specified, the grid-row-start longhand is set to the value before the slash, and the grid-row-end longhand is set to the value after the slash.

+ +

{{cssinfo}}

+ +

Syntax

+ +
/* Keyword values */
+grid-row: auto;
+grid-row: auto / auto;
+
+/* <custom-ident> values */
+grid-row: somegridarea;
+grid-row: somegridarea / someothergridarea;
+
+/* <integer> + <custom-ident> values */
+grid-row: somegridarea 4;
+grid-row: 4 somegridarea / 6;
+
+/* span + <integer> + <custom-ident> values */
+grid-row: span 3;
+grid-row: span somegridarea;
+grid-row: 5 somegridarea span;
+grid-row: span 3 / 6;
+grid-row: span somegridarea / span someothergridarea;
+grid-row: 5 somegridarea span / 2 span;
+
+/* Global values */
+grid-row: inherit;
+grid-row: initial;
+grid-row: unset;
+
+ +

Values

+ +
+
auto
+
Is a keyword indicating that the property contributes nothing to the grid item’s placement, indicating auto-placement, an automatic span, or a default span of 1.
+
<custom-ident>
+
If there is a named line with the name '<custom-ident>-start'/'<custom-ident>-end', it contributes the first such line to the grid item’s placement. +

Note: Named grid areas automatically generate implicit named lines of this form, so specifying grid-row: foo; will choose the start/end edge of that named grid area (unless another line named foo-start/foo-end was explicitly specified before it).

+ +

Otherwise, this is treated as if the integer 1 had been specified along with the <custom-ident>.

+
+
<integer> && <custom-ident>?
+
Contributes the nth grid line to the grid item’s placement. If a negative integer is given, it instead counts in reverse, starting from the end edge of the explicit grid. +

If a name is given as a <custom-ident>, only lines with that name are counted. If not enough lines with that name exist, all implicit grid lines are assumed to have that name for the purpose of finding this position.

+ +

An {{cssxref("integer")}} value of 0 is invalid.

+
+
span && [ <integer> || <custom-ident> ]
+
Contributes a grid span to the grid item’s placement such that the corresponding edge of the grid item’s grid area is n lines from the opposite edge. +

If a name is given as a <custom-ident>, only lines with that name are counted. If not enough lines with that name exist, all implicit grid lines on the side of the explicit grid corresponding to the search direction are assumed to have that name for the purpose of counting this span.

+ +

If the <integer> is omitted, it defaults to 1. Negative integers or 0 are invalid.

+
+
+ +

Formal syntax

+ +
{{csssyntax}}
+ +

Example

+ +

HTML Content

+ +
<div id="grid">
+  <div id="item1"></div>
+  <div id="item2"></div>
+  <div id="item3"></div>
+</div>
+ +

CSS Content

+ +
#grid {
+  display: grid;
+  height: 200px;
+  grid-template-columns: 200px;
+  grid-template-rows: repeat(6, 1fr);
+}
+
+#item1 {
+  background-color: lime;
+}
+
+#item2 {
+  background-color: yellow;
+  grid-row: 2 / 4;
+}
+
+#item3 {
+  background-color: blue;
+  grid-row: span 2 / 7;
+}
+
+ +

{{EmbedLiveSample("Example", "200px", "200px")}}

+ +

Specifications

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("CSS3 Grid", "#propdef-grid-row", "grid-row")}}{{Spec2("CSS3 Grid")}}Initial definition
+ +

Browser compatibility

+ + + +

{{Compat("css.properties.grid-row")}}

+ +

See also

+ + + + diff --git a/files/zh-tw/web/css/grid-template-columns/index.html b/files/zh-tw/web/css/grid-template-columns/index.html new file mode 100644 index 0000000000..31ef2b30b3 --- /dev/null +++ b/files/zh-tw/web/css/grid-template-columns/index.html @@ -0,0 +1,196 @@ +--- +title: 网格模板列 +slug: Web/CSS/grid-template-columns +tags: + - CSS + - CSS網格 + - 列子 +translation_of: Web/CSS/grid-template-columns +--- +

Summary

+ +

The grid-template-columns CSS property defines the line names and track sizing functions of the {{glossary("grid column", "grid columns")}}.

+ +

{{cssinfo}}

+ +

Syntax

+ +
/* Keyword value */
+grid-template-columns: none;
+
+/* <track-list> values */
+grid-template-columns: 100px 1fr;
+grid-template-columns: [linename] 100px;
+grid-template-columns: [linename1] 100px [linename2 linename3];
+grid-template-columns: minmax(100px, 1fr);
+grid-template-columns: fit-content(40%);
+grid-template-columns: repeat(3, 200px);
+
+/* <auto-track-list> values */
+grid-template-columns: 200px repeat(auto-fill, 100px) 300px;
+grid-template-columns: minmax(100px, max-content)
+                       repeat(auto-fill, 200px) 20%;
+grid-template-columns: [linename1] 100px [linename2]
+                       repeat(auto-fit, [linename3 linename4] 300px)
+                       100px;
+grid-template-columns: [linename1 linename2] 100px
+                       repeat(auto-fit, [linename1] 300px) [linename3];
+
+/* Global values */
+grid-template-columns: inherit;
+grid-template-columns: initial;
+grid-template-columns: unset;
+
+ +

Values

+ +
+
none
+
Is a keyword meaning that there is no explicit grid. Any columns will be implicitly generated and their size will be determined by the {{cssxref("grid-auto-columns")}} property.
+
<length>
+
Is a non-negative length.
+
<percentage>
+
Is a non-negative {{cssxref("percentage", "<percentage>")}} value relative to the inline size of the grid container. If the size of the grid container depends on the size of its tracks, then the percentage must be treated as auto.
+ The intrinsic size contributions of the track may be adjusted to the size of the grid container and increase the final size of the track by the minimum amount that would result in honoring the percentage.
+
<flex>
+
Is a non-negative dimension with the unit fr specifying the track’s flex factor. Each <flex>-sized track takes a share of the remaining space in proportion to its flex factor. +

When appearing outside a minmax() notation, it implies an automatic minimum (i.e. minmax(auto, <flex>)).

+
+
max-content
+
Is a keyword representing the largest maximal content contribution of the grid items occupying the grid track.
+
min-content
+
Is a keyword representing the largest minimal content contribution of the grid items occupying the grid track.
+
{{cssxref("minmax", "minmax(min, max)")}}
+
Is a functional notation that defines a size range greater than or equal to min and less than or equal to max. If max is smaller than min, then max is ignored and the function is treated as min. As a maximum, a <flex> value sets the track’s flex factor. It is invalid as a minimum.
+
auto
+
Is a keyword that is identical to maximal content if it's a maximum. As a minimum it represents the largest minimum size (as specified by {{cssxref("min-width")}}/{{cssxref("min-height")}}) of the grid items occupying the grid track.
+
+

Note: auto track sizes (and only auto track sizes) can be stretched by the {{cssxref("align-content")}} and {{cssxref("justify-content")}} properties.

+
+
{{cssxref("fit-content", "fit-content( [ <length> | <percentage> ] )")}}
+
Represents the formula min(max-content, max(auto, argument)), which is calculated similar to auto (i.e. minmax(auto, max-content)), except that the track size is clamped at argument if it is greater than the auto minimum.
+
{{cssxref("repeat", "repeat( [ <positive-integer> | auto-fill | auto-fit ] , <track-list> )")}}
+
Represents a repeated fragment of the track list, allowing a large number of columns that exhibit a recurring pattern to be written in a more compact form.
+
+ +

Formal syntax

+ +
{{csssyntax}}
+ +

Examples

+ +

CSS

+ +
#grid {
+  display: grid;
+  width: 100%;
+  grid-template-columns: 50px 1fr;
+}
+
+#areaA {
+  background-color: lime;
+}
+
+#areaB {
+  background-color: yellow;
+}
+ +

HTML

+ +
<div id="grid">
+  <div id="areaA">A</div>
+  <div id="areaB">B</div>
+</div>
+ +

Result

+ +

{{EmbedLiveSample("Examples", "100%", "20px")}}

+ +

Specifications

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("CSS3 Grid", "#propdef-grid-template-columns", "grid-template-columns")}}{{Spec2("CSS3 Grid")}}Initial definition
+ +

Browser compatibility

+ + + +

{{Compat("css.properties.grid-template-columns")}}

+ +

See also

+ + + + diff --git a/files/zh-tw/web/css/grid-template/index.html b/files/zh-tw/web/css/grid-template/index.html new file mode 100644 index 0000000000..9363bb9e1e --- /dev/null +++ b/files/zh-tw/web/css/grid-template/index.html @@ -0,0 +1,197 @@ +--- +title: grid-template +slug: Web/CSS/grid-template +translation_of: Web/CSS/grid-template +--- +

grid-templateCSS屬性是一個速記屬性,用於定義{{詞彙表(“網格列”,“網格列”)}},{{詞彙表(“網格行”,“行”)}},和{{詞彙表(“格狀區“,” area“)}}。

+ +
{{EmbedInteractiveExample(“ pages / css / grid-template.html”)}}
+ + + +

作者可以為長期屬性設置值:{{cssxref(“ grid-template-rows”)}},{{cssxref(“ grid-template-columns”)}}和{{cssxref(“ grid-template-areas “)}}。

+ +

句法

+ +
/* Keyword value */
+grid-template: none;
+
+/* grid-template-rows / grid-template-columns values */
+grid-template: 100px 1fr / 50px 1fr;
+grid-template: auto 1fr / auto 1fr auto;
+grid-template: [linename] 100px / [columnname1] 30% [columnname2] 70%;
+grid-template: fit-content(100px) / fit-content(40%);
+
+/* grid-template-areas grid-template-rows / grid-template-column values */
+grid-template: "a a a"
+               "b b b";
+grid-template: "a a a" 20%
+               "b b b" auto;
+grid-template: [header-top] "a a a"     [header-bottom]
+                 [main-top] "b b b" 1fr [main-bottom]
+                            / auto 1fr auto;
+
+/* Global values */
+grid-template: inherit;
+grid-template: initial;
+grid-template: unset;
+
+ +

價值觀

+ +
+
none
+
是將所有三個長期屬性設置為的關鍵字none,表示沒有顯式網格。沒有命名的網格區域。行和列將隱式生成;它們的大小將由{{cssxref(“ grid-auto-rows”)}}和{{cssxref(“ grid-auto-columns”)}}屬性確定。
+
<'grid-template-rows'> / <'grid-template-columns'>
+
將{{cssxref(“ grid-template-rows”)}}和{{cssxref(“ grid-template-columns”)}}設置為指定值,並設置{{cssxref(“ grid-template-areas”)} }至none
+
[ <line-names>? <string> <track-size>? <line-names>? ]+ [ / <explicit-track-list> ]?
+
Sets {{cssxref("grid-template-areas")}} to the strings listed, {{cssxref("grid-template-rows")}} to the track sizes following each string (filling in auto for any missing sizes), and splicing in the named lines defined before/after each size, and {{cssxref("grid-template-columns")}} to the track listing specified after the slash (or none, if not specified).
+ +

Note: The {{cssxref("repeat")}} function isn’t allowed in these track listings, as the tracks are intended to visually line up one-to-one with the rows/columns in the “ASCII art”.

+
+
+ +

Note: The {{cssxref("grid")}} shorthand accepts the same syntax, but also resets the implicit grid properties to their initial values. Use grid (as opposed to grid-template) to prevent these values from cascading in seperately.

+ +

Formal syntax

+ +
{{csssyntax}}
+ +

Examples

+ +

CSS

+ +
#page {
+  display: grid;
+  width: 100%;
+  height: 200px;
+  grid-template: [header-left] "head head" 30px [header-right]
+                 [main-left]   "nav  main" 1fr  [main-right]
+                 [footer-left] "nav  foot" 30px [footer-right]
+                 / 120px 1fr;
+}
+
+header {
+  background-color: lime;
+  grid-area: head;
+}
+
+nav {
+  background-color: lightblue;
+  grid-area: nav;
+}
+
+main {
+  background-color: yellow;
+  grid-area: main;
+}
+
+footer {
+  background-color: red;
+  grid-area: foot;
+}
+ +

HTML

+ +
<section id="page">
+  <header>Header</header>
+  <nav>Navigation</nav>
+  <main>Main area</main>
+  <footer>Footer</footer>
+</section>
+ +

Result

+ +

{{EmbedLiveSample("Examples", "100%", "200px")}}

+ +

Specifications

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName("CSS3 Grid", "#propdef-grid-template", "grid-template")}}{{Spec2("CSS3 Grid")}}Initial definition
+ +

{{cssinfo}}

+ +

Browser compatibility

+ + + +

{{Compat("css.properties.grid-template")}}

+ +

See also

+ + + + diff --git a/files/zh-tw/web/css/height/index.html b/files/zh-tw/web/css/height/index.html new file mode 100644 index 0000000000..139ec496b6 --- /dev/null +++ b/files/zh-tw/web/css/height/index.html @@ -0,0 +1,234 @@ +--- +title: height +slug: Web/CSS/height +translation_of: Web/CSS/height +--- +
{{CSSRef}}
+ +

概要

+ +

高度(height) 的 CSS 屬性指定了元素內容區域的高度。content area 在元素的留白(padding)、邊框(border) 與 邊界(margin) 內。

+ +

{{cssxref("min-height")}} 與 {{cssxref("max-height")}} 的特性比 {{Cssxref("height")}} 更重要。

+ +

{{cssinfo}}

+ +

語法

+ +
/* Keyword value */
+height: auto;
+
+/* <length> values */
+height: 120px;
+height: 10em;
+
+/* <percentage> value */
+height: 75%;
+
+/* Global values */
+height: inherit;
+height: initial;
+height: unset;
+
+ +

+ +
+
<length>
+
查看 {{cssxref("<length>")}} 可用的單位。
+
<percentage>
+
{{cssxref("<percentage>")}} 相對於元素的塊狀高度。如果沒有指定塊狀元素的高度,預設值為 auto。用在 root 元素 (e.g. <html>) 上是相對於初始塊狀元素(即顯示器的尺寸)。
+
border-box {{experimental_inline}}
+
If present, the preceding {{cssxref("<length>")}} or {{cssxref("<percentage>")}} is applied to the element's border box.
+
content-box {{experimental_inline}}
+
{{cssxref("<length>")}} 或 {{cssxref("<percentage>")}} 是應用於元素的 content box.
+
auto
+
瀏覽器將計算並選擇指定元素的高度。
+
fill {{experimental_inline}}
+
Use the fill-available inline size or fill-available block size, as appropriate to the writing mode.
+
max-content {{experimental_inline}}
+
The intrinsic preferred height.
+
min-content {{experimental_inline}}
+
The intrinsic minimum height.
+
available {{experimental_inline}}
+
The containing block height minus vertical margin, border and padding.
+
fit-content {{experimental_inline}}
+
The larger of: +
    +
  • the intrinsic minimum height
  • +
  • the smaller of the intrinsic preferred height and the available height
  • +
+
+
+ +

正式語法

+ +
{{csssyntax}}
+ +

範例

+ +

HTML

+ +
<div id="red">
+  <span>I'm 50 pixels tall.</span>
+</div>
+<div id="green">
+  <span>I'm 25 pixels tall.</span>
+</div>
+<div id="parent">
+  <div id="child">
+    <span>I'm half the height of my parent.</span>
+  </div>
+</div>
+
+ +

CSS

+ +
div {
+  width: 250px;
+  margin-bottom: 5px;
+  border: 3px solid #999999;
+}
+
+#red {
+  height: 50px;
+}
+
+#green {
+  height: 25px;
+}
+
+#parent {
+  height: 100px;
+}
+
+#child {
+  height: 50%;
+  width: 75%;
+}
+
+ +

{{EmbedLiveSample('Example')}}

+ +

規格

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Box', '#the-width-and-height-properties', 'height')}}{{Spec2('CSS3 Box')}}Added the max-content, min-content, available, fit-content, border-box, content-box keywords.
{{SpecName('CSS3 Transitions', '#animatable-css', 'height')}}{{Spec2('CSS3 Transitions')}}Lists height as animatable.
{{SpecName('CSS2.1', 'visudet.html#the-height-property', 'height')}}{{Spec2('CSS2.1')}}Adds support for the {{cssxref("<length>")}} values and precises on which element it applies to.
{{SpecName('CSS1', '#height', 'height')}}{{Spec2('CSS1')}}Initial definition
{{SpecName('CSS3 Sizing', '#width-height-keywords', 'width')}}{{Spec2('CSS3 Sizing')}}Adds new sizing keywords for width and height.
+ +

瀏覽器兼容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1")}}4.07.01.0
fill, fit-content, min-content, max-content{{CompatChrome(46.0)}}{{CompatUnknown}}    
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidAndroid WebviewEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari MobileChrome for Android
Basic support1.0{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatGeckoMobile("1")}}6.06.01.0{{CompatVersionUnknown}}
fill, fit-content, min-content, max-content{{CompatUnknown}}{{CompatChrome(46.0)}}{{CompatUnknown}}    {{CompatChrome(46.0)}}
+
+ +

See also

+ + diff --git a/files/zh-tw/web/css/ime-mode/index.html b/files/zh-tw/web/css/ime-mode/index.html new file mode 100644 index 0000000000..a487af23e0 --- /dev/null +++ b/files/zh-tw/web/css/ime-mode/index.html @@ -0,0 +1,56 @@ +--- +title: ime-mode +slug: Web/CSS/ime-mode +tags: + - CSS +translation_of: Web/CSS/ime-mode +--- +

{{ CSSRef() }} +{{ Fx_minversion_header(3) }} +

+

摘要

+

ime-mode 特性可用以控制某文字輸入欄位的輸入法狀態。 +

+ +

語法

+
ime-mode: <mode>
+
+

特性值

+
auto
不改變輸入法狀態,此為預設值。 +
normal
輸入法設為一般狀態,使用者可在自訂樣式表中蓋過網頁的設定。Internet Explorer 不支援此值。 +
active
輸入法設為啟用狀態。除非使用者刻意關閉、否則此文字欄位將使用輸入法工具。Linux 不支援此值。 +
inactive
輸入法設為關閉狀態,但使用者仍可另行啟用。Linux 不支援此值。 +
disabled
輸入法設為停用狀態,在此欄位中使用者亦無法將其啟用。 +
+

範例

+
<input type="text" name="name" value="initial value" style="ime-mode: disabled">
+
+

此範例在輸入欄位中設定為停用輸入法,在後端資料庫不支援擴充字元集、卻必須讓使用者自行輸入文字時,可以使用。 +

+

備註

+

與 Internet Explorer 不同的地方是,Firefox 實作 ime-mode 時亦允許此特性套用至密碼輸入欄位,但這在理想的使用體驗上有不妥之處、而密碼欄位也應該停用輸入法。若有網站執意將不適切的行為套用至密碼欄位,則使用者可以在自訂 CSS 檔中加上下列設定以強迫調整此功能: +

+
input[type=password] {
+	ime-mode: auto !important;
+}
+
+

{{ Note("一般說來,公開的網站不該自行調整輸入法模式的行為。這個特性主要是給網際應用程式使用的。") }} +

Mac 版的 Gecko 1.9 中,若某欄位設定停用輸入法,則自該欄位移開輸入焦點時並無法自行恢復輸入法狀態,所以若使用 disabled 值,Mac 的使用者可能會碰上麻煩。 +

{{ Note("別僅僅仰賴停用輸入法的招術來避免使用者輸入擴充字元,因為即使輸入法被停用,使用者依然可自他處剪下擴充字元後貼到表單欄位中。") }} +

+

規格出處

+ +

瀏覽器相容性

+

Firefox 3 以後便能同 Internet Explorer 一般支援 ime-mode 特性。 +


+

+
+
+{{ languages( { "en": "en/CSS/ime-mode", "es": "es/CSS/ime-mode", "fr": "fr/CSS/ime-mode", "ja": "ja/CSS/ime-mode" } ) }} diff --git a/files/zh-tw/web/css/index.html b/files/zh-tw/web/css/index.html new file mode 100644 index 0000000000..f894fc2d6a --- /dev/null +++ b/files/zh-tw/web/css/index.html @@ -0,0 +1,100 @@ +--- +title: CSS +slug: Web/CSS +tags: + - CSS + - Cascading Style Sheets + - Design + - Landing + - Layout + - Reference + - Style Sheets + - Styles + - Stylesheets + - 樣式表 + - 版面配置 + - 設計 +translation_of: Web/CSS +--- +

層疊樣式表(Cascading Style Sheets, CSS)是用來描述 HTMLXML(包含 SVGXHTML 等各種 XML 變形)文件外觀的樣式表語言。CSS 會描述文件裡的結構化元素,該如何呈現在螢幕、紙、語音報讀、或其他媒介上。

+ +

CSS開放網路的核心語言之一,具有標準化的 W3C 規範。歷經不同層級的開發,CSS1 目前已被棄用、CSS2.1 是建議規範,而 CSS3 目前被分作數個較小的模組,持續在標準化的路上行進。

+ +
+ + +
+
+

教學

+ +

我們的 CSS 學習專區有很多從頭教起的 CSS 模組。你不需要背景知識。

+ +
+
CSS 介紹
+
此模組讓你理解 CSS 工作原理,包含選擇器與屬性、撰寫 CSS 規則、在 HTML 套用 CSS、如何在 CSS 指定長度、色彩、還有其它單位、階層與繼承、box model 基礎、以及針對 CSS 除錯。
+
文字樣式
+
在這裡我們專注在文字樣式的基礎,包含設定字體、粗細、斜體、行距、字距、陰影以及其他文字屬性。最後以應用自訂字體、樣式化列表、樣式化連結結束。
+
樣式化盒子
+
接著,我們關注樣式化盒子,這是網頁排版中一個基礎的環節。在這個系列中我們會複習盒子模型,然後操作盒子的排版,像是設定留白、邊框、邊距、背景顏色或圖片以及其他特色,還有一些酷炫的功能像是陰影、過濾器。
+
CSS 排版
+
到了這裡,我們已經看完 CSS 的基礎(樣式化文字、樣式化與操作盒子使你的內容可以合適的展示)。現在該來看看如何把你的盒子放在相對於可視區正確的地方。我們已經擁有必要的知識,所以你可以更深入了解 CSS 排版、看不同的顯示設定、傳統排版方法如浮動或定位、新的排版方法如彈性盒子。
+
+
+ +
+

參考

+ + + +

CSS 開發工具

+ + + +

Meta 錯誤

+ +
    +
  • Firefox: {{bug(1323667)}}
  • +
+
+
+
+ +

參見

+ + diff --git a/files/zh-tw/web/css/inheritance/index.html b/files/zh-tw/web/css/inheritance/index.html new file mode 100644 index 0000000000..f67ad62107 --- /dev/null +++ b/files/zh-tw/web/css/inheritance/index.html @@ -0,0 +1,48 @@ +--- +title: 繼承 +slug: Web/CSS/inheritance +translation_of: Web/CSS/inheritance +--- +

摘要

+ +

每個 CSS property definition 都寫道是否這個屬性預設有繼承: ("Inherited: Yes") 或是 預設沒有繼承: ("Inherited: no"). 這個設定將會在沒有位屬性標註值時發生.

+ +

繼承屬性

+ +

When no value for an inherited property has been specified on an element, the element gets the computed value of that property on its parent element. Only the root element of the document gets the initial value given in the property's summary.

+ +

A typical example of an inherited property is the {{ Cssxref("color") }} property. Given the style rules:

+ +
p { color: green }
+ +

HTML:

+ +
<p>This paragraph has <em>emphasized text</em> in it.</p>
+ +

the words "emphasized text" will appear green, since the em element has inherited the value of the {{ Cssxref("color") }} property from the p element. It does not get the initial value of the property (which is the color that is used for the root element when the page specifies no color).

+ +

非繼承屬性

+ +

When no value for an non-inherited property (sometimes called a reset property in Mozilla code) has been specified on an element, the element gets the initial value of that property (as specified in the property's summary).

+ +

A typical example of a non-inherited property is the {{ Cssxref("border") }} property. Given the style rules:

+ +
 p { border: medium solid }
+ +

HTML:

+ +
  <p>This paragraph has <em>emphasized text</em> in it.</p>
+ +

the words "emphasized text" will not have a border (since the initial value of {{ Cssxref("border-style") }} is none).

+ +

+ +

{{ Cssxref("inherit") }} 關鍵字允許作者準確地去標註. 這個在繼承和非繼承屬性都是有效的.

+ +

參見

+ + diff --git a/files/zh-tw/web/css/line-break/index.html b/files/zh-tw/web/css/line-break/index.html new file mode 100644 index 0000000000..f7e073e100 --- /dev/null +++ b/files/zh-tw/web/css/line-break/index.html @@ -0,0 +1,71 @@ +--- +title: line-break +slug: Web/CSS/line-break +translation_of: Web/CSS/line-break +--- +
{{CSSRef}}
+ +

line-break CSS 屬性能夠設定在中文、日文和韓文(CJK) 的文字中,遇到標點或符號時該如何斷行。

+ +
/* Keyword values */
+line-break: auto;
+line-break: loose;
+line-break: normal;
+line-break: strict;
+line-break: anywhere;
+
+/* Global values */
+line-break: inherit;
+line-break: initial;
+line-break: unset;
+
+ +
{{cssinfo}}
+ +

Syntax

+ +

Values

+ +
+
auto
+
以預設的斷行規則斷開文字。
+
loose
+
Break text using the least restrictive line break rule. Typically used for short lines, such as in newspapers.
+
normal
+
Break text using the most common line break rule.
+
strict
+
Break text using the most stringent line break rule.
+
anywhere 
+
+

There is a soft wrap opportunity around every typographic character unit, including around any punctuation character or preserved white spaces, or in the middle of words, disregarding any prohibition against line breaks, even those introduced by characters with the GL, WJ, or ZWJ character class or mandated by the word-break property. The different wrapping opportunities must not be prioritized. Hyphenation is not applied.

+
+
+ +

Formal syntax

+ +
{{csssyntax}}
+ +

Specifications

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Text', '#line-break-property', 'line-break')}}{{Spec2('CSS3 Text')}}Initial definition
+ +

Browser compatibility

+ + + +

{{Compat("css.properties.line-break")}}

diff --git a/files/zh-tw/web/css/media_queries/index.html b/files/zh-tw/web/css/media_queries/index.html new file mode 100644 index 0000000000..41339e07bc --- /dev/null +++ b/files/zh-tw/web/css/media_queries/index.html @@ -0,0 +1,112 @@ +--- +title: Media queries +slug: Web/CSS/Media_Queries +translation_of: Web/CSS/Media_Queries +--- +
{{CSSRef}}
+ +

Media Queries is a module of CSS that defines expressions allowing to tailor presentations to a specific range of output devices without changing the content itself.

+ +

參考

+ +

At-rules

+ +
+ +
+ +

指南

+ +
+
Using media queries
+
Presents what media queries are doing and explains the possible expressions.
+
Testing media queries
+
Explains how to test a media query programmatically, from JavaScript.
+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Conditional')}}{{Spec2('CSS3 Conditional')}} 
{{SpecName('CSS4 Media Queries')}}{{Spec2('CSS4 Media Queries')}} 
{{SpecName('CSS3 Media Queries')}}{{Spec2('CSS3 Media Queries')}} 
{{SpecName('CSS2.1', 'media.html')}}{{Spec2('CSS2.1')}}Initial definition
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support1.0{{CompatGeckoDesktop(1.7)}}9.09.21.3
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support1.0{{CompatGeckoMobile(1.7)}}9.09.03.1
+
diff --git a/files/zh-tw/web/css/media_queries/testing_media_queries/index.html b/files/zh-tw/web/css/media_queries/testing_media_queries/index.html new file mode 100644 index 0000000000..5c61c6483f --- /dev/null +++ b/files/zh-tw/web/css/media_queries/testing_media_queries/index.html @@ -0,0 +1,118 @@ +--- +title: 測試 media queries +slug: Web/CSS/Media_Queries/Testing_media_queries +translation_of: Web/CSS/Media_Queries/Testing_media_queries +--- +

{{SeeCompatTable}}

+ +

DOM 提供了一個用程式去測試 media query 的方法:那就是透過 {{domxref("MediaQueryList") }} 物件;透過 {{domxref("MediaQueryList") }} 物件上的屬性和方法,我們可以得知、觀察目前 media query 的狀態。

+ +

創建 media query list 物件

+ +

透過傳入目標 medai query 到 {{domxref("window.matchMedia") }} 方法,我們將可以取得相對應的 MediaQueryList 物件。

+ +

以下範例將取得偵測螢幕方向的 MediaQueryList 物件:

+ +
var mql = window.matchMedia("(orientation: portrait)");
+
+ +

檢查 media query 結果

+ +

讀取 MediaQueryList 物件 的 matches 屬性就可以得知測試結果:

+ +
if (mql.matches) {
+  /* The device is currently in portrait orientation */
+} else {
+  /* The device is currently in landscape orientation */
+}
+
+ +

接收測試結果通知

+ +

當我們想要動態依據 media query 測試狀況執行對應處理,除了持續定期偵測外,還有一個更有效率的途徑:那就是註冊 media query 的事件處理器 (listener)。只要呼叫 MediaQueryList 物件上 addListener 方法,傳入符合 {{domxref("MediaQueryListListener") }} 介面的 listener 便完成事件註冊

+ +
var mql = window.matchMedia("(orientation: portrait)");
+mql.addListener(handleOrientationChange);
+handleOrientationChange(mql);
+
+ +

上面我們替螢幕方向 media query 註冊了一個 listener。請注意,在第一次註冊後,listener 會立刻被呼叫一次,這是為了初始化準備,因為我們可能預設 UI 是針對 'portait' 模式,但目前卻是 'landscape' 模式,所以這個第一次呼叫將給予我們作初始化調整的空間。

+ +

下面handleOrientationChange() 方法便是我們針對螢幕方向變化的 listener

+ +
function handleOrientationChange(mql) {
+  if (mql.matches) {
+    /* The device is currently in portrait orientation */
+  } else {
+    /* The device is currently in landscape orientation */
+  }
+}
+
+ +

停止接收測試結果通知

+ +

當我們不需要接受通知時,只需要呼叫 removeListener 方法,然後傳入欲移除的 listener 即可:

+ +
mql.removeListener(handleOrientationChange);
+
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support9{{CompatGeckoDesktop("6.0") }}1012.15.1
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support3.0{{CompatUnknown}}1012.15
+
+ +

 

+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/css/object-fit/index.html b/files/zh-tw/web/css/object-fit/index.html new file mode 100644 index 0000000000..e6b73dc0b9 --- /dev/null +++ b/files/zh-tw/web/css/object-fit/index.html @@ -0,0 +1,217 @@ +--- +title: object-fit +slug: Web/CSS/object-fit +translation_of: Web/CSS/object-fit +--- +
{{CSSRef}}
+ +

Summary

+ +

The object-fit CSS property specifies how the contents of a replaced element should be fitted to the box established by its used height and width.

+ +

物件契合(object-fit)CSS屬性能指定置換元素(replaced element)的內容要如何契合、安裝到其使用的高度和寬度已確定的框。

+ +

 

+ +

{{cssinfo}}

+ +

Syntax

+ +
/* Keyword values */
+object-fit: fill;
+object-fit: contain;
+object-fit: cover;
+object-fit: none;
+object-fit: scale-down;
+
+/* Global values */
+object-fit: inherit;
+object-fit: initial;
+object-fit: unset;
+
+ +

Values

+ +
+
fill
+
The replaced content is sized to fill the element’s content box: the object’s concrete object size is the element’s used width and height.
+
contain
+
The replaced content is sized to maintain its aspect ratio while fitting within the element’s content box: its concrete object size is resolved as a contain constraint against the element’s used width and height.
+
cover
+
The replaced content is sized to maintain its aspect ratio while filling the element’s entire content box: its concrete object size is resolved as a cover constraint against the element’s used width and height.
+
none
+
The replaced content is not resized to fit inside the element’s content box: the object’s concrete object size is determined using the default sizing algorithm with no specified size, and a default object size equal to the replaced element’s used width and height.
+
scale-down
+
The content is sized as if none or contain were specified, whichever would result in a smaller concrete object size.
+
+ +

Formal syntax

+ +
{{csssyntax}}
+ +

Example

+ +

HTML Content

+ +
<div>
+  <h2>object-fit: fill</h2>
+  <img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" alt="MDN Logo" class="fill"/>
+
+  <img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" alt="MDN Logo" class="fill narrow"/>
+
+  <h2>object-fit: contain</h2>
+  <img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" alt="MDN Logo" class="contain"/>
+
+  <img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" alt="MDN Logo" class="contain narrow"/>
+
+  <h2>object-fit: cover</h2>
+  <img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" alt="MDN Logo" class="cover"/>
+
+  <img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" alt="MDN Logo" class="cover narrow"/>
+
+  <h2>object-fit: none</h2>
+  <img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" alt="MDN Logo" class="none"/>
+
+  <img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" alt="MDN Logo" class="none narrow"/>
+
+  <h2>object-fit: scale-down</h2>
+  <img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" alt="MDN Logo" class="scale-down"/>
+
+  <img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" alt="MDN Logo" class="scale-down narrow"/>
+
+</div>
+ +

CSS Content

+ +
h2 {
+  font-family: Courier New, monospace;
+  font-size: 1em;
+  margin: 1em 0 0.3em;
+}
+
+div {
+  display: flex;
+  flex-direction: column;
+  flex-wrap: wrap;
+  align-items: flex-start;
+  height: 940px;
+}
+
+img {
+  width: 150px;
+  height: 100px;
+  border: 1px solid #000;
+}
+
+.narrow {
+  width: 100px;
+  height: 150px;
+  margin-top: 10px;
+}
+
+.fill {
+  object-fit: fill;
+}
+
+.contain {
+  object-fit: contain;
+}
+
+.cover {
+  object-fit: cover;
+}
+
+.none {
+  object-fit: none;
+}
+
+.scale-down {
+  object-fit: scale-down;
+}
+
+ +

Output

+ +

{{ EmbedLiveSample('Example', 500, 450) }}

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS4 Images', '#the-object-fit', 'object-fit')}}{{Spec2('CSS4 Images')}}The from-image and flip keywords have been added.
{{SpecName('CSS3 Images', '#the-object-fit', 'object-fit')}}{{Spec2('CSS3 Images')}}Initial definition
+ +

Browser compatibility

+ +

{{ CompatibilityTable }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support31.0{{ CompatGeckoDesktop("36") }}{{CompatNo}}11.60{{ property_prefix("-o") }}
+ 19.0
{{ CompatVersionUnknown }}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support4.4.4{{ CompatGeckoDesktop("36") }}{{CompatNo}}11.5{{ property_prefix("-o") }}
+ 24
{{ CompatVersionUnknown }}
+
+ +

See also

+ + diff --git a/files/zh-tw/web/css/pseudo-classes/index.html b/files/zh-tw/web/css/pseudo-classes/index.html new file mode 100644 index 0000000000..1a222e59cd --- /dev/null +++ b/files/zh-tw/web/css/pseudo-classes/index.html @@ -0,0 +1,129 @@ +--- +title: 虛擬類別 +slug: Web/CSS/Pseudo-classes +translation_of: Web/CSS/Pseudo-classes +--- +

{{ CSSRef() }}

+ +

CSS 虛擬類別(pseudo-class)的元素,在特殊狀態下被選取的話,會作為關鍵字被加到選擇器裡面。例如 {{ Cssxref(":hover") }} 會讓用戶的滑鼠停在某個元素的時候,套用指定選擇器的樣式。

+ +

虛擬類別與 {{ Cssxref("pseudo-elements") }} 能讓你不只能給文件樹(document tree)本身的相關內容套用樣式,還能給諸如瀏覽歷史({{ cssxref(":visited") }})、內容的狀態({{ cssxref(":checked") }})、還有滑鼠的位置(像 {{ cssxref(":hover") }} 就能讓偵測滑鼠是否在元件上)之類的外部相關因素套用樣式。

+ +

語法

+ +
selector:pseudo-class {
+  property: value;
+}
+
+ +

基本虛擬類別的目錄

+ +
+ +
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態註解
{{ SpecName('Fullscreen') }}{{ Spec2('Fullscreen') }}定義 :fullscreen
{{ SpecName('HTML WHATWG') }}{{ Spec2('HTML WHATWG') }}在 {{ SpecName('HTML5 W3C') }} 並沒有改變。
{{SpecName('CSS4 Selectors')}}{{Spec2('CSS4 Selectors')}}定義 :any-link, :local-link, :scope, :active-drop-target, :valid-drop-target, :invalid-drop-target, :current, :past, :future, :placeholder-shown, :user-error, :blank, :nth-match(), :nth-last-match(), :nth-column(), :nth-last-column(), and :matches().
+ 沒有針對 {{SpecName('CSS3 Selectors')}} 與 {{SpecName('HTML5 W3C')}} 虛擬類別的重大更改(though semantic meaning not taken over)
{{ SpecName('HTML5 W3C') }}{{ Spec2('HTML5 W3C') }}定義以下 HTML context 的語意含義: :link, :visited, :active, :enabled, :disabled, :checked, and :indeterminate.
+ 定義 :default, :valid, :invalid, :in-range, :out-of-range, :required, :optional, :read-only, :read-write, and :dir().
{{ SpecName('CSS3 Basic UI') }}{{ Spec2('CSS3 Basic UI') }}定義 :default, :valid, :invalid, :in-range, :out-of-range, :required, :optional, :read-only, :read-write,但沒有語意含義的定義。
{{SpecName('CSS3 Selectors')}}{{Spec2('CSS3 Selectors')}}定義 :target, :root, :nth-child(), :nth-last-of-child(), :nth-of-type(), :nth-last-of-type(), :last-child, :first-of-type, :last-of-type, :only-child, :only-of-type, :empty, :not().
+ 定義 :enabled, :disabled, :checked, :indeterminate 的語法,但沒有語意含義的定義。
+ 在 {{SpecName('CSS2.1')}} 並沒有明顯改變。
{{SpecName('CSS2.1')}}{{Spec2('CSS2.1')}}定義 :lang(), :first-child, :hover, :focus.
+ 在 {{SpecName('CSS1')}} 並沒有明顯改變。
{{SpecName('CSS1')}}{{Spec2('CSS1')}}定義 :link, :visited, :active,但沒有語意含義的定義。
+ +

參閱

+ + diff --git a/files/zh-tw/web/css/radial-gradient()/index.html b/files/zh-tw/web/css/radial-gradient()/index.html new file mode 100644 index 0000000000..bd054abab3 --- /dev/null +++ b/files/zh-tw/web/css/radial-gradient()/index.html @@ -0,0 +1,183 @@ +--- +title: radial-gradient() +slug: Web/CSS/radial-gradient() +translation_of: Web/CSS/radial-gradient() +--- +
{{CSSRef}}
+ +

CSS radial-gradient() 函數創建了一個圖片,其由一個從原點輻射開的在兩個或者多個顏色之前的漸變組成。這個方法得到的是一個CSS<gradient>數據類型的物件,其是 <image> 的一種。

+ +
{{EmbedInteractiveExample("pages/css/function-radial-gradient.html")}}
+ + + +

As with any gradient, a radial gradient has no intrinsic dimensions; i.e., it has no natural or preferred size, nor a preferred ratio. Its concrete size will match the size of the element it applies to.

+ +

To create a radial gradient that repeats so as to fill its container, use the {{cssxref("repeating-radial-gradient")}} function instead.

+ +

Because <gradient>s belong to the <image> data type, they can only be used where <image>s can be used. For this reason, radial-gradient() won't work on {{Cssxref("background-color")}} and other properties that use the {{cssxref("<color>")}} data type.

+ +

Composition of a radial gradient

+ +

向量漸變(Radial gradients)由其中心點、邊緣形狀輪廓及位置、色值結束點(color stops)定義而成。

+ +

To create a smooth gradient, the radial-gradient() function draws a series of concentric shapes radiating out from the center to the ending shape (and potentially beyond). The ending shape may be either a circle or an ellipse.

+ +

Color-stop points are positioned on a virtual gradient ray that extends horizontally from the center towards the right. Percentage-based color-stop positions are relative to the intersection between the ending shape and this gradient ray, which represents 100%. Each shape is a single color determined by the color on the gradient ray it intersects.

+ +

Syntax

+ +
/* A gradient at the center of its container,
+   starting red, changing to blue, and finishing green */
+radial-gradient(circle at center, red 0, blue, green 100%)
+ +

Values

+ +
+
{{cssxref("<position>")}}
+
The position of the gradient, interpreted in the same way as {{cssxref("background-position")}} or {{cssxref("transform-origin")}}. If unspecified, it defaults to center.
+
<shape>
+
The gradient's shape. The value can be circle (meaning that the gradient's shape is a circle with constant radius) or ellipse (meaning that the shape is an axis-aligned ellipse). If unspecified, it defaults to ellipse.
+
<extent-keyword>
+
A keyword describing how big the ending shape must be. The possible values are: + + + + + + + + + + + + + + + + + + + + + + + + + +
KeywordDescription
closest-sideThe gradient's ending shape meets the side of the box closest to its center (for circles) or meets both the vertical and horizontal sides closest to the center (for ellipses).
closest-cornerThe gradient's ending shape is sized so that it exactly meets the closest corner of the box from its center.
farthest-sideSimilar to closest-side, except the ending shape is sized to meet the side of the box farthest from its center (or vertical and horizontal sides).
farthest-cornerThe default value, the gradient's ending shape is sized so that it exactly meets the farthest corner of the box from its center.
+ +
+

Note: Early implementations of this function included other keywords (cover and contain) as synonyms of the standard farthest-corner and closest-side, respectively. Use the standard keywords only, as some implementations have already dropped those older variants.

+
+
+
<linear-color-stop>
+
A color-stop's {{cssxref("<color>")}} value, followed by an one or two optional stop positions (either a {{cssxref("<percentage>")}} or a {{cssxref("<length>")}} along the gradient's axis). A percentage of 0%, or a length of 0, represents the center of the gradient; the value 100% represents the intersection of the ending shape with the virtual gradient ray. Percentage values in between are linearly positioned on the gradient ray. Including two stop positions is equivalent to declaring two color stops with the same color at the two positions.
+
<color-hint>
+
Th color-hint is an interpolation hint defining how the gradient progresses between adjacent color stops. The length defines at which point between two color stops the gradient color should reach the midpoint of the color transition. If omitted, the midpoint of the color transition is the midpoint between two color stops.
+
+ +

Formal syntax

+ +
radial-gradient(
+  [ [ circle || <length> ]                         [ at <position> ]? , |
+    [ ellipse || [ <length> | <percentage> ]{2} ]  [ at <position> ]? , |
+    [ [ circle | ellipse ] || <extent-keyword> ] [at <position> ]? , |
+    at <position> ,
+  ]?
+  <color-stop-list> [ , <color-stop-list> ]+
+)
+where <extent-keyword> = closest-corner | closest-side | farthest-corner | farthest-side
+   and <color-stop-list> = [ <linear-color-stop> [, <color-hint>? ]? ]#, <linear-color-stop>
+   and <linear-color-stop> = <color> [ <color-stop-length> ]?
+   and <color-stop-length> = [ <percentage> | <length> ]{1,2}
+   and <color-hint> = [ <percentage> | <length> ]
+
+ +
+

Note that negative <length>'s are not allowed, however browsers had implemented negative lengths which are now being removed. See the Firefox site compat note.

+
+ +

Examples

+ +

Simple gradient

+ + + +
.radial-gradient {
+  background-image: radial-gradient(cyan 0%, transparent 20%, salmon 40%);
+} 
+ +

{{EmbedLiveSample('Simple_gradient', 120, 120)}}

+ +

Non-centered gradient

+ + + +
.radial-gradient {
+  background-image: radial-gradient(farthest-corner at 40px 40px,
+      #f35 0%, #43e 100%);
+}
+ +

{{EmbedLiveSample('Non-centered_gradient', 240, 120)}}

+ +
+

Note: Please see Using CSS gradients for more examples.

+
+ +

Specifications

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Images', '#radial-gradients', 'radial-gradients()')}}{{Spec2('CSS3 Images')}}Initial definition.
+ +

Browser compatibility

+ + + +
{{Compat("css.types.image.gradient.radial-gradient")}}
+ +

Quantum CSS notes

+ +

Gecko used to have a long-standing bug whereby radial gradients like radial-gradient(circle gold,red) would work, even though they shouldn't because of the missing comma between circle and gold. Also, {{cssxref("calc")}} expressions were rejected — causing the value to be invalid — when used as the radius component of a radial-gradient() function ({{bug(1376019)}}). Firefox's new parallel CSS engine (also known as Quantum CSS or Stylo, released in Firefox 57) fixed these bugs.

+ +

See also

+ + diff --git a/files/zh-tw/web/css/reference/index.html b/files/zh-tw/web/css/reference/index.html new file mode 100644 index 0000000000..2b2dfc4455 --- /dev/null +++ b/files/zh-tw/web/css/reference/index.html @@ -0,0 +1,211 @@ +--- +title: CSS 參考文件 +slug: Web/CSS/Reference +translation_of: Web/CSS/Reference +--- +

Use this CSS reference to browse an alphabetical index of all the standard CSS properties, pseudo-classes, pseudo-elements, data types, and at-rules. You can also browse a list of all the CSS selectors organized by type and a list of key CSS concepts. Also included is a brief DOM-CSS / CSSOM reference.

+ +

基本語法規則

+ +

Style rule syntax

+ +
selectorlist {
+  property: value;
+  [more property:value; pairs]
+}
+
+... where selectorlist is: selector[:pseudo-class] [::pseudo-element] [, more selectorlists]
+
+See selector, pseudo-class, pseudo-element lists below.
+
+ +

Style rule examples

+ +
strong {
+  color: red;
+}
+
+div.menu-bar li:hover > ul {
+  display: block;
+}
+
+ +

For a beginner-level introduction to the syntax of CSS selectors, please see this tutorial. Be aware that any CSS syntax error in a rule definition invalidates the entire rule. Invalid rules are ignored by the browser. Note that CSS rule definitions are entirely (ASCII) text-based, whereas DOM-CSS / CSSOM (the rule management system) is object-based.

+ +

At-rule syntax

+ +

As the structure of at-rules varies widely, please see At-rule to find the syntax of the specific one you want.

+ +

Keyword index

+ +
+

Note: The property names in this index do not include the JavaScript names where they differ from the CSS standard names.

+
+ +
{{CSS_Ref}}
+ +

Selectors

+ +

Basic selectors

+ + + +

Combinators

+ + + +

Pseudo-classes

+ +
+ +
+ +

Pseudo-elements

+ +
+ +
+ +
+

See also: A complete list of selectors in the Selectors Level 3 specification.

+
+ +

Concepts

+ +

Syntax and semantics

+ + + +

Values

+ + + +

Layout

+ + + +

DOM-CSS / CSSOM

+ +

Major object types

+ + + +

Important methods

+ + + +

See also

+ + diff --git a/files/zh-tw/web/css/replaced_element/index.html b/files/zh-tw/web/css/replaced_element/index.html new file mode 100644 index 0000000000..10e6def514 --- /dev/null +++ b/files/zh-tw/web/css/replaced_element/index.html @@ -0,0 +1,20 @@ +--- +title: 置換元素 (Replaced element) +slug: Web/CSS/Replaced_element +translation_of: Web/CSS/Replaced_element +--- +
{{CSSRef()}}
+ +

摘要

+ +

CSS 中所謂的「置換元素 (Replaced element)」,即是該元素所呈現的內容不在 CSS 的控制範圍之內。這類外部物件所呈現的內容均獨立於 CSS 之外。常見的置換元素包含 {{HTMLElement("img")}}、{{HTMLElement("object")}}、{{HTMLElement("video")}},或如 {{HTMLElement("textarea")}} 與 {{HTMLElement("input")}} 的表單元素。某些元素 (像是 {{HTMLElement("audio")}} 或 {{HTMLElement("canvas")}}) 只有在特殊情況下才是置替換元素。若是透過 CSS {{cssxref("content")}} 屬性所插入的物件,則稱為「不具名置換元素 (Anonymous replaced elements)」。

+ +

在某些情況下,CSS 會特別處理置換元素,如計算邊距空白 (Margin) 與某些 auto 的值。

+ +

另需注意的是,某些置換元素本身就具備固定尺寸 (Intrinsic dimension) 或已定義的基準線 (Baseline),並可由 CSS 的某些屬性 (如 {{cssxref("vertical-align")}}) 所利用。

+ +

另可參閱

+ + diff --git a/files/zh-tw/web/css/ruby-position/index.html b/files/zh-tw/web/css/ruby-position/index.html new file mode 100644 index 0000000000..6caff70d64 --- /dev/null +++ b/files/zh-tw/web/css/ruby-position/index.html @@ -0,0 +1,112 @@ +--- +title: ruby-position +slug: Web/CSS/ruby-position +translation_of: Web/CSS/ruby-position +--- +
{{CSSRef}}{{SeeCompatTable}}
+ +

CSS 的 ruby-position 屬性定義了 ruby 元素與該基礎元素(base element)相關聯的位置。它能在元素上方(over)、下方(under)、兩個字符之間、抑或右方(inter-character)。

+ +
/* 關鍵字值 */
+ruby-position: over;
+ruby-position: under;
+ruby-position: inter-character;
+
+/* 全域值 */
+ruby-position: inherit;
+ruby-position: initial;
+ruby-position: unset;
+
+ +

{{cssinfo}}

+ +

語法

+ +

屬性值

+ +
+
over
+
Over example如果文件以橫式排列,該關鍵字會指引旁註標記(ruby)出現在主文的上方。如果文件以直式排列,則會出現在主文的右方。
+
under
+
Under example如果文件以橫式排列,該關鍵字會指引旁註標記出現在在主文的下方。如果文件以直式排列,則會出現在主文的左方。
+
inter-character
+
該關鍵字會指引旁註標記出現在在主文的兩個字符的中間。
+
+ +

正式語法

+ +
{{csssyntax}}
+ +

示例

+ +

HTML 會因為 ruby-position 的值不同,而作出不同的渲染:

+ +
<ruby>
+  <rb>超電磁砲</rb>
+  <rp>(</rp><rt>レールガン</rt><rp>)</rp>
+</ruby>
+
+ +

旁註標記定位到主文上方

+ + + +
ruby {
+    ruby-position:over;
+}
+ +

它會給出如下結果:

+ +

{{EmbedLiveSample("旁註標記定位到主文上方", 100, 40)}}

+ +

旁註標記定位到主文下方

+ + + +
ruby {
+    ruby-position:under;
+}
+ +

它會給出如下結果:

+ +

{{EmbedLiveSample("旁註標記定位到主文下方", 100, 40)}}

+ +

規範

+ + + + + + + + + + + + + + + + +
規範狀態註解
{{ SpecName('CSS3 Ruby', '#rubypos', 'ruby-position') }}{{ Spec2('CSS3 Ruby') }}初始定義
+ +

瀏覽器相容性

+ + + +

{{Compat("css.properties.ruby-position")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/css/shorthand_properties/index.html b/files/zh-tw/web/css/shorthand_properties/index.html new file mode 100644 index 0000000000..2e880da57e --- /dev/null +++ b/files/zh-tw/web/css/shorthand_properties/index.html @@ -0,0 +1,138 @@ +--- +title: 特性簡寫 +slug: Web/CSS/Shorthand_properties +translation_of: Web/CSS/Shorthand_properties +--- +

定義

+ +

特性簡寫,是一種可以同時設定許多其他 CSS 屬性值的 CSS 屬性。 使用特性簡寫,網頁開發者可以寫出更簡潔、且通常更具可讀性的樣式表,省時又省力。

+ +

CSS 規範中定義,特性簡寫用來組合作用於相同主題的常見性質。舉例來說,CSS {{cssxref("background")}} 這個性質是個特性簡寫,可同時定義 {{cssxref("background-color")}}, {{cssxref("background-image")}}, {{cssxref("background-repeat")}}, 和 {{cssxref("background-position")}} 等屬性。同樣的,最常用的字體相關屬性,可以使用 {{cssxref("font")}} 來定義;圍繞在方塊周圍的邊界,則可簡單地以 {{cssxref("margin")}} 簡寫來定義。

+ +

需謹慎之處

+ +

即便特性簡寫非常易於使用,仍有幾個需要銘記在心的情況:

+ +
    +
  1. 未指明的值會被設為預設值。這聽起來真的很怪,但他的確會覆寫先前的設定值。比如: + +
    background-color: red;
    +background: url(images/bg.gif) no-repeat top right;
    + 不會將背景設為紅色,而是使用 {{cssxref("background-color")}} 的預設值 transparent,由於較後面的規則為優先。
  2. +
  3. 只有獨立的屬性可以被繼承。就如同遺失的值會被預設值取代一樣,不可能讓缺漏的值再去繼承個別屬性。關鍵字 inherit 可以用於屬性,但只能整體繼承,而不能用於個別值上。意思是,如果要繼承某個特定的值,就必須使用完整的語句,搭配 inherit 關鍵字
  4. +
  5. 簡寫屬性試著不強迫使用特定順序,在那些屬性有許多不同類型的值的狀況下的確很方便。但是在許多屬性具有類似值時就沒這麼簡單了,此時會以以下規則處理: +
      +
    1. 關於區塊的簡寫性質,諸如 {{cssxref("border-style")}}, {{cssxref("margin")}} 或 {{cssxref("padding")}},就會使用連貫的1~4個值來定義下列這些邊: + + + + + + + + + + + + + + + + + + + +
      border1.png單值語法:border-width: 1em — 這個唯一的值定義所有四邊
      border2.png雙值語法:border-width: 1em 2em — 第一個值代表垂直部分,也就是上和下邊;第二個值則是指水平部分,也就是左右邊。
      border3.png三值語法:border-width: 1em 2em 3em — 第一個值代表上邊,第二個值代表兩旁的邊,而第三個值代表下邊。
      border4.png +

      四值語法:border-width: 1em 2em 3em 4em — 這四個值分別代表上、右、下、左邊,順時針的方向由上開始排列(可以以 trouble 來記憶,即英文首文字的縮寫 TRBL)

      +
      +
    2. +
    3. 與之相似地,關於區塊角落的屬性,像是 {{cssxref("border-radius")}},也會使用連貫的1~4個值來代表四個角落: + + + + + + + + + + + + + + + + + + + +
      corner1.png單值語法:border-radius: 1em — 這唯一的值代表了所有角落。
      corner2.png雙值語法:border-radius: 1em 2em — 第一個值代表左上和右下,第二個值則是右上及左下角。
      corner3.png三值語法:border-radius: 1em 2em 3em — 第一個值代表左上,第二個值代表右上及左下,第三個值則是右下的角落。
      corner4.png +

      四值語法:border-radius: 1em 2em 3em 4em — 這四個值分別代表左上、右上、右下、左下,由左上開始的順時針排序。

      +
      +
    4. +
    +
  6. +
+ +

背景屬性

+ +

背景會有下列這些屬性:

+ +
background-color: #000;
+background-image: url(images/bg.gif);
+background-repeat: no-repeat;
+background-position: top right;
+ +

可以簡寫為一句宣告:

+ +
background: #000 url(images/bg.gif) no-repeat top right;
+ +

(寫成簡化屬性的效果,完全等同於上方未簡化的屬性,外加 background-attachment: scroll 及其他 CSS3 中額外增加的屬性。)

+ +

字體屬性

+ +

下列的宣告:

+ +
font-style: italic;
+font-weight: bold;
+font-size: .8em;
+line-height: 1.2;
+font-family: Arial, sans-serif;
+ +

可以簡寫成這樣:

+ +
font: italic bold .8em/1.2 Arial, sans-serif;
+ +

簡化定義的效果完全等同於未簡化前的屬性效果,加上 font-variant: normalfont-size-adjust: none (CSS2.0 / CSS3) 及 font-stretch: normal (CSS3) 等屬性。

+ +

邊框屬性

+ +

邊框的寬度、顏色、樣式可以簡寫成一句宣告。舉例來說:

+ +
border-width: 1px;
+border-style: solid;
+border-color: #000;
+ +

可以寫成:

+ +
border: 1px solid #000;
+ +

邊界與內距屬性

+ +

margin 和 padding 的簡化版本大致相同。下列的 CSS 宣告:

+ +
margin-top: 10px;
+margin-right: 5px;
+margin-bottom: 10px;
+margin-left: 5px;
+ +

等同於下面的宣告(注意值的排序是順時鐘的順序:上,右,下,左 (TRBL,可以「trouble」這個單字的諧音來記憶)

+ +
margin: 10px 5px 10px 5px;
+ +

相關連結

+ + diff --git a/files/zh-tw/web/css/syntax/index.html b/files/zh-tw/web/css/syntax/index.html new file mode 100644 index 0000000000..c777095cb0 --- /dev/null +++ b/files/zh-tw/web/css/syntax/index.html @@ -0,0 +1,74 @@ +--- +title: 語法 +slug: Web/CSS/Syntax +translation_of: Web/CSS/Syntax +--- +
{{cssref}}
+ +

串接式樣式表 (CSS) 語言的基礎目標是是讓瀏覽器引擎用特定的功能將元素寫在頁面上,像是顏色、位置與裝飾。CSS 語法反映出了目的,而它的基本組成為:

+ + + +

CSS 宣告

+ +

設定特定參數值給 CSS 屬性是 CSS 語言的核心功能。一對屬性與參數叫做宣告,而為了適當的排版與套用樣式,任何 CSS 引擎會演算每個頁面上的元素該套用哪個宣告。

+ +

在 CSS 中屬性與參數都預設為不區分大小寫。它們由冒號區隔,':' (U+003A COLON),而在屬性與參數前、中間與後面並不需要有空白,空白會被忽略。

+ +

css syntax - declaration.png

+ +

在 CSS 中有超過100種不同的屬性與接近無限個不同的參數。並非所有的屬性與參數組都是被准許的,且每個屬性定義了哪些是有效的參數。當一個參數對屬性無效的時候,宣告會被認為是無效的且會完全被 CSS 引擎忽略。

+ +

CSS 宣告區塊

+ +

Declarations are grouped in blocks, that is in a structure delimited by an opening brace, '{' (U+007B LEFT CURLY BRACKET), and a closing one, '}' (U+007D RIGHT CURLY BRACKET). Blocks sometimes can be nested, so opening and closing braces must be matched.

+ +

css syntax - block.png

+ +

Such blocks are naturally called declaration blocks and declarations inside them are separated by a semi-colon, ';' (U+003B SEMICOLON). A declaration block may be empty, that is containing null declaration. White spaces around declarations are ignored. The last declaration of a block doesn't need to be terminated by a semi-colon, though it is often considered good style to do it as it prevents forgetting to add it when extending the block with another declaration.

+ +

css syntax - declarations block.png

+ +
The content of a CSS declaration block, that is a list of semi-colon-separated declarations, without the initial and closing braces, can be put inside an HTML {{htmlattrxref("style")}} attribute.
+ +

CSS rulesets

+ +

If style sheets could only apply a declaration to each element of a Web page, they would be pretty useless. The real goal is to apply different declarations to different parts of the document.

+ +

CSS allows this by associating conditions with declarations blocks. Each (valid) declaration block is preceded by one or more comma-separated selectors which are conditions selecting some elements of the page. The pair selector group-declarations block is called a ruleset, or often simply a rule.

+ +

css syntax - ruleset.png

+ +

As an element of the page may be matched by several selectors, and therefore by several rules potentially containing a given property several times, with different values, the CSS standard defines which one has precedence over the other and must be applied: this is called the cascade algorithm.

+ +
It is important to note that even if a ruleset characterized by a group of selectors is a kind of shorthand replacing rulesets with a single selector each, this doesn't apply to the validity of the ruleset itself.
+
+This leads to an important consequence: if one single basic selector is invalid, like when using an unknown pseudo-element or pseudo-class, the whole selector is invalid and therefore the entire rule is ignored (as invalid too).
+ +

CSS statements

+ +

Rulesets are the main building blocks of a style sheet, which often consists of only a big list of them. But there is other information that a Web author wants to convey in the style sheet, like the character set, other external style sheets to import, font face or list counter descriptions and many more. It will use other and specific kinds of statements to do that.

+ +

A statement is a building block that begins with any non-space characters and ends at the first closing brace or semi-colon (outside a string, non-escaped and not included into another {}, () or [] pair).

+ +

css syntax - statements Venn diag.png

+ +

There are two kinds of statements:

+ + + +

Any statement which isn't a ruleset or an at-rule is invalid and ignored.

+ +

There is another group of statements – the nested statements. These are statements that can be used in a specific subset of at-rules – the conditional group rules. These statements only apply if a specific condition is matched: the @media at-rule content is applied only if the device on which the browser runs matches the expressed condition; the @document at-rule content is applied only if the current page matches some conditions, and so on. In CSS1 and CSS2.1, only rulesets could be used inside conditional group rules. That was very restrictive and this restriction was lifted in CSS Conditionals Level 3. Now, though still experimental and not supported by every browser, conditional group rules can contain a wider range of content: rulesets but also some, but not all, at-rules.

+ +

See also

+ + diff --git a/files/zh-tw/web/css/transform-function/index.html b/files/zh-tw/web/css/transform-function/index.html new file mode 100644 index 0000000000..73b08839ed --- /dev/null +++ b/files/zh-tw/web/css/transform-function/index.html @@ -0,0 +1,894 @@ +--- +title: transform-function +slug: Web/CSS/transform-function +translation_of: Web/CSS/transform-function +--- +

{{ CSSRef("CSS Transforms") }}The <transform-function> CSS data type denotes a function applied to an element's representation in order to modify it. Usually such transform may be expressed by matrices and the resulting images can be determined using matrix multiplication on each point.

+ +

Coordinates for 2D graphics

+ +

There are several coordinate models used when describing transformation. The most common are the Cartesian coordinate system and homogeneous coordinates.

+ +

笛卡兒坐標系

+ +

+ +

In Cartesian coordinates each point of the Euclidian space is described using two values, the abscissa and the ordinate. The origin, the (0, 0) is the top-left corner of the element. Unlike the usual geometric convention, and like most cases in computer graphics, the y-axis goes to the bottom. Each point is mathematically described using the vector notation (x,y).

+ +

Each linear function is described using a 2x2 matrix like:

+ +
+

ac bd

+
+ +

Applying the transformation consists in doing, for each point, the matrix multiplication between both:

+ +
.
+ +

It is possible to apply several transformations in a row:

+ +
.
+ +

With this notation, it is possible to describe, and therefore composite, most usual transformations: rotations, scaling, or skewing. In fact all transformations that are linear functions can be described. One major transformation is not linear and therefore must be special-cased when using this notation: translation. The translation vector (tx, ty) must be expressed separately, as two more parameters.

+ +

Möbius' homogeneous coordinates in projective geometry leading to 3x3 transformation matrices, though more complex and unusual for non-specialists, doesn't suffer from the translation limitation as these can be expressed as linear functions in this algebra, removing the need for special cases.

+ +

Coordinates for 3D graphics

+ +

Functions defining transformations

+ +

matrix()

+ +

The matrix() CSS function specifies a homogeneous 2D transformation matrix comprised of the specified six values. The constant values of such matrices are implied and not passed as parameters; the other parameters are described in the column-major order.

+ +

matrix(a, b, c, d, tx, ty) is a shorthand for matrix3d(a, b, 0, 0, c, d, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1).

+ +
Note: Until Firefox 16, Gecko accepted a {{cssxref("<length>")}} value for tx and ty.
+ +

表達式

+ +
matrix(a, b, c, d, tx, ty)
+
+ +

+ +
+
a b c d
+
Are {{cssxref("<number>")}} describing the linear transformation.
+
tx ty
+
Are {{cssxref("<number>")}} describing the translation to apply.
+
+ + + + + + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
ac bd actybdtx001 actybdtx001 ac0txbd0ty00100001
[a b c d tx ty]
+ +

matrix3d()

+ +

The matrix3d() CSS function describes a 3D transform as a 4x4 homogeneous matrix. The 16 parameters are described in the column-major order.

+ +
Note: Until Firefox 16, Gecko accepted a {{cssxref("<length>")}} value for a4, b4 and c4.
+ +

表達式

+ +
matrix3d(a1, b1, c1, d1, a2, b2, c2, d2, a3, b3, c3, d3, a4, b4, c4, d4)
+ +

+ +
+
a1 b1 c1 d1 a2 b2 c2 d2 a3 b3 c3 d3 d4
+
Are {{cssxref("<number>")}} describing the linear transformation.
+
a4 b4 c4
+
Are {{cssxref("<number>")}} describing the translation to apply.
+
+ + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
This transform applies to the 3D space and cannot be represented on the plan.Cartesian-coordinate matrix doesn't allow to represent a generic 3d affine transforms as translations are not linear transforms.a1a2a3a4b1b2b3b4c1c2c3c4d1d2d3d4
+ +

perspective()

+ +

The perspective() CSS function defines the distance between the z=0 plane and the user in order to give to the 3D-positioned element some perspective. Each 3D element with z>0 becomes larger; each 3D-element with z<0 becomes smaller. The strength of the effect is determined by the value of this property.

+ +

表達式

+ +
perspective(l)
+
+ +

+ +
+
l
+
Is a {{cssxref("<length>")}} giving the distance from the user to the z=0 plane. It is used to apply a perspective transform to the element. If it is 0 or a negative value, no perspective transform is applied.
+
+ + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
+

This transform applies to the 3D space and cannot be represented on the plan.

+
A perspective is not a linear transform in ℝ3 and cannot be represented using a matrix in the Cartesian coordinates system. 100001000010001/d1
+ +

rotate()

+ +

The rotate() CSS function defines a transformation that moves the element around a fixed point (as specified by the {{ Cssxref("transform-origin") }} property) without deforming it. The amount of movement is defined by the specified angle; if positive, the movement will be clockwise, if negative, it will be counter-clockwise. A rotation by 180° is called point reflection.

+ +

表達式

+ +
rotate(a)
+
+ +

+ +
+
a
+
Is an {{ cssxref("<angle>") }} representing the angle of the rotation. A positive angle denotes a clockwise rotation, a negative angle a counter-clockwise one.
+
+ + + + + + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
cos(a)-sin(a) sin(a)cos(a) cos(a)-sin(a)0sin(a)cos(a)0001 cos(a)-sin(a)0sin(a)cos(a)0001 cos(a)-sin(a)00sin(a)cos(a)0000100001
[cos(a) sin(a) -sin(a) cos(a) 0 0]
+ +

rotate3d()

+ +

The rotate3d()CSS function defines a transformation that moves the element around a fixed axis without deforming it. The amount of movement is defined by the specified angle; if positive, the movement will be clockwise, if negative, it will be counter-clockwise.

+ +

In the 3D space, rotations have three degrees of liberty, describing an axis of rotation. The axis of rotation is defined by an [x, y, z] vector and pass by the origin (as defined by the {{ cssxref("transform-origin") }} CSS property. If the vector is not normalized, that is the sum of the square of its three coordinates is not 1, it will be normalized internally. A non-normalizable vector, like the null vector, [0, 0, 0], will cause the rotation not to be applied, without invaliding the whole CSS property.

+ +
In opposition to rotations in the plane, the composition of 3D rotations is usually not commutative; it means that the order in which the rotations are applied is crucial.
+ +

表達式

+ +
rotate3d(x, y, z, a)
+
+ +

+ +
+
x
+
Is a {{cssxref("<number>")}} describing the x-coordinate of the vector denoting the axis of rotation.
+
y
+
Is a {{cssxref("<number>")}} describing the y-coordinate of the vector denoting the axis of rotation.
+
z
+
Is a {{cssxref("<number>")}} describing the z-coordinate of the vector denoting the axis of rotation.
+
a
+
Is an {{ cssxref("<angle>") }} representing the angle of the rotation. A positive angle denotes a clockwise rotation, a negative angle a counter-clockwise one.
+
+ + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
This transform applies to the 3D space and cannot be represented on the plane. 1+(1-cos(a))(x2-1)z·sin(a)+xy(1-cos(a))-y·sin(a)+xz·(1-cos(a))-z·sin(a)+xy·(1-cos(a))1+(1-cos(a))(y2-1)x·sin(a)+yz·(1-cos(a))ysin(a) + xz(1-cos(a))-xsin(a)+yz(1-cos(a))1+(1-cos(a))(z2-1)t0001
+ +

rotateX()

+ +

The rotateX()CSS function defines a transformation that moves the element around the abscissa without deforming it. The amount of movement is defined by the specified angle; if positive, the movement will be clockwise, if negative, it will be counter-clockwise.

+ +

The axis of rotation passes by the origin, defined by {{ cssxref("transform-origin") }} CSS property.

+ +

rotateX(a)is a shorthand for rotate3D(1, 0, 0, a).

+ +
In opposition to rotations in the plane, the composition of 3D rotations is usually not commutative; it means that the order in which the rotations are applied is crucial.
+ +

表達式

+ +
rotateX(a)
+
+ +

+ +
+
a
+
Is an {{ cssxref("<angle>") }} representing the angle of the rotation. A positive angle denotes a clockwise rotation, a negative angle a counter-clockwise one.
+
+ + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
This transform applies to the 3D space and cannot be represented on the plane. 1000cos(a)-sin(a)0sin(a)cos(a) 10000cos(a)-sin(a)00sin(a)cos(a)00001
+ +

rotateY()

+ +

The rotateY()CSS function defines a transformation that moves the element around the ordinate without deforming it. The amount of movement is defined by the specified angle; if positive, the movement will be clockwise, if negative, it will be counter-clockwise.

+ +

The axis of rotation passes by the origin, defined by {{ cssxref("transform-origin") }} CSS property.

+ +

rotateY(a)is a shorthand for rotate3D(0, 1, 0, a).

+ +
In opposition to rotations in the plane, the composition of 3D rotations is usually not commutative; it means that the order in which the rotations are applied is crucial.
+ +

表達式

+ +
rotateY(a)
+
+ +

+ +
+
a
+
Is an {{ cssxref("<angle>") }} representing the angle of the rotation. A positive angle denotes a clockwise rotation, a negative angle a counter-clockwise one.
+
+ + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
This transform applies to the 3D space and cannot be represented on the plane. cos(a)0sin(a)010-sin(a)0cos(a) cos(a)0sin(a)00100-sin(a)0cos(a)00001
+ +

rotateZ()

+ +

The rotateZ()CSS function defines a transformation that moves the element around the z-axis without deforming it. The amount of movement is defined by the specified angle; if positive, the movement will be clockwise, if negative, it will be counter-clockwise.

+ +

The axis of rotation passes by the origin, defined by {{ cssxref("transform-origin") }} CSS property.

+ +

rotateZ(a)is a shorthand for rotate3D(0, 0, 1, a).

+ +
In opposition to rotations in the plane, the composition of 3D rotations is usually not commutative; it means that the order in which the rotations are applied is crucial.
+ +

表達式

+ +
rotateZ(a)
+
+ +

+ +
+
a
+
Is an {{ cssxref("<angle>") }} representing the angle of the rotation. A positive angle denotes a clockwise rotation, a negative angle a counter-clockwise one.
+
+ + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
This transform applies to the 3D space and cannot be represented on the plane. cos(a)-sin(a)0sin(a)cos(a)0001 cos(a)-sin(a)00sin(a)cos(a)0000000001
+ +

scale()

+ +

+ +

The scale() CSS function modifies the size of the element. It can either augment or decrease its size and as the amount of scaling is defined by a vector, it can do so more in one direction than in another one.

+ +

This transformation is characterized by a vector whose coordinates define how much scaling is done in each direction. If both coordinates of the vector are equal, the scaling is uniform, or isotropic, and the shape of the element is preserved. In that case, the scaling function defines a homothetic transformation.

+ +

When outside the ]-1, 1[ range, the scaling enlarges the element in the direction of the coordinate; when inside the range, it shrinks the element in that direction. When equal to 1 it does nothing and when negative it performs a point reflection and the size modification.

+ +
The scale() function only applies the transformation in the Euclidian plane (in 2D). To scale in the space, the scale3D() function has to be used.
+ +

表達式

+ +
scale(sx) or
+scale(sx, sy)
+
+ +

+ +
+
sx
+
Is a {{cssxref("<number>")}} representing the abscissa of the scaling vector.
+
sy
+
Is a {{cssxref("<number>")}} representing the ordinate of the scaling vector. If not present, its default value is sx, leading to a uniform scaling preserving the shape of the element.
+
+ + + + + + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
sx0 0sy sx000sy0001 sx000sy0001 sx0000sy0000100001
[sx 0 0 sy 0 0]
+ +

scale3d()

+ +

The scale3d() CSS function modifies the size of an element. Because the amount of scaling is defined by a vector, it can resize different dimensions at different scales.

+ +

This transformation is characterized by a vector whose coordinates define how much scaling is done in each direction. If all three coordinates of the vector are equal, the scaling is uniform, or isotropic, and the shape of the element is preserved. In that case, the scaling function defines a homothetic transformation.

+ +

When outside the [-1, 1] range, the scaling enlarges the element in the direction of the coordinate; when inside the range, it shrinks the element in that direction. When equal to 1 it does nothing and when negative it performs a point reflection and the size modification.

+ +

表達式

+ +
scale3d(sx, sy, sz)
+
+ +

+ +
+
sx
+
Is a {{cssxref("<number>")}} representing the abscissa of the scaling vector.
+
sy
+
Is a {{cssxref("<number>")}} representing the ordinate of the scaling vector.
+
sz
+
Is a {{cssxref("<number>")}} representing the z-component of the scaling vector.
+
+ + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
This transform applies to the 3D space and cannot be represented on the plane. sx000sy000sz sx0000sy0000sz00001
+ +

scaleX()

+ +

The scaleX() CSS function modifies the abscissa of each element point by a constant factor, except if this scale factor is 1, in which case the function is the identity transform. The scaling is not isotropic and the angles of the element are not conserved.

+ +

scaleX(sx) is a shorthand for scale(sx, 1) or for scale3d(sx, 1, 1).

+ +

scaleX(-1) defines an axial symmetry with a vertical axis passing by the origin (as specified by the transform-origin property).

+ +

表達式

+ +
scaleX(s)
+
+ +

+ +
+
s
+
Is a {{cssxref("<number>")}} representing the scaling factor to apply on the abscissa of each point of the element.
+
+ + + + + + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
s0 01 s00010001 s00010001 s000010000100001
[s 0 0 1 0 0]
+ +

scaleY()

+ +

+ +

The scaleY() CSS function modifies the ordinate of each element point by a constant factor except if this scale factor is 1, in which case the function is the identity transform. The scaling is not isotropic and the angles of the element are not conserved.

+ +

scaleY(sy) is a shorthand for scale(1, sy) or for scale3d(1, sy, 1).

+ +

scaleY(-1) defines an axial symmetry with a horizontal axis passing by the origin (as specified by the transform-origin property).

+ +

表達式

+ +
scaleY(s)
+
+ +

+ +
+
s
+
Is a {{cssxref("<number>")}} representing the scaling factor to apply on the ordinate of each point of the element.
+
+ + + + + + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
10 0s 1000s0001 1000s0001 10000s0000100001
[1 0 0 s 0 0]
+ +

scaleZ()

+ +

The scaleZ() CSS function modifies the z-coordinate of each element point by a constant factor, except if this scale factor is 1, in which case the function is the identity transform. The scaling is not isotropic and the angles of the element are not conserved.

+ +

scaleZ(sz) is a shorthand for scale3d(1, 1, sz).

+ +

scaleZ(-1) defines an axial symmetry along the z-axis passing by the origin (as specified by the transform-origin property).

+ +

表達式

+ +
scaleZ(s)
+
+ +

+ +
+
s
+
Is a {{cssxref("<number>")}} representing the scaling factor to apply on the z-coordinate of each point of the element.
+
+ + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
This transform applies to the 3D space and cannot be represented on the plane. 10001000s 1000010000s00001
+ +

skew()

+ +

The skew() CSS function is a shear mapping, or transvection, distorting each point of an element by a certain angle in each direction. It is done by increasing each coordinate by a value proportionate to the specified angle and to the distance to the origin. The more far from the origin, the more away the point is, the greater will be the value added to it.

+ +

表達式

+ +
skew(ax)       or
+skew(ax, ay)
+
+ +

+ +
+
ax
+
Is an {{ cssxref("<angle>") }} representing the angle to use to distort the element along the abscissa.
+
ay
+
Is an {{ cssxref("<angle>") }} representing the angle to use to distort the element along the ordinate.
+
+ + + + + + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
1tan(ax)tan(ay)1 1tan(ax)0tan(ay)10001 1tan(ax)0tan(ay)10001 1tan(ax)00tan(ay)10000100001
[1 tan(ay) tan(ax) 1 0 0]
+ +

skewX()

+ +

The skewX() CSS function is a horizontal shear mapping distorting each point of an element by a certain angle in the horizontal direction. It is done by increasing the abscissa coordinate by a value proportionate to the specified angle and to the distance to the origin. The more far from the origin, the more away the point is, the greater will be the value added to it.

+ +

表達式

+ +
skewX(a)
+
+ +

+ +
+
a
+
Is an {{ cssxref("<angle>") }} representing the angle to use to distort the element along the abscissa.
+
+ + + + + + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
1tan(ay)01 1tan(ay)0010001 1tan(ay)0010001 1tan(ay)00010000100001
[1 0 tan(a) 1 0 0]
+ +

skewY()

+ +

The skewY() CSS function is a vertical shear mapping distorting each point of an element by a certain angle in the vertical direction. It is done by increasing the ordinate coordinate by a value proportionate to the specified angle and to the distance to the origin. The more far from the origin, the more away the point is, the greater will be the value added to it.

+ +

表達式

+ +
skewY(a)
+
+ +

+ +
+
a
+
Is an {{ cssxref("<angle>") }} representing the angle to use to distort the element along the ordinate.
+
+ + + + + + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
10tan(ax)1 100tan(ax)10001 100tan(ax)10001 1000tan(ax)10000100001
[1 tan(a) 0 1 0 0]
+ +

translate()

+ +

The translate() CSS function moves the position of the element on the plane. This transformation is characterized by a vector whose coordinates define how much it moves in each direction.

+ +

Syntax

+ +
translate(tx)       or
+translate(tx, ty)
+
+ +

+ +
+
tx
+
Is a {{cssxref("<length>")}} representing the abscissa of the translating vector.
+
ty
+
Is a {{cssxref("<length>")}} representing the ordinate of the translating vector. If missing, it is assumed to be equals to txtranslate(2) means translate(2, 2).
+
+ + + + + + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
+

A translation is not a linear transform in ℝ2 and cannot be represented using a matrix in the cartesian coordinates system.

+
10tx01ty001 10tx01ty001 100tx010ty00100001
[1 0 0 1 tx ty]
+ +

translate3d()

+ +

The translate3d() CSS function moves the position of the element in the 3D space. This transformation is characterized by a 3-dimension vector whose coordinates define how much it moves in each direction.

+ +

表達式

+ +
translate3d(tx, ty, tz)
+
+ +

+ +
+
tx
+
Is a {{cssxref("<length>")}} representing the abscissa of the translating vector.
+
ty
+
Is a {{cssxref("<length>")}} representing the ordinate of the translating vector.
+
tz
+
Is a {{cssxref("<length>")}} representing the z component of the translating vector. It can't be a {{cssxref("<percentage>")}} value; in that case the property containing the transform is considered invalid.
+
+ + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
+

This transform applies to the 3D space and cannot be represented on the plane.

+
A translation is not a linear transform in ℝ3 and cannot be represented using a matrix in the Cartesian coordinates system. 100tx010ty001tz0001
+ +

translateX()

+ +

The translateX() CSS function moves the element horizontally on the plane. This transformation is characterized by a {{cssxref("<length>")}} defining how much it moves horizontally.

+ +

translateX(tx) is a shortcut for translate(tx, 0).

+ +

表達式

+ +
translateX(t)
+
+ +

+ +
+
t
+
Is a {{cssxref("<length>")}} representing the abscissa of the translating vector.
+
+ + + + + + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
+

A translation is not a linear transform in ℝ2 and cannot be represented using a matrix in the cartesian coordinates system.

+
10t010001 10t010001 100t010000100001
[1 0 0 1 t 0]
+ +

translateY()

+ +

The translateY() CSS function moves the element vertically on the plane. This transformation is characterized by a {{cssxref("<length>")}} defining how much it moves vertically.

+ +

translateY(ty) is a shortcut for translate(0, ty).

+ +

Syntax

+ +
translateY(t)
+
+ +

+ +
+
t
+
Is a {{cssxref("<length>")}} representing the ordinate of the translating vector.
+
+ + + + + + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
+

A translation is not a linear transform in ℝ2 and cannot be represented using a matrix in the cartesian coordinates system.

+
10001t001 10001t001 1000010t00100001
[1 0 0 1 0 t]
+ +

translateZ()

+ +

The translateZ() CSS function moves the element along the z-axis of the 3D space. This transformation is characterized by a {{cssxref("<length>")}} defining how much it moves.

+ +

translateZ(tz) is a shorthand for translate3d(0, 0, tz).

+ +

表達式

+ +
translateZ(t)
+
+ +

+ +
+
t
+
Is a {{cssxref("<length>")}} representing the z-component of the translating vector. It can't be a {{cssxref("<percentage>")}} value; in that case the property containing the transform is considered invalid.
+
+ + + + + + + + + + + + + + + + + +
Cartesian coordinates on ℝ2Homogeneous coordinates on ℝℙ2Cartesian coordinates on ℝ3Homogeneous coordinates on ℝℙ3
This transform applies to the 3D space and cannot be represented on the plane.A translation is not a linear transform in ℝ3 and cannot be represented using a matrix in the Cartesian coordinates system. 10000100001t0001
+ +

 

diff --git a/files/zh-tw/web/css/transform-function/translate3d()/index.html b/files/zh-tw/web/css/transform-function/translate3d()/index.html new file mode 100644 index 0000000000..149980d71d --- /dev/null +++ b/files/zh-tw/web/css/transform-function/translate3d()/index.html @@ -0,0 +1,116 @@ +--- +title: translate3d() +slug: Web/CSS/transform-function/translate3d() +translation_of: Web/CSS/transform-function/translate3d() +--- +
{{CSSRef}}
+ +

translate3d() CSS 函式以 3D 場境的方式定位元素。其結果為 {{cssxref("<transform-function>")}} 資料型別。

+ +
{{EmbedInteractiveExample("pages/css/function-translate3d.html")}}
+ + + +

這個轉場的特徵是三維向量,其坐標則定義元素的方向該如何移動。

+ +

語法

+ +
translate3d(tx, ty, tz)
+
+ +

數值

+ +
+
tx
+
其 {{cssxref("<length>")}} 代表平移向量的橫坐標。
+
ty
+
其 {{cssxref("<length>")}} 代表平移向量的縱坐標。
+
tz
+
其 {{cssxref("<length>")}} 代表平移向量的 z 分量。數值不能是 {{cssxref("<percentage>")}}:否則,此轉場的屬性無效。
+
+ + + + + + + + + + + + + + + + + +
2 上的笛卡兒座標(Cartesian coordinate)ℝℙ2 上的齊次坐標(homogeneous coordinates)3 上的笛卡兒座標ℝℙ3 上的齊次坐標
+

This transformation applies to the 3D space and can't be represented on the plane.

+
A translation is not a linear transformation in ℝ3 and can't be represented using a Cartesian-coordinate matrix. 100tx010ty001tz0001
+ +

示例

+ +

使用單軸平移

+ +

HTML

+ +
<div>Static</div>
+<div class="moved">Moved</div>
+<div>Static</div>
+ +

CSS

+ +
div {
+  width: 60px;
+  height: 60px;
+  background-color: skyblue;
+}
+
+.moved {
+  /* Equivalent to perspective(500px) translateX(10px) */
+  transform: perspective(500px) translate3d(10px, 0, 0px);
+  background-color: pink;
+}
+
+ +

結果

+ +

{{EmbedLiveSample("Using_a_single_axis_translation", 250, 250)}}

+ +

Combining z-axis and x-axis translation

+ +

HTML

+ +
<div>Static</div>
+<div class="moved">Moved</div>
+<div>Static</div>
+ +

CSS

+ +
div {
+  width: 60px;
+  height: 60px;
+  background-color: skyblue;
+}
+
+.moved {
+  transform: perspective(500px) translate3d(10px, 0, 100px);
+  background-color: pink;
+}
+
+ +

結果

+ +

{{EmbedLiveSample("Combining_z-axis_and_x-axis_translation", 250, 250)}}

+ +

瀏覽器相容性

+ +

請參見 <transform-function>

+ +

參見

+ + diff --git a/files/zh-tw/web/css/transform-origin/index.html b/files/zh-tw/web/css/transform-origin/index.html new file mode 100644 index 0000000000..2cfccb1716 --- /dev/null +++ b/files/zh-tw/web/css/transform-origin/index.html @@ -0,0 +1,455 @@ +--- +title: transform-origin +slug: Web/CSS/transform-origin +tags: + - CSS +translation_of: Web/CSS/transform-origin +--- +
{{ CSSRef }}
+ +

CSS 內的transform-origin屬性可以設定元素變化的原點。

+ +
{{EmbedInteractiveExample("pages/css/transform-origin.html")}}
+ + + +

變化原點指的是應用變化的點。舉例來說, rotate()函數的原點為旋轉中心。 (This property is applied by first translating the element by the negated value of the property, then applying the element's transform, then translating by the property value.)

+ +

語法

+ +
/* One-value syntax */
+transform-origin: 2px;
+transform-origin: bottom;
+
+/* x-offset | y-offset */
+transform-origin: 3cm 2px;
+
+/* x-offset-keyword | y-offset */
+transform-origin: left 2px;
+
+/* x-offset-keyword | y-offset-keyword */
+transform-origin: right top;
+
+/* y-offset-keyword | x-offset-keyword */
+transform-origin: top right;
+
+/* x-offset | y-offset | z-offset */
+transform-origin: 2px 30% 10px;
+
+/* x-offset-keyword | y-offset | z-offset */
+transform-origin: left 5px -3px;
+
+/* x-offset-keyword | y-offset-keyword | z-offset */
+transform-origin: right bottom 2cm;
+
+/* y-offset-keyword | x-offset-keyword | z-offset */
+transform-origin: bottom right 2cm;
+
+/* Global values */
+transform-origin: inherit;
+transform-origin: initial;
+transform-origin: unset;
+
+ +

The transform-origin p屬性可以使用多次,每一次都代表著一個偏移量。若未設定偏移量,則重置為其對應的 初始值

+ +

If two or more values are defined and either no value is a keyword, or the only used keyword is center, then the first value represents the horizontal offset and the second represents the vertical offset.

+ + + +

Values

+ +
+
x-offset
+
Is a {{cssxref("<length>")}} or a {{cssxref("<percentage>")}} describing how far from the left edge of the box the origin of the transform is set.
+
offset-keyword
+
Is one of the left, right, top, bottom, or center keyword describing the corresponding offset.
+
y-offset
+
Is a {{cssxref("<length>")}} or a {{cssxref("<percentage>")}} describing how far from the top edge of the box the origin of the transform is set.
+
x-offset-keyword
+
Is one of the left, right, or center keyword describing how far from the left edge of the box the origin of the transform is set.
+
y-offset-keyword
+
Is one of the top, bottom, or center keyword describing how far from the top edge of the box the origin of the transform is set.
+
z-offset
+
Is a {{cssxref("<length>")}} (and never a {{cssxref("<percentage>")}} which would make the statement invalid) describing how far from the user eye the z=0 origin is set.
+
+ +

The keywords are convenience shorthands and match the following {{cssxref("<percentage>")}} values:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeywordValue
left0%
center50%
right100%
top0%
bottom100%
+ +

Formal syntax

+ +
{{csssyntax}}
+ +

Examples

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodeSample
+

transform: none;

+
+ + +
{{EmbedLiveSample('transform_none', '', 120, '', '', 'no-button') }}
+
+

transform: rotate(30deg);

+
+ + +
{{EmbedLiveSample('transform_rotate_only', '', 120, '', '', 'no-button') }}
+
+

transform: rotate(30deg);
+ transform-origin: 0 0;

+
+ + +
{{EmbedLiveSample('transform_rotate', '', 120, '', '', 'no-button') }}
+
+

transform: rotate(30deg);
+ transform-origin: 100% 100%;

+
+ + +
{{EmbedLiveSample('transform_rotate_with_percentage', '', 120, '', '', 'no-button') }}
+
+

transform: rotate(30deg);
+ transform-origin: -1em -3em;

+
+ + +
{{EmbedLiveSample('transform_rotate_with_em', '', 120, '', '', 'no-button') }}
+
+

transform: scale(1.7);

+
+ + +
{{EmbedLiveSample('transform_scale_only', '', 120, '', '', 'no-button') }}
+
+

transform: scale(1.7);
+ transform-origin: 0 0;

+
+ + +
{{EmbedLiveSample('transform_scale_without_origin', '', 120, '', '', 'no-button') }}
+
+

transform: scale(1.7);
+ transform-origin: 100% -30%;

+
+ + +
{{EmbedLiveSample('transform_scale', '', 120, '', '', 'no-button') }}
+
+

transform: skewX(50deg);
+ transform-origin: 100% -30%;

+
+ + +
{{EmbedLiveSample('transform_skew_x', '', 120, '', '', 'no-button') }}
+
+

transform: skewY(50deg);
+ transform-origin: 100% -30%;

+
+ + +
{{EmbedLiveSample('transform_skew_y', '', 120, '', '', 'no-button') }}
+
+ +

Specifications

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('CSS3 Transforms', '#transform-origin-property', 'transform-origin') }}{{ Spec2('CSS3 Transforms') }} 
+ +

{{Cssinfo}}

+ +

Browser compatibility

+ + + +

{{Compat("css.properties.transform-origin")}}

+ +

See also

+ + diff --git a/files/zh-tw/web/css/transform/index.html b/files/zh-tw/web/css/transform/index.html new file mode 100644 index 0000000000..7b1f9ee11b --- /dev/null +++ b/files/zh-tw/web/css/transform/index.html @@ -0,0 +1,159 @@ +--- +title: transform +slug: Web/CSS/transform +tags: + - CSS + - CSS Property + - NeedsBrowserCompatibility + - Reference + - Transforms +translation_of: Web/CSS/transform +--- +
{{CSSRef}}
+ +

transform CSS 屬性可以讓你修改 CSS 可視化格式模型(visual formatting model)的空間維度。使用此屬性,元素可以被平移、旋轉、縮放和傾斜。

+ +
{{EmbedInteractiveExample("pages/css/transform.html")}}
+ +

如果這個屬性的值不是 none,將會建立一個 stacking context。在這個情況下,此元素將被其所包含的 position: fixed 元素當成一個 containing block。

+ +
+

只有可以變形的元素可以被變形,這包括所有被CSS box model掌管輸出的元素,除了視覺格式化模型, table-column boxestable-colunm-group boxes

+
+ +

語法

+ +
/* Keyword values */
+transform: none;
+
+/* Function values */
+transform: matrix(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
+transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+transform: perspective(17px);
+transform: rotate(0.5turn);
+transform: rotate3d(1, 2.0, 3.0, 10deg);
+transform: rotateX(10deg);
+transform: rotateY(10deg);
+transform: rotateZ(10deg);
+transform: translate(12px, 50%);
+transform: translate3d(12px, 50%, 3em);
+transform: translateX(2em);
+transform: translateY(3in);
+transform: translateZ(2px);
+transform: scale(2, 0.5);
+transform: scale3d(2.5, 1.2, 0.3);
+transform: scaleX(2);
+transform: scaleY(0.5);
+transform: scaleZ(0.3);
+transform: skew(30deg, 20deg);
+transform: skewX(30deg);
+transform: skewY(1.07rad);
+
+/* Multiple function values */
+transform: translateX(10px) rotate(10deg) translateY(5px);
+transform: perspective(500px) translate(10px, 0, 20px) rotateY(3deg);
+
+/* Global values */
+transform: inherit;
+transform: initial;
+transform: unset;
+ +

transform 屬性可能被指定為關鍵字值 none 或著一或多個 <transform-function> 值。

+ +

+ +
+
{{cssxref("<transform-function>")}}
+
可使用一個或多個 CSS transform functions。複合的transforms 會由左至右的順序來套用。
+
none
+
設定為沒有套用任何 transform。
+
+ +

可使用性問題

+ +

改變尺寸和伸縮的動畫會影響網頁普遍的可使用性,因為它們可能促發一些頭痛的問題。如果你想要在網頁中提供這樣的功能,最好在網頁中放上給使用者關閉這些功能的控制開關。

+ +

另外也可考慮使用{{cssxref("@media/prefers-reduced-motion", "prefers-reduced-motion")}} 這個媒體功能來寫一個在系統設定端的媒體詢問,讓使用者在減少了動畫偏好之後可以關閉該使用者網頁的動畫功能。

+ +

瞭解更多:

+ + + +

正式定義

+ +

{{CSSInfo}}

+ +

標準語法

+ +
{{csssyntax}}
+ +

範例

+ +

平移、旋轉元素

+ + + +

HTML

+ + + +
<p>Transformed element</p>
+ +

CSS

+ +
p {
+  border: solid red;
+  transform: translate(100px) rotate(20deg);
+  transform-origin: 0 -250px;
+}
+ +

結果

+ +

{{EmbedLiveSample("Translating_and_rotating_an_element", "400", "160")}}

+ +

更多範例

+ +

請參考使用 CSS transforms 以及 {{cssxref("<transform-function>")}} 的更多範例。

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS Transforms 2', '#transform-functions', 'transform')}}{{Spec2('CSS Transforms 2')}}Adds 3D transform functions.
{{SpecName('CSS3 Transforms', '#transform-property', 'transform')}}{{Spec2('CSS3 Transforms')}}Initial definition.
+ +

{{cssinfo}}

+ +

瀏覽器相容性

+ + + +

{{Compat("css.properties.transform")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/css/transition-duration/index.html b/files/zh-tw/web/css/transition-duration/index.html new file mode 100644 index 0000000000..f29fa166ca --- /dev/null +++ b/files/zh-tw/web/css/transition-duration/index.html @@ -0,0 +1,342 @@ +--- +title: transition-duration +slug: Web/CSS/transition-duration +tags: + - CSS + - CSS Property + - CSS 轉場 + - Reference +translation_of: Web/CSS/transition-duration +--- +
{{CSSRef}}
+ +

transition-duration CSS 屬性指定轉場動畫所需經歷的時間,以秒或是毫秒為單位。默認值為0,表示沒有任何轉場動畫。

+ +
{{EmbedInteractiveExample("pages/css/transition-duration.html")}}
+ + + +

你可以指定多個時間長度,每一個時間長度都會被應用在{{ cssxref("transition-property") }} 設定的對應屬性上(which acts as a master list.) 如果指定的時間長度的數量比對應屬性的數量少,那麼時間長度就會被重複使用。反之,多餘的時間長度就會被刪去。而這兩種情況之下的CSS宣告都是有效的。

+ +

語法

+ +
/* <time> 值 */
+transition-duration: 6s;
+transition-duration: 120ms;
+transition-duration: 1s, 15s;
+transition-duration: 10s, 30s, 230ms;
+
+/* 全域值 */
+transition-duration: inherit;
+transition-duration: initial;
+transition-duration: unset;
+
+ +

+ +
+
<time>
+
{{cssxref("<time>")}}類型表示轉場動畫從舊狀態轉至新狀態所需要的時間。如果時間長度為0,表示沒有任何轉場,狀態之間會立即改變。若時間長度為負值則無效。
+
+ +

正式語法

+ +
{{csssyntax}}
+ +

範例

+ +
+
+

transition-duration: 0.5s

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top transform -webkit-transform color;
+    -webkit-transition-duration:0.5s;
+    -webkit-transition-timing-function: ease-in-out;
+    transition-property: width height background-color font-size left top transform -webkit-transform color;
+    transition-duration:0.5s;
+    transition-timing-function: ease-in-out;
+}
+.box1{
+    transform: rotate(270deg);
+    -webkit-transform: rotate(270deg);
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top transform -webkit-transform color;
+    -webkit-transition-duration:0.5s;
+    -webkit-transition-timing-function: ease-in-out;
+    transition-property: width height background-color font-size left top transform -webkit-transformv color;
+    transition-duration:0.5s;
+    transition-timing-function: ease-in-out;
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("duration_0_5s",275,150)}}
+
+ +
+

transition-duration: 1s

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top -webkit-transform color;
+    -webkit-transition-duration:1s;
+    -webkit-transition-timing-function: ease-in-out;
+    transition-property: width height background-color font-size left top transform color;
+    transition-duration:1s;
+    transition-timing-function: ease-in-out;
+}
+.box1{
+    transform: rotate(270deg);
+    -webkit-transform: rotate(270deg);
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top -webkit-transform transform color;
+    -webkit-transition-duration:1s;
+    -webkit-transition-timing-function: ease-in-out;
+    transition-property: width height background-color font-size left top transform -webkit-transform color;
+    transition-duration:1s;
+    transition-timing-function: ease-in-out;
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("duration_1s",275,150)}}
+
+ +
+

transition-duration: 2s

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top transform -webkit-transform color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: ease-in-out;
+    transition-property: width height background-color font-size left top transform -webkit-transform color;
+    transition-duration:2s;
+    transition-timing-function: ease-in-out;
+}
+.box1{
+    transform: rotate(270deg);
+    -webkit-transform: rotate(270deg);
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top transform -webkit-transform color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: ease-in-out;
+    transition-property: width height background-color font-size left top transform -webkit-transform color;
+    transition-duration:2s;
+    transition-timing-function: ease-in-out;
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("duration_2s",275,150)}}
+
+ +
+

transition-duration: 4s

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top transform -webkit-transform color;
+    -webkit-transition-duration:4s;
+    -webkit-transition-timing-function: ease-in-out;
+    transition-property: width height background-color font-size left top transform -webkit-transform color;
+    transition-duration:4s;
+    transition-timing-function: ease-in-out;
+}
+.box1{
+    transform: rotate(270deg);
+    -webkit-transform: rotate(270deg);
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top transform -webkit-transform color;
+    -webkit-transition-duration:4s;
+    -webkit-transition-timing-function: ease-in-out;
+    transition-property: width height background-color font-size left top transform -webkit-transform color;
+    transition-duration:4s;
+    transition-timing-function: ease-in-out;
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("duration_4s",275,150)}}
+
+
+ +

規範

+ + + + + + + + + + + + + + + + +
規範狀態備註
{{ SpecName('CSS3 Transitions', '#transition-duration', 'transition-duration') }}{{ Spec2('CSS3 Transitions') }}Initial definition
+ +

{{cssinfo}}

+ +

瀏覽器支援情形

+ + + +

{{Compat("css.properties.transition-duration")}}

+ +

更多資訊

+ + diff --git a/files/zh-tw/web/css/transition-timing-function/index.html b/files/zh-tw/web/css/transition-timing-function/index.html new file mode 100644 index 0000000000..492a4e3c3e --- /dev/null +++ b/files/zh-tw/web/css/transition-timing-function/index.html @@ -0,0 +1,605 @@ +--- +title: transition-timing-function +slug: Web/CSS/transition-timing-function +translation_of: Web/CSS/transition-timing-function +--- +
{{CSSRef}}
+ +

transition-timing-function CSS 屬性用於表示各個被動畫特效影響的屬性的區間值計算方式。

+ +
{{EmbedInteractiveExample("pages/css/transition-timing-function.html")}}
+ + + +

 

+ +

本質上,這個屬性讓你使用加速度曲線來表示動畫變換的速度。

+ +

而每個可以動畫化的屬性使用一個 {{cssxref("<timing-function>")}} 作為加速度曲線。

+ +

 

+ +

你也許有許多時間函數,而你可以透過使用 {{ cssxref("transition-property") }} 屬性來個別設置。如果有前述清單的數量超過時間函數的數量,則會使用預設值 ease;如果少於那多餘的時間函數會被忽略,在這兩種情況,CSS 宣告總會有效。

+ +

語法

+ +
/* Keyword */
+transition-timing-function: ease;
+transition-timing-function: ease-in;
+transition-timing-function: ease-out;
+transition-timing-function: ease-in-out;
+transition-timing-function: linear;
+transition-timing-function: step-start;
+transition-timing-function: step-end;
+
+/* 函數 */
+transition-timing-function: steps(4, end);
+transition-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1);
+transition-timing-function: frames(10);
+
+/* 多個函數 */
+transition-timing-function: ease, step-start, cubic-bezier(0.1, 0.7, 1.0, 0.1);
+
+/* 全域值 */
+transition-timing-function: inherit;
+transition-timing-function: initial;
+transition-timing-function: unset;
+
+/* 包含 transition-property */
+transition-property: width, height;
+transition-timing-function: ease-in, ease-out; // ease-in to width and ease-out to height
+
+
+ +

+ +
+
<timing-function>
+
每個 {{cssxref("<timing-function>")}} 連結到對應的動畫化屬性,請參考 {{ cssxref("transition-property") }}。
+
+ +

公式語法

+ +
{{csssyntax}}
+ +

範例

+ +
+
+

transition-timing-function: ease

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: ease;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: ease;
+}
+.box1{
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: ease;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: ease;
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("ttf_ease",275,150)}}
+
+ +
+

transition-timing-function: ease-in

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+     -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: ease-in;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: ease-in;
+}
+.box1{
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: ease-in;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: ease-in;
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("ttf_easein",275,150)}}
+
+ +
+

transition-timing-function: ease-out

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: ease-out;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: ease-out;
+}
+.box1{
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: ease-out;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: ease-out;
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("ttf_easeout",275,150)}}
+
+ +
+

transition-timing-function: ease-in-out

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: ease-in-out;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: ease-in-out;
+}
+.box1{
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: ease-in-out;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: ease-in-out;
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("ttf_easeinout",275,150)}}
+
+
+ +
+

transition-timing-function: linear

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: linear;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: linear;
+}
+.box1{
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: linear;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: linear;
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("ttf_linear",275,150)}}
+
+ +
+

transition-timing-function: step-start

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: step-start;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: step-start;
+}
+.box1{
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: step-start;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: step-start;
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("ttf_stepstart",275,150)}}
+
+ +
+

transition-timing-function: step-end

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: step-end;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: step-end;
+}
+.box1{
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: step-end;
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: step-end;
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("ttf_stepend",275,150)}}
+
+ +
+

transition-timing-function: steps(4, end)

+ +
+
 <div class="parent">
+  <div class="box">Lorem</div>
+</div>
+  
+ +
.parent { width: 250px; height:125px;}
+.box {
+    width: 100px;
+    height: 100px;
+    background-color: red;
+    font-size: 20px;
+    left: 0px;
+    top: 0px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: steps(4, end);
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: steps(4, end);
+}
+.box1{
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+    color: yellow;
+    font-size: 18px;
+    left: 150px;
+    top:25px;
+    position:absolute;
+    -webkit-transition-property: width height background-color font-size left top color;
+    -webkit-transition-duration:2s;
+    -webkit-transition-timing-function: steps(4, end);
+    transition-property: width height background-color font-size left top color;
+    transition-duration:2s;
+    transition-timing-function: steps(4, end);
+}
+
+ +
function updateTransition() {
+  var el = document.querySelector("div.box");
+
+  if (el) {
+    el.className = "box1";
+  } else {
+    el = document.querySelector("div.box1");
+    el.className = "box";
+  }
+
+  return el;
+}
+
+var intervalID = window.setInterval(updateTransition, 7000);
+
+
+ +
{{EmbedLiveSample("ttf_step4end",275,150)}}
+
+ +

規格

+ + + + + + + + + + + + + + + + +
規格狀態備註
{{ SpecName('CSS3 Transitions', '#transition-timing-function-property', 'transition-timing-function') }}{{ Spec2('CSS3 Transitions') }}初始定義
+ +

{{cssinfo}}

+ +

相容性

+ + + +

{{Compat("css.properties.transition-timing-function")}}

+ +

看更多

+ + diff --git a/files/zh-tw/web/css/transition/index.html b/files/zh-tw/web/css/transition/index.html new file mode 100644 index 0000000000..3e5b3c042c --- /dev/null +++ b/files/zh-tw/web/css/transition/index.html @@ -0,0 +1,106 @@ +--- +title: transition +slug: Web/CSS/transition +tags: + - CSS + - CSS Property + - CSS轉場 + - Reference +translation_of: Web/CSS/transition +--- +
{{CSSRef}}
+ +

transition CSS 屬性是 {{ cssxref("transition-property") }}, {{ cssxref("transition-duration") }}, {{ cssxref("transition-timing-function") }}, and {{ cssxref("transition-delay") }}的 特性簡寫

+ +
{{EmbedInteractiveExample("pages/css/transition.html")}}
+ + + +

Transitions 讓你可以定義元件在兩個狀態之間切換的轉場效果。兩個不同狀態可以使用虛擬類別 定義,像是{{cssxref(":hover")}} 或 {{cssxref(":active")}} 亦或是 使用JavaScript設定的狀態變化。

+ +

語法

+ +
/* Apply to 1 property */
+/* property name | duration */
+transition: margin-right 4s;
+
+/* property name | duration | delay */
+transition: margin-right 4s 1s;
+
+/* property name | duration | timing function */
+transition: margin-right 4s ease-in-out;
+
+/* property name | duration | timing function | delay */
+transition: margin-right 4s ease-in-out 1s;
+
+/* Apply to 2 properties */
+transition: margin-right 4s, color 1s;
+
+/* Apply to all changed properties */
+transition: all 0.5s ease-out;
+
+/* Global values */
+transition: inherit;
+transition: initial;
+transition: unset;
+
+ +

transition 屬性可以包含一個或多個轉場設定,每一項設定都以逗點分開。

+ +

每一項設定都描述著每一項屬性所對應的轉場效果(或是all 及 none這兩個特殊值) 。其包含了:

+ + + +

當每個轉場設定不等長時,請參見 當property values list 之間不等長時... 。簡而言之,多餘的描述(超過實際被執行的數量)會直接被忽略。

+ +

標準語法

+ +
{{csssyntax}}
+ +

範例

+ +

CSS 轉場 有更多範例。

+ +

規範

+ + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{ SpecName('CSS3 Transitions', '#transition-shorthand-property', 'transition') }}{{ Spec2('CSS3 Transitions') }}Initial definition
+ +

{{cssinfo}}

+ +

瀏覽器支援情況

+ + + +

{{Compat("css.properties.transition")}}

+ +

更多資訊

+ + diff --git a/files/zh-tw/web/css/type_selectors/index.html b/files/zh-tw/web/css/type_selectors/index.html new file mode 100644 index 0000000000..6a6bb32e89 --- /dev/null +++ b/files/zh-tw/web/css/type_selectors/index.html @@ -0,0 +1,79 @@ +--- +title: 元素選擇器 +slug: Web/CSS/Type_selectors +translation_of: Web/CSS/Type_selectors +--- +
{{CSSRef}}
+CSS 元素選擇器 (也稱 型態選擇器)依照 Node 節點名稱選取匹配的 Element 元素。換句話說,此選擇器選取在 Document 文件內所有指定該型態的元素。
+ +
 
+ +
/* 全部的 <a> 元素。*/
+a {
+  color: red;
+}
+ +

語法

+ +
element { style properties }
+
+ +

範例

+ +

CSS

+ +
span {
+  background-color: skyblue;
+}
+
+ +

HTML

+ +
<span>Here's a span with some text.</span>
+<p>Here's a p with some text.</p>
+<span>Here's a span with more text.</span>
+
+ +

Result

+ +

{{EmbedLiveSample('Example', '100%', 150)}}

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS4 Selectors', '#type-selectors', 'Type (tag name) selector')}}{{Spec2('CSS4 Selectors')}}No changes
{{SpecName('CSS3 Selectors', '#type-selectors', 'type selectors')}}{{Spec2('CSS3 Selectors')}}No changes
{{SpecName('CSS2.1', 'selector.html#type-selectors', 'type selectors')}}{{Spec2('CSS2.1')}} 
{{SpecName('CSS1', '#basic-concepts', 'type selectors')}}{{Spec2('CSS1')}}Initial definition
+ +

Browser compatibility

+ + + +

{{Compat("css.selectors.type")}}

diff --git a/files/zh-tw/web/css/white-space/index.html b/files/zh-tw/web/css/white-space/index.html new file mode 100644 index 0000000000..eef166cc0e --- /dev/null +++ b/files/zh-tw/web/css/white-space/index.html @@ -0,0 +1,425 @@ +--- +title: white-space +slug: Web/CSS/white-space +translation_of: Web/CSS/white-space +--- +
{{CSSRef}}
+ +

此 CSS white-space 屬性決定如何處理元素內的空白字元。

+ +
+

提醒:如果要讓文字本身斷行,請改用 {{cssxref("overflow-wrap")}}、{{cssxref("word-break")}} 或 {{cssxref("hyphens")}}。

+
+ +
/* Keyword values */
+white-space: normal;
+white-space: nowrap;
+white-space: pre;
+white-space: pre-wrap;
+white-space: pre-line;
+
+/* Global values */
+white-space: inherit;
+white-space: initial;
+white-space: unset;
+
+ + + +

{{EmbedLiveSample("white-space", "100%", 530, "", "", "example-outcome-frame")}}

+ +

{{cssinfo}}

+ +

Syntax

+ +

 white-space 的特性值為下列其中之一。

+ +

Values

+ +
+
normal
+
連續的空白字元會被合併(collapse),換行字元被視為空白字元。換行只在被文字空間限制時發生。
+
nowrap
+
對待空白字元的方式跟 normal 一樣,且會強制不換行。
+
pre
+
連續的空白字元都會被保留。換行在有換行字元以及{{HTMLElement("br")}}時發生。
+
pre-wrap
+
連續的空白字元都會被保留。換行會在換行字元、有{{HTMLElement("br")}}元素以及被文字空間限制時發生。
+
pre-line
+
連續的空白字元會被合併(collapse)。換行在換行字元、 {{HTMLElement("br")}}以及被文字空間限制時發生。
+
+ +

下列表格整理了各項 white-space 值的行為:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 New linesSpaces and tabsText wrapping
normalCollapseCollapseWrap
nowrapCollapseCollapseNo wrap
prePreservePreserveNo wrap
pre-wrapPreservePreserveWrap
pre-linePreserveCollapseWrap
+ +

Formal syntax

+ +
{{csssyntax}}
+ +

Examples

+ +

Basic example

+ +
code {
+  white-space: pre;
+}
+ +

Line breaks inside {{HTMLElement("pre")}} elements

+ +
pre {
+  word-wrap: break-word;      /* IE 5.5-7 */
+  white-space: -moz-pre-wrap; /* Firefox 1.0-2.0 */
+  white-space: pre-wrap;      /* Modern browsers */
+}
+ +

See it in action

+ + + +

Source

+ +
    <p>    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+    Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+
+    Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+
+ +

CSS + Result

+ +

{{ EmbedLiveSample('See_in_action', '80%', '500px') }}

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Text', '#propdef-white-space', 'white-space')}}{{Spec2('CSS3 Text')}}Precisely defines the breaking algorithms.
{{SpecName('CSS2.1', 'text.html#white-space-prop', 'white-space')}}{{Spec2('CSS2.1')}}Initial definition.
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support (normal and nowrap)1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.0")}}5.5[1]4.01.0 (85)
pre1.0{{CompatVersionUnknown}}1.06.04.01.0 (85)
pre-wrap1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.0")}}{{property_prefix("-moz")}}
+ {{CompatGeckoDesktop("1.9")}}
8.08.03.0 (522)
pre-line1.0{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.9.1")}}8.09.53.0 (522)
Support on <textarea>1.0{{CompatUnknown}}{{CompatGeckoDesktop("36")}}5.54.01.0 (85)
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidEdgeFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Internet Explorer 5.5+ supports {{Cssxref("word-wrap")}}: break-word;.

+ +

See also

+ + diff --git a/files/zh-tw/web/css/width/index.html b/files/zh-tw/web/css/width/index.html new file mode 100644 index 0000000000..9459dd32e9 --- /dev/null +++ b/files/zh-tw/web/css/width/index.html @@ -0,0 +1,294 @@ +--- +title: width +slug: Web/CSS/width +translation_of: Web/CSS/width +--- +
{{CSSRef}}
+ +

The width CSS property specifies the width of an element. By default, the property defines the width of the content area. If {{cssxref("box-sizing")}} is set to border-box, however, it instead determines the width of the border area.

+ +
/* <length> values */
+width: 300px;
+width: 25em;
+
+/* <percentage> value */
+width: 75%;
+
+/* Keyword values */
+width: 25em border-box;
+width: 75% content-box;
+width: max-content;
+width: min-content;
+width: available;
+width: fit-content;
+width: auto;
+
+/* Global values */
+width: inherit;
+width: initial;
+width: unset;
+
+ + + +
{{EmbedLiveSample("width", "100%", 660, "", "", "example-outcome-frame")}}
+ +
+

注意: {{cssxref("min-width")}} 和 {{cssxref("max-width")}} 會覆寫 {{cssxref("width")}}.

+
+ +
{{cssinfo}}
+ +

Syntax

+ +

The width property is specified as either:

+ + + +

Values

+ +
+
{{cssxref("<length>")}}
+
Defines the width as an absolute value.
+
{{cssxref("<percentage>")}}
+
Defines the width as a percentage of the containing block's width. If the width of the containing block depends on the width of the element, the resulting layout is undefined.
+
border-box {{experimental_inline}}
+
If present, the preceding {{cssxref("<length>")}} or {{cssxref("<percentage>")}} is applied to the element's border box.
+
content-box {{experimental_inline}}
+
If present, the preceding {{cssxref("<length>")}} or {{cssxref("<percentage>")}} is applied to the element's content box.
+
auto
+
The browser will calculate and select a width for the specified element.
+
fill {{experimental_inline}}
+
Use the fill-available inline size or fill-available block size, as appropriate to the writing mode.
+
max-content {{experimental_inline}}
+
The intrinsic preferred width.
+
min-content {{experimental_inline}}
+
The intrinsic minimum width.
+
available {{experimental_inline}}
+
The containing block width minus horizontal margin, border and padding.
+
fit-content {{experimental_inline}}
+
The larger of: +
    +
  • the intrinsic minimum width
  • +
  • the smaller of the intrinsic preferred width and the available width
  • +
+
+
+ +

Formal syntax

+ +
{{csssyntax}}
+ +

範例

+ +

預設寬度

+ +
p.goldie {
+  background: gold;
+}
+ +
<p class="goldie">The Mozilla community produces a lot of great software.</p>
+ +

{{EmbedLiveSample('Default_width', '500px', '64px')}}

+ +

像素和相對大小

+ +
.px_length {
+  width: 200px;
+  background-color: red;
+  color: white;
+  border: 1px solid black;
+}
+
+.em_length {
+  width: 20em;
+  background-color: white;
+  color: red;
+  border: 1px solid black;
+}
+
+ +
<div class="px_length">Width measured in px</div>
+<div class="em_length">Width measured in em</div>
+ +

{{EmbedLiveSample('Pixels_and_ems', '500px', '64px')}}

+ +

百分比

+ +
.percent {
+  width: 20%;
+  background-color: silver;
+  border: 1px solid red;
+}
+ +
<div class="percent">Width in percentage</div>
+ +

{{EmbedLiveSample('Percentage', '500px', '64px')}}

+ +

內容最大值

+ +
p.maxgreen {
+  background: lightgreen;
+  width: intrinsic;           /* Safari/WebKit uses a non-standard name */
+  width: -moz-max-content;    /* Firefox/Gecko */
+  width: -webkit-max-content; /* Chrome */
+}
+ +
<p class="maxgreen">The Mozilla community produces a lot of great software.</p>
+ +

{{EmbedLiveSample('max-content_2', '500px', '64px')}}

+ +

內容最小值

+ +
p.minblue {
+  background: lightblue;
+  width: -moz-min-content;    /* Firefox */
+  width: -webkit-min-content; /* Chrome */
+}
+ +
<p class="minblue">The Mozilla community produces a lot of great software.</p>
+ +

{{EmbedLiveSample('min-content_2', '500px', '155px')}}

+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('CSS3 Box', '#the-width-and-height-properties', 'width')}}{{Spec2('CSS3 Box')}}Added the max-content, min-content, available, fit-content, border-box, content-box keywords.
{{SpecName('CSS3 Transitions', '#animatable-css', 'width')}}{{Spec2('CSS3 Transitions')}}Lists width as animatable.
{{SpecName('CSS2.1', 'visudet.html#the-width-property', 'width')}}{{Spec2('CSS2.1')}}Precises on which element it applies to.
{{SpecName('CSS1', '#width', 'width')}}{{Spec2('CSS1')}}Initial definition.
{{SpecName('CSS3 Sizing', '#width-height-keywords', 'width')}}{{Spec2('CSS3 Sizing')}}Adds new sizing keywords for width and height.
+ +

瀏覽器相容性

+ + + +

{{Compat("css.properties.width")}}

+ +

參考

+ + diff --git a/files/zh-tw/web/demos_of_open_web_technologies/index.html b/files/zh-tw/web/demos_of_open_web_technologies/index.html new file mode 100644 index 0000000000..5baa250a38 --- /dev/null +++ b/files/zh-tw/web/demos_of_open_web_technologies/index.html @@ -0,0 +1,144 @@ +--- +title: Demos of open web technologies +slug: Web/Demos_of_open_web_technologies +tags: + - 影片 + - 網站 + - 網頁 + - 設計 +translation_of: Web/Demos_of_open_web_technologies +--- +

Mozilla 支援豐富、廣泛且扣人心弦的網路公開技術,並且我們鼓勵使用他們。這個頁面提供一些展示這些有趣技術的連結,包含那些曾經在 Demo Studio 有人氣的,但現在已經落伍了的技術。如果你知道有關於新的網路公開技術,不錯的展示或是應用程式,請將連結加到下方適合的區塊中。

+ +

2D 繪圖

+ +

Canvas

+ + + +

SVG

+ + + +

影片

+ + + +

3D 繪圖

+ +

WebGL

+ + + +

虛擬實境 ( Virtual Reality )

+ + + +

CSS

+ + + +

轉換 ( Transformations )

+ + + +

遊戲

+ + + +

HTML

+ + + +

Web APIs

+ + + +

提示工具的 API

+ + + + + +

網路 API

+ + + +

檔案的 API

+ + + +

Web Workers

+ + diff --git a/files/zh-tw/web/events/abort/index.html b/files/zh-tw/web/events/abort/index.html new file mode 100644 index 0000000000..a2d9d86059 --- /dev/null +++ b/files/zh-tw/web/events/abort/index.html @@ -0,0 +1,67 @@ +--- +title: abort +slug: Web/Events/abort +translation_of: Web/API/HTMLMediaElement/abort_event +--- +

當資源載入被拒絕時將會觸發abort事件。

+ +

一般資訊

+ +
+
規範
+
DOM L3
+
介面
+
若由使用者介面產生,為UIEvent,否則為Event。
+
是否向上(冒泡)
+
+
是否為可取消
+
+
目標對象
+
Element
+
預設行為
+
+
+ +

屬性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
屬性型態描述
target {{readonlyInline}}EventTarget事件的目標對象 (DOM樹中最頂層的對象)。
type {{readonlyInline}}DOMString事件的型態。
bubbles {{readonlyInline}}Boolean事件是否向上冒泡。
cancelable {{readonlyInline}}Boolean事件是否能夠取消。
view {{readonlyInline}}WindowProxydocument.defaultView (該文檔(Document)的window)
detail {{readonlyInline}}long (float)0.
diff --git a/files/zh-tw/web/events/domcontentloaded/index.html b/files/zh-tw/web/events/domcontentloaded/index.html new file mode 100644 index 0000000000..0ec78423ec --- /dev/null +++ b/files/zh-tw/web/events/domcontentloaded/index.html @@ -0,0 +1,133 @@ +--- +title: DOMContentLoaded +slug: Web/Events/DOMContentLoaded +translation_of: Web/API/Window/DOMContentLoaded_event +--- +

DOMContentLoaded事件是當document被完整的讀取跟解析後就會被觸發,不會等待 stylesheets, 圖片和subframes完成讀取  (load事件可以用來作為判斷頁面已經完整讀取的方法).

+ +
+

Note: Stylesheet loads block script execution, 如果 <script> 被放在 <link rel="stylesheet" ...>後面的話, 須等到前面的stylesheet載入並完成解析,此時 DOMContentLoaded才會被觸發。

+
+ +

Speeding up

+ +

If you want DOM to get parsed as fast as possible after the user had requested the page, some things you could do is turn your JavaScript asynchronous and to optimize loading of stylesheets which if used as usual, slow down page load due to being loaded in parallel, "stealing" traffic from the main html document.

+ +

General info

+ +
+
Specification
+
HTML5
+
Interface
+
Event
+
Bubbles
+
Yes
+
Cancelable
+
Yes (although specified as a simple event that isn't cancelable)
+
Target
+
Document
+
Default Action
+
None.
+
+ +

屬性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
target {{readonlyInline}}{{domxref("EventTarget")}}The event target (the topmost target in the DOM tree).
type {{readonlyInline}}{{domxref("DOMString")}}The type of event.
bubbles {{readonlyInline}}{{jsxref("Boolean")}}Whether the event normally bubbles or not.
cancelable {{readonlyInline}}{{jsxref("Boolean")}}Whether the event is cancellable or not.
+ +

瀏覽器相容性

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support0.2{{ CompatGeckoDesktop("1") }}9.09.03.1
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{ CompatVersionUnknown() }}{{ CompatGeckoMobile("1") }}{{ CompatUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
+
+ +

Bubbling for this event is supported by at least Gecko 1.9.2, Chrome 6, and Safari 4.

+ +

Cross-browser fallback

+ +

Internet Explorer 8 supports the <code>readystatechange</code> event, which can be used to detect that the DOM is ready. In earlier version of Internet Explorer, this state can be detected by regularily trying to execute <code>document.documentElement.doScroll("left");</code>, as this snippet will throw an error until the DOM is ready.

+ +

General-purpose JS libraries such as jQuery offer cross-browser methods to detect that the DOM is ready. There are also standalone scripts that offer this feature : contentloaded.js (supports only one listener) and jquery.documentReady.js (doesn't depend on jQuery, despite its name).

+ + + + diff --git a/files/zh-tw/web/events/index.html b/files/zh-tw/web/events/index.html new file mode 100644 index 0000000000..569afb05e4 --- /dev/null +++ b/files/zh-tw/web/events/index.html @@ -0,0 +1,1928 @@ +--- +title: Event reference +slug: Web/Events +tags: + - NeedsTag + - NeedsTranslation + - TopicStub +translation_of: Web/Events +--- +

事件為一些有趣事情,發生後會被傳出以通知code。每個事件被表示為一個根據{{domxref("Event")}}所定義的物件,且可能會有額外自訂欄位與(或)函式來描述發生了什麼事。事件可以表示從使用者互動到自動通知等渲染model所有的事情。

+ +

Events are sent to notify code of interesting things that have taken place. Each event is represented by an object which is based on the {{domxref("Event")}} interface, and may have additional custom fields and/or functions used to get additional information about what happened. Events can represent everything from basic user interactions to automated notifications of things happening in the rendering model.

+ +

This article offers a list of events that can be sent; some are standard events defined in official specifications, while others are events used internally by specific browsers; for example, Mozilla-specific events are listed so that add-ons can use them to interact with the browser.no

+ +

標準事件

+ +

以下事件是由官方的 Web 標準規範中所定義,且應適用於所有的瀏覽器。下面的清單將列出事件和其所有傳送給事件的物件的 interface (所以你可以看到每個事件需要提供哪些資料)以及事件的定義規範。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
事件名稱事件類型規範觸發時機
{{event("abort")}}{{domxref("UIEvent")}}DOM L3The loading of a resource has been aborted.
abort{{domxref("ProgressEvent")}}Progress and XMLHttpRequestProgression has been terminated (not due to an error).
abort{{domxref("Event")}}IndexedDBA transaction has been aborted.
{{event("afterprint")}} {{gecko_minversion_inline("6")}}{{domxref("Event")}}HTML5The associated document has started printing or the print preview has been closed.
{{event("animationend")}}{{domxref("AnimationEvent")}}CSS AnimationsA CSS animation has completed.
{{event("animationiteration")}}{{domxref("AnimationEvent")}}CSS AnimationsA CSS animation is repeated.
{{event("animationstart")}}{{domxref("AnimationEvent")}}CSS AnimationsA CSS animation has started.
{{event("audioprocess")}}{{domxref("AudioProcessingEvent")}}{{SpecName('Web Audio API', '#AudioProcessingEvent', 'audioprocess')}}The input buffer of a {{domxref("ScriptProcessorNode")}} is ready to be processed.
{{event("beforeprint")}} {{gecko_minversion_inline("6")}}{{domxref("Event")}}HTML5The associated document is about to be printed or previewed for printing.
{{event("beforeunload")}}{{domxref("BeforeUnloadEvent")}}HTML5
{{event("beginEvent")}}{{domxref("TimeEvent")}}SVGA SMIL animation element begins.
blockedIndexedDBAn open connection to a database is blocking a versionchange transaction on the same database.
{{event("blur")}}{{domxref("FocusEvent")}}DOM L3An element has lost focus (does not bubble).
{{event("cached")}}{{domxref("Event")}}OfflineThe resources listed in the manifest have been downloaded, and the application is now cached.
{{event("canplay")}}{{domxref("Event")}}HTML5 mediaThe user agent can play the media, but estimates that not enough data has been loaded to play the media up to its end without having to stop for further buffering of content.
{{event("canplaythrough")}}{{domxref("Event")}}HTML5 mediaThe user agent can play the media, and estimates that enough data has been loaded to play the media up to its end without having to stop for further buffering of content.
{{event("change")}}{{domxref("Event")}}DOM L2, HTML5An element loses focus and its value changed since gaining focus.
{{event("chargingchange")}}{{domxref("Event")}}Battery statusThe battery begins or stops charging.
{{event("chargingtimechange")}}{{domxref("Event")}}Battery statusThe chargingTime attribute has been updated.
{{event("checking")}}{{domxref("Event")}}OfflineThe user agent is checking for an update, or attempting to download the cache manifest for the first time.
{{event("click")}}{{domxref("MouseEvent")}}DOM L3A pointing device button has been pressed and released on an element.
close{{domxref("Event")}}WebSocketA WebSocket connection has been closed.
{{event("compassneedscalibration")}}{{domxref("SensorEvent")}}OrientationThe compass used to obtain orientation data is in need of calibration.
{{event("compositionend")}}{{domxref("CompositionEvent")}}DOM L3The composition of a passage of text has been completed or canceled.
{{event("compositionstart")}}{{domxref("CompositionEvent")}}DOM L3The composition of a passage of text is prepared (similar to keydown for a keyboard input, but works with other inputs such as speech recognition).
{{event("compositionupdate")}}{{domxref("CompositionEvent")}}DOM L3A character is added to a passage of text being composed.
completeIndexedDBThe transaction successfully completed.
{{event("contextmenu")}}{{domxref("MouseEvent")}}HTML5The right button of the mouse is clicked (before the context menu is displayed).
{{event("copy")}}{{domxref("ClipboardEvent")}}ClipboardThe text selection has been added to the clipboard.
{{event("cut")}}{{domxref("ClipboardEvent")}}ClipboardThe text selection has been removed from the document and added to the clipboard.
{{event("dblclick")}}{{domxref("MouseEvent")}}DOM L3A pointing device button is clicked twice on an element.
{{event("devicehumidity")}}{{domxref("SensorEvent")}}SensorFresh data is available from a humidity sensor.
{{event("devicelight")}}{{domxref("SensorEvent")}}SensorFresh data is available from a light sensor.
{{event("devicemotion")}}{{domxref("SensorEvent")}}OrientationFresh data is available from a motion sensor.
{{event("devicenoise")}}{{domxref("SensorEvent")}}SensorFresh data is available from a noise sensor.
{{event("deviceorientation")}}{{domxref("SensorEvent")}}OrientationFresh data is available from an orientation sensor.
{{event("devicepressure")}}{{domxref("SensorEvent")}}SensorFresh data is available from a pressure sensor.
{{event("deviceproximity")}}{{domxref("SensorEvent")}}SensorFresh data is available from a proximity sensor (indicates an approximated distance between the device and a nearby object).
{{event("devicetemperature")}}{{domxref("SensorEvent")}}SensorFresh data is available from a temperature sensor.
{{event("dischargingtimechange")}}{{domxref("Event")}}Battery statusThe dischargingTime attribute has been updated.
DOMActivate {{deprecated_inline}}{{domxref("UIEvent")}}DOM L3A button, link or state changing element is activated (use {{event("click")}} instead).
DOMAttributeNameChanged {{deprecated_inline}}{{domxref("MutationNameEvent")}}DOM L3 RemovedThe name of an attribute changed (use mutation observers instead).
DOMAttrModified {{deprecated_inline}}{{domxref("MutationEvent")}}DOM L3The value of an attribute has been modified (use mutation observers instead).
DOMCharacterDataModified {{deprecated_inline}}{{domxref("MutationEvent")}}DOM L3A text or another CharacterData has changed (use mutation observers instead).
{{event("DOMContentLoaded")}}{{domxref("Event")}}HTML5The document has finished loading (but not its dependent resources).
DOMElementNameChanged {{deprecated_inline}}{{domxref("MutationNameEvent")}}DOM L3 RemovedThe name of an element changed (use mutation observers instead).
DOMFocusIn {{deprecated_inline}}{{domxref("FocusEvent")}}DOM L3An element has received focus (use {{event("focus")}} or {{event("focusin")}} instead).
DOMFocusOut {{deprecated_inline}}{{domxref("FocusEvent")}}DOM L3An element has lost focus (use {{event("blur")}} or {{event("focusout")}} instead).
DOMNodeInserted {{deprecated_inline}}{{domxref("MutationEvent")}}DOM L3A node has been added as a child of another node (use mutation observers instead).
DOMNodeInsertedIntoDocument {{deprecated_inline}}{{domxref("MutationEvent")}}DOM L3A node has been inserted into the document (use mutation observers instead).
DOMNodeRemoved {{deprecated_inline}}{{domxref("MutationEvent")}}DOM L3A node has been removed from its parent node (use mutation observers instead).
DOMNodeRemovedFromDocument {{deprecated_inline}}{{domxref("MutationEvent")}}DOM L3A node has been removed from the document (use mutation observers instead).
DOMSubtreeModified {{deprecated_inline}}{{domxref("MutationEvent")}}DOM L3A change happened in the document (use mutation observers instead).
{{event("downloading")}}{{domxref("Event")}}OfflineThe user agent has found an update and is fetching it, or is downloading the resources listed by the cache manifest for the first time.
{{event("drag")}}{{domxref("DragEvent")}}HTML5An element or text selection is being dragged (every 350ms).
{{event("dragend")}}{{domxref("DragEvent")}}HTML5A drag operation is being ended (by releasing a mouse button or hitting the escape key).
{{event("dragenter")}}{{domxref("DragEvent")}}HTML5A dragged element or text selection enters a valid drop target.
{{event("dragleave")}}{{domxref("DragEvent")}}HTML5A dragged element or text selection enters a valid drop target.
{{event("dragover")}}{{domxref("DragEvent")}}HTML5An element or text selection is being dragged over a valid drop target (every 350ms).
{{event("dragstart")}}{{domxref("DragEvent")}}HTML5The user starts dragging an element or text selection.
{{event("drop")}}{{domxref("DragEvent")}}HTML5An element is dropped on a valid drop target.
{{event("durationchange")}}{{domxref("Event")}}HTML5 mediaThe duration attribute has been updated.
{{event("emptied")}}{{domxref("Event")}}HTML5 mediaThe media has become empty; for example, this event is sent if the media has already been loaded (or partially loaded), and the load() method is called to reload it.
{{event("ended")}}{{domxref("Event")}}HTML5 mediaPlayback has stopped because the end of the media was reached.
{{event("ended_(Web_Audio)", "ended")}}{{domxref("Event")}}{{SpecName("Web Audio API")}}
{{event("endEvent")}}{{domxref("TimeEvent")}}SVGA SMIL animation element ends.
{{event("error")}}{{domxref("UIEvent")}}DOM L3A resource failed to load.
{{event("error")}}{{domxref("ProgressEvent")}}Progress and XMLHttpRequestProgression has failed.
{{event("error")}}{{domxref("Event")}}OfflineAn error occurred while downloading the cache manifest or updating the content of the application.
{{event("error")}}{{domxref("Event")}}WebSocketA WebSocket connection has been closed with prejudice (some data couldn't be sent for example).
{{event("error")}}{{domxref("Event")}}Server Sent EventsAn event source connection has been failed.
{{event("error")}}{{domxref("Event")}}IndexedDBA request caused an error and failed.
{{event("focus")}}{{domxref("FocusEvent")}}DOM L3An element has received focus (does not bubble).
{{event("focusin")}}{{domxref("FocusEvent")}}DOM L3An element is about to receive focus (bubbles).
{{event("focusout")}}{{domxref("FocusEvent")}}DOM L3An element is about to loose focus (bubbles).
{{event("fullscreenchange")}}{{domxref("Event")}}Full ScreenAn element was turned to fullscreen mode or back to normal mode.
{{event("fullscreenerror")}}{{domxref("Event")}}Full ScreenIt was impossible to switch to fullscreen mode for technical reasons or because the permission was denied.
{{event("gamepadconnected")}}{{domxref("GamepadEvent")}}GamepadA gamepad has been connected.
{{event("gamepaddisconnected")}}{{domxref("GamepadEvent")}}GamepadA gamepad has been disconnected.
{{event("hashchange")}}{{domxref("HashChangeEvent")}}HTML5The fragment identifier of the URL has changed (the part of the URL after the #).
{{event("input")}}{{domxref("Event")}}HTML5The value of an element changes or the content of an element with the attribute contenteditable is modified.
{{event("invalid")}}{{domxref("Event")}}HTML5A submittable element has been checked and doesn't satisfy its constraints.
{{event("keydown")}}{{domxref("KeyboardEvent")}}DOM L3A key is pressed down.
{{event("keypress")}}{{domxref("KeyboardEvent")}}DOM L3A key is pressed down and that key normally produces a character value (use input instead).
{{event("keyup")}}{{domxref("KeyboardEvent")}}DOM L3A key is released.
{{event("levelchange")}}{{domxref("Event")}}Battery statusThe level attribute has been updated.
{{event("load")}}{{domxref("UIEvent")}}DOM L3A resource and its dependent resources have finished loading.
load{{domxref("ProgressEvent")}}Progress and XMLHttpRequestProgression has been successful.
{{event("loadeddata")}}{{domxref("Event")}}HTML5 mediaThe first frame of the media has finished loading.
{{event("loadedmetadata")}}{{domxref("Event")}}HTML5 mediaThe metadata has been loaded.
{{event("loadend")}}{{domxref("ProgressEvent")}}Progress and XMLHttpRequestProgress has stopped (after "error", "abort" or "load" have been dispatched).
{{event("loadstart")}}{{domxref("ProgressEvent")}}Progress and XMLHttpRequestProgress has begun.
message{{domxref("MessageEvent")}}WebSocketA message is received through a WebSocket.
message{{domxref("MessageEvent")}}Web WorkersA message is received from a Web Worker.
message{{domxref("MessageEvent")}}Web MessagingA message is received from a child (i)frame or a parent window.
message{{domxref("MessageEvent")}}Server Sent EventsA message is received through an event source.
{{event("mousedown")}}{{domxref("MouseEvent")}}DOM L3A pointing device button (usually a mouse) is pressed on an element.
{{event("mouseenter")}}{{domxref("MouseEvent")}}DOM L3A pointing device is moved onto the element that has the listener attached.
{{event("mouseleave")}}{{domxref("MouseEvent")}}DOM L3A pointing device is moved off the element that has the listener attached.
{{event("mousemove")}}{{domxref("MouseEvent")}}DOM L3A pointing device is moved over an element.
{{event("mouseout")}}{{domxref("MouseEvent")}}DOM L3A pointing device is moved off the element that has the listener attached or off one of its children.
{{event("mouseover")}}{{domxref("MouseEvent")}}DOM L3A pointing device is moved onto the element that has the listener attached or onto one of its children.
{{event("mouseup")}}{{domxref("MouseEvent")}}DOM L3A pointing device button is released over an element.
{{event("noupdate")}}{{domxref("Event")}}OfflineThe manifest hadn't changed.
{{event("obsolete")}}{{domxref("Event")}}OfflineThe manifest was found to have become a 404 or 410 page, so the application cache is being deleted.
{{event("offline")}}{{domxref("Event")}}HTML5 offlineThe browser has lost access to the network.
{{event("online")}}{{domxref("Event")}}HTML5 offlineThe browser has gained access to the network (but particular websites might be unreachable).
open{{domxref("Event")}}WebSocketA WebSocket connection has been established.
open{{domxref("Event")}}Server Sent EventsAn event source connection has been established.
{{event("orientationchange")}}{{domxref("Event")}}Screen OrientationThe orientation of the device (portrait/landscape) has changed
{{event("pagehide")}}{{domxref("PageTransitionEvent")}}HTML5A session history entry is being traversed from.
{{event("pageshow")}}{{domxref("PageTransitionEvent")}}HTML5A session history entry is being traversed to.
{{event("paste")}}{{domxref("ClipboardEvent")}}ClipboardData has been transfered from the system clipboard to the document.
{{event("pause")}}{{domxref("Event")}}HTML5 mediaPlayback has been paused.
{{event("pointerlockchange")}}{{domxref("Event")}}Pointer LockThe pointer was locked or released.
{{event("pointerlockerror")}}{{domxref("Event")}}Pointer LockIt was impossible to lock the pointer for technical reasons or because the permission was denied.
{{event("play")}}{{domxref("Event")}}HTML5 mediaPlayback has begun.
{{event("playing")}}{{domxref("Event")}}HTML5 mediaPlayback is ready to start after having been paused or delayed due to lack of data.
{{event("popstate")}}{{domxref("PopStateEvent")}}HTML5A session history entry is being navigated to (in certain cases).
{{event("progress")}}{{domxref("ProgressEvent")}}Progress and XMLHttpRequestIn progress.
progress{{domxref("ProgressEvent")}}OfflineThe user agent is downloading resources listed by the manifest.
{{event("ratechange")}}{{domxref("Event")}}HTML5 mediaThe playback rate has changed.
{{event("readystatechange")}}{{domxref("Event")}}HTML5 and XMLHttpRequestThe readyState attribute of a document has changed.
{{event("repeatEvent")}}{{domxref("TimeEvent")}}SVGA SMIL animation element is repeated.
{{event("reset")}}{{domxref("Event")}}DOM L2, HTML5A form is reset.
{{event("resize")}}{{domxref("UIEvent")}}DOM L3The document view has been resized.
{{event("scroll")}}{{domxref("UIEvent")}}DOM L3The document view or an element has been scrolled.
{{event("seeked")}}{{domxref("Event")}}HTML5 mediaA seek operation completed.
{{event("seeking")}}{{domxref("Event")}}HTML5 mediaA seek operation began.
{{event("select")}}{{domxref("UIEvent")}}DOM L3Some text is being selected.
{{event("show")}}{{domxref("MouseEvent")}}HTML5A contextmenu event was fired on/bubbled to an element that has a contextmenu attribute
{{event("stalled")}}{{domxref("Event")}}HTML5 mediaThe user agent is trying to fetch media data, but data is unexpectedly not forthcoming.
{{event("storage")}}{{domxref("StorageEvent")}}Web StorageA storage area (localStorage or sessionStorage) has changed.
{{event("submit")}}{{domxref("Event")}}DOM L2, HTML5A form is submitted.
success{{domxref("Event")}}IndexedDBA request successfully completed.
{{event("suspend")}}{{domxref("Event")}}HTML5 mediaMedia data loading has been suspended.
{{event("SVGAbort")}}{{domxref("SVGEvent")}}SVGPage loading has been stopped before the SVG was loaded.
{{event("SVGError")}}{{domxref("SVGEvent")}}SVGAn error has occurred before the SVG was loaded.
{{event("SVGLoad")}}{{domxref("SVGEvent")}}SVGAn SVG document has been loaded and parsed.
{{event("SVGResize")}}{{domxref("SVGEvent")}}SVGAn SVG document is being resized.
{{event("SVGScroll")}}{{domxref("SVGEvent")}}SVGAn SVG document is being scrolled.
{{event("SVGUnload")}}{{domxref("SVGEvent")}}SVGAn SVG document has been removed from a window or frame.
{{event("SVGZoom")}}{{domxref("SVGZoomEvent")}}SVGAn SVG document is being zoomed.
{{event("timeout")}}{{domxref("ProgressEvent")}}XMLHttpRequest
{{event("timeupdate")}}{{domxref("Event")}}HTML5 mediaThe time indicated by the currentTime attribute has been updated.
{{event("touchcancel")}}{{domxref("TouchEvent")}}Touch EventsA touch point has been disrupted in an implementation-specific manners (too many touch points for example).
{{event("touchend")}}{{domxref("TouchEvent")}}Touch EventsA touch point is removed from the touch surface.
{{event("touchenter")}}{{domxref("TouchEvent")}}Touch Events RemovedA touch point is moved onto the interactive area of an element.
{{event("touchleave")}}{{domxref("TouchEvent")}}Touch Events RemovedA touch point is moved off the interactive area of an element.
{{event("touchmove")}}{{domxref("TouchEvent")}}Touch EventsA touch point is moved along the touch surface.
{{event("touchstart")}}{{domxref("TouchEvent")}}Touch EventsA touch point is placed on the touch surface.
{{event("transitionend")}}{{domxref("TransitionEvent")}}CSS TransitionsA CSS transition has completed.
{{event("unload")}}{{domxref("UIEvent")}}DOM L3The document or a dependent resource is being unloaded.
{{event("updateready")}}{{domxref("Event")}}OfflineThe resources listed in the manifest have been newly redownloaded, and the script can use swapCache() to switch to the new cache.
upgradeneededIndexedDBAn attempt was made to open a database with a version number higher than its current version. A versionchange transaction has been created.
{{event("userproximity")}}{{domxref("SensorEvent")}}SensorFresh data is available from a proximity sensor (indicates whether the nearby object is near the device or not).
versionchangeIndexedDBA versionchange transaction completed.
{{event("visibilitychange")}}{{domxref("Event")}}Page visibilityThe content of a tab has become visible or has been hidden.
{{event("volumechange")}}{{domxref("Event")}}HTML5 mediaThe volume has changed.
{{event("waiting")}}{{domxref("Event")}}HTML5 mediaPlayback has stopped because of a temporary lack of data.
{{event("wheel")}} {{gecko_minversion_inline("17")}}{{domxref("WheelEvent")}}DOM L3A wheel button of a pointing device is rotated in any direction.
+ +

非標準事件

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
事件名稱事件類型規範觸發時機
{{event("afterscriptexecute")}}{{domxref("Event")}}Mozilla SpecificA script has been executed.
{{event("beforescriptexecute")}}{{domxref("Event")}}Mozilla SpecificA script is about to be executed.
{{event("cardstatechange")}}Firefox OS specificThe {{domxref("MozMobileConnection.cardState")}} property changes value.
{{event("connectionInfoUpdate")}}Firefox OS specificThe informations about the signal strength and the link speed have been updated.
{{event("cfstatechange")}}Firefox OS specificThe call forwarding state changes.
{{event("datachange")}}Firefox OS specificThe {{domxref("MozMobileConnection.data")}} object changes values.
{{event("dataerror")}}Firefox OS specificThe {{domxref("MozMobileConnection.data")}} object receive an error from the RIL.
{{event("DOMMouseScroll")}} {{deprecated_inline}}Mozilla specificThe wheel button of a pointing device is rotated (detail attribute is a number of lines). (use {{event("wheel")}} instead)
dragdrop {{deprecated_inline}}DragEventMozilla specificAn element is dropped (use {{event("drop")}} instead).
dragexit {{deprecated_inline}}DragEventMozilla specificA drag operation is being ended(use {{event("dragend")}} instead).
draggesture {{deprecated_inline}}DragEventMozilla specificThe user starts dragging an element or text selection (use {{event("dragstart")}} instead).
{{event("icccardlockerror")}}Firefox OS specificthe {{domxref("MozMobileConnection.unlockCardLock()")}} or {{domxref("MozMobileConnection.setCardLock()")}} methods fails.
{{event("iccinfochange")}}Firefox OS specificThe {{domxref("MozMobileConnection.iccInfo")}} object changes.
{{event("localized")}}Mozilla SpecificThe page has been localized using data-l10n-* attributes.
{{event("mousewheel")}} {{deprecated_inline}}IE inventedThe wheel button of a pointing device is rotated.
{{event("MozAudioAvailable")}}{{domxref("Event")}}Mozilla specificThe audio buffer is full and the corresponding raw samples are available.
{{event("MozGamepadAxisMove")}}To be specifiedA gampad axis is moving.
{{event("MozGamepadButtonDown")}}To be specifiedA gamepad button is pressed down.
{{event("MozGamepadButtonUp")}}To be specifiedA gamepad button is released.
{{event("MozMousePixelScroll")}} {{deprecated_inline}}Mozilla specificThe wheel button of a pointing device is rotated (detail attribute is a number of pixels). (use wheel instead)
{{event("MozOrientation")}} {{deprecated_inline}}Mozilla specificFresh data is available from an orientation sensor (see deviceorientation).
{{event("MozScrolledAreaChanged")}}{{domxref("UIEvent")}}Mozilla specificThe document view has been scrolled or resized.
{{event("moztimechange")}}Mozilla specificThe time of the device has been changed.
MozTouchDown {{deprecated_inline}}Mozilla specificA touch point is placed on the touch surface (use touchstart instead).
MozTouchMove {{deprecated_inline}}Mozilla specificA touch point is moved along the touch surface (use touchmove instead).
MozTouchUp {{deprecated_inline}}Mozilla specificA touch point is removed from the touch surface (use touchend instead).
onalerting{{domxref("CallEvent")}}To be specifiedThe correspondent is being alerted (his/her phone is ringing).
onbusy{{domxref("CallEvent")}}To be specifiedThe line of the correspondent is busy.
oncallschanged{{domxref("CallEvent")}}To be specifiedA call has been added or removed from the list of current calls.
onconnected{{domxref("CallEvent")}}To be specifiedA call has been connected.
onconnecting{{domxref("CallEvent")}}To be specifiedA call is about to connect.
ondelivered{{domxref("SMSEvent")}}To be specifiedAn SMS has been successfully delivered.
ondialing{{domxref("CallEvent")}}To be specifiedThe number of a correspondent has been dialed.
{{event("ondisabled")}}Firefox OS specificWifi has been disabled on the device.
ondisconnected{{domxref("CallEvent")}}To be specifiedA call has been disconnected.
ondisconnecting{{domxref("CallEvent")}}To be specifiedA call is about to disconnect.
{{event("onenabled")}}Firefox OS specificWifi has been enabled on the device.
onerror{{domxref("CallEvent")}}To be specifiedAn error occurred.
onheld{{domxref("CallEvent")}}To be specifiedA call has been held.
onholding{{domxref("CallEvent")}}To be specifiedA call is about to be held.
onincoming{{domxref("CallEvent")}}To be specifiedA call is being received.
onreceived{{domxref("SMSEvent")}}To be specifiedAn SMS has been received.
onresuming{{domxref("CallEvent")}}To be specifiedA call is about to resume.
onsent{{domxref("SMSEvent")}}To be specifiedAn SMS has been sent.
onstatechange{{domxref("CallEvent")}}To be specifiedThe state of a call has changed.
onstatuschangeFirefox OS specificThe status of the Wifi connection changed.
{{event("overflow")}}{{domxref("UIEvent")}}Mozilla specificAn element has been overflowed by its content or has been rendered for the first time in this state (only works for elements styled with overflow != visible).
{{event("smartcard-insert")}}Mozilla specificA smartcard has been inserted.
{{event("smartcard-remove")}}Mozilla specificA smartcard has been removed.
{{event("stkcommand")}}Firefox OS specificThe STK Proactive Command is issued from ICC.
{{event("stksessionend")}}Firefox OS specificThe STK Session is terminated by ICC.
textMozilla SpecificA generic composition event occurred.
{{event("underflow")}}"{{domxref("UIEvent")}}Mozilla specificAn element is no longer overflowed by its content (only works for elements styled with overflow != visible).
uploadprogress {{deprecated_inline}}{{domxref("ProgressEvent")}}Mozilla SpecificUpload is in progress (see {{event("progress")}}).
{{event("ussdreceived")}}Firefox OS specificA new USSD message is received
{{event("voicechange")}}Firefox OS specificThe {{domxref("MozMobileConnection.voice")}} object changes values.
+ +

Mozilla 專屬事件

+ +
+

Note: 以下事件從未在網頁上觸發。它們僅在能在 chrome content context 上使用。

+
+ +

XUL 事件

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
事件名稱事件類型規範觸發時機
{{event("broadcast")}}XULAn observer noticed a change to the attributes of a watched broadcaster.
{{event("CheckboxStateChange")}}XULThe state of a checkbox has been changed either by a user action or by a script (useful for accessibility).
closeXULThe close button of the window has been clicked.
{{event("command")}}XULAn element has been activated.
{{event("commandupdate")}}XULA command update occurred on a commandset element.
{{event("DOMMenuItemActive")}}XULA menu or menuitem has been hovered or highlighted.
{{event("DOMMenuItemInactive")}}XULA menu or menuitem is no longer hovered or highlighted.
{{event("popuphidden")}}PopupEventXULA menupopup, panel or tooltip has been hidden.
{{event("popuphiding")}}PopupEventXULA menupopup, panel or tooltip is about to be hidden.
{{event("popupshowing")}}PopupEventXULA menupopup, panel or tooltip is about to become visible.
{{event("popupshown")}}PopupEventXULA menupopup, panel or tooltip has become visible.
{{event("RadioStateChange")}}XULThe state of a radio has been changed either by a user action or by a script (useful for accessibility).
{{event("ValueChange")}}XULThe value of an element has changed (a progress bar for example, useful for accessibility).
+ +

附加元件專屬事件

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
事件名稱事件類型規範觸發時機
MozSwipeGestureAddons specificA touch point is swiped across the touch surface
MozMagnifyGestureStartAddons specificTwo touch points start to move away from each other.
MozMagnifyGestureUpdateAddons specificTwo touch points move away from each other (after a MozMagnifyGestureStart).
MozMagnifyGestureAddons specificTwo touch points moved away from each other (after a sequence of MozMagnifyGestureUpdate).
MozRotateGestureStartAddons specificTwo touch points start to rotate around a point.
MozRotateGestureUpdateAddons specificTwo touch points rotate around a point (after a MozRotateGestureStart).
MozRotateGestureAddons specificTwo touch points rotate around a point (after a sequence of MozRotateGestureUpdate).
MozTapGestureAddons specificTwo touch points are tapped on the touch surface.
MozPressTapGestureAddons specificA "press-tap" gesture happened on the touch surface (first finger down, second finger down, second finger up, first finger up).
MozEdgeUIGestureAddons specificA touch point is swiped across the touch surface to invoke the edge UI (Win8 only).
MozAfterPaintAddons specificContent has been repainted.
MozBeforeResizeAddons specificA window is about to be resized.
DOMPopupBlockedAddons specificA popup has been blocked
DOMWindowCreatedAddons specificA window has been created.
DOMWindowCloseAddons specificA window is about to be closed.
DOMTitleChangedAddons specifcThe title of a window has changed.
DOMLinkAddedAddons specifcA link has been added a document.
DOMLinkRemovedAddons specifcA link has been removed inside from a document.
DOMMetaAddedAddons specificA meta element has been added to a document.
DOMMetaRemovedAddons specificA meta element has been removed from a document.
DOMWillOpenModalDialogAddons specificA modal dialog is about to open.
DOMModalDialogClosedAddons specificA modal dialog has been closed.
DOMAutoCompleteAddons specificThe content of an element has been auto-completed.
DOMFrameContentLoadedAddons specificThe frame has finished loading (but not its dependent resources).
AlertActiveAddons specificA notification element is shown.
AlertCloseAddons specificA notification element is closed.
fullscreenAddons specificBrowser fullscreen mode has been entered or left.
sizemodechangeAddons specificWindow has entered/left fullscreen mode, or has been minimized/unminimized.
MozEnteredDomFullscreenAddons specificDOM fullscreen mode has been entered.
SSWindowClosingAddons specificThe session store will stop tracking this window.
SSTabClosingAddons specificThe session store will stop tracking this tab.
SSTabRestoringAddons specificA tab is about to be restored.
SSTabRestoredAddons specificA tab has been restored.
SSWindowStateReadyAddons specificA window state has switched to "ready".
SSWindowStateBusyAddons specificA window state has switched to "busy".
tabviewsearchenabledAddons specificThe search feature of Panorama has been activated
tabviewsearchdisabledAddons specificThe search feature of Panorama has been deactivated
tabviewframeinitializedAddons specificThe frame container of Panorama has been initialized
tabviewshownAddons specificThe Panorama tab has been shown
tabviewhiddenAddons specificThe Panorama tab has been hidden
TabOpenAddons specificA tab has been opened.
TabCloseAddons specificA tab has been closed.
TabSelectAddons specificA tab has been selected.
TabShowAddons specificA tab has been shown.
TabHideAddons specificA tab has been hidden.
TabPinnedAddons specificA tab has been pinned.
TabUnpinnedAddons specificA tab has been unpinned.
+ +

開發者工具(Developer tool )專屬事件

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
事件名稱事件類型規範觸發時機
CssRuleViewRefresheddevtools specificThe "Rules" view of the style inspector has been updated.
CssRuleViewChangeddevtools specificThe "Rules" view of the style inspector has been changed.
CssRuleViewCSSLinkClickeddevtools specificA link to a CSS file has been clicked in the "Rules" view of the style inspector.
+ +

事件分類

+ +

動畫事件(Animation events)

+ +

{{event("animationend")}}, {{event("animationiteration")}}, {{event("animationstart")}}, {{event("beginEvent")}}, {{event("endEvent")}}, {{event("repeatEvent")}}

+ +

電池相關事件(Battery events)

+ +

{{event("chargingchange")}} {{event("chargingtimechange")}}, {{event("dischargingtimechange")}} {{event("levelchange")}}

+ +

電話事件(Call events)

+ +

{{event("alerting")}}, {{event("busy")}}, {{event("callschanged")}} {{event("cfstatechange")}}, {{event("connected")}}, {{event("connecting")}}, {{event("dialing")}}, {{event("disconnected")}}, {{event("disconnecting")}}, {{event("error_(Telephony)","error")}}, {{event("held")}}, {{event("holding")}}, {{event("incoming")}}, {{event("resuming")}}, {{event("statechange")}}, {{event("voicechange")}}

+ +

CSS 事件

+ +

CssRuleViewRefreshedCssRuleViewChangedCssRuleViewCSSLinkClicked, {{event("transitionend")}}

+ +

資料庫事件

+ +

abortblockedcomplete, {{event("error")}} (link), successupgradeneededversionchange

+ +

Document 事件

+ +

DOMLinkAddedDOMLinkRemovedDOMMetaAddedDOMMetaRemoved,DOMWillOpenModalDialogDOMModalDialogClosed, {{event("unload")}}

+ +

DOM mutation events

+ +

DOMAttributeNameChangedDOMAttrModifiedDOMCharacterDataModified, {{event("DOMContentLoaded")}}, DOMElementNameChangedDOMNodeInserted,DOMNodeInsertedIntoDocumentDOMNodeRemovedDOMNodeRemovedFromDocument,DOMSubtreeModified

+ +

拖曳事件

+ +

{{event("drag")}}, dragdrop, {{event("dragend")}}, {{event("dragenter")}}, dragexitdraggesture, {{event("dragleave")}}, {{event("dragover")}}, {{event("dragstart")}}, {{event("drop")}}

+ +

元素相關事件

+ +

{{event("invalid")}}, {{event("overflow")}}, {{event("underflow")}}, DOMAutoComplete, {{event("command")}}, {{event("commandupdate")}}

+ +

Focus events

+ +

{{event("blur")}}, {{event("change")}}, DOMFocusInDOMFocusOut, {{event("focus")}}, {{event("focusin")}}, {{event("focusout")}}

+ +

表單相關事件

+ +

{{event("reset")}}, {{event("submit")}}

+ +

Frame 相關事件

+ +

{{event("mozbrowserclose")}}, {{event("mozbrowsercontextmenu")}}, {{event("mozbrowsererror")}}, {{event("mozbrowsericonchange")}}, {{event("mozbrowserlocationchange")}}, {{event("mozbrowserloadend")}}, {{event("mozbrowserloadstart")}}, {{event("mozbrowseropenwindow")}}, {{event("mozbrowsersecuritychange")}}, {{event("mozbrowsershowmodalprompt")}} (link), {{event("mozbrowsertitlechange")}}, DOMFrameContentLoaded

+ +

Input device events

+ +

{{event("click")}}, {{event("contextmenu")}}, {{event("DOMMouseScroll")}}, {{event("dblclick")}}, {{event("gamepadconnected")}}, {{event("gamepaddisconnected")}}, {{event("keydown")}}, {{event("keypress")}}, {{event("keyup")}}, {{event("MozGamepadButtonDown")}}, {{event("MozGamepadButtonUp")}}, {{event("mousedown")}}, {{event("mouseenter")}}, {{event("mouseleave")}}, {{event("mousemove")}}, {{event("mouseout")}}, {{event("mouseover")}}, {{event("mouseup")}}, {{event("mousewheel")}}, {{event("MozMousePixelScroll")}}, {{event("pointerlockchange")}}, {{event("pointerlockerror")}},{{event("wheel")}}

+ +

多媒體事件

+ +

{{event("audioprocess")}}, {{event("canplay")}}, {{event("canplaythrough")}}, {{event("durationchange")}}, {{event("emptied")}}, {{event("ended")}}, {{event("ended_(Web_Audio)", "ended")}}, {{event("loadeddata")}}, {{event("loadedmetadata")}}, {{event("MozAudioAvailable")}}, {{event("pause")}}, {{event("play")}}, {{event("playing")}}, {{event("ratechange")}}, {{event("seeked")}}, {{event("seeking")}}, {{event("stalled")}}, {{event("suspend")}}, {{event("timeupdate")}}, {{event("volumechange")}}, {{event("waiting")}}, {{event("complete")}}

+ +

目錄事件

+ +

{{event("DOMMenuItemActive")}}, {{event("DOMMenuItemInactive")}}

+ +

網路相關事件

+ +

{{event("datachange")}}, {{event("dataerror")}}, {{event("disabled")}}, {{event("enabled")}}, {{event("offline")}}, {{event("online")}}, {{event("statuschange")}}, {{event("connectionInfoUpdate")}},

+ +

Notification events

+ +

AlertActiveAlertClose

+ +

Pointer events

+ +

{{event("pointerover")}}, {{event("pointerenter")}}, {{event("pointerdown")}}, {{event("pointermove")}}, {{event("pointerup")}}, {{event("pointercancel")}}, {{event("pointerout")}}, {{event("pointerleave")}}, {{event("gotpointercapture")}}, {{event("lostpointercapture")}}

+ + + +

{{event("popuphidden")}}, {{event("popuphiding")}}, {{event("popupshowing")}}, {{event("popupshown")}}, DOMPopupBlocked

+ +

列印相關事件

+ +

{{event("afterprint")}}, {{event("beforeprint")}}

+ +

Progress events

+ +

abort, {{event("error")}}, load, {{event("loadend")}}, {{event("loadstart")}}, {{event("progress")}},progress, {{event("timeout")}}, uploadprogress

+ +

Resource events

+ +

{{event("abort")}}, {{event("cached")}}, {{event("error")}}, {{event("load")}}

+ +

Script events

+ +

{{event("afterscriptexecute")}}, {{event("beforescriptexecute")}}

+ +

Sensor events

+ +

{{event("compassneedscalibration")}}, {{event("devicelight")}}, {{event("devicemotion")}}, {{event("deviceorientation")}}, {{event("deviceproximity")}}, {{event("MozOrientation")}}, {{event("orientationchange")}}, {{event("userproximity")}}

+ +

Session history events

+ +

{{event("pagehide")}}, {{event("pageshow")}}, {{event("popstate")}}

+ +

Smartcard events

+ +

{{event("icccardlockerror")}}, {{event("iccinfochange")}}, {{event("smartcard-insert")}}, {{event("smartcard-remove")}}, {{event("stkcommand")}}, {{event("stksessionend")}}, {{event("cardstatechange")}}

+ +

SMS and USSD events

+ +

{{event("delivered")}}, {{event("received")}}, {{event("sent")}}, {{event("ussdreceived")}}

+ +

Storage events

+ +

{{event("change")}} (see {{anch("Non-standard events")}}), {{event("storage")}}

+ +

SVG 事件

+ +

{{event("SVGAbort")}}, {{event("SVGError")}}, {{event("SVGLoad")}}, {{event("SVGResize")}}, {{event("SVGScroll")}}, {{event("SVGUnload")}}, {{event("SVGZoom")}}

+ +

Tab events

+ +

tabviewsearchenabledtabviewsearchdisabledtabviewframeinitializedtabviewshown,tabviewhiddenTabOpenTabCloseTabSelectTabShowTabHideTabPinnedTabUnpinned,SSTabClosingSSTabRestoringSSTabRestored, {{event("visibilitychange")}}

+ +

Text events

+ +

{{event("compositionend")}}, {{event("compositionstart")}}, {{event("compositionupdate")}}, {{event("copy")}}, {{event("cut")}}, {{event("paste")}}, {{event("select")}}, text

+ +

Touch events

+ +

MozEdgeUIGestureMozMagnifyGestureMozMagnifyGestureStartMozMagnifyGestureUpdate,MozPressTapGestureMozRotateGestureMozRotateGestureStartMozRotateGestureUpdate,MozSwipeGestureMozTapGestureMozTouchDownMozTouchMoveMozTouchUp, {{event("touchcancel")}}, {{event("touchend")}}, {{event("touchenter")}}, {{event("touchleave")}}, {{event("touchmove")}}, {{event("touchstart")}}

+ +

Update events

+ +

{{event("checking")}}, {{event("downloading")}}, {{event("error")}}, {{event("noupdate")}}, {{event("obsolete")}}, {{event("updateready")}}

+ +

Value change events

+ +

{{event("broadcast")}}, {{event("CheckboxStateChange")}}, {{event("hashchange")}}, {{event("input")}}, {{event("RadioStateChange")}}, {{event("readystatechange")}}, {{event("ValueChange")}}

+ +

View events

+ +

fullscreen, {{event("fullscreenchange")}}, {{event("fullscreenerror")}}, MozEnteredDomFullscreen, {{event("MozScrolledAreaChanged")}}, {{event("resize")}}, {{event("scroll")}}, sizemodechange

+ +

Websocket 事件

+ +

close, {{event("error")}}, messageopen

+ +

Window events

+ +

DOMWindowCreatedDOMWindowCloseDOMTitleChangedMozBeforeResize {{obsolete_inline}},SSWindowClosingSSWindowStateReadySSWindowStateBusyclose

+ +

尚未分類的事件

+ +

{{event("beforeunload")}}, {{event("localized")}}, messagemessagemessageMozAfterPaint, {{event("moztimechange")}}, open, {{event("show")}}

+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/events/load/index.html b/files/zh-tw/web/events/load/index.html new file mode 100644 index 0000000000..7c6d314925 --- /dev/null +++ b/files/zh-tw/web/events/load/index.html @@ -0,0 +1,88 @@ +--- +title: load +slug: Web/Events/load +translation_of: Web/API/Window/load_event +--- +

load 事件發生在加載完目標資源、該資源依賴的其他資源時。

+ +

一般資訊

+ +
+
規範
+
DOM L3
+
介面
+
UIEvent
+
起泡事件
+
No
+
可取消
+
No
+
對象
+
Window
+
預設行為
+
None.
+
+ +

屬性

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
target {{readonlyInline}}EventTargetThe event target (the topmost target in the DOM tree).
type {{readonlyInline}}DOMStringThe type of event.
bubbles {{readonlyInline}}BooleanWhether the event normally bubbles or not.
cancelable {{readonlyInline}}BooleanWhether the event is cancellable or not.
view {{readonlyInline}}WindowProxydocument.defaultView (window of the document)
detail {{readonlyInline}}long (float)0.
+ +

範例

+ +
<script>
+  window.addEventListener("load", function(event) {
+    console.log("All resources finished loading!");
+  });
+</script>
+
+ +

 

+ +

相關事件

+ + diff --git a/files/zh-tw/web/guide/ajax/getting_started/index.html b/files/zh-tw/web/guide/ajax/getting_started/index.html new file mode 100644 index 0000000000..7e27c1ebac --- /dev/null +++ b/files/zh-tw/web/guide/ajax/getting_started/index.html @@ -0,0 +1,287 @@ +--- +title: 入門篇 +slug: Web/Guide/AJAX/Getting_Started +tags: + - AJAX + - API + - Advanced + - JavaScript + - WebMechanics + - XMLHttpRequest +translation_of: Web/Guide/AJAX/Getting_Started +--- +

這篇文章說明 AJAX 相關技術的基礎,並提供兩個簡單的實際操作範例供您入門。

+ +

AJAX 是什麼?

+ +

AJAX 代表 Asynchronous JavaScript And XML,即非同步 JavaScript 及 XML。簡單地說,AJAX 使用 {{domxref("XMLHttpRequest")}} 物件來與伺服器進行通訊。它可以傳送並接收多種格式的資訊,包括 JSON、XML、HTML、以及文字檔案。AJAX 最吸引人的特點是「非同步」的本質,這代表它可以與伺服溝通、交換資料、以及更新頁面,且無須重整網頁。

+ +

有兩項即將討論到的特點如下︰

+ + + +

第一步 – 如何發出 HTTP 請求

+ +

為了使用 JavaScript 向伺服器發送 HTTP 請求,便需要一個能夠提供相關功能的類別實體(an instance of a class)。這樣的類別最初由 Internet Explorer 以 ActiveX 物件的方式引入,稱為 XMLHTTP。Mozilla、Safari 及其他瀏覽器則隨後跟進,實作了 XMLHttpRequest 類別,以提供微軟最初的 ActiveX 物件中的方法及屬性。

+ +

因此,為了建立能夠跨瀏覽器的物件實體,可以這麼寫:

+ +
// Old compatibility code, no longer needed.
+if (window.XMLHttpRequest) { // Mozilla, Safari, IE7+ ...
+    httpRequest = new XMLHttpRequest();
+} else if (window.ActiveXObject) { // IE 6 and older
+    httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
+}
+
+ +
備註:出於解說上的需要,上述代碼使用最簡方式建立 XMLHTTP 的實體。較貼近實際運用的範例,見第三步。
+ +

部分版本的 Mozilla 瀏覽器,在伺服器送回的資料未含 XML mime-type 標頭(header)時會出錯。為了避免這個問題,你可以用下列方法覆寫伺服器傳回的檔頭,以免傳回的不是 text/xml

+ +
httpRequest = new XMLHttpRequest();
+httpRequest.overrideMimeType('text/xml');
+
+ +

接下來是要決定伺服器傳回資料後的處理方式,此時你只要以 onreadystatechange 這個屬性指明要處理傳回值的 JavaScript 函式名稱即可,例如:

+ +
httpRequest.onreadystatechange = nameOfTheFunction;
+ +

注意,指定的函式名稱後不加括號也沒有參數。這只是簡單的賦值,而非真的呼叫函數。除了指定函式名稱外,你也能用 Javascript 即時定義函式的技巧(稱為〝匿名函數〞)來定一個新的處理函式,如下:

+ +
httpRequest.onreadystatechange = function(){
+    // 做些事
+};
+
+ +

決定處理方式之後你得確實發出 request,此時需叫用 HTTP request 類別的 open()send() 方法,如下:

+ +
httpRequest.open('GET', 'http://www.example.org/some.file', true);
+httpRequest.send();
+
+ + + +

send() 的參數在以 POST 發出 request 時,可以是任何想傳給伺服器的東西,而資料則以查詢字串的方式列出,例如:

+ +
"name=value&anothername="+encodeURIComponent(myVar)+"&so=on"
+ +

不過如果你想要以 POST 方式傳送資料,則必須先將 MIME 型態改好,如下:

+ +
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+
+ +

否則伺服器就不會理你傳過來的資料了。

+ +

第二步 – 處理伺服器傳回的資料

+ +

傳出 request 時必須提供處理傳回值的函數名稱,這個函數是用來處理伺服器的回應。

+ +
httpRequest.onreadystatechange = nameOfTheFunction;
+
+ +

那麼來看看這個函數該做些什麼。首先,它必須檢查 request 目前的狀態。如果狀態值為 4 代表伺服器已經傳回所有資訊了,便可以開始解析所得資訊。

+ +
if (httpRequest.readyState === XMLHttpRequest.DONE) {
+    // 一切 ok, 繼續解析
+} else {
+    // 還沒完成
+}
+
+ +

readyState 所有可能的值如下:

+ + + +

資料來源:MSDN

+ +

接下來要檢查伺服器傳回的 HTTP 狀態碼。所有狀態碼列表可於 W3C 網站上查到,但我們要管的是 200 OK 這種狀態。

+ +
if (httpRequest.status === 200) {
+    // 萬事具備
+} else {
+    // 似乎有點問題。
+    // 或許伺服器傳回了 404(查無此頁)
+    // 或者 500(內部錯誤)什麼的。
+}
+
+ +

檢查傳回的 HTTP 狀態碼後,要怎麼處理傳回的資料就由你決定了。有兩種存取資料的方式:

+ + + +

第三步 – 簡單範例

+ +

好,接著就做一次簡單的 HTTP 範例,演示方才的各項技巧。這段 JavaScript 會向伺服器要一份裡頭有「I'm a test.」字樣的 HTML 文件(test.html),而後以 alert() 將文件內容列出。

+ +
<button id="ajaxButton" type="button">Make a request</button>
+
+<script>
+(function() {
+  var httpRequest;
+  document.getElementById("ajaxButton").addEventListener('click', makeRequest);
+
+  function makeRequest() {
+    httpRequest = new XMLHttpRequest();
+
+    if (!httpRequest) {
+      alert('Giving up :( Cannot create an XMLHTTP instance');
+      return false;
+    }
+    httpRequest.onreadystatechange = alertContents;
+    httpRequest.open('GET', 'test.html');
+    httpRequest.send();
+  }
+
+  function alertContents() {
+    if (httpRequest.readyState === XMLHttpRequest.DONE) {
+      if (httpRequest.status === 200) {
+        alert(httpRequest.responseText);
+      } else {
+        alert('There was a problem with the request.');
+      }
+    }
+  }
+})();
+</script>
+
+ +

在此範例中:

+ + + +

你可以由此測試本例,也可以參考測試檔案

+ +
Note:如果你傳送一個要求到一段代碼,而這段代碼將回應XML而非靜態的HTML檔,那則必須要設定一個可以在IE中運作的header。如果我們不設定header  Content-Type: application/xml,IE將會在我們試圖運作的XML項目行下,回應一個"Object Expected" 的錯誤。
+ +
Note 2: 如果我們沒有設定header Cache-Control: no-cache,那瀏覽器將會藏匿response並且不再重新傳送request,造成除錯上的挑戰。我們也可以增加一個 always-different GET 參數,像是 timestamp 或 random number (詳見bypassing the cache)
+ +
Note 3: If the httpRequest variable is used globally, competing functions calling makeRequest() can overwrite each other, causing a race condition. Declaring the httpRequest variable local to a closure containing the AJAX functions avoids this.
+ +

In the event of a communication error (such as the server going down), an exception will be thrown in the onreadystatechange method when accessing the response status. To mitigate this problem, you could wrap your if...then statement in a try...catch:

+ +
function alertContents() {
+  try {
+    if (httpRequest.readyState === XMLHttpRequest.DONE) {
+      if (httpRequest.status === 200) {
+        alert(httpRequest.responseText);
+      } else {
+        alert('There was a problem with the request.');
+      }
+    }
+  }
+  catch( e ) {
+    alert('Caught Exception: ' + e.description);
+  }
+}
+
+ +

第四步 – 運用 XML 資料

+ +

前面的例子中,在收到 HTTP 傳回值後我們以物件的 reponseText 屬性接收 test.html 檔案的內容,接著來試試 responseXML 屬性。

+ +

首先,我們得做個格式正確的 XML 文件以便稍後取用。文件 (test.xml) 內容如下:

+ +
<?xml version="1.0" ?>
+<root>
+    I'm a test.
+</root>
+
+ +

在程式中,我們叫用檔案的地方只須略事修改如下:

+ +
...
+onclick="makeRequest('test.xml')">
+...
+
+ +

接著在 alertContents() 中,我們把 alert(http_request.responseText); 改成這樣:

+ +
var xmldoc = httpRequest.responseXML;
+var root_node = xmldoc.getElementsByTagName('root').item(0);
+alert(root_node.firstChild.data);
+
+ +

這樣一來我們便可取得 responseXML 所傳回的 XMLDocument 物件,而後以 DOM 方法取用 XML 文件的內容。你可以參考 test.xml 的原始碼 以及修改過後的測試程式

+ +

關於 DOM 方法,請參考 Mozilla DOM 文件。

+ +

Step 5 – Working with data

+ +

Finally, let's send some data to the server and receive a response. Our JavaScript will request a dynamic page this time, test.php, which will take the data we send and return a "computed" string - "Hello, [user data]!" - which we'll alert().

+ +

First we'll add a text box to our HTML so the user can enter their name:

+ +
<label>Your name:
+  <input type="text" id="ajaxTextbox" />
+</label>
+<span id="ajaxButton" style="cursor: pointer; text-decoration: underline">
+  Make a request
+</span>
+ +

We'll also add a line to our event handler to get the user's data from the text box and send it to the makeRequest() function along with the URL of our server-side script:

+ +
  document.getElementById("ajaxButton").onclick = function() {
+      var userName = document.getElementById("ajaxTextbox").value;
+      makeRequest('test.php',userName);
+  };
+
+ +

We need to modify makeRequest() to accept the user data and pass it along to the server. We'll change the request method from GET to POST, and include our data as a parameter in the call to httpRequest.send():

+ +
  function makeRequest(url, userName) {
+
+    ...
+
+    httpRequest.onreadystatechange = alertContents;
+    httpRequest.open('POST', url);
+    httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+    httpRequest.send('userName=' + encodeURIComponent(userName));
+  }
+
+ +

The function alertContents() can be written the same way it was in Step 3 to alert our computed string, if that's all the server returns. However, let's say the server is going to return both the computed string and the original user data. So if our user typed "Jane" in the text box, the server's response would look like this:

+ +

{"userData":"Jane","computedString":"Hi, Jane!"}

+ +

To use this data within alertContents(), we can't just alert the responseText, we have to parse it and alert computedString, the property we want:

+ +
function alertContents() {
+  if (httpRequest.readyState === XMLHttpRequest.DONE) {
+    if (httpRequest.status === 200) {
+      var response = JSON.parse(httpRequest.responseText);
+      alert(response.computedString);
+    } else {
+      alert('There was a problem with the request.');
+    }
+  }
+}
+ +

The test.php file should contain the following:

+ +
$name = (isset($_POST['userName'])) ? $_POST['userName'] : 'no name';
+$computedString = "Hi, " . $name;
+$array = ['userName' => $name, 'computedString' => $computedString];
+echo json_encode($array);
+ +

For more on DOM methods, be sure to check Mozilla's DOM implementation documents.

diff --git a/files/zh-tw/web/guide/ajax/index.html b/files/zh-tw/web/guide/ajax/index.html new file mode 100644 index 0000000000..8e6a49698f --- /dev/null +++ b/files/zh-tw/web/guide/ajax/index.html @@ -0,0 +1,119 @@ +--- +title: Ajax +slug: Web/Guide/AJAX +translation_of: Web/Guide/AJAX +--- +
入門篇
+Ajax 簡介。
+ +
+

非同步 JavaScript 及 XML(Asynchronous JavaScript and XML,AJAX) 並不能稱做是種「技術」,而是 2005 年時由 Jesse James Garrett 所發明的術語,描述一種使用數個既有技術的「新」方法。這些技術包括 HTMLXHTML層疊樣式表JavaScript文件物件模型XMLXSLT 以及最重要的 XMLHttpRequest 物件
+ 當這些技術被結合在 Ajax 模型中,Web 應用程式便能快速、即時更動介面及內容,不需要重新讀取整個網頁,讓程式更快回應使用者的操作。

+ +

雖然 X 在 Ajax 中代表 XML,但由於 JSON 的許多優點,如輕量以及其本身就是 JavaScript 的一部分等,讓現今 JSON 比起 XML 被更廣泛的使用。JSON 與 XML 兩者都被用來在 Ajax 模型中包裝資訊。

+
+ +
+
+

文件

+ +
+
入門篇
+
這篇文章會指引你瞭解 Ajax 的基礎知識並提供了兩個簡單的動手做範例來入門。
+
使用 XMLHttpRequest API
+
XMLHttpRequest API 是 Ajax 的核心。這篇文章將解釋如何使用一些 Ajax 技術,例如: + +
+
Fetch API
+
Fetch API 提供了取得資源(fetching resources)的介面(interface)。這似乎對於曾使用過 {{domxref("XMLHTTPRequest")}} 的人而言並不陌生,然而這個 API 提供一個更強大且彈性的功能集。
+
Server-sent events
+
傳統上來說,一個網頁必須送出 request 到伺服器來得到新的資料,也就是說,網頁藉由server-sent 事件從伺服器請求 (request) 資料,伺服器在任何時候都能送新的資料給網頁,藉由推送訊息到網頁。這些傳入的訊息可以被視為網頁中的 事件 + 資料,請參見 使用server-sent event 
+
Pure-Ajax navigation example
+
This article provides a working (minimalist) example of a pure-Ajax website composed only of three pages.
+
Sending and Receiving Binary Data
+
The responseType property of the XMLHttpRequest object can be set to change the expected response type from the server. Possible values are the empty string (default), "arraybuffer", "blob", "document", "json", and "text". The response property will contain the entity body according to responseType, as an ArrayBuffer, Blob, Document, JSON, or string. This article will show some Ajax I/O techniques.
+
XML
+
可擴展標記語言(The Extensible Markup Language, XML)是W3C推薦的用於創建特殊用途標記語言的通用標記語言。它是SGML的簡化子集,能夠描述許多不同類型的數據。其主要目的是促進不同系統間的數據共享,特別是通過網際網路連接的系統。
+
JXON
+
JXON 代表無損耗 Javascript XML Object Notation, 是一個通用名稱,用來定義使用 XML 的 Javascript 物件樹(JSON) 的通用名稱。
+
解析和序列化 XML
+
如何從一串字串,一個檔案中透過 Javascript 解析一個 XML 文件  ,以及如何將 XML 檔案序列化成字串、Javascript 物件樹(JXON) 或檔案。 
+
XPath
+
XPath stands for XML Path Language, it uses a non-XML syntax that provides a flexible way of addressing (pointing to) different parts of an XML document. As well as this, it can also be used to test addressed nodes within a document to determine whether they match a pattern or not.
+
The FileReader API
+
The FileReader API lets web applications asynchronously read the contents of files (or raw data buffers) stored on the user's computer, using File or Blob objects to specify the file or data to read. File objects may be obtained from a FileList object returned as a result of a user selecting files using the <input> element, from a drag and drop operation's DataTransfer object, or from the mozGetAsFile() API on an HTMLCanvasElement.
+
HTML in XMLHttpRequest
+
The W3C XMLHttpRequest specification adds HTML parsing support to XMLHttpRequest, which originally supported only XML parsing. This feature allows Web apps to obtain an HTML resource as a parsed DOM using XMLHttpRequest.
+
Other resources
+
Other Ajax resources you may find useful.
+
+ +

View All...

+ +

參見

+ +
+
Alternate Ajax Techniques
+
Most articles on Ajax have focused on using XMLHttp as the means to achieving such communication, but Ajax techniques are not limited to just XMLHttp. There are several other methods.
+
Ajax: A New Approach to Web Applications
+
Jesse James Garrett, of adaptive path, wrote this article in February 2005, introducing Ajax and its related concepts.
+
A Simpler Ajax Path
+
"As it turns out, it's pretty easy to take advantage of the XMLHttpRequest object to make a web app act more like a desktop app while still using traditional tools like web forms for collecting user input."
+
Ajax Mistakes
+
Alex Bosworth has written this article outlining some of the mistakes Ajax application developers can make.
+
Tutorial with examples.
+
 
+
XMLHttpRequest specification
+
W3C Working draft
+
+
+ + +
+ +

{{ListSubpages}}

diff --git a/files/zh-tw/web/guide/api/index.html b/files/zh-tw/web/guide/api/index.html new file mode 100644 index 0000000000..950affd971 --- /dev/null +++ b/files/zh-tw/web/guide/api/index.html @@ -0,0 +1,25 @@ +--- +title: Guide to Web APIs +slug: Web/Guide/API +tags: + - API + - Guide + - Landing + - NeedsTranslation + - TopicStub + - Web +translation_of: Web/Guide/API +--- +

Here you'll find links to each of the guides introducing and explaining each of the APIs that make up the Web development architecture.

+

Web APIs from A to Z

+ +

{{ListGroups}}

+ +

See also

+ + diff --git a/files/zh-tw/web/guide/dom/index.html b/files/zh-tw/web/guide/dom/index.html new file mode 100644 index 0000000000..997730a412 --- /dev/null +++ b/files/zh-tw/web/guide/dom/index.html @@ -0,0 +1,21 @@ +--- +title: DOM developer guide +slug: Web/Guide/DOM +tags: + - API + - DOM + - Guide + - NeedsTranslation + - TopicStub +translation_of: Web/API/Document_Object_Model +--- +

{{draft}}

+

The Document Object Model is an API for HTML and XML documents. It provides a structural representation of the document, enabling the developer to modify its content and visual presentation. Essentially, it connects web pages to scripts or programming languages.

+

All of the properties, methods, and events available to the web developer for manipulating and creating web pages are organized into objects (e.g., the document object that represents the document itself, the table object that represents a HTML table element, and so forth). Those objects are accessible via scripting languages in most recent web browsers.

+

The DOM is most often used in conjunction with JavaScript. However, the DOM was designed to be independent of any particular programming language, making the structural representation of the document available from a single, consistent API. Though we focus on JavaScript throughout this site, implementations of the DOM can be built for any language.

+

The World Wide Web Consortium establishes a standard for the DOM, called the W3C DOM. It should, now that the most important browsers correctly implement it, enable powerful cross-browser applications.

+

Why is the DOM important?

+

"Dynamic HTML" (DHTML) is a term used by some vendors to describe the combination of HTML, style sheets and scripts that allows documents to be animated. The W3C DOM Working Group is working hard to make sure interoperable and language-neutral solutions are agreed upon (see also the W3C FAQ). As Mozilla claims the title of "Web Application Platform", support for the DOM is one of the most requested features, and a necessary one if Mozilla wants to be a viable alternative to the other browsers.

+

Even more important is the fact that the user interface of Mozilla (also Firefox and Thunderbird) is built using XUL, using the DOM to manipulate its own UI.

+

More about the DOM

+

{{LandingPageListSubpages}}

diff --git a/files/zh-tw/web/guide/events/creating_and_triggering_events/index.html b/files/zh-tw/web/guide/events/creating_and_triggering_events/index.html new file mode 100644 index 0000000000..c198adaa5e --- /dev/null +++ b/files/zh-tw/web/guide/events/creating_and_triggering_events/index.html @@ -0,0 +1,144 @@ +--- +title: 建立或觸發事件 +slug: Web/Guide/Events/Creating_and_triggering_events +tags: + - Advanced + - DOM + - Guide + - JavaScript + - 事件 +translation_of: Web/Guide/Events/Creating_and_triggering_events +--- +

本文介紹如何建立和觸發事件。

+ +

建立自定義事件

+ +

事件可以用 {{domxref("Event")}} constructor 建立,如下所示:

+ +
var event = new Event('build');
+
+// 監聽事件
+elem.addEventListener('build', function (e) { ... }, false);
+
+// 觸發事件
+elem.dispatchEvent(event);
+ +

除了 Internet Explorer 以外,大多數的瀏覽器都支持這個 constructor 。若要能夠支援 Internet Explore 的更詳細的方法,可以參考段落《早期的做法》。

+ +

增加自定義的資料--CustomEvent()

+ +

要在事件的 object 追加其他資料,能使用 {{domxref("CustomEvent")}} 介面。它有 detail 屬性,可以用來傳送自訂資料。
+ 舉例來說,可以以下面方式建立事件:

+ +
var event = new CustomEvent('build', { 'detail': elem.dataset.time });
+ +

它可以讓你傳送自訂資料到事件的監聽器:

+ +
function eventHandler(e) {
+  log('The time is: ' + e.detail);
+}
+
+ +

早期的做法

+ +

早期建立事件的方式參考了 Java 的 API 。下為一個早期作法的例子:

+ +
// 建立事件
+var event = document.createEvent('Event');
+
+// 設定事件名稱為 “build” 。
+event.initEvent('build', true, true);
+
+// 監聽事件
+elem.addEventListener('build', function (e) {
+  // e.target matches elem
+}, false);
+
+// 事件對象可以是任一 HTML 元素或是 EventTarget 。
+elem.dispatchEvent(event);
+
+
+ +

觸發自定義事件

+ +

下面的例子演示了一個複選框藉由 DOM 的 methods 模擬一次點擊(換言之,讓程式執行一次「點擊事件」。)。 觀看實例

+ +
function simulateClick() {
+  var event = new MouseEvent('click', {
+    'view': window,
+    'bubbles': true,
+    'cancelable': true
+  });
+  var cb = document.getElementById('checkbox');
+  var canceled = !cb.dispatchEvent(event);
+  if (canceled) {
+    // A handler called preventDefault.
+    alert("canceled");
+  } else {
+    // None of the handlers called preventDefault.
+    alert("not canceled");
+  }
+}
+ +

瀏覽器的支援度

+ +

 

+ +

{{ CompatibilityTable() }}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)EdgeInternet ExplorerOperaSafari (WebKit)
Event() constructor1511{{CompatVersionUnknown}}{{CompatNo}}11.606
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}{{ CompatUnknown() }}6
+
+ +

延伸閱讀

+ + diff --git a/files/zh-tw/web/guide/events/event_handlers/index.html b/files/zh-tw/web/guide/events/event_handlers/index.html new file mode 100644 index 0000000000..519ac8bf90 --- /dev/null +++ b/files/zh-tw/web/guide/events/event_handlers/index.html @@ -0,0 +1,178 @@ +--- +title: DOM on-event 處理器 +slug: Web/Guide/Events/Event_handlers +translation_of: Web/Guide/Events/Event_handlers +--- +

Web 平台提供了多種獲得 DOM 事件通知的方式。兩種常見的風格為:通用的 {{domxref("EventTarget.addEventListener", "addEventListener()")}} 及一組特定的 on-event 處理器。本頁聚焦在後者如何運作的細節。

+ +

註冊 on-event 處理器

+ +

on-event 處理器為一群由 DOM 元素提供的屬性({{Glossary("property")}}),用來協助管理元素要如何應對事件。元素可以是具互動性的(如:links、buttons、images、forms)或非互動性的(如頁面基礎 document)。事件為一個操作,像是點擊(clicked)、偵測按下按鍵(pressed keys)、取得焦點(focus)等。on-event 處理器通常是根據它被設計來應對的事件,例如 onclickonkeypressonfocus 等等。

+ +

你可以使用兩種不同的方式來為一個物件的特定事件(例如:{{event("click")}})指定一個 on<...> 事件處理器:

+ + + +

Note that each object can have only one on-event handler for a given event (though that handler could call multiple sub-handlers). This is why {{domxref("EventTarget.addEventListener", "addEventListener()")}} is often the better way to get notified of events, especially when wishing to apply various event handlers independently from each other, even for the same event and/or to the same element.

+ +

Also note that on-event handlers are called automatically, not at the programmer's will (although you can, like mybutton.onclick(myevent); ) since they serve more as placeholders to which a real handler function can be assigned.

+ +

非元素物件

+ +

Event handlers can also be set using properties on many non-element objects that generate events, including {{ domxref("window") }}, {{ domxref("document") }}, {{ domxref("XMLHttpRequest") }}, and others, for example:

+ +
xhr.onprogress = function() { ... }
+ +

細節

+ +

HTML 的 on<...> 屬性值及對應的 JavaScript 屬性

+ +

A handler registered via an on<...> attribute will be available via the corresponding on<...> property, but not the other way around:

+ +
<div id="a" onclick="alert('old')">Open the Developer Tools Console to see the output.</div>
+
+<script>
+window.onload = function () {
+  var div = document.getElementById("a");
+  console.log("Attribute reflected as a property: ", div.onclick.toString());
+  // Prints: function onclick(event) { alert('old') }
+  div.onclick = function() { alert('new') };
+  console.log("Changed property to: ", div.onclick.toString());
+  // Prints: function () { alert('new') }
+  console.log("Attribute value is unchanged: ", div.getAttribute("onclick"));
+  // Prints: alert('old')
+}
+</script>
+ +

For historical reasons, some attributes/properties on the {{HTMLElement("body")}} and {{HTMLElement("frameset")}} elements actually set event handlers on their parent {{domxref("Window")}} object. (The HTML specification names these: onblur, onerror, onfocus, onload, onscroll.)

+ +

事件處理器的參數、this 綁定及回傳值

+ +

當一個事件處理被定義成為一個 HTML 的屬性時,給定的程式碼會被包成一個具有下列參數的函式:

+ + + +

當事件處理函式被觸發時,處理函式中的關鍵字: this 被設定成為註冊這個事件處理函式的DOM 元件。 請參閱 this 關鍵字說明 獲得更多細節。

+ +

The return value from the handler determines if the event is canceled. The specific handling of the return value depends on the kind of event, for details see "The event handler processing algorithm" in the HTML specification.

+ +

當事件處理器被調用

+ +

TBD (non-capturing listener)

+ +

術語

+ +

The term event handler may be used to refer to:

+ + + +

When discussing the various methods of listening to events,

+ + + +

規範

+ + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', 'webappapis.html#event-handler-attributes', 'event handlers')}}{{Spec2('HTML WHATWG')}}
{{SpecName('HTML5 W3C', 'webappapis.html#event-handler-attributes', 'event handlers')}}{{Spec2('HTML5 W3C')}}
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

Event handler changes in Firefox 9

+ +

In order to better match the specifications, and improve cross-browser compatibility, the way event handlers were implemented at a fundamental level changed in Gecko 9.0 {{ geckoRelease("9.0") }}.

+ +

Specifically, in the past, event handlers were not correctly implemented as standard IDL attributes. In Gecko 9.0, this was changed. Because of this, certain behaviors of event handlers in Gecko have changed. In particular, they now behave in all the ways standard IDL attributes behave. In most cases, this shouldn't affect web or add-on content at all; however, there are a few specific things to watch out for.

+ +

Detecting the presence of event handler properties

+ +

You can now detect the presence of an event handler property (that is, for example, onload), using the JavaScript in operator. For example:

+ +
if ("onsomenewfeature" in window) {
+  /* do something amazing */
+}
+
+ +

Event handlers and prototypes

+ +

You can't set or access the values of any IDL-defined attributes on DOM prototype objects; that means you can't, for example, change Window.prototype.onload anymore. In the past, event handlers (onload, etc.) weren't implemented as IDL attributes in Gecko, so you were able to do this for those. Now you can't. This improves compatibility.

diff --git a/files/zh-tw/web/guide/events/index.html b/files/zh-tw/web/guide/events/index.html new file mode 100644 index 0000000000..4484986b66 --- /dev/null +++ b/files/zh-tw/web/guide/events/index.html @@ -0,0 +1,52 @@ +--- +title: Event developer guide +slug: Web/Guide/Events +tags: + - DOM + - Event + - Guide + - NeedsTranslation + - NeedsUpdate + - TopicStub +translation_of: Web/Guide/Events +--- +

{{draft()}}

+ +

Events refers both to a design pattern used for the asynchronous handling of various incidents which occur in the lifetime of a web page and to the naming, characterization, and use of a large number of incidents of different types.

+ +

The overview page provides an introduction to the design pattern and a summary of the types of incidents which are defined and reacted to by modern web browsers.

+ +

The custom events page describes how the event code design pattern can be used in custom code to define new event types emitted by user objects, register listener functions to handle those events, and trigger the events in user code.

+ +

The remaining pages describe how to use events of different kinds defined by web browsers. Unfortunately, these events have been defined piece by piece as web browsers have evolved so that there is no satisfying systematic characterization of the events built-in or defined by modern web browsers.

+ +

The device on which the web browser is running can trigger events, for example due to a change in its position and orientation in the real world, as discussed partially by the page on orientation coordinate systems and the page on the use of 3D transforms. That is different, but similar, to the change in device vertical orientation.

+ +

The window in which the browser is displayed can trigger events; for example, change size if the user maximizes the window or otherwise changes it.

+ +

The process loading of a web page can trigger events in response to the completion of different steps in the downloading, parsing, and rendering of the web page for display to the user.

+ +

The user interaction with the web page contents can trigger events. The events triggered by user interaction evolved during the early years of browser design and include a complicated system defining the sequence in which events will be called and the manner in which that sequence can be controlled. The different types of user interaction-driven events include:

+ + + +

The modification of the web page in structure or content might trigger some events, as explained in the mutation events page, but the use of these events has been deprecated in favour of the lighter Mutation Observer approach.

+ +

The media streams embedded in the HTML documents might trigger some events, as explained in the media events page.

+ +

The network requests made by a web page might trigger some events.

+ +

There are many other sources of events defined by web browsers for which pages are not yet available in this guide.

+ +
+

Note: This Event Developer Guide needs substantial work. The structure needs to be reorganized and the pages rewritten. Our hope is that everything you need to know about events will go under here.

+
+ +

文件

+ +

{{LandingPageListSubpages}}

diff --git a/files/zh-tw/web/guide/graphics/index.html b/files/zh-tw/web/guide/graphics/index.html new file mode 100644 index 0000000000..224757c138 --- /dev/null +++ b/files/zh-tw/web/guide/graphics/index.html @@ -0,0 +1,49 @@ +--- +title: 網頁上的圖像 +slug: Web/Guide/Graphics +translation_of: Web/Guide/Graphics +--- +

現代網站或應用程式通常都配有圖像。我們可以很容易地使用{{HTMLElement("img")}}元素呈現靜態圖像 , 或藉由使用{{cssxref("background-image")}} 設定HTML的背景元素性質。你常會想要建立動態圖像或在事後操縱圖像。這些文章將讓你知道如何達成這些效果。

+ +
+
+

2D 圖像

+ +
+
Canvas
+
{{HTMLElement("canvas")}} 元素提供 APIs讓開發者透過Javascript來繪製2D圖像.
+
SVG
+
可縮放向量圖像(SVG) 讓你可以使用直線,曲線以及其他幾何圖形來編寫圖像。避免使用點陣圖像(bitmaps),你可以創造出適合任何大小的圖像。
+
+ +

 

+ +

 

+ +

 

+ +

 

+ +

觀看全部...

+
+ +
+

3D 圖像

+ +
+
WebGL
+
一份WebGL初始指南,網頁用3D 圖像 API。這項技術讓你在網頁內容使用standard OpenGL ES。
+
+ +

影片

+ +
+
使用 HTML5 影音
+
在 HTML 檔案嵌入影片及控制播放。
+
WebRTC
+
在WebRTC 中 RTC 是 Real-Time Communications 的簡稱,讓瀏覽器客戶端之間(peers)串流影片/音效檔案與數據分享的技術。
+
+
+
+ +

 

diff --git a/files/zh-tw/web/guide/html/content_categories/index.html b/files/zh-tw/web/guide/html/content_categories/index.html new file mode 100644 index 0000000000..707e63ca85 --- /dev/null +++ b/files/zh-tw/web/guide/html/content_categories/index.html @@ -0,0 +1,150 @@ +--- +title: 內容類型 +slug: Web/Guide/HTML/Content_categories +translation_of: Web/Guide/HTML/Content_categories +--- +

每個 HTML 元素都要遵從該元素可擁有何種內容規則,這些規則被歸為幾種常用的內容模型(content model)。每個 HTML 元素都屬於零個、一個、或數個內容的模型,所有元素內容的設置規則都要遵從 HTML 一致性文件。

+ +

內容類型有三種類型:

+ + + +
Content_categories_venn.png
+ +

主要內容類型

+ +

資訊元內容(Metadata content)

+ +

屬於元資訊內容類型的元素修飾該文件其餘部分的陳述或行為、與其他文件建立連結、或是傳達其他外來(out of band)訊息。

+ +

屬於這個類型的元素有 {{HTMLElement("base")}}、{{ Obsolete_inline() }}{{HTMLElement("command")}}、{{HTMLElement("link")}}、{{HTMLElement("meta")}}、{{HTMLElement("noscript")}}、{{HTMLElement("script")}}、{{HTMLElement("style")}} 與 {{HTMLElement("title")}}

+ +

流內容(Flow content)

+ +

屬於流內容的元素通常含有文字或嵌入內容。它們是:{{HTMLElement("a")}}、{{HTMLElement("abbr")}}、{{HTMLElement("address")}}、{{HTMLElement("article")}}、{{HTMLElement("aside")}}、{{HTMLElement("audio")}}、{{HTMLElement("b")}},{{HTMLElement("bdo")}}、{{HTMLElement("bdi")}}、{{HTMLElement("blockquote")}}、{{HTMLElement("br")}}、{{HTMLElement("button")}}、{{HTMLElement("canvas")}}、{{HTMLElement("cite")}}、{{HTMLElement("code")}}、{{ Obsolete_inline() }}{{HTMLElement("command")}}、{{HTMLElement("data")}}、{{HTMLElement("datalist")}}、{{HTMLElement("del")}}、{{HTMLElement("details")}}、{{HTMLElement("dfn")}}、{{HTMLElement("div")}}、{{HTMLElement("dl")}}、{{HTMLElement("em")}}、{{HTMLElement("embed")}}、{{HTMLElement("fieldset")}}、{{HTMLElement("figure")}}、{{HTMLElement("footer")}}、{{HTMLElement("form")}}、{{HTMLElement("h1")}}、{{HTMLElement("h2")}}、{{HTMLElement("h3")}}、{{HTMLElement("h4")}}、{{HTMLElement("h5")}}、{{HTMLElement("h6")}}、{{HTMLElement("header")}}、{{HTMLElement("hgroup")}}、{{HTMLElement("hr")}}、{{HTMLElement("i")}}、{{HTMLElement("iframe")}}、{{HTMLElement("img")}}、{{HTMLElement("input")}}、{{HTMLElement("ins")}}、{{HTMLElement("kbd")}}、{{deprecated_inline()}}{{HTMLElement("keygen")}}、{{HTMLElement("label")}}、{{HTMLElement("main")}}、{{HTMLElement("map")}}、{{HTMLElement("mark")}}、{{MathMLElement("math")}}、{{HTMLElement("menu")}}、{{HTMLElement("meter")}}、{{HTMLElement("nav")}}、{{HTMLElement("noscript")}}、{{HTMLElement("object")}}、{{HTMLElement("ol")}}、{{HTMLElement("output")}}、{{HTMLElement("p")}}、{{HTMLElement("pre")}}、{{HTMLElement("progress")}}、{{HTMLElement("q")}}、{{HTMLElement("ruby")}}、{{HTMLElement("s")}}、{{HTMLElement("samp")}}、{{HTMLElement("script")}}、{{HTMLElement("section")}}、{{HTMLElement("select")}}、{{HTMLElement("small")}}、{{HTMLElement("span")}}、{{HTMLElement("strong")}}、{{HTMLElement("sub")}}、{{HTMLElement("sup")}}、{{SVGElement("svg")}}、{{HTMLElement("table")}}、{{HTMLElement("template")}}、{{HTMLElement("textarea")}}、{{HTMLElement("time")}}、{{HTMLElement("ul")}}、{{HTMLElement("var")}}、{{HTMLElement("video")}}、{{HTMLElement("wbr")}} 還有文字。

+ +

在滿足特定條件下,某些元素也屬這個類型:

+ + + +

章節型內容(Sectioning content)

+ +

屬於章節型內容模型的元素會在該大綱裡面創立章節,這個章節會定義{{HTMLElement("header")}}、{{HTMLElement("footer")}}、還有heading content的範圍。

+ +

屬於這個類型的元素有{{HTMLElement("article")}}、{{HTMLElement("aside")}}、{{HTMLElement("nav")}}還有{{HTMLElement("section")}}。

+ +
+

注意:不要把這個內容模型,和把內容與常規大綱隔開的 sectioning root 類別搞混。

+
+ +

標題型內容(Heading content)

+ +

标题内容 定义了分节的标题,而这个分节可能由一个明确的分节内容元素直接标记,也可能由标题本身隐式地定义。

+ +

標題型內容定義了章節的標題,不論該章節由明確的章節型內容元素標記、抑或由標題本身隱式定義。

+ +

屬於這個類型的元素有{{HTMLElement("h1")}}、{{HTMLElement("h2")}}、{{HTMLElement("h3")}}, {{HTMLElement("h4")}}、{{HTMLElement("h5")}}、{{HTMLElement("h6")}}還有{{HTMLElement("hgroup")}}.

+ +
+

注意:儘管 {{HTMLElement("header")}} 可能含有某些標題型內容,但它本身並不是。

+
+ +

段落型內容(Phrasing content)

+ +

段落型內容定義了文字、還有它包含的標記。Runs of phrasing content make up paragraphs.

+ +

屬於這個類型的元素有{{HTMLElement("abbr")}}、{{HTMLElement("audio")}}、{{HTMLElement("b")}}、{{HTMLElement("bdo")}}、{{HTMLElement("br")}}、{{HTMLElement("button")}}、{{HTMLElement("canvas")}}、{{HTMLElement("cite")}}、{{HTMLElement("code")}}、{{ Obsolete_inline() }}{{HTMLElement("command")}}、{{HTMLElement("datalist")}}、{{HTMLElement("dfn")}}、{{HTMLElement("em")}}、{{HTMLElement("embed")}}、{{HTMLElement("i")}}、{{HTMLElement("iframe")}}、{{HTMLElement("img")}}、{{HTMLElement("input")}}、{{HTMLElement("kbd")}}、{{deprecated_inline()}}{{HTMLElement("keygen")}}、{{HTMLElement("label")}}、{{HTMLElement("mark")}}、{{MathMLElement("math")}}、{{HTMLElement("meter")}}、{{HTMLElement("noscript")}}、{{HTMLElement("object")}}、{{HTMLElement("output")}}、{{HTMLElement("progress")}}、{{HTMLElement("q")}}、{{HTMLElement("ruby")}}、{{HTMLElement("samp")}}、{{HTMLElement("script")}}、{{HTMLElement("select")}}、{{HTMLElement("small")}}、{{HTMLElement("span")}}、{{HTMLElement("strong")}}、{{HTMLElement("sub")}}、{{HTMLElement("sup")}}、{{SVGElement("svg")}}、{{HTMLElement("textarea")}}、{{HTMLElement("time")}}、{{HTMLElement("var")}}、{{HTMLElement("video")}}、{{HTMLElement("wbr")}}以及空白字符在內的純文本。

+ +

在滿足特定條件下,某些元素也屬這個類型:

+ + + +

嵌入型內容(Embedded content)

+ +

嵌入型內容從其他標記語言或文件命名空間,導入資源或插入內容。 屬於這個類型的元素有{{HTMLElement("audio")}}、{{HTMLElement("canvas")}}、{{HTMLElement("embed")}}、{{HTMLElement("iframe")}}、{{HTMLElement("img")}}、{{MathMLElement("math")}}、{{HTMLElement("object")}}、{{SVGElement("svg")}}、{{HTMLElement("video")}}。

+ +

互動型內容(Interactive content)

+ +

互動型內容包含專為用戶互動設計的元素。屬於這個類型的元素有 {{HTMLElement("a")}}、{{HTMLElement("button")}}、{{HTMLElement("details")}}、{{HTMLElement("embed")}}、{{HTMLElement("iframe")}}、{{deprecated_inline()}}{{HTMLElement("keygen")}}、{{HTMLElement("label")}}、{{HTMLElement("select")}} 還有 {{HTMLElement("textarea")}}。

+ +

在滿足特定條件下,某些元素也屬這個類型:

+ + + +

捫及內容(Palpable content)

+ +

不是空白或隱藏的內容稱為捫及。屬於流內容或是Phrasing content模型的元素最少要有一個捫及的節點。

+ +

表單相關內容(Form-associated content)

+ +

表單相關內容包含了由 form 屬性顯露的 form owner 元素。form owner 是本身包含於 {{HTMLElement("form")}}、或 id 由 form 屬性指定的元素。

+ + + +

本類型包含某些子類別:

+ +
+
listed
+
Elements that are listed in the form.elements and fieldset.elements IDL collections. Contains {{HTMLElement("button")}}, {{HTMLElement("fieldset")}}, {{HTMLElement("input")}}, {{deprecated_inline()}}{{HTMLElement("keygen")}}, {{HTMLElement("object")}}, {{HTMLElement("output")}}, {{HTMLElement("select")}}, and {{HTMLElement("textarea")}}.
+
labelable
+
與元素 {{HTMLElement("label")}} 相關的元素。包含 {{HTMLElement("button")}}、{{HTMLElement("input")}}、{{deprecated_inline()}}{{HTMLElement("keygen")}}、{{HTMLElement("meter")}}、{{HTMLElement("output")}}、{{HTMLElement("progress")}}、{{HTMLElement("select")}}、{{HTMLElement("textarea")}}。
+
submittable
+
用在建構送出時,資料就設定好的表單元素。包含 {{HTMLElement("button")}}、{{HTMLElement("input")}}、{{deprecated_inline()}}{{HTMLElement("keygen")}}、{{HTMLElement("object")}}、{{HTMLElement("select")}}、{{HTMLElement("textarea")}}。
+
resettable
+
當表單重設時會受影響的元素。包含 {{HTMLElement("button")}}、{{HTMLElement("input")}}、{{deprecated_inline()}}{{HTMLElement("keygen")}}、{{HTMLElement("output")}}、{{HTMLElement("select")}}、{{HTMLElement("textarea")}}。
+
+ +

透明內容模型(Transparent content model)

+ +

如果一個元素是透明內容模型,then its contents must be structured such that they would be valid HTML 5,就算該透明元素被移除、並由子元素取代。

+ +

例如,{{HTMLElement("del")}} 與 {{HTMLELement("ins")}} 元素都是透明的:

+ +
<p>我們認為下面這些真理是<del><em>神聖不可否認</em></del><ins>不言而喻的。</ins></p>
+
+ +

這果這些元素被刪掉的話,這個分段依然在 HTML 有效(if not correct English)

+ +
<p>我們認為下面這些真理是<em>神聖不可否認</em>不言而喻的。</p>
+
+ + +

其他內容模型

+ +

章節根(Sectioning root)

diff --git a/files/zh-tw/web/guide/html/event_attributes/index.html b/files/zh-tw/web/guide/html/event_attributes/index.html new file mode 100644 index 0000000000..6f57526dde --- /dev/null +++ b/files/zh-tw/web/guide/html/event_attributes/index.html @@ -0,0 +1,84 @@ +--- +title: Event attributes +slug: Web/Guide/HTML/Event_attributes +translation_of: >- + Learn/JavaScript/Building_blocks/Events#Inline_event_handlers_%E2%80%94_don%27t_use_these +--- +

每一個 HTML 元素都可以放置事件屬性,以藉此於事件發生時能執行 JavaScripte 程式。事件屬性的名稱都有一個前綴「on」,例如當使用者點選元素時要執行指定的 JavaScript,可以使用 onclick 屬性並把要執行的 JavaScript 當成屬性值。

+ +

In the JavaScript code executed in response to the event, this is bound to the HTML element and the {{domxref("Event")}} object can be reached using the event variable in the scope of the attribute.

+ +
+

Warning: These attributes should be avoided. This makes the markup bigger and less readable. Concerns of content/structure and behavior are not well-separated, making a bug harder to find. Furthermore, usage of event attributes almost always causes scripts to expose global functions on the {{domxref("Window")}} object, polluting the global namespace.

+
+ +

While these attributes can at times be attractively easy to use, you should avoid using them. Instead, use the {{domxref("EventTarget.addEventListener()")}} function to add a listener for the event.

+ +

Event attributes can be blocked by using Content Security Policy which if used, blocks all inline scripts unless the 'unsafe-inline' keyword is used.

+ +

Example using event attributes

+ +

This example appends text to an element each time time the {{HTMLElement("div")}} is clicked.

+ +
+

Note: This is an example of how not to do things, using one of these attributes.

+
+ +
<!doctype html>
+<html>
+  <head>
+    <title>Event Attribute Example</title>
+    <script>
+      function doSomething() {
+        document.getElementById("thanks").innerHTML += "<p>Thanks for clicking!</p>";
+      }
+    </script>
+  </head>
+  <body>
+    <div onclick="doSomething();">Click me!</div>
+    <div id="thanks"></div>
+  </body>
+</html>
+
+ +

Try this example below:

+ +

{{ EmbedLiveSample('Example_using_event_attributes', '', '', '') }}

+ +

Example using event listeners

+ +

Instead, you should use {{domxref("EventTarget.addEventListener()")}}, as shown here:

+ +
<!doctype html>
+<html>
+  <head>
+    <title>Event Attribute Example</title>
+    <script>
+      function doSomething() {
+        document.getElementById("thanks").innerHTML += "<p>Thanks for clicking!</p>";
+      }
+
+      // Called when the page is done loading; this is where we do any setup we need,
+      // such as creating event listeners for the elements in the page.
+
+      function setup() {
+        document.getElementById("click").addEventListener("click", doSomething, true);
+      }
+
+      // Install an event handler on the window to receive the "load" event, which
+      // indicates that the document has finished loading into the window.
+
+      window.addEventListener("load", setup, true);
+    </script>
+  </head>
+  <body>
+    <div id="click">Click me!</div>
+    <div id="thanks"></div>
+  </body>
+</html>
+ +

You can see this in action below:

+ +

{{ EmbedLiveSample('Example_using_event_listeners', '', '', '') }}

+ + diff --git a/files/zh-tw/web/guide/html/html5/index.html b/files/zh-tw/web/guide/html/html5/index.html new file mode 100644 index 0000000000..c1ea8252ef --- /dev/null +++ b/files/zh-tw/web/guide/html/html5/index.html @@ -0,0 +1,112 @@ +--- +title: HTML5 +slug: Web/Guide/HTML/HTML5 +translation_of: Web/Guide/HTML/HTML5 +--- +

HTML5 是 HTML 標準中的最新版。在 HTML5 規格還未拍板定案之前,Mozilla 以及其他瀏覽器開發商已經著手實現其中的部分功能。本文所列的連結網址與相關內容,是 Mozilla  Gecko 解析引擎已經支援的部份,Firefox許多其他產品都使用 Gecko 解析引擎。

+ +

(這裡是 另一篇 HTML5 分類整理文章。)

+ +

HTML5 簡介

+ +
+
HTML5 簡介
+
這篇文章介紹如何在你的網頁設計或 Web 應用程式中使用 HTML5。
+
+ +

HTML5 元素

+ +
+
使用 audio 和 video {{ gecko_minversion_inline("1.9.2") }}
+
Firefox 3.5 開始支援 HTML5 {{ HTMLElement("audio") }} 和 {{ HTMLElement("video") }} 兩個元素。
+
HTML5 表單 {{ gecko_minversion_inline("2.0") }}
+
簡單介紹 HTML5 對於 Web 表單的改進項目:限制條件與驗證 API、多個新增的屬性、新增多個值供 {{ HTMLElement("input") }} 的 {{ htmlattrxref("type", "input") }} 屬性使用,並且新增 {{ HTMLElement("output") }} 元素。
+
Sections 和 outlines {{ gecko_minversion_inline("2.0") }}
+
HTML5 對於大綱與分段的支援元素包含有: {{ HTMLElement("section") }}、{{ HTMLElement("article") }}、{{ HTMLElement("nav") }}、{{ HTMLElement("header") }}、{{ HTMLElement("footer") }}、{{ HTMLElement("aside") }} 以及 {{ HTMLElement("hgroup") }}。
+
元素 {{ HTMLElement("mark") }} {{ gecko_minversion_inline("2.0") }}
+
元素 mark 被用在標註特別相關的重點文字。
+
元素 {{ HTMLElement("figure") }} 和 {{ HTMLElement("figcaption") }} {{ gecko_minversion_inline("2.0") }}
+
These elements lets you add figures and illustration, with an eventual caption, loosely coupled to the main text.
+
+ +

支援 Canvas

+ +
+
Canvas 導覽 {{ gecko_minversion_inline("1.8.1") }}
+
 學習如何使用新的 {{ HTMLElement("canvas") }} 元素,以及如何在 Firefox 中繪製圖表與其他物件。
+
<canvas> 元素的 HTML5 文字(text) API {{ gecko_minversion_inline("1.9.1") }}
+
{{ HTMLElement("canvas") }} 元素現在已經支援 HTML5 文字(text) API。
+
+ +

給 Web 應用程式的新功能

+ +
+
Firefox 中的離線資源(含 HTML5 Application Cache 介紹)  {{ gecko_minversion_inline("1.9.1") }}
+
Firefox 完整支援 HTML5 離線資源規格。
+
上線與離線事件 (Online and offline events) {{ gecko_minversion_inline("1.9") }}
+
Firefox 3 支援 WHATWG 的上線與離線事件,這讓應用程式與擴充套件可以偵測目前是否有可用的 Internet 連線,也可以偵測何時建立或結束這個網路連線。
+
WHATWG 用戶端 session 與持續性儲存 (persistent storage) (亦稱 DOM 儲存) {{ gecko_minversion_inline("1.8.1") }}
+
用戶端 session 與持續性儲存功能,讓 web 應用程式可以在用戶端儲存結構性資料。
+
屬性 contentEditable ,將你的網站變成 wiki ! {{ gecko_minversion_inline("1.9.1") }}
+
HTML5 已經將 contentEditable 屬性標準化。學習更多這個新功能。
+
在 web 應用程式中存取檔案 {{ gecko_minversion_inline("1.9.2") }}
+
Gecko 已經支援新的 HTML5 檔案 API,讓 web 應用程式可以存取使用者所選的本地端檔案。這個功能也包含使用檔案類型的輸入元素 {{ HTMLElement("input") }}  type file 的新屬性 multiple 來選取多個檔案。
+
+ +

DOM 新功能

+ +
+
getElementsByClassName {{ fx_minversion_inline(3.0) }}
+
支援 Document 與 Element 節點的 getElementsByClassName 方法。這個方法允許藉由指定的一個或多個 class 尋找頁面中的元素。
+
拖曳功能 (Drag and drop) {{ fx_minversion_inline(3.5) }}
+
HTML5 拖曳 API 支援在一個或多個網站之間拖曳物件。也提供了一個更簡化的 API 供擴充套件與 Mozilla-based 應用程式使用。
+
HTML Focus 管理 {{ fx_minversion_inline(3.0) }}
+
支援新的 HTML5 屬性:activeElementhasFocus
+
Web-based 協定處理器 {{ fx_minversion_inline(3.0) }}
+
你現在可以使用 navigator.registerProtocolHandler() 方法將 web 應用程式註冊成協定處理器 (protocol handlers)。
+
+ +

HTML 解析器

+ +

Gecko 的 HTML5相容解析器 — 負責將一份 HTML 文件字元們轉化為 DOM — 已經於 2010 年五月預設為啟用。(備忘:該 HTML5 解析器版本搭載於 Gecko 1.9.2 / Firefox 3.6 當中,是個不穩定的版本,並且不建議用於正式使用環境。) {{ fx_minversion_inline(4.0) }}

+ +

其他

+ + + +

有些人自以為它是 HTML5 的一部分……XD

+ + + +

參考

+ + + +

{{ HTML5ArticleTOC() }}

+ +

{{ languages( {"es": "es/HTML/HTML5", "fr": "fr/HTML/HTML5", "ja": "ja/HTML/HTML5" , "ko": "ko/HTML/HTML5" , "pt": "pt/HTML/HTML5", "zh-cn": "cn/HTML/HTML5", "zh-tw": "zh_tw/HTML/HTML5", "pt-br": "pt-br/HTML/HTML5"} ) }}

diff --git a/files/zh-tw/web/guide/html/html5/introduction_to_html5/index.html b/files/zh-tw/web/guide/html/html5/introduction_to_html5/index.html new file mode 100644 index 0000000000..7e2eba7335 --- /dev/null +++ b/files/zh-tw/web/guide/html/html5/introduction_to_html5/index.html @@ -0,0 +1,40 @@ +--- +title: Introduction to HTML5 +slug: Web/Guide/HTML/HTML5/Introduction_to_HTML5 +tags: + - HTML + - HTML5 +translation_of: Web/Guide/HTML/HTML5/Introduction_to_HTML5 +--- +

HTML5 是目前最新的HTML標準。它提供一些新特性,不只是支援多媒體,還讓網頁應用程式可以更容易、更有效地與使用者、伺服器互動。

+ +

目前,仍有一些瀏覽器未完全支援HTML5所有特性。但是使用Gecko解析引擎的Firefox已經對HTML5十分支持,現時還繼續開發去支援更多特性。Gecko已經在1.8.1版本開始支持一些HTML5 了。你可以在main HTML5 page找到Gecko解析引擎最近支援的HTML5特性列表。若要更仔細知道多種瀏覽器支援的情況,可瀏覽CanIUse

+ +

建立HTML5文件並宣告HTML5 doctype

+ +

要建立HTML5文件很簡單,只需要在文件開首宣告:

+ +
<!DOCTYPE html>
+
+ +

對於未支援HTML5標準的瀏覽器,瀏覽器會繼續解析,但要注意一些HTML5的新特性則會忽略、不會支援。

+ +

然而這個宣告方法比以前HTML版本更簡單、更短,更容易記憶,亦減少文件容量。

+ +

利用<meta charset>來宣告字符集

+ +

你需要首先指示瀏覽器要使用哪一種字符集。在以前版本,這需要複雜的<meta>完素;來到HTML5,這變得非常簡單:

+ +
<meta charset="UTF-8">
+ +

將它放置在<head></head>之間。若果你使用的字符集與瀏覽器預先設定的不一樣,瀏覽器會重新解析文件。另外,若你目前並非UTF-8字符集,建議你在網頁中自行設定。

+ +

為了加強安全,HTML5文件限制字符集需要兼容ASCII和最少8位元。

+ +

Using the new HTML5 parser

+ +

The parsing rule of HTML5, which analyzes the meaning of mark-up, has been more precisely defined in HTML5. Until the introduction of HTML5, only the meaning of valid mark-up was defined, meaning that as soon as one small error was made in the mark-up (most Web sites have at least one), the behavior was undefined. Essentially, it meant that all browsers behaved differently, which is no longer the case. Now, faced with errors in the mark-up, all compliant browsers must behave exactly in the same way.

+ +

This requirement helps Web developers quite a bit. While it is true that all modern browsers now use these HTML5 parsing rules, non-HTML5-compliant browsers are still used by some. Keep in mind that it's still highly recommended that one write valid mark-up, as such code is easier to read and maintain, and it greatly decreases the prominence of incompatibilities that exists in various older browsers.

+ +

Don't worry — you don't have to change anything on your Web site — the Web browsers' developers have done everything for you!

diff --git a/files/zh-tw/web/guide/index.html b/files/zh-tw/web/guide/index.html new file mode 100644 index 0000000000..48772ec771 --- /dev/null +++ b/files/zh-tw/web/guide/index.html @@ -0,0 +1,29 @@ +--- +title: Web 開發者指引 +slug: Web/Guide +tags: + - Guide + - Landing + - NeedsTranslation + - TopicStub + - Web +translation_of: Web/Guide +--- +

這些文章提供了如何幫助你使用特定技術和 APIs 的資訊。

+ +
+

注意: 很抱歉。這個頁面在我們完成內容遷移之前會很混亂。

+
+ +
{{LandingPageListSubpages}}
+ +
+
JavaScript
+
JavaScript 是用來創造網頁應用程式的腳本化語言.
+
+ +

參見

+ + diff --git a/files/zh-tw/web/guide/introduction_to_web_development/index.html b/files/zh-tw/web/guide/introduction_to_web_development/index.html new file mode 100644 index 0000000000..ec264af0b3 --- /dev/null +++ b/files/zh-tw/web/guide/introduction_to_web_development/index.html @@ -0,0 +1,13 @@ +--- +title: Web開發入門 +slug: Web/Guide/Introduction_to_Web_development +translation_of: Web/Guide/Introduction_to_Web_development +--- +

不論你是否是剛入門的 Web 開發者,或者只是為了拓寬視野而進入全新的 Web 領域,這裡的連結應該幫得上你。至少,我們在此有很多的連結。

+
附註: 本頁明顯還是個片斷,我們需要在此產生一些內容。
+ +

文件主題

在此我們還沒有任何文章,但很需要。

資源

+
W3Schools簡體中文版
免費的 Web 開發教學,從提供給初學者的 HTML,到高級的 Web 技術。
+
+

 

+

{{ languages( { "en": "en/Web_Development/Introduction_to_Web_development" } ) }}

diff --git a/files/zh-tw/web/guide/performance/index.html b/files/zh-tw/web/guide/performance/index.html new file mode 100644 index 0000000000..00c4b9d7fe --- /dev/null +++ b/files/zh-tw/web/guide/performance/index.html @@ -0,0 +1,14 @@ +--- +title: Optimization and performance +slug: Web/Guide/Performance +tags: + - Landing + - NeedsTranslation + - Optimization + - Performance + - TopicStub + - Web +translation_of: Web/Guide/Performance +--- +

When building modern Web apps and sites, it's important to make your content perform well. That is, to make it work quickly and efficiently. This lets it work effectively both for users of powerful desktop systems as well as for handheld devices with less power.

+

{{LandingPageListSubpages}}

diff --git a/files/zh-tw/web/guide/woff/index.html b/files/zh-tw/web/guide/woff/index.html new file mode 100644 index 0000000000..38bc75a2c1 --- /dev/null +++ b/files/zh-tw/web/guide/woff/index.html @@ -0,0 +1,100 @@ +--- +title: 網路開放字型格式 (WOFF) +slug: Web/Guide/WOFF +tags: + - Fonts + - NeedsMobileBrowserCompatibility + - WOFF + - 字型 +translation_of: Web/Guide/WOFF +--- +

WOFF網頁開放字型格式)是由 Mozilla、Type Supply、LettError 和其它組織協力開發的全新網路字型格式。它使用了同為表格結構的 sfnt 壓縮版,廣泛用於 TrueType、OpenType 和開放字型格式,另外加入了中繼資料和私有資料結構,其中包含事先定義的欄位,讓有意願的廠商和製造商提供授權資訊。

+ +

使用 WOFF 主要有以下三項好處:

+ +
    +
  1. 字型資料經過壓縮,因此使用 WOFF 的網站流量降低,載入速度也會比未壓縮的 TrueType 或 OpenType 檔更快。
  2. +
  3. 許多不願授權的字型商都可以授權 WOFF 格式的字型,網站設計師有更多的字型可以選擇。
  4. +
  5. 專有軟體和自由軟體商都喜歡 WOFF 格式,因此在網路世界上,可以成為真正通用和可交換的字型格式,有別於目前其它字型格式。
  6. +
+ +

使用 WOFF

+ +

您可透過{{cssxref("@font-face")}} CSS 屬性在網頁內的文字使用 WOFF 字型。它的運作方式和 OpenType 以及 TrueType 字型並無二異,但在下載內容時可能會更有效率,這完全歸功於其與生俱來的壓縮特性。

+ +

規格文件

+ + + + + + + + + + + + + + + + +
規格文件狀態註解
{{SpecName('WOFF1.0', '', '')}}{{Spec2('WOFF1.0')}}初始規格文件
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
功能特色ChromeFirefox (Gecko)Internet ExplorerOperaSafari
基本支援6.0{{CompatGeckoDesktop("1.9.1")}}9.011.105.1
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
功能特色AndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
基本支援{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("1.9.1")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

詳見

+ + diff --git a/files/zh-tw/web/guide/writing_forward-compatible_websites/index.html b/files/zh-tw/web/guide/writing_forward-compatible_websites/index.html new file mode 100644 index 0000000000..67d7b2c5e9 --- /dev/null +++ b/files/zh-tw/web/guide/writing_forward-compatible_websites/index.html @@ -0,0 +1,70 @@ +--- +title: Writing forward-compatible websites +slug: Web/Guide/Writing_forward-compatible_websites +translation_of: Web/Guide/Writing_forward-compatible_websites +--- +

這個頁面將解釋如何撰寫在新的瀏覽器版本發布時不會遭受毀損的網頁。

+

這對內部網路和其他非公共網站尤其重要,如果我們不能看到你的原始碼,我們將無法看到它是否已遭受毀損。底下所提到的原則可能無法全數做到,但盡可能遵守這些原則,對於你的網站在未來發展維護上有所幫助。

+

JavaScript

+

以「window.」前綴修飾所有存取於 onfoo 屬性的全域變數

+

當一個事件處理器內容屬性(例如:onclick, onmouseover 等等)被使用在 HTML 的元素上時,所有對於屬性內名稱的查找首先發生在元素本身,若元素為表單控制項,再來尋找元素的表單,接著是 document,最後是 window(你定義全域變數的地方)。例如,如果你有這樣的原始碼:

+
<div onclick="alert(ownerDocument)">點我一下</div>
+

在點選文字時,div 中的 ownerDocument 會被提示,即使是在全域範圍內宣告 var ownerDocument 這種情況依然會發生。

+

這意味著,無論你何時在事件處理器內容屬性存取了一個全域變數,包括呼叫任何全域函數,當規格中新增了和您變數或函式同名的 DOM 屬性到元素或文件之中,在瀏覽器實作之後,就會產生名稱衝突。這時你的函式將突然被停止呼叫。這種情況在 HTML5 的發展之下,多次在不同網站中發生。

+

為了避免這種情況,以 window 來限定全域變數的存取,例如:

+
<script>
+  function localName() {
+    alert('函式 localName 被呼叫了');
+  }
+</script>
+<div onclick="window.localName()">按一下會跑出一個提示訊息</div>
+
+

不要直接附加非您能控制的腳本

+

"use strict;" 指令在 ECMAScript 裡,使用於檔案層級時適用於檔案的所有程式碼。因此,若將取決非嚴格模式行為的腳本,直接附加到要求嚴格模式的腳本會導致不正常的行為。

要求 JavaScript 函式庫的作者遵守這些規則

+

向您喜歡的函式庫開發者們建議他們遵循這些規範,否則您無法確保未來這些函式庫能否依舊正常運作。可惜的是函式庫往往違反這些準則。

+

偵測

+

偵測特定功能支援

+

如果您打算使用某些功能,盡可能使用物件偵測來偵測功能是否支援。簡單來說,不要假設只要 "filter" in body.style 測試結果為 true 的瀏覽器必定是 Microsoft Internet Explorer,進而我們一定會有 window.event 物件提供事件處理器。不要假設一個擁有特定 DOM 功能的瀏覽器一定也有另外一個 DOM 功能(特別是非標準功能);或著反過來假設一定不會支持某些功能(例如,假設在腳本元素中支援 onload 的瀏覽器一定不會支援 onreadystatechange)。隨著瀏覽器們整合他們的行為,它們會同時新增和刪除許多功能並修正錯誤。過去即是如此,未來也將會如此。

+

所以,在偵測特定功能時,不要接著假定「只要某個功能支援與否,另外一樣功能就一定支援與否」。

+

別做 UA 偵測

+

這就是假設一項功能存在(User Agent 中包含特定的字元)時,必定有哪些東西可用或不可用的常見實例。

+

如果您不得不做 UA 偵測,僅針對過去的瀏覽器版本

+

如果您還是得訴諸 UA(User Agent)偵測,請只針對特定瀏覽器的過去版本進行偵測。首先,對於未知的、所測試瀏覽器的目前與未來版本執行預設的程式內容。接著如果無法透過偵測,找出過去瀏覽器版本中預設程式內容中無法使用的功能,就可以透過偵測特定瀏覽器的過去版本來追加對應的修正。

+

在這個提案中,「目前的版本」意指您所能測試到的最新版本。如果您的預設程式內容在 Firefox Aurora 中可以正常運作,而在 Beta 和最新釋出版中存在問題而無法運作,此時您可以將您所測試中的 Firefox Aurora 版本標為「目前的版本」,將 Beta 以前的版本都視為「過去的版本」,即使它們還沒有被正式釋出給大眾。

+

不要為了不同的瀏覽器設計多餘的對應程式

+

當您所用的一部分程式內容可能在所有瀏覽器都能運作時,別隨便透過物件或 UA 偵測來決定執行不同的程式碼。瀏覽器很有可能改變它們的行為並互相整合,若您任意切出不同的替代程式,您的網站將有可能會損壞。

+

測試

+

測試所有主流引擎

+

至少在 Firefox、Chrome 或 Safari(因為兩者都基於相同的 WebKit 引擎)、Opera 及 Internet Explorer 測試您的程式碼。若遵循以上原則,你有一個單一的程式碼內容在目前所有的和未知的瀏覽器都測試過,在所有主要引擎都能運作下,極有可能表示您的程式碼將不會在未來被破壞。

+

有時不同瀏覽器對特定功能的實作不盡相同。如果你有一個單一的程式碼內容,在所有常用的引擎中都沒問題,這可能表示,你使用了各瀏覽器間已經整合的行為,或著使用了尚未整合,而程式碼無關引擎的行為標準所堅持的部份。

+

特定瀏覽器支援的功能和前綴

+

別針對目前或未來的瀏覽器版本做臨時方案

+

這又是一個常見的實例:假設目前瀏覽器臭蟲之間的關聯性可以代表未來也會繼續擁有如此的關聯。針對舊瀏覽器,如果您用做臨時方案的臭蟲在目前的瀏覽器已經不存在,那針對舊瀏覽器套用方案沒有問題;只針對舊瀏覽器下,一旦瀏覽器修正了 X 臭蟲,您可以肯定所有具有臭蟲 X 的瀏覽器都有臭蟲 Y,因此使用臭蟲 X 的存在來針對臭蟲 Y 的問題做解套。

+

跟之前 UA 偵測中的建議一樣,「目前的版本」意指您所能測試到的最新版本。

+

避免依賴新潮的非標準功能

+

就算加了前綴,使用新潮的功能依舊還是很危險:隨著規格的發展,瀏覽器前綴的實作也會遵循最新的規範而改變。一旦功能被標準化,含前綴的版本有可能會被刪除。

+

瀏覽器開發者提供前綴與非標準功能給您是為了實驗和意見回饋,而非讓您將這些酷玩意散佈出去。如果您選擇使用它們,請準備經常更新您的網站以趕上變化。

+

當使用未普遍實作(即使是標準)的新潮功能時,記得測試備援方案

+

要檢查在未實作所用功能的瀏覽器下瀏覽網頁會發生什麼事,尤其是您在工作時不會經常使用的瀏覽器。

+

除非針對過去有問題的版本,不要使用廠商前綴(Vender-prefix)功能

+

廠商前綴的功能可以在將來的版本中改變。然而,一旦瀏覽器已提供不帶前綴的功能,您可以在確保不帶前綴版在可用時總會被套用下,使用前綴版本針對舊版本。一個很好的例子,假設-vnd 廠商已經將不帶前綴的 make-it-pretty 屬性實作加入新出品的瀏覽器,包含一個前綴版與不含前綴版作用不同的值「sometimes」:

+
<style>
+  .pretty-element {
+    -vnd-make-it-pretty: sometimes;
+    make-it-pretty: sometimes;
+  }
+</style>
+
+

上述規則中,聲明的順序非常重要:無前綴者一定要排在最後。

+

在沒有瀏覽器支援前,不要使用不含前綴的 CSS 屬性或 API

+

除非不帶前綴的版本得到了廣泛支持,其行為可能仍會發生意想不到的改變。特別是,當沒有瀏覽器支援不帶前綴的版本時,就不要使用不帶前綴的版本。最終的語法不盡然會和任何帶前綴的語法相同。

+

程式碼維護

+

別忘了 >

+

透過驗證器可以確保這個問題不會發生,但即使你的網站沒有完全驗證,你仍應確保你所有的 > 字元都有出現。少了它可能會讓接下來的 Tag 名稱被當成上一個 Tag 所屬的屬性,而造成意想不到的結果。可能一小段沒問題,但接下來因為某段文字代表一個屬性而完全被破壞。舉例來說,以下是一段在不支援 HTML5 瀏覽器下可正常運作,但卻讓支援 HTML5 的瀏覽器無法正常運作的網頁程式碼:

+
<form action="http://www.example.com">
+  <input type="submit" value="傳送此表單"
+</form>
+
+

因為在 input Tag 的最後忘了加上 >

+

別把失敗的實驗品留在您的網頁程式碼裡

+

如果您想嘗試一個 CSS 屬性或其他的酷東西,但沒有效果,請記得拿掉。不然您無法預知這東西未來會做什麼壞事。

diff --git a/files/zh-tw/web/html/applying_color/index.html b/files/zh-tw/web/html/applying_color/index.html new file mode 100644 index 0000000000..4e9aa26498 --- /dev/null +++ b/files/zh-tw/web/html/applying_color/index.html @@ -0,0 +1,502 @@ +--- +title: Applying color to HTML elements using CSS +slug: Web/HTML/Applying_color +translation_of: Web/HTML/Applying_color +--- +
{{HTMLRef}}
+ +

The use of color is a fundamental form of human expression. Children experiment with color before they even have the manual dexterity to draw. Maybe that's why color is one of the first things people often want to experiment with when learning to develop web sites. With CSS, there are lots of ways to add color to your HTML elements to create just the look you want. This article is a primer introducing each of the ways CSS color can be used in HTML.

+ +

Fortunately, adding color to your HTML is actually really easy to do, and you can add color to nearly anything.

+ +

We're going to touch on most of what you'll need to know when using color, including a {{anch("Things that can have color", "list of what you can color and what CSS properties are involved")}}, {{anch("How to describe a color", "how you describe colors")}}, and how to actually {{anch("Using color", "use colors both in stylesheets and in scripts")}}. We'll also take a look at how to {{anch("Letting the user picka color", "let the user pick a color")}}.

+ +

Then we'll wrap things up with a brief discussion of how to {{anch("Using color wisely", "use color wisely")}}: how to select appropriate colors, keeping in mind the needs of people with differing visual capabilities.

+ +

Things that can have color

+ +

At the element level, everything in HTML can have color applied to it. Instead, let's look at things in terms of the kinds of things that are drawn in the elements, such as text and borders and so forth. For each, we'll see a list of the CSS properties that apply color to them.

+ +

At a fundamental level, the {{cssxref("color")}} property defines the foreground color of an HTML element's content and the {{cssxref("background-color")}} property defines the element's background color. These can be used on just about any element.

+ +

Text

+ +

Whenever an element is rendered, these properties are used to determine the color of the text, its background, and any decorations on the text.

+ +
+
{{cssxref("color")}}
+
The color to use when drawing the text and any text decorations (such as the addition of under- or overlines, strike-through lines, and so forth.
+
{{cssxref("background-color")}}
+
The text's background color.
+
{{cssxref("text-shadow")}}
+
Configures a shadow effect to apply to text. Among the options for the shadow is the shadow's base color (which is then blurred and blended with the background based on the other parameters). See {{SectionOnPage("/en-US/docs/Learn/CSS/Styling_text/Fundamentals", "Text drop shadows")}} to learn more.
+
{{cssxref("text-decoration-color")}}
+
By default, text decorations (such as underlines, strikethroughs, etc) use the color property as their colors. However, you can override that behavior and use a different color for them with the text-decoration-color property.
+
{{cssxref("text-emphasis-color")}}
+
The color to use when drawing emphasis symbols adjacent to each character in the text. This is used primarily when drawing text for East Asian languages.
+
{{cssxref("caret-color")}}
+
The color to use when drawing the {{Glossary("caret")}} (sometimes referred to as the text input cursor) within the element. This is only useful in elements that are editable, such as {{HTMLElement("input")}} and {{HTMLElement("textarea")}} or elements whose HTML {{htmlattrxref("contenteditable")}} attribute is set.
+
+ +

Boxes

+ +

Every element is a box with some sort of content, and has a background and a border in addition to whatever contents the box may have.

+ +
+
{{anch("Borders")}}
+
See the section {{anch("Borders")}} for a list of the CSS properties you can use to set the colors of a box's borders.
+
{{cssxref("background-color")}}
+
The background color to use in areas of the element that have no foreground content.
+
{{cssxref("column-rule-color")}}
+
The color to use when drawing the line separating columns of text.
+
{{cssxref("outline-color")}}
+
The color to use when drawing an outline around the outside of the element. This outline is different from the border in that it doesn't get space set aside for it in the document (so it may overlap other content). It's generally used as a focus indicator, to show which element will receive input events.
+
+ +

Borders

+ +

Any element can have a border drawn around it. A basic element border is a line drawn around the edges of the element's content. See {{SectionOnPage("/en-US/docs/Learn/CSS/Introduction_to_CSS/Box_model", "Box properties")}} to learn about the relationship between elements and their borders, and the article Styling borders using CSS to learn more about applying styles to borders.

+ +

You can use the {{cssxref("border")}} shorthand property, which lets you configure everything about the border in one shot (including non-color features of borders, such as its width, style (solid, dashed, etc.), and so forth.

+ +
+
{{cssxref("border-color")}}
+
Specifies a single color to use for every side of the element's border.
+
{{cssxref("border-left-color")}}, {{cssxref("border-right-color")}}, {{cssxref("border-top-color")}}, and {{cssxref("border-bottom-color")}}
+
Lets you set the color of the corresponding side of the element's border.
+
{{cssxref("border-block-start-color")}} and {{cssxref("border-block-end-color")}}
+
With these, you can set the color used to draw the borders which are closest to the start and end of the block the border surrounds. In a left-to-right writing mode (such as the way English is written), the block start border is the top edge and the block end is the bottom. This differs from the inline start and end, which are the left and right edges (corresponding to where each line of text in the box begins and ends).
+
{{cssxref("border-inline-start-color")}} and {{cssxref("border-inline-end-color")}}
+
These let you color the edges of the border closest to to the beginning and the end of the start of lines of text within the box. Which side this is will vary depending on the {{cssxref("writing-mode")}}, {{cssxref("direction")}}, and {{cssxref("text-orientation")}} properties, which are typically (but not always) used to adjust text directionality based on the language being displayed. For example, if the box's text is being rendered right-to-left, then the border-inline-start-color is applied to the right side of the border.
+
+ +

Other ways to use color

+ +

CSS isn't the only web technology that supports color. There are graphics technologies that are available on the web which also support color.

+ +
+
The HTML Canvas API
+
Lets you draw 2D bitmapped graphics in a {{HTMLElement("canvas")}} element. See our Canvas tutorial to learn more.
+
SVG (Scalable Vector Graphics)
+
Lets you draw images using commands that draw specific shapes, patterns, and lines to produce an image. SVG commands are formatted as XML, and can be embedded directly into a web page or can be placed in he page using the {{HTMLElement("img")}} element, just like any other type of image.
+
WebGL
+
The Web Graphics Library is an OpenGL ES-based API for drawing high-performance 2D and 3D graphics on the Web. See Learn WebGL for 2D and 3D graphics to find out more.
+
+ +

How to describe a color

+ +

In order to represent a color in CSS, you have to find a way to translate the analog concept of "color" into a digital form that a computer can use. This is typically done by breaking down the color into components, such as how much of each of a set of primary colors to mix together, or how bright to make the color. As such, there are several ways you can describe color in CSS.

+ +

For more detailed discussion of each of the color value types, see the reference for the CSS {{cssxref("<color>")}} unit.

+ +

Keywords

+ +

A set of standard color names have been defined, letting you use these keywords instead of numeric representations of colors if you choose to do so and there's a keyword representing the exact color you want to use. Color keywords include the standard primary and secondary colors (such as red, blue, or orange), shades of gray (from black to white, including colors like darkgray and lightgrey), and a variety of other blended colors including lightseagreen, cornflowerblue, and rebeccapurple.

+ +

See {{SectionOnPage("/en-US/docs/Web/CSS/color_value", "Color keywords", "code")}} for a list of all available color keywords.

+ +

RGB values

+ +

There are three ways to represent an RGB color in CSS.

+ +

Hexadecimal string notation

+ +

Hexadecimal string notation represents a color using hexadecimal digits to represent each of the color components (red, green, and blue). It may also include a fourth component: the alpha channel (or opacity). Each color component can be represented as a number between 0 and 255 (0x00 and 0xFF) or, optionally, as a number between 0 and 15 (0x0 and 0xF). All components must be specified using the same number of digits. If you use the single-digit notation, the final color is computed by using each component's digit twice; that is, "#D" becomes "#DD" when drawing.

+ +

A color in hexadecimal string notation always begins with the character "#". After that come the hexadecimal digits of the color code. The string is case-insensitive.

+ +
+
"#rrggbb"
+
Specifies a fully-opaque color whose red component is the hexadecimal number 0xrr, green component is 0xgg, and blue component is 0xbb.
+
"#rrggbbaa"
+
Specifies a color whose red component is the hexadecimal number 0xrr, green component is 0xgg, and blue component is 0xbb. The alpha channel is specified by 0xaa; the lower this value is, the more translucent the color becomes.
+
"#rgb"
+
Specifies a color whose red component is the hexadecimal number 0xrr, green component is 0xgg, and blue component is 0xbb.
+
"#rgba"
+
Specifies a color whose red component is the hexadecimal number 0xrr, green component is 0xgg, and blue component is 0xbb. The alpha channel is specified by 0xaa; the lower this value is, the more translucent the color becomes.
+
+ +

As an example, you can represent the opaque color bright blue as "#0000ff" or "#00f". To make it 25% opaque, you can use "#0000ff44" or "#00f4".

+ +

RGB functional notation

+ +

RGB (Red/Green/Blue) functional notation, like hexadecimal string notation, represents colors using their red, green, and blue components (as well as, optionally, an alpha channel component for opacity). However, instead of using a string, the color is defined using the CSS function {{cssxref("color_value", "rgb()", "#rgb()")}}. This function accepts as its input parameters the values of the red, green, and blue components and an optional fourth parameter, the value for the alpha channel.

+ +

Legal values for each of these parameters are:

+ +
+
red, green, and blue
+
Each must be an {{cssxref("<integer>")}} value between 0 and 255 (inclusive), or a {{cssxref("<percentage>")}} from 0% to 100%.
+
alpha
+
The alpha channel is a number between 0.0 (fully transparent) and 1.0 (fully opaque). You can also specify a percentage where 0% is the same as 0.0 and 100% is the same as 1.0.
+
+ +

For example, a bright red that's 50% opaque can be represented as rgb(255, 0, 0, 0.5) or rgb(100%, 0, 0, 50%).

+ +

HSL functional notation

+ +

Designers and artists often prefer to work using the {{interwiki("wikipedia", "HSL and HSV", "HSL")}} (Hue/Saturation/Luminosity) color method. On the web, HSL colors are represented using HSL functional notation. The hsl() CSS function is very similar to the rgb() function in usage otherwise.

+ +
+
HSL color cylinder +
Figure 1. An HSL color cylinder. Hue defines the actual color based on the position along a circular color wheel representing the colors of the visible spectrum. Saturation is a percentage of how much of the way between being a shade of gray and having the maximum possible amount of the given hue. As the value of luminance (or lightness) increases, the color transitions from the darkest possible to the brightest possible (from black to white). Image courtesy of user SharkD on Wikipedia, distributed under the CC BY-SA 3.0 license.
+
+
+ +

The value of the hue (H) component of an HSL color is an angle from red around through yellow, green, cyan, blue, and magenta (ending up back at red again at 360°) that identifies what the base color is. The value can be specified in any {{cssxref("<angle>")}} unit supported by CSS, including degrees (deg), radians (rad), gradians (grad), or turns (turn). But this doesn't control how vivid or dull, or how bright or dark the color is.

+ +

The saturation (S) component of the color specifies what percentage of the final color is comprised of the specified hue. The rest is defined by the grey level provided by the luminance (L) component.

+ +

Think of it like creating the perfect paint color:

+ +
    +
  1. You start with base paint that's the maximum intensity possible for a given color, such as  the most intense blue that can be represented by the user's screen. This is the hue (H) component: a value representing the angle around the color wheel for the vivid hue we want to use as our base.
  2. +
  3. Then select a greyscale paint that corresponds how bright you want the color to be; this is the luminance. Do you want it to be very bright and nearly white, or very dark and closer to black, or somewhere in between? This is specified using a percentage, where 0% is perfectly black and 100% is perfectly white. (regardless of the saturation or hue). In between values are a literal grey area.
  4. +
  5. Now that you have a grey paint and a perfectly vivid color, you need to mix them together. The saturation (S) component of the color indicates what percentage of the final color should be comprised of that perfectly vivid color. The rest of the final color is made up of the grey paint that represents the saturation.
  6. +
+ +

You can also optionally include an alpha channel, to make the color less than 100% opaque.

+ +

Here are some sample colors in HSL notation:

+ +
+ + +

{{EmbedLiveSample("hsl-swatches", 300, 260)}}

+
+ +
+

Note that when you omit the hue's unit, it's assumed to be in degrees (deg).

+
+ +

Using color

+ +

Now that you know what CSS properties exist that let you apply color to elements and the formats you can use to describe colors, you can put this together to begin to make use of color. As you may have seen from the list under {{anch("Things that can have color")}}, there are plenty of things you can color with CSS. Let's look at this from two sides: using color within a {{Glossary("stylesheet")}}, and adding and changing color using {{Glossary("JavaScript")}} code to alter the styles of elements.

+ +

Specifying colors in stylesheets

+ +

The easiest way to apply color to elements—and the way you'll usually do it—is to simply specify colors in the CSS that's used when rendering elements. While we won't use every single property mentioned previously, we'll look at a couple of examples. The concept is the same anywhere you use color.

+ +

Let's take a look at an example, starting by looking at the results we're trying to achieve:

+ +
{{EmbedLiveSample("Specifying_colors_in_stylesheets", 650, 150)}}
+ +

HTML

+ +

The HTML responsible for creating the above example is shown here:

+ +
<div class="wrapper">
+  <div class="box boxLeft">
+    <p>
+      This is the first box.
+    </p>
+  </div>
+  <div class="box boxRight">
+    <p>
+      This is the second box.
+    </p>
+  </div>
+</div>
+ +

This is pretty simple, using a {{HTMLElement("div")}} as a wrapper around the contents, which consists of two more <div>s, each styled differently with a single paragraph ({{HTMLElement("p")}}) in each box.

+ +

The magic happens, as usual, in the CSS, where we'll apply colors define the layout for the HTML above.

+ +

CSS

+ +

We'll look at the CSS to create the above results a piece at a time, so we can review the interesting parts one by one.

+ +
.wrapper {
+  width: 620px;
+  height: 110px;
+  margin: 0;
+  padding: 10px;
+  border: 6px solid mediumturquoise;
+}
+ +

The .wrapper class is used to assign styles to the {{HTMLElement("div")}} that encloses all of our other content. This establishes thesize of the container using {{cssxref("width")}} and {{cssxref("height")}} as well as its {{cssxref("margin")}} and {{cssxref("padding")}}.

+ +

Of more interest to our discussion here is the use of the {{cssxref("border")}} property to establish a border around the outside edge of the element. This border is a solid line, 6 pixels wide, in the color mediumturquoise.

+ +

Our two colored boxes share a number of properties in common, so next we establish a class, .box, that defines those shared properties:

+ +
.box {
+  width: 290px;
+  height: 100px;
+  margin: 0;
+  padding: 4px 6px;
+  font: 28px "Marker Felt", "Zapfino", cursive;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+ +

In brief, .box establishes the size of each box, as well as the configuration of the font used within. We also take advantage of CSS Flexbox to easily center the contents of each box. We enable flex mode using {{cssxref("display", "display: flex")}}, and set both {{cssxref("justify-content")}} and {{cssxref("align-items")}} to center. Then we can create a class for each of the two boxes that defines the propeties that differ between the two.

+ +
.boxLeft {
+  float: left;
+  background-color: rgb(245, 130, 130);
+  outline: 2px solid darkred;
+}
+ +

The .boxLeft class—which, cleverly, is used to style the box on the left—floats the box to the left, then sets up the colors:

+ + + +
.boxRight {
+  float: right;
+  background-color: hsl(270deg, 50%, 75%);
+  outline: 4px dashed rgb(110, 20, 120);
+  color: hsl(0deg, 100%, 100%);
+  text-decoration: underline wavy #88ff88;
+  text-shadow: 2px 2px 3px black;
+}
+ +

Finally, the .boxRight class describes the unique properties of the box that's drawn on the right. It's configured to float the box to the right so that it appears next to the previous box. Then the following colors are established:

+ + + +

Letting the user pick a color

+ +

There are many situations in which your web site may need to let the user select a color. Perhaps you have a customizable user interface, or you're implementing a drawing app. Maybe you have editable text and need to let the user choose the text color. Or perhaps your app lets the user assign colors to folders or items. Although historically it's been necessary to implement your own {{interwiki("wikipedia", "color picker")}}, HTML now provides support for browsers to provide one for your use through the {{HTMLElement("input")}} element, by using "color" as the value of its {{htmlattrxref("type", "input")}} attribute.

+ +

The <input> element represents a color only in the {{anch("Hexadecimal string notation", "hexadecimal string notation")}} covered above.

+ +

Example: Picking a color

+ +

Let's look at a simple example, in which the user can choose a color. As the user adjusts the color, the border around the example changes to reflect the new color. After finishing up and picking the final color, the color picker's value is displayed.

+ +

{{EmbedLiveSample("Example_Picking_a_color", 525, 275)}}

+ +
+

On macOS, you indicate that you've finalized selection of the color by closing the color picker window.

+
+ +

HTML

+ +

The HTML here creates a box that contains a color picker control (with a label created using the {{HTMLElement("label")}} element) and an empty paragraph element ({{HTMLElement("p")}}) into which we'll output some text from our JavaScript code.

+ +
<div id="box">
+  <label for="colorPicker">Border color:</label>
+  <input type="color" value="#8888ff" id="colorPicker">
+  <p id="output"></p>
+</div>
+ +

CSS

+ +

The CSS simply establishes a size for the box and some basic styling for appearances. The border is also established with a 2-pixel width and a border color that won't last, courtesy of the JavaScript below...

+ +
#box {
+  width: 500px;
+  height: 200px;
+  border: 2px solid rgb(245, 220, 225);
+  padding: 4px 6px;
+  font: 16px "Lucida Grande", "Helvetica", "Arial", "sans-serif"
+}
+ +

JavaScript

+ +

The script here handles the task of updating the starting color of the border to match the color picker's value. Then two event handlers are added to deal with input from the <input type="color"> element.

+ +
let colorPicker = document.getElementById("colorPicker");
+let box = document.getElementById("box");
+let output = document.getElementById("output");
+
+box.style.borderColor = colorPicker.value;
+
+colorPicker.addEventListener("input", function(event) {
+  box.style.borderColor = event.target.value;
+}, false);
+
+colorPicker.addEventListener("change", function(event) {
+  output.innerText = "Color set to " + colorPicker.value + ".";
+}, false);
+ +

The {{event("input")}} event is sent every time the value of the element changes; that is, every time the user adjusts the color in the color picker. Each time this event arrives, we set the box's border color to match the color picker's current value.

+ +

The {{event("change")}} event is received when the color picker's value is finalized. We respond by setting the contents of the <p> element with the ID "output" to a string describing the finally selected color.

+ +

Using color wisely

+ +

Making the right choices when selecting colors when designing a web site can be a tricky process, especially if you aren't well-grounded in art, design, or at least basic color theory. The wrong color choice can render your site unattractive, or even worse, leave the content unreadable due to problems with contrast or conflicting colors. Worse still, if using the wrong colors can result in your content being outright unusable by people withcertain vision problems, particularly color blindness.

+ +

Finding the right colors

+ +

Coming up with just the right colors can be tricky, especially without training in art or design. Fortunately, there are tools available that can help you. While they can't replace having a good designer helping you make these decisions, they can definitely get you started.

+ +

Base color

+ +

The first step is to choose your base color. This is the color that in some way defines your web site or the subject matter of the site. Just as we associate green with the beverage {{interwiki("wikipedia", "Mountain Dew")}} and one might think of the color blue in relationship with the sky or the ocean, choosing an appropriate base color to represent your site is a good place to start. There are plenty of ways to select a base color; a few ideas include:

+ + + +

When trying to decide upon a base color, you may find that browser extensions that let you select colors from web content can be particularly handy. Some of these are even specifically designed to help with this sort of work. For example, the web site ColorZilla offers an extension (Chrome / Firefox) that offers an eyedropper tool for picking colors from the web. It can also take averages of the colors of pixels in various sized areas or even a selected area of the page.

+ +
+

The advantage to averaging colors can be that often what looks like a solid color is actually a surprisingly varied number of related colors all used in concert, blending to create a desired effect. Picking just one of these pixels can result in getting a color that on its own looks very out of place.

+
+ +

Fleshing out the palette

+ +

Once you have decided on your base color, there are plenty of online tools that can help you build out a palette of appropriate colors to use along with your base color by applying color theory to your base color to determine appropriate added colors. Many of these tools also support viewing the colors filtered so you can see what they would look like to people with various forms of color blindness. See {{anch("Color and accessibility")}} for a brief explanation of why this matters.

+ +

A few examples (all free to use as of the time this list was last revised):

+ + + +

When designing your palette, be sure to keep in mind that in addition to the colors these tools typically generate, you'll probably also need to add some core neutral colors such as white (or nearly white), black (or nearly black), and some number of shades of gray.

+ +
+

Usually, you are far better off using the smallest number of colors possible. By using color to accentuate rather than adding color to everything on the page, you keep your content easy to read and the colors you do use have far more impact.

+
+ +

Color theory resources

+ +

A full review of color theory is beyond the scope of this article, but there are plenty of articles about color theory available, as well as courses you can find at nearby schools and universities. A couple of useful resources about color theory:

+ +
+
Color Science (Khan Academy in association with Pixar)
+
An online course which introduces concepts such as what color is, how it's percieved, and how to use colors to express ideas. Presented by Pixar artists and designers.
+
{{interwiki("wikipedia", "Color theory")}} on Wikipedia
+
Wikipedia's entry on color theory, which has a lot of great information from a technical perspective. It's not really a resource for helping you with the color sleection process, but is still full of useful information.
+
+ +

Color and accessibility

+ +

There are several ways color can be an {{Glossary("accessibility")}} problem. Improper or careless use of color can result in a web site or app that a percentage of your target audience may not be able to use adequately, resulting in lost traffic, lost business, and possibly even a public relations problem. So it's important to consider your use of color carefully.

+ +

You should do at least basic research into {{interwiki("wikipedia", "color blindness")}}. There are several kinds; the most common is red-green color blindness, which causes people to be unable to differentiate between the colors red and green. There are others, too, ranging from inabilities to tell the difference between certain colors to total inability to see color at all.

+ +
+

The most important rule: never use color as the only way to know something. If, for example, you indicate success or failure of an operation by changing the color of a shape from white to green for success and red for failure, users with red-green color-blindness won't be able to use your site properly. Instead, perhaps use both text and color together, so that everyone can understand what's happening.

+
+ +

For more information about color blindness, see the following articles:

+ + + +

Palette design example

+ +

Let's consider a quick example of selecting an appropriate color palette for a site. Imagine that you're building a web site for a new game that takes place on the planet Mars. So let's do a Google search for photos of Mars. Lots of good examples of Martian coloration there. We carefully avoid the mockups and the photos from movies. And we decide to use a photo taken by one of the Mars landers humanity has parked on the surface over the last few decades, since the game takes place on the planet's surface. We use a color picker tool to select a sample of the color we choose.

+ +

Using an eyedropper tool, we identify a color we like and determine that the color in question is #D79C7A, which is an appropriate rusty orange-red color that's so stereotypical of the Martian surface.

+ +

Having selected our base color, we need to build out our palette. We decide to use Paletton to come up with the other colors we need. Upon opening Paletton, we see:

+ +

Right after loading Paletton.

+ +

Next, we enter our color's hex code (D79C7A) into the "Base RGB" box at the bottom-left corner of the tool:

+ +

After entering base color

+ +

We now see a monochromatic palette based on the color we picked from the Mars photo. If you need a lot of related colors for some reason, those are likely to be good ones. But what we really want is an accent color. Something that will pop along side the base color. To find that, we click the "add complementary" toggle underneath the menu that lets you select the palette type (currently "Monochromatic"). Paletton computes an appropriate accent color; clicking on the accent color down in the bottom-right corner tells us that this color is #508D7C.

+ +

Now with complementary colors included.

+ +

If you're unhappy with the color that's proposed to you, you can change the color scheme, to see if you find something you like better. For example, if we don't like the proposed greenish-blue color, we can click the Triad color scheme icon, which presents us with the following:

+ +

Triad color scheme selected

+ +

That greyish blue in the top-right looks pretty good. Clicking on it, we find that it's #556E8D. That would be used as the accent color, to be used sparingly to make things stand out, such as in headlines or in the highlighting of tabs or other indicators on the site:

+ +

Triad color scheme selected

+ +

Now we have our base color and our accent. On top of that, we have a few complementary shades of each, just in case we need them for gradients and the like. The colors can then be exported in a number of formats so you can make use of them.

+ +

Once you have these colors, you will probably still need to select appropriate neutral colors. Common design practice is to try to find the sweet spot where there's just enough contrast that the text is crisp and readable but not enough contrast to become harsh for the eyes. It's easy to go too far in one way or another so be sure to get feedback on your colors once you've selected them and have examples of them in use available. If the contrast is too low, your text will tend to be washed out by the background, leaving it unreadable, but if your contrast is too high, the user may find your site garish and unpleasant to look at.

+ +

Color, backgrounds, contrast, and printing

+ +

What looks good on screen may look very different on paper. In addition, ink can be expensive, and if a user is printing your page, they don't necessarily need all the backgrounds and such using up their precious ink when all that matters is the text itself. Most browsers, by default, remove background images when printing documents.

+ +

If your background colors and images have been selected carefully and/or are crucial to the usefulness of the content, you can use the CSS {{cssxref("color-adjust")}} property to tell the browser that it should not make adjustments to the appearance of content.

+ +

The default value of color-adjust, economy, indicates that the browser is allowed to make appearance changes as it deems necessary in order to try to optimize the legibility and/or print economy of the content, given the type of output device the document is being drawn onto.

+ +

You can set color-adjust to exact to tell the browser that the element or elements on which you use it have been designed specifically to best work with the colors and images left as they are. With this set, the browser won't tamper with the appearance of the element, and will draw it as indicated by your CSS.

+ +
+

Note: There is no guarantee, though, that color-adjust: exact will result in your CSS being used exactly as given. If the browser provides user preferences to change the output (such as a "don't print backgrounds" checkbox in a print dialog box), that overrides the value of color-adjust.

+
+ +

See also

+ + diff --git a/files/zh-tw/web/html/attributes/index.html b/files/zh-tw/web/html/attributes/index.html new file mode 100644 index 0000000000..834f36b4a9 --- /dev/null +++ b/files/zh-tw/web/html/attributes/index.html @@ -0,0 +1,643 @@ +--- +title: HTML attribute reference +slug: Web/HTML/Attributes +translation_of: Web/HTML/Attributes +--- +

HTML 中的元素具有屬性 ; 而這些屬性可以藉由各種方式去設定元素或調整它們的行為,以符合使用者的期待。

+ +

屬性列表

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
屬性名稱元素描述
hiddenGlobal attribute避免呈現給定的元素,並且保持子元素,例如 script elements、active。
high{{ HTMLElement("meter") }}指示下界的上限範圍。
href{{ HTMLElement("a") }}, {{ HTMLElement("area") }}, {{ HTMLElement("base") }}, {{ HTMLElement("link") }}連結資源的 URL。
hreflang{{ HTMLElement("a") }}, {{ HTMLElement("area") }}, {{ HTMLElement("link") }}指定連結資源的語言。
http-equiv{{ HTMLElement("meta") }} 
icon{{ HTMLElement("command") }}指定呈現指令的圖片。
idGlobal attribute經常和 CSS 一起被用來設計特定元素。這個屬性的值必須是唯一的。
ismap{{ HTMLElement("img") }}指示該圖像是伺服器端之影像地圖的一部分。
itempropGlobal attribute 
keytype{{ HTMLElement("keygen") }}指定所生成密鑰的類型。
kind{{ HTMLElement("track") }}指明文章 track 的類型。
label{{ HTMLElement("track") }}指明文章 track 的使用者可讀之標題。
langGlobal attribute定義該元素中所使用的語言。
language{{ HTMLElement("script") }}定義該元素中所使用的腳本語言。
list{{ HTMLElement("input") }}指示一串預先定義的選項供使用者參考。
loop{{ HTMLElement("audio") }}, {{ HTMLElement("bgsound") }}, {{ HTMLElement("marquee") }}, {{ HTMLElement("video") }}指示當媒體完成時,是否應該從一開始的時候播放。
low{{ HTMLElement("meter") }}指示上界的下限範圍。
manifest{{ HTMLElement("html") }}指定文件中緩存清單的 URL。
max{{ HTMLElement("input") }}, {{ HTMLElement("meter") }}, {{ HTMLElement("progress") }}指示所允許的最大值。
maxlength{{ HTMLElement("input") }}, {{ HTMLElement("textarea") }}定義該元素中所允許的最大字元數目。
media{{ HTMLElement("a") }}, {{ HTMLElement("area") }}, {{ HTMLElement("link") }}, {{ HTMLElement("source") }}, {{ HTMLElement("style") }}指定一些連接資源已經被設計的媒體。
method{{ HTMLElement("form") }}定義當呈交該格式時,哪個 HTTP 方法要被使用。可以用 GET(預設)或是 POST。
min{{ HTMLElement("input") }}, {{ HTMLElement("meter") }}指示所允許的最小值。
multiple{{ HTMLElement("input") }}, {{ HTMLElement("select") }}指示多個值是否可以進入單一輸入的 email 或是 file 之類別。
name{{ HTMLElement("button") }}, {{ HTMLElement("form") }}, {{ HTMLElement("fieldset") }}, {{ HTMLElement("iframe") }}, {{ HTMLElement("input") }}, {{ HTMLElement("keygen") }}, {{ HTMLElement("object") }}, {{ HTMLElement("output") }}, {{ HTMLElement("select") }}, {{ HTMLElement("textarea") }}, {{ HTMLElement("map") }}, {{ HTMLElement("meta") }}, {{ HTMLElement("param") }} +

元素的名字。例如被伺服器所使用時,來識別格式提交的現場。

+
novalidate{{ HTMLElement("form") }}該屬性指示當本格式被提交時,並無法通過驗證。
open{{ HTMLElement("details") }}指示是否細節顯示於加載頁面上。
optimum{{ HTMLElement("meter") }}指示最佳化數值。
pattern{{ HTMLElement("input") }}定義一個元素值將被驗證的正規表達式。
ping{{ HTMLElement("a") }}, {{ HTMLElement("area") }} 
placeholder{{ HTMLElement("input") }}, {{ HTMLElement("textarea") }}提示使用者什麼可以被輸入進該區。
poster{{ HTMLElement("video") }} +

顯現一個指示 poster frame 的 URL,直到使用者撥放或是搜索。

+
preload{{ HTMLElement("audio") }}, {{ HTMLElement("video") }}指示是否整個資源、一部分的資源、或是沒有資源應該被預先裝載。
pubdate{{ HTMLElement("time") }}指示該日期和時間,是否和距離最近的 {{ HTMLElement("article") }} 舊元素的日期一樣。
radiogroup{{ HTMLElement("command") }} 
readonly{{ HTMLElement("input") }}, {{ HTMLElement("textarea") }}指示是否該元素可以被編輯。
rel{{ HTMLElement("a") }}, {{ HTMLElement("area") }}, {{ HTMLElement("link") }}指定目標物件和連結物驗的關係。
required{{ HTMLElement("input") }}, {{ HTMLElement("select") }}, {{ HTMLElement("textarea") }}指示該元素是否被要求填寫。
reversed{{ HTMLElement("ol") }}指示該目錄是否應以降序展出而不是升序。
rows{{ HTMLElement("textarea") }}定義 textarea 的行數。
rowspan{{ HTMLElement("td") }}, {{ HTMLElement("th") }}定義表格單元的行數應該被 span over。
sandbox{{ HTMLElement("iframe") }} 
spellcheckGlobal attribute指示為該元素的拼字檢查是否允許。
scope{{ HTMLElement("th") }} 
scoped{{ HTMLElement("style") }} 
seamless{{ HTMLElement("iframe") }} 
selected{{ HTMLElement("option") }}定義一個值將被選擇到上載頁面中。
shape{{ HTMLElement("a") }}, {{ HTMLElement("area") }} 
size{{ HTMLElement("input") }}, {{ HTMLElement("select") }}定義元素的寬度 (以 pixel 為單位) 。如果該元素之類型的屬性是文本或是密碼,那麼它就是字元的數目。
sizes{{ HTMLElement("link") }} 
span{{ HTMLElement("col") }}, {{ HTMLElement("colgroup") }} 
src{{ HTMLElement("audio") }}, {{ HTMLElement("embed") }}, {{ HTMLElement("iframe") }}, {{ HTMLElement("img") }}, {{ HTMLElement("input") }}, {{ HTMLElement("script") }}, {{ HTMLElement("source") }}, {{ HTMLElement("track") }}, {{ HTMLElement("video") }}可嵌入內容的網址。
srcdoc{{ HTMLElement("iframe") }} 
srclang{{ HTMLElement("track") }} 
srcset{{ HTMLElement("img") }} 
start{{ HTMLElement("ol") }}如果第一個數字不是 1 的話,則定義該數。
step{{ HTMLElement("input") }} 
styleGlobal attribute定義多載先前的樣式設定之 CSS 樣式。
summary{{ HTMLElement("table") }} 
tabindexGlobal attribute多載瀏覽器的預設頁面標籤之順序並且遵守指定的那個。
target{{ HTMLElement("a") }}, {{ HTMLElement("area") }}, {{ HTMLElement("base") }}, {{ HTMLElement("form") }} 
titleGlobal attribute當滑鼠標停在元素時,文本會顯示在工具提示中。
type{{ HTMLElement("button") }}, {{ HTMLElement("input") }}, {{ HTMLElement("command") }}, {{ HTMLElement("embed") }}, {{ HTMLElement("object") }}, {{ HTMLElement("script") }}, {{ HTMLElement("source") }}, {{ HTMLElement("style") }}, {{ HTMLElement("menu") }}定義元素的類型。
usemap{{ HTMLElement("img") }},  {{ HTMLElement("input") }}, {{ HTMLElement("object") }} 
value{{ HTMLElement("button") }}, {{ HTMLElement("option") }}, {{ HTMLElement("input") }}, {{ HTMLElement("li") }}, {{ HTMLElement("meter") }}, {{ HTMLElement("progress") }}, {{ HTMLElement("param") }}定義將顯示在加載頁面上元素的預設值。
width{{ HTMLElement("canvas") }}, {{ HTMLElement("embed") }}, {{ HTMLElement("iframe") }}, {{ HTMLElement("img") }}, {{ HTMLElement("input") }}, {{ HTMLElement("object") }}, {{ HTMLElement("video") }}注意 : 在有些情況中,例如 {{ HTMLElement("div") }},這是傳統的屬性,而 CSS {{ Cssxref("width") }} 特性應當被使用。在其他的情況中,例如 {{ HTMLElement("canvas") }} ,寬度必須用該屬性來指定。
wrap{{ HTMLElement("textarea") }}指定文章是否要被掩飾。
border{{ HTMLElement("img") }}, {{ HTMLElement("object") }}, {{ HTMLElement("table") }} +

邊界寬度。

+ +

注意 : 這是一個傳統的屬性。請利用 CSS {{ Cssxref("border") }} 特性。

+
buffered{{ HTMLElement("audio") }}, {{ HTMLElement("video") }}包含被緩衝之媒體的時間範圍。
challenge{{ HTMLElement("keygen") }}隨著公共密鑰提交的挑戰字串。
charset{{ HTMLElement("meta") }}, {{ HTMLElement("script") }}聲明頁面或腳本的字元編碼。
checked{{ HTMLElement("command") }}, {{ HTMLElement("input") }}指定在加載頁面上的元素是否要被檢查。
cite{{ HTMLElement("blockquote") }}, {{ HTMLElement("del") }}, {{ HTMLElement("ins") }}, {{ HTMLElement("q") }}包含一個 URL,用來指出引用或是改變的來源地址。
classGlobal attribute經常使用共同屬性和 CSS 一起設計元素。
code{{ HTMLElement("applet") }}指明被加載與執行的 applet 類別文件之 URL。
codebase{{ HTMLElement("applet") }}This attribute gives the absolute or relative URL of the directory where applets' .class files referenced by the code attribute are stored.
color{{ HTMLElement("basefont") }}, {{ HTMLElement("font") }}, {{ HTMLElement("hr") }} +

該屬性使用命名顏色或十六進制 #RRGGBB 格式來設置文本顏色。

+ +

注意 : 這是一個傳統的屬性。請使用 CSS {{ Cssxref("color") }} 特性。

+
cols{{ HTMLElement("textarea") }}定義在一個 textarea 中有多少欄位。
colspan{{ HTMLElement("td") }}, {{ HTMLElement("th") }}colspan 屬性定義一個單元格之欄位的數量。
content{{ HTMLElement("meta") }}一個有關於 http-equiv 或是根據上下文 name 的值 。
contenteditableGlobal attribute指定元素的內容是否可以被編輯。
contextmenuGlobal attribute定義將作為元素上下文選項單的 {{ HTMLElement("menu") }} 元素之 ID。
controls{{ HTMLElement("audio") }}, {{ HTMLElement("video") }}指定瀏覽器是否應該顯示錄放控制給使用者。
coords{{ HTMLElement("area") }}一組值指明熱點區域的座標。
+

data

+
+

{{ HTMLElement("object") }}

+
+

指明 URL 的資源。

+
+

data-*

+
+

Global attribute

+
+

讓您可以將自行定義屬性附加在 HTML 元素上。

+
datetime{{ HTMLElement("del") }}, {{ HTMLElement("ins") }}, {{ HTMLElement("time") }}指定元素所相關的日期與時間。
default{{ HTMLElement("track") }}指定 track 應被啟用,除非使用者的偏好表示不同。
defer{{ HTMLElement("script") }}指定該頁面被瀏覽完後腳本應被執行。
dirGlobal attribute定義文章的方向。被允許的值有 ltr (Left-To-Right) 或 rtl (Right-To-Left)。
dirname{{ HTMLElement("input") }}, {{ HTMLElement("textarea") }} 
disabled{{ HTMLElement("button") }}, {{ HTMLElement("command") }}, {{ HTMLElement("fieldset") }}, {{ HTMLElement("input") }}, {{ HTMLElement("keygen") }}, {{ HTMLElement("optgroup") }}, {{ HTMLElement("option") }}, {{ HTMLElement("select") }}, {{ HTMLElement("textarea") }}指名使用者是否可以與元素互動。
download{{ HTMLElement("a") }}, {{ HTMLElement("area") }} +

指定該超連結是用於下載的資源。

+
draggableGlobal attribute定義元素是否可以拖曳。
dropzoneGlobal attribute指定該元素接受它內容的滑鼠落下物。
enctype{{ HTMLElement("form") }}當方法為 POST 的時候,定義格式日期的內容類型。
for{{ HTMLElement("label") }}, {{ HTMLElement("output") }}描述屬於這一個的元素。
form{{ HTMLElement("button") }}, {{ HTMLElement("fieldset") }}, {{ HTMLElement("input") }}, {{ HTMLElement("keygen") }}, {{ HTMLElement("label") }}, {{ HTMLElement("meter") }}, {{ HTMLElement("object") }}, {{ HTMLElement("output") }}, {{ HTMLElement("progress") }}, {{ HTMLElement("select") }}, {{ HTMLElement("textarea") }} +

指定元素之所有者的格式。

+
formaction{{ HTMLElement("input") }}, {{ HTMLElement("button") }}指定元素的作用,多載的動作被定義在 {{ HTMLElement("form") }}。
headers{{ HTMLElement("td") }}, {{ HTMLElement("th") }}對適用於該元素的 <th> 元素之 ID。
height{{ HTMLElement("canvas") }}, {{ HTMLElement("embed") }}, {{ HTMLElement("iframe") }}, {{ HTMLElement("img") }}, {{ HTMLElement("input") }}, {{ HTMLElement("object") }}, {{ HTMLElement("video") }}注意 : 在有些情況中,例如 {{ HTMLElement("div") }},這是傳統的屬性,而 CSS {{ Cssxref("height") }} 特性應當被使用。在其他的情況中,例如 {{ HTMLElement("canvas") }},高度必須用該屬性來指定。
accept{{ HTMLElement("form") }}, {{ HTMLElement("input") }}伺服器接受的類型之列表,通常是文件類型。
accept-charset{{ HTMLElement("form") }}支持字元集的列表。
accesskeyGlobal attribute定義鍵盤快捷鍵來啟動或添加焦點到該元素。
action{{ HTMLElement("form") }}一個程序處理經由該格式提交信息的 URI。
align{{ HTMLElement("applet") }}, {{ HTMLElement("caption") }}, {{ HTMLElement("col") }}, {{ HTMLElement("colgroup") }},  {{ HTMLElement("hr") }}, {{ HTMLElement("iframe") }}, {{ HTMLElement("img") }}, {{ HTMLElement("table") }}, {{ HTMLElement("tbody") }},  {{ HTMLElement("td") }},  {{ HTMLElement("tfoot") }} , {{ HTMLElement("th") }}, {{ HTMLElement("thead") }}, {{ HTMLElement("tr") }}指定元素的水平對齊方式。
alt +

{{ HTMLElement("applet") }}, {{ HTMLElement("area") }}, {{ HTMLElement("img") }}, {{ HTMLElement("input") }}

+
在圖像無法顯示的情況下,顯示代替文本。
async{{ HTMLElement("script") }}指定該腳本應該被不同步得執行。
autocomplete{{ HTMLElement("form") }}, {{ HTMLElement("input") }}指定是否以該格式控制,可以在默認情況下由瀏覽器自動完成其值。
autofocus{{ HTMLElement("button") }}, {{ HTMLElement("input") }}, {{ HTMLElement("keygen") }}, {{ HTMLElement("select") }}, {{ HTMLElement("textarea") }}該元素應該在頁面加載後自動焦距。
autoplay{{ HTMLElement("audio") }}, {{ HTMLElement("video") }}音頻或視頻應該越早撥放越好。
autosave{{ HTMLElement("input") }}上一個值應該持續存在到跨頁面加載的可選值之下拉列表中。
bgcolor{{ HTMLElement("body") }}, {{ HTMLElement("col") }}, {{ HTMLElement("colgroup") }}, {{ HTMLElement("marquee") }}, {{ HTMLElement("table") }}, {{ HTMLElement("tbody") }}, {{ HTMLElement("tfoot") }}, {{ HTMLElement("td") }}, {{ HTMLElement("th") }}, {{ HTMLElement("tr") }} +

元素的背景顏色。

+ +

注意 : 這是一個傳統的屬性。請使用 CSS {{ Cssxref("background-color") }} 特性。

+
+ +

內容與IDL屬性

+ +

在 HTML 中,大部分的屬性有兩種面向 : 內容屬性IDL 屬性

+ +

內容屬性是您可以從內容中設定的屬性 (HTML 程式碼) 而且您可以藉由 {{domxref("element.setAttribute()")}} 或是 {{domxref("element.getAttribute()")}} 來設定它或得到它。內容屬性永遠都是字串,即便我們所期望的值是一個整數。舉例來說,假設今天要用內容屬性去設定一個 {{HTMLElement("input")}} 元素的最大長度是42,您必須在該元素上呼叫 setAttribute("maxlength", "42")。

+ +

IDL 屬性也被稱為 JavaScript 特性。您可以使用 JavaScript 特性的 element.foo 以閱讀或是設定這些屬性。當您要得到 IDL 屬性時,它總是要使用 (但可能改變) 基本的內容屬性以返回值,而當您要設定 IDL 屬性時,它需要儲存資料在內容屬性中。換句話說,IDL 屬性在本質上反映了內容屬性。

+ +

在大部分的時間中,當 IDL 屬性真正被使用時,將會返回它們的值。舉例而言,{{HTMLElement("input")}} 元素的預設型態是 "text",所以如果您設定 input.type="foobar",<input> 元素一樣是 text 的型態 (在外觀和行為上而言),但是 "type" 內容屬性的值將會變成 "foobar"。然而,IDL 屬性的型態將會回傳 "text" 字串。

+ +

IDL 屬性並非永遠的字串 ; 舉例來說,input.maxlength 便是一個數字(型態為 signed long)。當使用 IDL 屬性,您會閱讀或是設定所需的型態,而當您設定 input.maxlength 時,它總是回傳一個數字,因為它正需要一個數字。如果您傳入別的型態,它會依照標準 JavaScript 型態轉換規則,將傳入值轉成一個數字。

+ +

IDL 屬性可以 反應其他型態,例如 unsigned long、URLs、booleans,等等。不幸的是,並沒有明確的規則來規範,而且與 IDL 屬性行為相對應的內容屬性連結中,也沒有取決於該屬性的方式。在大部分的時間裡,它會遵守 規範中所制定的規則,但有時候它並不會。HTML 規範嘗試讓它變得容易使用,但由於各種原因 (大多是因為歷史),有些屬性表現得很奇怪 (舉例來說,select.size),而您應該詳細閱讀規範以了解各個屬性的行為。

+ +

另請參見

+ + diff --git a/files/zh-tw/web/html/block-level_elements/index.html b/files/zh-tw/web/html/block-level_elements/index.html new file mode 100644 index 0000000000..32d8a405b0 --- /dev/null +++ b/files/zh-tw/web/html/block-level_elements/index.html @@ -0,0 +1,130 @@ +--- +title: 區塊級元素 +slug: Web/HTML/Block-level_elements +translation_of: Web/HTML/Block-level_elements +--- +

HTML (超文字標記語言, Hypertext Markup Language) 元素通常為 "區塊級" 元素或是 "行內" 元素。 一個區塊級元素會藉由建立"區塊"的動作, 完全佔滿其父元素(容器)的空間。本文將為您說明其意涵.

+ +

瀏覽器預設以在元素前後換行的方式, 表現區塊級元素. 視覺上會呈現為一排縱向堆疊的方塊。

+ +
+

區塊級元素必定以換行方式, 取得完整寬度的空間(向左右兩側儘可能地延伸出去)。

+
+ +

以下範例將展示區塊級元素的影響:

+ +

區塊級元素

+ +

HTML

+ +
<p>This paragraph is a block-level element; its background has been colored to display the paragraph's parent element.</p>
+ +

CSS

+ +
p { background-color: #8ABB55; }
+
+ +

{{ EmbedLiveSample('Block-level_Example') }}

+ +

用法

+ + + +

區塊級 vs. 行內元素

+ +

There are a couple of key differences between block-level elements and inline elements:

+ +
+
Formatting
+
By default, block-level elements begin on new lines, but inline elements can start anywhere in a line.
+
Content model
+
Generally, block-level elements may contain inline elements and other block-level elements. Inherent in this structural distinction is the idea that block elements create "larger" structures than inline elements.
+
+ +

The distinction of block-level vs. inline elements is used in HTML specifications up to 4.01. In HTML5, this binary distinction is replaced with a more complex set of content categories. The "block-level" category roughly corresponds to the category of flow content in HTML5, while "inline" corresponds to phrasing content, but there are additional categories.

+ +

相關元素

+ +

The following is a complete list of all HTML block level elements (although "block-level" is not technically defined for elements that are new in HTML5).

+ +
+
+
{{ HTMLElement("address") }}
+
Contact information.
+
{{ HTMLElement("article") }} {{ HTMLVersionInline(5) }}
+
Article content.
+
{{ HTMLElement("aside") }} {{ HTMLVersionInline(5) }}
+
Aside content.
+
{{ HTMLElement("blockquote") }}
+
Long ("block") quotation.
+
{{ HTMLElement("canvas") }} {{ HTMLVersionInline(5) }}
+
Drawing canvas.
+
{{ HTMLElement("dd") }}
+
Describes a term in a description list.
+
{{ HTMLElement("div") }}
+
Document division.
+
{{ HTMLElement("dl") }}
+
Description list.
+
{{ HTMLElement("dt") }}
+
Description list term.
+
{{ HTMLElement("fieldset") }}
+
Field set label.
+
+ +
+
{{ HTMLElement("figcaption") }} {{ HTMLVersionInline(5) }}
+
Figure caption.
+
{{ HTMLElement("figure") }} {{ HTMLVersionInline(5) }}
+
Groups media content with a caption (see {{ HTMLElement("figcaption") }}).
+
{{ HTMLElement("footer") }} {{ HTMLVersionInline(5) }}
+
Section or page footer.
+
{{ HTMLElement("form") }}
+
Input form.
+
{{ HTMLElement("h1") }}, {{ HTMLElement("h2") }}, {{ HTMLElement("h3") }}, {{ HTMLElement("h4") }}, {{ HTMLElement("h5") }}, {{ HTMLElement("h6") }}
+
Heading levels 1-6.
+
{{ HTMLElement("header") }} {{ HTMLVersionInline(5) }}
+
Section or page header.
+
{{ HTMLElement("hgroup") }} {{ HTMLVersionInline(5) }}
+
Groups header information.
+
{{ HTMLElement("hr") }}
+
Horizontal rule (dividing line).
+
{{ HTMLElement("li") }}
+
List item.
+
{{ HTMLElement("main") }}
+
Contains the central content unique to this document.
+
{{ HTMLElement("nav") }}
+
Contains navigation links.
+
+ +
+
{{ HTMLElement("noscript") }}
+
Content to use if scripting is not supported or turned off.
+
{{ HTMLElement("ol") }}
+
Ordered list.
+
{{ HTMLElement("output") }} {{ HTMLVersionInline(5) }}
+
Form output.
+
{{ HTMLElement("p") }}
+
Paragraph.
+
{{ HTMLElement("pre") }}
+
Preformatted text.
+
{{ HTMLElement("section") }} {{ HTMLVersionInline(5) }}
+
Section of a web page.
+
{{ HTMLElement("table") }}
+
Table.
+
{{ HTMLElement("tfoot") }}
+
Table footer.
+
{{ HTMLElement("ul") }}
+
Unordered list.
+
{{ HTMLElement("video") }} {{ HTMLVersionInline(5) }}
+
Video player.
+
+
+ +


+ 參閱

+ + diff --git a/files/zh-tw/web/html/element/a/index.html b/files/zh-tw/web/html/element/a/index.html new file mode 100644 index 0000000000..91224a9318 --- /dev/null +++ b/files/zh-tw/web/html/element/a/index.html @@ -0,0 +1,313 @@ +--- +title: +slug: Web/HTML/Element/a +translation_of: Web/HTML/Element/a +--- +

HTML <a> 元素(意為 Anchor)建立了通往其他頁面、檔案、Email 地址、或其他 URL 的超連結。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
內容類型流型內容phrasing content, interactive content, palpable content.
內容省略Transparent, containing either flow content (excluding interactive content) or phrasing content.
標籤省略{{no_tag_omission}}
允許的父元素任何允許 phrasing contentflow content 的內容,但 <a> 永遠例外(according to the logical principle of symmetry, if <a> tag, as a parent, can not have interactive content, then the same <a> content can not have <a> tag as its parent)
Permitted ARIA roles{{ARIARole("button")}}, {{ARIARole("checkbox")}}, {{ARIARole("menuitem")}}, {{ARIARole("menuitemcheckbox")}}, {{ARIARole("menuitemradio")}}, {{ARIARole("option")}}, {{ARIARole("radio")}}, {{ARIARole("switch")}}, {{ARIARole("tab")}}, {{ARIARole("treeitem")}}
DOM 介面{{domxref("HTMLAnchorElement")}}
+ +

屬性

+ +

本元素包含全域屬性

+ +
+
{{htmlattrdef("download")}} {{HTMLVersionInline(5)}}
+
This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). There are no restrictions on allowed values, though / and \ are converted to underscores. Most file systems limit some punctuation in file names, and browsers will adjust the suggested name accordingly. +
Notes: +
    +
  • This attribute only works for same-origin URLs.
  • +
  • This attribute can be used with blob: URLs and data: URLs to download content generated by JavaScript, such as pictures created in an image-editor Web app.
  • +
  • If the HTTP header Content-Disposition: gives a different filename than this attribute, the HTTP header takes priority over this attribute.
  • +
  • If Content-Disposition: is set to inline, Firefox prioritizes Content-Disposition, like the filename case, while Chrome prioritizes the download attribute.
  • +
+
+
+
{{htmlattrdef("href")}}
+
Contains a URL or a URL fragment that the hyperlink points to.
+
A URL fragment is a name preceded by a hash mark (#), which specifies an internal target location (an ID of an HTML element) within the current document. URLs are not restricted to Web (HTTP)-based documents, but can use any protocol supported by the browser. For example, file:, ftp:, and mailto: work in most browsers.
+
This attribute may be omitted (as of HTML5) to create a placeholder link. A placeholder link resembles a traditional hyperlink, but does not lead anywhere. +
+

Note: You can use href="#top" or the empty fragment href="#" to link to the top of the current page. This behavior is specified by HTML5.

+
+
+
{{htmlattrdef("hreflang")}}
+
This attribute indicates the human language of the linked resource. It is purely advisory, with no built-in functionality. Allowed values are determined by BCP47.
+
{{htmlattrdef("ping")}}
+
Contains a space-separated list of URLs to which, when the hyperlink is followed, {{HTTPMethod("POST")}} requests with the body PING will be sent by the browser (in the background). Typically used for tracking.
+
{{htmlattrdef("referrerpolicy")}} {{experimental_inline}}
+
Indicates which referrer to send when fetching the URL: +
    +
  • 'no-referrer' means the Referer: header will not be sent.
  • +
  • 'no-referrer-when-downgrade' means no Referer: header will be sent when navigating to an origin without HTTPS. This is the default behavior.
  • +
  • 'origin' means the referrer will be the origin of the page, not including information after the domain.
  • +
  • 'origin-when-cross-origin' meaning that navigations to other origins will be limited to the scheme, the host and the port, while navigations on the same origin will include the referrer's path.
  • +
  • 'unsafe-url' means the referrer will include the origin and path, but not the fragment, password, or username. This is unsafe because it can leak data from secure URLs to insecure ones.
  • +
+
+
{{htmlattrdef("rel")}}
+
Specifies the relationship of the target object to the link object. The value is a space-separated list of link types.
+
{{htmlattrdef("target")}}
+
Specifies where to display the linked URL. It is a name of, or keyword for, a browsing context: a tab, window, or <iframe>. The following keywords have special meanings: +
    +
  • _self: Load the URL into the same browsing context as the current one. This is the default behavior.
  • +
  • _blank: Load the URL into a new browsing context. This is usually a tab, but users can configure browsers to use new windows instead.
  • +
  • _parent: Load the URL into the parent browsing context of the current one. If there is no parent, this behaves the same way as _self.
  • +
  • _top: Load the URL into the top-level browsing context (that is, the "highest" browsing context that is an ancestor of the current one, and has no parent). If there is no parent, this behaves the same way as _self.
  • +
+ +
+

Note: When using target, consider adding rel="noopener noreferrer" to avoid exploitation of the window.opener API.

+
+
+
{{htmlattrdef("type")}}
+
Specifies the media type in the form of a {{Glossary("MIME type")}} for the linked URL. It is purely advisory, with no built-in functionality.
+
+ +

Obsolete

+ +
+
{{htmlattrdef("charset")}} {{obsoleteGeneric("inline","HTML5")}}
+
This attribute defined the character encoding of the linked URL. The value should be a space- and/or comma-delimited list of character sets defined in RFC 2045. The default value is ISO-8859-1. +
+

Usage note: This attribute is obsolete in HTML5 and should not be used by authors. To achieve its effect, use the HTTP Content-Type: header on the linked URL.

+
+
+
{{htmlattrdef("coords")}} {{HTMLVersionInline(4)}} only, {{obsoleteGeneric("inline","HTML5")}}
+
For use with the below shape attribute, this attribute used a comma-separated list of numbers to define the coordinates of the link on the page.
+
{{htmlattrdef("name")}} {{HTMLVersionInline(4)}} only, {{obsoleteGeneric("inline","HTML5")}}
+
This attribute was required for anchors defining a possible target location within a page. In HTML 4.01, id and name could be used simultaneously on a <a> element as long as they have identical values. +
+

Usage note: This attribute is obsolete in HTML5, use the global attribute id instead.

+
+
+
{{htmlattrdef("rev")}} {{HTMLVersionInline(4)}} only, {{obsoleteGeneric("inline","HTML5")}}
+
This attribute specified a reverse link, the inverse relationship of the rel attribute. It was deprecated for being very confusing.
+
{{htmlattrdef("shape")}} {{HTMLVersionInline(4)}} only, {{obsoleteGeneric("inline","HTML5")}}
+
This attribute was used to define a region for hyperlinks to create an image map. The values are circle, default, polygon, and rect. The format of the coords attribute depends on the value of shape. For circle, the value is x,y,r where x and y are the pixel coordinates for the center of the circle and r is the radius value in pixels. For rect, the coords attribute should be x,y,w,h. The x,y values define the upper-left-hand corner of the rectangle, while w and h define the width and height respectively. A value of polygon for shape requires x1,y1,x2,y2,... values for coords. Each of the x,y pairs defines a point in the polygon, with successive points being joined by straight lines and the last point joined to the first. The value default for shape requires that the entire enclosed area, typically an image, be used. +
Note: Use the usemap attribute for the {{HTMLElement("img")}} element and the associated {{HTMLElement("map")}} element to define hotspots instead of the shape attribute.
+
+
+ +

Examples

+ +

Linking to an external location

+ +
<!-- anchor linking to external file -->
+<a href="https://www.mozilla.com/">
+External Link
+</a>
+
+ +

Result

+ +

External Link

+ +

Linking to another section on the same page

+ +
<!-- links to element on this page with id="attr-href" -->
+<a href="#attr-href">
+Description of Same-Page Links
+</a>
+
+ +

Result

+ +

Description of Same Page Links

+ +

Creating a clickable image

+ +

This example uses an image to link to the MDN home page. The home page will open in a new browsing context, that is, a new page or a new tab.

+ +
<a href="https://developer.mozilla.org/en-US/" target="_blank">
+  <img src="https://mdn.mozillademos.org/files/6851/mdn_logo.png"
+       alt="MDN logo" />
+</a>
+
+ +

Result

+ +
+

{{EmbedLiveSample("Creating_a_clickable_image", "320", "64")}}

+
+ + + +

It's common to create links that open in the user's email program to allow them to send a new message. This is done with a mailto: link. Here's a simple example:

+ +
<a href="mailto:nowhere@mozilla.org">Send email to nowhere</a>
+ +

Result

+ +

Send email to nowhere

+ +

For additional details about the mailto URL scheme, such as including the subject, body, or other predetermined content, see Email links or {{RFC(6068)}}.

+ + + +

Offering phone links is helpful for users viewing web documents and laptops connected to phones.

+ +
<a href="tel:+491570156">+49 157 0156</a>
+ +

For additional details about the tel URL scheme, see {{RFC(3966)}}.

+ +

Using the download attribute to save a <canvas> as a PNG

+ +

If you want to let users download an HTML {{HTMLElement("canvas")}} element as an image, you can create a link with a download attribute and the canvas data as a file URL:

+ +
var link = document.createElement('a');
+link.textContent = 'download image';
+
+link.addEventListener('click', function(ev) {
+    link.href = canvas.toDataURL();
+    link.download = "mypainting.png";
+}, false);
+
+document.body.appendChild(link);
+ +

You can see this in action at jsfiddle.net/codepo8/V6ufG/2/.

+ +

Notes

+ +

HTML 3.2 defines only the name, href, rel, rev, and title attributes.

+ +

Accessibility recommendations

+ +

Anchor tags are often abused with the onclick event to create pseudo-buttons by setting href to "#" or "javascript:void(0)" to prevent the page from refreshing. These values cause unexpected behavior when copying/dragging links, opening links in a new tabs/windows, bookmarking, and when JavaScript is still downloading, errors out, or is disabled. This also conveys incorrect semantics to assistive technologies (e.g., screen readers). In these cases, it is recommended to use a {{HTMLElement("button")}} instead. In general you should only use an anchor for navigation using a proper URL.

+ +

Clicking and focus

+ +

Whether clicking on an {{HTMLElement("a")}} causes it to become focused varies by browser and OS.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Does clicking on an {{HTMLElement("a")}} give it focus?
Desktop BrowsersWindows 8.1OS X 10.9
Firefox 30.0YesYes
Chrome ≥39
+ (Chromium bug 388666)
YesYes
Safari 7.0.5N/AOnly when it has a tabindex
Internet Explorer 11YesN/A
Presto (Opera 12)YesYes
+ + + + + + + + + + + + + + + + + + + + +
Does tapping on an {{HTMLElement("a")}} give it focus?
Mobile BrowsersiOS 7.1.2Android 4.4.4
Safari MobileOnly when it has a tabindexN/A
Chrome 35???Only when it has a tabindex
+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Referrer Policy', '#referrer-policy-delivery-referrer-attribute', 'referrer attribute')}}{{Spec2('Referrer Policy')}}Added the referrer attribute.
{{SpecName('HTML WHATWG', 'semantics.html#the-a-element', '<a>')}}{{Spec2('HTML WHATWG')}}
{{SpecName('HTML5 W3C', 'text-level-semantics.html#the-a-element', '<a>')}}{{Spec2('HTML5 W3C')}}
{{SpecName('HTML4.01', 'struct/links.html#h-12.2', '<a>')}}{{Spec2('HTML4.01')}}
+ +

Browser compatibility

+ + + +

{{Compat("html.elements.a")}}

+ +

See also

+ + + +
{{HTMLRef}}
diff --git a/files/zh-tw/web/html/element/blink/index.html b/files/zh-tw/web/html/element/blink/index.html new file mode 100644 index 0000000000..9913548a5c --- /dev/null +++ b/files/zh-tw/web/html/element/blink/index.html @@ -0,0 +1,75 @@ +--- +title: :文字閃爍元素(已過時) +slug: Web/HTML/Element/blink +translation_of: Web/HTML/Element/blink +--- +
{{Deprecated_header}} {{obsolete_header}}
+ +

非標準元素 HTML Blink<blink>)可以讓該元素裡面的文字緩慢閃爍。

+ +
不要使用這個元素,因為它已經被棄用,而且是糟糕的設計。無障礙標準不會接受閃爍文字、而 CSS 規範上允許瀏覽器忽略閃爍效果。
+ +

DOM 介面

+ +

此元素並未被支援,因此是透過 {{domxref("HTMLUnknownElement")}} 介面實做。

+ +

示例

+ +
<blink>Why would somebody use this?</blink>
+
+ +

結果(已經過淡化!)

+ +

Image:HTMLBlinkElement.gif

+ +

規範

+ +

此元素並非標準元素,也不屬於任何規範。不信的話,你自己來看 HTML 規範

+ +

CSS Polyfill

+ +

如果真的需要 polyfill,請使用以下的 CSS。它支援 IE10 以上。

+ +
blink {
+    -webkit-animation: 2s linear infinite condemned_blink_effect; // for android
+    animation: 2s linear infinite condemned_blink_effect;
+}
+@-webkit-keyframes condemned_blink_effect { // for android
+    0% {
+        visibility: hidden;
+    }
+    50% {
+        visibility: hidden;
+    }
+    100% {
+        visibility: visible;
+    }
+}
+@keyframes condemned_blink_effect {
+    0% {
+        visibility: hidden;
+    }
+    50% {
+        visibility: hidden;
+    }
+    100% {
+        visibility: visible;
+    }
+}
+ +

瀏覽器相容性

+ + + +

{{Compat("html.elements.blink")}}

+ +

參見

+ + + +

{{HTMLRef}}

diff --git a/files/zh-tw/web/html/element/blockquote/index.html b/files/zh-tw/web/html/element/blockquote/index.html new file mode 100644 index 0000000000..6b0fe2650f --- /dev/null +++ b/files/zh-tw/web/html/element/blockquote/index.html @@ -0,0 +1,149 @@ +--- +title:
+slug: Web/HTML/Element/blockquote +translation_of: Web/HTML/Element/blockquote +--- +

摘要

+ +

HTML <blockquote> 元素HTML 區塊引言元素)定義一段文字屬於引用。通常,這元素會透過縮排來呈現(要知道如何改變,請參考備註)。引言的 URL 來源可透過 cite 屬性賦予,而來源的文本形式可以使用 {{HTMLElement("cite")}} 元素。

+ + + + + + + + + + + + + + + + + + + + + + + + +
內容類別流內容、sectioning root、捫及內容。
允許內容內容流.
Tag 省略{{no_tag_omission}}
允許父元素任何允許內容流的元素
DOM 介面{{domxref("HTMLQuoteElement")}}
+ +

屬性

+ +

這個屬性包含全局屬性

+ +
+
{{htmlattrdef("cite")}}
+
一個指向被引用的原始文件或訊息的 URL 。這個屬性預期要指引到解釋內容的資訊,或是引言的援引。
+
+ +

範例

+ +
<blockquote cite="http://developer.mozilla.org">
+  <p>這是取自於 Mozilla Developer Center 的引言。</p>
+</blockquote>
+
+ +

以上的 HTML 原始碼會輸出:

+ +
+

這是取自於 Mozilla Developer Center 的引言。

+
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('HTML WHATWG', 'semantics.html#the-blockquote-element', '<blockquote>')}}{{Spec2('HTML WHATWG')}} 
{{SpecName('HTML5 W3C', 'grouping-content.html#the-blockquote-element', '<blockquote>')}}{{Spec2('HTML5 W3C')}} 
{{SpecName('HTML4.01', 'struct/text.html#h-9.2.2', '<blockquote>')}}{{Spec2('HTML4.01')}} 
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
特徵ChromeFirefox (Gecko)Internet ExplorerOperaSafari
基本支援{{CompatVersionUnknown}}{{CompatGeckoDesktop("1.0")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + +
特徵AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
基本支援{{CompatVersionUnknown}}{{CompatGeckoMobile("1.0")}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
+
+ +

備註

+ +

要改變<blockquote>的縮進,請使用 CSS 的 {{cssxref("margin")}} 屬性。

+ +

針對短篇引文請使用 {{HTMLElement("q")}} 元素。

+ +

延伸閱讀

+ +
    +
  • {{HTMLElement("q")}} 元素:用以表示單行的引用內容。
  • +
  • {{HTMLElement("cite")}} 元素:用以表示引用來源。
  • +
+ +

{{HTMLRef}}

diff --git a/files/zh-tw/web/html/element/br/index.html b/files/zh-tw/web/html/element/br/index.html new file mode 100644 index 0000000000..2542c0182e --- /dev/null +++ b/files/zh-tw/web/html/element/br/index.html @@ -0,0 +1,130 @@ +--- +title:
(斷行元素) +slug: Web/HTML/Element/br +translation_of: Web/HTML/Element/br +--- +
{{HTMLRef}}
+ +

HTML <br> 元素會產生文字的斷行(carriage-return、CR 或是確認鍵)。此元素主要用於斷行有所意義的時候,像是寫詩或寫住址。

+ +
{{EmbedInteractiveExample("pages/tabbed/br.html", "tabbed-standard")}}
+ + + +

如上所示,<br> 元素會在需要斷行的時候出現。在 <br> 之後的文字會從文字區域的下一行出現。

+ +
+

注意:不要用 <br> 建立段落間距:這種情況下要用 {{htmlelement("p")}} 把它們包起來,並使用 CSS {{cssxref('margin')}} 屬性控制間距大小。

+
+ +

屬性

+ +

這個元件屬性含有全域屬性

+ +

棄用屬性

+ +
+
{{htmlattrdef("clear")}}
+
指示中斷後下一行的開始位置。
+
+ +

使用 CSS 樣式化

+ +

<br> 元素有一個定義明確的用途:在文字區塊裡面建立斷行。因此它本身沒有尺寸或視覺輸出,基本上你做不了任何樣式化。

+ +

你可以給 <br> 元素設置 {{cssxref("margin")}} 以增加文字之間的斷行大小,但這並不是正確的作法:你應該用 {{cssxref("line-height")}} 屬性做這件事情。

+ +

示例

+ +
Mozilla Foundation<br>
+1981 Landings Drive<br>
+Building K<br>
+Mountain View, CA 94043-0801<br>
+USA
+
+ +

以上 HTML 將顯示

+ +

{{ EmbedLiveSample('示例', '100%', '90') }}

+ +

無障礙議題

+ +

使用 <br> 元素分段不只作法不佳,對於使用輔具的人來說,也會是有問題的。螢幕閱讀器會念出該元素,但 <br> 裡面的內容是念不出來的。對於使用螢幕閱讀器的人來說,這可能是困惑與沮喪的體驗。

+ +

請使用 <p> 元素搭配 CSS 屬性如 {{cssxref("margin")}} 來控制間距大小。

+ +

技術摘要

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
內容類型流型內容段落型內容
允許內容無,這是個{{Glossary("空元素")}}.
標籤省略絕對要有開啟標籤,也絕不能關閉標籤。在 XHTML 文件內,要把這個元素寫成 <br />.
允許父元素任何接受段落型內容的元素
允許的 ARIA roles所有
DOM 介面{{domxref("HTMLBRElement")}}
+ +

規範

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('HTML WHATWG', 'semantics.html#the-br-element', '<br>')}}{{Spec2('HTML WHATWG')}}
{{SpecName('HTML5 W3C', 'textlevel-semantics.html#the-br-element', '<br>')}}{{Spec2('HTML5 W3C')}}
{{SpecName('HTML4.01', 'struct/text.html#h-9.3.2.1', '<br>')}}{{Spec2('HTML4.01')}}
+ +

瀏覽器相容性

+ + + +

{{Compat("html.elements.br")}}

+ +

參見

+ +
    +
  • {{HTMLElement("address")}} 元素
  • +
  • {{HTMLElement("p")}} 元素
  • +
  • {{HTMLElement("wbr")}} 元素
  • +
+ +
{{HTMLRef}}
diff --git a/files/zh-tw/web/html/element/button/index.html b/files/zh-tw/web/html/element/button/index.html new file mode 100644 index 0000000000..a78352ca0f --- /dev/null +++ b/files/zh-tw/web/html/element/button/index.html @@ -0,0 +1,355 @@ +--- +title: