| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 | <template>	<view		class="u-loading-icon"		:style="[$u.addStyle(customStyle)]"		:class="[vertical && 'u-loading-icon--vertical']"		v-if="show"	>		<view			v-if="!webviewHide"			class="u-loading-icon__spinner"			:class="[`u-loading-icon__spinner--${mode}`]"			ref="ani"			:style="{				color: color,				width: $u.addUnit(size),				height: $u.addUnit(size),				borderTopColor: color,				borderBottomColor: otherBorderColor,				borderLeftColor: otherBorderColor,				borderRightColor: otherBorderColor,				'animation-duration': `${duration}ms`,				'animation-timing-function': mode === 'semicircle' || mode === 'circle' ? timingFunction : ''			}"		>			<block v-if="mode === 'spinner'">				<!-- #ifndef APP-NVUE -->				<view					v-for="(item, index) in array12"					:key="index"					class="u-loading-icon__dot"				>				</view>				<!-- #endif -->				<!-- #ifdef APP-NVUE -->				<!-- 此组件内部图标部分无法设置宽高,即使通过width和height配置了也无效 -->				<loading-indicator					v-if="!webviewHide"					class="u-loading-indicator"					:animating="true"					:style="{						color: color,						width: $u.addUnit(size),						height: $u.addUnit(size)					}"				/>				<!-- #endif -->			</block>		</view>		<text			v-if="text"			class="u-loading-icon__text"			:style="{				fontSize: $u.addUnit(textSize),				color: textColor,			}"		>{{text}}</text>	</view></template><script>	import props from './props.js';	// #ifdef APP-NVUE	const animation = weex.requireModule('animation');	// #endif	/**	 * loading 加载动画	 * @description 警此组件为一个小动画,目前用在uView的loadmore加载更多和switch开关等组件的正在加载状态场景。	 * @tutorial https://www.uviewui.com/components/loading.html	 * @property {Boolean}			show			是否显示组件  (默认 true)	 * @property {String}			color			动画活动区域的颜色,只对 mode = flower 模式有效(默认color['u-tips-color'])	 * @property {String}			textColor		提示文本的颜色(默认color['u-tips-color'])	 * @property {Boolean}			vertical		文字和图标是否垂直排列 (默认 false )	 * @property {String}			mode			模式选择,见官网说明(默认 'circle' )	 * @property {String | Number}	size			加载图标的大小,单位px (默认 24 )	 * @property {String | Number}	textSize		文字大小(默认 15 )	 * @property {String | Number}	text			文字内容 	 * @property {String}			timingFunction	动画模式 (默认 'ease-in-out' )	 * @property {String | Number}	duration		动画执行周期时间(默认 1200)	 * @property {String}			inactiveColor	mode=circle时的暗边颜色 	 * @property {Object}			customStyle		定义需要用到的外部样式	 * @example <u-loading mode="circle"></u-loading>	 */	export default {		name: 'u-loading-icon',		mixins: [uni.$u.mpMixin, uni.$u.mixin, props],		data() {			return {				// Array.form可以通过一个伪数组对象创建指定长度的数组				// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/from				array12: Array.from({					length: 12				}),				// 这里需要设置默认值为360,否则在安卓nvue上,会延迟一个duration周期后才执行				// 在iOS nvue上,则会一开始默认执行两个周期的动画				aniAngel: 360, // 动画旋转角度				webviewHide: false, // 监听webview的状态,如果隐藏了页面,则停止动画,以免性能消耗				loading: false, // 是否运行中,针对nvue使用			}		},		computed: {			// 当为circle类型时,给其另外三边设置一个更轻一些的颜色			// 之所以需要这么做的原因是,比如父组件传了color为红色,那么需要另外的三个边为浅红色			// 而不能是固定的某一个其他颜色(因为这个固定的颜色可能浅蓝,导致效果没有那么细腻良好)			otherBorderColor() {				const lightColor = uni.$u.colorGradient(this.color, '#ffffff', 100)[80]				if (this.mode === 'circle') {					return this.inactiveColor ? this.inactiveColor : lightColor				} else {					return 'transparent'				}				// return this.mode === 'circle' ? this.inactiveColor ? this.inactiveColor : lightColor : 'transparent'			}		},		watch: {			show(n) {				// nvue中,show为true,且为非loading状态,就重新执行动画模块				// #ifdef APP-NVUE				if (n && !this.loading) {					setTimeout(() => {						this.startAnimate()					}, 30)				}				// #endif			}		},		mounted() {			this.init()		},		methods: {			init() {				setTimeout(() => {					// #ifdef APP-NVUE					this.show && this.nvueAnimate()					// #endif					// #ifdef APP-PLUS 					this.show && this.addEventListenerToWebview()					// #endif				}, 20)			},			// 监听webview的显示与隐藏			addEventListenerToWebview() {				// webview的堆栈				const pages = getCurrentPages()				// 当前页面				const page = pages[pages.length - 1]				// 当前页面的webview实例				const currentWebview = page.$getAppWebview()				// 监听webview的显示与隐藏,从而停止或者开始动画(为了性能)				currentWebview.addEventListener('hide', () => {					this.webviewHide = true				})				currentWebview.addEventListener('show', () => {					this.webviewHide = false				})			},			// #ifdef APP-NVUE			nvueAnimate() {				// nvue下,非spinner类型时才需要旋转,因为nvue的spinner类型,使用了weex的				// loading-indicator组件,自带旋转功能				this.mode !== 'spinner' && this.startAnimate()			},			// 执行nvue的animate模块动画			startAnimate() {				this.loading = true				const ani = this.$refs.ani				if (!ani) return				animation.transition(ani, {					// 进行角度旋转					styles: {						transform: `rotate(${this.aniAngel}deg)`,						transformOrigin: 'center center'					},					duration: this.duration,					timingFunction: this.timingFunction,					// delay: 10				}, () => {					// 每次增加360deg,为了让其重新旋转一周					this.aniAngel += 360					// 动画结束后,继续循环执行动画,需要同时判断webviewHide变量					// nvue安卓,页面隐藏后依然会继续执行startAnimate方法					this.show && !this.webviewHide ? this.startAnimate() : this.loading = false				})			}			// #endif		}	}</script><style lang="scss" scoped>	@import "../../libs/css/components.scss";	$u-loading-icon-color: #c8c9cc !default;	$u-loading-icon-text-margin-left:4px !default;	$u-loading-icon-text-color:$u-content-color !default;	$u-loading-icon-text-font-size:14px !default;	$u-loading-icon-text-line-height:20px !default;	$u-loading-width:30px !default;	$u-loading-height:30px !default;	$u-loading-max-width:100% !default;	$u-loading-max-height:100% !default;	$u-loading-semicircle-border-width: 2px !default;	$u-loading-semicircle-border-color:transparent !default;	$u-loading-semicircle-border-top-right-radius: 100px !default;	$u-loading-semicircle-border-top-left-radius: 100px !default;	$u-loading-semicircle-border-bottom-left-radius: 100px !default;	$u-loading-semicircle-border-bottom-right-radiu: 100px !default;	$u-loading-semicircle-border-style: solid !default;	$u-loading-circle-border-top-right-radius: 100px !default;	$u-loading-circle-border-top-left-radius: 100px !default;	$u-loading-circle-border-bottom-left-radius: 100px !default;	$u-loading-circle-border-bottom-right-radiu: 100px !default;	$u-loading-circle-border-width:2px !default;	$u-loading-circle-border-top-color:#e5e5e5 !default;	$u-loading-circle-border-right-color:$u-loading-circle-border-top-color !default;	$u-loading-circle-border-bottom-color:$u-loading-circle-border-top-color !default;	$u-loading-circle-border-left-color:$u-loading-circle-border-top-color !default;	$u-loading-circle-border-style:solid !default;	$u-loading-icon-host-font-size:0px !default;	$u-loading-icon-host-line-height:1 !default;	$u-loading-icon-vertical-margin:6px 0 0 !default;	$u-loading-icon-dot-top:0 !default;	$u-loading-icon-dot-left:0 !default;	$u-loading-icon-dot-width:100% !default;	$u-loading-icon-dot-height:100% !default;	$u-loading-icon-dot-before-width:2px !default;	$u-loading-icon-dot-before-height:25% !default;	$u-loading-icon-dot-before-margin:0 auto !default;	$u-loading-icon-dot-before-background-color:currentColor !default;	$u-loading-icon-dot-before-border-radius:40% !default;	.u-loading-icon {		/* #ifndef APP-NVUE */		// display: inline-flex;		/* #endif */		flex-direction: row;		align-items: center;		justify-content: center;		color: $u-loading-icon-color;		&__text {			margin-left: $u-loading-icon-text-margin-left;			color: $u-loading-icon-text-color;			font-size: $u-loading-icon-text-font-size;			line-height: $u-loading-icon-text-line-height;		}		&__spinner {			width: $u-loading-width;			height: $u-loading-height;			position: relative;			/* #ifndef APP-NVUE */			box-sizing: border-box;			max-width: $u-loading-max-width;			max-height: $u-loading-max-height;			animation: u-rotate 1s linear infinite;			/* #endif */		}		&__spinner--semicircle {			border-width: $u-loading-semicircle-border-width;			border-color: $u-loading-semicircle-border-color;			border-top-right-radius: $u-loading-semicircle-border-top-right-radius;			border-top-left-radius: $u-loading-semicircle-border-top-left-radius;			border-bottom-left-radius: $u-loading-semicircle-border-bottom-left-radius;			border-bottom-right-radius: $u-loading-semicircle-border-bottom-right-radiu;			border-style: $u-loading-semicircle-border-style;		}		&__spinner--circle {			border-top-right-radius: $u-loading-circle-border-top-right-radius;			border-top-left-radius: $u-loading-circle-border-top-left-radius;			border-bottom-left-radius: $u-loading-circle-border-bottom-left-radius;			border-bottom-right-radius: $u-loading-circle-border-bottom-right-radiu;			border-width: $u-loading-circle-border-width;			border-top-color: $u-loading-circle-border-top-color;			border-right-color: $u-loading-circle-border-right-color;			border-bottom-color: $u-loading-circle-border-bottom-color;			border-left-color: $u-loading-circle-border-left-color;			border-style: $u-loading-circle-border-style;		}		&--vertical {			flex-direction: column		}	}	/* #ifndef APP-NVUE */	:host {		font-size: $u-loading-icon-host-font-size;		line-height: $u-loading-icon-host-line-height;	}	.u-loading-icon {		&__spinner--spinner {			animation-timing-function: steps(12)		}		&__text:empty {			display: none		}		&--vertical &__text {			margin: $u-loading-icon-vertical-margin;			color: $u-content-color;		}		&__dot {			position: absolute;			top: $u-loading-icon-dot-top;			left: $u-loading-icon-dot-left;			width: $u-loading-icon-dot-width;			height: $u-loading-icon-dot-height;			&:before {				display: block;				width: $u-loading-icon-dot-before-width;				height: $u-loading-icon-dot-before-height;				margin: $u-loading-icon-dot-before-margin;				background-color: $u-loading-icon-dot-before-background-color;				border-radius: $u-loading-icon-dot-before-border-radius;				content: " "			}		}	}	@for $i from 1 through 12 {		.u-loading-icon__dot:nth-of-type(#{$i}) {			transform: rotate($i * 30deg);			opacity: 1 - 0.0625 * ($i - 1);		}	}	@keyframes u-rotate {		0% {			transform: rotate(0deg)		}		to {			transform: rotate(1turn)		}	}	/* #endif */</style>
 |