项目中要实现下图效果
在这里插入图片描述
说明:效果二和效果三是说明不同宽度达到的组件效果

css实现宽度自定义居中

通过elementUI API中发现没有暴露轮播图卡片化的自定义的宽度,通过查看样式得知是固定的50%的宽度,那么要实现修改宽度可以进行样式覆盖代码如下

.el-carousel__container {
	.el-carousel__item--card {
		width: 850px !important;
		background: #fff;
	}
	.el-carousel__item {
		width: 850px !important;
		background-color: #d3dce6;
	}
	.el-carousel__item--card.is-active {
		z-index: 2;
		position: absolute;
		left: 50%;
		transform: translate(-50%, 0px) !important;
	}
}

但是这样看上去切换动画效果有些奇怪,且这样并不能满足项目对效果三的需求,所以对elementUI的carousel组件进行修改
具体操作如下
首先找到:node_modules —— elementui —— packages —— carousel,把整个文件夹复制出来,单独在项目中另行引入组件,不影响其他模块再次使用这个carousel组件

实现效果三的完整代码

说明:main.vue动的不多(也可能没动,忘记了),主要修改的是item.vue文件,且没有删除使用非卡片功能代码可以直接使用这个组件实现异形非卡片功能轮播图。
页面引入

import carousel from './components/carousel/src/main';
import carouselItem from './components/carousel/src/item';
export default {
	name: 'Login',
	components: {
		carousel,
		carouselItem
	},
};

页面直接使用:(暴露自定义宽度字段:cardwidth

<carousel class="service-advantage" :interval="40000000" type="card" height="200px"&gt;
	<carousel-item v-for="(item,index) in 5" :key="`a3${index}`" cardwidth="650px"&gt;
		<h3 class="medium"&gt;{{ item }}</h3&gt;
	</carousel-item&gt;
</carousel>

具体对组件进行修改的完整代码
main.vue

<template>
	<div :class="carouselClasses" @mouseenter.stop="handleMouseEnter" @mouseleave.stop="handleMouseLeave">
		<div class="el-carousel__container" :style="{ height: height }">
			<transition v-if="arrowDisplay" name="carousel-arrow-left">
				<button type="button" v-show="(arrow === 'always' || hover) &amp;&amp; (loop || activeIndex > 0)"
					@mouseenter="handleButtonEnter('left')" @mouseleave="handleButtonLeave"
					@click.stop="throttledArrowClick(activeIndex - 1)" class="el-carousel__arrow el-carousel__arrow--left">
					<i class="el-icon-arrow-left"></i>
				</button>
			</transition>
			<transition v-if="arrowDisplay" name="carousel-arrow-right">
				<button type="button" v-show="(arrow === 'always' || hover) &amp;&amp; (loop || activeIndex < items.length - 1)"
					@mouseenter="handleButtonEnter('right')" @mouseleave="handleButtonLeave"
					@click.stop="throttledArrowClick(activeIndex + 1)" class="el-carousel__arrow el-carousel__arrow--right">
					<i class="el-icon-arrow-right"></i>
				</button>
			</transition>
			<slot></slot>
		</div>
		<ul v-if="indicatorPosition !== 'none'" :class="indicatorsClasses">
			<li v-for="(item, index) in items" :key="index" :class="[
          'el-carousel__indicator',
          'el-carousel__indicator--' + direction,
          { 'is-active': index === activeIndex }]" @mouseenter="throttledIndicatorHover(index)"
				@click.stop="handleIndicatorClick(index)">
				<button class="el-carousel__button">
					<span v-if="hasLabel">{{ item.label }}</span>
				</button>
			</li>
		</ul>
	</div>
</template>

<script>
import throttle from 'throttle-debounce/throttle';
import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event';

