Skip to content

fpi-el-rolling 无限滚动组件 0.7.2

TIP

当前组件在 element-plus-expand 0.7.2 版本后正式部署

横向滚动

设置 directionx 即可开启横向滚动,当然默认组件也是 x 可以不传。 time 是滚动完一个周期所需要的时间,组件内部会动态监听时间变化而刷新动画。

<template>
    <div class="rolling-test">
        <FpiElRolling direction="x" :time="10">
            <div class="model-box">
                <div v-for="item, index in list" :key="index" class="model">
                    {{ item }}
                </div>
            </div>
        </FpiElRolling>
    </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
const list = [1, 2, 3, 4, 5, 6, 7, 8]
</script>

<style lang="scss" scoped>
.rolling-test {
    width: 100%;
    height: 120px;

    .model-box {
        display: flex;
        height: 120px;
        padding: 10px 0;

        div {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 120px;
            height: 100%;
            margin: 0 2px;
            color: white;
            cursor: pointer;
            background-color: var(--el-color-primary-light-3);
            transition: all 0.5s;
        }

        div:hover {
            box-shadow: 0 0 10px 5px #67b3dd;
            transform: scale(1.1);
        }
    }
}
</style>
显示代码

外部控制动画 和 设置触发条件

我们可以传入 v-model 外部控制动画效果, true 为播放 false 为暂停。 我们传入 action 可以设置改变动画状态的条件, 当设置为 none 时 组件内部不会自动改变动画

<!--
 * @Author: mjh
 * @Date: 2023-05-11 11:08:09
 * @LastEditors: mjh
 * @LastEditTime: 2023-05-11 11:27:01
 * @Description:
-->
<template>
    <div class="rolling-test">
        <FpiElRolling v-model="isRolling" action="dblclick">
            <div class="model-box">
                <div v-for="item, index in list" :key="index" class="model">
                    {{ item }}
                </div>
            </div>
        </FpiElRolling>
    </div>
    <ElButton @click="updateList()">
        点击修改状态
    </ElButton>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
const list = [1, 2, 3, 4, 5, 6, 7, 8]
const isRolling = ref(true)

const updateList = () => {
    isRolling.value = !isRolling.value
}
</script>

<style lang="scss" scoped>
.rolling-test {
    width: 100%;
    height: 120px;

    .model-box {
        display: flex;
        height: 120px;
        padding: 10px 0;

        div {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 120px;
            height: 100%;
            margin: 0 2px;
            color: white;
            cursor: pointer;
            background-color: var(--el-color-primary-light-3);
            transition: all 0.5s;
        }

        div:hover {
            box-shadow: 0 0 10px 5px #67b3dd;
            transform: scale(1.1);
        }
    }
}
</style>
显示代码

纵向滚动

设置 directiony 即可开启纵向滚动

<!--
 * @Author: mjh
 * @Date: 2023-05-11 11:08:09
 * @LastEditors: mjh
 * @LastEditTime: 2023-05-25 15:11:14
 * @Description:
-->
<template>
    <div class="rolling-test">
        <FpiElRolling direction="y" :time="5">
            <div class="model-box">
                <div v-for="item, index in list" :key="index" class="model">
                    {{ item }}
                </div>
            </div>
        </FpiElRolling>
    </div>
</template>

<script lang="ts" setup>
const list = [1, 2, 3, 4, 5, 6, 7, 8]
</script>

<style lang="scss" scoped>
.rolling-test {
    width: 120px;
    height: 300px;
    margin: 0 auto;

    .model-box {
        padding: 0 10px;

        div {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 100px;
            height: 100px;
            margin: 2px 0;
            color: white;
            cursor: pointer;
            background-color: var(--el-color-primary-light-3);
            transition: all 0.5s;
        }

        div:hover {
            box-shadow: 0 0 10px 5px #67b3dd;
            transform: scale(1.1);
        }
    }
}
</style>
显示代码

自动停止

组件内部会监听内部的插槽dom的变化,当内部插槽dom 相应的宽高变化时会重新刷新动画。如果内部的插槽相应的宽或者高低于容器时,会触发组件的强制停止,无限滚动动画会无法开启。

<!--
 * @Author: mjh
 * @Date: 2023-05-11 11:22:40
 * @LastEditors: mjh
 * @LastEditTime: 2023-05-17 10:28:10
 * @Description:
-->
<template>
    <div class="rolling-test">
        <FpiElRolling ref="rollingDom">
            <div class="model-box">
                <div v-for="item, index in list" :key="index" class="model">
                    {{ item }}
                </div>
            </div>
        </FpiElRolling>
    </div>
    <ElButton @click="updateList()">
        点击改变列表
    </ElButton>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
