드롭다운에서 화살표 키를 사용하여 스크롤합니다(vuejs).
vuejs에서 자동 완성 부품을 만들고 있어요
그리고 그 순간 저는 스크롤 애니메이션에 갇혔습니다.
화살표 키를 클릭하여 키의 방향으로 스크롤하는 것이 목적이지만 스크롤은 옵션이 표시되지 않을 때만 실행됩니다.
이런 걸 원했는데 vue / javascript로 - http://jsfiddle.net/kMzR9/3/
화면이 작기 때문에 여기에 남겨둔 예에서 문제를 볼 수 없다면, 여기 jsfiddle - https://jsfiddle.net/v7yd94r5/가 있습니다.
여기 제가 가지고 있는 것의 예가 있습니다.
const Autocomplete = {
name: "autocomplete",
template: "#autocomplete",
props: {
items: {
type: Array,
required: false,
default: () => []
},
isAsync: {
type: Boolean,
required: false,
default: false
}
},
data() {
return {
isOpen: false,
results: [],
search: "",
isLoading: false,
arrowCounter: 0
};
},
methods: {
onChange() {
// Let's warn the parent that a change was made
this.$emit("input", this.search);
// Is the data given by an outside ajax request?
if (this.isAsync) {
this.isLoading = true;
} else {
// Let's search our flat array
this.filterResults();
this.isOpen = true;
}
},
filterResults() {
// first uncapitalize all the things
this.results = this.items.filter(item => {
return item.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
});
},
setResult(result) {
this.search = result;
this.isOpen = false;
},
onArrowDown(evt) {
if (this.arrowCounter < this.results.length) {
this.arrowCounter = this.arrowCounter + 1;
}
},
onArrowUp() {
if (this.arrowCounter > 0) {
this.arrowCounter = this.arrowCounter - 1;
}
},
onEnter() {
this.search = this.results[this.arrowCounter];
this.isOpen = false;
this.arrowCounter = -1;
},
showAll() {
this.isOpen = !this.isOpen;
(this.isOpen) ? this.results = this.items : this.results = [];
},
handleClickOutside(evt) {
if (!this.$el.contains(evt.target)) {
this.isOpen = false;
this.arrowCounter = -1;
}
}
},
watch: {
items: function(val, oldValue) {
// actually compare them
if (val.length !== oldValue.length) {
this.results = val;
this.isLoading = false;
}
}
},
mounted() {
document.addEventListener("click", this.handleClickOutside);
},
destroyed() {
document.removeEventListener("click", this.handleClickOutside);
}
};
new Vue({
el: "#app",
name: "app",
components: {
autocomplete: Autocomplete
}
});
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.autocomplete {
position: relative;
width: 130px;
}
.autocomplete-results {
padding: 0;
margin: 0;
border: 1px solid #eeeeee;
height: 120px;
overflow: auto;
width: 100%;
}
.autocomplete-result {
list-style: none;
text-align: left;
padding: 4px 2px;
cursor: pointer;
}
.autocomplete-result.is-active,
.autocomplete-result:hover {
background-color: #4aae9b;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<autocomplete :items="[ 'Apple', 'Banana', 'Orange', 'Mango', 'Pear', 'Peach', 'Grape', 'Tangerine', 'Pineapple']" />
</div>
<script type="text/x-template" id="autocomplete">
<div class="autocomplete">
<input type="text" @input="onChange" v-model="search" @keyup.down="onArrowDown" @keyup.up="onArrowUp" @keyup.enter="onEnter" @click="showAll" />
<ul id="autocomplete-results" v-show="isOpen" class="autocomplete-results">
<li class="loading" v-if="isLoading">
Loading results...
</li>
<li v-else v-for="(result, i) in results" :key="i" @click="setResult(result)" class="autocomplete-result" :class="{ 'is-active': i === arrowCounter }">
{{ result }}
</li>
</ul>
</div>
</script>
현재 요소의 위치를 확인하고 필요에 따라 스크롤 용기를 이동하는 기능이 필요합니다. 또한 아래 화살표 기능에도 문제가 있습니다.
<ul ... ref="scrollContainer" ... >
...
<li ref="options" ... >
...
</ul>
onArrowDown(ev) {
ev.preventDefault()
if (this.arrowCounter < this.results.length-1) { <--- HERE NEED -1
this.arrowCounter = this.arrowCounter + 1;
this.fixScrolling();
}
},
onArrowUp(ev) {
ev.preventDefault()
if (this.arrowCounter > 0) {
this.arrowCounter = this.arrowCounter - 1;
this.fixScrolling()
}
},
fixScrolling(){
const liH = this.$refs.options[this.arrowCounter].clientHeight;
this.$refs.scrollContainer.scrollTop = liH * this.arrowCounter;
},
const Autocomplete = {
name: "autocomplete",
template: "#autocomplete",
props: {
items: {
type: Array,
required: false,
default: () => Array(150).fill().map((_, i) => `Fruit ${i+1}`)
},
isAsync: {
type: Boolean,
required: false,
default: false
}
},
data() {
return {
isOpen: false,
results: [],
search: "",
isLoading: false,
arrowCounter: 0
};
},
methods: {
onChange() {
// Let's warn the parent that a change was made
this.$emit("input", this.search);
// Is the data given by an outside ajax request?
if (this.isAsync) {
this.isLoading = true;
} else {
// Let's search our flat array
this.filterResults();
this.isOpen = true;
}
},
filterResults() {
// first uncapitalize all the things
this.results = this.items.filter(item => {
return item.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
});
},
setResult(result, i) {
this.arrowCounter = i;
this.search = result;
this.isOpen = false;
},
onArrowDown(ev) {
ev.preventDefault()
if (this.arrowCounter < this.results.length-1) {
this.arrowCounter = this.arrowCounter + 1;
this.fixScrolling();
}
},
onArrowUp(ev) {
ev.preventDefault()
if (this.arrowCounter > 0) {
this.arrowCounter = this.arrowCounter - 1;
this.fixScrolling()
}
},
fixScrolling(){
const liH = this.$refs.options[this.arrowCounter].clientHeight;
this.$refs.scrollContainer.scrollTop = liH * this.arrowCounter;
},
onEnter() {
this.search = this.results[this.arrowCounter];
this.isOpen = false;
this.arrowCounter = -1;
},
showAll() {
this.isOpen = !this.isOpen;
(this.isOpen) ? this.results = this.items : this.results = [];
},
handleClickOutside(evt) {
if (!this.$el.contains(evt.target)) {
this.isOpen = false;
this.arrowCounter = -1;
}
}
},
watch: {
items: function(val, oldValue) {
// actually compare them
if (val.length !== oldValue.length) {
this.results = val;
this.isLoading = false;
}
}
},
mounted() {
document.addEventListener("click", this.handleClickOutside);
},
destroyed() {
document.removeEventListener("click", this.handleClickOutside);
}
};
new Vue({
el: "#app",
name: "app",
components: {
autocomplete: Autocomplete
}
});
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.autocomplete {
position: relative;
width: 130px;
}
.autocomplete-results {
padding: 0;
margin: 0;
border: 1px solid #eeeeee;
height: 120px;
overflow: auto;
width: 100%;
}
.autocomplete-result {
list-style: none;
text-align: left;
padding: 4px 2px;
cursor: pointer;
}
.autocomplete-result.is-active,
.autocomplete-result:hover {
background-color: #4aae9b;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<autocomplete />
</div>
<script type="text/x-template" id="autocomplete">
<div class="autocomplete">
<input type="text" @input="onChange" v-model="search" @keyup.down="onArrowDown" @keyup.up="onArrowUp" @keyup.enter="onEnter" @click="showAll" />
<ul id="autocomplete-results" v-show="isOpen" ref="scrollContainer" class="autocomplete-results">
<li class="loading" v-if="isLoading">
Loading results...
</li>
<li ref="options" v-else v-for="(result, i) in results" :key="i" @click="setResult(result, i)" class="autocomplete-result" :class="{ 'is-active': i === arrowCounter }">
{{ result }}
</li>
</ul>
</div>
</script>
오래된 것일 수도 있지만 스크롤인투뷰를 사용하여 스크롤할 수 있습니다.
fixScrolling() {
currentElement.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
},
언급URL : https://stackoverflow.com/questions/50927481/scroll-with-arrow-keys-on-dropdown-vuejs
'programing' 카테고리의 다른 글
g++ 링커: 정적 라이브러리가 있는 경우 정적 링크를 강제로 적용하시겠습니까? (0) | 2022.07.28 |
---|---|
구조와 유니언의 차이점 (0) | 2022.07.28 |
페이지 새로고침 후 데이터가 사라짐 - vuexfire (0) | 2022.07.28 |
Vue.js를 사용한 인덱스에 따라 렌더링된 목록 항목의 클래스는 어떻게 변경됩니까? (0) | 2022.07.28 |
nuxt.js $ 라우터 뒤에 페이지컴포넌트를 새로고침하지 않는 방법푸시() (0) | 2022.07.28 |