<template>
    <div class="nus_wheel"
        @click="_onClick"
        @tap="_onTap">
        <div class="nu_wheel-wrap"
            ref="hook_wheel">
            <div class="nu_wheel-rule nu_wheel-rule-ft"></div>
            <ul class="nu_wheel-scroll">
                <li class="nu_wheel-item"
                    v-for="(item, key) in (list || [])"
                    :key="key">
                    {{ _getName(item, prefix, suffix) }}
                </li>
            </ul>
        </div>
    </div>
</template>

<script>
import { Wheel } from 'js-wheel';
import { callFn, diffData } from 'nimble-lib';
import WidgetTmp from '../_comm/WidgetTmp';
import attrSync from '../../../Mixins/attrSync/attrSync';
export default {
    extends: WidgetTmp,
    name: 'NuWheel',
    props: {
        index: {
            type: Number,
            default: 0
        },
        /**
         * 滑动的数据
         */
        list: {
            type: Array
        },
        /**
         * 展示文案的前缀
         */
        prefix: {
            type: String,
            default: ''
        },
        /**
         * 展示文案的后缀
         */
        suffix: {
            type: String,
            default: ''
        },
        /**
         * 进行状态
         */
        state: {
            type: String
        },
        /**
         * 过滤名称过滤器
         */
        filterName: {
            type: Function,
            default(item, options) {
                if (item instanceof Object) {
                    return (options.prefix || '') + ((item && item.text) || '') + (options.suffix || '');
                }
                return (options.prefix || '') + item || '' + (options.suffix || '');
            }
        },

        /**
         * 是否初始化数据
         */
        isInit: {
            type: Boolean,
            default: false
        }
    },
    mixins: [attrSync('activeIndex', { // 设置当前活动项的索引
        value: {
            type: Number,
            default: 0
        },
        mValueChange(nowVal) {
            const _that = this;
            if (_that.myActiveIndex !== nowVal) {
                const _wheel = _that.wheel;
                _that.myActiveIndex = nowVal;
                _wheel && _wheel.wheelTo(nowVal || 0);
            }
            return false;
        },
        myValueChange() {
            return false;
        }
    }) ],
    mounted () {
        this._initCom();
    },
    watch: {
        /**
         * watch是否渲染列表
         * @param {Boolean} nowVal 是否初始化列表新的值
         * @param {Boolean} oldVal 是否初始化列表旧的值
         */
        isInit () {
            const _that = this;
            // 防止元素还没加载到页面上的时候去初始化了
            _that._stopEmit();
            _that._timer = setTimeout(() => {
                _that._timer = undefined;
                _that._initCom();
            }, 0);
        },
        /**
         * watch列表数据的变化
         */
        list () {
            const _that = this;
            const _wheel = _that.wheel;
            if (_wheel) {
                _that._stopEmit();
                _that._timer = setTimeout(() => {
                    _that._timer = undefined;
                    _that._resetCom();
                    _that._emitInitData();
                }, 0);
            } else {
                _that._initCom();
            }
        }
    },
    methods: {
        /**
         * 初始化组件
         */
        _initCom () {
            const _that = this;
            if (_that.isInit) {
                _that.$nextTick(() => {
                    const _wheelEl = _that.$refs && _that.$refs['hook_wheel'];
                    _that._stopEmit();
                    _that._timer = setTimeout(() => {
                        _that._timer = undefined;
                        _wheelEl && _that._initWheel(_wheelEl);
                        _that.initState = _that.list && _that.list.length > 0;
                    }, 20);
                });
            }
        },
        _stopEmit() {
            const _that = this;
            if (_that._timer !== undefined) {
                clearTimeout(_that._timer);
            }
        },
        /**
         * 初化时提交事件
         */
        _emitInitData() {
            const _that = this;
            _that._stopEmit();
            _that._timer = setTimeout(() => {
                _that._timer = undefined;
                _that._emitData();
            }, 20);
        },
        /**
         * 重置组件
         */
        _resetCom () {
            const _that = this;
            _that.initState = _that.list && _that.list.length > 0;
            const _wheel = _that.wheel;
            if (_wheel) {
                _wheel.refresh();
                _wheel.wheelTo(_that.activeIndex || 0);
            } else {
                _that._initWheel();
            }
        },
        /**
         * 初始化滚动
         * @param {HTMLElement} el 滚动元素的root节点对象
         */
        _initWheel () {
            const _that = this;
            if (!_that.wheel) {
                const _wheelEl = _that.$refs && _that.$refs['hook_wheel'];
                if (_wheelEl) {
                    const _opts = {
                        selectedIndex: _that.myActiveIndex || 0,
                        wheelEl: '.nu_wheel-scroll',
                        wheelItemEl: '.nu_wheel-item',
                        activeCls: 'nu_active', // 活动项的Class名
                        visibleCls: 'nu_visible' // 显示项的Class名
                    };
                    _that.wheel = new Wheel(_wheelEl, _opts);
                    _that._initListener();
                    if (_opts.selectedIndex === 0) { // 防止默认第一个元素取不到数据的问题
                        _that._emitInitData();
                    }
                }
            }
        },
        /**
         * 获取展示的文案名称
         * @param {String} item 列表项
         * @param {String} prefix 前缀
         * @param {String} suffix 后缀
         * @returns {String} 返回展示的文案名称
         */
        _getName (item, prefix, suffix) {
            const _that = this;
            let _name = callFn(_that.filterName, [item, {
                prefix,
                suffix,
                index: _that.index,
                activeIndex: _that.activeIndex
            }]);
            if (typeof _name === 'undefined') {
                _name = (prefix || '') + item + (suffix || '');
            }
            return _name;
        },
        /**
         * 注册监听器
         */
        _initListener () {
            const _that = this;
            [{
                type: 'scrollStart',
                data: 'start' // 开始滚动状态
            }, {
                type: 'scroll',
                data: 'rolling' // 滚动状态
            }, {
                type: 'scrollEnd' // 滚动结束
            }].forEach((evt) => { // 注册监听事件
                const _type = evt.type;
                _that.wheel.on(_type, () => {
                    if (_type === 'scrollEnd') {
                        _that._emitData();
                    } else {
                        const _index = (_that.wheel && _that.wheel.getSelectedIndex()) || 0;
                        if (_that._isSelect !== _index) {
                            _that.$emit('stateChange', evt.data);
                        }
                    }
                });
            });
        },
        /**
         * 发送数据给父组件
         */
        _emitData () {
            const _that = this;
            if (_that.isInit) {
                if (_that.initState) {
                    const _index = (_that.wheel && _that.wheel.getSelectedIndex()) || 0;
                    let _data = (_that.list && _that.list[_index]);
                    if (_that._isSelect !== 'number' || _that._isSelect !== _index || diffData(_that._isSelectData, _data)) {
                        _that._isSelect = _index;
                        _that._isSelectData = _data;
                        if (_that.myActiveIndex !== _index) {
                            _that.myActiveIndex = _index;
                            _that.$emit('update:activeIndex', _index);
                        }
                        _that.$emit('select', {
                            data: _data || {},
                            prefix: _that.prefix || '',
                            suffix: _that.suffix || ''
                        });
                    }
                }
                // 结束状态
                _that.$emit('stateChange', 'end');
            }
        }
    }
};
</script>

