Day36:组件进阶和插槽

94 阅读5分钟

动态写选项卡

 vue内置组件,这个组件可以让视图动态地渲染对应的组件内容

vue内置组件不用自己定义,可以直接拿来使用。

vue内置组件component,这个组件可以让视图动态地渲染对应的组件内容

注意:

内置组件component和注册标签components只是长得像其实没有关系。

如果在component中直接使用了引入的标签,可以不用在components中注册;

如果在component中没有使用了引入的标签,则需要在components中注册。

 vue内置组件keep-alive,这个组件可以缓存组件的状态

<keep-alive>
  <component :is="comp"></component>
</keep-alive>

通过keepalive包裹的组件没有被销毁,也没有重新挂载,生命周期被保存了

写一个动态绑定的选项卡

<template>
  <div class="tabControl">
    <span @click="fn1()">    Home    </span>
    <span @click="fn2()">    Post    </span>
    <span @click="fn3()">    Archive    </span>
  </div>
  <keep-alive>
    <component :is="comp"></component>
  </keep-alive>
</template>
<script>
  // 导入
  import Home    from './components/Home.vue'
  import Archive from './components/Archive.vue'
  import Post    from './components/Post.vue' 
  export default {
    name: 'App', 
    data(){
      return {
        comp:Home  /* 初始值为home,切换选项卡就是修改home */
      },
    methods:{
    fn1(){
      this.comp = Home
    },
    fn2(){
      this.comp = Post
    },
    fn3(){
      this.comp = Archive
    },
  },
    }
</script>

新增生命周期

4组8个生命周期(create,mounte,update,destroy)

在生命周期中经常使用的是:mounted(发送http请求,进行Dom操作,连接服务器等),beforeDestroyed(清除副作用,取消连接服务器,清除全局定时器,清除一些订阅消息。)

除此之外,keepalive缓存组件中还新增两个生命周期——激活activated失活deactivated

选项卡切换:初始挂载+激活,切换时失活——挂载——激活,再次切换失活——激活,不再重新挂载

组件通信

父子组件通信

父到子——props 既是基本属性,也可以是方法

子到父——1.自定义事件;2.接受props方法

祖先到后代——provide/inject 依赖/注入

  1. 在祖先中provide注入信息(provide与components同级
  2. 在后代组件中inject:["msg"]注入组件内容,即可在后代组件中调用

Vue获取Dom元素

vue是数据驱动视图的框架,一般情况下,操作的数据,Dom操作由框架来实现,不能用document.querySelector

在Vue中如果希望能获取Dom元素,可以使用ref属性来获取Dom元素,还可以获取组件实例

切换视图后立刻更新

在vue中,数据一变,视图会立即更新吗?不是的。

所有操作结束后,视图统一批量更新,是更合理的操作

视图还未更新时,是无法获取更新后新的值,获取该值得到undefined

调用$nextTick方法通知视图立马更新,这个方法中传入的回调函数的逻辑会在视图更新后执行

this.$nextTick(function(){})

this.$nextTick(function(){
  if(this.isEdit){
    this.$refs.ref1.focus();
  }
});
<template>
  <div class="app">
    <div class="left">
      <div
        v-if="!isEdit"
        class="t1"
      >
        {{ msg }}
      </div>
      <div
        v-else
        class="t2"
      >
        <input
          ref="ref1"
          v-model="msg"
          type="text"
        >
      </div>
    </div>
    <div class="right">
      <button @click="edit">
        {{ isEdit ? "确定" : "编辑" }}
      </button>
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      msg: 'hello',
      isEdit: false,
    }
  },
  methods: {
    edit() {
      this.isEdit = !this.isEdit
      if(this.isEdit){
        this.$refs.ref1.focus()
      }
    },
  },
};
</script>

<style scoped>
.app {
  background-color: #ddd;
  padding: 8px;
  display: flex;
}
.left {
  width: 30%;
  margin-right: 20px;
}
.t1 {
  border: 1px solid #000;
}
.t2 input {
  width: 100%;
}
</style>

name后面为项目名,最好写

el后面的为vue管理的区域,必须写

选择器,可以叫app,也可以叫别的。

插槽

如果希望child传递的一些数据(是js数据的话),通过props传递

我现在希望给child组件传递一些html结构(比如传递过去一个input框——vue插槽)

可以通过一个内置组件来接受父组件传递过来的DOM结构——slot

插槽可以分发一些视图

首先组件需要写成双标签,双标签中的内容为父组件传给子组件的内容

使用slot在子组件中接收并渲染从父组件接收过来的内容

简单父子组件插槽

<!-- 父控件内容 -->
<div id="app">
  <p ref="peiqi">这是一个段落</p>
  <Child>
    <input />
  </Child>
</div>

<!-- 子控件内容 -->
<div>
  <slot></slot>
</div>

双插槽(具名插槽)

<Child>
  <!-- 需要将h1放在name=h1的插槽中,将p放在name=p的插槽中 -->
  <template v-slot:h1>
    <h1>这是一个父组件的标题</h1>
  </template>
  <template v-slot:p>
    <p>这是一个父组件的段落</p>
  </template>
</Child>
<!-- 子控件内容 -->
<slot name="h1"></slot>
this is a child
<slot name="p"></slot>

为默认插槽,只分发一个的时候,可以不写name="default"与