nut-popup 二次封装 弹窗 选择组件 vue3

<template>
    <nut-popup overlay-class="diolagClass" pop-class="nut-popup-name-class" :position="posititon"
        v-model:visible="showBasic" @click-overlay="handleClickoverlay" duration="0.2">
        <div class="search-container" v-show="isSearch">
            <div class="search-ipt">
                <input type="text" v-model="cityValue" />
                <IconFont name="search" color="#cccccc" style="
            position: absolute;
            left: 10px;
            top: 50%;
            transform: translateY(-50%);
          "></IconFont>
            </div>
            <div class="search-Icon">
                <IconFont name="search" color="#ffffff" style="font-size: 16px"></IconFont>
            </div>
        </div>
        <scroll-view :scroll-y="true" :style="{ 'min-height': `${listContainerHeight / 2}px` }">
            <div class="list-container" v-if="!status">
                <div class="item" @click="toggleAllItems" :class="{ selected: areAllOptionsSelected() }">
                    全部
                </div>
                <div class="item" v-for="(item, index) in state.options1" :key="item.id" @click="toggleItem(item)"
                    :class="{ selected: isSelected(item.name) }">
                    {{ item.name }}
                </div>
            </div>
            <div class="list-container" v-else>
                <div class="item" v-for="(item, index) in state.options1" :key="item.id" @click="toggleRadioItem(item)"
                    :class="{ selected: isSelected(item.name) }">
                    {{ item.name }}
                </div>
            </div>
        </scroll-view>

        <div class="footerBtn" v-if="!status">
            <div class="footerBtn-left">
                已选择<span style="color: #ee0a24">{{ selectedItems.length }}</span>个
            </div>
            <div class="footerBtn-right">
                <nut-button plain type="primary" @click="resetSelected">
                    <template #icon>
                        <IconFont name="del2"></IconFont>
                    </template>
                    重置
                </nut-button>
                <nut-button style="margin-left: 20px" color="linear-gradient(to right, #ff6034, #ee0a24)"
                    @click="handleClickConfirm" type="info">确认选择</nut-button>
            </div>
        </div>
        <div v-else style="height: 40px"></div>
    </nut-popup>
</template>
<script setup>
import { reactive, ref } from "vue";
import { storeToRefs } from "pinia";
import { IconFont } from "@nutui/icons-vue-taro";
import { toRefs } from "vue";
import Taro from "@tarojs/taro";
const props = defineProps({
    list: Array,
    status: Boolean,
    listContainerHeight: Number,
    showBasic: Boolean,
    type: String,
    posititon: String,
    isSearch: Boolean
});
const { list, status, listContainerHeight, showBasic, type, posititon, isSearch } =
    toRefs(props);
const selectedItems = ref([]);

//判断一下当前的组件是哪个数据触发的
if (type.value == "movie" && Taro.getStorageSync("movie").length) {
    selectedItems.value = Taro.getStorageSync("movie");

} else if (type.value == "cinema" && Taro.getStorageSync("cinema").length) {
    selectedItems.value = Taro.getStorageSync("cinema");

} else {
    selectedItems.value = [];

}


const emit = defineEmits(["onFlagChange", "onconfirmItems", "seatChange", "onupdatedItems"])
const sleectedCloneItems = ref([]);

const state = reactive({
    options1: list,
});

const isSelected = (id) => {
    // console.log(id,"valSeat");
    return selectedItems.value.includes(id);
};

const toggleItem = (e) => {
    if (isSelected(e.name)) {
        selectedItems.value = selectedItems.value.filter((item) => item !== e.name);
    } else {
        selectedItems.value.push(e.name);
    }
};
// 新增函数来检查是否所有选项都被选中
const areAllOptionsSelected = () => {
    return state.options1.every((item) => isSelected(item.name));
};

// 修改点击"全部"选项的逻辑
const toggleAllItems = () => {
    if (areAllOptionsSelected()) {
        selectedItems.value = [];
    } else {
        selectedItems.value = state.options1.map((item) => item.name);
    }
};



const toggleRadioItem = (e) => {
    selectedItems.value = [e.name];
    emit("seatChange", selectedItems.value);
};
const handleClickoverlay = () => {

    emit("onFlagChange", false);

}

