3

I'm trying to create a a component that overlaps over the user icons just as shown in the photo. I've seen this being used on google. If I have a list of user icons, how do I overlap them over each other?

I want something like this enter image description here.

<template>
    <div >
    <ul>
      <li v-for="user in userList" :key="user.key">
        <user-icon-component :name="user.name" :image="user.picture"></user-icon-component>
      </li>
    </ul>
    </div>
</template>


<script>
export default {
  name: "UserList",
  props: {
    userList: {
      type: Object,
      default: null,
    },
  },
};
</script>

<style>

</style>
vuenewb
  • 99
  • 9

2 Answers2

2

The icon component is just an <img> tag with a user prop:

Vue.component('user-icon-component', {
  props: ['user'],
  template: `
  <img :src="user.picture" width="32" height="32" />
  `
})

Give the <li>s position: absolute and the <ul> position: relative to pull them out of the normal document flow. Set the left position on each <li> as a calculation from the index of the loop:

<ul class="icon-container">
  <li v-for="(user, key, i) in userList" :key="user.key"
      class="icon" :style="{ left: `${i * 20}px` }">
    <user-icon-component :user="user"></user-icon-component>
  </li>
</ul>

Here's a demo:

Vue.component('user-icon-component', {
    props: ['user'],
  template: `
  <img :src="user.picture" width="32" height="32" />
  `
})

/***** APP *****/
new Vue({
  el: "#app",
  data() {
    return {
        userList: {
        'Bob': { name: 'Bob', key: 1, picture: 'https://www.flaticon.com/svg/static/icons/svg/3084/3084430.svg' },
        'Mary': { name: 'Mary', key: 2, picture: 'https://www.flaticon.com/svg/static/icons/svg/3084/3084431.svg' },
        'Paul': { name: 'Paul', key: 3, picture: 'https://www.flaticon.com/svg/static/icons/svg/3084/3084452.svg' },
      }
    }
  },
});
.icon-container {
  position: relative;
}
.icon {
  position: absolute;
}
ul {
  list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <ul class="icon-container">
    <li v-for="(user, key, i) in userList" :key="user.key"
        class="icon" :style="{ left: `${i * 20}px` }">
      <user-icon-component :user="user"></user-icon-component>
    </li>
  </ul>
</div>
Dan
  • 59,490
  • 13
  • 101
  • 110
  • I did exactly as you did but it isn't even showing the circle icons. the circle component accepts `:name` and ':picture`. the way I did, is it correct to send them like that? – vuenewb Dec 16 '20 at 18:25
  • 1
    You could pass the properties individually like that, but I think it makes more sense to pass the whole `user` object. It works either way. Maybe try to copy and paste the code from the answer in case something is different than you realize – Dan Dec 16 '20 at 18:26
  • It says that `Invalid prop: type check failed for prop "userList". Expected Object, got Array ` @Dan Now the circles show but the pictures don't show.. – vuenewb Dec 16 '20 at 18:42
  • I did exactly what you did. Not sure why it says that it got an array – vuenewb Dec 16 '20 at 18:44
  • I'm using storybooks. and it all shows [object Object] in the props area – vuenewb Dec 16 '20 at 18:48
  • the date will come from the server in json array of pictures of name and picture format. so I can't change the format of the props. Is it possible to get the name and picture out of that array of object? – vuenewb Dec 16 '20 at 18:56
  • 1
    That does not change whether you can pass the `user`. My first answer was for an array of objects and I updated it because you said it's an object of objects. I think you'll need to post your code to https://www.codesandbox.io with an example of all of your data because i've already shown both ways – Dan Dec 16 '20 at 18:59
2

I liked the idea in your question and took it as a challenge for myself and here is the result:

vue overlapping avatars component

basically the approach I took was to use the component's props as style in style binding. there are some scoped style as well but I think they can be set in the style binding as well if needs be (probably the code could be cleaner).

user prop is an array of objects that contains this property: img: 'imageURL' and using a v-for on a div element with:

:style="{ backgroundImage: `url(${user.img})`}"

we can set the images.

as for the overlapping part, divs have position: relative and using the index of v-for, the style binding becomes like this:

:style="{backgroundImage: `url(${user.img})`, left: `-${i*15}px`}"

which shifts every element to the left by 15px except for the first one.

here is the image of the final result:

enter image description here

Thanks for your question, it was fun :)

hamid niakan
  • 2,668
  • 1
  • 12
  • 25