跳转到内容

Vue

刀刀

3/20/2025

0 字

0 分钟

动态组件

动态组件基本概念

作用

可以让多个组件使用同一个挂载点,并动态切换。 component 本质上是一个占位符,通过 :is 属性来指定渲染谁。

语法

vue
<component :is="vue变量"></component>

例子

创建两个子组件。

子组件1:

html
<template>
  <div>
      用户名:<input type="text">
      密码:<input type="text">
  </div>
</template>
复制代码

子组件2:

html
<template>
  <div>
      用户名:<input type="text">
      密码:<input type="text">
  </div>
</template>
复制代码

App.vue 中插入动态组件:

html
<template>
  <div>
    <h1>动态组件的使用</h1>
    <div>
      <button @click="change('username')">账号密码</button>
      <button @click="change('userinfo')">用户信息</button>
    </div>
    <component :is="curComp"></component>
  </div>
</template>

<script>
import userinfo from "./components/userinfo.vue";
import username from "./components/username.vue";
export default {
  data () {
    return {
      curComp:'username'
    }
  },
  methods: {
    change(type){
      this.curComp=type
    }
  },
  components: {
    username,userinfo
  }
}
</script>
复制代码

data 中设置了子组件的变量名,点击按钮改变子组件从而实现动态组件的效果。

动态组件.png

组件缓存

动态组件频繁切换会导致频繁销毁和创建组件,不利于提高性能。因此在组件创建出来之后将其缓存起来不被销毁,需要的时候就能使用。

语法

keep-alive 将其包裹即可。

vue
<keep-alive>
    <component :is="vue变量名"></component>
</keep-alive>

总结:

keep-alive可以把内部的组件进行缓存而非销毁,内部包裹的标签不会被销毁和重新创建,因此能够提高组件的性能。

生命周期补充

组件被缓存起来后钩子函数不会再触发,想要判断某个组件当前是显示还是隐藏状态,需要用到 activeddeactivated 这两个钩子。

  • actived :当前组件显示状态。当组件被激活的时候会自动触发这个生命周期函数。
  • deactived :当前组件隐藏状态。当组件被缓存的时候会自动触发这个生命周期函数。

被缓存的组件不再创建和销毁,也就意味着钩子函数 created 和销毁函数只会触发一次,为了能得知此时组件是否是显示状态,可以通过新的钩子判断其是否被激活。

总结:

当组件第一次被创建的时候,既会触发 created 生命周期,也会触发 actived 生命周期。而组件被激活的时候,只会触发 actived 生命周期,而不触发 created 生命周期。

include 属性

用来指定:只有名称匹配的组件会被缓存,多个组件名之间使用英文逗号分隔。

相反的,指定 exinclude 可用来指定被匹配的组件不会被缓存。

注意:

二者只能选其一来使用,不能一起使用。

组件注册与组件声明的区别

  • 组件注册 组件注册指在a组件中引入b组件时设置的名称,主要应用场景:把注册好的组件渲染到页面上。
  • 组件声明 组件声明指创建好了组件后为其设置一个 name 属性,主要应用场景:结合 keep-alive 标签实现组件缓存功能,以及在调试工具中看到组建的 name 名称。

解析 DOM 模板时的注意事项

有些 HTML 元素,诸如 <ul><ol><table><select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li><tr><option>,只能出现在其它某些特定的元素内部。

这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:

html
<table>
  <blog-post-row></blog-post-row>
</table>

这个自定义组件 <blog-post-row> 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is attribute 给了我们一个变通的办法:

html
<table>
  <tr is="blog-post-row"></tr>
</table>

插槽

含义

作用

用于实现组件的内容分发, 通过 slot 标签, 可以接收到写在组件标签内的内容。

vue中不仅组件可以动态改变,标签也可以动态改变,提供组件插槽能力, 允许开发者在封装组件时,把不确定的部分定义为插槽。

语法

子组件中:使用以下代码,作用是占位

html
<slot></slot>

父组件中:插入以下代码,把动态的标签写入其中即可。

html
<子组件名称></子组件名称>

例子

子组件中,生成一个骨架,把会变化的部分用占位符替换。

html
<template>
  <div>
      <slot></slot>
  </div>
</template>

<script>
export default {
}
</script>

<style>

</style>

父组件中,用引入的子组件 Pannel 包裹动态的标签,多个标签还能实现复用。

html
<template>
  <div>
    <div>
      <h1>插槽的使用</h1>
      <pannel>
        <p>哈哈哈哈</p>
        <p>我是文字</p>
      </pannel>
      <pannel>
        <ul>
          <li>刀刀</li>
          <li>刀刀</li>
          <li>刀刀</li>
          <li>刀刀</li>
        </ul>
      </pannel>
    </div>
  </div>
</template>

<script>
import pannel from "./components/pannel.vue";
export default {
  components: {
    pannel
  }
}
</script>

作用域

如果在插槽中想要使用变量或方法,例如:

vue
<navigation-link url="/profile">
  <div @click="click">Logged in as {{ user.name }}</div>
</navigation-link>

该插槽跟模板的其它地方一样可以访问相同的实例 property (也就是相同的“作用域”),而不能访问 <navigation-link> 的作用域。

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

默认内容

如果调用者不传值, 有默认内容就会显示默认内容,默认内容添加在 slot 标签内。

语法

html
<slot>默认内容</slot>

具名插槽

当一个组件内有2处以上需要外部传入标签的插槽,可以为每个插槽添加名字加以区分。

