0

My design is that all blocks are arranged in descending order by a number I input on the screen.when I reinput the number, an animation that the block goes up or down will appear. The picture blow is more intuitive. enter image description here

These blocks are generated by reading datas from the back end.

Chat.vue
<div  v-for="arr in data">
 <chatcard
   :id="arr.id"
   :weight="arr.weight"
   :content="arr.content"
   @msg="send"
 ></chatcard>
</div>
interface dataItem {
 id: number
 weight: number
 content: string
}
let data: dataItem[] = reactive([])
onMounted(()=>{


axios.get('/api/chat').then((res)=>{
    if(res.data.code===101){
      _.forEach(res.data.data,function(arr){
        data.push({
          id: arr.id,
          weight: arr.weight,
          content: arr.content
        })
      })
    }
  })
})
chatcard.vue

 <a-card class="card">
 <a-form>
      <a-form-item label="weight">
        <a-input v-model:value="weight"  style="width:100px"></a-input>
      </a-form-item>
      <a-form-item label="content">
        <a-textarea v-model:value="content" :rows="4" show-count :maxlength="1000" allow-clear/>

      </a-form-item>
      <a-form-item>
        <a-button type="primary" @click="submit">submit</a-button>
        <a-button  @click="del" danger>delete</a-button>
      </a-form-item>
    </a-form>
    </a-card>
    const weight=ref(0)
const content=ref('')

const info = defineProps({
  id: {
    type: String,
    default: ''
  },
  weight:  {
    type: Number,
    default:0,
  },
  content: {
    type: String,
    default: ''
  }
})

onMounted(()=>{
  weight.value=info.weight
  content.value=info.content
})

const emit = defineEmits(['msg'])

const submit=()=>{
  let paramm = {
    id: info.id,
    weight: info.weight,
    content: info.content
  }
  emit('msg', paramm)
}

const del=()=>{
  let paramm = {
    id: info.id,
    flag: 1
  }
  emit('msg', paramm)
}


  .card{
  width: 80vw;
  height: 250px;
  margin-left: 80px;
  background-color: white;
  margin-bottom: 30px;
}

The codes above is part of my codes. To accomplish my effect, I need every chatcard's position, but where is it? And how do I get the distance of swaped chatcards?

delia
  • 11
  • 3
  • I don't think you're going to accomplish this with pure CSS - is JavaScript on the table, or no? – Jake Mar 06 '23 at 07:49
  • Yes, not with pure CSS. My expression is not enough clear. Obviously, JavaScript is nessary. What confuses me is that I know the order, but I dont'know how to translate A to B and B to A. I use the Vue, chatcard is a children component and generated dynamicly. I don't know its id and concrete position. – delia Mar 06 '23 at 09:10

1 Answers1

0

If you need a CSS-only solution, I don't think this is possible (although I'm happy to be proven wrong by another poster).

One barebones way to do it would be using the CSS order property combined with a flexbox:

.container{
  display: flex;
  flex-direction: column;
  width: 300px;
}

input{
  margin: 20px;
}
<div class="container">
  <input oninput="this.style.order=this.value"/>
  <input oninput="this.style.order=this.value"/>
  <input oninput="this.style.order=this.value"/>
</div>

We subscribe to the oninput event here to update the order of the elements; this is a very minimal amount of JS. This solution has the (potentially large) downside of not being possible to animate, so if you wanted to smoothly slide the elements up & down into their new positions, then you could look into a solution like this one, or a more in-depth JS solution involving absolute positioning with a transition on the top, like this:

var inputs = [...document.querySelectorAll("input")];

function onInput(){
    inputs.sort((a, b) => (+a.value > 0 ? +a.value : 0) - (+b.value > 0 ? +b.value : 0));
  
  for (var i = 0; i < inputs.length; i++)
  {
    inputs[i].style.top = (i * 50) + "px";
  }
}
.container{
  width: 300px;
  position: relative;
}

input{
  margin: 20px;
  position: absolute;
  transition: all 1s;
}
<div class="container">
  <input oninput="onInput()" style="top: 0px"/>
  <input oninput="onInput()" style="top: 50px"/>
  <input oninput="onInput()" style="top: 100px"/>
</div>

You probably want to do some validation that the input is actually a number and not a string or other garbage, but hopefully this gets the idea across.

Jake
  • 862
  • 6
  • 10