vue2、3复习03-组件概念,keep-alive保持状态,插槽的基础用法、默认内容,具名插槽,作用域插槽,解构作用域插槽的scope,私有及全局自定义指令,updated函数,自定义指令的参数值

1、什么是动态组件

指的是动态切换组件的显示与隐藏,vue提供了一个内置的<component>组件,专门用来实现组件的动态渲染。
1、<component>是组件的占位符
2、通过is属性动态来指定要渲染的组件名称
3、<component is="要渲染的组件的名称"></component

关键代码:

    <component :is="comName"></component>

源码
grandFather.vue

<template>
  <h3>here is grandfather component</h3>
</template>

<script>

  export default {
    name: 'GrandFather',
    data(){
      return{
      }
    },
    methods:{

    },
    components:{
    }
  }
</script>

<style scoped>

</style>

Father.vue

<template>
  <h3>here is Father component</h3>
  <hr/>
</template>

<script>

  export default {
    name: 'Father',
    components:{
    }
  }
</script>

<style scoped>

</style>

app.vue

<template>
  <div>
    <component :is="comName"></component>
    <button @click="changeGrandFather">切换组件grandfather</button>
    <button @click="changeFather">切换组件father</button>
    <hr/>

  </div>
</template>

<script>
  import GrandFather from './components/GrandFather.vue'
  import Father from './components/Father.vue'

  export default {
  name: 'App',
  data(){
    return {
      comName:''
    }
  },
  methods:{
    changeGrandFather(){
      console.log('grandfather')
      this.comName='GrandFather'
    },
    changeFather(){
      console.log('father')
      this.comName='Father'
    }
  },

  components: {
    GrandFather,
    Father

  }
}
</script>

<style scoped>

</style>


2、keep-alive保持状态

默认情况下,切换动态组件无法保持组件的状态。此时可以使用vue内置的<keep-alive>组件保持动态组件的状态
方法:
使用<keep-alive>包裹<component>占位组件
关键代码

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

当切换组件的时候,组件内绑定的值不会回到初始状态

grandfather.vue

<template>
  <h3>here is grandfather component{{count}}</h3>
  <button @click="addcount">add</button>
</template>

<script>

  export default {
    name: 'GrandFather',
    data(){
      return{
        count:0
      }
    },
    methods:{
      addcount(){
        this.count++
      }
    },
    components:{
    }
  }
</script>

<style scoped>

</style>

3、插槽的基础用法

在封装组件时,可以通过<slot>元素定义插槽,从而为用户预留内容占位符
如果在封装组件时没有预留任何<slot>插槽,则用户提供的任何自定义内容都会被丢弃
1、在子组件中申明插槽位置进行占位
2、在父组件的组件标签内进行填充
grandfather.vue

<template>
  <h3>here is grandfather component</h3>
  <slot></slot>
  <h3>here is grandfather component</h3>
</template>

<script>

  export default {
    name: 'GrandFather',
    data(){
      return{

      }
    },
    methods:{

    },
    components:{
    }
  }
</script>

<style scoped>

</style>

app.vue

<template>
  <div>
    <GrandFather>
      <p>我是把插槽占位填满的内容</p>
    </GrandFather>

    <hr/>

  </div>
</template>

<script>
  import GrandFather from './components/GrandFather.vue'

  export default {
  name: 'App',
  data(){
    return {
    }
  },
  methods:{

  },

  components: {
    GrandFather,
  }
}
</script>

<style scoped>

</style>


4、插槽的默认内容

封装组件时,可以为插槽提供默认内容,如果组件的使用者没有为插槽提供任何内容,则默认内容会生效。
grandfather.vue

<template>
  <h3>here is grandfather component</h3>
  <slot>我是插槽的默认内容</slot>
  <h3>here is grandfather component</h3>
</template>

<script>

  export default {
    name: 'GrandFather',
    data(){
      return{

      }
    },
    methods:{

    },
    components:{
    }
  }
</script>

<style scoped>

</style>

app.vue

<template>
  <div>
    <GrandFather>
    </GrandFather>

    <hr/>

  </div>
</template>

<script>
  import GrandFather from './components/GrandFather.vue'

  export default {
  name: 'App',
  data(){
    return {
    }
  },
  methods:{

  },

  components: {
    GrandFather,
  }
}
</script>

<style scoped>

</style>


5、具名插槽

1、封装组件时需要预留多个插槽节点,则需要为每个<slot>指定具体的name名称。这种带有具体名称的查插槽叫做具名插槽。
形式为:
<slot name=“插槽名”>
2、如果不为插槽指定插槽名,也会有一个默认的插槽名:default
3、在父组件中使用具名插槽使用<template v-slot:插槽名></template>
4、具名插槽可以用#来简写,简写成#header之类

