Vue2
父傳子
父傳子比較簡單, 主要通過以下步驟實現
-
父在
template
中為子繫結屬性<Child :childData='pMsg'/> <!-- 也可以寫死 --> <Child childData='123'/>
-
子用
props
接收資料,props
的值可以是陣列或物件props: ["childData"]
-
子在
template
中或其他地方任意使用接受到的資料<h2>我得到了{{childData}}</h2>
列出完整例子:
<!--@html-start-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>title</title>
</style>
</head>
<body>
<div id="app">{{ message }}</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</body>
</html>
<!--@html-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
<!--@javascript-start-->
Vue.component("Parent", {
data() {
return {
pMsg: "小樓昨夜又東風",
};
},
//步驟一
template: `<div><fieldset><legend>父元件</legend><input type="text" v-model="pMsg"/><Child :childData='pMsg'/></fieldset></div>`,
});
Vue.component("Child", {
//步驟三
template: `<div><fieldset><legend>子元件</legend>來自父元件的資料: {{ childData }}</fieldset></div>`,
//步驟二
props: ["childData"],
});
var vm = new Vue({
el: "#app",
data() {
return {
msg: "往input中輸入東西試試",
};
},
template: `<div><fieldset><legend>App元件</legend>{{ msg }}<Parent/></fieldset></div>`,
});
<!--@javascript-end-->
子傳父
- 父元件中為子元件繫結一個自定義事件
<h2> <Child @childHandler="childHandler" /></h2>`
- 父元件中為自定義事件寫函式,形參為要接收的值,假如要加到
this
中的話,最好在data
中預留一個key
methods: { childHandler(val) { this.ChildData = val } }
- 子元件中繫結一個原生事件
再在方法中使用@input="change(data)"
$emit
呼叫父元件中的方法
觸發父元件中的自定義事件this.$emit("childHandler", val)
$emit
: 觸發當前例項上的事件。附加引數都會傳給監聽器回撥
完整例子:
<!--@html-start-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>title</title>
</head>
<body>
<div id="app">{{ message }}</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</body>
</html>
<!--@html-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
<!--@javascript-start-->
Vue.component("Parent", {
data() {
return {
ChildData: "",
};
},
//步驟一
template: `<div><fieldset><legend>父元件</legend><p>來自子元件的資料: {{ ChildData }}</p><Child @childHandler="childHandler" /></fieldset></div>`,
// 步驟二
methods: {
// 處理從子元件中獲取的資料
childHandler(val) {
this.ChildData = val;
},
},
});
Vue.component("Child", {
data() {
return {
data: "故國不堪回首月明中",
};
},
//步驟三
template: `<div><fieldset><legend>子元件</legend><input type="text" v-model="data" @input="change(data)" /></fieldset></div>`,
methods: {
// 呼叫$emit方法
change(val) {
this.$emit("childHandler", val);
},
},
});
var vm = new Vue({
el: "#app",
data() {
return {
msg: "在input中輸入東西試試",
};
},
template: `<div><fieldset><legend>App元件</legend>{{msg}}</h1><Parent/></fieldset></div>`,
});
<!--@javascript-end-->
父傳孫
父元件裡使用provide
, 子元件裡使用inject
完整例子
<!--@html-start-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>title</title>
</head>
<body>
<div id="app">{{ message }}</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</body>
</html>
<!--@html-end-->
<!--@javascript-start-->
Vue.component("Parent", {
data() {
return { data: "小樓昨夜又東風" };
},
template: `<div><fieldset><legend>父元件</legend><p>父元件資料: {{ data }}</p><Child /></fieldset></div>`,
// 步驟一
provide() {
return {
data: this.data,
};
},
});
Vue.component("Child", {
template: `<div><fieldset><legend>子元件</legend><GrandSon /></fieldset></div>`,
});
Vue.component("GrandSon", {
// 步驟二
// 接收祖輩的資料 data
inject: ["data"],
data() {
return {
// 通過this.x取值
parentData: this.data,
};
},
template: `<div><fieldset><legend>孫元件</legend><p>祖輩的資料: {{ parentData }}</p></fieldset></div>`,
});
var vm = new Vue({
el: "#app",
data() {
return {
msg: "觀察元件的資料",
};
},
template: `<div><fieldset><legend>App元件</legend><p>{{ msg }}</p><Parent/></fieldset></div>`,
});
<!--@javascript-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
注意, 這種方法傳值不是響應資料
你可以把資料變為object型別, 讓其可以同步修改
兄弟之間互傳
- 在Vue的原型物件向上新增一個屬性叫
$bus
該屬性是一個Vue
例項物件 - 傳送端, 呼叫
this.$bus.$emit
- 接收端, 監聽對應事件, 處理資料
完整例子:
<!--@html-start-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>title</title>
</head>
<body>
<div id="app">{{ message }}</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</body>
</html>
<!--@html-end-->
<!--@javascript-start-->
// 步驟一 新增$bus屬性
Vue.prototype.$bus = new Vue();
Vue.component("Child1", {
data() {
return { data: "小樓昨夜又東風" };
},
methods: {
update() {
// 步驟二 使用$emit觸發自定義事件, 傳入資料
this.$bus.$emit("handlerData", this.data);
},
},
template: `<div><fieldset><legend>子元件</legend><p>子元件傳送的資料: <input type="text" v-model="data" @input="update()"/></p></fieldset></div>`,
});
Vue.component("Child2", {
data() {
return {
data: "",
};
},
mounted() {
// 步驟三 處理傳過來的資料
this.$bus.$on("handlerData", (val) => {
this.data = val;
});
},
template: `<div><fieldset><legend>子元件</legend><p>子元件接收的資料: {{ data }}</p></fieldset></div>`
});
var vm = new Vue({
el: "#app",
data() {
return {
msg: "往input中輸入資料試試",
};
},
template: `<div><fieldset><legend>App元件</legend><p>{{msg}}</p><Child1 /> <Child2 /></fieldset></div>`,
});
<!--@javascript-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
Vue3
由於vue3
將vue2
的選項變為了組合API, 而且把data
和methods
集合到了setup
中, 故而使用起來有所區別, 但也大差不差
父傳子
- 父元件使用
ref
或reactive
將資料變為響應資料 - 子元件使用
props
接收關於
props
見: props - 要在
setup
中使用, 使用如下方法:props: ["data"], setup(props, context) { props.data }
完整例子
<!--@html-start-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>title</title>
</head>
<body>
<div id="app">
<fieldset>
<legend>app元件</legend>
{{ data }}
<!-- 使用元件 -->
<Parent />
</fieldset>
</div>
<script src="https://unpkg.com/vue@3.2.26/dist/vue.global.js"></script>
</body>
</html>
<!--@html-end-->
<!--@javascript-start-->
const AttributeBindingApp = {
name: "App",
setup() {
const data = "往input中輸入東西試試";
return {
data,
};
},
};
const app = Vue.createApp(AttributeBindingApp);
app.component("Parent", {
setup() {
// 變為響應資料
const parentData = Vue.ref("故國不堪回首月明中");
return {
parentData,
};
},
template: `<fieldset><legend>父元件</legend> <input type="text" v-model="parentData" /> <Child :parentData="parentData" /></fieldset>`,
});
app.component("Child", {
props: ["parentData"],
setup() {
const childData = "childData";
return {
childData,
};
},
template: `<fieldset><legend>子元件</legend>{{ parentData }}</fieldset>`,
});
app.mount("#app");
<!--@javascript-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
子傳父
- 父元件中定義接收資料的方法
- 在
template
中為子元件繫結自定義事件 - 在子元件中觸發自定義事件, 執行
context.emit
方法 - 傳給父元件使用
總的來說, 原理與Vue2差不多, 但由於要在
setup
中獲取值, 故要使用引數接收
<!--@html-start-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>title</title>
</head>
<body>
<div id="app">
<fieldset>
<legend>app元件</legend>
{{ data }}
<!-- 使用元件 -->
<Parent />
</fieldset>
</div>
<script src="https://unpkg.com/vue@3.2.26/dist/vue.global.js"></script>
</body>
</html>
<!--@html-end-->
<!--@javascript-start-->
const AttributeBindingApp = {
name: "App",
setup() {
const data = "往input中輸入東西試試";
return {
data,
};
},
};
const app = Vue.createApp(AttributeBindingApp);
app.component("Parent", {
setup(props, context) {
const childData = Vue.ref("");
// 步驟一 定義處理接收資料的方法
const receive = (e) => {
// 處理從子元件中傳來的資料
childData.value = e;
};
return {
receive,
childData,
};
},
// 步驟二 自定義事件 觸發處理接收資料的方法
template: `<fieldset><legend>父元件</legend><p>子元件中的資料: {{ childData }}</p><Child @inputText="receive" /></fieldset>`,
});
app.component("Child", {
props: ["parentData"],
setup(props, context) {
const data = Vue.ref("小樓昨夜又東風");
// 步驟四 呼叫context.emit
const toParent = () => {
// input時呼叫
// 呼叫inputText事件
context.emit("inputText", data.value);
};
return {
data,
toParent,
};
},
// 步驟三 觸發事件
template: `<fieldset><legend>子元件</legend><input type="text" @input="toParent" v-model="data" /></fieldset>`,
});
app.mount("#app");
<!--@javascript-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
父傳孫
和vue2一樣, 同樣使用
provide
和inject
但不同的是, 我們可以使用ref
和reactive
將資料轉換為響應式資料
<!--@html-start-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>title</title>
</head>
<body>
<div id="app">
<fieldset>
<legend>app元件</legend>
{{ data }}
<!-- 使用元件 -->
<Parent />
</fieldset>
</div>
<script src="https://unpkg.com/vue@3.2.26/dist/vue.global.js"></script>
</body>
</html>
<!--@html-end-->
<!--@javascript-start-->
const AttributeBindingApp = {
name: "App",
setup() {
const data = "往兩個input中都輸入試試";
return {
data,
};
},
};
const app = Vue.createApp(AttributeBindingApp);
app.component("Parent", {
setup() {
// 響應的資料
const data = Vue.ref("");
// 步驟一 使用provide
// 把data 標記為 "parentData"
Vue.provide("parentData", data);
return {
data,
};
},
template: `<fieldset><legend>父元件</legend>從子孫輩中獲取的資料: <input type="text" v-model="data" /> <Child /></fieldset>`,
});
app.component("Child", {
template: `<fieldset><legend>子元件</legend><GrandSon /></fieldset>`,
});
app.component("GrandSon", {
setup() {
// 步驟二 接收資料
// 接收 parentData
const data = Vue.inject("parentData");
return {
data,
};
},
template: `<fieldset><legend>孫元件</legend><p>從父輩中獲取的資料: <input type="text" v-model="data" /></p></fieldset>`,
});
app.mount("#app");
<!--@javascript-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->