vuejs3 第2页
#概览 非兼容:自定义元素白名单现在在模板编译期间执行,应该通过编译器选项而不是运行时配置来配置。 非兼容:特定 is prop 用法仅限于保留的 <component> 标记。 新增:有了新的 v-is 指令来支持 2.x 用例,其中在原生元素上使用了 v-is 来处理原生 HTML 解析限制。 #自主定制元素 如果我们想添加在 Vue 外部定义的自定义元素 (例如使用 Web 组件 API),我们需要“指示”Vue 将其视为自定义元素。让我们以下面的模板为例。 <plastic-button></plastic-button> #2.x 语法 在 Vue 2.x 中,将标记作为自定义元素白名单是通过 Vue.config.ignoredElements: // 这将使Vue忽略在Vue外部定义的自定义元素 // (例如:使用 Web Components API) Vue.config.ignoredElements = ['plastic-button'] #3.x 语法 在 Vue 3.0 中,此检查在模板编译期间执行指示编译器将 <plastic-button> 视为自定义元素: 如果使用生成步骤:将 isCustomElement 传递给 Vue 模板编译器,如果使用 vue-loader,则应通过 vue-loader 的 compilerOptions 选项传递: // webpack 中的配置 rules: [ { test: /\.vue$/, use: 'vue-loader', options: { compilerOptions: { isCustomElement: tag => tag === 'plastic-button' } } } // ... ] 如果使用动态模板编译,请通过 app.config.isCustomElement 传递: const app = Vue.createApp({}) app.config.isCustomElement = tag => tag === 'plastic-button' 需要注意的是,运行时配置只会影响运行时模板编译——它不会影响预编译的模板。 #定制内置元素 自定义元素规范提供了一种将自定义元素用作自定义内置模板的方法,方法是向内置元素添加 is 属性: <button is="plastic-button">点击我!</button> Vue 对 is 特殊 prop 的使用是在模拟 native attribute 在浏览器中普遍可用之前的作用。但是,在 2.x 中,它被解释为渲染一个名为...
#文档 WCAG 2.0 WCAG 2.1 可访问的富 Internet 应用程序 (WAI-ARIA) 1.2 WAI-ARIA 创作实践 1.2 #辅助技术 屏幕阅读器 NVDA VoiceOver [JAWS_blank_nofollow](https://www.freedomscientific.com/products/software/jaws/?utm_term=jaws screen reader&utm_source=adwords&utm_campaign=All+Products&utm_medium=ppc&hsa_tgt=kwd-394361346638&hsa_cam=200218713&hsa_ad=296201131673&hsa_kw=jaws screen reader&hsa_grp=52663682111&hsa_net=adwords&hsa_mt=e&hsa_src=g&hsa_acc=1684996396&hsa_ver=3&gclid=Cj0KCQjwnv71BRCOARIsAIkxW9HXKQ6kKNQD0q8a_1TXSJXnIuUyb65KJeTWmtS6BH96-5he9dsNq6oaAh6UEALw_wcB) ChromeVox 缩放工具 MAGic ZoomText Magnifier #测试 自动化工具 Lighthouse WAVE 颜色工具 WebAim Color Contrast WebAim Link Color Contrast 其他辅助性工具 HeadingMap Color Oracle Focus Indicator NerdeFocus #用户 世界卫生组织估计,世界 15%的人口患有某种形式的残疾,其中 2 – 4%的人严重残疾。估计全世界有 10 亿人,使残疾人成为世界上最大的少数群体。 残疾的种类繁多,大致可分为四类: 视觉的 – 这些用户可以受益于使用屏幕阅读器、屏幕放大、控制屏幕对比度或盲文显示。 听觉的 – 这些用户可以从字幕、文字记录或手语视频中获益。 运动的 – 这些用户可以从一系列运动障碍辅助技术中受益:语音识别软件、眼球跟踪、单开关接入、头棒、单开关接入、sip 和 puff 开关、超大轨迹球鼠标、自适应键盘或其他辅助技术。 认知 – 这些用户可以从补充媒体、内容的结构化组织、清晰和简单的写作中获益。 请从 WebAim 查看以下链接,以便用户了解: web 可达性透视:探索对每个人的影响和益处 网络用户的故事## #文档
Web 可访问性 (也称为 a11y) 是指创建可供任何人使用的网站的实践方式——无论是身患某种障碍、通过慢速的网络连接访问、使用老旧或损坏的硬件,还是仅仅是处于不利环境中的人。例如,在视频中添加字幕可以帮助失聪、重听或在嘈杂的环境中听不到手机的用户。同样,请确保文字对比度不要太低,这对低视力用户和那些试图在强光下使用手机的用户都有帮助。 你是否已经准备开始却又无从下手? 可以先看看由万维网联盟 (W3C) 提供的规划和管理 web 可访问性。 #跳过链接 你应该在每个页面的顶部添加一个直接指向主内容区域的链接,这样用户就可以跳过在多个网页上重复的内容。 通常这个链接会放在 App.vue 的顶部,这样它就会是所有页面上的第一个可聚焦元素: <ul class="skip-links"> <li> <a href="#main" ref="skipLink">跳到主内容</a> </li> </ul> 若想在非聚焦状态下隐藏该链接,可以添加以下样式: .skipLink { white-space: nowrap; margin: 1em auto; top: 0; position: fixed; left: 50%; margin-left: -72px; opacity: 0; } .skipLink:focus { opacity: 1; background-color: white; padding: .5em; border: 1px solid black; } 一旦用户改变路由,请将焦点放回到这个跳过链接。通过用如下方式聚焦 ref 即可实现: <script> export default { watch: { $route() { this.$refs.skipLink.focus(); } } }; </script> 点击此处实现 阅读关于跳跃到主体内容的链接的文档 #组织内容 可访问性最重要的部分之一是确保设计本身是可访问的。设计不仅要考虑颜色对比度、字体选择、文本大小和语言,还要考虑应用程序中内容的结构。 #标题 用户可以通过标题在应用程序中进行导航。为应用程序的每个部分设置描述性标题可以让用户更容易地预测每个部分的内容。说到标题,有几个推荐的可访问性实践: 按级别顺序嵌套标题:<h1> – <h6> 不要在一个章节内跳跃标题的级别 使用实际的标题标记,而不是通过对文本设置样式以提供视觉上的标题 关于标题可进一步阅读 <main role="main" aria-labelledby="main-title"> <h1 id="main-title">Main title</h1> <section aria-labelledby="section-title"> <h2 id="section-title"> Section Title </h2> <h3>Section Subtitle</h3> <!-- 内容 --> </section> <section aria-labelledby="section-title"> <h2 id="section-title"> Section Title </h2> <h3>Section Subtitle</h3> <!-- 内容 --> <h3>Section Subtitle</h3> <!-- 内容 -->...
插件是自包含的代码,通常向 Vue 添加全局级功能。它可以是公开 install() 方法的 object,也可以是 function 插件的功能范围没有严格的限制——一般有下面几种: 添加全局方法或者 property。如:vue-custom-element 添加全局资源:指令/过滤器/过渡等。如:vue-touch 通过全局混入来添加一些组件选项。如:vue-router 添加全局实例方法,通过把它们添加到 config.globalProperties 上实现。 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如:vue-router #编写插件 为了更好地理解如何创建自己的 Vue.js 版插件,我们将创建一个非常简化的插件版本,它显示 i18n 准备好的字符串。 每当这个插件被添加到应用程序中时,如果它是一个对象,就会调用 install 方法。如果它是一个 function,则函数本身将被调用。在这两种情况下——它都会收到两个参数:由 Vue 的 createApp 生成的 app 对象和用户传入的选项。 让我们从设置插件对象开始。建议在单独的文件中创建它并将其导出,如下所示,以保持包含的逻辑和分离的逻辑。 // plugins/i18n.js export default { install: (app, options) => { // Plugin code goes here } } 我们想要一个函数来翻译整个应用程序可用的键,因此我们将使用 app.config.globalProperties 暴露它。 该函数将接收一个 key 字符串,我们将使用它在用户提供的选项中查找转换后的字符串。 // plugins/i18n.js export default { install: (app, options) => { app.config.globalProperties.$translate = key => { return key.split('.').reduce((o, i) => { if (o) return o[i] }, i18n) } } } 我们假设用户使用插件时,将在 options 参数中传递一个包含翻译后的键的对象。我们的 $translate 函数将使用诸如 greetings.hello 之类的字符串,查看用户提供的配置内部并返回转换后的值-在这种情况下为 Bonjour!。 例如: greetings: { hello: 'Bonjour!' } 插件还允许我们使用 inject 为插件的用户提供功能或 attribute。例如,我们可以允许应用程序访问 options 参数以能够使用翻译对象。 // plugins/i18n.js export default { install: (app, options) => { app.config.globalProperties.$translate = key =>...
Vue 鼓励我们通过将 UI 和相关行为封装到组件中来构建 UI。我们可以将它们嵌套在另一个内部,以构建一个组成应用程序 UI 的树。 然而,有时组件模板的一部分逻辑上属于该组件,而从技术角度来看,最好将模板的这一部分移动到 DOM 中 Vue app 之外的其他位置。 一个常见的场景是创建一个包含全屏模式的组件。在大多数情况下,你希望模态框的逻辑存在于组件中,但是模态框的快速定位就很难通过 CSS 来解决,或者需要更改组件组合。 考虑下面的 HTML 结构。 <body> <div style="position: relative;"> <h3>Tooltips with Vue 3 Teleport</h3> <div> <modal-button></modal-button> </div> </div> </body> 让我们来看看 modal-button 组件: 该组件将有一个 button 元素来触发模态的打开,以及一个具有类 .modal 的 div 元素,它将包含模态的内容和一个用于自关闭的按钮。 const app = Vue.createApp({}); app.component('modal-button', { template: ` <button @click="modalOpen = true"> Open full screen modal! </button> <div v-if="modalOpen" class="modal"> <div> I'm a modal! <button @click="modalOpen = false"> Close </button> </div> </div> `, data() { return { modalOpen: false } } }) 当在初始的 HTML 结构中使用这个组件时,我们可以看到一个问题——模态是在深度嵌套的 div 中渲染的,而模态的 position:absolute 以父级相对定位的 div 作为引用。 Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。 让我们修改 modal-button 以使用 <teleport>,并告诉 Vue “Teleport 这个 HTML 到该‘body’标签”。 app.component('modal-button', { template: ` <button @click="modalOpen = true"> Open full screen modal!...
提示 已经了解 Vue 2,只想了解 Vue 3 的新功能可以参阅迁移指南! #Vue.js 是什么 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。 如果你想在深入学习 Vue 之前对它有更多了解,我们制作了一个视频,带你了解其核心概念和一个示例工程。 如果你已经是有经验的前端开发者,想知道 Vue 与其它库/框架有哪些区别,请查看对比其它框架。 #起步 安装 TIP 官方指南假设你已了解关于 HTML、CSS 和 JavaScript 的中级知识。如果你刚开始学习前端开发,将框架作为你的第一步可能不是最好的主意——掌握好基础知识再来吧!之前有其它框架的使用经验会有帮助,但这不是必需的 尝试 Vue.js 最简单的方法是使用 Hello World 例子,你可以在浏览器新标签页中打开它,跟着例子学习一些基础用法。 安装教程给出了更多安装 Vue 的方式。请注意我们不推荐新手直接使用 vue-cli,尤其是在你还不熟悉基于 Node.js 的构建工具时。 #声明式渲染 Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统: <div id="counter"> Counter: {{ counter }} </div> const Counter = { data() { return { counter: 0 } } } Vue.createApp(Counter).mount('#counter') 我们已经成功创建了第一个 Vue 应用!看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被建立了关联,所有东西都是响应式的。我们要怎么确认呢?请看下面的示例,其中 counter property 每秒递增,你将看到渲染的 DOM 是如何变化的: const CounterApp = { data() { return { counter: 0 } }, mounted() { setInterval(() => { this.counter++ }, 1000) } } Counter: 36 Stop timer 除了文本插值,我们还可以像这样绑定元素的 attribute: <div id="bind-attribute"> <span v-bind:title="message"> 鼠标悬停几秒钟查看此处动态绑定的提示信息! </span> </div> const AttributeBinding = {...
#简介 除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。举个聚焦输入框的例子,如下: 点击此处实现 当页面加载时,该元素将获得焦点 (注意:autofocus 在移动版 Safari 上不工作)。事实上,只要你在打开这个页面后还没点击过任何内容,这个输入框就应当还是处于聚焦状态。此外,你可以单击 Rerun 按钮,输入将被聚焦。 现在让我们用指令来实现这个功能: const app = Vue.createApp({}) // 注册一个全局自定义指令 `v-focus` app.directive('focus', { // 当被绑定的元素插入到 DOM 中时…… mounted(el) { // Focus the element el.focus() } }) 如果想注册局部指令,组件中也接受一个 directives 的选项: directives: { focus: { // 指令的定义 mounted(el) { el.focus() } } } 然后你可以在模板中任何元素上使用新的 v-focus property,如下: <input v-focus /> #钩子函数 一个指令定义对象可以提供如下几个钩子函数 (均为可选): beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用。在这里你可以做一次性的初始化设置。 mounted:在挂载绑定元素的父组件时调用。 beforeUpdate:在更新包含组件的 VNode 之前调用。 提示 我们会在稍后讨论渲染函数时介绍更多 VNodes 的细节。 updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用。 beforeUnmount:在卸载绑定元素的父组件之前调用 unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次。 接下来我们来看一下在自定义指令 API 钩子函数的参数 (即 el、binding、vnode 和 prevNnode) #动态指令参数 指令的参数可以是动态的。例如,在 v-mydirective:[argument]="value" 中,argument 参数可以根据组件实例数据进行更新!这使得自定义指令可以在应用中被灵活使用。 例如你想要创建一个自定义指令,用来通过固定布局将元素固定在页面上。我们可以像这样创建一个通过指令值来更新竖直位置像素值的自定义指令: <div id="dynamic-arguments-example" class="demo"> <p>Scroll down the page</p> <p v-pin="200">Stick me 200px from the top of the page</p> </div> const app = Vue.createApp({}) app.directive('pin', { mounted(el, binding)...
该页面假设你已经阅读过了组件基础。如果你还对组件不太了解,推荐你先阅读它。 #插槽内容 Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口。 它允许你像这样合成组件: <todo-button> Add todo </todo-button> 然后在 <todo-button> 的模板中,你可能有: <!-- todo-button 组件模板 --> <button class="btn-primary"> <slot></slot> </button> 当组件渲染的时候,将会被替换为“Add Todo”。 <!-- 渲染 HTML --> <button class="btn-primary"> Add todo </button> 不过,字符串只是开始!插槽还可以包含任何模板代码,包括 HTML: <todo-button> <!-- 添加一个Font Awesome 图标 --> <i class="fas fa-plus"></i> Add todo </todo-button> 或其他组件 <todo-button> <!-- 添加一个图标的组件 --> <font-awesome-icon name="plus"></font-awesome-icon> Add todo </todo-button> 如果 <todo-button> 的 template 中没有包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃 <!-- todo-button 组件模板 --> <button class="btn-primary"> Create a new item </button> <todo-button> <!-- 以下文本不会渲染 --> Add todo </todo-button> #渲染作用域 当你想在一个插槽中使用数据时,例如: <todo-button> Delete a {{ item.name }} </todo-button> 该插槽可以访问与模板其余部分相同的实例 property (即相同的“作用域”)。 插槽不能访问 <todo-button> 的作用域。例如,尝试访问 action 将不起作用: <todo-button action="delete"> Clicking here will {{ action }} an item <!-- `action` 未被定义,因为它的内容是传递*到* <todo-button>,而不是*在* <todo-button>里定义的。...
这里是官方的 Vue 特有代码的风格指南。如果在工程中使用 Vue,为了回避错误、小纠结和反模式,该指南是份不错的参考。不过我们也不确信风格指南的所有内容对于所有的团队或工程都是理想的。所以根据过去的经验、周边的技术栈、个人价值观做出有意义的偏差是可取的。 对于其绝大部分,我们也总体上避免就 JavaScript 或 HTML 的本身提出建议。我们不介意你是否使用分号或结尾的逗号。我们不介意你在 HTML attribute 中使用单引号还是双引号。不过当我们发现在 Vue 的情景下有帮助的特定模式时,也会存在例外。 最终,我们把所有的规则归为了四个大类: [#]()规则类别 [#]()优先级 A:必要的 这些规则会帮你规避错误,所以学习并接受它们带来的全部代价吧。这里面可能存在例外,但应该非常少,且只有你同时精通 JavaScript 和 Vue 才可以这样做。 #优先级 B:强烈推荐 这些规则能够在绝大多数工程中改善可读性和开发体验。即使你违反了,代码还是能照常运行,但例外应该尽可能少且有合理的理由。 #优先级 C:推荐 当存在多个同样好的选项,选任意一个都可以确保一致性。在这些规则里,我们描述了每个选项并建议一个默认的选择。也就是说只要保持一致且理由充分,你可以随意在你的代码库中做出不同的选择。请务必给出一个好的理由!通过接受社区的标准,你将会: 训练你的大脑,以便更容易的处理你在社区遇到的代码; 不做修改就可以直接复制粘贴社区的代码示例; 能够经常招聘到和你编码习惯相同的新人,至少跟 Vue 相关的东西是这样的。 #优先级 D:谨慎使用 有些 Vue 特性的存在是为了照顾极端情况或帮助老代码的平稳迁移。当被过度使用时,这些特性会让你的代码难于维护甚至变成 bug 的来源。这些规则是为了给有潜在风险的特性敲个警钟,并说明它们什么时候不应该使用以及为什么。 #优先级 A 的规则:必要的 (规避错误) #组件名为多个单词必要 组件名应该始终是多个单词的,根组件 App 以及 <transition>、<component> 之类的 Vue 内置组件除外。 这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。 反例 app.component('todo', { // ... }) export default { name: 'Todo', // ... } 好例子 app.component('todo-item', { // ... }) export default { name: 'TodoItem', // ... } #Prop 定义必要 Prop 定义应尽量详细 在你提交的代码中,prop 的定义应该尽量详细,至少需要指定其类型。 详解 细致的 prop 定义有两个好处: 它们写明了组件的 API,所以很容易看懂组件的用法; 在开发环境下,如果向一个组件提供格式不正确的 prop,Vue 将会告警,以帮助你捕获潜在的错误来源。 反例 // 这样做只有开发原型系统时可以接受 props: ['status'] 好例子 props: { status: String } // 更好的例子 props: { status: { type: String,...
本节例子中代码使用的单文件组件语法 #setup 一个组件选项,在创建组件之前执行,一旦 props 被解析,并作为组合式 API 的入口点 入参: {Data} props {SetupContext} context 类型声明: interface Data { [key: string]: unknown } interface SetupContext { attrs: Data slots: Slots emit: (event: string, ...args: unknown[]) => void } function setup(props: Data, context: SetupContext): Data TIP 若要获取传递给 setup() 的参数的类型推断,请使用 defineComponent 是需要的。 示例: 使用模板: <!-- MyBook.vue --> <template> <div>{{ readersNumber }} {{ book.title }}</div> </template> <script> import { ref, reactive } from 'vue' export default { setup() { const readersNumber = ref(0) const book = reactive({ title: 'Vue 3 Guide' }) // expose to template return { readersNumber, book } } } </script> 使用渲染函数: // MyBook.vue import { h, ref, reactive } from 'vue' export default { setup() { const readersNumber = ref(0) const book...