onmounted vue3_体验vue3,竟然可以完美丝滑的嵌入vue2

vue3马上就要发布了,在正式版发布之前尝了下新,惊喜的发现vue3一个隐藏的玩法:完全兼容vue2,你可以在文件里随意写vue2的代码,接下来听我娓娓道来。

拿一个虚拟长列表组件实现来说:

这是我的父组件:

<LongList :data = 'listData'></LongList>

 setup(){
    const state = reactive({
      listData:list
    })
    return {
      ...toRefs(state)
   }
  }

父组件要做的事情很简单,向虚拟长列表传入listData,下面我们来实现子组件

<template>
  <div class="long-list">
    <div class="list-view" ref='sparent' @scroll="handleScroll">
      <div
      class="list-view-phantom"       
      :style="{
         height: contentHeight
      }"></div>
      <div
        ref="content"
        class="list-view-content">
          <div
            class="list-view-item"
            :style="{
              height: itemHeight + 'px'
            }"
           v-for="(item,index) in visibleData" :key="index">
            {{ item.value }}
          </div>
        </div>
    </div>
  </div>
</template>
<style>
.list-view {
  height: 400px;
  overflow: auto;
  position: relative;
  border: 1px solid #aaa;
}

.list-view-phantom {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  z-index: -1;
}

.list-view-content {
  left: 0;
  right: 0;
  top: 0;
  position: absolute;
}

.list-view-item {
  padding: 5px;
  color: #666;
  line-height: 30px;
  box-sizing: border-box;
}
</style>

template和css和以前的没有什么区别,来看看js吧

import { reactive, computed, onMounted, toRefs, ref } from 'vue'
export default {
  props:{
    data:{
      require:true,
      type:Array
    },
    itemHeight:{
      type:Number,
        default:50
      }
    },
    setup(props){
      const {data, itemHeight} = props
      // 可视区域节点
      const content = ref(null)
      // 容器节点
      const sparent = ref(null)
      const state = reactive({
        visibleData:[],
      })
      // 计算列表的总长度
      const contentHeight = computed(()=> {
        const height = data.length*itemHeight+'px'
        return height
      })
  
      onMounted(()=>{
        updateVisibleData()
      })
  
      // 随着滚动更新可视区域数据
      const updateVisibleData = scrollTop => {
        scrollTop = scrollTop || 0;
       // 可视区域item条数
        const visibleCount = Math.ceil( sparent.value.clientHeight/ itemHeight);
        // 可视区域头尾在数据中的的索引
        const start = Math.floor(scrollTop / itemHeight);
        const end = start + visibleCount;
        state.visibleData = data.slice(start, end);
        // 移动可视区域头部至指定位置
        content.value.style.webkitTransform = `translate3d(0, ${ start * itemHeight }px, 0)`;
      }
  
      // 滚动事件
      const handleScroll = () => {
        const scrollTop = sparent.value.scrollTop
        updateVisibleData(scrollTop)
      } 
      return{
        contentHeight,
        content,
        sparent,
        ...toRefs(state),
        handleScroll,     
      }
   },
}

35c7e3d1a4e66e06f37221c303acdd44.png

如此,我们的虚拟长表单已经基本实现了,这也没有vue2的代码啊?别急,继续听我说。

我们暂时只是实现了虚拟长表单的效果,真实情况往往要点击跳转这种需求,找了下非官方文档,不知道该如何通过子组件向父组件派发事件,这就比较难受了啊。想起之前看资料说vue3可以在文件中使用vue2的代码,然后就找了下尤大的github(传送门:vue-next),搜了下emit,注意到了这个目录vue-next/test-dts/defineComponent.test-d.tsx,这一定就是demo的测试用例了,机智如我这个小机灵鬼。

进去之后先发现了这个东西:

713ec2263279cdc610480db34c213187.png

这熟悉的option API使我热泪盈眶,这是不是意味着setup也是option API的一个选项,如果你想用vue2的生命周期、data、methods、computed,也完全没有问题呢?说干就干,我在setup外边定义methods,果然我能拿到this,也可以完美的使用诸如this.$emit之类的api,是不是特别丝滑?对于不太想用vue3的人完全还是没有压力的,因为几乎完全兼容。这是我的一个意外发现,其实我还是想找到vue3的emit用法,继续向下看,然后终于找到了:

986608e7e3cac2fd5d88e4c583efd19a.png

我们只需在setup中传入一个{emit}就可以在setup中使用了,修改下代码:

  <div class="long-list">
    <div class="list-view" ref='sparent' @scroll="handleScroll">
      <div
      class="list-view-phantom"       
      :style="{
         height: contentHeight
      }"></div>
      <div
        ref="content"
        class="list-view-content">
          <div
            class="list-view-item"
            :style="{
              height: itemHeight + 'px'
            }"
            @click="handleClick(item,index)"
            v-for="(item,index) in visibleData" :key="index">
            {{ item.value }}
          </div>
        </div>
    </div>
  </div>


import { reactive, computed, onMounted, toRefs, ref } from 'vue'
export default {
  props:{
    data:{
      require:true,
      type:Array
    },
    itemHeight:{
      type:Number,
        default:50
      }
    },
    setup(props,{emit}){
      const {data, itemHeight} = props
      // 可视区域节点
      const content = ref(null)
      // 容器节点
      const sparent = ref(null)
      const state = reactive({
        visibleData:[],
      })
      // 计算列表的总长度
      const contentHeight = computed(()=> {
        const height = data.length*itemHeight+'px'
        return height
      })
  
      onMounted(()=>{
        updateVisibleData()
      })
  
      // 随着滚动更新可视区域数据
      const updateVisibleData = scrollTop => {
        scrollTop = scrollTop || 0;
        console.log(sparent,'可视')
        // 可视区域item条数
        const visibleCount = Math.ceil( sparent.value.clientHeight/ itemHeight);
        // 可视区域头尾在数据中的的索引
        const start = Math.floor(scrollTop / itemHeight);
        const end = start + visibleCount;
        state.visibleData = data.slice(start, end);
        // 移动可视区域头部至指定位置
        content.value.style.webkitTransform = `translate3d(0, ${ start * itemHeight }px, 0)`;
      }
  
      // 滚动事件
      const handleScroll = () => {
        const scrollTop = sparent.value.scrollTop
        updateVisibleData(scrollTop)
      }
  
      //向父组件派发事件,父组件和vue2一样的处理
      const handleClick = (item,index)=>{
        console.log(item.value,'??')
        emit('clickItem',{item,index})
      }
  
      return{
        contentHeight,
        content,
        sparent,
        ...toRefs(state),
        handleScroll,
        handleClick
      }
    },
}

好了,完美解决,如果你有的地方喜欢用vue2过渡一下,没有问题,可以实现但我还是喜欢vue3的方式,所以,让我们期待vue3的正式发版吧。最后说一句:尤大牛批,vue牛批!!!

最后的最后,贴一个vue3的API地址:vue-next尝鲜版

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值