export default {
	name: 'ElCarousel',
	props: {
		initialIndex: {
			type: Number,
			default: 0
		},
		height: String,
		trigger: {
			type: String,
			default: 'hover'
		},
		autoplay: {
			type: Boolean,
			default: true
		},
		interval: {
			type: Number,
			default: 3000
		},
		indicatorPosition: String,
		indicator: {
			type: Boolean,
			default: true
		},
		arrow: {
			type: String,
			default: 'hover'
		},
		type: String,
		loop: {
			type: Boolean,
			default: true
		},
		direction: {
			type: String,
			default: 'horizontal',
			validator(val) {
				return ['horizontal', 'vertical'].indexOf(val) !== -1;
			}
		}
	},

	data() {
		return {
			items: [],
			activeIndex: -1,
			containerWidth: 0,
			timer: null,
			hover: false
		};
	},

	computed: {
		arrowDisplay() {
			return this.arrow !== 'never' &amp;&amp; this.direction !== 'vertical';
		},

		hasLabel() {
			return this.items.some((item) => item.label.toString().length > 0);
		},

		carouselClasses() {
			const classes = ['my-el-carousel', 'el-carousel--' + this.direction];
			if (this.type === 'card') {
				classes.push('el-carousel--card');
			}
			return classes;
		},

		indicatorsClasses() {
			const classes = ['el-carousel__indicators', 'el-carousel__indicators--' + this.direction];
			if (this.hasLabel) {
				classes.push('el-carousel__indicators--labels');
			}
			if (this.indicatorPosition === 'outside' || this.type === 'card') {
				classes.push('el-carousel__indicators--outside');
			}
			return classes;
		}
	},

	watch: {
		items(val) {
			if (val.length > 0) this.setActiveItem(this.initialIndex);
		},

		activeIndex(val, oldVal) {
			this.resetItemPosition(oldVal);
			if (oldVal > -1) {
				this.$emit('change', val, oldVal);
			}
		},

		autoplay(val) {
			val ? this.startTimer() : this.pauseTimer();
		},

		loop() {
			this.setActiveItem(this.activeIndex);
		}
	},

	methods: {
		handleMouseEnter() {
			this.hover = true;
			this.pauseTimer();
		},

		handleMouseLeave() {
			this.hover = false;
			this.startTimer();
		},

		itemInStage(item, index) {
			const length = this.items.length;
			if (
				(index === length - 1 &amp;&amp; item.inStage &amp;&amp; this.items[0].active) ||
				(item.inStage &amp;&amp; this.items[index + 1] && this.items[index + 1].active)
			) {
				return 'left';
			} else if (
				(index === 0 && item.inStage && this.items[length - 1].active) ||
				(item.inStage && this.items[index - 1] && this.items[index - 1].active)
			) {
				return 'right';
			}
			return false;
		},

		handleButtonEnter(arrow) {
			if (this.direction === 'vertical') return;
			this.items.forEach((item, index) => {
				if (arrow === this.itemInStage(item, index)) {
					item.hover = true;
				}
			});
		},

		handleButtonLeave() {
			if (this.direction === 'vertical') return;
			this.items.forEach((item) => {
				item.hover = false;
			});
		},

		updateItems() {
			this.items = this.$children.filter((child) => child.$options.name === 'ElCarouselItem');
		},

		resetItemPosition(oldIndex) {
			this.items.forEach((item, index) => {
				item.translateItem(index, this.activeIndex, oldIndex);
			});
		},

		playSlides() {
			if (this.activeIndex < this.items.length - 1) {
				this.activeIndex++;
			} else if (this.loop) {
				this.activeIndex = 0;
			}
		},

		pauseTimer() {
			if (this.timer) {
				clearInterval(this.timer);
				this.timer = null;
			}
		},

		startTimer() {
			if (this.interval <= 0 || !this.autoplay || this.timer) return;
			this.timer = setInterval(this.playSlides, this.interval);
		},

		setActiveItem(index) {
			if (typeof index === 'string') {
				const filteredItems = this.items.filter((item) => item.name === index);
				if (filteredItems.length > 0) {
					index = this.items.indexOf(filteredItems[0]);
				}
			}
			index = Number(index);
			if (isNaN(index) || index !== Math.floor(index)) {
				console.warn('[Element Warn][Carousel]index must be an integer.');
				return;
			}
			let length = this.items.length;
			const oldIndex = this.activeIndex;
			if (index < 0) {
				this.activeIndex = this.loop ? length - 1 : 0;
			} else if (index >= length) {
				this.activeIndex = this.loop ? 0 : length - 1;
			} else {
				this.activeIndex = index;
			}
			if (oldIndex === this.activeIndex) {
				this.resetItemPosition(oldIndex);
			}
		},

		prev() {
			this.setActiveItem(this.activeIndex - 1);
		},

		next() {
			this.setActiveItem(this.activeIndex + 1);
		},

		handleIndicatorClick(index) {
			this.activeIndex = index;
		},

		handleIndicatorHover(index) {
			if (this.trigger === 'hover' && index !== this.activeIndex) {
				this.activeIndex = index;
			}
		}
	},

	created() {
		this.throttledArrowClick = throttle(300, true, (index) => {
			this.setActiveItem(index);
		});
		this.throttledIndicatorHover = throttle(300, (index) => {
			this.handleIndicatorHover(index);
		});
	},

	mounted() {
		this.updateItems();
		this.$nextTick(() => {
			addResizeListener(this.$el, this.resetItemPosition);
			if (this.initialIndex < this.items.length && this.initialIndex >= 0) {
				this.activeIndex = this.initialIndex;
			}
			this.startTimer();
		});
	},

	beforeDestroy() {
		if (this.$el) removeResizeListener(this.$el, this.resetItemPosition);
		this.pauseTimer();
	}
};
</script>

item.vue

