wenzhixin / bootstrap-table

An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation, Vue.js)
https://bootstrap-table.com/
MIT License
11.73k stars 4.44k forks source link

onLoadSuccess 事件中向 $root 发送事件, $root 中更改值时,此时会再触发子组件中的 onLoadSuccess,导致无限循环 #6945

Closed szwss closed 9 months ago

szwss commented 1 year ago

Bootstraptable version(s) affected

1.22.1

Description

子组件中用了 bootstrap-table-vue, 在其中监听了事件onLoadSuccess 事件,并在其中向 $root 发送事件,

onLoadSuccess(data) {
    console.log('onLoadSuccess: ', data)

    // 在子组件中触发事件
    this.$eventBus.$emit('bootstrapTableOnLoadSuccess', data)
}

$root 中监听事件

    created() {
        this.$eventBus.$on('bootstrapTableOnLoadSuccess', (data)=>{
            console.log('bootstrapTableOnLoadSuccess event:', data)
            this.statistics = {
                notCashed: 0,
                cashed: 0,
                outOfDate: 0,
            }
        })
}

在监听事件中更改值时,此时会再触发子组件中的 onLoadSuccess,导致无限循环

szwss commented 1 year ago

20230828 最新发现

在 $root 中,如果有 data 改变,都会触发 子组件中的 table 重新请求 api

image
szwss commented 1 year ago

$root 中的 data : bFormCheckboxGroupOnlyWonModal "只看中奖"复选框, 勾选和不勾选都会触发 table 重新请求服务器,

这一点不需要呀

szwss commented 1 year ago

经过进一步测试, 即使不在 $root 下改变一个值,只要在 bootstrap-vue 组件的父组件中 的 onLoadSuccess中改变一个值,都会触发重新 onLoadSuccess

onLoadSuccess() 中放入以下代码,都会造成重新触发 onLoadSuccess

this.statistics = {
                    notCashed: 0,
                    cashed: 0,
                    outOfDate: 0,
                }
szwss commented 11 months ago

@wenzhixin

wenzhixin commented 11 months ago

this.statistics 是不是作为 table 的 options 或者 data 了?

szwss commented 11 months ago

没有哦,就是单纯的 vue 中的 data

wenzhixin commented 11 months ago

假如你是从 url 中获取的数据,那就无需设置 data 呀,因为会去 watch 改值,变更的情况会重新渲染表格。

szwss commented 11 months ago

vue 中的 data: bFormCheckboxGroupOnlyWonModal,这个值在 vue 中改变时,我想触发 bootstrap-table 请求api 获取数据, 只需要请求一次即可

但是现在是,这个值一改变, bootstrap-table 请求api 会无限循环的请求

szwss commented 11 months ago

好久了,上一条回复可能有误

只要在 bootstrap-table 组件的父组件中 的 onLoadSuccess 中改变 vue data 中任意变量的一个值,都会触发重新 onLoadSuccess 事件, 因为我想在 table 加載完数据后,改变 vue data 中的某个变量的值,我发现只能在 onLoadSuccess 事件中能这么做,但是在 onLoadSuccess 这里面改变值后,会重新触发 onLoadSuccess

wenzhixin commented 11 months ago

请求一次即可

建议使用 axios 先获取数据,然后根据返回值去更新 data 的值应该可以解决。

szwss commented 11 months ago

@wenzhixin 您看一下 js:

import BootstrapTable from 'bootstrap-table/dist/bootstrap-table-vue.esm.js'

Vue.component('Dashboard', {
    components: {
        BootstrapTable,
    },
    data() {
        return {
            /**
             *
             */
            statistics: {
                notCashed: 111,
                cashed: 0,
                outOfDate: 0,
            },
        }
    },
    props: {

    },
    computed: {
    },
    created() {
        console.log('main created')
    },
    methods: {
        ajaxRequest(params) {
        ...
        },
        queryParams(params) {
        ...
        },
        onLoadSuccess(data) {
            console.log('onLoadSuccess: ', data)
            this.statistics = {
                notCashed: 0,
                cashed: 0,
                outOfDate: 0,
            }
        },
    },
})

html:

