Vue学习记录-v-model

2020年5月12日

<div id="app">
    <!-- <input type="text" v-model="message"> -->
    <input type="text" :value="message" @input="valueChange">
    <!-- v-model双向绑定实现 -->
    <input type="text" :value="message" @input="message = $event.target.value">
    <h2>{{message}}</h2>

  </div>
  <script src="../js/vue.js">
  </script>
  <script>
     const app = new Vue({
        el: '#app',
        data: {
          message: 'hello'
        },
        methods: {
          valueChange(event){
            this.message = event.target.value
          }
        }
     })
  </script>

radio:

<div id="app">
    <label for="male">
      <input type="radio" id="male" value="男" v-model="sex">男
    </label>
    <label for="female">
      <input type="radio" id="female" value="女" v-model="sex">女
    </label>
    <h2>您选择的是{{sex}}</h2>
  </div>
  <script src="../js/vue.js">
  </script>
  <script>
     const app = new Vue({
        el: '#app',
        data: {
          message: 'hello',
          sex: '男'
        }
     })
  </script>

checkbox:

<div id="app">
    <label for="license">
      <input type="checkbox" id="license" v-model="isli">同意协议
    </label>
    <button :disabled="!isli">下一步</button>
    <div></div>
    <input type="checkbox" value="篮球" v-model="hobbies">篮球
    <input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球
    <input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球
    <input type="checkbox" value="足球" v-model="hobbies">足球
    <h2>您的爱好是{{hobbies}}</h2>
  </div>
  <script src="../js/vue.js">
  </script>
  <script>
     const app = new Vue({
        el: '#app',
        data: {
          message: 'hello',
          isli: false,
          hobbies: []
        }
     })
  </script>

select:

<div id="app">
  <select name="abc" id="" v-model="fruit">
    <option value="苹果" >苹果</option>
    <option value="香蕉" >香蕉</option>
    <option value="葡萄" >葡萄</option>
  </select>
  <div></div>
  <select name="abc" id="" v-model="fruits" multiple>
    <option value="苹果" >苹果</option>
    <option value="香蕉" >香蕉</option>
    <option value="葡萄" >葡萄</option>
  </select>
  
  </div>
  <script src="../js/vue.js">
  </script>
  <script>
     const app = new Vue({
        el: '#app',
        data: {
          message: 'hello',
          fruit: "香蕉",
          fruits: []
        }
     })
  </script>

值绑定:

<div id="app">
    <label v-for="item in originHobbies" :for="item">
      <input type="checkbox" :value="item" id="item" v-model="hobbies">{{item}}
    </label>
    <h2>您的爱好:{{hobbies}}</h2>
  </div>
  <script src="../js/vue.js">
  </script>
  <script>
     const app = new Vue({
        el: '#app',
        data: {
          message: 'hello',
          hobbies: [],
          originHobbies: ["篮球","足球","乒乓球","羽毛球","台球","高尔夫球"]
        }
     })
  </script>

修饰符:

<div id="app">
    <label v-for="item in originHobbies" :for="item">
      <input type="checkbox" :value="item" id="item" v-model="hobbies">{{item}}
    </label>
    <h2>您的爱好:{{hobbies}}</h2>
  </div>
  <script src="../js/vue.js">
  </script>
  <script>
     const app = new Vue({
        el: '#app',
        data: {
          message: 'hello',
          hobbies: [],
          originHobbies: ["篮球","足球","乒乓球","羽毛球","台球","高尔夫球"]
        }
     })
  </script>

 