grandfather.vue

<template>
  <h3>header</h3>
  <slot name="headerSlot">我是header插槽的默认内容</slot>
  <h3>body</h3>
  <slot name="bodySlot">我是body插槽的默认内容</slot>
  <h3>defualt</h3>
  <slot >不指定插槽名称会有一个默认的名称叫做defualt</slot>
  <h3>Footer</h3>
  <slot name="FooterSlot">我是Footer插槽的默认内容</slot>
</template>

<script>

  export default {
    name: 'GrandFather',
    data(){
      return{

      }
    },
    methods:{

    },
    components:{
    }
  }
</script>

<style scoped>

</style>

app.vue

<template>
  <div>
    <GrandFather>
      <template v-slot:headerSlot>
        我是header的内容,从父组件传来的
      </template>
      <template v-slot:bodySlot>
        我父组件传来的body内容
      </template>
      我是父组件传来的默认内容
      <template v-slot:FooterSlot>
        我是父组件传来的footer内容
      </template>
    </GrandFather>

    <hr/>

  </div>
</template>



<script>
  import GrandFather from './components/GrandFather.vue'

  export default {
  name: 'App',
  data(){
    return {
    }
  },
  methods:{

  },

  components: {
    GrandFather,
  }
}
</script>

<style scoped>

</style>


6、作用域插槽

在封装组件的过程中,可以为预留的<slot>插槽绑定props数据,这种带有props数据的插槽叫做‘作用域插槽’

  • 1、在子组件中定义具名插槽,并在插槽中通过绑定方式传入相应的数据,这个数据可以是多个属性

ps:注意,虽然是子组件,但是由于在父组件中使用插槽,事实上,这里的插槽承担起了传值的功能,事实上扮演了一个父组件(父传子)的角色。也就需要在slot上添加属性,绑定子组件中的数据(通常是一个对象)

<template>
  <h3>header</h3>
  <slot name="headerSlot" :info="information" :msg="mymsg"></slot>

</template>
data(){
      return{
        information:{
          name:'zhangsan',
          age:12
        },
        mymsg:{
          address:'beijing',
          major:'computer'
        }
      }
    },
  • 2、在父组件中使用插槽。由于是在组件中使用插槽,事实上承担了子组件的功能。所以。从插槽传来的数据,要在父组件中使用
    关键代码:
<template>
  <div>
    <GrandFather>
     <template v-slot:headerSlot="scope">
        我是header的内容,从父组件传来的:
        {{scope}}
        <br/>
        {{scope.info.name}}
      </template>

    </GrandFather>

    <hr/>

  </div>
</template>

ps:这里cope接受组件中slot传来的数据,scope是一个约定俗成的单词,不是默认,直接使用具名插槽使用等号接收数据,打印内容如下

header
我是header的内容,从父组件传来的: { "info": { "name": "zhangsan", "age": 12 }, "msg": { "address": "beijing", "major": "computer" } }
7、结构作用域插槽的scope

上例app.vue

<template>
  <div>
    <GrandFather>
      <template v-slot:headerSlot="{info,msg}">
        我是header的内容,从父组件传来的:
        {{info}}
        <br/>
        {{info.name}}
      </template>

    </GrandFather>

    <hr/>

  </div>
</template>



<script>
  import GrandFather from './components/GrandFather.vue'

  export default {
  name: 'App',
  data(){
    return {
    }
  },
  methods:{

  },

  components: {
    GrandFather,
  }
}
</script>

<style scoped>

</style>


打印内容如下:

header
我是header的内容,从父组件传来的: { "name": "zhangsan", "age": 12 }
zhangsan
8、自定义指令

1、私有自定义指令:组件内的自定义指令
2、全局自定义指令:main.js声明的自定义指令,全局可用

9、创建私有自定义指令

1、在每个vue组件中的directives节点声明私有自定义指令,directives里面每个自定义组件是一个自定义指令对象,自定义指令对象中是一个mouted(){}生命周期函数,在这个函数里面可以创建自定义指令的具体逻辑。
ps:这里mouted的参数el就是自定义指令所在的dom元素

directives:{
      //自定义一个私有指令
      focus:{
        //让被绑定的元素插入到dom中时,自动触发mounted函数
        mounted(el){
          el.focus()
        }

      }
    } ,

2、在组件内使用v-xxx自定义指令

<template>
  <h3>header</h3>
  <input type="text" v-focus>
</template>

完整代码

<template>
  <h3>header</h3>
  <input type="text" v-focus>
</template>

<script>

  export default {
    name: 'GrandFather',
    data(){
      return{
        information:{
          name:'zhangsan',
          age:12
        },
        mymsg:{
          address:'beijing',
          major:'computer'
        }
      }
    },
    directives:{
      //自定义一个私有指令
      focus:{
        //让被绑定的元素插入到dom中时,自动触发mounted函数
        mounted(el){
          el.focus()
        }

      }
    } ,
    methods:{

    },
    components:{
    }
  }
