Vue的 value=“1“ 和 :value=“1“ 有什么区别

文章目录

环境

  • Ubuntu 24.04
  • Chrome Version 146.0.7680.164 (Official Build) (64-bit)
  • VSCode 1.109.5
  • npm 11.6.2
  • Vue 3.5.32

准备

创建一个Vue项目。创建过程略,具体可参见 https://blog.csdn.net/duke_ding2/article/details/159510007

关于 props ,参见 https://blog.csdn.net/duke_ding2/article/details/159696940

背景

在Vue中, v-bind 指令用来动态的绑定属性。

注: v-bind:xxx 可以简写为 :xxx ,本文统一采用简写形式。

需求:有一个 <input> 输入框,其初始值是 1

例1

不使用动态绑定,修改 App.vue 如下:

html 复制代码
<template>
    <input value="1">
</template>

效果如下:

例2

使用 v-bind 动态绑定 value 属性值:

html 复制代码
<template>
    <input :value="myValue">
</template>

<script>
    export default {
        data() {
            return {
                myValue: "1"
            }
        }
    }
</script>

效果是一样的。

注:也可以赋值给 myValue 数值 1

javascript 复制代码
                myValue: 1

效果也是一样的。

例3

使用 v-bind 设置属性值,并直接设置常量:

html 复制代码
<template>
    <input :value="1">
</template>

效果也是一样的。

注:也可以使用字符串常量 1

html 复制代码
    <input :value="'1'">

效果也是一样的。

那么问题来了:上述的这几种情况,它们的效果和本质是完全相同的吗?如果不相同,具体差别是什么?

分析

对于原生的HTML元素,其属性值是literal的字符串。

比如:

html 复制代码
<template>
    <input value="1+2">
</template>

其中, 1+2 是literal字符串。效果如下:

所以,不能使用显式的字符串:

html 复制代码
    <input value="'1'">

因为这样就相当于字符串 '1' (注意这是3个字符)。

而对于 v-bind 绑定的属性值,其值是一个JavaScript表达式。

比如:

html 复制代码
<template>
    <input :value="1+2">
</template>

其中, 1+2 是一个表达式,Vue会对该表达式求值。效果如下:

注意:上面这两种情况的本质区别在于:

  • <input value="1"> 里的 1 是字符串
  • <input :value="1"> 里的 1 是数值

同理,看下面的代码:

html 复制代码
    <input :value="myValue">

v-bind 绑定的属性值是一个表达式,只不过此处表达式就是变量 myValue 本身,所以表达式的结果取决于 myValue 的具体值,而表达式的类型则取决于 myValue 的类型:

  • myValue 是字符串 1 ,则绑定的值是字符串 1
  • myValue 是数值 1 ,则绑定的值是数值 1

注意:对于 <input>value 属性值是字符串 1 或者数值 1 其实并无太大区别,这是因为 <input>value 属性值一定会被当作字符串来处理,所以即使 v-bind 绑定的表达式是数值,也会隐式的转换为字符串。

考一考

题目1

看下面的代码:

html 复制代码
    <input value="1">

把它换成等价的 v-bind 写法。

答案:

html 复制代码
    <input :value="'1'">

这是因为,在第一种写法中,属性的值是literal字符串(无需加引号)。而在第二种写法中,属性的值是JavaScript表达式,要想表示字符串,必须显式加上引号。

题目2

下面的代码:

html 复制代码
<template>
    <div v-if="true">aaa</div>
    <div v-if="false">bbb</div>
    <div v-if="'true'">ccc</div>
    <div v-if="'false'">ddd</div>
</template>

结果是什么?

答案:效果如下:

这是因为, v-if 的判断条件是JavaScript表达式,其返回值是布尔类型,因此:

  • true :布尔类型常量true
  • false :布尔类型常量false
  • 'true' :字符串类型,由于字符串非空,会被看做true
  • 'false' :字符串类型,由于字符串非空,会被看做true

组件的自定义属性

我们知道, v-bind 可用于组件的自定义属性,用来给子组件传递数据。在子组件中,通过 props 来声明自定义属性。

<input>value 属性值天然就是字符串,即使提供的是其它类型,也会隐式转换。而自定义属性则是完全独立自由的。因此,使用自定义属性时,更要加倍小心,别把类型搞错了。

创建 MyComponent.vue 文件如下:

html 复制代码
<template>
    <div>
        姓名: {{ name }},语文成绩: {{ chinese }},数学成绩: {{ math }},英语成绩: {{ english }}
    </div>
</template>

<script>
    export default {
        props: ['id', 'name', 'chinese', 'math', 'english'],
    }
</script>

该组件的功能是,列出某个学生的各科成绩。

修改 App.vue 如下:

html 复制代码
<template>
    <div>
        <ul v-for="(student, index) in students" :key="id">
            <li>
                <MyComponent :id="student.id" :name="student.name" :chinese="student.chinese" :math="student.math" :english="student.english" />
            </li>
        </ul>
    </div>
