Vue 组件(七)
1、组件创建及使用
(1)在 components 目录下,新建 Learn.vue 文件,示例代码如下:
<template> <!-- 只能存在一个根容器 --> <div class="container"> <p>hello world</p> </div> </template> <script> export default { name: "Learn", // 所有初始化数据全部放入 data 中 data() { } } </script> <!-- 样式,scope 属性表示样式只在当前组件生效 --> <style lang="css" scoped> </style>
(2)在 App.vue 文件中引入刚刚创建的 Learn.vue:
<template> <div id="app"> <Learn /> </div> </template> <script> // 导入组件 import Learn from "./components/Learn" export default { name: "App", components: { Learn // 注入 }, data() { return { message: '' } } }; </script>
2、使用 props 传递数据(父传子)
通常常父组件的模板中包含子组件,父组件要正向地向子组件传递数据或参数,子组件接收到后根据参数的不同来渲染不同的内容或执行操作。这个正向传递数据的过程就是通过 props 来实现的。
在组件中,使用选项props 来声明需要从父级接收的数据, props 的值可以是两种, 一种是字符串数组,一种是对象:
1、使用字符串数组方式传递:
父组件 App.vue:
<template> <div id="app"> <!-- 将 message 参数传递给子组件 --> <Learn message="来自父组件的数据"/> </div> </template> <script> // 导入组件 import Learn from "./components/Learn" export default { name: "App", components: { Learn // 注入 }, data() { return { } } }; </script>
Learn.vue 子组件:
<template> <!-- 只能存在一个根容器 --> <div class="container"> <p>{{ message }}</p> </div> </template> <script> export default { name: "Learn", // 所有初始化数据全部放入 data 中 data() { }, // 接收父级组件传递的数据 props: ['message'] } </script>
2、使用对象方式传递:
父组件 App.vue:
<template> <div id="app"> <!-- 将 message 参数传递给子组件,传递的数据为一个对象 --> <Learn :message="message"/> </div> </template> <script> // 导入组件 import Learn from "./components/Learn" export default { name: "App", components: { Learn // 注入 }, data() { return { // 返回一个对象 message: { id: 1, text: '这是父组件数据' } } } }; </script>
子组件 Learn.vue:
<template> <!-- 只能存在一个根容器 --> <div class="container"> <p>{{ message.text }}</p> </div> </template> <script> export default { name: "Learn", // 所有初始化数据全部放入 data 中 data() { }, // 接收父级组件传递的数据 props: ['message'] } </script>
3、自定义事件向父组件传递数据(子传父)
当子组件需要向父组件传递数据时,就要用到自定义事件。我们在介绍指令v-on 时有提到,v-on 除了监昕DOM 事件外,还可以用于组件之间的自定义事件。
子组件用 $emit() 来触发事件,父组件用 $on 来监听子组件的事件。
子组件 Learn.vue :
<template> <!-- 只能存在一个根容器 --> <div class="container"> <button @click="sendMsg" type="button" name="button">传递数据</button> </div> </template> <script> export default { name: "Learn", // 所有初始化数据全部放入 data 中 data() { }, methods: { sendMsg() { // 第一个参数 getMsg 为自定义事件名,第二个为传递的值 this.$emit("getMsg", "这是儿子的数据") } } } </script>
父组件 App.vue:
<template> <div id="app"> 接收的子组件数据:{{ message }} <!-- 监听自定义事件 getMsg --> <Learn @getMsg="getSonMsg"/> </div> </template> <script> // 导入组件 import Learn from "./components/Learn" export default { name: "App", components: { Learn // 注入 }, data() { return { message: '' } }, methods: { getSonMsg(message) { // message 为子组件传递的参数值 this.message = message } } }; </script>
如上,在点击传递数据按钮后,可以看到子组件给父组件传递的数据。
4、在自定义组件上使用 v-model 指令
子组件 Learn.vue:
<template> <!-- 只能存在一个根容器 --> <div class="container"> <input type="text" v-model="searchText"> <button @click="sendMsg" type="button" name="button">传递数据</button> </div> </template> <script> export default { name: "Learn", // 所有初始化数据全部放入 data 中 data() { return { searchText: '' } }, methods: { sendMsg() { // 第一个参数 getMsg 为自定义事件名,第二个为传递的值 this.$emit("getMsg", this.searchText) } } } </script>
父组件 App.vue:
<template> <div id="app"> 接收的子组件数据:{{ message }} <!-- 监听自定义事件 getMsg --> <Learn @getMsg="getSonMsg"/> </div> </template> <script> // 导入组件 import Learn from "./components/Learn" export default { name: "App", components: { Learn // 注入 }, data() { return { message: '' } }, methods: { getSonMsg(message) { // message 为子组件传递的参数值 this.message = message } } }; </script>
如上,当在文本框输入信息后,再点击传递数据按钮,父组件成功接收到子组件传递的数据。
5、props 验证
一般当你组件需要提供给别人使用时,推荐都进行数据验证。比如某个数据必须是数字类型,如果传入字符串,就会在控制台显示警告。
父组件 App.vue:
<template> <div id="app"> <Learn name="张三" age="26"/> </div> </template> <script> // 导入组件 import Learn from "./components/Learn" export default { name: "App", components: { Learn // 注入 }, data() { return { } } }; </script>
子组件 Learn.vue:
<template> <!-- 只能存在一个根容器 --> <div class="container"> <p>{{ name }}</p> <p>{{ age }}</p> </div> </template> <script> export default { name: "Learn", // 所有初始化数据全部放入 data 中 data() { return { } }, props: { // 必须是字符串类型 name: String, // 自定义一个验证函数 age: { validator: function(value) { return value > 30 } } } } </script>
通过浏览器控制台发现,当父组件传递给子组件的参数验证失败时,会给出相应的警告信息。
props 常用验证示例如下:
6、处理边界情况
(1)访问根实例:
main.js:
import Vue from 'vue' import App from './App' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', render: h => h(App), // 设置根实例数据 data: function() { return { name: 'rootData' } }, // 设置根实例方法 methods: { rootMethod: function() { return "rootHandler" } }, // 设置根实例计算属性 computed: { rootComputed: function() { return "rootComputed" } } })
App.vue:
<template> <div id="app"> <Learn/> <button @click="getRootData">获取根实例数据</button> </div> </template> <script> // 导入组件 import Learn from "./components/Learn" export default { name: "App", components: { Learn // 注入 }, data() { return { } }, methods: { getRootData() { // 访问根实例中的 data 数据 console.log(this.$root.name); // 访问根实例中的方法 console.log(this.$root.rootMethod) // 访问根实例中的计算属性 console.log(this.$root.rootComputed) // 写入根实例的数据 this.$root.age = 20; console.log(this.$root.age); } } }; </script>
当点击按钮后,成功获取到根实例的相关信息。
对于小型应用,这样的使用方式是很方便的。不过这个模式扩展到中大型应用来说就不然了。因此在绝大多数情况下,还是推荐使用 Vuex 来处理。
(2)访问父级组件实例:
父组件 App.vue :
<template> <div id="app"> <Learn/> </div> </template> <script> // 导入组件 import Learn from "./components/Learn" export default { name: "App", components: { Learn // 注入 }, // 设置父组件实例数据 data() { return { parentName: 'parentName' } }, // 设置父组件实例方法 methods: { parentMethod: function() { return "parentMethod" } }, // 设置父组件实例计算属性 computed: { parentComputed: function() { return "parentComputed" } } }; </script>
子组件 Learn.vue :
<template> <!-- 只能存在一个根容器 --> <div class="container"> <button @click="getParentInfo">获取父组件实例数据</button> </div> </template> <script> export default { name: "Learn", // 所有初始化数据全部放入 data 中 data() { return { } }, methods: { getParentInfo: function() { // 访问父组件实例的 data 数据 console.log(this.$parent.parentName); // 访问父组件实例的方法 console.log(this.$parent.parentMethod); // 访问父组件实例的计算属性 console.log(this.$parent.parentComputed); } } } </script>
当点击按钮后,成功获取到父组件实例的相关数据。
(3)访问子组件实例:
有时候仍可能需要在 JavaScript 里直接访问一个子组件。为了达到这个目的,可以通过 ref 特性为这个子组件赋予一个ID引用。
子组件 Learn.vue :
<template> <!-- 只能存在一个根容器 --> <div class="container"> </div> </template> <script> export default { name: "Learn", // 设置子组件 data 数据 data() { return { childData: 'childData' } }, // 设置子组件方法 methods: { childMethod: function() { return "childMethod" } }, // 设置子组件计算属性 computed: { childComputed: function() { return "childComputed" } } } </script>
父组件 App.vue :
<template> <div id="app"> <!-- 给子组件 Learn 赋予一个 ID引用 --> <Learn ref="child"/> <button @click="getChildInfo">获取子组件实例数据</button> </div> </template> <script> // 导入组件 import Learn from "./components/Learn" export default { name: "App", components: { Learn // 注入 }, data() { return { } }, methods: { getChildInfo: function() { // 访问子组件实例 data 数据 console.log(this.$refs.child.childData); // 访问子组件实例的方法 console.log(this.$refs.child.childMethod); // 访问子组件实例的计算属性 console.log(this.$refs.child.childComputed); } } }; </script>
当点击按钮后,成功获取到子组件实例的相关数据。
参考:
《Vue.js 实战》