使用
<template>
<div id="app">
<span>前往搜索页</span>
<Carousel class="content">
<CarouselItem>
<div class="test1 test">1</div>
</CarouselItem>
<CarouselItem>
<div class="test2 test">2</div>
</CarouselItem>
<CarouselItem>
<div class="test3 test">3</div>
</CarouselItem>
<CarouselItem>
<div class="test4 test">4</div>
</CarouselItem>
<CarouselItem>
<div class="test5 test">5</div>
</CarouselItem>
<CarouselItem>
<div class="test2 test">6</div>
</CarouselItem>
<CarouselItem>
<div class="test3 test">7</div>
</CarouselItem>
</Carousel>
</div>
</template>
<script>
import Carousel from "./components/CarouselCloud/carousel"
import CarouselItem from './components/CarouselCloud/carousel-item'
export default {
components:{Carousel,CarouselItem},
data(){
return {
}
},
}
</script>
<style lang="less">
.content{
width: 90%;
}
.test{
width: 100%;
height:300px;
}
.test1{
background-color: antiquewhite;
}
.test2{
background-color: aqua;
}
.test3{
background: blueviolet;
}
.test4{
background: chocolate;
}
.test5{
background: aquamarine;
}
</style>
carsouel
<template>
<!-- 尼玛,很久之前写的代码竟然不认识了。。。 -->
<div v-cloak class="li-carousel"
:style="carouseStyles"
@mouseleave="setAutoplay"
@mouseenter="stop">
<div class="li-carousel-wrap">
<slot></slot>
<!-- 里面放的是所有的子项目 -->
</div>
<!-- 下方的标识 -->
<ul class="li-carousel-list">
<template v-if="this.sliderLength">
<li
v-for="n in this.sliderLength"
:class="[n===currentIndex?pre+'-active':'']"
@click="handleMove(n)"
@mouseenter="handleHoverMove(n)"
>
</li>
</template>
</ul>
</div>
</template>
<script>
const pre='li-carousel'
export default {
name:'li-carousel',
// 那这个属性那里能访问到
props:{
arrow:{
type:String,
default:'hover',
validator(value){
return ['hover','never','always'].includes(value)
}
},
// 切换箭头出现的方式
autoplay:{
type:Boolean,
default:false,
},
autoplaySpeed:{
type:Number,
default:2000,
},
loop:{
type:Boolean,
default:false,
},
easeing:{
type:String,
default:'ease'
},
// 动画效果
dots:{
type:String,
default:'inside',
validator(value){
return ['inside','outside','none']
}
},
// 下方缩略图的位置
radiusDot:{
type:Boolean,
default:false,
},
// 是否显示圆形显示器
trigger:{
type:String,
default:'click',
validator(value){
return ['click','hover'].includes(value)
}
},
// 指示器的触发方式
value:{
type:Number,
default:1,
},
height:{
type:Number,
default:300,
},
width:{
type:Number,
default:600,
},
transitionName:{
type:String,
default:'ease'
}
// 这里需要的是左右滑动的渐变值
},
data(){
return {
currentIndex:this.value,
// 当前的索引位置
sliderLength:0,
// 总的列表长度
currentTransitionName:this.transitionName,
// 将要变换的参数
pre:'li-carousel',
timer:null,
// 自动变化的定时器
allStyles:[],
// 初始的样式
computedStyles:[],
// 根据currentIndex调整后的数据
centerIndex:0,
// 初始的center数据的位置
centerStyle:{},
leftStyle:{},
leftOtherStyle:{},
rightStyle:{},
rightOtherStyle:{},
childWidth:0,
}
},
computed:{
arrowClasses(){
return[
{[`${pre}-`+'arrow'+`-${this.arrow}`]:this.arrow}
]
},
carouseStyles(){
return {
width:`${this.width}px`,
height:`${this.height}px`
}
}
},
methods:{
updateSlides(){
// 给每个子组件设置值
let index=1
this.sliderLength=0
// 这个变量必须重置,每一次重新计算的时候
const children=this.$children
if(children){
children.forEach((child)=>{
if(child.$options.name=='li-carousel-item'){
child.index=index++
child.currentIndex=this.currentIndex
this.sliderLength++
if(child.width&&!this.childWidth){
this.childWidth=child.width
}
this.getStyle(this.sliderLength)
// 这里要求出所有的样式
}else{
console.log('不是想要的子元素,不进行操作')
}
})
console.log('父组件在更新数据')
}else{
console.log('没有子元素')
}
this.setComputedStyles(this.currentIndex)
},
// 核心是这个函数
setComputedStyles(index){
this.currentIndex=index
let style=new Array(this.allStyles.length)
if(index==1){
// 老是写一个等号。。。。。。。
style[0]=this.centerStyle
style[1]=this.rightStyle
style[this.allStyles.length-1]=this.leftStyle
}else if(index==this.allStyles.length){
style[this.allStyles.length-1]=this.centerStyle
style[index-2]=this.leftStyle
style[0]=this.rightStyle
}else{
style[index-2]=this.leftStyle
style[index-1]=this.centerStyle
style[index]=this.rightStyle
}
let count=Math.floor((this.allStyles.length-3)/2)
for(let i=0;i<this.allStyles.length;i++){
if(index==this.allStyles.length){
if(!style[i]){
if(!count){
style[i]=this.rightOtherStyle
}else{
style[i]=this.leftOtherStyle
count--
}
}
}else if(index==1){
if(!style[i]){
if(count){
style[i]=this.rightOtherStyle
count--
}else{
style[i]=this.leftOtherStyle
}
}
}else{
if(i<index){
if(!style[i]){
style[i]=this.leftOtherStyle
}
}else if(i>index){
if(!style[i]&&count){
style[i]=this.rightOtherStyle
count--
}else{
if(!style[i]){
style[i]=this.leftOtherStyle
}
}
}
}
}
this.computedStyles=style
},
getStyle(index){
// 这里可以少计算很多
let scaleWidth=this.childWidth*0.1
if(index==1){
this.allStyles.push({
opacity:1,
'z-index':4,
'transform':`translateX(${(this.width-this.childWidth)/2}px) scale(1)`,
})
this.centerStyle={
opacity:1,
'z-index':4,
'transform':`translateX(${(this.width-this.childWidth)/2}px) scale(1)`,
}
}else if(index%2==0){
if(index==2){
this.right=this.width-this.childWidth+scaleWidth
this.allStyles.push({
opacity:0.8,
'z-index':3,
transform:`translateX(${this.right}px) scale(0.8)`,
})
this.rightStyle={
opacity:0.8,
'z-index':3,
transform:`translateX(${this.right}px) scale(0.8)`,
}
}else{
if(this.right<this.width){
this.right+=this.width
}
this.allStyles.push(
{
opacity:0,
'z-index':3,
transform:`translateX(${this.right}px) scale(0.8)`,
// 这里要加单位的,不然是不行的
// transform:`scale(1)`
}
)
this.rightOtherStyle={
opacity:0,
'z-index':3,
transform:`translateX(${this.right}px) scale(0.8)`,
// 这里要加单位的,不然是不行的
// transform:`scale(1)`
}
}
}else{
if(index==3){
this.left=0-scaleWidth
this.centerIndex++
this.allStyles.unshift({
opacity:0.8,
'z-index':3,
transform:`translateX(${this.left}px) scale(0.8)`,
})
this.leftStyle={
opacity:0.8,
'z-index':3,
transform:`translateX(${this.left}px) scale(0.8)`,
}
}else{
this.centerIndex++
if(this.left>=-this.width){
this.left-=this.width
}
this.allStyles.unshift(
{
opacity:0,
'z-index':3,
transform:`translateX(${this.left}px) scale(0.8)`,
}
)
this.leftOtherStyle={
opacity:0,
'z-index':3,
transform:`translateX(${this.left}px) scale(0.8)`,
}
}
}
},
add(value){
console.log('add',value)
this.computedStyles.unshift(this.computedStyles[this.sliderLength-1])
this.computedStyles.pop()
if(value){
this.currentIndex=value
return
}
if(this.currentIndex<this.allStyles.length){
this.currentIndex++
}else{
this.currentIndex=1
}
},
sub(value){
// 有值得话直接跳过去。
console.log('sub',value)
this.computedStyles.push(this.computedStyles[0])
this.computedStyles.shift()
if(value){
this.currentIndex=value
return
}
if(this.currentIndex>1){
this.currentIndex--
}else{
this.currentIndex=this.allStyles.length
}
},
// 左右简单的切换,根据currnetIndex切换是下面的函数
// 当有slot元素发生变化的时候,或者子元素
slotChange(){
this.$nextTick(()=>{
this.updateSlides()
})
},
handleResize(){
// 外面用一个更加全局的函数,发现变化的时候直接改变width,然后下面watch直接观察就可以了
},
setAutoplay(){
window.clearInterval(this.timer)
if(this.autoplay){
this.timer=window.setInterval(()=>{
this.sub()
},this.autoplaySpeed)
}
},
handleMove(e){
if(this.trigger!=='click'||e==this.currentIndex)return
this.$emit('on-change',e)
if(e>this.currentIndex&&e-this.currentIndex==1){
this.add(e)
}else if(e<this.currentIndex&&this.currentIndex-e==1){
this.sub(e)
}else{
this.setComputedStyles(e)
}
},
stop(){
window.clearInterval(this.timer)
// 鼠标放到界面上。其实默认
},
handleHoverMove(e){
if(this.trigger!=='hover'||e==this.currentIndex)return
if(this.currentIndex=e)return
this.$emit('on-change',n)
this.$emit('input',n)
if(e>this.currentIndex&&e-this.currentIndex==1){
this.add()
}else if(e<this.currentIndex&&this.currentIndex-e==1){
this.sub()
}else{
this.setComputedStyles(e)
}
}
},
mounted(){
this.handleResize()
// 计算父级元素的大小
// 子组件执行父组件相关的计算方法,他里面有一个值是this.handleResize赋给的。
this.updateSlides()
// 计算slot相关,最关键的函数,第一次加载父组件的时候,操作一下子组件
// 计算窗口
window.addEventListener('resize',this.handleResize,false)
// 挂载自动轮播
this.listWidth=this.$el.getBoundingClientRect().width
this.setAutoplay()
// 一秒之后去掉首次加载第一张图片不加过渡的操作
},
beforeDestroy(){
widnow.removeEventListener('resize',this.handleResize,false)
},
watch:{
height(v){
this.$children.forEach((c)=>{
c.height=typeof this.height=='number'?`${this.height}px`:this.height
})
},
currentTransitionName(v){
this.$children.forEach((c)=>{
c.transitionName=v
})
},
currentIndex(v){
this.$children.forEach((c)=>{
c.currentIndex=v
})
},
value(v){
this.currentIndex=v
},
autoplay(){
this.setAutoplay()
},
autoplaySpeed(){
this.setAutoplay()
},
},
beforeDestroy(){
}
// init触发函数:
// 1.slotChange:子元素发起:计算子元素样式,每一个子元素都会触发一遍
// 2.updateSlider:slotChange函数发起
// 3.updateSliderWidth:更新子元素的宽度,因为没有办法确认什么时候会获得得出的宽度,所以他这里会频繁的调用这个函数来更新子元素的宽度,来确保是正确的值
// 4.比如他在updateSLider里面最后就调用一个函数,然后这个函数结束之后立马又调用了一次
//
}
</script>
<style lang="less" src="./index.less"></style>
carsoule-item
<template>
<div
class="li-carousel-item"
:style="styles"
:class="itemClasses"
:key="index"
@click="handleClick"
>
<slot></slot>
</div>
</template>
<script>
import anime from 'animejs/lib/anime.es.js';
export default {
name:'li-carousel-item',
props:{
width:{
type:Number,
default:400,
},
height:{
type:Number,
default:100,
}
},
data(){
return {
currentIndex:1,
index:0,
transitionName:'next',
}
},
computed:{
styles(){
if(this.$parent.computedStyles[this.index-1]){
let style=this.$parent.computedStyles[this.index-1]
style['width']=`${this.width}px`
return style
}
},
computedTransitionName(){
// 做个兼容,如果是第一张图,第一次加载的时候不做过渡
if(this.index==1&&this.$parent.first){
return ''
}else{
// 这里出现的时候其实要分担一部分动画的东西
return ""
}
},
itemClasses(){
}
},
mounted(){
},
beforeDestroy(){
this.$parent.slotChange()
// 组件卸载的时候也要更新下数据
},
watch:{
currentIndex(n,o){
}
},
methods:{
handleClick(){
if(this.index==this.currentIndex){
return
}
if(this.currentIndex==1&&this.index==this.$parent.allStyles.length){
this.$parent.sub()
}else if(this.currentIndex==this.$parent.allStyles.length&&this.index==1){
this.$parent.add()
}else if(this.currentIndex>this.index){
this.$parent.sub()
}else if(this.currentIndex<this.index){
this.$parent.add()
}
}
}
}
</script>
<style lang="less" src="./index.less">
</style>
index.less
@import '../../assets/gLess.less';
@name:.li-carousel;
[v-cloak]{
display: none !important;
}
@{name}{
// 父组件的样式
position: relative;
overflow: hidden;
// background-color: burlywood;
display: flex;
height:300px;
user-select: none;
cursor: pointer;
&-wrap{
flex:1;
overflow: hidden;
}
&-item{
// 子组件的样式:默认的是很少的
position: absolute;
height: 100%;
min-height: 1px;
transition: all 0.3s ease;
&-center{
left:50%;
transform: translateX(-50%);
z-index: 10;
}
&-last{
z-index: 9;
opacity: 0.8;
}
&-next{
right: 0;
z-index:9 ;
opacity: 0.8;
}
&-mask{
width: 100%;
height: 100%;
position: absolute;
background-color: rgba(19, 19, 19, 0.65);
top: 0;
}
}
&-arrow{
// 左右显示箭头
cursor: pointer;
opacity: 0;
transition:@transition-time;
background-color:rbga(31,45,61,.11);
height: 40px;
line-height: 40px;
color:#fff;
&:hover{
background-color: rgba(31,45,61,0.5);
}
&-always{
opacity: 1;
}
&-never{
opacity: 0;
}
}
&:hover &-arrow-hover{
opacity:1;
}
&-left{
position: absolute;
top:50%;
left:5px;
transform: translateY(-50%);
}
&-right{
position: absolute;
top:50%;
transform: translateY(-50%);
right: 5px;
}
&-list{
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
z-index: 10;
padding: 0;
list-style: none;
text-align: center;
height: 20px;
margin: 0;
display: flex;
flex-direction: row;
li{
margin: 0 2px;
cursor: pointer;
display: inline-block;
width: 16px;
height: 3px;
border-radius: 1px;
background-color: #8391a5;
opacity: 0.3;
color: transparent;
transition:all .5s;
&:hover{
opacity: 0.7;
}
}
&-radius{
width: 6px;
height: 6px;
border-radius: 50%;
}
}
&-active{
opacity: 1 !important;
width: 24px !important;
}
}
// 过渡样式
// 左->右
// 那这里还需要做一个单独的js检测,因为传入的就是一个参数值,比如next,这里换第对应参数的时候需要
.next-enter{
// opacity:0;
transform: translateX(-100%);
}
.next-leave-to{
// opacity:0;
transform: translateX((100%));
}
.next-enter-active,.next-leave-active{
transition: all 500ms;
}
// 右->左
.last-enter{
// opacity:0;
transform: translateX(100%);
}
.last-leave-to{
// opacity:0;
transform: translateX(-100%);
}
.last-enter-active,.last-leave-active{
transition: all 500ms;
}
// 这种可以是一对对的
// 上下
.up-enter{
// opacity:0;
transform: translateY(-100%);
}
.up-leave-to{
// opacity:0;
transform: translateY((100%));
}
.up-enter-active,.up-leave-active{
transition: all 500ms;
}
// 右->左
.down-enter{
// opacity:0;
transform: translateY(100%);
}
.down-leave-to{
// opacity:0;
transform: translateY(-100%);
}
.down-enter-active,.down-leave-active{
transition: all 500ms;
}
网友评论