const list = ref([1, 2, 3, 4, 5, 6, 7, 8])
const rollingDom = ref()
const updateList = () => {
    list.value = list.value.length === 3 ? [1, 2, 3, 4, 5, 6, 7, 8] : [1, 2, 3]
}
</script>

<style lang="scss" scoped>
.rolling-test {
    width: 100%;
    height: 120px;

    .model-box {
        display: flex;
        height: 120px;
        padding: 10px 0;

        div {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 120px;
            height: 100%;
            margin: 0 2px;
            color: white;
            cursor: pointer;
            background-color: var(--el-color-primary-light-3);
            transition: all 0.5s;
        }

        div:hover {
            box-shadow: 0 0 10px 5px #67b3dd;
            transform: scale(1.1);
        }
    }
}
</style>
显示代码

循环获取dom

由于为了实现首尾相连的效果组件内部会将我们的 dom 复制一份,所以如果我们需要循环操作dom的时候,请设置 dom 一样的 class 然后通过 class 来获取 dom 列表,列表内就会出现相应被复制的内容,最后记得将我们复制的 dom 也进行操作哦!

<template>
    <div class="rolling-test">
        <FpiElRolling>
            <div class="model-box">
                <div v-for="item, index in dataList" :key="index" class="model-charts-example" />
            </div>
        </FpiElRolling>
    </div>
</template>

<script lang="ts" setup>
import * as echarts from 'echarts'
import { onMounted } from 'vue'
const dataList = [
    {
        count: 1,
        dataList: [
            { name: '以建设', value: 4, rate: '100%' },
            { name: '建设中', value: 0, rate: '0%' }
        ]
    },
    {
        count: 2,
        dataList: [
            { name: '以建设', value: 23, rate: '100%' },
            { name: '建设中', value: 0, rate: '0%' }
        ]
    },
    {
        count: 3,
        dataList: [
            { name: '以建设', value: 2, rate: '100%' },
            { name: '建设中', value: 0, rate: '0%' }
        ]
    },
    {
        count: 4,
        dataList: [
            { name: '以建设', value: 2, rate: '100%' },
            { name: '建设中', value: 0, rate: '0%' }
        ]
    },
    {
        count: 5,
        dataList: [
            { name: '以建设', value: 4, rate: '100%' },
            { name: '建设中', value: 0, rate: '0%' }
        ]
    },
    {
        count: 6,
        dataList: [
            { name: '以建设', value: 23, rate: '100%' },
            { name: '建设中', value: 0, rate: '0%' }
        ]
    },
    {
        count: 7,
        dataList: [
            { name: '以建设', value: 2, rate: '100%' },
            { name: '建设中', value: 0, rate: '0%' }
        ]
    },
    {
        count: 8,
        dataList: [
            { name: '以建设', value: 2, rate: '100%' },
            { name: '建设中', value: 0, rate: '0%' }
        ]
    }
]

const getProjectProgressOption = (pieData: { name: string; value: number; rate: string }[], count: number) => {
    const chartOption = {
        grid: {
            top: 'center',
            left: 'center',
        },
        color: ['#36F097', '#FF8000'],
        tooltip: {
            trigger: 'item',
            formatter: (params: {
                data: {
                    name: string
                    value: string
                    rate: string
                }
            }) => {
                const {
                    data: { name, value, rate }
                } = params
                return `${name}${value}家(${rate})`
            }
        },
        graphic: [ // 设置饼图中间文字内容
            {
                type: 'text',
                left: 'center', // center不行 因为会飞到整个div的中间
                top: 'center',
                style: {
                    text: count,
                    textAlign: 'center',
                    fontWeight: 'normal',
                    fill: 'rgba(255,255,255,.85)',
                    fontSize: 24,
                    fontFamily: 'Oswald'
                }
            }
        ],
        series: [
            {
                name: '企业档案',
                type: 'pie',
                center: ['50%', '50%'],
                radius: ['63%', '90%'],
                avoidLabelOverlap: true,
                hoverAnimation: false,
                data: pieData,
                itemStyle: {
                    normal: {
                        label: {
                            show: false
                        },
                        labelLine: {
                            show: false
                        }
                    }
                }
            }
        ]
    }
    return chartOption
}

onMounted(() => {
    getChartData()
})

