Пишу drag-and-drop с возможностью поворота и ресайза на VueJs. Суть работы простая: отслеживаю перемещения мышкой, в соответствии с ними обновляю модель, в которой хранится положение элемента и которая потом отправляется на сервер. Эта модель успешно обновляется при перемещениях мышки, но стили, которые я к ней прикрепил, не обновляются.
<div
:style="{
top: layout.top,
left: layout.left,
width: layout.width,
rotate: layout.rotate,
position: 'absolute'}"
>
console.log при этом пишет, что модель обновляется. Что я делаю не так? В чём может быть причина? Заранее спасибо PS. Попробовал вывести в консоли модель при перемещении мышью - всё норм. Выводит это:
Но watch его не видит (точнее, не видит при перемещении, хотя видит при вставке фото в макет)(на проверку if(this.pageKey === 'photo_cover_main') не обращайте внимания):
layout: function (val) {
if(this.pageKey === 'photo_cover_main')
alert()
}
Соответственно, из-за этого не перемещается сама фотка. Почему даже watch не видит - не понимаю Модель передаётся в этот компонент свойством, а при перемещении фото вызывается $emit на родителя, который обновляет данные
Layout получается запросом к API
$.get('/api/users/order-layout', data => {
this.layout = data;
});
В родительском компоненте следующий код шаблона:
<hole-view
v-for="(hole, holeKey) in page.holes_coordinats"
:hole="hole"
:hole-key="holeKey"
:layout="layout.content[pageKey] && layout.content[pageKey][holeKey] ? layout.content[pageKey][holeKey] : {}"
:page-key="pageKey"
@moved="movedHoleImageBind"
/>
В дочернем компоненте при перетаскивании объекта мышью после вычисления всех координат вызывается $emit:
this.$emit('moved', top, left, x, y);
В родительском компоненте на событие moved вешается такой обработчик:
movedHoleImageBind(top, left, x, y){
try{
this.$set(this.layout.content[this.editingHoleImage.pageKey][this.editingHoleImage.holeKey], 'top', top);
this.$set(this.layout.content[this.editingHoleImage.pageKey][this.editingHoleImage.holeKey], 'left', left);
}catch (e) {}
}
HTML получается такой (сама фотка - div.image-in-layout-slider и img в нём):
<div data-v-1a44c9e7="" data-v-58dc894e="" data-index="0" data-page="photo_cover_main"
class="slider__empty-block slider__empty-block-focus"
style="top: 19.6875%; left: 64.3931%; width: 22.7381%; height: 50%; position: absolute;">
<div data-v-1a44c9e7="" class="image-in-layout-slider"
style="top: -22.4529%; left: 0px; width: 100%; position: absolute;"><img data-v-1a44c9e7=""
src="http://deti/wp-content/uploads/general_photos/83/FdjjGawbNjA.jpg"
class="img-responsive ls-is-cached lazyloaded"><span
data-v-1a44c9e7="" title="Повернуть" class="rotate-slider-image"><i data-v-1a44c9e7=""
aria-hidden="true"
class="glyphicon glyphicon-repeat"></i></span><span
data-v-1a44c9e7="" title="Удалить" class="slider-photo-remove-js"><i data-v-1a44c9e7=""
aria-hidden="true"
class="glyphicon glyphicon-remove"></i></span>
<div data-v-1a44c9e7="" class="my-resizable-block my-resizable-block-vertical"></div>
<div data-v-1a44c9e7="" class="my-resizable-block my-resizable-block-horizontal"></div>
<div data-v-1a44c9e7="" class="my-resizable-block my-resizable-block-diagonal"></div>
</div>
Убедитесь, что дочерний компонент отправляет необходимые данные:
console.log({top, left, x, y});
this.$emit('moved', top, left, x, y);
Убедитесь, что родительский компонент принимает их, а также, что свойства top
и left
изначально были прописаны в объектах:
movedHoleImageBind(top, left, x, y){
console.log({top, left, x, y});
this.layout.content[this.editingHoleImage.pageKey][this.editingHoleImage.holeKey].top = top;
this.layout.content[this.editingHoleImage.pageKey][this.editingHoleImage.holeKey].left = left;
}
1 Возможно, что вы не передаёте единицы измерения и обращаетесь к не существующему CSS свойству rotate
. Как бы там ни было, свойства лучше перенести в поле computed
.
// Отключим ненужные для примера
// сообщения в консоли.
Vue.config.productionTip = false;
Vue.config.devtools = false;
// Дочерний компонент.
const HoleView = {
props: ['layout'],
computed: {
dragStyle() {
return {
'top': this.layout.top + 'px',
'left': this.layout.left + 'px',
'width': this.layout.width + 'px',
'transform': 'rotate(' + this.layout.rotate + 'deg)'
}
}
},
template: `<div class="block" :style="dragStyle">Содержимое блока</div>`
}
new Vue({
el: '#app',
components: {
'hole-view': HoleView
},
data: {
layout: {
top: 0,
left: 0,
width: 288,
rotate: 0
},
}
});
.container {
max-width: 800px;
margin: 50px auto;
position: relative;
}
.form {
max-width: 800px;
margin: 50px auto;
position: relative;
display: flex;
flex-wrap: wrap;
}
.label {
display: block;
}
.block {
height: 188px;
box-sizing: border-box;
border: 1px dashed #888;
background: rgb(178, 214, 60);
position: absolute;
}
<div id="app">
<form class="form">
<div>
<label class="label">Слева {{ layout.left }}</label>
<input type="range" v-model="layout.left">
</div>
<div>
<label class="label">Сверху {{ layout.top }}</label>
<input type="range" v-model="layout.top">
</div>
<div>
<label class="label">Ширина {{ layout.width }}</label>
<input type="range" v-model="layout.width" min="120" max="400">
</div>
<div>
<label class="label">Поворот {{ layout.rotate }}</label>
<input type="range" v-model="layout.rotate" min="0" max="360">
</div>
</form>
<div class="container">
<hole-view :layout="layout"></hole-view>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
2 Укажите уникальный атрибут key
для каждого элемента, вот так:
<hole-view v-for="(hole, holeKey) in page.holes_coordinats" :key="holeKey" ...>
3 Указывайте глубину слежения за объектом в поле watch
:
// ... остальной код
watch: {
// Коллбэк будет вызываться каждый раз,
// когда изменяется любое из свойств наблюдаемого объекта.
layout: {
handler: 'layoutWatcher',
deep: true, // независимо от глубины их вложенности.
immediate: true // коллбэк будет вызван сразу же после начала наблюдения.
},
}
// ... остальной код
methods: {
layoutWatcher(newVal, oldVal) {
// Реализация метода для наблюдателя.
// ... code
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Есть сайт на angular, сайт не мойХочу немного оптимизировать работу с ним для себя
Вопрос, возможно, слишком общий или не по теме, но мне интересноЯ видел, что кто-то использует querySelector для поиска элемента по id, а не по имени...
Хочу сделать, чтобы бот менял свой никПодскажите как правильно это сделать