Vue .exact modifier test
by ChangJoo Park
HTML
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
<div id="app">
<div>
<h2>Desktop using Vue.js 2.5.x </h2>
<p><strong>Click</strong> a Icon, <strong>Click(+ Ctrl)</strong> Icons, <strong>Click</strong> blank area</p>
<div class="frame">
<div class="frame-header">
<i class="fa fa-folder-o" aria-hidden="true"></i>
<span>File Explorer</span>
</div>
<div class="frame-body" @click="resetSelectedIcons">
<div class="icons">
<div class="icon" :class="{ active: isSelected(icon)}" v-for="icon in icons" :key="icon.id" @click.exact.stop="selectIcon(icon)" @click.ctrl.exact.stop="multiSelectIcons(icon)"
@click.meta.exact.stop="multiSelectIcons(icon)">
<i class="fa fa-5x icon-image" :class="`fa-${icon.image}`"></i>
<span class="icon-name">{{icon.name}}</span>
</div>
</div>
</div>
<div class="frame-footer">
<span>{{ iconCount }}</span>
<span>{{ selectedIconCount }}</span>
</div>
</div>
<hr>
<div class="debug">
<pre>{{selected}}</pre>
</div>
</div>
</div>
SCSS
* {
box-sizing: border-box;
}
.frame {
outline: 1px solid #1883d7;
.frame-header {
padding: 5px;
height: 30px;
outline: 1px solid #ddd;
}
.frame-body {
padding: 5px;
height: 200px;
overflow: auto;
}
.frame-footer {
height: 20px;
outline: 1px solid #ddd;
}
}
.icons {
display: flex;
flex-wrap: wrap;
align-items: center;
overflow: auto;
.icon {
flex: 1;
display: flex;
max-width: 200px;
align-items: center;
user-select: none;
padding: 10px;
margin: 5px;
&:hover {
background-color: rgba(3, 166, 255, 0.3);
}
&.active {
outline: solid rgba(3, 166, 255, 0.9);
background-color: rgba(3, 166, 255, 0.3);
}
.icon-name {
margin-left: 5px;
}
}
}
JavaScript
new Vue({
el: '#app',
mounted: function() {
this.icons = [{
id: 1,
image: 'desktop',
name: 'My Computer'
}, {
id: 2,
image: 'github',
name: 'Github'
}, {
id: 3,
image: 'folder-o',
name: 'Documents'
}, {
id: 4,
image: 'terminal',
name: 'Terminal'
}, {
id: 5,
image: 'chrome',
name: 'Chrome'
}]
this.selected = [this.icons[1], this.icons[2]]
},
data: function() {
return {
selected: [],
icons: []
}
},
computed: {
iconCount: function () {
const count = this.icons.length
return count < 2 ? `${count} Item` : `${count} Items`
},
selectedIconCount: function () {
const count = this.selected.length
if (count === 0) {
return ''
} else if (count === 1) {
return '1 Item selected'
} else {
return `${count} Items selected`
}
}
},
methods: {
selectIcon: function(clickedIcon) {
this.selected = [clickedIcon]
},
multiSelectIcons: function(clickedIcon) {
if (this.isSelected(clickedIcon)) {
const index = this.selected.indexOf(clickedIcon)
this.selected.splice(index, 1)
} else {
this.selected.push(clickedIcon)
}
},
resetSelectedIcons: function() {
this.selected = []
},
isSelected: function(icon) {
return this.selected.includes(icon)
}
}
})