css3 异形Tab

197 阅读2分钟

radial-gradient() CSS函数创建了一个图像,该图像是由从原点发出的两种或者多种颜色之间的逐步过渡组成。它的形状可以是圆形(circle)或椭圆形(ellipse)。这个方法得到的是一个CSS<gradient>数据类型的对象,其是 <image> 的一种。

image.png

组件tabs

import { ScrollView, View } from "@tarojs/components";
import Taro from "@tarojs/taro";
import { memo, useState } from "react";
import "./index.scss";

interface TabItem {
    title: string;
    value: string | number;
}
interface PropsType {
    tabList: TabItem[]
    tabIndex: number;
    onChange?: (value: string | number) => void;
}
const defaultProps: PropsType = {
    tabList: [],
    tabIndex: 0
};
const Tabs = (props: PropsType) => {
    const { tabList, tabIndex, onChange } = props
    const [activeIndex, setActiveIndex] = useState<number>(tabIndex)
    const [scrollLeft, setScrollLeft] = useState<number>(0)
    const getScrollLeft = (index: number) => {
        const query = Taro.createSelectorQuery();
        query.select('.tab-item').boundingClientRect();
        query.exec((res) => {
            console.log('@res#::', res);
            let width = res[0].width * index;
            console.log('@width#::', width);
            setScrollLeft(width)
        })
    }
    return (
        <ScrollView className="tabs-container" scroll-left={scrollLeft} scrollX={true} scroll-with-animation={true}>
            <View className="tabs">
                {tabList.length && (
                    tabList.map((item: TabItem, index: number) => {
                        return (
                            <View key={index} className="tab-item" onClick={() => {
                                setActiveIndex(index);
                                getScrollLeft(index)
                                onChange && onChange(item.value)
                            }
                            }>
                                <View className={`tab-item-text ${activeIndex === index ? 'text-on' : ''}`} >{item.title}</View>
                                {activeIndex === index && <View className="tab-item-on"></View>}
                            </View>
                        )
                    })
                )}
            </View>
        </ScrollView>
    )
}

Tabs.defaultProps = defaultProps;
export default memo(Tabs);

tab样式

.tabs {
    display: flex;
    align-items: flex-end;
    // flex-wrap: nowrap;
    width: 100%;
    // background-color: #f0ecf4;
    border-radius: 0rpx 20rpx 0rpx 20rpx;
    white-space: nowrap;
    .tab-item {
        position: relative;
        display: inline-block;
        height: 70rpx;
        font-weight: 400;
        font-size: 30rpx;
        color: #808080;
        letter-spacing: 6rpx;
        text-transform: none;
        background-color: #f0ecf4;
        &:first-child {
            border-bottom-left-radius: 20rpx;
        }
        &:last-child {
            border-top-right-radius: 20rpx;
        }
    }
    .tab-item-text {
        position: absolute;
        z-index: 2;
        width: 100%;
        height: 70rpx;
        line-height: 70rpx;
        text-align: center;
    }
    .text-on {
        font-weight: 500;
        color: #fff;
    }
    .tab-item-on {
        position: absolute;
        bottom: 0;
        left: 0;
        z-index: 1;
        width: 100%;
        background-image: linear-gradient(90deg, #87b0fc 0%, #a0cbfb 100%);
    }
    .tab-item {
        &:not(:first-child):not(:last-child) {
            .tab-item-on {
                &::before {
                    content: "";
                    position: absolute;
                    width: 20px;
                    height: 20px;
                    left: -20px;
                    bottom: 0;
                    background: #000;
                    background: radial-gradient(
                        circle at 0 0,
                        transparent 20px,
                        #87b0fc 21px
                    );
                }
                &::after {
                    content: "";
                    position: absolute;
                    width: 20px;
                    height: 20px;
                    right: -20px;
                    bottom: 0;
                    background: #000;
                    background: radial-gradient(
                        circle at 100% 0,
                        transparent 20px,
                        #a0cbfb 21px
                    );
                }
            }
        }
        &:first-child {
            .tab-item-on {
                &::after {
                    content: "";
                    position: absolute;
                    width: 20px;
                    height: 20px;
                    right: -20px;
                    bottom: 0;
                    background: #000;
                    background: radial-gradient(
                        circle at 100% 0,
                        transparent 20px,
                        #a0cbfb 21px
                    );
                }
            }
        }
        &:last-child {
            .tab-item-on {
                &::before {
                    content: "";
                    position: absolute;
                    width: 20px;
                    height: 20px;
                    left: -20px;
                    bottom: 0;
                    background: #000;
                    background: radial-gradient(
                        circle at 0 0,
                        transparent 20px,
                        #87b0fc 21px
                    );
                }
            }
        }
    }
}

.tabs-line {
    white-space: nowrap;
    &-item {
        display: inline-block;
        text-align: center;
        font-size: 26rpx;
        color: #000000;
        border-bottom: 2rpx solid #000;
    }
    .item-on {
        position: relative;
        font-size: 30rpx;
        border-bottom:none;
        .text{
            background: radial-gradient(
                90deg,
                #223261 0%,
                #3d5ba9 50%,
                #172653 100%
            );
            -webkit-background-clip: text;
            color: transparent;
        }
        &::after {
            position: absolute;
            bottom: -2rpx;
            left: 0;
            content: "";
            display: inline-block;
            width: 100%;
            height: 9rpx;
            background: radial-gradient(
                90deg,
                #223261 0%,
                #3d5ba9 50%,
                #172653 100%
            );
        }
    }
}


使用

import { IMG_URL } from "@/config";
import { Image, ScrollView, View } from "@tarojs/components";
import "./index.scss";

import { useState } from "react";
import Tabs from "../commponets/tabs/index";

const MemberDay = () => {
    const [tabList, _] = useState([
        {
            title: '临柜礼遇',
            value: 'v1'
        },
        {
            title: '兑礼规则',
            value: 'v2'
        },
        {
            title: '积分兑礼',
            value: 'v3'
        },
    ]);
    const [toView, setToView] = useState('');
    return (
        <ScrollView style={{ height: '100vh' }} scroll-into-view={toView} scrollY scroll-with-animation={true}>
            <View className="member-day">
                <Image className="bg" mode="widthFix" src={IMG_URL + 'al_member_bg.png'}></Image>
                <View className="tabs-box">
                    <Tabs tabList={tabList} onChange={(value: string) => {
                        setToView(value)
}}/>
                </View>
                <view className="v1 v" id="v1">1</view>
                <view className="v2 v" id="v2">3</view>
                <view className="v3 v" id="v3">3</view>
            </View>
        </ScrollView>
    )
};

export default MemberDay;