仿Element

编程入门 行业动态 更新时间:2024-10-24 20:17:27

仿<a href=https://www.elefans.com/category/jswz/34/1769660.html style=Element"/>

仿Element

目标:

  • 实现一个轮播图组件

基本步骤:

  • 开发组件。packages/slider/slider.vue
  • 添加到packages/index.js,全局注册
  • 在测试页面中使用组件

准备工作

  1. 添加组件

    创建一个组件

    <template><div class=''>我是一个轮播图组件</div>
    </template><script>
    export default {name: 'MySlider'
    }
    </script>
  2. 导出组件

    packages/index.js

    // semantic-ui样式
    import 'semantic-ui-css/semantic.css'// 收集所有packages下面的组件,并按vue插件的格式做导出
    import Button from './button/button.vue'
    import Slider from './slider/slider.vue'export default {install (Vue) {// 创建全局组件Vueponent('MyButton', Button)Vueponent('MySlider', Slider)}
    }
  3. 在测试项目中使用组件

    (1)添加测试页面


内容

<template><div class="home"><h3>对轮播图组件进行测试</h3><!-- 2000表示 每隔2s自动播放下一张 --><my-slider style="width:250px;height:350px;":auto="2000":curIdx="curIdx":list="list"></my-slider></div>
</template><script>export default {name: 'SliderTest',data () {return {curIdx: 1, // 默认显示第二张图list: [ // 需要轮播的图片数据{url: ';quality=80&size=b9999_10000&sec=1603552928895&di=033a3b0900cb6094b581325f1b6a43ad&imgtype=0&src=http%3A%2F%2Fpic1.win4000%2Fpic%2Fe%2F0f%2F1b7e513753.jpg',alt: '离太阳最近的地方的一场春耕'},{url: ';quality=80&size=b9999_10000&sec=1603552961721&di=e0ff498eb7dbb671ea204454cf0ca58f&imgtype=0&src=http%3A%2F%2Fhbimg.b0.upaiyun%2F2f6ae348b19c83fdc721ca5a54d4adb8d7455fa31dc76-GMqiCq_fw658',alt: '长江三峡水库'},{url: ';quality=80&size=b9999_10000&sec=1603553792310&di=db02409d236f067161d3a6d51439d3a1&imgtype=0&src=http%3A%2F%2Fpic1.win4000%2Fpic%2F1%2F74%2Fe433515514.jpg_195.jpg',alt: '月球方舟在格陵兰岛测试'},{url: ';quality=80&size=b9999_10000&sec=1603553028011&di=100b009e9f826b13b7d52b86a1947568&imgtype=0&src=http%3A%2F%2Fpic1.win4000%2Fpic%2F1%2F50%2F3b06419346.jpg',alt: '虎门大桥水域恢复通航'}]}
}
</script>

(2)添加路由

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'Vue.use(VueRouter)const routes = [{path: '/',name: 'Home',component: Home},{path: '/button',name: 'Button',// route level code-splitting// this generates a separate chunk (about.[hash].js) for this route// which is lazy-loaded when the route is visitedponent: () => import(/* webpackChunkName: "about" */ '../views/Button.vue')},{path: '/slider',name: 'Slider',component: () => import('../views/SliderTest.vue')}
]

(3)添加路由导航

App.vue

     <div id="app"><div id="nav"><router-link to="/">按钮</router-link> |<router-link to="/test-alert">警示框</router-link> |<router-link to="/my-dialog">弹出框</router-link> |<router-link to="/my-switch">开关</router-link> |<router-link to="/slider">轮播图</router-link> |<router-link to="/headline">标题组件</router-link></div><router-view/></div>

效果

slider组件的基本结构和样式

下面是一个结构和样式,修改slider.vue的内容如下:

<template><div class="slider"><div class="slider-content"><!-- 每一个slider-item表示一张图 --><div class="slider-item"><img src=".jpeg?x-bce-process=image/crop,x_0,y_0,w_899,h_490" alt="离太阳最近的地方的一场春耕" /></div></div><!-- 左右两个按钮 --><span class="btn btn_left"></span><span class="btn btn_right"></span><!-- 方案 --><div class="txt">离太阳最近的地方的一场春耕</div><!-- 指示条 --><ol class="indirector"><li></li><li class="current"></li><li></li></ol></div>
</template>
<style>
.slider .slider-content,
.slider img {width: 100%;height: 100%;
}
.slider {margin: 0 auto;border: 1px solid #ccc;position: relative;cursor: pointer;
}
.slider .slider-content {overflow: hidden;position: relative;
}
.slider .slider-content .slider-item {top: 0;left: 0;width:100%;height:100%;
}
.slider img {width: 100%;
}
.slider .btn,
.slider .txt,
.slider .indirector {position: absolute;
}
.slider .btn {cursor: pointer;width: 50px;height: 50px;border-radius: 50%;background-color: rgba(255, 255, 255, 0);top: 50%;transform: translateY(-50%);transition: background-color 0.2s;
}
.slider .btn:hover {background-color: rgba(255, 255, 255, 1);
}.slider .btn:before,
.slider .btn:after {content: "";height: 3px;width: 25px;background-color: #fff;position: absolute;left: 15px;top: 23px;transform: rotateZ(60deg);transform-origin: 0px center;transition: all 0.2s;
}
.slider .btn:after {transform: rotateZ(-60deg);
}
.slider .btn:hover:before {transform: rotateZ(45deg);background-color: red;
}
.slider .btn:hover:after {transform: rotateZ(-45deg);background-color: red;
}.slider .btn.btn_right:before,
.slider .btn.btn_right:after {transform-origin: right center;
}.slider .btn.btn_left {left: 20px;
}
.slider .btn.btn_right {right: 20px;
}.slider .txt {text-indent: 1em;line-height: 40px;background-color: rgba(0, 0, 0, 0.5);text-align: left;bottom: 0;left: 0;width: 100%;color: #fff;
}
.slider .indirector {bottom: 10px;right: 1em;margin: 0;
}
.slider .indirector li {display: inline-block;margin: 0 5px;height: 10px;width: 10px;border-radius: 50%;background-color: #fff;
}
.slider .indirector li {transition: transform 0.2s;
}
.slider .indirector .current {background-color: #369;transform: scale(1.2);
}
</style>

分析

功能

  • 允许用户传入图片列表
  • 左右按钮可以点击切换
  • 指定从哪一张开始放映
  • 自动播放功能(指定播放时间间隔,鼠标进入时,要停止自动播放)
  • 指示条上 鼠标滑动 也能切换

测试用例

<template><div class="about"><h1>对轮播组件测试</h1><!--这里的style会在组件的根元素上生效- list:是图片列表数据,它是一个数组,保存要轮播图片信息- auto:2000. 开启自动播放。2000毫秒切换一张.- curIdx:初始播放第几张
--><my-sliderstyle="width:550px;height:350px;"auto='2000'curIdx='1':list="list"></my-slider></div>
</template>
  • list:是图片列表数据,它是一个数组,保存要轮播图片信息

  • auto:2000. 开启自动播放。2000毫秒切换一张.

  • curIdx:初始播放第几张

基本实现

目标:

  • 从用prop传入三项:
    • 图片列表
    • 当前索引
    • auto

思路:

  • 用v-for循环生成图片列表: 只显示当前项,其它隐藏
  • 显示当前图片的文案
  • 用v-for循环生成指示条,只有当前项是高亮的

$attrs和props

在父组件中向子组件传递自定义属性时,如果:

  • 在子组件内部有对应的props项, 则,数据会传入props。
  • 在子组件中没有定义对应的props,则在组件内部可以通过 $attrs来查看

$attrs最终会显示在dom格式上

<div data-v-63407e8a=""
class="slider" 
list="[object Object],[object Object],[object Object],[object Object]" abc="123" 
style="width: 550px; height: 350px;">

组件代码

  • 通过循环生成轮播图的每一项,根据下标决定显示与否
  • 根据list及传入的下标,取出当前的方案
  • 通过循环生成指示条的每一项,根据下标决定显示高亮
<template><div class="slider"><div class="slider-content"><!-- 每一个slider-item表示一张图 --><div class="slider-item"v-for="(item, idx) in list":key="idx"v-show="curIdx==idx"><img :src="item.url" :alt="item.alt" /></div></div><!-- 左右两个按钮 --><span class="btn btn_left"></span><span class="btn btn_right"></span><!-- 文案 --><div class="txt">{{list[curIdx].alt}}</div><!-- 指示条 --><ol class="indirector"><li v-for="(item, idx) in list":key="idx":class="{'current': curIdx==idx}"></li></ol></div>
</template>
<script>
export default {name: 'MySlider',// 在父组件中向子组件传递自定义属性时,如果在子组件内部有对应的props项,// 则,数据会传入props。如果在子组件中没有定义对应的props,则在组件内部可以通过 $attrs来查看props: {list: {type: Array,required: true},curIdx: {type: [String, Number],default: 0 // 默认显示第一张},auto: {type: [String, Number], // "2000", 2000default: 0}}
}
</script>

给按钮添加点击事件

目标:让轮播图上的左右按钮产生点击切换效果。

思路:

  • 修改当前项的下标
  • 添加下标索值即可。要注意越界的情况。

步骤:

  • 添加一个数据项:currentIndex。由于在切换上一张下一张时本质上是要修改索引值,而这个索引值是通过prop传入的,我们不能直接修改,所以这里补充一个currentIndex来保存传入的索引值。

    data () {return {// 由于在子组件内,不允许直接赋值给props// 在这里,补充一个数据项,从curIdx中获取初始值currentIndex: this.curIdx}}
    
  • 把模板中的原来对curIdx的引用,改成对currentIndex的引用。

  • 在模板中对按钮添加点击事件,在事件中修改currentIndex的值。

模板

<template><div class="slider">....<!-- 左右两个按钮 -->
+    <span class="btn btn_left" @click="hPrev"></span>
+    <span class="btn btn_right" @click="hNext"></span>....</div>
</template>

代码

methods: {hNext () {// 下一张图// 1. 把下标向后移// 2. 判断是否越界this.currentIndex++if (this.currentIndex === this.list.length) {this.currentIndex = 0}},hPrev () {// 上一张图// 1. 把下标向前移// 2. 判断是否越界this.currentIndex--if (this.currentIndex === -1) {this.currentIndex = this.list.length - 1}// this.currentIndex = this.currentIndex === -1 ? this.list.length - 1 : this.currentIndex}}

添加自动播放功能

目标:

  • 允许用户手动启动轮播功能

思路:

  • 在组件上添加auto这个prop,它用来接收用户的输入,如果有值,则开启定时器
  • 在创建组件时,如果有auto的值,就用setInterval来启动定时器。

组件代码:

补充一个钩子函数created

created () {// 如果用户设置了auto值,则表示开启自动播放功能// 每隔auto值,去调用一次:播放下一张if (this.auto) {setInterval(() => {this.hNext()}, this.auto)}}

补充一下对auto属性值的限制

props: {// ...auto: {type: [String, Number], // "2000", 2000default: 0,
+      validator: function (val) {if (typeof val === 'number') {return val >= 0}if (typeof val === 'string') {if (isNaN(val)) {console.log(val, '不是合法的数值')return false} else {return true}}}}},

改进轮播功能:hover暂停

目标:

  • 当用户鼠标进入轮播图时,停止动画(clearInterval)

    当用户鼠标移出轮播图时,再次启动动画

思路:

  • 在组件中,给外层容器添加mouseenter,mouseleave事件。并在各自事件中删除或启动定时器。
<div class="slider"@mouseleave="hMouseLeave"@mouseenter="hMouseEnter">//...
</div>

代码

补充一个数据项,保存定时器

data () {return {// 由于在子组件内部,不允许修改从父组件中传入的props// 所以,这里补充定义一个数据项,从curIdx中获取初始值currentIdx: this.curIdx,
+      timer: null // 保存定时器 (它不是必须的,只是让大家看到值)}}

方法

created () {this.play()},methods: {play () {// 如果用户设置了auto值,则表示开启自动播放功能// 每隔auto值,去调用一次:播放下一张if (this.auto) {this.timer = setInterval(() => {this.hNext()}, this.auto)}},stop () {if (this.timer) {clearInterval(this.timer)}},// 下一张图hNext () {// 1. 把下标向后移// 2. 判断是否越界this.currentIndex++if (this.currentIndex === this.list.length) {this.currentIndex = 0}},hPrev () {// 上一张图// 1. 把下标向前移// 2. 判断是否越界this.currentIndex--if (this.currentIndex === -1) {this.currentIndex = this.list.length - 1}// this.currentIndex = this.currentIndex === -1 ? this.list.length - 1 : this.currentIndex},// 鼠标进入,如果自动播放的定时器,则要删除定时器,停止自动播放hMouseEnter () {this.stop()},// 鼠标离开,如果有自动播放,则要继续开启定时器,自动播放hMouseLeave () {this.play()}},beforeDestroy () {this.stop()}

指示条上鼠标滑动也能切换

思路:

  • 给每个指示条上的 li添加mouseenter事件,调整当前图片索引值

组件的模块

<!-- 指示条 --><ol class="indirector"><!-- 只有是当前要显示的图,才会添加current类 --><li v-for="(item,idx) in list":key="idx":class="{current:idx===currentIdx}"
+      @mouseenter="currentIdx=idx"></li></ol>

emit事件

目标:

  • 让用户能够监听
    • 点击事件
    • 切换事件

在组件内部的某个场合下,抛出来事件。

  • 点击图片时

    <template><div class="slider"@click="$emit('click',currentIndex)"@mouseleave="hMouseLeave"@mouseenter="hMouseEnter">
    
  • 切换时

    补充一个watch

watch: {currentIndex () {// console.log('当前的下标变了', this.currentIndex)this.$emit('slider', this.currentIndex)}}

测试代码

<div class="about"><h1>对轮播组件测试</h1><!--这里的style会在组件的根元素上生效- list:是图片列表数据,它是一个数组,保存要轮播图片信息- auto:2000. 开启自动播放。2000毫秒切换一张.- curIdx:初始播放第几张
--><my-sliderstyle="width:550px;height:350px;":list="list":curIdx='2'auto='2000'@click="hClick"@slider="hSlider"></my-slider></div>methods: {hClick (index) {alert(index)console.log('当前是', index, '被点击')},hSlider (idx) {this.curIdx = idxconsole.log(idx)}}

切换动画

列表动画transition-group组件:

格式:

<transition-group>列表项1,列表项2......
</transition-group>

属性值:

  • name: 与<transition>组件中的name意义一样的,用于指定产生动画的那个特殊的类名。
  • tag:要渲染成的dom类型.

补充css

.fade-enter, .fade-leave-to {opacity: 0.8;
}
.fade-enter-active, .fade-leave-active {transition: all 0.5s;
}

补充说明图片的地址问题

如果传入的图片是相对地址,则需要使用require()处理。

list: [{// 图片在本地,这里采用相对地址。// 结果不对。http://localhost:8080/1.jpeg。这样找不到。// url: './1.jpeg',url: require('./1.jpeg'),// http://localhost:8080/img/1.6034a006.jpegalt: '图片在本地,这里采用相对地址'},{url: '.jpeg?x-bce-process=image/crop,x_0,y_0,w_750,h_408',alt: 'babababa'}
]

e-leave-active {
transition: all 0.5s;
}

## 补充说明图片的地址问题如果传入的图片是相对地址,则需要使用require()处理。

list: [
{
// 图片在本地,这里采用相对地址。
// 结果不对。http://localhost:8080/1.jpeg。这样找不到。
// url: ‘./1.jpeg’,
url: require(’./1.jpeg’),// http://localhost:8080/img/1.6034a006.jpeg
alt: ‘图片在本地,这里采用相对地址’
},
{
url: ‘.jpeg?x-bce-process=image/crop,x_0,y_0,w_750,h_408’,
alt: ‘babababa’
}
]


更多推荐

仿Element

本文发布于:2024-02-25 15:39:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1699465.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Element

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!