vue学习备注

273 阅读2分钟

基础组件的自动化全局注册

如果你使用了webpack(或在内部使用了webpack的Vue CLI 3+),那么就可以使用require.context只全局注册这些非常通用的基础组件。这里有一份可以让你在应用入口(比如src/main.js)中全局导入基础组件的视力代码

    import Vue from 'vue'
    import upperFirst from 'lodash/upperFirst'
    import camelCase from 'lodash/camelCase'
    
    const requireComponent = require.context(
        // 其组件目录的相对路径
        './components',
        // 是否查询其子目录
        false,
        // 匹配基础组件文件名的正则表达式
        /Base[A-Z]\w+\.(vue|js)$/
    )
    
    requireComponent.keys().forEach(fileName => {
        // 获取组件配置
        const componentConfig = requireComponent(fileName)
    
        // 获取组件的 PascalCase 命名
        const componentName = upperFirst(
            camelCase(
              // 获取和目录深度无关的文件名
              fileName
                .split('/')
                .pop()
                .replace(/\.\w+$/, '')
            )
        )
    
        // 全局注册组件
        Vue.component(
            componentName,
            // 如果这个组件选项是通过 `export default` 导出的,
            // 那么就会优先使用 `.default`,
            // 否则回退到使用模块的根。
            componentConfig.default || componentConfig
        )
    })

记住全局注册的行为必须在根Vue实例(通过new Vue)创建之前发生。

自定义事件

事件名

不同于组件和prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。

    this.$emit('myEvent')

则监听这个名字的kebab-case版本是不会有任何效果的:

    <my-component v-on:my-event="doSomething"/>

v-on事件监听器在DOM模板中会被自动转换为全小写(因为HTML是大小写不敏感的),所以v-on:myEvent将变成v-on:myevent,最终导致myEvent不会被监听到。因此,推荐你始终使用kebab-case事件名。

作用域插槽

一般情况下,插槽的作用域为父组件的作用域。为了让插槽内容可以访问到子组件的数据,我们可以将user(子组件的数据)作为slot元素的一个attribute绑定上去:

    <!--子组件-->
    <span>
        <slot :user="user">
            {{user.lastName}
        </slot>
    </span>
    <!--父组件-->
    <current-user>
        <template v-slot:default="slotProps">
            {{ slotProps.user.firstName }
        </template>
    </current-user>

独占默认插槽的缩写语法

当被提供的内容只有默认插槽时,组件的标签才可以被当做插槽的模板来使用。这种情况我们就可以把v-slot直接用在组件上:

    <current-user v-slot:default="slotProps">
        {{ slotProps.user.firstName }}
    </current-user>

注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:

    <!--无效,会导致警告-->
    <current-user v-slot="slotProps">
        {{ slotProps.user.firstName }}
        <template v-slot:other="otherSlotProps">
            slotProps is NOT available here
        </template>
    </current-user>

只要出现多个插槽,请始终为所有的插槽使用完整的基于template的语法:

    <!--正确写法-->
    <current-user>
        <template v-slot:default="slotProps">
            {{ slotProps.user.firstName }}
        </template>
        <template v-slot:other="otherSlotProps">
            ...
        </template>
    </current-user>

处理边界情况

访问元素&组件

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

#访问根实例($root)

    <!--vue实例-->
    new Vue({
        data: { foo: 1 },
        methods: {
            baz() {...}
        },
        computed: {
            bar() {...}
        }
    })

所有的子组件都可以将这个实例作为一个全局store来访问或者使用

    //获取根组件的数据
    this.$root.foo
    
    //调用跟组件的方法
    this.$root.baz()
    
    //访问根组件的计算属性
    this.$root.bar

对于demo或非常小型的有少量组件的应用来说这是很方便的。不过这个模型扩展到中大型应用来说就不然了。因此在却大多数情况下,我们强烈推荐使用Vuex来管理状态。

#访问父级组件实例($parent)

#访问子组件实例或子元素(ref)

    <input ref="input"/>
    this.$refs.input.force()

#依赖注入(provide) provide选项允许我们指定我们想要提供给后台组件的数据/方法。

    <!--父组件-->
    provide() {
        return {
            getMap: this.getMap
        }
    }
    <!--子组件-->
    inject: ['getMap']

然而,依赖注入还是有负面影响的。他将你应用程序中的组件与它们当前的组织方式耦合起来,使重构变得更加困难。

控制更新

强制更新($forceUpdate)

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

不要过度使用这种模式。当你需要渲染大量的静态内容时,极少数的情况下它会给你带来便利,除非你非常留意渲染变慢了,不然它完全没有必要--再加上它在后期会带来很多困惑。例如,设想另一个开发者并不熟悉 v-once 或漏看了它在模板中,他们可能会花很多个小时去找出模板为什么无法正确更新。

生命周期图示

选项/生命周期钩子

所有的生命周期钩子自动绑定this上下文到实例中(因为箭头函数绑定了父上下文,所以不能用箭头函数来定义一个生命周期方法)