- 导轨 6
- Vue 2.6.10
- vuedraggable 2.23.0
问题如下,里面有一个 Cards 的列表,当你点击 Card 时,会弹出一个有 Card 的模态窗口,然后在模态窗口上按住鼠标左键并按住鼠标,vuedraggable 事件将关闭模态窗口并破坏卡片列表,当模态窗口打开时如何避免这种可拖动的行为?
代码可以完全从 GoRails 下载,我是通过视频 https://github.com/gorails-screencasts/vuejs-trello-clone完成的
播放方法——点击卡片打开模态窗口,在打开的模态窗口中,按住鼠标左键不放,此时模态窗口将关闭,列表将断开
应用程序.js
/* eslint no-console:0 */
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
//
// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
// layout file, like app/views/layouts/application.html.erb
import Vue from 'vue/dist/vue.esm'
import Vuex from 'vuex'
import App from '../app.vue'
import TurbolinksAdapter from 'vue-turbolinks'
Vue.use(Vuex)
Vue.use(TurbolinksAdapter)
window.store = new Vuex.Store({
state: {
lists: []
},
mutations: {
addList(state, data) {
state.lists.push(data)
},
moveList(state, data) {
const index = state.lists.findIndex(item => item.id == data.id)
state.lists.splice(index, 1)
state.lists.splice(data.position - 1, 0, data)
},
addCard(state, data) {
const index = state.lists.findIndex(item => item.id == data.list_id)
state.lists[index].cards.push(data)
},
editCard(state, data) {
const list_index = state.lists.findIndex((item) => item.id == data.list_id)
const card_index = state.lists[list_index].cards.findIndex((item) => item.id == data.id)
state.lists[list_index].cards.splice(card_index, 1, data)
},
moveCard(state, data) {
const old_list_index = state.lists.findIndex((list) => {
return list.cards.find((card) => {
return card.id === data.id
})
})
const old_card_index = state.lists[old_list_index].cards.findIndex((item) => item.id == data.id)
const new_list_index = state.lists.findIndex((item) => item.id == data.list_id)
if (old_list_index != new_list_index) {
// Remove card from old list, add to new one
state.lists[old_list_index].cards.splice(old_card_index, 1)
state.lists[new_list_index].cards.splice(data.position - 1, 0, data)
} else {
state.lists[new_list_index].cards.splice(old_card_index, 1)
state.lists[new_list_index].cards.splice(data.position - 1, 0, data)
}
}
}
})
document.addEventListener("turbolinks:load", function() {
var element = document.querySelector("#boards")
if (element != undefined) {
window.store.state.lists = JSON.parse(element.dataset.lists)
const app = new Vue({
el: element,
store: window.store,
template: "<App />",
components: { App }
})
}
});
应用程序.vue
<template>
<div class="board">
<draggable v-model="lists" :options="{group: 'lists'}" class="dragArea d-inline-block" @end="listMoved">
<list v-for="(list, index) in lists" :list="list"></list>
</draggable>
<div class="list">
<a v-if="!editing" v-on:click="startEditing">Add a List</a>
<textarea v-if="editing" ref="message" v-model="message" class="form-control mb-1"></textarea>
<button v-if="editing" v-on:click="createList" class="btn btn-secondary">Add</button>
<a v-if="editing" v-on:click="editing=false">Cancel</a>
</div>
</div>
</template>
<script>
import draggable from 'vuedraggable'
import list from 'components/list'
export default {
components: { draggable, list },
data: function() {
return {
editing: false,
message: "",
}
},
computed: {
lists: {
get() {
return this.$store.state.lists
},
set(value) {
this.$store.state.lists = value
},
},
},
methods: {
startEditing: function() {
this.editing = true
this.$nextTick(() => { this.$refs.message.focus() })
},
listMoved: function(event) {
var data = new FormData
data.append("list[position]", event.newIndex + 1)
Rails.ajax({
beforeSend: () => true,
url: `/lists/${this.lists[event.newIndex].id}/move`,
type: "PATCH",
data: data,
dataType: "json",
})
},
createList: function() {
var data = new FormData
data.append("list[name]", this.message)
Rails.ajax({
beforeSend: () => true,
url: "/lists",
type: "POST",
data: data,
dataType: "json",
success: (data) => {
this.message = ""
this.editing = false
}
})
}
}
}
</script>
<style scoped>
.dragArea {
min-height: 10px;
}
.board {
overflow-x: auto;
white-space: nowrap;
}
.list {
background: #E2E4E6;
border-radius: 3px;
display: inline-block;
margin-right: 20px;
padding: 10px;
vertical-align: top;
width: 270px;
}
</style>
列表.vue
<template>
<div class="list">
<h6>{{ list.name }}</h6>
<draggable v-model="list.cards" :options="{group: 'cards'}" class="dragArea" @change="cardMoved">
<card v-for="card in list.cards" :key="card.id" :card="card" :list="list"></card>
</draggable>
<a v-if="!editing" v-on:click="startEditing">Add a card</a>
<textarea v-if="editing" ref="message" v-model="message" class="form-control mb-1"></textarea>
<button v-if="editing" v-on:click="createCard" class="btn btn-secondary">Add</button>
<a v-if="editing" v-on:click="editing=false">Cancel</a>
</div>
</template>
<script>
import draggable from 'vuedraggable'
import card from 'components/card'
export default {
components: { card, draggable },
props: ["list"],
data: function() {
return {
editing: false,
message: ""
}
},
methods: {
startEditing: function() {
this.editing = true
this.$nextTick(() => { this.$refs.message.focus() })
},
cardMoved: function(event) {
const evt = event.added || event.moved
if (evt == undefined) { return }
const element = evt.element
const list_index = window.store.state.lists.findIndex((list) => {
return list.cards.find((card) => {
return card.id === element.id
})
})
var data = new FormData
data.append("card[list_id]", window.store.state.lists[list_index].id)
data.append("card[position]", evt.newIndex + 1)
Rails.ajax({
beforeSend: () => true,
url: `/cards/${element.id}/move`,
type: "PATCH",
data: data,
dataType: "json"
})
},
createCard: function() {
var data = new FormData
data.append("card[list_id]", this.list.id)
data.append("card[name]", this.message)
Rails.ajax({
beforeSend: () => true,
url: "/cards",
type: "POST",
data: data,
dataType: "json",
success: (data) => {
this.message = ""
this.$nextTick(() => { this.$refs.message.focus() })
}
})
}
}
}
</script>
<style scoped>
.dragArea {
min-height: 10px;
}
</style>
卡片.vue
<template>
<div>
<div @click="editing=true" class="card card-body mb-3">
{{card.name}}
</div>
<div v-if='editing' class="modal-backdrop show"></div>
<div v-if='editing' @click="closeModal" class="modal show" style="display: block">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ card.name }}</h5>
</div>
<div class="modal-body">
<input v-model="name" class="form-control"></input>
</div>
<div class="modal-footer">
<button @click="save" type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['card', 'list'],
data: function() {
return {
editing: false,
name: this.card.name,
}
},
methods: {
closeModal: function(event) {
if (event.target.classList.contains("modal")) { this.editing = false }
},
save: function() {
var data = new FormData
data.append("card[name]", this.name)
Rails.ajax({
beforeSend: () => true,
url: `/cards/${this.card.id}`,
type: "PATCH",
data: data,
dataType: "json",
success: (data) => {
this.editing = false
}
})
},
}
}
</script>
<style scoped>
</style>
之前和之后会发生什么