Я пытаюсь реализовать экранную клавиатуру для ввода чисел в различные поля ввода. В реальном проекте их несколько десятков. Я сохраняю активное поле через фокус, и когда я нажимаю на число, оно добавляется в конец значения поля. Но когда я меняю значение ввода, значение связанной v-модели не меняется. Хотя, когда захожу с обычной клавиатуры, все меняется нормально. прилагаю пример кода
<template>
<p>xSize</p>
<input v-model = "xSize">
<p>ySize</p>
<input v-model = "ySize">
<div class = "keyboard">
<button v-for = "i in [1,2,3,4,5,6,7,8,9,0]" class = "key" :key = "i" @click = "addChar(i)">{{i}}</button>
</div>
<p>xSize = {{xSize}}</p>
<p>ySize = {{ySize}}</p>
<div class = "test-box" v-bind:style = "{width: this.xSize + 'px', height: this.ySize + 'px'}"></div>
</template>
<script>
export default {
data: function () {
return {
xSize: 50,
ySize: 50,
activeElement: null
}
},
props: {
},
created() {
document.addEventListener('focusin', this.focusChanged)
},
beforeUnmount() {
document.removeEventListener('focusin', this.focusChanged)
},
methods: {
focusChanged: function (event) {
const el = event.target
if (el.type === "text") {
if (this.activeElement !== el && this.activeElement !== null) {
this.activeElement.style.background = "white";
}
this.activeElement = el
this.activeElement.style.background = "red";
}
},
addChar: function (char) {
if (this.activeElement !== null) {
this.activeElement.value += char
}
}
}
}
</script>
<style scoped>
.keyboard {
display: flex;
}
.key {
margin: 3px;
width: 30px;
height: 30px;
border: 2px black ridge;
}
.test-box {
border: 2px black ridge;
background: red;
margin: 15px;
}
</style>
Пример
попробуйте проверить что-то вроде:
<input v-model = "xSize" @input = "updateSize('xSize', $event.target.value)">
@input
событие в полях ввода, чтобы гарантировать, что любое изменение входного значения фиксируется и обрабатывается методом updateSize,updateSize
вызывается с соответствующим типом размера (xSize или ySize) и новым значением. Этот метод обновляет соответствующее свойство в экземпляре Vue.Потому что вы изменили только значение элемента, а не реагирующие данные в данных.
Я понимаю, это. Вопрос в том, можно ли как-то изменить эти адаптивные данные через элемент. Или по событию щелкните доступ к адаптивным данным.
Конечно. Я добавил код в другой ответ, вы можете посмотреть.
Пожалуйста, взгляните на следующий пример (вы можете использовать событие @focus
и преобразовать код в API-интерфейс опций, если вам так нравится :))
const { ref, computed } = Vue
const app = Vue.createApp({
setup() {
const xSize = ref(50)
const ySize = ref(50)
const activeElement = ref('x')
const operation = ref('+')
const isActive = (el) => {
return activeElement.value === el ? 'active' : ''
}
const addChar = (char) => {
if (operation.value === '+') {
activeElement.value === 'x' ?
xSize.value = +xSize.value + char :
ySize.value = +ySize.value + char
} else {
activeElement.value === 'x' ?
xSize.value = +xSize.value >= +char ? +xSize.value - char : +xSize.value :
ySize.value = +ySize.value >= +char ? +ySize.value - char : +ySize.value
}
}
const setSize = computed(() => {
return {
width: xSize.value + 'px',
height: ySize.value + 'px'
}
})
return {
xSize, ySize, activeElement, addChar, isActive, operation, setSize
}
},
})
app.mount("#demo");
.keyboard {
display: flex;
}
.key {
margin: 3px;
width: 30px;
height: 30px;
border: 2px black ridge;
}
.test-box {
border: 2px black ridge;
background: red;
margin: 15px;
}
.active {
background: red;
color: white;
}
button {
cursor: pointer;
}
<script src = "https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id = "demo">
<div>
<span>xSize </span>
<input v-model = "xSize" :class = "isActive('x')" @focus = "activeElement = 'x'">
</div>
<div>
<span>ySize </span>
<input v-model = "ySize" :class = "isActive('y')" @focus = "activeElement = 'y'">
</div>
<div class = "keyboard">
<button @click = "operation = operation === '+' ? '-' : '+'" class = "key">{{ operation }}</button>
<button v-for = "i in 10" class = "key" :key = "i" @click = "addChar(i)">{{ i }}</button>
</div>
<div class = "test-box" :style = "setSize"></div>
</div>
Спасибо за ответ. Честно говоря, мне бы хотелось избежать этого решения, поскольку в реальном проекте оно привело бы к очень большой конструкции «переключателя».
Потому что вы изменили только значение элемента, а не реагирующие данные в данных.
Вы можете изменить код таким образом.
<template>
<p>xSize</p>
<input v-model = "xSize" data-name = "xSize">
<p>ySize</p>
<input v-model = "ySize" data-name = "ySize">
<div class = "keyboard">
<button v-for = "i in [1,2,3,4,5,6,7,8,9,0]" class = "key" :key = "i" @click = "addChar(i)">{{i}}</button>
</div>
<p>xSize = {{xSize}}</p>
<p>ySize = {{ySize}}</p>
<div class = "test-box" v-bind:style = "{width: this.xSize + 'px', height: this.ySize + 'px'}"></div>
</template>
<script>
export default {
data: function () {
return {
xSize: 50,
ySize: 50,
activeElement: null
}
},
props: {
},
created() {
document.addEventListener('focusin', this.focusChanged)
},
beforeUnmount() {
document.removeEventListener('focusin', this.focusChanged)
},
methods: {
focusChanged: function (event) {
const el = event.target
if (el.type === "text") {
if (this.activeElement !== el && this.activeElement !== null) {
this.activeElement.style.background = "white";
}
this.activeElement = el
this.activeElement.style.background = "red";
}
},
addChar: function (char) {
if (this.activeElement !== null) {
const fieldName = this.activeElement.getAttribute("data-name");
this[fieldName] += char
}
}
}
}
</script>
<style scoped>
.keyboard {
display: flex;
}
.key {
margin: 3px;
width: 30px;
height: 30px;
border: 2px black ridge;
}
.test-box {
border: 2px black ridge;
background: red;
margin: 15px;
}
</style>
Да, ваше решение мне помогло. Большое спасибо за помощь!
Спасибо за ответ. Увы, событие @input не срабатывает при нажатии клавиш.