vue2函数式组件

1,282 阅读3分钟

image.png

特点:无状态 (没有响应式数据),也没有实例 (没有 this 上下文)

官网

可以使用数据

官网列出了函数式组件中可以使用的东西

image.png

根据官网我全部列出了参数

image.png

因为有一些参数有循环引用,JSON无法解析,所以我打印在控制台上面

image.png

下面是组件的源码

<template functional>
  <div>
    <el-row :gutter="20">
      <el-col :span="5">props:提供所有 prop 的对象</el-col>
      <el-col :span="19">{{props}}</el-col>
    </el-row>
    <el-divider></el-divider>
    <el-row :gutter="20">
      <el-col :span="5">children:VNode 子节点的数组</el-col>
      <el-col :span="19">{{props.showChildren(children)}}</el-col>
    </el-row>
    <el-divider></el-divider>
    <el-row :gutter="20">
      <el-col :span="5">slots:一个函数,返回了包含所有插槽的对象</el-col>
      <el-col :span="19">{{props.showSlots(slots())}}</el-col>
    </el-row>
    <el-divider></el-divider>
    <el-row :gutter="20">
      <el-col :span="5">scopedSlots:(2.6.0+) 一个暴露传入的作用域插槽的对象。也以函数形式暴露普通插槽。</el-col>
      <el-col :span="19">{{scopedSlots}}</el-col>
    </el-row>
    <el-divider></el-divider>
    <el-row :gutter="20">
      <el-col :span="5">data:传递给组件的整个数据对象,作为 createElement 的第二个参数传入组件</el-col>
      <el-col :span="19">{{data}}</el-col>
    </el-row>
    <el-divider></el-divider>
    <el-row :gutter="20">
      <el-col :span="5">parent:对父组件的引用</el-col>
      <el-col :span="19">
        <span>
          {{props.showParent}}
        </span>
        {{props.showParent(parent)}}
      </el-col>
    </el-row>
    <el-divider></el-divider>
    <el-row :gutter="20">
      <el-col :span="5">listeners:(2.3.0+) 一个包含了所有父组件为当前组件注册的事件监听器的对象。这是 data.on 的一个别名。</el-col>
      <el-col :span="19">{{listeners}}</el-col>
    </el-row>
    <el-divider></el-divider>
    <el-row :gutter="20">
      <el-col :span="5">injections:(2.3.0+) 如果使用了 inject 选项,则该对象包含了应当被注入的 property。</el-col>
      <el-col :span="19">{{props.showInjections(injections)}}</el-col>
    </el-row>
    <el-divider></el-divider>
  </div>
</template>

<script lang="ts">
// @ts-nocheck
export default {
  name: 'FunGetData',
  props:{
    showParent:{
      type: Function,
      default:(val)=>{
        console.log('showParent',val)
        return '66666'
      }
    },
    showInjections:{
      type: Function,
      default:(val)=>{
        console.log('showInjections',val)
        return '66666'
      }
    },
    showChildren:{
      type: Function,
      default:(val)=>{
        console.log('showChildren',val)
        return '66666'
      }
    },
    showSlots:{
      type: Function,
      default:(val)=>{
        console.log('showSlots',val)
        return '66666'
      }
    },
    showValue: {
      type:String,
      default: '5555'
    }
  },
  inject:['testData']
}
</script>

<style scoped lang="scss">
</style>

父级组件

<template>
  <div class="funcComIndex">
    <el-card>
      <h1>函数单文件</h1>
      <p><a href="https://v2.cn.vuejs.org/v2/guide/render-function.html#函数式组件" target="_blank">函数式组件</a></p>
    </el-card>
    <el-card>
      <h1>可以获取的数据</h1>
      <FunGetData>
        <div>test</div>
      </FunGetData>
    </el-card>
    <el-card>
      <h1>ref</h1>
      <p>这个ref应该写在函数组件内部,函数组件自己是没有实例的,所以获取的ref都是函数组件里面带有实例的</p>
      <FunRef refs="FunRefs"></FunRef>
    </el-card>
    <el-card>
      <h1>递归</h1>
      <Recursion
        :count="1"
        :flood="3"
      ></Recursion>
    </el-card>
  </div>
</template>

<script lang="ts">
// @ts-nocheck
import FunGetData from './FunGetData'
import FunRef from './FunRef'
import Recursion from './Recursion'
export default {
  name: "FuncCom",
  components:{
    FunRef,
    FunGetData,
    Recursion,
  },
  data(){
    return {
      data: '6666'
    }
  },
  provide(){
    return {
      testData: this.data
    }
  },
  methods:{
  }
}
</script>

<style scoped lang="scss">
.funcComIndex{
  color: blue;
}
.FunGetData{
  color: red;
}
</style>

一开始我以为children就是slot,但是官网有解释

image.png

控制台打印出来的数据也是如此

image.png

小提示

函数式组件的props也是可以有默认值的

实例引用ref

父组件都是上面提到的父组件

比如想引用这个组件调用方法,这个ref怎么用?

这个官网没有提到,就比如下面的这个组件我想引用里面这个元素怎么办?

<template functional>
  <div :ref="props.refs">
    我是funRef函数式组件: {{props.refs}}
  </div>
</template>

<script lang="ts">
// @ts-nocheck
export default {
  props:{
    refs:{
      type:String,
      default: ''
    }
  }
}
</script>

<style scoped lang="scss">

</style>

一开始我是这样写的

<FunRef ref="FunRef"></FunRef>

image.png

在refs中没有FunRef这个引用,绝了

后来我在组件里面写了一个,不过现在这里我是通过props传入名字,也是一样的,props不能是ref,这个ref就像关键词一样,会不生效,所以我写了一个refs传入进去 ̄□ ̄||

<FunRef refs="FunRefs"></FunRef>

image.png

在组件引用中就出现了

image.png

这个就完全实现了我想要减少vue层级的功能

样式-class

我只在父级写了样式

image.png

image.png

发现编译出来的data-v是一样的,我在想这样是不是样式就是要写在一起

image.png

事实证明是可以写在一起的

image.png

image.png

但是如果你在组件里面也写了样式

image.png

这个data-v就变了,也就是说这个函数式组件可以写独立的样式

image.png

递归

image.png

<template functional>
  <div :ref="'count'+props.count">
    这是递归:层级{{props.count}}
    <Recursion
      v-if="props.count < props.flood"
      :flood="props.flood"
      :count="props.count+1"
    ></Recursion>
  </div>
</template>

<script lang="ts">
// @ts-nocheck
export default {
  name: 'Recursion',
  props: {
    count: {
      type: Number,
      default: 3
    },
    flood:{
      type:Number,
      default: 3
    }
  }
}
</script>

<style scoped lang="scss">

</style>

递归也是完全可以使用的

层级再多,这个$refs也是挂载在父级中,非常的好用

image.png

总结

利用函数式组件的这些特性,我们封装组件就可以减少vue层级,也就是减少$refs的个数就可以拿到对应的实例,

比如:

page--》vue1---》vue3---》vue2

功能上面vue2其实就是展示vue1的数据,用vue1的数据进行双向绑定,但是vue2比较麻烦我就用vue3包装了一下,这个时候我要拿vue2,我就要这样:

page.$refs.vue1.$refs.vue3.$refs.vue2

如果vue3是一个函数式组件,我就可以这样写

page--》vue1---》vue3---》vue2

page.$refs.vue1.$refs.vue2

非常的快乐

最后

欢迎关注公众号致心空间:O(∩_∩)O😁

致心空间