<Dashboard
            inline-template
            :prop-Options="{url:'{{ route($type.'.index_main_data') }}',search: false}"
        >
            <div>
                <div class="my-4 text-center">
                    <b-alert variant="primary" show>
                        <span class="mr-2"><span class="text-secondary">未兑换:</span><span class="text-danger display-4"> @{{ statistics.notCashed }}</span></span>
                        <span class="mr-2"><span class="text-secondary">已兑换:</span><span class="text-success display-4"> @{{ statistics.cashed }}</span></span>
                        <span class=""><span class="text-secondary">到期:</span><span class="display-4"> @{{ statistics.notCashed }}</span></span>
                    </b-alert>
                </div>

                <div id="bootstrap-table-toolbar">
                    <slot name="toolbar"></slot>
                </div>
                <Bootstrap-Table
                    ref="BootstrapTable"
                    :options="computedOptions"

                    :columns="[
                {
                    field: 'id',
                    title: '序号',
                    width: '60',
                    halign:'center',
                    align:'center',
                    sortable:'true',
                },
                {
                    field: 'prize.category',
                    title: '类型',
                    width: '60',
                    halign:'center',
                    align:'center',
                    formatter:'categoryFormatter',
                },
                {
                    field: 'prize.text',
                    title: '奖项名称',
                    width: '80',
                    halign:'center',
                    align:'center',
                },
                {
                    field: 'updated_at',
                    title: '创建时间',
                    width: '100',
                    halign:'center',
                    align:'center',
                },
                {
                    field: 'user.mobile_phone',
                    title: '中奖用户',
                    width: '80',
                    halign:'center',
                    align:'center',
                },
                {
                    field: 'won_at',
                    title: '中奖时间',
                    width: '100',
                    halign:'center',
                    align:'center',
                },
                {
                    field: 'cash_at',
                    title: '兑换时间',
                    width: '100',
                    halign:'center',
                    align:'center',
                    formatter:'cashStatusFormatter',
                },
            ]"
                    @on-load-success="onLoadSuccess"
                />
                <div slot="toolbar">
                    <b-form-radio-group
                        :options="[{ value: 'product', text: '产品' },{ value: 'coupon', text: '优惠券' },{ value: 'money', text: '现金' },]"
                        buttons
                        button-variant="outline-primary"
                        @change="bFormRadioGroupTypeChange"
                        class="d-inline-block"
                    ></b-form-radio-group>
                    <div class="d-inline-block mt-2">
                        <b-form-checkbox-group
                            :options="[{ text: '只看中奖', value: 'only_won' }]"
                            class="ml-2"
                            @change="bFormCheckboxGroupOnlyWonChange"
                        ></b-form-checkbox-group>
                    </div>
                </div>
            </div>

        </Dashboard>

我想在 table 成功加载之后,按情况修改 this.statistics, 当代码这样写时,table 就会触发不断的请求 API, table 不间断的在刷新

szwss commented 11 months ago

我录了个视频 @wenzhixin https://github.com/wenzhixin/bootstrap-table/assets/584808/ff8f34ba-ae23-491a-8b4d-2e8c35630bbe

szwss commented 11 months ago

请求一次即可

建议使用 axios 先获取数据,然后根据返回值去更新 data 的值应该可以解决。

因为有不同状态下的 table 数据不一样,所以还不能这样只取一次的, table 新数据拿到时,再 按需求更改 vue data 中其它的变量, 这个需求应该是请普遍的哦

szwss commented 11 months ago

@wenzhixin 能解决一下吗?目前想拿到数据库视情况更改 vue 中 其它 data 的值,这样才能彻底把 table 组件化,有空看一下嘛

wenzhixin commented 10 months ago

看不出来是什么问题, computedOptions 是如何定义的呢?

szwss commented 10 months ago

computedOptions 这样定义的 @wenzhixin

computed: {
        computedOptions: function () {
            // console.log(this)
            let options = this.defaultOptions

            // options.url = this.propUrl
            Object.keys(this.propOptions).forEach((key, index) => {
                options[key] = this.propOptions[key]
            })

            if (!options.ajax) {
                options.ajax = this.ajaxRequest
            }
            if (!options.queryParams) {
                options.queryParams = this.queryParams
            }

            return options
        },
    },