<think>我们有一个需求:在Vue 2中使用v-model,并且希望在输入时使用replace方法处理输入的数据(例如,只允许输入数字)。 根据引用[1]和引用[2],我们可以知道: 1. v-model用于双向数据绑定,通常用于表单元素。 2. 我们可以通过事件处理(如v-on:input)来修改输入的值。 引用[1]提供了几种方法: 方法1:直接在input元素上使用oninput事件(但这是原生JS,在Vue中我们可以用v-on:input) 方法2:封装一个方法,在v-on:input中调用该方法,并在方法中使用replace替换非数字字符。 方法3:封装成全局方法,通过Vue.prototype添加,这样在任何组件中都可以使用。 但是,注意:v-model实际上是一个语法糖,它相当于绑定了value属性(或组件的model)和监听input事件(对于输入框)或change事件(对于其他控件)。 因此,如果我们想要在输入时过滤非数字字符,我们可以这样做: 方案: 1. 不使用v-model,而是使用:value绑定数据,然后使用@input事件处理输入,并在事件处理函数中修改数据。 2. 在事件处理函数中,使用replace方法将非数字字符替换为空字符串,然后将处理后的值赋给数据。 例如: <input type="text" :value="inputValue" @input="handleInput"> 在Vue实例中: data: { inputValue: '' }, methods: { handleInput(event) { // 使用replace替换非数字字符 let value = event.target.value.replace(/\D/g, ''); // 将处理后的值赋给inputValue this.inputValue = value; // 注意:由于我们替换了非数字字符,所以显示的值会立即被修正 } } 但是,如果我们想使用v-model,同时又要对输入进行过滤,我们可以使用计算属性的setter和getter,或者使用watch。但是,在输入过程中,我们更倾向于实时处理,所以使用@input事件更直接。 然而,引用[1]也展示了另一种方式:在v-model绑定的同时,使用v-on:input事件来调用一个方法,并在该方法中修改绑定的值。例如: <input type="text" v-model="value" v-on:input="value = onlyNum(value)"> 其中,onlyNum方法定义在methods中: onlyNum(value) { return value.replace(/\D/g, ''); } 但是,注意:这种方式可能会导致光标位置问题,因为每次输入都会修改整个字符串,光标会跳到末尾。所以,对于需要保持光标位置的场景,我们需要更复杂的处理。 因此,我们推荐使用第一种方案(拆分v-model为:value和@input),因为这样我们可以更灵活地控制。但是,如果我们不关心光标位置,第二种方案更简洁。 另外,引用[1]还提到了全局方法的封装,我们可以将onlyNum方法挂载到Vue原型上,这样在任何组件中都可以使用。 步骤: 1. 在main.js中定义全局方法: Vue.prototype.$num = function(value) { return value.replace(/\D/g, ''); } 2. 在组件中使用: <input type="text" v-model="value" v-on:input="value = $num(value)"> 但是,注意:在模板中直接调用方法并赋值,可能会引起性能问题,因为每次输入都会触发。不过,对于简单的替换,通常是可以接受的。 另外,我们还可以使用自定义指令来实现,这样更优雅。但是,根据引用[3]和引用[4],我们没有直接看到自定义指令的例子,但我们可以自行实现。 自定义指令示例(可选方案): 我们可以注册一个全局指令,比如v-num,这样在输入框上使用v-num就可以自动过滤非数字字符。 在main.js中: Vue.directive('num', { bind: function (el, binding, vnode) { // 我们监听input事件 el.addEventListener('input', function (event) { let value = event.target.value; let newValue = value.replace(/\D/g, ''); // 如果值被修改了,我们需要更新输入框的值 if (newValue !== value) { event.target.value = newValue; // 触发input事件,让v-model更新 event.target.dispatchEvent(new Event('input')); } }); } }); 然后在组件中: <input type="text" v-model="value" v-num> 这样,我们就将逻辑封装在指令中,使得模板更简洁。 总结: 有几种方法可以在Vue2中使用v-model并利用replace方法处理输入数据: 1. 拆分v-model,使用:value和@input,并在事件处理函数中手动替换并赋值。 2. 使用v-model和v-on:input,并在模板中直接调用一个替换方法(可以是局部方法或全局方法)。 3. 使用自定义指令(推荐,因为可以复用且不污染模板逻辑)。 根据需求选择合适的方法。 注意:在方法2中,由于我们直接修改了绑定的值,可能会导致光标位置问题。如果输入中间插入非数字字符,光标会跳到末尾。而自定义指令中,我们是在事件处理函数中修改DOM的值,然后触发input事件,这样Vue会更新数据,同时光标位置可能会被重置(但我们在事件处理函数中修改了DOM,所以光标会跳到末尾)。要解决光标位置问题,需要记录光标位置并在替换后恢复,这稍微复杂一些。 如果对光标位置没有要求,可以使用简单的方法。如果有要求,可能需要更复杂的处理。 下面给出一个解决光标位置问题的示例(在自定义指令中): Vue.directive('num', { bind: function (el) { el.addEventListener('input', function (event) { let start = event.target.selectionStart; let end = event.target.selectionEnd; let value = event.target.value; let newValue = value.replace(/\D/g, ''); if (newValue !== value) { event.target.value = newValue; // 触发input事件 event.target.dispatchEvent(new Event('input')); // 恢复光标位置(因为替换后字符串长度可能变短,所以光标位置需要调整) // 计算光标位置:因为删除了非数字字符,所以光标位置应该减去被删除的字符数(从开始到原光标位置) // 但是这里我们简单处理:将光标设置到原位置(但实际上,因为删除了字符,光标位置应该前移,所以我们可以尝试计算删除的字符数) // 更简单的方法:记录新字符串中,从开始到原光标位置(不包括非数字)的字符数 // 这里我们不做复杂处理,直接设置回原来的位置(减去被删除的字符数并不容易,所以我们可以尝试将光标设置在当前位置减去删除的字符数?) // 另一种思路:计算从开始到光标开始位置有多少个非数字字符,然后光标位置减去这个数量 // 这里我们选择重新计算光标位置:新位置 = 原位置 - (原字符串长度 - 新字符串长度) ? 不准确,因为可能删除的是中间字符 // 实际上,我们可以在替换前记录光标位置,然后替换后,光标位置应该等于原位置减去(从0到原位置之间被删除的字符数) let diff = value.length - newValue.length; // 但是,我们不知道被删除的字符具体在什么位置,所以不能简单减去diff。我们可以计算0到原位置(start)之间有多少个非数字字符? let nonDigitCount = 0; for (let i = 0; i < start; i++) { if (/\D/.test(value[i])) { nonDigitCount++; } } let newStart = start - nonDigitCount; let newEnd = end - (diff + nonDigitCount); // 这里简化处理,实际上end位置也类似 // 但是注意:我们只替换了非数字字符,所以新字符串中,从0到newStart的字符都是数字,并且长度是newStart event.target.setSelectionRange(newStart, newEnd); } }); } }); 这个处理光标位置的方法较为复杂,如果对光标位置要求不高,可以忽略。 因此,根据需求复杂度选择方案: 简单场景:使用方法2(全局方法或局部方法)或自定义指令(不处理光标位置)。 复杂场景(需要保持光标位置):使用自定义指令并处理光标位置,或者使用更复杂的组件(如使用input事件处理函数,并在函数中修改值的同时调整光标位置)。 下面我们给出一个简单的实现示例(不处理光标位置),使用全局方法: 步骤1:在main.js中定义全局方法 Vue.prototype.$num = function(value) { return value.replace(/\D/g, ''); } 步骤2:在组件中使用 <template> <input type="text" v-model="value" @input="value = $num(value)"> </template> <script> export default { data() { return { value: '' } } } </script> 或者使用局部方法: <template> <input type="text" v-model="value" @input="value = onlyNum(value)"> </template> <script> export default { data() { return { value: '' } }, methods: { onlyNum(value) { return value.replace(/\D/g, ''); } } } </script> 注意:在模板中,我们使用@input事件(v-on:input的简写)来实时处理输入。 如果输入框初始值不为空,我们可能需要在创建时也进行一次过滤,可以在created或mounted钩子中处理。 最后,根据用户的问题,用户希望使用v-model,所以我们提供的方案都是基于v-model的,同时利用事件处理来过滤输入。 请根据实际情况选择适合的方案。</think>在 Vue 2 中,使用 `v-model` 结合 `replace()` 方法处理输入数据可以通过以下两种方式实现: ### 方法一:使用 `v-on:input` + 自定义方法(推荐) ```vue <template> <input type="text" :value="inputValue" @input="handleInput($event)" placeholder="请输入数字" > </template> <script> export default { data() { return { inputValue: '' }; }, methods: { handleInput(event) { // 使用 replace 过滤非数字字符 this.inputValue = event.target.value.replace(/\D/g, ''); } } }; </script> ``` ### 方法二:封装全局方法(复用场景) 1. **在 main.js 中定义全局方法**: ```javascript // main.js Vue.prototype.$filterNum = (value) => { return value.replace(/\D/g, ''); // 移除非数字字符 }; ``` 2. **组件中使用**: ```vue <template> <input type="text" :value="inputValue" @input="inputValue = $filterNum($event.target.value)" > </template> <script> export default { data() { return { inputValue: '' } } }; </script> ``` ### 关键说明 1. **双向绑定原理** Vue 2 通过 `v-model` 语法糖实现双向绑定,本质是 `:value` + `@input` 的组合[^5]。直接修改输入值需通过事件触发。 2. **`replace` 正则说明** `/\D/g` 正则表达式: - `\D`:匹配非数字字符 - `g`:全局替换标志 - 效果:`"a1b2c3"` → `"123"` 3. **避免直接修改 DOM** 通过 `event.target.value` 获取输入值,处理后更新到 Vue 数据层,保证数据驱动视图[^2]。 ### 注意事项 - **光标位置问题**:直接赋值可能导致光标跳转末尾,可通过保存/恢复光标位置优化 - **初始值处理**:若初始值需过滤,请在 `created()` 钩子中预处理 - **扩展场景**:支持负数和小数可修改正则:`/[^\d.-]/g` > 两种方案均通过事件拦截实现输入过滤,符合 Vue 数据驱动原则。全局方法适合多组件复用,简单场景推荐局部方法[^1][^3]。 --- ### 相关问题 1. 如何在 Vue 2 中实现输入框只允许输入字母? 2. Vue 2 自定义指令和全局方法在处理 DOM 操作时有何区别? 3. 如何解决输入过滤时光标位置异常的问题? 4. Vue 3 的 `v-model` 处理输入过滤与 Vue 2 有何不同? 5. 除了 `replace()`,还有哪些常用的输入校验方法? [^1]: 原始方法封装示例 [^2]: Vue 2 模板语法及 `v-model` 实现原理 [^3]: 全局过滤器的使用场景 [^5]: Vue 2 双向数据绑定原理
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值