文章目录环境准备背景例1例2例3分析考一考题目1题目2组件的自定义属性总结环境Ubuntu 24.04Chrome Version 146.0.7680.164 (Official Build) (64-bit)VSCode 1.109.5npm 11.6.2Vue 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如下templateinputvalue1/template效果如下例2使用v-bind动态绑定value属性值templateinput:valuemyValue/templatescriptexportdefault{data(){return{myValue:1}}}/script效果是一样的。注也可以赋值给myValue数值1myValue:1效果也是一样的。例3使用v-bind设置属性值并直接设置常量templateinput:value1/template效果也是一样的。注也可以使用字符串常量1input:value1效果也是一样的。那么问题来了上述的这几种情况它们的效果和本质是完全相同的吗如果不相同具体差别是什么分析对于原生的HTML元素其属性值是literal的字符串。比如templateinputvalue12/template其中12是literal字符串。效果如下所以不能使用显式的字符串inputvalue1因为这样就相当于字符串1注意这是3个字符。而对于v-bind绑定的属性值其值是一个JavaScript表达式。比如templateinput:value12/template其中12是一个表达式Vue会对该表达式求值。效果如下注意上面这两种情况的本质区别在于input value1里的1是字符串input :value1里的1是数值同理看下面的代码input:valuemyValuev-bind绑定的属性值是一个表达式只不过此处表达式就是变量myValue本身所以表达式的结果取决于myValue的具体值而表达式的类型则取决于myValue的类型若myValue是字符串1则绑定的值是字符串1若myValue是数值1则绑定的值是数值1注意对于inputvalue属性值是字符串1或者数值1其实并无太大区别这是因为input的value属性值一定会被当作字符串来处理所以即使v-bind绑定的表达式是数值也会隐式的转换为字符串。考一考题目1看下面的代码inputvalue1把它换成等价的v-bind写法。答案input:value1这是因为在第一种写法中属性的值是literal字符串无需加引号。而在第二种写法中属性的值是JavaScript表达式要想表示字符串必须显式加上引号。题目2下面的代码templatedivv-iftrueaaa/divdivv-iffalsebbb/divdivv-iftrueccc/divdivv-iffalseddd/div/template结果是什么答案效果如下这是因为v-if的判断条件是JavaScript表达式其返回值是布尔类型因此true布尔类型常量truefalse布尔类型常量falsetrue字符串类型由于字符串非空会被看做truefalse字符串类型由于字符串非空会被看做true组件的自定义属性我们知道v-bind可用于组件的自定义属性用来给子组件传递数据。在子组件中通过props来声明自定义属性。input的value属性值天然就是字符串即使提供的是其它类型也会隐式转换。而自定义属性则是完全独立自由的。因此使用自定义属性时更要加倍小心别把类型搞错了。创建MyComponent.vue文件如下templatediv姓名 {{ name }}语文成绩 {{ chinese }}数学成绩 {{ math }}英语成绩 {{ english }}/div/templatescriptexportdefault{props:[id,name,chinese,math,english],}/script该组件的功能是列出某个学生的各科成绩。修改App.vue如下templatedivulv-for(student, index) in students:keyidliMyComponent:idstudent.id:namestudent.name:chinesestudent.chinese:mathstudent.math:englishstudent.english//li/ul/div/templatescriptimportMyComponentfrom./MyComponent.vue;exportdefault{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如下templatediv姓名 {{ name }}语文成绩 {{ chinese }}数学成绩 {{ math }}英语成绩 {{ english }}平均成绩 {{ average }}/div/templatescriptexportdefault{props:[id,name,chinese,math,english],computed:{average(){return((this.chinesethis.maththis.english)/3).toFixed(2);}}}/script可见在子组件中添加了一个计算属性用来计算三门课程的平均成绩。效果如下可以看出计算出来的平均成绩是错误的。来看一下计算平均成绩的逻辑computed:{average(){return((this.chinesethis.maththis.english)/3).toFixed(2);}}该代码中使用了一个计算属性average计算三门课程成绩的平均值并保留两位小数。代码看来没有什么问题那么问题到底出在哪儿呢答案父组件所传递的数据的类型有问题。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只需把课程成绩改为数值类型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声明自定义属性时可以添加校验。props:[id,name,chinese,math,english],本例中没有任何校验这也是导致错误的一个间接原因。可以加上类型限定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 MyComponent id3 name“王五” chinese“78” … at App效果如下总结对于原生的HTML元素其属性值是literal的字符串例如12会被看做字符串对于input元素其value属性一定会作为字符串来处理即使提供的数据是数值也会隐式转换为字符串对于v-bind绑定的属性值其值是一个JavaScript表达式要注意表达式的返回类型是否合适对于v-if需要布尔类型的表达式如果表达式不是布尔类型则会隐式转换例如v-iffalse字符串false会隐式转换为true在使用自定义属性给子组件传递数据时一定要注意别把类型搞错了子组件的props声明自定义属性时可以添加校验逻辑包括类型限定