整个 data 是这样定义的

 data() {
        return {
            //普通 radio group 选项
            // commonRadioYesAndNoOptions: [
            //     {text: '是', value: true}, {text: '否', value: false},
            // ],
            commonRadioOnAndOffOptions: [
                {text: '开启', value: true}, {text: '关闭', value: false},
            ],

            // options: this.propOptions,
            // columns: this.propColumns,
            // data: [],

            /**
             * 20230823 防止前端定制 options 时需要传太多内容
             * 使用这个 default options, 定制时只需要传不一样的 key value 即可
             *
             */
            defaultOptions: {
                toolbar: '#bootstrap-table-toolbar',
                classes: 'table table-bordered table-hover bg-white',
                buttonsClass: 'outline-primary',
                theadClasses: 'thead-light',

                /**
                 *
                 */
                iconsPrefix: 'opacity-75 ion',
                // paginationPreText: '<',
                // paginationNextText: '>',
                icons: {
                    paginationSwitchDown: 'ion-ios-arrow-down icon-chevron-down',
                    paginationSwitchUp: 'ion-ios-arrow-up icon-chevron-up',
                    refresh: 'ion-md-refresh icon-refresh',
                    columns: 'ion-md-apps icon-th',
                    detailOpen: 'ion-ios-arrow-dropright h4 mt-1 mb-0 text-primary',
                    detailClose: 'ion-ios-arrow-dropdown h4 mt-1 mb-0 text-primary',
                    export: 'ion-md-cloud-download icon-share',
                    fullscreen: 'ion-md-contract icon-share',
                    toggleOff: 'ion-md-map',
                    toggleOn: 'ion-ios-map',
                },
                pageList: [10, 25, 50, 100, 500, 1000, 2000], //可供选择的每页的行数()
                /**
                 *
                 */

                locale: 'zh-CN',
                search: true,
                showRefresh: true,
                showToggle: true,
                mobileResponsive: true,
                showFooter: false,
                showColumns: true,
                showExport: true,
                showFullscreen: true,
                rememberOrder: true,

                minimumCountColumns: 1,
                showPaginationSwitch: false,
                pagination: true,
                pageSize: 10,

                idField: 'id',
                sortName: 'id',
                sortOrder: 'desc',

                // ajax: ajaxRequest(),
                sidePagination: 'server',
                // url: this.propUrl,
                // queryParams: queryParams,
            },

            // base
            bFormDatepickerLocale: {
                todayButton: true,
                resetButton: true,
                closeButton: true,
                locale: "zh",
                showDecade: "true",

                weekdayHeaderFormat: "narrow",
                labelPrevDecade: "过去十年",
                labelPrevYear: "上一年",
                labelPrevMonth: "上个月",
                labelCurrentMonth: "当前月份",
                labelNextMonth: "下个月",
                labelNextYear: "明年",
                labelNextDecade: "下一个十年",
                labelToday: "今天",
                labelSelected: "选定日期",
                labelNoDateSelected: "未选择日期",

                labelCalendar: "日历",
                labelNav: "日历导航",
                labelHelp: "使用光标键浏览日期",

                labelTodayButton: "今天",
                labelResetButton: "重置",
                labelCloseButton: "关闭",
            },
            bFormTimepickerLocale: {
                locale: "zh",
                labelHours: "小时",
                labelMinutes: "分钟",
                labelSeconds: "秒",
                labelAmpm: "上午下午",
                labelAm: "上午",
                labelPm: "下午",
                labelIncrement: "增量",
                labelDecrement: "减量",
                labelSelected: "选定时间",
                labelNoTimeSelected: "没有选择时间",

                labelNowButton: "现在",
                labelResetButton: "重置",
                labelCloseButton: "关闭",

                hour12: false,//???
                hourCycle: "h23",//???

                nowButton: true,
                resetButton: true,
                showSeconds: true,
            },

            /**
             *
             */
            statistics: {
                notCashed: 111,
                cashed: 0,
                outOfDate: 0,
            },
        }
    },
szwss commented 10 months ago

有空解决一下吗? 或者有别的方法实现: 当 ajax 请求拿到数据后,也就是 onLoadSuccess 时,能正常修改 vue 中其它的值,不重复触发 onLoadSuccess, 有别的方法实现也行

这是组件化一个重要的路径,这个不解决,我只能一个 vue 写一个页面,会有很多重复代码

szwss commented 10 months ago

看不出来是什么问题, computedOptions 是如何定义的呢?

@wenzhixin

szwss commented 10 months ago

有空解决一下吗? 或者有别的方法实现: 当 ajax 请求拿到数据后,也就是 onLoadSuccess 时,能正常修改 vue 中其它的值,不重复触发 onLoadSuccess, 有别的方法实现也行

这是组件化一个重要的路径,这个不解决,我只能一个 vue 写一个页面,会有很多重复代码

@wenzhixin 能测试解决一下么? 这是一个蛮重要的问题哦

szwss commented 10 months ago

看不出来是什么问题, computedOptions 是如何定义的呢?

@wenzhixin

szwss commented 10 months ago

我试图创建一个在线的 demo: shandbox 但是一直报错 $ is undefined @wenzhixin

wenzhixin commented 10 months ago

https://live.bootstrap-table.com/ 创建一个?

szwss commented 10 months ago

https://live.bootstrap-table.com/ 创建一个?

看了一下,这个是测试 bootstrap-table html 版的, 我用 html 版时没有遇到问题, 现在遇到问题的是 vue 版

vue 版下在 onLoadSuccess 事件中如果改变 vue 实例的其它 data 会重新触发 onLoadSuccess 事件, 是 vue 版才有这种情况 @wenzhixin

szwss commented 10 months ago

@wenzhixin 今天又看了一下,做出来了 https://live.bootstrap-table.com/code/szwss/16828 闪现很快,可以看 console 不断的在请求数据

szwss commented 10 months ago

image

szwss commented 10 months ago

https://live.bootstrap-table.com/code/szwss/16834 onLoadSuccess() 添加了 log 输出

szwss commented 10 months ago

@wenzhixin 能解决吗

wenzhixin commented 10 months ago

@szwss 调试了下,好像是因为你把 columns 定义在了 html 中导致的,statistics 的改变导致渲染的时候把 columns 当做新的属性了,将其移动到 data 或者 computed 中,改为 :columns="columns" 即可解决问题。

https://live.bootstrap-table.com/code/wenzhixin/16859

wenzhixin commented 9 months ago

已给出了解决方案。

szwss commented 3 months ago

好的,谢谢