本教程为入门教程,如有错误,请各位前端大佬指出。
是一个自定义元素或称为一个模块,包括所需的模板、逻辑和样式。在HTML模板中,组件以一个自定义标签的形式存在,起到占位符的功能。通过Vue.js的声明式渲染后,占位符将会被替换为实际的内容。我们可以在一个通过 new Vue
创建的 Vue 根实例中,把这个组件作为自定义元素来使用。
1.组件的生命周期
通过运行以下代码,可以清晰的看到组件的生命周期日志。建议执行,了解一下。
1. <template> 2. <div> 3. <button v-on:click = "clickButton" name = "button" type = "button">按钮</button> 4. {{message}} 5. </div> 6. </template> 7. 8. <script> 9. export default { 10. name: 'ComponentDemo', 11. data () { 12. return { 13. message:"改变之前" 14. } 15. }, 16. methods: { 17. clickButton(){ 18. this.message = "改变之后" 19. } 20. }, 21. //组件被创建之前 22. beforeCreate() { 23. console.log("组件被创建之前") 24. }, 25. created() { 26. console.log("组件被创建之后") 27. }, 28. beforeMount() { 29. console.log("组件被渲染之前") 30. }, 31. mounted() { 32. console.log("组件被渲染之后") 33. }, 34. beforeUpdate() { 35. console.log("数据改变渲染之前") 36. }, 37. updated() { 38. console.log("数据改变渲染之后") 39. }, 40. beforeDestroy() { 41. console.log("销毁之前") 42. }, 43. destroyed() { 44. console.log("销毁之后") 45. } 46. } 47. </script> 48. 复制代码
2.简单组件使用
组件可以理解为在一个页面引用另一个页面,以下介绍简单的组件使用方式。
1. 组件 2. <template> 3. <div> 4. 我是组件啊 5. </div> 6. </template> 7. 8. <script> 9. export default { 10. name: 'demoOne', 11. el: '#app', 12. data () { 13. return { 14. } 15. } 16. } 17. </script> 18. 19. <style scoped> 20. </style> 21. 22. 主页 23. <template> 24. <div> 25. 我是主页 26. <demoOne/> 27. </div> 28. </template> 29. 30. <script> 31. import demoOne from './demoOne.vue' 32. 33. export default { 34. name: 'HelloWorld', 35. el: '#app', 36. data () { 37. return { 38. } 39. }, 40. components:{ 41. demoOne 42. } 43. } 44. </script> 45. 复制代码
4.父传子
prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
1. app.vue 2. <template> 3. <div id="app"> 4. <parent/> 5. </div> 6. </template> 7. 8. <script> 9. import parent from './components/parent.vue' 10. 11. export default { 12. name: 'App', 13. components:{ 14. parent 15. } 16. } 17. </script> 18. 19. <style> 20. 21. </style> 22. 23. parent.vue 24. <template> 25. <div> 26. <p>我是父亲</p> 27. <son title="你好儿子" v-bind:thing = "thing"/> 28. </div> 29. </template> 30. 31. <script> 32. import son from './son.vue' 33. export default { 34. name: 'parent', 35. data () { 36. return { 37. thing:"给你钱" 38. } 39. }, 40. components:{ 41. son 42. } 43. } 44. </script> 45. 46. <style> 47. </style> 48. 49. 50. son.vue 51. <template> 52. <div> 53. 我是儿子 54. 父亲对我说{{title}}-{{thing}}-{{age}} 55. </div> 56. </template> 57. 58. <script> 59. export default { 60. name: 'son', 61. data () { 62. return { 63. } 64. }, 65. props:{ 66. title:String, 67. thing:String, 68. age: { 69. type: Number, 70. default: 100 71. } 72. } 73. } 74. </script> 75. 76. <style scoped> 77. </style> 78. 复制代码
5.父传子的值验证
组件可以为 props 指定验证要求。 为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。
1. props: { 2. // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证) 3. propA: Number, 4. // 多个可能的类型 5. propB: [String, Number], 6. // 必填的字符串 7. propC: { 8. type: String, 9. required: true 10. }, 11. // 带有默认值的数字 12. propD: { 13. type: Number, 14. default: 100 15. }, 16. // 带有默认值的对象 17. propE: { 18. type: Object, 19. // 对象或数组默认值必须从一个工厂函数获取 20. default: function () { 21. return { message: 'hello' } 22. } 23. }, 24. // 自定义验证函数 25. propF: { 26. validator: function (value) { 27. // 这个值必须匹配下列字符串中的一个 28. return ['success', 'warning', 'danger'].indexOf(value) !== -1 29. } 30. } 31. 复制代码
6.子传父
与上文相反,子组件传递值到父组件。
1. app.vue 2. <template> 3. <div id="app"> 4. <parent/> 5. </div> 6. </template> 7. 8. <script> 9. import parent from './components/parent.vue' 10. 11. export default { 12. name: 'App', 13. components:{ 14. parent 15. } 16. } 17. </script> 18. 19. <style> 20. 21. </style> 22. 23. 24. parent.vue 25. <template> 26. <div> 27. <p>我是父亲</p> 28. <son v-on:getMessage = "getMsg" title="你好儿子"/> 29. 儿子跟我说话了{{msg}} 30. </div> 31. </template> 32. 33. <script> 34. import son from './son.vue' 35. export default { 36. name: 'parent', 37. data () { 38. return { 39. msg:null 40. } 41. }, 42. components:{ 43. son 44. }, 45. methods: { 46. getMsg(data){ 47. this.msg = data 48. } 49. } 50. } 51. </script> 52. 53. <style> 54. </style> 55. 56. 57. son.vue 58. <template> 59. <div> 60. <button v-on:click = "sendMessage" name = 'button' type = "button">说话</button> 61. </div> 62. </template> 63. 64. <script> 65. export default { 66. name: 'son', 67. data () { 68. return { 69. message:"你好父亲" 70. } 71. }, 72. methods: { 73. sendMessage(event){ 74. this.$emit("getMessage",this.message); 75. } 76. } 77. } 78. </script> 79. 80. <style scoped> 81. </style> 82. 复制代码
7.插槽
插槽内可以是任意内容。如果子组件没有使用插槽,父组件如果需要往子组件中填充模板或者html, 是没法做到的。 下文介绍普通插槽和具名插槽的使用方法。
1. app.vue 2. <template> 3. <div id="app"> 4. <HelloWorld> 5. <!-- 依然在父组件中渲染 --> 6. <!--普通插槽--> 7. <!-- <p>我是父亲你好插槽</p> --> 8. <!-- 具名插槽 --> 9. <div slot ="demo"> 10. <p>aaaa</p> 11. <p>bbbb</p> 12. <p>cccc</p> 13. </div> 14. <p slot = "demo2">{{message}}</p> 15. <!-- 接收儿子传递的 --> 16. <p slot = "demo3" slot-scope = "props">{{props.text}}</p> 17. </HelloWorld> 18. </div> 19. </template> 20. 21. <script> 22. import HelloWorld from './components/HelloWorld.vue' 23. 24. export default { 25. name: 'App', 26. components:{ 27. HelloWorld 28. }, 29. data () { 30. return { 31. message:"this is message" 32. } 33. } 34. } 35. </script> 36. 37. <style> 38. 39. </style> 40. 41. HelloWorld.vue 42. <template> 43. <div> 44. <!-- 父亲的数据在儿子中显示 --> 45. <!-- <slot>普通插槽</slot> --> 46. <slot name= "demo">具名插槽1</slot> 47. <slot name= "demo2">具名插槽2</slot> 48. <!-- 儿子传递给父亲 --> 49. <slot name= "demo3" v-bind:text = "message">儿到父</slot> 50. </div> 51. </template> 52. 53. <script> 54. import demoOne from './demoOne.vue' 55. 56. export default { 57. name: 'HelloWorld', 58. data () { 59. return { 60. message:"儿子到父亲" 61. } 62. }, 63. components:{ 64. demoOne 65. } 66. } 67. </script> 68. 复制代码
8.缓存keep-alive
重新创建动态组件的行为通常是非常有用的,但是在这个案例中,我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个 元素将其动态组件包裹起来。
1. app.vue 2. <template> 3. <div id="app"> 4. <button v-on:click = "clickButton" name = "button" type = "button">切换</button> 5. <!-- 可以尝试去掉keep-alive --> 6. <keep-alive> 7. <!-- 失活的组件将会被缓存!--> 8. <component v-bind:is="stutas"></component> 9. </keep-alive> 10. </div> 11. </template> 12. 13. <script> 14. import HelloWorld from './components/HelloWorld.vue' 15. import HelloWorld2 from './components/HelloWorld2.vue' 16. 17. export default { 18. name: 'App', 19. components:{ 20. HelloWorld, 21. HelloWorld2 22. }, 23. data () { 24. return { 25. stutas:HelloWorld 26. } 27. }, 28. methods: { 29. clickButton(event){ 30. if(this.stutas ==HelloWorld){ 31. this.stutas = HelloWorld2 32. }else{ 33. this.stutas = HelloWorld 34. } 35. } 36. }, 37. } 38. </script> 39. 40. <style> 41. 42. </style> 43. 44. 45. HelloWorld.vue 46. <template> 47. <div> 48. <button v-on:click = "clickButton1" name = "button" type = "button">1组件切换</button> 49. {{content}} 50. </div> 51. </template> 52. 53. <script> 54. export default { 55. name: 'HelloWorld', 56. data () { 57. return { 58. content:"组件1" 59. } 60. }, 61. methods:{ 62. clickButton1(event){ 63. this.content = "我刚刚点击了" 64. } 65. } 66. } 67. </script> 68. 69. HelloWorld2.vue 70. <template> 71. <div> 72. HelloWorld2 73. </div> 74. </template> 75. 76. <script> 77. 78. export default { 79. name: 'HelloWorld2', 80. data () { 81. return { 82. } 83. } 84. } 85. </script>