const getChartData = () => {
    const getDomList = document.getElementsByClassName('model-charts-example')
    const length = dataList.length
    dataList.forEach((item, index) => {
        const dom = getDomList[index] as HTMLElement
        const domClone = getDomList[index + length] as HTMLElement
        if (!dom || !domClone) return
        const option = getProjectProgressOption(item.dataList, item.count)
        const chartChance = echarts.init(dom)
        chartChance.setOption(option)
        // 绘制复制dom
        const chartChanceClone = echarts.init(domClone)
        chartChanceClone.setOption(option)
    })
}
</script>

<style lang="scss" scoped>
.rolling-test {
    width: 100%;
    height: 120px;

    .model-box {
        display: flex;
        height: 120px;
        padding: 10px 0;

        div {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 120px;
            height: 100%;
            margin: 0 2px;
            color: white;
            cursor: pointer;
            background-color: var(--el-color-primary-light-3);
            transition: all 0.5s;
        }

        div:hover {
            box-shadow: 0 0 10px 5px #67b3dd;
            transform: scale(1.1);
        }
    }
}
</style>
显示代码

鼠标滚动控制动画 0.7.4

如果滚动方向为 y,可以设置 scrollAble 为 true 即可开启鼠标滚动控制动画。

<!--
 * @Author: mjh
 * @Date: 2023-05-11 11:08:09
 * @LastEditors: mjh
 * @LastEditTime: 2023-05-25 15:11:24
 * @Description:
-->
<template>
    <div class="rolling-test">
        <FpiElRolling direction="y" scroll-able :time="5">
            <div class="model-box">
                <div v-for="item, index in list" :key="index" class="model">
                    {{ item }}
                </div>
            </div>
        </FpiElRolling>
    </div>
</template>

<script lang="ts" setup>
const list = [1, 2, 3, 4, 5, 6, 7, 8]
</script>

<style lang="scss" scoped>
.rolling-test {
    width: 120px;
    height: 300px;
    margin: 0 auto;

    .model-box {
        padding: 0 10px;

        div {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 100px;
            height: 100px;
            margin: 2px 0;
            color: white;
            cursor: pointer;
            background-color: var(--el-color-primary-light-3);
            transition: all 0.5s;
        }

        div:hover {
            box-shadow: 0 0 10px 5px #67b3dd;
            transform: scale(1.1);
        }
    }
}
</style>
显示代码

鼠标拖拽控制动画 0.8.11

可以设置 isDragControl 为 true 即可开启鼠标拖拽控制动画。

<!--
 * @Author: mjh
 * @Date: 2023-08-24 09:59:34
 * @LastEditors: mjh
 * @LastEditTime: 2023-08-24 10:19:06
 * @Description:
-->
<template>
    <div class="rolling-test">
        <FpiElRolling is-drag-control :time="10">
            <div class="model-box">
                <div v-for="item, index in list" :key="index" class="model">
                    {{ item }}
                </div>
            </div>
        </FpiElRolling>
    </div>
</template>

<script lang="ts" setup>
const list = [1, 2, 3, 4, 5, 6, 7, 8]
</script>

<style lang="scss" scoped>
.rolling-test {
    width: 100%;
    height: 120px;

    .model-box {
        display: flex;
        height: 120px;
        padding: 10px 0;

        div {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 120px;
            height: 100%;
            margin: 0 2px;
            color: white;
            cursor: pointer;
            background-color: var(--el-color-primary-light-3);
            transition: all 0.5s;
        }

        div:hover {
            box-shadow: 0 0 10px 5px #67b3dd;
            transform: scale(1.1);
        }
    }
}
</style>
显示代码

属性

参数说明类型可选值默认值
v-model控制播放, 可以不传booleantrue/falsetrue
direction播放的方向stringx/yx
time播放周期时间number-5
action触发播放改变逻辑stringhover,click,dblclick,none'hover'
scrollAble 0.7.4鼠标滚动控制动画booleantrue/falsefalse
isDragControl 0.8.11鼠标拖拽控制动画booleantrue/falsefalse

事件

事件名说明参数
change动画播放状态组件内部主动改变时触发boolean 播放状态
domChange组件内部插槽dom的相应的宽或者高变化触发currDistance 相应的距离, MutationObserver Observer监听实例

方法

方法名说明参数
clearAnimation清除动画
controlAnimation刷新动画
changeForcedStop手动改变组件强制停止状态(传入 false 时,组件将会无法开启动画)boolean
startAnimation开始动画,如果绑定了v-model会改变modelValue为true--

贡献者:

水产品-马佳辉
大气-李国帝

fpi-component