• 前端框架Vue学习的心得记录(深入了解组件)


    目标:深入了解Vue框架(2.x版本)的组件

    方法:通过看Vue的官方手册(Vue官方网站

    内容:本博客记录一些学习Vue中的心得,便于日后启发。(深入了解组件)

    注:遇到一些不懂的函数等,可以看官网的API参考

    正文:

    一、组件注册

    1、组件名

    在注册一个组件的时候(Vue.component),我们始终需要给它一个名字(组件名)。该组件名就是 Vue.component 的第一个参数。当直接在 DOM 中使用一个组件 (而不是在字符串模板或单文件组件) 的时候,我们强烈推荐遵循 W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符)。这会帮助你避免和当前以及未来的 HTML 元素相冲突。定义组件名的方式有两种:使用 kebab-case(当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case)和使用 PascalCase(当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。)

    2、全局注册

    到目前为止,我们只用过 Vue.component 来创建组件,这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用。

    3、局部注册

    全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。在这些情况下,你可以通过一个普通的 JavaScript 对象来定义组件。然后在new Vue定义下的 components 选项中定义你想要使用的组件,对于 components 对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。注意局部注册的组件在其子组件中不可用,除非把一个组件定义到另一个组件内。

    4、模块系统

    针对使用import/require 来使用一个模块系统的情况,Vue官网提供了一些特殊的使用说明和注意事项。在模板系统中局部注册:在这些情况下,我们推荐创建一个 components 目录,并将每个组件放置在其各自的文件中。然后你需要在局部注册之前导入每个你想使用的组件。基础组件的自动化全局注册:可能你的许多组件只是包裹了一个输入框或按钮之类的元素,是相对通用的。我们有时候会把它们称为基础组件,它们会在各个组件中被频繁的用到。所以会导致很多组件里都会有一个包含基础组件的长列表,而只是用于模板中的一小部分。幸好如果你使用了 webpack (或在内部使用了 webpack 的 Vue CLI 3+),那么就可以使用 require.context 只全局注册这些非常通用的基础组件。(这里有一份可以让你在应用入口文件 (比如 src/main.js) 中全局导入基础组件的示例代码)记住全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生。

    二、Prop

    1、Prop的大小写

    HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法)(JS命名习惯) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) (HTML命名习惯)命名。如果你使用字符串模板,那么这个限制就不存在了。

    2、Prop的类型

    除了以字符串数组形式列出的 prop,如果希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop,这些属性的名称和值分别是 prop 各自的名称和类型。这不仅为你的组件提供了文档,还会在它们遇到错误的类型时从浏览器的 JavaScript 控制台提示用户。

    3、传递静态或者动态Prop

    通过在组件定义中在Prop使用字符串数组声明属性,传递静态Prop给组件。prop 也可以通过 v-bind 动态赋值(如变量的值,复杂表达式的值)。之前我们传入的值都是字符串类型的,但实际上任何类型的值都可以传给一个 prop,如传入一个数字,一个布尔值,一个数组,一个对象和一个对象的所有属性。

    4、单向数据流

    所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。

    5、Prop验证

    我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。

    6、非Prop的特性

    一个非 prop 特性是指传向一个组件,但是该组件并没有相应 prop 定义的特性。因为显式定义的 prop 适用于向一个子组件传入信息,然而组件库的作者并不总能预见组件会被用于怎样的场景。这也是为什么组件可以接受任意的特性,而这些特性会被添加到这个组件的根元素上。替换/合并已有的特性,对于绝大多数特性来说,从外部提供给组件的值会替换掉组件内部设置好的值,庆幸的是,class 和 style 特性会稍微智能一些,即两边的值会被合并起来,从而得到最终的值。禁用特性继承,如果你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false,这尤其适合配合实例的 $attrs 属性使用,该属性包含了传递给一个组件的特性名和特性值,有了 inheritAttrs: false 和 $attrs,你就可以手动决定这些特性会被赋予哪个元素。注意 inheritAttrs: false 选项不会影响 style 和 class 的绑定。

    三、自定义事件

    1、事件名

     不同于组件和 prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。不同于组件和 prop,事件名不会被用作一个 JavaScript 变量名或属性名,所以就没有理由使用 camelCase 或 PascalCase 了。并且 v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。因此,我们推荐你始终使用 kebab-case 的事件名。

    2、自定义组件的v-model

    一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value 特性用于不同的目的。model 选项可以用来避免这样的冲突。

    3、将原生事件绑定到组件

    你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。这时,你可以使用 v-on 的 .native 修饰符。在有的时候这是很有用的,不过在你尝试监听一个类似 <input> 的非常特定的元素时,这并不是个好主意,例如它可能是被别的元素包裹,导致父级的 .native 监听器将静默失败。它不会产生任何报错,但是 onFocus 处理函数不会如你预期地被调用。为了解决这个问题,Vue 提供了一个 $listeners 属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。

    4、.sync修饰符

    在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之。然后父组件可以监听那个事件并根据需要更新一个本地的数据属性。为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符。注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用。当我们用一个对象同时设置多个 prop 的时候,也可以将这个 .sync 修饰符和 v-bind 配合使用。

    四、插槽

    在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍在文档中的特性。

    1、插槽内容

    Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口。当组件渲染的时候,插槽内可以包含任何模板代码,包括 HTML,甚至其它的组件。如果组件没有包含一个<slot>元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

    2、编译作用域

    父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

    3、后备内容

    有时为一个插槽设置具体的后备 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染。

    4、具名插槽(自 2.6.0 起有所更新)

    有时我们需要多个插槽。对于这样的情况,<slot> 元素有一个特殊的特性:name。这个特性可以用来定义额外的插槽。一个不带 name 的 <slot> 出口会带有隐含的名字“default”。在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。注意 v-slot 通常只能添加在 <template> 上。

    5、作用域插槽(自 2.6.0 起有所更新)

    有时让插槽内容能够访问子组件中才有的数据是很有用的。绑定在 <slot> 元素上的特性被称为插槽 prop。不带参数的 v-slot 被假定对应默认插槽。注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确,只要出现多个插槽,请始终为所有的插槽使用完整的基于 <template> 的语法。作用域插槽的内部工作原理是将你的插槽内容包括在一个传入单个参数的函数里。这意味着 v-slot 的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式。所以在支持的环境下 (单文件组件或现代浏览器),你也可以使用 ES2015 解构来传入具体的插槽 prop。

    6、动态插槽名

    动态指令参数也可以用在 v-slot 上,来定义动态的插槽名。

    7、具名插槽的缩写

    跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。然而,和其它指令一样,该缩写只在其有参数的时候才可用。如果你希望使用缩写的话,你必须始终以明确插槽名取而代之。

    8、说明

    插槽 prop 允许我们将插槽转换为可复用的模板,这些模板可以基于输入的 prop 渲染出不同的内容。这在设计封装数据逻辑同时允许父级组件自定义部分布局的可复用组件时是最有用的。

    9、废弃了的语法

    v-slot 指令自 Vue 2.6.0 起被引入,提供更好的支持 slot 和 slot-scope 特性的 API 替代方案。在接下来所有的 2.x 版本中 slot 和 slot-scope 特性仍会被支持,但已经被官方废弃且不会出现在 Vue 3 中。

    五、动态组件&异步组件

    1、在动态组件上使用keep-alive

    我们之前曾经在一个多标签的界面中使用 is 特性来切换不同的组件。当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。如果更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个 <keep-alive> 元素将其动态组件包裹起来。注意这个 <keep-alive> 要求被切换到的组件都有自己的名字,不论是通过组件的 name 选项还是局部/全局注册。

    2、异步组件

    在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。一个推荐的做法是将异步组件和 webpack 的 code-splitting 功能一起配合使用。

    六、处理边界情况

    这里记录的都是和处理边界情况有关的功能,即一些需要对 Vue 的规则做一些小调整的特殊情况。不过注意这些功能都是有劣势或危险的场景的。我们会在每个案例中注明,所以当你使用每个功能的时候请稍加留意。

    1、访问元素&组件

    在绝大多数情况下,我们最好不要触达另一个组件实例内部或手动操作 DOM 元素。不过也确实在一些情况下做这些事情是合适的。

    1.1 访问根节点

    在每个 new Vue 实例的子组件中,其根实例可以通过 $root 属性进行访问。所有的子组件都可以将这个实例作为一个全局 store 来访问或使用。对于 demo 或非常小型的有少量组件的应用来说这是很方便的。不过这个模式扩展到中大型应用来说就不然了。因此在绝大多数情况下,我们强烈推荐使用 Vuex 来管理应用的状态。(tips:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。)

    1.2 访问父级组件实例

    和 $root 类似,$parent 属性可以用来从一个子组件访问父组件的实例。它提供了一种机会,可以在后期随时触达父级组件,以替代将数据以 prop 的方式传入子组件的方式。注意,在绝大多数情况下,触达父级组件会使得你的应用更难调试和理解,尤其是当你变更了父级组件的数据的时候。

    1.3 访问子组件实例或子元素

    尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件。为了达到这个目的,你可以通过 ref 特性为这个子组件赋予一个 ID 引用。注意,$refs 只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs。

    1.4 依赖注入

    使用 $parent 属性无法很好的扩展到更深层级的嵌套组件上。这也是依赖注入的用武之地,它用到了两个新的实例选项:provide 和 inject。provide 选项允许我们指定我们想要提供给后代组件的数据/方法。然后在任何后代组件里,我们都可以使用 inject 选项来接收指定的我们想要添加在这个实例上的属性。然而,依赖注入还是有负面影响的。它将你应用程序中的组件与它们当前的组织方式耦合起来,使重构变得更加困难。

    2、程序化的事件侦听器

    现在,你已经知道了 $emit 的用法,它可以被 v-on 侦听,但是 Vue 实例同时在其事件接口中提供了其它的方法。我们可以: 通过 $on(eventName, eventHandler) 侦听一个事件, 通过 $once(eventName, eventHandler) 一次性侦听一个事件, 通过 $off(eventName, eventHandler) 停止侦听一个事件。

    3、循环引用

    组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name 选项来做这件事。稍有不慎,递归组件就可能导致无限循环,所以请确保递归调用是条件性的 (例如使用一个最终会得到 false 的 v-if)。组件之间的循环引用:我们先把两个组件称为 A 和 B。模块系统发现它需要 A,但是首先 A 依赖 B,但是 B 又依赖 A,但是 A 又依赖 B,如此往复。这变成了一个循环,不知道如何不经过其中一个组件而完全解析出另一个组件。为了解决这个问题,我们需要给模块系统一个点,在那里“A 反正是需要 B 的,但是我们不需要先解析 B。”

    4、模板定义的替代品

    当 inline-template 这个特殊的特性出现在一个子组件上时,这个组件将会使用其里面的内容作为模板,而不是将其作为被分发的内容。这使得模板的撰写工作更加灵活。另一个定义模板的方式是在一个 <script> 元素中,并为其带上 text/x-template 的类型,然后通过一个 id 将模板引用过去。

    5、控制更新

    感谢 Vue 的响应式系统,它始终知道何时进行更新 (如果你用对了的话)。不过还是有一些边界情况,你想要强制更新,尽管表面上看响应式的数据没有发生改变。也有一些情况是你想阻止不必要的更新。

    1,1 强制更新

    如果你发现你自己需要在 Vue 中做一次强制更新,99.9% 的情况,是你在某个地方做错了事。你可能还没有留意到数组或对象的变更检测注意事项,或者你可能依赖了一个未被 Vue 的响应式系统追踪的状态。然而,如果你已经做到了上述的事项仍然发现在极少数的情况下需要手动强制更新,那么你可以通过 $forceUpdate 来做这件事。

    1.2 通过v-once创建低开销的静态组件

    渲染普通的 HTML 元素在 Vue 中是非常快速的,但有的时候你可能有一个组件,这个组件包含了大量静态内容。在这种情况下,你可以在根元素上添加 v-once 特性以确保这些内容只计算一次然后缓存起来。注意,试着不要过度使用这个模式。当你需要渲染大量静态内容时,极少数的情况下它会给你带来便利,除非你非常留意渲染变慢了,不然它完全是没有必要的——再加上它在后期会带来很多困惑。例如,设想另一个开发者并不熟悉 v-once 或漏看了它在模板中,他们可能会花很多个小时去找出模板为什么无法正确更新。

  • 相关阅读:
    2018-2019-1 20165212 《信息安全系统设计基础》第九周学习总结
    12321
    实现mybash
    2018-2019-1 20165212 《信息安全系统设计基础》第八周学习总结(pwd)
    2018-2019-1 20165212 实验三-并发程序设计
    2018-2019-1 20165212 20165222 20165313 实验二 固件程序设计
    2018-2019-1 20165212 《信息安全系统设计基础》第1次实验——实验环境的熟悉
    开根号(二分法、牛顿法)
    logistic回归的损失函数是什么形式?为什么?为什么不选平方损失函数?
    西瓜书课后习题——第六章
  • 原文地址:https://www.cnblogs.com/xinkuiwu/p/11996308.html
Copyright © 2020-2023  润新知