我怎样才能让一个元素失去它的盒子模型?

时间:2019-09-10 21:36:32

标签: html css vue.js

我正在使用VueJS并具有像这样动态创建的嵌套元素:

<container>
  <outerElement class="outer" v-for="obj in objects">
    <innerElement class="inner" v-for="element in obj"/>
  </outerElement>
</container>

现在谈到CSS时,我遇到了一个小问题。由于innerElement旨在可移动,因此它们需要外部元素具有与容器相同的大小/位置。

CSS中是否有某种方法可以将“盒子”模型从“外部”类中移除,同时保留在容器中?

这是我要实现的目标的草图。 sketch


编辑:

为解决上述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作为父级,我想我的想法有点奇怪。

这是问题的屏幕截图: screenshot

可移动框不能在容器内移动,因为outsideElement不会继承容器的位置和大小。

2 个答案:

答案 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;
}