<style lang="scss">
@import '../../../_assets/style/_iconFont.scss';
@import '../../../_assets/style/_var.scss';
@import '../../../_assets/style/_mixin.scss';

.nus_wheel {
    @include flexFix();
    text-align: center;
    position: relative;
    user-select: none;
    box-sizing: border-box;
    height: 175px;
    border-color: $nuwheel-br-color;
    color: $nuwheel-color;
    cursor: default;
    *,::after,::before{
        border-color: inherit;
    }
    .nu_active {
        color: $nuwheel-active-color;
    }
    .nu_wheel-wrap {
        position: relative;
        width: 100%;
        height: 100%;
        overflow: hidden;
        mask-box-image: linear-gradient(to bottom, transparent, transparent 5%, #fff 20%, #fff 80%, transparent 95%, transparent);
        mask-box-image: linear-gradient(to top, transparent, transparent 5%, #fff 20%, #fff 80%, transparent 95%, transparent);
    }
    .nu_wheel-rule,.nu_wheel-scroll {
        margin: 0;
        padding: 0;
        width: 100%;
        height: $nuwheel-height;
        line-height: $nuwheel-height;
        position: absolute;
        left: 0;
        top: 50%;
        margin-top: -18px;
    }
    .nu_wheel-rule-ft {
        z-index: 2;
        pointer-events: none;
        &:before, &:after {
            content: '\20';
            border: {
                top-style: solid;
                top-width: 1px;
            }
            transform: scaleY(0.5);
            position: absolute;
            height: 0;
            left: 0;
            right: 0;
        }
        &:before {
            top: 0;
        }
        &:after {
            bottom: 0;
        }
    }
    .nu_wheel-scroll {
        z-index: 1;
        transform-style: preserve-3d;
        transform: perspective(1000px) rotateY(0deg) rotateX(0deg);
    }
    .nu_wheel-item {
        position: absolute;
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden;
        backface-visibility: hidden;
        visibility: hidden;
        list-style: none;
        width: 100%;
        height: 100%;
        padding: 0 8px;
        &.nu_active, &.nu_visible {
            visibility: visible;
        }
    }
}
</style>
