我正在使用VueJS并具有像这样动态创建的嵌套元素:
<container>
<outerElement class="outer" v-for="obj in objects">
<innerElement class="inner" v-for="element in obj"/>
</outerElement>
</container>
现在谈到CSS时,我遇到了一个小问题。由于innerElement旨在可移动,因此它们需要外部元素具有与容器相同的大小/位置。
CSS中是否有某种方法可以将“盒子”模型从“外部”类中移除,同时保留在容器中?
为解决上述XY问题,这是简化版的模板,使用与我的应用程序相同的实现方法。
<template>
<div class="home">
<h1>This is the main Page.</h1>
<h2>Testing area:</h2>
<br />Simple Data Example:
<br />
<div class="container">
<button @click="simpleXOR()">XOR</button>
{{ data }}
<vue-draggable-resizable
class="simple"
v-for="(bit,index) in simpleData"
:key="index"
:w="50"
:h="50"
:parent="true"
:resizable="false"
>
{{`Bit-${index} => `}}
<status-indicator :status="bit ? 'positive' : 'negative'" />
</vue-draggable-resizable>
</div>
<br />Nested Data Example
<div class="container">
<div class="outer" v-for="obj in nestedObj.data" :key="obj.name">
<div class="label">
<button @click="nestedXOR(obj.name)">XOR -> {{ obj.name }}</button>
{{ obj.states }}
</div>
<vue-draggable-resizable
class="inner"
v-for="(state, index) in obj.states"
:key="index"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div v-if="obj.contentType === 'TypeA'">
<b>{{ `Bit-${index} of ${obj.name}` }}</b>
<br />
<status-indicator :status="state ? 'positive' : 'negative'" />
</div>
<div v-else>
<b>{{ `Bit-${index} of ${obj.name}` }}</b>
<br />
<status-indicator :status="state ? 'active' : 'intermediary'" />
</div>
</vue-draggable-resizable>
</div>
</div>
</div>
</template>
<script>
// @ is an alias to /src
export default {
name: "home",
components: {},
data() {
return {
simpleData: [0, 1, 0, 1],
nestedObj: {
data: [
{
states: [0, 1, 0, 1],
name: "a",
contentType: "TypeA"
},
{
states: [0, 1, 0, 1],
name: "b",
contentType: "TypeB"
}
]
}
};
},
computed: {
data() {
return this.simpleData;
}
},
methods: {
simpleXOR() {
var x = [];
for (var i = 0; i < this.simpleData.length; i++) {
x.push(this.simpleData[i] ^ 1);
}
this.simpleData = x;
console.debug(this.simpleData);
},
nestedXOR(name) {
var index = this.nestedObj.data.findIndex(obj => {
return obj.name === name;
});
var x = [];
for (var i = 0; i < this.nestedObj.data[index].states.length; i++) {
x.push(this.nestedObj.data[index].states[i] ^ 1);
}
this.nestedObj.data[index].states = x;
}
}
};
</script>
<style scoped>
.container {
margin: auto;
height: 200px;
width: 1000px;
border: 2px solid black;
position: relative;
}
.simple {
top: 0px;
left: 0px;
}
.outer {
display: contents; /* as suggested */
}
.inner {
/* ??? */
}
.label {
border: 1px dashed green;
padding: 10px;
height: 20%;
width: 20%;
}
/* // This is the css for vue-draggable-resizable */
/* // DON'T EDIT unless customization is needed */
.vdr {
touch-action: none;
position: absolute;
box-sizing: border-box;
border: 1px dashed black;
}
.handle {
box-sizing: border-box;
position: absolute;
width: 10px;
height: 10px;
background: #eee;
border: 1px solid #333;
}
.handle-tl {
top: -10px;
left: -10px;
cursor: nw-resize;
}
.handle-tm {
top: -10px;
left: 50%;
margin-left: -5px;
cursor: n-resize;
}
.handle-tr {
top: -10px;
right: -10px;
cursor: ne-resize;
}
.handle-ml {
top: 50%;
margin-top: -5px;
left: -10px;
cursor: w-resize;
}
.handle-mr {
top: 50%;
margin-top: -5px;
right: -10px;
cursor: e-resize;
}
.handle-bl {
bottom: -10px;
left: -10px;
cursor: sw-resize;
}
.handle-bm {
bottom: -10px;
left: 50%;
margin-left: -5px;
cursor: s-resize;
}
.handle-br {
bottom: -10px;
right: -10px;
cursor: se-resize;
}
@media only screen and (max-width: 768px) {
[class*="handle-"]:before {
content: "";
left: -10px;
right: -10px;
bottom: -10px;
top: -10px;
position: absolute;
}
}
</style>
当前,此代码中的问题是innerElements不能在容器内移动,因为externalElement是它们的容器。
由于我无法更改父选择器以使用容器而不是externalElement,因此很难更改。
因此,我想使outerElements边界不存在,以便innerElement将容器用作父项。
但是考虑到vue-draggable-resizable组件将无论如何都使用externalElement作为父级,我想我的想法有点奇怪。
可移动框不能在容器内移动,因为outsideElement不会继承容器的位置和大小。
答案 0 :(得分:2)
尝试在display:contents
元素上使用CSS outer
。这个display property基本上使元素对浏览器“不可见”。
但是,我认为您最好重构Vue模板以删除外部元素。例如,您可以在执行循环之前处理objects数组以合并其子级。
答案 1 :(得分:1)
对于您的简单示例,您可以在迭代之前仅flatten the nested array:
<container>
<innerElement class="inner" v-for="element in objects.flat(1)" />
</container>
您发布的更复杂的示例有些棘手,因为内部循环还需要访问obj
。尽管如此,您仍可以通过编写一个自定义方法来实现此目的,该方法将每个状态包装在一个包装器中,该包装器既包含状态又包含对其所属对象的引用,如下所示:
<div class="container">
<div class="label" v-for="obj in nestedObj.data" :key="obj.name">
<button @click="nestedXOR(obj.name)">XOR -> {{ obj.name }}</button>
{{ obj.states }}
</div>
<vue-draggable-resizable
class="inner"
v-for="wrapper in flattenStates(nestedObj.data)"
:key="wrapper.key"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div v-if="wrapper.obj.contentType === 'TypeA'">
<b>{{ `Bit-${wrapper.index} of ${wrapper.obj.name}` }}</b>
<br />
<status-indicator :status="wrapper.state ? 'positive' : 'negative'" />
</div>
<div v-else>
<b>{{ `Bit-${wrapper.index} of ${wrapper.obj.name}` }}</b>
<br />
<status-indicator :status="wrapper.state ? 'active' : 'intermediary'" />
</div>
</vue-draggable-resizable>
</div>
flattenStates
方法看起来像这样:
flattenStates: function (objects) {
return objects.flatMap( obj => {
return obj.states.map( (state, index) => {
return {
obj: obj,
state: state,
index: index,
key: obj.name + " state " + index
};
} );
} );
}
兼容性说明:.flat()
和.flatMap()
在IE或Edge的当前稳定版本上不可用。要使这些代码在那些浏览器上运行,您需要一个polyfill。但是,基于Chromium的基于Chromium的新版本在撰写本文时仍处于beta版,但同时支持这两种版本。
或者,您可以通过将一些逻辑移至flattenStates
方法中来简化模板:
<div class="container">
<!-- label divs omitted for brevity -->
<vue-draggable-resizable
class="inner"
v-for="wrapper in flattenStates(nestedObj.data)"
:key="wrapper.title"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div>
<b>{{ wrapper.title }}</b>
<br />
<status-indicator :status="wrapper.status" />
</div>
</vue-draggable-resizable>
</div>
flattenStates: function (objects) {
return objects.flatMap( obj => {
return obj.states.map( (state, index) => {
const wrapper = {
title: `Bit-${index} of ${obj.name}` // also used as :key
};
if (obj.contentType === 'TypeA') {
wrapper.status = (state ? 'positive' : 'negative');
} else {
wrapper.status = (state ? 'active' : 'intermediary');
}
return wrapper;
} );
} );
}
...甚至:
<div class="container">
<!-- label divs omitted for brevity -->
<vue-draggable-resizable
class="inner"
v-for="(status, title) in flattenStates(nestedObj.data)"
:key="title"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div>
<b>{{ title }}</b>
<br />
<status-indicator :status="status" />
</div>
</vue-draggable-resizable>
</div>
flattenStates: function (objects) {
const objStates = {};
for (const obj of objects) {
obj.states.forEach( (state, index) => {
const title = `Bit-${index} of ${obj.name}`;
if (obj.contentType === 'TypeA') {
objStates[title] = (state ? 'positive' : 'negative');
} else {
objStates[title] = (state ? 'active' : 'intermediary');
}
} );
}
return objStates;
}