</template>

<script>
    import MyComponent from './MyComponent.vue';
    export default {
        components: {
            MyComponent
        },
        data() {
            return {
                students: [
                    { id: 1, name: "张三", chinese: '85', math: '90', english: '88' },
                    { id: 2, name: "李四", chinese: '92', math: '87', english: '91' },
                    { id: 3, name: "王五", chinese: '78', math: '85', english: '82' }
                ]
            }
        },
    }
</script>

效果如下:

看上去一切OK。

现在,有一个新的需求:对于每个学生,要显示其"平均成绩"。

修改 MyComponent.vue 如下:

html 复制代码
<template>
    <div>
        姓名: {{ name }},语文成绩: {{ chinese }},数学成绩: {{ math }},英语成绩: {{ english }},平均成绩: {{ average }}
    </div>
</template>

<script>
    export default {
        props: ['id', 'name', 'chinese', 'math', 'english'],
        computed: {
            average() {
                return ((this.chinese + this.math + this.english) / 3).toFixed(2);
            }
        }
    }
</script>

可见,在子组件中,添加了一个计算属性,用来计算三门课程的平均成绩。

效果如下:

可以看出,计算出来的平均成绩是错误的。

来看一下计算平均成绩的逻辑:

javascript 复制代码
        computed: {
            average() {
                return ((this.chinese + this.math + this.english) / 3).toFixed(2);
            }
        }

该代码中,使用了一个计算属性 average ,计算三门课程成绩的平均值,并保留两位小数。

代码看来没有什么问题,那么问题到底出在哪儿呢?

答案:父组件所传递的数据的类型有问题。

javascript 复制代码
        data() {
            return {
                students: [
                    { id: 1, name: "张三", chinese: '85', math: '90', english: '88' },
                    { id: 2, name: "李四", chinese: '92', math: '87', english: '91' },
                    { id: 3, name: "王五", chinese: '78', math: '85', english: '82' }
                ]
            }
        },

可以看出,三门课程成绩都是字符串类型,导致平均成绩计算错误。

要fix这个bug,只需把课程成绩改为数值类型:

javascript 复制代码
        data() {
            return {
                students: [
                    { id: 1, name: "张三", chinese: 85, math: 90, english: 88 },
                    { id: 2, name: "李四", chinese: 92, math: 87, english: 91 },
                    { id: 3, name: "王五", chinese: 78, math: 85, english: 82 }
                ]
            }
        },

效果如下:

这次,平均成绩计算正确了。

实际上,子组件在 props 声明自定义属性时,可以添加校验。

javascript 复制代码
        props: ['id', 'name', 'chinese', 'math', 'english'],

本例中,没有任何校验,这也是导致错误的一个间接原因。

可以加上类型限定:

javascript 复制代码
        props: {
            id: Number,
            name: String,
            chinese: Number,
            math: Number,
            english: Number
        },

这样,如果传递的数据不满足条件,在开发环境下,会收到警告信息,比如:

Vue warn\]: Invalid prop: type check failed for prop "english". Expected Number with value 82, got String with value "82". at \ at \

效果如下:

总结

  • 对于原生的HTML元素,其属性值是literal的字符串,例如 1+2 ,会被看做字符串
    • 对于 <input> 元素,其 value 属性一定会作为字符串来处理
      • 即使提供的数据是数值,也会隐式转换为字符串
  • 对于 v-bind 绑定的属性值,其值是一个JavaScript表达式
    • 要注意表达式的返回类型是否合适
    • 对于 v-if ,需要布尔类型的表达式,如果表达式不是布尔类型,则会隐式转换
      • 例如: v-if="'false'" ,字符串 false 会隐式转换为true
  • 在使用自定义属性给子组件传递数据时,一定要注意别把类型搞错了
    • 子组件的 props 声明自定义属性时,可以添加校验逻辑,包括类型限定
相关推荐
小李子呢02112 小时前
前端八股6---v-model双向绑定
前端·javascript·算法
He少年2 小时前
【基础知识、Skill、Rules和MCP案例介绍】
java·前端·python
史迪仔01122 小时前
[QML] QML IMage图像处理
开发语言·前端·javascript·c++·qt
AI_Claude_code2 小时前
ZLibrary访问困境方案四:利用Cloudflare Workers等边缘计算实现访问
javascript·人工智能·爬虫·python·网络爬虫·边缘计算·爬山算法
AwesomeCPA2 小时前
Miaoduo MCP 使用指南(VDI内网环境)
前端·ui·ai编程
前端大波2 小时前
前端面试通关包(2026版,完整版)
前端·面试·职场和发展
qq_433502183 小时前
Codex cli 飞书文档创建进阶实用命令 + Skill 创建&使用 小白完整教程
java·前端·飞书
IT_陈寒3 小时前
为什么我的Vite热更新老是重新加载整个页面?
前端·人工智能·后端