十、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
}
}
}
})
-->