</script>

<style scoped>

</style>

10、创建全局自定义指令

在main.js中的app对象上创建全局自定义指令
语法格式如下

app.directive(‘指令名’,{指令对象}

关键代码

app.directive('focus',{
  //让被绑定的元素插入到dom中时,自动触发mounted函数
  mounted(el){
     el.focus()
  }
})

完整代码
main.js

import { createApp } from 'vue'
import App from './App.vue'
import './index.css'

const app=createApp(App)

app.directive('focus',{
  //让被绑定的元素插入到dom中时,自动触发mounted函数
  mounted(el){
     el.focus()
  }
})

app.mount('#app')

app.js

<template>
  <div>
    <input type="text" v-focus>
  </div>
</template>



<script>
  import GrandFather from './components/GrandFather.vue'

  export default {
  name: 'App',
  data(){
    return {
    }
  },

  methods:{

  },

  components: {
    GrandFather,
  }
}
</script>

<style scoped>

</style>


11、updated函数

上例在自定义指令中指定了mouted方法,mounted函数只在元素第一次插入dom时被调用,当dom更新时mounted函数不会被触发,updated函数会在每次dom更新完成后被调用。

在directive里面生命updated函数
关键代码

app.directive('focus',{
  //让被绑定的元素插入到dom中时,自动触发mounted函数
  mounted(el){
     el.focus()
  },
  //每次dom更新时都会触发update函数
  updated(el){
    el.focus()
  }
})

完整代码
grandfather.vue

<template>
  <h3>GrandFather组件 {{count}}</h3>
  <input type="text" v-focus>
  <button @click="addone">add1</button>
</template>

<script>

  export default {
    name: 'GrandFather',
    data(){
      return{
        count:0
      }
    },

    methods:{
      addone(){
        this.count++
      }
    },
    components:{
    }
  }
</script>

<style scoped>

</style>

app.vue

<template>
  <GrandFather></GrandFather>
</template>



<script>
  import GrandFather from './components/GrandFather.vue'

  export default {
  name: 'App',
  data(){
    return {
    }
  },

  methods:{

  },

  components: {
    GrandFather,
  }
}
</script>

<style scoped>

</style>


main.js

import { createApp } from 'vue'
import App from './App.vue'
import './index.css'

const app=createApp(App)

app.directive('focus',{
  //让被绑定的元素插入到dom中时,自动触发mounted函数
  mounted(el){
     el.focus()
  },
  //每次dom更新时都会触发update函数
  updated(el){
    el.focus()
  }
})

app.mount('#app')

12、自定义指令的两个注意点

1、vue3使用mouted方法,vue2使用bind方法
2、mouted和update函数中的逻辑完全相同,可以进行简写

app.directive('focus',(el)=>{
	//在mounted和updated时都会触发相同的业务处理
     el.focus()
})
13、自定义指令的参数值

在绑定指令是,可以通过等号的形式为指令绑定具体的参数值
关键代码为:
子组件
grandfather.vue

<template>
  <h3>GrandFather组件</h3>
  <div v-color="'red'">通过自定义指令传参,给文字添加颜色</div>
</template>

<script>

  export default {
    name: 'GrandFather',
    data(){
      return{
      }
    },

    methods:{

    },
    components:{
    }
  }
</script>

<style scoped>

</style>

自定义指令代码
main.js

import { createApp } from 'vue'
import App from './App.vue'
import './index.css'

const app=createApp(App)

app.directive('color',{
  mounted(el,params){
    //parmas.value就是通过等号为指定绑定的值
    el.style.color=params.value
  }
})

app.mount('#app')

自己写的一个穿多个参数的情形

grandfather.vue

<template>
  <h3>GrandFather组件</h3>
  //这里传入了一个数组
  <div v-color="['red','green']">通过自定义指令传参,给文字添加颜色</div>
</template>

<script>

  export default {
    name: 'GrandFather',
    data(){
      return{
      }
    },

    methods:{

    },
    components:{
    }
  }
</script>

<style scoped>

</style>

app.vue

<template>
  <GrandFather></GrandFather>
</template>



<script>
  import GrandFather from './components/GrandFather.vue'

  export default {
  name: 'App',
  data(){
    return {
    }
  },

  methods:{

  },

  components: {
    GrandFather,
  }
}
</script>

<style scoped>

</style>


main.js

app.directive('color',{
  mounted(el,params){
    console.log(params)
    //parmas.value就是通过等号为指定绑定的值
    for (let index in params) {
      el.style.color=params.value[0]
      el.style.backgroundColor=params.value[1]
    }

  }
})
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值