1. Введение
Vue используется некоторое время, и разработанная система управления фоном также становится все более и более совершенной.Сейчас время относительно простаивает! В это свободное время я изучаю некоторые другие возможности Vue, такие как компоненты, плагины и т. д. Сегодня я поделюсь практическим проектом компонента — компонентом переключения карт фокуса. Этот проект я использую для практики компонентов vue.Конечно, код также будет отправлен на github (ec-slider), также будет сохранен. Я также думаю, что то, что я разработал, проще в использовании! Теперь я предлагаю нуждающимся партнерам прийти и сыграть в этот проект в качестве практики! Кроме того, если у вас есть какие-либо предложения, добро пожаловать, чтобы дать указатели!
предложение
1. Для следующих шагов лучше запускать их локально, и выполнять их шаг за шагом в соответствии с шагами статьи.Если вы только посмотрите на код, то легко запутаться.
2. Если вы не знаете, какой код что делает, вы можете отладить его самостоятельно, удалить код и посмотреть, какой эффект он дает, и легко понять, что делает код!
2. Каталог проекта
Очень распространенный, хорошо понятный каталог, но позвольте мне кратко объяснить его
node_modules
: модуль файловых зависимостей (создается автоматически)dist
:Каталог вывода файла пакета (создается автоматически)src
: Каталог файлов разработкиsrc/components
: Каталог файлов компонентов.babelrc
:babel компилирует файлы конфигурации es6.gitnore
: файлы конфигурации для файлов (каталогов), не зафиксированных в gitfontSize
: Установить файл алгоритма rem (сейчас не используется, игнорировать)index.html
: файл шаблонаindex.js
: входной файлpackage.json
:файл конфигурацииREADME.md
: Документацияwebpack.config.babel.js
: файл конфигурации веб-пакета
3. Подробные шаги
3-1 разбег
Это первый шаг проекта (проект создает это, я не буду много говорить, предыдущая статья уже говорила это несколько раз!), Сейчасsrc/components/ec-slider.vue
Это выводит «ожидание»
1. Во-первых, вsrc/components/ec-slider.vue
Он выводит «ожидание», код выглядит следующим образом
<template>
<div>
守候
</div>
</template>
<script type="text/javascript">
export default {
data () {
return {
}
},
computed: {
},
mounted(){
},
props: [],
methods: {
}
}
</script>
2. Затем вsrc/components/index.js
Установите компонент регистрации внутри (методом установки), код выглядит следующим образом
import SlideImg from './ec-slider.vue'
const ecslide={
install:function (Vue) {
Vue.component('ec-slide',SlideImg)
}
}
export default ecslide;
3. Введите и используйте компоненты в файле ввода, index.js
require("./index.html");
require("./src/sass/index.scss");
import Vue from 'vue'
//引入并且使用组件
import ecslide from './src/js/components/index';
Vue.use(ecslide);
let app6 = new Vue({
el: "#app6",
data: {
},
mounted(){
}
});
4. В Index.html (файл шаблона) выходной компонент
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<title>Title</title>
</head>
<body>
<div id="app6">
<ec-slide></ec-slide>
</div>
</body>
</html>
5. Ввод командной строки$ npm run dev
Беги, получилось идеально! Принципы этих шагов, кажется, ни о чем не говорят, все они являются фиксированными шагами.
3-2 Подготовка к разработке
После предыдущего шага заложена основа, затем следующий шаг — процесс разработки, большая часть которого — модификации.src/components/ec-slider.vue
этот файл.
Перед разработкой не спешите писать код, сначала проанализируйте запущенный процесс!
Во-первых, какие параметры нужны для переключения карты фокуса? Согласно следующим каштанам Taobao, я просто проанализирую следующие!
list
-список изображений[{источник:'url',href:'www.baidu.com'},{src:'url',href:'www.163.com'}] (src: src картинки, href: переход по ссылке, при нажатии на картинку)autoplay
- следует ли автоматически воспроизводить логическое значение (по умолчанию false)type
- Режим карусели «прозрачный» (переключатель прозрачности), «слайд» (ползунковый переключатель) (слайд по умолчанию)option
-Соответствующий переключатель (по умолчанию false, не отображается)time
- Интервал карусели, миллисекунд (по умолчанию 4000)sildetype
- эффекты перехода (по умолчанию «облегчение» медленного начала, затем быстрее и конец эффекта медленного перехода, ссылка:transition-timing-function)arrowurl
-стрелка ссылка на изображениеarrowsize
- Размер стрелки "ширина, высота"direction
- переключить ориентацию «влево» (влево и вправо) «вверх» (вверх и вниз) (по умолчанию: влево и вправо)
После анализа я знаю, что временно нужно очень много параметров, тогда следующим шагом будетec-slider.vue
Внутри получите эти параметры. Я хочу, чтобы все знали, как передавать параметры между родительским и дочерним компонентами.props
. код показывает, как показано ниже
<template>
<div>
守候
</div>
</template>
<script type="text/javascript">
export default {
data () {
return {
}
},
computed: {
},
mounted(){
},
props: ['list', 'autoplay', 'type', 'time', 'sildetype', 'arrowurl','arrowsize','option','direction'],
methods: {
}
}
</script>
Если есть место для получения параметров, должно быть место и для передачи параметров, т.е.index.html
в файле шаблона
<div class="slider-left">
<ec-slide :list='list' :autoplay="true" :type="'slide'" :option="true" :time="4000" :sildetype="'ease'" :arrowurl="'http://i1.buimg.com/1949/4d860a3067fab23b.jpg'" :arrowsize="'20,40'" :direction="'left'"></ec-slide>
</div>
макет 3-3 стиля
Теперь, когда вы знаете, какие параметры будут получены, давайте сначала разложим макет стиля и сначала сделаем его правильно.Ничего особенного, код выглядит следующим образом! (Некоторые пояснения я также ввел прямо в код)
<template>
<div class="switch-img-box" id="ec-slide-box">
<div class="switch-img-type switch-img-left">
<ul :style="{'width':ulWidth,'transition-timing-function':slideChange}">
<li v-for="(li,index) in list" :style="{'width':listWidth+'%'}">
<a :href="li.href?li.href:'javascript:;'">
<img :src="li.src" class="slider-img"/>
</a>
</li>
</ul>
</div>
<!--如果需要显示对应的点-->
<div class="switch-option" v-if="option">
<div>
<span v-for="(li,index) in list"></span>
</div>
</div>
<!--如果需要显示箭头-->
<div class="switch-arrow" v-if="arrowurl&&arrowsize">
<div :class="{'arrow-left':direction==='left','arrow-top':direction==='top'}"
:style="{'width':arrowWidth+'px','height':arrowHeight+'px','background':'url('+arrowurl+') no-repeat','background-size':'100%'}"></div>
<div :class="{'arrow-right':direction==='left','arrow-bottom':direction==='top'}"
:style="{'width':arrowWidth+'px','height':arrowHeight+'px','background':'url('+arrowurl+') no-repeat','background-size':'100%'}"></div>
</div>
</div>
</template>
<script type="text/javascript">
export default {
data () {
return {
slideChange: '',
arrowWidth: '',
arrowHeight: '',
}
},
computed: {
//ul宽度
ulWidth: function () {
return (this.list.length) + "00%";
},
//li宽度
listWidth: function () {
return 100 / (this.list.length)
}
},
mounted(){
//设置各个数据初始值
this.slideChange = this.sildetype || 'ease';
if (this.arrowsize && this.arrowurl) {
this.arrowWidth = this.arrowsize.split(',')[0];
this.arrowHeight = this.arrowsize.split(',')[1];
}
},
props: ['list', 'autoplay', 'type', 'time', 'sildetype', 'arrowurl', 'arrowsize', 'option', 'direction'],
methods: {
}
}
</script>
<style lang="scss">
.ec-slide-img-box {
width: 100%;
height: 100%;
position: relative;
touch-action: none;
}
.ec-slide-img-type {
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
&.ec-slide-img-top {
}
&.ec-slide-img-left {
li {
display: inline-block;
font-size: 0;
}
}
&.ec-slide-img-transparent {
li {
opacity: 0;
transition: opacity 1s;
width: 0;
&.cur {
width: auto;
}
&.show {
opacity: 1;
}
}
}
ul {
font-size: 0;
&.tran {
transition: all .4s;
}
li {
text-align: center;
}
img {
vertical-align: middle;
max-width: 100%;
max-height: 100%;
}
}
}
.ec-slide-arrow {
div {
position: absolute;
z-index: 2;
margin: auto;
top: 0;
bottom: 0;
right: 0;
left: 0;
opacity: .5;
&:hover {
opacity: 1;
}
&.arrow-left {
left: 10px;
right: auto;
}
&.arrow-right {
right: 10px;
left: auto;
transform: rotate(180deg);
}
&.arrow-top {
top: 10px;
bottom: auto;
}
&.arrow-bottom {
bottom: 10px;
top: auto;
transform: rotate(180deg);
}
}
}
.ec-slide-option {
position: absolute;
font-size: 0;
bottom: 10px;
text-align: center;
width: 100%;
z-index: 5;
&.isFirst {
span:first-child {
display: none;
}
}
&.isLast {
span:last-child {
display: none;
}
}
span {
border-radius: 100%;
margin: 0 5px;
background: #fff;
display: inline-block;
width: 10px;
height: 10px;
&.active {
background: #09f;
}
}
&.ec-slide-option-top {
display: table;
width: 10px;
height: 100%;
top: 0;
right: 10px;
margin: auto;
bottom: 0;
span {
margin: 5px 0;
}
div {
display: table-cell;
vertical-align: middle;
}
}
}
</style>
Результат операции следующий
3-4 Выполнить анимацию
Макет готов, и вы можете написать анимацию ниже, чтобы карусель двигалась! Здесь также необходимо добавить несколько переменных, одна из которых — nowIndex, которая записывает текущий индекс. Один таймер таймер!
Во-первых, я используюtransform:translate3d()
контролировать таким образомul
скользящий.
<ul :style="{'width':ulWidth,'transform':'translate3d(-'+(listWidth*(nowIndex))+'%,0,0)','transition-timing-function':slideChange,'transition': 'all .4s'}">
<li v-for="(li,index) in list" :style="{'width':listWidth+'%'}">
<a :href="li.href?li.href:'javascript:;'">
<img :src="li.src" class="slider-img"/>
</a>
</li>
</ul>
Затем, согласно nowIndex, установить класс соответствующей точки.
<div class="switch-option" v-if="option">
<div>
<!--如果当前索引index等于nowIndex。则添加active这个class,点就会变成蓝色-->
<span v-for="(li,index) in list" :class="{'active':index===nowIndex}"></span>
</div>
</div>
js-код выглядит следующим образом
<script type="text/javascript">
export default {
data () {
return {
nowIndex: 0,
timer: null,
slideChange: '',
arrowWidth: '',
arrowHeight: '',
}
},
computed: {
//ul宽度
ulWidth: function () {
return (this.list.length) + "00%";
},
//li宽度
listWidth: function () {
return 100 / (this.list.length)
}
},
mounted(){
//是否自动播放
if (this.autoplay) {
this.autoSwitch();
}
//设置初始值
this.slideChange = this.sildetype || 'ease';
if (this.arrowsize && this.arrowurl) {
this.arrowWidth = this.arrowsize.split(',')[0];
this.arrowHeight = this.arrowsize.split(',')[1];
}
},
props: ['list', 'autoplay', 'type', 'time', 'sildetype', 'arrowurl', 'arrowsize', 'option', 'direction'],
methods: {
//滑动操作
switchDo(reduce){
clearInterval(this.timer);
//根据reduce判断this.nowIndex的增加或者减少!
//如果是减少模式reduce=‘reduce’
if (reduce === 'reduce') {
//如果nowIndex等于0,已经是第一个了,就回到最后一个
if (this.nowIndex === 0) {
this.nowIndex = this.list.length - 1;
}
else {
this.nowIndex--;
}
}
//如果是增加模式reduce=undefined
else {
//如果nowIndex等于this.list.length-1,已经是最后一个了,就回到第一个
if (this.nowIndex === this.list.length-1) {
this.nowIndex = 0;
}
else{
this.nowIndex++;
}
}
//如果需要自动播放
if (this.autoplay) {
this.autoSwitch();
}
},
//自动播放函数
autoSwitch(){
let time = this.time || 4000;
this.timer = setInterval(() => {
this.switchDo();
}, time);
}
}
}
</script>
На этом этапе остается только нажать на две стрелки, чтобы выполнить соответствующую анимацию.Это относительно просто.Это не что иное, как вызов функции switchDo.Единственная разница в том, что нажатие на стрелку слева вызывает уменьшение режим, а стрелка справа — режим увеличения. Код выглядит следующим образом, легко понять.
<!--判断是否需要显示箭头-->
<div class="switch-arrow" v-if="arrowurl&&arrowsize">
<div :class="{'arrow-left':direction==='left','arrow-top':direction==='top'}"
:style="{'width':arrowWidth+'px','height':arrowHeight+'px','background':'url('+arrowurl+') no-repeat','background-size':'100%'}" @click.stop="switchDo('reduce')"></div>
<div :class="{'arrow-right':direction==='left','arrow-bottom':direction==='top'}"
:style="{'width':arrowWidth+'px','height':arrowHeight+'px','background':'url('+arrowurl+') no-repeat','background-size':'100%'}" @click.stop="switchDo"></div>
</div>
Вот разработчики взаимодействующие за обсессивно-компульсивное расстройство не выдерживают.На последнем кликните на стрелку вправо, появится следующая ситуация!
Когда вы дойдете до первой картинки, снова нажмите на стрелку влево — аналогичная ситуация, что очень плохо. В идеале следующее
3-5 Детальная оптимизация
Если вы хотите добиться вышеуказанного эффекта, изменений будет больше.Давайте сначала поговорим о принципе.Когда вы дойдете до последнего, в это время нажмите стрелку справа, как Taobao, чтобы вернуться к первому. Когда вы дойдете до первого, нажмите стрелку слева, чтобы вернуться к последнему. Итак, окончательный макет выглядит так
Таким образом, макет может достичь эффекта.Когда вы дойдете до последнего, в это время снова нажмите стрелку справа, как Taobao, чтобы вернуться к первому. как ниже
В это время вам нужно сделать еще один шаг, а когда вы прокрутите здесь, мгновенно оттяните его назад. И потяните это назад, чтобы сделать эффект перехода ultransition
Удалите его, или вы увидите переходный эффект оттягивания назад! Также измените файл nowIndex.
1. Во-первых, аспект макета UL
<div class="switch-img-type switch-img-left" v-if="type==='slide'&&direction==='left'">
<!--用tran这个class控制ul是否含有过渡效果,样式已经写好-->
<ul :style="{'width':ulWidth,'transform':'translate3d(-'+(listWidth*(nowIndex+1))+'%,0,0)','transition-timing-function':slideChange}"
:class="{'tran':noLast}">
<!--最后一张图片-->
<li :style="{'width':listWidth+'%'}">
<a :href="list[list.length-1].href?list[list.length-1].href:'javascript:;'">
<img :src="list[list.length-1].src" class="slider-img"/>
</a>
</li>
<!--遍历出来的图片-->
<li v-for="(li,index) in list" :style="{'width':listWidth+'%'}">
<a :href="li.href?li.href:'javascript:;'">
<img :src="li.src" class="slider-img"/>
</a>
</li>
<!--第一张图片-->
<li :style="{'width':listWidth+'%'}">
<a :href="list[0].href?list[0].href:'javascript:;'">
<img :src="list[0].src" class="slider-img"/>
</a>
</li>
</ul>
</div>
2. Затем соответствующая точка изменена
<!--isLast:隐藏最后一个span,isFirst隐藏第一个span-->
<div class="switch-option" v-if="option"
:class="{'isLast':nowIndex===list.length, 'isFirst':nowIndex===-1,'switch-option-top':direction==='top'}">
<div>
<span class="active span1" v-if="nowIndex===list.length"></span>
<span v-for="(li,index) in list" :class="{'active':index===nowIndex}"></span>
<span class="active span2" v-if="nowIndex===-1"></span>
</div>
</div>
Это может быть немного извилистым, позвольте мне объяснить, например, прокрутите последний, нажмите стрелку справа и проведите вправо до первого, как показано ниже
В это время первая точка должна снова стать синей, но индекс соответствующей точки не совпадает с nowIndex.В это время используется трюк. Показать первую точку (.span1) и скрыть последнюю точку. Таким образом, пользователь все равно видит на экране 4 точки! Когда анимация закончится, вернитесь к первому. Скрыть .span1 и нормально отображать соответствующие точки! Все это знают, если подумать. Когда вы доберетесь до первого, нажмите на стрелку слева, чтобы таким же образом вернуться к последнему!
На данный момент функция в основном завершена, и эта часть кода приведена ниже!
<template>
<div class="ec-slide-img-box" id="ec-slide-box">
<div class="ec-slide-img-type ec-slide-img-left" v-if="type==='slide'&&direction==='left'">
<!--用tran这个class控制ul是否含有过渡效果,样式已经写好-->
<ul :style="{'width':ulWidth,'transform':'translate3d(-'+(listWidth*(nowIndex+1))+'%,0,0)','transition-timing-function':slideChange}"
:class="{'tran':noLast}">
<!--最后一张图片-->
<li :style="{'width':listWidth+'%'}">
<a :href="list[list.length-1].href?list[list.length-1].href:'javascript:;'">
<img :src="list[list.length-1].src" class="slider-img"/>
</a>
</li>
<!--遍历出来的图片-->
<li v-for="(li,index) in list" :style="{'width':listWidth+'%'}">
<a :href="li.href?li.href:'javascript:;'">
<img :src="li.src" class="slider-img"/>
</a>
</li>
<!--第一张图片-->
<li :style="{'width':listWidth+'%'}">
<a :href="list[0].href?list[0].href:'javascript:;'">
<img :src="list[0].src" class="slider-img"/>
</a>
</li>
</ul>
</div>
<!--isLast:隐藏最后一个span,isFirst隐藏第一个span-->
<div class="ec-slide-option" v-if="option"
:class="{'isLast':nowIndex===list.length, 'isFirst':nowIndex===-1,'ec-slide-option-top':direction==='top'}">
<div>
<span class="active" v-if="nowIndex===list.length"></span>
<span v-for="(li,index) in list" :class="{'active':index===nowIndex}"></span>
<span class="active" v-if="nowIndex===-1"></span>
</div>
</div>
<div class="ec-slide-arrow" v-if="arrowurl&&arrowsize">
<div :class="{'arrow-left':direction==='left','arrow-top':direction==='top'}"
:style="{'width':arrowWidth+'px','height':arrowHeight+'px','background':'url('+arrowurl+') no-repeat','background-size':'100%'}"
@click.stop="switchDo('reduce')"></div>
<div :class="{'arrow-right':direction==='left','arrow-bottom':direction==='top'}"
:style="{'width':arrowWidth+'px','height':arrowHeight+'px','background':'url('+arrowurl+') no-repeat','background-size':'100%'}"
@click.stop="switchDo"></div>
</div>
</div>
</template>
<script type="text/javascript">
export default {
data () {
return {
nowIndex: 0,
noLast: true,
timer: null,
slideChange: '',
arrowWidth: '',
arrowHeight: ''
}
},
computed: {
ulWidth: function () {
return (this.list.length + 2) + "00%";
},
listWidth: function () {
return 100 / (this.list.length + 2)
}
},
mounted(){
if (this.autoplay) {
this.autoSwitch();
}
this.slideChange = this.sildetype || 'ease';
if (this.arrowsize && this.arrowurl) {
this.arrowWidth = this.arrowsize.split(',')[0];
this.arrowHeight = this.arrowsize.split(',')[1];
}
},
props: ['list', 'autoplay', 'type', 'time', 'sildetype', 'arrowurl', 'arrowsize', 'option', 'direction'],
methods: {
//滑动操作
switchDo(reduce){
clearInterval(this.timer);
//根据reduce判断this.nowIndex的增加或者减少!
if (reduce === 'reduce') {
if (this.nowIndex === 0) {
//如果是滑动切换
this.nowIndex--;
//执行完了这次动画之后,去除过渡效果
setTimeout(() => {
this.nowIndex = this.list.length - 1;
this.noLast = false;
}, 400)
}
else {
this.nowIndex--;
}
}
else {
this.nowIndex++;
}
if (this.nowIndex === this.list.length) {
//执行完了这次动画之后,去除过渡效果
setTimeout(() => {
this.nowIndex = 0;
this.noLast = false;
}, 400)
}
//如果需要自动播放
if (this.autoplay) {
this.autoSwitch();
}
//如果是滑动切换,设置this.noLast,增加过渡效果
this.noLast = true;
},
//自动播放函数
autoSwitch(){
let time = this.time || 4000;
this.timer = setInterval(() => {
this.switchDo();
}, time);
}
}
}
</script>
<style lang="scss">
.ec-slide-img-box {
width: 100%;
height: 100%;
position: relative;
touch-action: none;
}
.ec-slide-img-type {
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
&.ec-slide-img-top {
}
&.ec-slide-img-left {
li {
display: inline-block;
font-size: 0;
}
}
&.ec-slide-img-transparent {
li {
opacity: 0;
transition: opacity 1s;
width: 0;
&.cur {
width: auto;
}
&.show {
opacity: 1;
}
}
}
ul {
font-size: 0;
&.tran {
transition: all .4s;
}
li {
text-align: center;
}
img {
vertical-align: middle;
max-width: 100%;
max-height: 100%;
}
}
}
.ec-slide-arrow {
div {
position: absolute;
z-index: 2;
margin: auto;
top: 0;
bottom: 0;
right: 0;
left: 0;
opacity: .5;
&:hover {
opacity: 1;
}
&.arrow-left {
left: 10px;
right: auto;
}
&.arrow-right {
right: 10px;
left: auto;
transform: rotate(180deg);
}
&.arrow-top {
top: 10px;
bottom: auto;
}
&.arrow-bottom {
bottom: 10px;
top: auto;
transform: rotate(180deg);
}
}
}
.ec-slide-option {
position: absolute;
font-size: 0;
bottom: 10px;
text-align: center;
width: 100%;
z-index: 5;
&.isFirst {
span:first-child {
display: none;
}
}
&.isLast {
span:last-child {
display: none;
}
}
span {
border-radius: 100%;
margin: 0 5px;
background: #fff;
display: inline-block;
width: 10px;
height: 10px;
&.active {
background: #09f;
}
}
&.ec-slide-option-top {
display: table;
width: 10px;
height: 100%;
top: 0;
right: 10px;
margin: auto;
bottom: 0;
span {
margin: 5px 0;
}
div {
display: table-cell;
vertical-align: middle;
}
}
}
</style>
3-6 Другие методы переключения
Как кодовые фермеры могут быть довольны статус-кво, есть только один способ переключения, как это можно сделать, поэтому я еще немного улучшил его:
1. Способ переключения прозрачности.
2. При длине входящего списка 1 будет отображаться только картинка без анимации.
3. Обработка левого и правого скользящих событий мобильного телефона (нестандартная обработка)! Хотя у него мало функций, я могу удовлетворить его в ежедневной разработке!
4. Добавьте режим вращения вверх и вниз.
Полный код — это слишком много, и это приведет к тому, что он будет слишком длинным, поэтому я не буду публиковать его здесь, давайте пойдем на github, чтобы увидеть его!ec-slider
4. Резюме
Ну вот и все для сегодняшнего развития. Сначала я планировал использовать этот проект как практическую работу, но позже я использовал его в проекте.Хотя это относительно просто написать, эффект неплох. Нынешняя ситуация не очень хорошая, и при необходимости она сохранится и в будущем. В настоящее время также рекомендуется играть в этот проект.Хотя статья немного длинная, вы можете прочитать ее напрямую, написать код и прочитать статью, и вы ее найдете. Все кончено в мгновение ока! Это должен быть проект с хорошей практикой, вы можете быть знакомы с использованием vue для разработки компонентов! Наконец, если вы чувствуете, что с написанием что-то не так, вы можете указать!
------------------------- Великолепная разделительная линия --------------------
Хотите узнать больше, обратите внимание на мой публичный аккаунт WeChat: В ожидании книжного магазина