<template>
	<div v-show="ready" class="el-carousel__item" :class="{
      'is-active': active,
      'el-carousel__item--card': $parent.type === 'card',
      'is-in-stage': inStage,
      'is-hover': hover,
      'is-animating': animating
    }" @click="handleItemClick" :style="itemStyle">
		<div v-if="$parent.type === 'card'" v-show="!active" class="el-carousel__mask">
		</div>
		<slot></slot>
	</div>
</template>

<script>
import { autoprefixer } from 'element-ui/src/utils/util';
// const CARD_SCALE = 0.6;
// 缩放比例
const CARD_SCALE = 0.8;
export default {
	name: 'ElCarouselItem',
	props: {
		name: String,
		label: {
			type: [String, Number],
			default: ''
		},
		// 自定义卡片宽度
		cardwidth: {
			type: [String, Number],
			default: '50%'
		}
	},
	data() {
		return {
			hover: false,
			translate: 0,
			scale: 1,
			active: false,
			ready: false,
			inStage: false,
			animating: false,
			parentOffsetWidth: 0 //当前元素元素宽度
		};
	},

	methods: {
		processIndex(index, activeIndex, length) {
			if (activeIndex === 0 && index === length - 1) {
				return -1;
			} else if (activeIndex === length - 1 && index === 0) {
				return length;
			} else if (index < activeIndex - 1 && activeIndex - index >= length / 2) {
				return length + 1;
			} else if (index > activeIndex + 1 && index - activeIndex >= length / 2) {
				return -2;
			}
			return index;
		},

		// 卡片化的carousel重新计算位移
		calcCardTranslate(index, activeIndex) {
			const parentWidth = this.$parent.$el.offsetWidth;
			this.parentOffsetWidth = parentWidth;
			if (this.inStage) {
				let diffWid = (parseInt(this.cardwidth) - this.parentOffsetWidth / 2) / 1.1;
				let changWid = (parentWidth * ((2 - CARD_SCALE) * (index - activeIndex) + 1)) / 4;
				//270是基础值,可根据设计图进行修改
				let moveWid =
					changWid > 0
						? changWid === 360
							? changWid
							: this.cardwidth == '50%'
							? changWid + 270
							: changWid + 270 + diffWid
						: this.cardwidth == '50%'
						? changWid - 270
						: changWid - 270 - diffWid;
				return moveWid;
			} else if (index < activeIndex) {
				return (-(1 + CARD_SCALE) * parentWidth) / 4;
			} else {
				return ((3 + CARD_SCALE) * parentWidth) / 4;
			}
		},

		calcTranslate(index, activeIndex, isVertical) {
			const distance = this.$parent.$el[isVertical ? 'offsetHeight' : 'offsetWidth'];
			return distance * (index - activeIndex);
		},

		translateItem(index, activeIndex, oldIndex) {
			const parentType = this.$parent.type;
			const parentDirection = this.parentDirection;
			const length = this.$parent.items.length;
			if (parentType !== 'card' && oldIndex !== undefined) {
				this.animating = index === activeIndex || index === oldIndex;
			}
			if (index !== activeIndex && length > 2 && this.$parent.loop) {
				index = this.processIndex(index, activeIndex, length);
			}
			if (parentType === 'card') {
				if (parentDirection === 'vertical') {
					console.warn('[Element Warn][Carousel]vertical direction is not supported in card mode');
				}
				this.inStage = Math.round(Math.abs(index - activeIndex)) <= 1;
				this.active = index === activeIndex;
				this.translate = this.calcCardTranslate(index, activeIndex);
				this.scale = this.active ? 1 : CARD_SCALE;
			} else {
				this.active = index === activeIndex;
				const isVertical = parentDirection === 'vertical';
				this.translate = this.calcTranslate(index, activeIndex, isVertical);
			}
			this.ready = true;
		},

		handleItemClick() {
			const parent = this.$parent;
			if (parent && parent.type === 'card') {
				const index = parent.items.indexOf(this);
				parent.setActiveItem(index);
			}
		}
	},

	computed: {
		parentDirection() {
			return this.$parent.direction;
		},

		itemStyle() {
			const translateType = this.parentDirection === 'vertical' ? 'translateY' : 'translateX';
			const value = `${translateType}(${this.translate}px) scale(${this.scale})`;
			// 添加样式,实现自定义卡片宽度
			const style = {
				width: this.cardwidth,
				transform: value,
				left:
					this.cardwidth === '50%'
						? 0
						: `${-(parseInt(this.cardwidth) - this.parentOffsetWidth / 2) / 2}px`
			};
			return autoprefixer(style);
		}
	},

	created() {
		this.$parent && this.$parent.updateItems();
	},

	destroyed() {
		this.$parent && this.$parent.updateItems();
	}
};
</script>
<style scoped>
.el-carousel__item--card {
	border-radius: 12px;
	background: #fff;
}
</style>

原文地址:https://blog.csdn.net/zuoyiran520081/article/details/120866587

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_18833.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注