语法

html
<slot name="自定义名字"></slot>

默认情况下,在使用组件的时候,提供的内容都会被填充到名字为 default 的插槽中.

  1. 如果要把内容填充到指定名称的插槽中,需要使用 v-slot 这个指令.
  2. v-slot :后面要跟上插槽的名字.
  3. v-slot :指令不能直接作用在元素身上,必须用在 template 标签上.
  4. template :这个标签是一个虚拟标签,只起到包裹性质的作用,并不会被实际渲染成html元素.

在组件内添加 template 标签,结合 v-slot 或其简写形式 # 进行具名区分。

例子

子组件中定义两个具名插槽。

html
<template>
  <div>
      <slot name="title"></slot>
      <slot name="content"></slot>
  </div>
</template>

<script>
export default {
}
</script>

<style>

</style>

父组件分开使用。

html
<template>
  <div>
  <pannel>
    <template v-slot:title>
        <h1>我一路向北</h1>
    </template>
    <template #content>
        <p>离开有你的季节</p>
    </template>
  </pannel>
  </div>
</template>

<script>
import pannel from "./components/pannel.vue";
export default {
  components: {
    pannel
  }
}
</script>

作用域插槽

子组件里的值,给插槽赋值,在父组件环境下使用。

语法

html
<slot :自定义名称="子组件内的值"></slot>

使用

父组件中用 templatev-slot="自定义变量名" 来使用。变量名会收集slot身上属性和值形成对象。

html
<template v-slot="scope">
  <p>{{ scope.自定义名称.子组件内的值 }}</p>
</template>

推荐名称使用 scope ,但想起啥都无所谓。

例子

子组件内定义一个作用域插槽,把对象传过去。

html
<template>
  <div>
      <slot name="title"></slot>
      <slot :row="obj" name="content"></slot>
  </div>
</template>

<script>
export default {
    data () {
        return {
            obj:{
                one:'我是1',
                two:'我是0'
            }
        }
    }
}
</script>

父组件中接受其值,由于是对象形式的值,想要使用要再点一次。

html
<template>
  <div>
  <pannel>
    <template #title>
        <h1>七里香的滋味</h1>
    </template>
    <!-- 这里scoped变量只有当前template可以使用 -->
    <template #content="chao">
        <p>猫和你我都想了解</p>
        <p>{{chao.row.two}}</p>
    </template>
  </pannel>
  </div>
</template>

<script>
import pannel from "./components/pannel.vue";
export default {
  components: {
    pannel
  }
}
</script>

注意:

作用域插槽只有当前 template 可以使用。

自定义指令

除了核心功能默认内置的指令 (v-modelv-show),Vue 也允许注册自定义指令。

局部自定义

定义一个名为focus的指令,指向一个配置对象。

html
<div v-focus></div>
directives: {
    focus: {
        inserted(el,binding){
           // 这里el表示被引用的标签
        }
    }
}

当指令第一次被绑定到元素上时,会立即触发一次 inserted 函数。其余钩子函数如下所示:

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。

  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

  • unbind:只调用一次,指令与元素解绑时调用。

形参中的el表示当前指令所绑定到的那个dom对象, binding 可以获取指令绑定的值。其余参数如下所示:

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  • oldVnode:上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用。

传值

用第二个参数 binding 进行接受传递过来的参数。

html
<p v-color="colorStr">修改文字颜色</p>
Vue.directive('color', {
  inserted(el, binding) {
    el.style.color = binding.value
  },
})

总结: 全局注册自定义指令, 哪里都能用, 局部注册, 只能在当前 vue 文件里用。

注册

在自定义指令的标签注册后只执行一次 inserted 方法,后续发生改变也不会触发,因此需要新的指令 update 来监听。

js
Vue.directive('color', {
  inserted(el) {
  
  },
  update(el) {
    
  }
})

后续 dom 更新时都会触发 update 函数。

简写形式

如果 updateinserted 方法的代码指令一致,可以直接简写为函数的形式。

js
foucs(el,binging){
    el.style.color = binding.value
}

这样写的方式相当于 updateinserted 方法执行一样的指令。

全局自定义

main.js 文件中使用。

js
Vue.directive("自定义名称", {
  inserted(el) {
    el.focus() // 触发标签的事件方法
  }
})
复制代码

简写形式

js
Vue.directive("自定义名称", fucntion(el,binding) {
  inserted(el) {
    el.focus() // 触发标签的事件方法
  }
})
复制代码

ESlint 指令

VScode插件满足ESlint规范要求。

插件一:ESlint,作者:微软 插件二:prettier,作者:prettier

打开设置 setting.json添加配置代码

json
    // ESlint 插件配置
    "editor.codeActionsOnSave": {
        "source.fixAll": true
    },
    "eslint.alwaysShowStatus": true,
    "prettier.trailingComma": "none",
    "prettier.semi": false,
    // 每行文字超出限制自动换行
    "prettier.singleQuote": true,
    "prettier.arrowParens": "avoid",
    // 设置vue文件中,html代码的格式化插件
    "vetur.format.defaultFormatter.html": "js-beautify-html",
    "vetur.ignoreProjectWarning": true,
    "vetur.format.defaultFormatterOptions": {
        "js-beautify-html": {
            "wrap_attributes": false
        },
        "prettier": {
            "trailingComma": "none",
            "semi": false,
            "singleQuote": true,
            "arrowParens": "avoid",
            "printWidth": 300
        }
    },