Я пытаюсь решить тривиальную задачу с помощью Alpine JS и стандартной функции JS setInterval. Итак, я пытаюсь создать селектор изображений, в котором изображения будут меняться каждую секунду (1000 мс).
Вот что я получил:
<div x-data = "imgFunc()">
<h1 class = "text-xl py-3">Chosing the picture</h1>
<div class = "w-1/2">
<img x-show = "img === 'img1'" src = "{{ asset('images/training/img1.jpg') }}" alt = "Main Image">
<img x-show = "img === 'img2'" src = "{{ asset('images/training/img2.jpg') }}" alt = "Main Image">
<img x-show = "img === 'img3'" src = "{{ asset('images/training/img3.jpg') }}" alt = "Main Image">
</div>
<div>
<ul class = "flex">
<li class = "w-1/6 p-3" :class = "{ 'border' : img==='img1' }"><img src = " {{ asset('images/training/img1.jpg') }} " alt = "image1" @click = "startImg"></li>
<li class = "w-1/6 p-3" :class = "{ 'border' : img==='img2' }"><img src = " {{ asset('images/training/img2.jpg') }} " alt = "image2" @click = "img='img2'"></li>
<li class = "w-1/6 p-3" :class = "{ 'border' : img==='img3' }"><img src = " {{ asset('images/training/img3.jpg') }} " alt = "image3" @click = "img='img3'"></li>
</ul>
</div>
</div>
<script>
function imgFunc(){
var i = 1;
var img ='img'+i;
return {
i,
img,
startImg(){
var myvar = window.setInterval(function(){
this.img = 'img'+this.i;
if (this.i<3){
this.i++;
}else{
this.i=1;
}
}, 1000);
},
changeImg() {
this.img = 'img'+this.i;
if (this.i<3){
this.i++;
}else{
this.i=1;
}
}
}
}
</script>
При нажатии на изображение № 1 в списке изображения должны начать меняться, но этого никогда не происходит. Почему?
Я также попытался передать имя функции changeImg() в событии @click, и это сработало отлично, при нажатии на одно изображение менялось одно за другим.
Я также попытался передать имя функции changeImg() в setInerval() следующим образом:
startImg(){
var myvar = window.setInterval(this.changeImg, 1000);
},
Или вот так:
startImg(){
var myvar = window.setInterval(changeImg, 1000);
},
Я пытался изменить "это" на "я"
<script>
function imgFunc(){
var i = 1;
var img ='img'+i;
var self=this;
return {
i,
img,
startImg(){
var myvar = window.setInterval(function(){
self.img = 'img'+self.i;
if (self.i<3){
self.i++;
}else{
self.i=1;
}
}, 1000);
},
changeImg() {
this.img = 'img'+this.i;
if (this.i<3){
this.i++;
}else{
this.i=1;
}
}
}
}
</script>
Но на самом деле ничего не работает.
Ваша проблема заключается в использовании function
, поэтому this
внутри функции не является Alpine.js this
. this
внутри imgFunc
также не является Alpine.js this
(быстрое объяснение этого заключается в том, что imgFunc
запускается до инициализации Alpine.js для создания начального «состояния», поэтому this
— это окно)
Есть 2 способа исправить это: либо использовать this
, либо использовать функцию стрелки внутри setInterval
:
<script>
function imgFunc(){
var i = 1;
var img ='img'+i;
return {
i,
img,
startImg(){
var myvar = window.setInterval(() => {
this.img = 'img'+this.i;
if (this.i<3){
this.i++;
}else{
this.i=1;
}
}, 1000);
},
changeImg() {
this.img = 'img'+this.i;
if (this.i<3){
this.i++;
}else{
this.i=1;
}
}
}
}
</script>
В качестве альтернативы вы можете установить self = this
в функции startImg
<script>
function imgFunc(){
var i = 1;
var img ='img'+i;
return {
i,
img,
startImg(){
var self=this;
var myvar = window.setInterval(function(){
self.img = 'img'+self.i;
if (self.i<3){
self.i++;
}else{
self.i=1;
}
}, 1000);
},
changeImg() {
this.img = 'img'+this.i;
if (this.i<3){
this.i++;
}else{
this.i=1;
}
}
}
}
</script>
Есть еще один способ сделать это — использовать .bind
в обратном вызове setInterval
, но это более многословно и сложно.
Как упомянул Хьюго, контекст this
не разрешается во внешнюю функцию, поэтому вам нужно использовать функцию стрелки, поскольку у нее нет контекста.
Я внес несколько изменений, чтобы использовать alpine.js для того, для чего он создан.
<link href = "https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.0.1/tailwind.min.css" rel = "stylesheet" />
<script src = "https://cdnjs.cloudflare.com/ajax/libs/alpinejs/2.7.3/alpine.js"></script>
<div x-data = "imgFunc()">
<h1 class = "text-xl py-3">Chosing the picture</h1>
<div class = "w-1/2">
<img :src = "currentImage" alt = "Main Image">
</div>
<div>
<ul class = "flex">
<template x-for='(image,index) in images'>
<li class = "w-1/6 p-3" :class = "{'border': currentImage===image}">
<img :src = "image" alt = "image1" @click = "startImg(index)">
</li>
</template>
</ul>
</div>
</div>
<script>
function imgFunc() {
return {
currentImage: 'https://images.pexels.com/photos/5549634/pexels-photo-5549634.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=200&w=400',
images: [
'https://images.pexels.com/photos/5549634/pexels-photo-5549634.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=200&w=400',
'https://images.pexels.com/photos/5101387/pexels-photo-5101387.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
'https://images.pexels.com/photos/2363832/pexels-photo-2363832.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260'
],
startImg(index) {
this.currentImage = this.images[index];
if (index > 0)
return;
let i = 0;
var myvar = setInterval(() => {
i = (i >= this.images.length - 1) ? 0 : ++i;
this.currentImage = this.images[i];
}, 1000);
},
}
}
</script>
Я бы предпочел использовать блейд-шаблоны для тех же целей... Но все равно большое спасибо за внимание к этому вопросу.
Большое спасибо!!! работал как шарм! Я знаю, что что-то не так с видимостью, но я не мог понять, что именно...