//点击确定
const handleClickConfirm = async () => {
    console.log(selectedItems);
    await emit("onconfirmItems", { result: selectedItems.value, type: type.value })

    await emit("onFlagChange", false);

}
//重置按钮

const resetSelected = () => {
    if (!selectedItems.value.length) {
        return
    }
    selectedItems.value = [];
}

</script>
<style lang="less">
.diolagClass {
    top: 65px !important;
}

.nut-popup-name-class {
    margin-top: 65px;
    padding-top: 20px;
}

.nut-popup--top {
    width: 100% !important;
    border-bottom-left-radius: 40px;
    border-bottom-right-radius: 40px;
}

.list-container {
    display: flex;
    // align-items: center;
    justify-content: space-around;
    flex-wrap: wrap;
    padding: 0 20px;

    .selected {
        color: #ee0a24 !important;
        border: 1px solid #ee0a24;
        background-color: #fff !important;
    }

    .item {
        margin-top: 10px;
        font-size: 24px;
        width: 160px;
        height: 60px;
        line-height: 60px;
        background-color: #f7f8fb;
        border-radius: 25px;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 1;
        text-overflow: ellipsis;
        overflow: hidden;
        color: #15181d;
        text-align: center;
    }
}

.footerBtn {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20px;

    .footerBtn-left {
        color: #858a99;
        font-size: 30px;
    }

    .footerBtn-right {}
}

.search-container {
    display: flex;
    justify-content: space-between;
    padding: 20px 40px;
    align-items: center;

    .search-ipt {
        background-color: #fff;
        border: 1px solid #ccc;
        // flex: 4;
        flex: 1;
        position: relative;
        border-radius: 45px;
        padding: 20px;
        font-size: 25px;

        input {
            padding-left: 70px;
            color: #858a99;
        }
    }

    .search-Icon {
        background-color: #fff;
        width: 50px;
        height: 50px;
        line-height: 50px;
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;

        margin-left: 40px;
        background-color: #ee0a24;
        opacity: 0.6;
        padding: 10px;
    }
}
</style>

1.目前组件需求 

移动端使用 ,当需要时选择 单选或者多选的时候 都可以用这个组件

2.效果图片

3.样式大家还可以微调 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于使用 Vue3 和 Nut-Uploader 进行图片上传并调用接口的问题,你可以按照以下步骤进行操作: 1. 首先,确保你已经安装了 Vue3 和 Nut-Uploader,并在你的项目中引入它们。 2. 在你的 Vue 组件中,使用 Nut-Uploader 组件来创建一个上传按钮或拖拽区域。例如: ```vue <template> <nut-uploader :action="uploadUrl" :headers="uploadHeaders" :data="uploadData" @success="handleSuccess" @error="handleError" > <!-- 在这里可以放置上传按钮或拖拽区域的内容 --> </nut-uploader> </template> <script> import { ref } from 'vue'; import NutUploader from 'nut-uploader'; export default { components: { NutUploader, }, setup() { // 定义上传接口 URL const uploadUrl = 'your_upload_api_url'; // 定义上传请求头部信息(可选) const uploadHeaders = { // 设置请求头部信息 }; // 定义上传的附加数据(可选) const uploadData = ref({ // 设置附加数据 }); // 处理上传成功回调 const handleSuccess = (response) => { // 处理成功回调逻辑 }; // 处理上传失败回调 const handleError = (error) => { // 处理失败回调逻辑 }; return { uploadUrl, uploadHeaders, uploadData, handleSuccess, handleError, }; }, }; </script> ``` 3. 在 `uploadUrl` 参数中填入你的上传图片接口的 URL,可以是你自己开发的后端接口。 4. 可选地,你可以在 `uploadHeaders` 对象中设置请求头部信息,例如添加认证信息或其他自定义请求头。 5. 可选地,你可以在 `uploadData` 对象中设置上传时需要携带的额外数据。 6. 在 `handleSuccess` 回调函数中处理上传成功后的逻辑,你可以在这里获取到上传成功后的响应数据。 7. 在 `handleError` 回调函数中处理上传失败后的逻辑,你可以在这里获取到上传失败的错误信息。 请根据你的具体需求进行相关参数的配置和逻辑处理。同时,确保你的后端接口能够正确处理上传请求并返回相应的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值