<template>
	<view class="y-tab__pane" :data-index="index" :class="[uniquePaneClass, paneClass]" :style="[paneStyle]"
		@touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd">
		<!-- 渲染过的则不再渲染，未渲染的根据激活状态进行渲染 -->
		<view class="y-tab__pane--wrap" v-if="rendered ? true : active">
			<slot></slot>
		</view>
	</view>
</template>

<script>
import { isNull, toClass, getUid } from '../js/uitls';
import { touchMixin } from '../js/touchMixin';
export default {
	name: 'yTab',
	mixins: [touchMixin],
	options: {
		// 微信小程序中 options 选项
		styleIsolation: 'apply-shared', // [微信小程序] 启动样式隔离。当使用页面自定义组件，希望父组件影响子组件样式时可能需要配置。具体配置选项参见：微信小程序自定义组件的样式
		virtualHost: true // [微信小程序、支付宝小程序（默认值为 true）] 将自定义节点设置成虚拟的，更加接近Vue组件的表现。我们不希望自定义组件的这个节点本身可以设置样式、响应 flex 布局等，而是希望自定义组件内部的第一层节点能够响应 flex 布局或者样式由自定义组件本身完全决定
		// 微信（可以使用virtualHost配置）/QQ/百度/字节跳动这四家小程序，自定义组件在渲染时会比App/H5端多一级节点，导致flex无效，是否考虑在组件上增加class控制
	},
	props: {
		title: String, // 标题
		disabled: Boolean, // 是否禁用标签
		dot: Boolean, // 是否在标题右上角显示小红点
		badge: {
			type: [Number, String],
			default: ''
		}, // 图标右上角徽标的内容
		// 徽标数最大数字限制,超过这个数字将变成badgeMaxCount+,如果传空字符串则不设置
		badgeMaxCount: {
			type: [Number, String],
			default: 99
		},
		name: [Number, String], // 标签名称，作为匹配的标识符
		titleStyle: Object, //	自定义标题样式
		titleClass: String, //	自定义标题类名
		iconType: String, //图标图案，为uniapp扩展组件（uni-ui）下的uni-icons的type值，customPrefix用法等同
		iconSize: {
			type: Number,
			default: 16
		}, //图标大小
		customPrefix: String, //自定义图标
		imageSrc: String, //图片路径
		imageMode: {
			type: String,
			default: 'scaleToFill',
			validator(value) {
				return [
					'scaleToFill',
					'aspectFit',
					'aspectFill',
					'widthFix',
					'heightFix',
					'top',
					'bottom',
					'center',
					'left',
					'right',
					'top left',
					'top right',
					'bottom left',
					'bottom right'
				].includes(value);
			}
		}, //图片裁剪、缩放的模式，为uniapp内置组件->媒体组件—>image下的mode值
		position: {
			type: String,
			default: 'right',
			validator(value) {
				return ['top', 'bottom', 'left', 'right'].includes(value);
			}
		} //如果存在图片或图标，标题围绕它们的位置
	},
	data() {
		return {
			__isUnmounted: false,
			index: -1, //内容卡片对应的下标
			parent: null, //父元素实例
			active: false, //是否为激活状态
			rendered: false, //是否渲染过
			swipeable: false, //是否开启手势滑动切换
			paneStyle: null, //内容样式
			scrollspy: false, //是否为滚动导航模式
			paneObserver: null, //pane交叉观察器
			isDisjoint: false //当前pane是否与参照节点布局区域相离
		};
	},
	computed: {
		computedName() {
			return !isNull(this.name) ? this.name : this.index;
		},
		// test
		innerStyle() {
			return {
				position: 'absolute',
				width: "100%",
				height: "100%",
				transform: `translate(${100 * this.index}%, 0px) translateZ(0px)`
			}
		},
		// 保证唯一的样式
		uniquePaneClass() {
			return 'y-tab__pane' + getUid()
		},
		// 内容class
		paneClass() {
			return toClass({ 'is-active': this.active, 'is-scrollspy': this.scrollspy });
		},
	},
	watch: {
		$props: {
			deep: true,
			// immediate: true,
			handler(newValue, oldValue) {
				// 触发导航变化事件
				if (this.parent) {
					this.parent.updateTab({
						newValue: { ...newValue, badge: this.formatBadge() },
						oldValue: oldValue && { ...oldValue },
						index: this.index
					});
				}
			}
		}
	},
	created() {
		this.parent = this.getParent();
		if (this.parent) {
			this.parent.children.push(this);
			this.parent.putTab({ newValue: { ...this.$props, badge: this.formatBadge() } });
		}
	},
	mounted() {
		// this.$nextTick(() => {
		// 	this.observePane();
		// });
	},
	// #ifndef VUE3
	destroyed() {
		if (this.__isUnmounted) return;
		this.unInit();
	},
	// #endif
	// #ifdef VUE3
	unmounted() {
		this.__isUnmounted = true;
		this.unInit();
	},
	// #endif
	methods: {
		// 徽标格式化
		formatBadge() {
			if (!isNull(this.badge) && !isNull(this.badgeMaxCount) && this.badge > this.badgeMaxCount) {
				return this.badgeMaxCount + '+';
			} else {
				return this.badge
			}
		},
		// 获取查询节点信息的对象
		getSelectorQuery() {
			let query = null;
			// #ifdef MP-ALIPAY
			query = uni.createSelectorQuery();
			// #endif
			// #ifndef MP-ALIPAY
			query = uni.createSelectorQuery().in(this);
			// #endif
			return query;
		},
		// 获取元素位置信息
		getRect() {
			return new Promise((resolve, reject) => {
				this.getSelectorQuery()
					.select(`.${this.uniquePaneClass}`)
					.boundingClientRect()
					.exec(rect => {
						console.log(rect);
						resolve(rect[0] || {});
					});
			});
		},
		// 卸载组件的处理
		unInit() {
			this.disconnectObserver('paneObserver'); //销毁观察器
			if (this.parent) {
				const index = this.parent.children.findIndex(item => item === this);
				this.parent.children.splice(index, 1);
				this.parent.tabs.splice(index, 1);
				this.parent.tabRects.splice(index, 1);
			}
		},
		//获取父元素实例
		getParent(name = 'yTabs') {
			let parent = this.$parent;
			let parentName = parent.$options.name;
			while (parentName !== name) {
				parent = parent.$parent;
				if (!parent) return false;
				parentName = parent.$options.name;
			}
			return parent;
		},
		// 断掉观察，释放资源
		disconnectObserver(observerName) {
			const observer = this[observerName];
			observer && observer.disconnect();
		},
		// 观察 - 标签内容滚动时定位标签项
		async observePane(top) {
			if (!this.scrollspy) return //非滚动导航时不创建观察器
			this.disconnectObserver('paneObserver');
			const paneObserver = uni.createIntersectionObserver(this, { thresholds: [0, 1] });


			// 注意：如果是区域滚动，pane区域随着页面滚动了一部分，那么y-tabs__content的top就会变化，导致交互区域位置不准确
			// 最好不要有这种交互布局，不像Android有嵌套滑动机制，页面滑动到底后无法将事件分发给scroll-view

			paneObserver.relativeToViewport({ top: -top }); // 到屏幕顶部的高度时触发
			// 不能观察根节点 unk-vendors.js:14596 [system] Node .y-tab__pane9 is not found. Intersection observer will not trigger.
			paneObserver.observe(`.${this.uniquePaneClass} .y-tab__pane--wrap`, res => {
				// console.log('res:', this.title, res);
				// 如果目标节点布局区域小于参照节点布局区域top,则说明目标节点在参照节点布局区域之上,intersectionRatio小于等于0则说明两者不相交了
				this.isDisjoint = res.intersectionRatio <= 0 && res.boundingClientRect.top < res.relativeRect.top;

				// 标签栏点击时触发的滚动不允许设置激活下标
				if (!this.parent.lockedScrollspy) this.parent.setActivedIndexToScroll();
			});
			this.paneObserver = paneObserver;
		},
	}
};
</script>

<style lang="less" scoped>
@import url('../css/index.less');
</style>