我只往sieteItems 里push 了一次。为啥 watch 执行了两次呢?
怎么可以知道是哪儿导致触发的?
组件 A里的
下面是组件B里的
<template>
<div class="grid resizable" ref="draggable" @contextmenu.prevent.stop v-bind:style="{ left: grid.position.x + 'px', top: grid.position.y + 'px',width:grid.position.w+'px',height:grid.position.h+'px'}">
<h4 v-if="!grid.isRoot" :class="handle">{{grid.gridName}}</h4>
<div :class="{'contentBox':true, 'isRoot':grid.isRoot}" @contextmenu.prevent.stop="show">
<siteItem class="siteItemWrap" v-for="item in grid.siteItems" :item.sync="item" :key="item.siteId" @deleteItem="deleteItem" @moveItem="moveItem"></siteItem>
<gridItem v-for="grid in grid.gridItems" :grid.sync="grid" :key="grid.gridId" @resizGrid="resizGrid" @moveGrid="moveGrid"></gridItem>
<div v-show="contextmenu.isShowContextmenu" v-bind:style="{ left: contextmenu.x + 'px', top: contextmenu.y + 'px'}" class="contextmenu">
<el-button @click="addItem" :plain="true" type="info" icon="plus">新增网址</el-button>
<br>
<el-button @click="addGrid" :plain="true" type="info" icon="plus">新建格子</el-button>
</li>
</div>
</div>
</div>
</template>
<script type="text/javascript">
import siteItem from './siteItem';
export default {
props: {
grid: {
type: Object,
default: {
gridId: '',
gridName: '格子一',
position: { x: '0', y: '0', w: '100', h: '100' },
siteItems: [{
siteId: '5',
site: 'http://www.zhihu.com',
name: '知乎',
position: { x: '10', y: '20' }
}],
gridItems: [{
gridId: '',
gridName: '格子一',
position: { x: '0', y: '0' },
siteItems: [],
gridItems: []
},
{
gridId: '',
gridName: '格子一',
position: { x: '0', y: '0' },
siteItems: [],
gridItems: []
}
]
}
}
},
data() {
return {
contextmenu: {
isShowContextmenu: false,
x: 0,
y: 0
},
draggable: null
}
},
computed: {
handle: function() {
return 'handle' + this.grid.gridId;
}
},
watch: {
'grid.siteItems' () {
var self = this;
console.log(this)
//self.minPos();
}
},
methods: {
minPos() {
var self = this;
function setPos() {
var x, y;
$(self.draggable).children('.contentBox').children('.siteItemWrap,.grid').each(function(index, ele) {
ele = $(ele);
var disX = ele.position().left + ele.width();
var disY = ele.position().top + ele.height();
if (x == undefined) {
x = disX;
y = disY;
} else {
if (disX > x) {
x = disX;
}
if (disY > y) {
y = disY;
}
}
})
return { x, y: y + 30 };
}
if (!self.grid.isRoot) {
self.$nextTick(function() {
var minPos = setPos();
$(self.draggable).resizable("option", "minHeight", minPos.y);
$(self.draggable).resizable("option", "minWidth", minPos.x);
})
}
},
show(ev) {
var rect = ev.target.getBoundingClientRect();
this.contextmenu.x = ev.clientX - rect.left;
this.contextmenu.y = ev.clientY - rect.top;
this.$bus.$emit('isShowContextmenu', this.contextmenu);
},
addGrid() {
var self = this;
self.$bus.$emit('addGrid', self.grid, self.contextmenu);
},
moveGrid(grid) {
var self = this;
console.log(789)
self.minPos();
self.$bus.$emit('moveGrid', self.grid);
},
editGrid(grid) {
var self = this;
self.$bus.$emit('editGrid', self.grid);
},
deleteGrid() {
var self = this;
self.$bus.$emit('deleteGrid', self.grid);
},
addItem() {
var self = this;
self.$bus.$emit('addItem', self.grid, self.contextmenu);
},
deleteItem(item) {
var self = this;
self.$bus.$emit('deleteItem', self.grid, item);
},
moveItem(item) {
var self = this;
self.minPos();
self.$bus.$emit('moveItem', item)
},
resizGrid() {
var self = this;
self.minPos();
}
},
updated() {},
mounted() {
var self = this;
self.draggable = self.$refs.draggable;
self.$nextTick(function() {
if (!self.grid.isRoot) {
$(self.draggable).draggable({
handle: '.' + self.handle,
containment: "parent",
stop: function(event, ui) {
$(self.draggable).css('zIndex', self.$bus.zIndex++);
self.grid.position.x = ui.position.left;
self.grid.position.y = ui.position.top;
self.$emit('moveGrid', self.grid);
event.stopPropagation()
}
})
$(self.draggable).resizable({
stop: function(event, ui) {
self.grid.position.w = ui.size.width;
self.grid.position.h = ui.size.height;
self.$emit('resizGrid');
console.log('grid')
},
autoHide: true,
containment: "parent"
/*,
helper: "ui-resizable-helper"*/
})
self.minPos();
}
$(self.draggable).children('.contentBox').droppable({
greedy: true,
accept: '.siteItemWrap',
drop: function(event, ui) {
console.log(ui)
//ui.position.left < 0 || ui.position.top < 0||ui.position.left> ui.draggable.parent().width() ||ui.position.top> ui.draggable.parent().height()
if (ui.draggable.parent().get(0)!== this) {
ui.draggable.get(0).out = true;
var left = ui.offset.left - $(this).offset().left;
var top = ui.offset.top - $(this).offset().top;
var oVue = ui.draggable.get(0).oVue;
var grid = oVue.grid;
var item = oVue.item;
oVue.deleteItem();
item.position.x = left;
item.position.y = top;
self.$bus.$emit('addItemFromOther', self.grid, item);
}else{
console.log(1)
}
}
});
})
},
created() {
//alert('created grid')
},
name: 'gridItem',
components: { siteItem }
}
</script>
<template>
<div class="stage">
<gridItem class="rootGrid" :grid.sync="rootGrid" @click.native="close"></gridItem>
<el-dialog @contextmenu.native.prevent.stop :title="siteOption=='add'?'新增书签':'编辑书签'" :visible.sync="dialogFormVisible" size="tiny" :modal="false">
<el-form :label-position="'right'" label-width="80px" :model="form">
<el-form-item label="网址">
<el-input v-model="form.site" auto-complete="off" placeholder="请输入网址"></el-input>
</el-form-item>
<el-form-item label="名称">
<el-input v-model="form.name" auto-complete="off" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="格子">
<el-select v-model="form.grid" placeholder="请选择格子">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button v-if="siteOption=='add'" type="primary" @click="submitAddForm">确 定</el-button>
<el-button v-if="siteOption=='edit'" type="primary" @click="submitEditForm(form)">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import qs from 'qs';
import gridItem from './gridItem';
export default {
data() {
return {
rootGrid: {
gridId: '1',
gridName: '格子1',
position: { x: '0', y: '0' ,w:'500',h:'500'},
isRoot:true,
siteItems: [{
siteId: '5',
site: 'http://www.zhihu.com',
name: '知乎',
position: { x: '10', y: '20' },
isShowEdit:false
}
],
gridItems: [{
gridId: '1-1',
gridName: '格子1-1',
position: { x: '10', y: '10',w:'200',h:'100' },
siteItems: [],
gridItems: []
},
{
gridId: '1-2',
gridName: '格子1-2',
position: { x: '20', y: '20',w:'500',h:'500' },
siteItems: [{
siteId: '51',
site: 'http://www.zhihu.com',
name: '知乎1',
position: { x: '10', y: '20' },
isShowEdit:false
}],
gridItems: [
{
gridId: '1-2-1',
gridName: '格子1-2-1',
position: { x: '50', y: '50' ,w:'300',h:'100'},
siteItems: [{
siteId: '523',
site: 'http://www.zhihu.com',
name: '知乎1',
position: { x: '10', y: '20' },
isShowEdit:false
}],
gridItems: []
}
]
},
{
gridId: '1-3',
gridName: '格子1-3',
position: { x: '50', y: '50' },
siteItems: [{
siteId: '52',
site: 'http://www.zhihu.com',
name: '知乎1',
position: { x: '10', y: '20',w:'300',h:'100' },
isShowEdit:false
}],
gridItems: []
}
]
},
siteOption: "add",
currentGrid:{},
currentContextmenu:{},
currentItem:{},
dialogFormVisible: false,
form: {
siteId: '5',
site: '',
name: '',
grid: '',
position: { x: '10', y: '20' }
}
}
},
beforeUpdate() {
//alert('beforeUpdated hello')
},
updated() {
//alert('updated hello111')
},
methods: {
moveItem(item) {
var self = this;
self.currentItem = item;
},
deleteItem(grid, item) {
var self = this;
self.$axios.post('/mock/items/submitDelete', qs.stringify(item))
.then(function(response) {
self.$message({
type: 'success',
message: '删除成功'
});
var index = grid.siteItems.indexOf(item);
grid.siteItems.splice(index, 1);
})
.catch(function(error) {
console.log(error);
});
},
close(ev) {
this.currentItem.isShowEdit = false;
this.currentContextmenu.isShowContextmenu = false;
},
addGrid() {
this.gridItems.push({
gridId: '',
gridName: '格子一',
gridSites: []
})
},
editGrid() {
},
deleteGrid() {
},
submitAddForm() {
var self = this;
console.log(self.form,self.currentContextmenu,Object.assign({}, self.form),11)
self.$axios.post('/mock/items/submitAdd', qs.stringify(Object.assign({}, self.form)))
.then(function(response) {
self.$message({
type: 'success',
message: '新增成功'
});
debugger;
self.currentGrid.siteItems.push(response.data);
self.dialogFormVisible = false;
})
.catch(function(error) {
console.log(error);
});
},
submitEditForm(data, isPos) {
var self = this;
self.$axios.post('/mock/items/submitEdit', qs.stringify(data))
.then(function(response) {
if (!isPos) {
self.$message({
type: 'success',
message: '修改成功'
});
}
Object.assign(self.currentItem, JSON.parse(JSON.stringify(data)));
self.dialogFormVisible = false;
})
.catch(function(error) {
console.log(error);
});
},
init() {
var self = this;
self.$axios.get('/mock/items/all')
.then(function(response) {
console.log(response);
//response.data;
})
.catch(function(error) {
console.log(error);
});
}
},
created() {
//alert('created hello')
var self = this;
self.init();
self.$bus.$on('isShowEdit', function (item) {
self.currentItem.isShowEdit = false;
self.currentContextmenu.isShowContextmenu = false;
self.currentItem = item;
self.currentItem.isShowEdit = true;
})
self.$bus.$on('isShowContextmenu', function (contextmenu) {
self.currentItem.isShowEdit = false;
self.currentContextmenu.isShowContextmenu = false;
self.currentContextmenu = contextmenu;
self.currentContextmenu.isShowContextmenu = true;
})
self.$bus.$on('addItem', function (grid,contextmenu) {
self.currentGrid = grid;
self.currentContextmenu = contextmenu;
self.siteOption = "add";
self.form.siteId = '',
self.form.site = '',
self.form.name = '',
self.form.grid = '',
self.form.position = contextmenu;
self.dialogFormVisible = true;
})
self.$bus.$on('addItemFromOther', function (grid,item) { //新增从其他格子里移动进来的
console.log(222)
self.currentGrid = grid;
self.$axios.post('/mock/items/submitAdd', qs.stringify(Object.assign({},item)))
.then(function(response) {
self.$message({
type: 'success',
message: '移动成功'
});
self.currentGrid.siteItems.push(response.data);
})
.catch(function(error) {
console.log(error);
});
})
self.$bus.$on('editItem', function (item) {
self.currentItem = item;
self.siteOption = "edit";
Object.assign(self.form, JSON.parse(JSON.stringify(item)));
self.dialogFormVisible = true;
})
self.$bus.$on('deleteItem', function (grid, item) {
console.log(33)
self.deleteItem(grid, item);
})
},
mounted() {
//alert('mounted hello')
},
components: { gridItem }
}
</script>
大体效果如下
等会= =、
既然你讲
currentGrid和grid是同一个东西
,那么如果值发生变化self.currentGrid = grid
会触发。你可以先注释掉一个看看。
你的
siteItem.vue
组件中初步判定是
v-model="item.isShowEdit"
导致的。查调用栈,第二次触发的时候有一次
isShowEdit
的修改,至于这个值得变化是怎么引起的(可能跟element-ui的popover组件有关),你再自己看看。把上方的代码块注了就没事了,解决办法你再研究研究。