388 vue 之 props: 只读,prop的大小写,prop的类型,prop的校验
十、props 的特点 : 只读
- 演示验证 props 只读
-
- 传的是简单类型 : 修改会报错
- 传的复杂类型 (地址) : 修改不会报错,是因为地址没有变 ,测试
obj={}
立马报错 【修改对象中的数据,不会修改对象的地址,但是修改对象的地址就报错。】
- 修改
父组件传给子组件的
数据
思路 : 把接收过来的数据,保存到 data 中一个临时值 (适用在该组件接收数据只会在当前组件内使用)
Vue.component('child', {
template: `
<div>子组件 {{ cmsg }} </div>
`,
data() {
return {
cmsg: this.msg
}
},
props: ['msg'],
created() {
this.cmsg = 666
}
})
完善TodoMVC => 修改状态 + 修改任务
08-prop的只读特性.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<div id="app">
<child :msg="pmsg" :obj="pobj"></child>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('child', {
template: `
<div> 子组件 : {{ obj.name }}</div>
`,
props: ['msg', 'obj'],
mounted() {
// 修改传递过来的数据
// 1. 修改基本类型的数据,报错
// this.msg = 666
//2. 只是改了对象里的内容 ,并没有改地址
// this.obj.name = '春春' // 虽然这不会报错,但是也不要这么改
this.obj = {} // 这样写报错
}
})
const vm = new Vue({
el: '#app',
data: {
pmsg: '父的信息',
pobj: {
name: '张三'
}
}
})
</script>
</body>
</html>
补充的案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<one :msg="pMsg" :obj="pObj"></one>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('one', {
template: `
<div>
<div>{{msg}} - {{obj.name}}</div>
<div>{{cMsg}} - {{cObj.name}}</div>
</div> `,
data() {
return {
// 把接收过来的数据,保存到 data 中一个临时
cMsg: this.msg,
cObj: this.obj
}
},
props: ['msg', 'obj'],
created() {
this.cMsg = 333
this.cObj.name = '嘻嘻'
this.cObj = { name: '嘿嘿' }
},
})
const vm = new Vue({
el: '#app',
data: {
pMsg: '111',
pObj: {
name: '哈哈'
}
}
})
</script>
</body>
</html>
十一、prop 的大小写
-
官 : HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。
- html 的标签和 属性 都是一样,忽略大小写
<H1 TITLE="哈哈">我是h1</H1>
-
官 : 这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名不好使了
<child :cMsg="pmsg"></child>
会报警告,父传子也接收不到了- 原因是 : 接收的属性是:cMsg, 因为忽略大小写,已为 : cmsg
- 所以已经准备要读取的 是 cmsg 的值,否则要报警告
You should probably use "c-msg" instead of "cMsg".
-
方式 1 : 全用小写,不要使用驼峰命名 (不推荐)
- 接收 :
cmsg
- props/读取 :
cmsg
- 接收 :
-
方式 2 官 : 需要使用其等价的 kebab-case (短横线分隔命名) 命名: (推荐)
- 接收 :
:c-msg='pmsg'
- props/读取 :
cMsg / this.cMsg
- 接收 :
-
大小写在 父传子和 子传父中的应用 (都是要 带 - 的)
-
- 父传子 :
:c-msg ==> cMsg
改驼峰 - 因为props - 子传父 :
@todo-head = 'pAddTodo' ==> this.$emit('todo-head')
不改驼峰
- 父传子 :
-
完善 TodoMVC : 底部隐藏+剩余完成数+清除完成
- 计算属性 : 已知值(todoList 在 根组件) ==> 得到一个新值(子组件里使用)
- 父 => 子通讯
-
番外篇 : 方法当属性传、传过来的带:得到的原型
09-prop的大小写问题.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
原因 :
1. cMsg => cmsg
解决办法 :
1. 用小写 (不推荐)
2. 短横线分割符
赋值 :c-msg='pMsg'
-删除掉 -后面的首字母变大写 cMsg
指定 : cMsg
使用 : cMsg
-->
<div id="app">
<child :c-msg="pMsg" :c-user-name="pUserName"></child>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('child', {
template: `
<div> 子组件 : {{ cMsg }} {{ cUserName }} </div>
`,
props: ['cMsg', 'cUserName']
})
const vm = new Vue({
el: '#app',
data: {
pMsg: '父的信息',
pUserName: '大傻春'
}
})
</script>
</body>
</html>
10-大小写问题应用在子传父和父传子.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
(prop的)大小写问题 【是prop的大小写问题,不是事件的。 】
1. 父传子 c-msg => cMsg
2. 子传父 @add-todo ==> add-todo
-->
<div id="app">
<child :c-msg="pMsg" @add-todo="pAddTodo"></child>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('child', {
template: `
<div> 子组件 : {{ cMsg }} </div>
`,
props: ['cMsg'],
created() {
this.$emit('add-todo')
}
})
const vm = new Vue({
el: '#app',
data: {
pMsg: '父的信息'
},
methods: {
pAddTodo() {
console.log('哈哈')
}
}
})
</script>
</body>
</html>
11-prop的类型问题.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
1. 通过prop 赋值的时候, 如果直接赋值一个静态值, 不管是什么值, 都是字符串类型
'abc' / '123' / 'true'
2. 在 属性前面加一个冒号“:” , 可以获取它的真实类型
总结 :
1. :msg='pmsg/动态值/data里属性'
2. :msg='固定值/静态值' : 读取固定值的真实类型,赋值给 msg
-->
<div id="app">
<child :msg="true" :na="name"></child>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('child', {
template: `
<div> 子组件 : </div>
`,
props: ['msg'],
created() {
// 'abc' => 字符串
// '123' => '123' 字符串
console.warn(this.msg, typeof this.msg) // true "boolean"
console.warn(this.na, typeof this.na) // 123 "number"
}
})
const vm = new Vue({
el: '#app',
data: {
name: 123
}
})
</script>
</body>
</html>
12-类型的校验问题.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 大傻春拿去用了 -->
<!-- <child :msg="111"></child> -->
<child></child>
</div>
<script src="./vue.js"></script>
<script>
// 这个组件是我注册的
Vue.component('child', {
template: `
<div> 子组件 : </div>
`,
props: ['msg'],
// props: {
// msg: Number // 仅仅是告诉其类型
// },
// props: {
// msg: {
// type: Number, // 类型
// default: 100 // 默认值
// }
// },
created() {
// 我希望的是一个数字类型
console.log(this.msg, typeof this.msg)
console.log(this.msg + 10) // 133
}
})
const vm = new Vue({
el: '#app',
data: {}
})
</script>
</body>
</html>
<!--
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
-->