"vue.js既然是框架,那就不能只是简单的完成数据模板引擎的任务,它还提供了页面布局的功能。本文将详细介绍使用vue.js进行页面布局的强大工具——vue.js组件系统。

每一个新技术的诞生,都是为了解决特定的问题。

组件的出现就是为了解决页面布局等等一系列的问题。

Vue中的组件分为两种:全局组件与局部组件.

@



全局组件


注册

方式一:

  1. <body>
  2. <div id="app"></div>
  3. <script>
  4. // 下面的'global-component'是自定义的组件名,也是自定义的标签名
  5. Vue.component('global-component', {
  6. // 错误写法:(网页中不会显示)
  7. // template: `<h1>{{ zyk }}</h1><h1>{{ zyk }}</h1>`,
  8. // 正确写法:(要在外面套一层标签)
  9. template: `
  10. <div>
  11. <h1>{{ zyk01 }}</h1>
  12. <h1>{{ zyk02 }}</h1>
  13. </div>
  14. `,
  15. // data必须是函数,固定写法
  16. data() {
  17. return {
  18. zyk01: 'Hello zyk01',
  19. zyk02: 'Hello zyk02',
  20. };
  21. },
  22. });
  23. new Vue({
  24. el: '#app',
  25. template: '<global-component></global-component>',
  26. });
  27. </script>
  28. </body>

方式二:

  1. <body>
  2. <div id="app">
  3. <!--调用自定义的标签名 可重复调用 -->
  4. <global-component></global-component>
  5. <global-component></global-component>
  6. </div>
  7. <script>
  8. // 下面的'global-component'是自定义的组件名,也是自定义的标签名
  9. Vue.component('global-component', {
  10. // 错误写法:(网页中不会显示)
  11. // template: `<h1>{{ zyk }}</h1><h1>{{ zyk }}</h1>`,
  12. // 正确写法:(要在外面套一层标签)
  13. template: `
  14. <div>
  15. <h1>{{ zyk }}</h1>
  16. </div>
  17. `,
  18. // data必须是函数,固定写法
  19. data() {
  20. return {
  21. zyk: 'Hello zyk',
  22. };
  23. },
  24. });
  25. new Vue({
  26. el: '#app',
  27. });
  28. </script>
  29. </body>


局部组件

全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 无谓的增加。

全局组件适中是存在的,除非程序结束,如果组件越来越大,那么程序所占用的空间和消耗的性能就会更大。

所以我们需要使用局部组件。不用的时候,被垃圾回收。


注册

方式一:

  1. <body>
  2. <div id="app">
  3. <!--第三步:在根元素中使用-->
  4. <!--会将当前div渲染进DOM(也就是这里id为app的div)-->
  5. <my-header></my-header>
  6. </div>
  7. <script>
  8. // 第一步:创建局部组件
  9. let Header = {
  10. template: `
  11. <div>
  12. <button @click='count++'>{{ count }}</button>
  13. <button @click='count++'>{{ count }}</button>
  14. </div>
  15. `,
  16. data() {
  17. return {
  18. count: 0,
  19. };
  20. },
  21. };
  22. new Vue({
  23. el: '#app',
  24. // 第二步:在根实例中调用它
  25. components: {
  26. 'my-header': Header,
  27. },
  28. });
  29. </script>
  30. </body>

方式二:

  1. <body>
  2. <div id="app"></div>
  3. <script>
  4. let Header = {
  5. template: `
  6. <div>
  7. <button @click="count++">{{ count }}</button>
  8. <button @click="count++">{{ count }}</button>
  9. </div>
  10. `,
  11. data() {
  12. return {
  13. count: 0,
  14. };
  15. },
  16. };
  17. new Vue({
  18. el: '#app',
  19. // 这种方法不会将div渲染进DOM,以template为根元素
  20. template: `<my-header></my-header>`,
  21. // template: `<my-header/>`,
  22. components: {
  23. 'my-header': Header,
  24. },
  25. });
  26. </script>
  27. </body>

对于components 对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。


子组件的用法

  1. <body>
  2. <div id="app"></div>
  3. <script>
  4. // 第一步:创建一个局部组件(作为子组件)
  5. let Header01 = {
  6. template: `
  7. <div style='color: green;'>
  8. <h1>{{ greeting }}</h1>
  9. </div>
  10. `,
  11. data () {
  12. return {
  13. greeting: "我是子组件:Header01",
  14. };
  15. },
  16. };
  17. // 再创建一个吧(子组件)
  18. let Header02 = {
  19. template: `
  20. <div style='color: blue;'>
  21. <h1>{{ greeting }}</h1>
  22. </div>
  23. `,
  24. data () {
  25. return {
  26. greeting: "我是子组件:Header02",
  27. };
  28. },
  29. };
  30. // 下面的这个作为父组件
  31. let App = {
  32. // 第二步:在父组件中调用子组件
  33. template: `
  34. <div style='background-color: black;'>
  35. <app-header01></app-header01>
  36. <app-header02></app-header02>
  37. </div>
  38. `,
  39. // 第三步:在父组件中注册子组件
  40. components: {
  41. 'app-header01': Header01,
  42. 'app-header02': Header02,
  43. },
  44. };
  45. new Vue({
  46. el: '#app',
  47. template: `<App></App>`,
  48. components: {
  49. App,
  50. },
  51. });
  52. </script>
  53. </body>

父子组件的通讯

  1. <body>
  2. <div id="app"></div>
  3. <script>
  4. // 子组件
  5. let Header = {
  6. // ==== 第四步:调用提取后的数据 ====
  7. template: `
  8. <div>
  9. <h1>{{ greeting }} {{ fatherData }} </h1>
  10. </div>
  11. `,
  12. // ==== 第三步:提取传入的数据====
  13. props: ['fatherData'],
  14. // props:["传入时指定的关键字", "..."] -> 固定写法,可传入多个值
  15. data() {
  16. return {
  17. greeting: 'Hello',
  18. };
  19. },
  20. };
  21. // 父组件
  22. let App = {
  23. // ==== 第一步:将数据传入子组件 ====
  24. // 下面的:fatherData="name"为传入子组件中数据,前者为传入关键字,后者为data中返回的数据
  25. template: `
  26. <div>
  27. <app-header :fatherData="name"></app-header>
  28. </div>
  29. `,
  30. components: {
  31. 'app-header': Header,
  32. },
  33. data() {
  34. return {
  35. // ==== 第一步:先定义一个数据 ====
  36. name: 'zyk',
  37. };
  38. },
  39. };
  40. new Vue({
  41. el: '#app',
  42. template: `<App></App>`,
  43. components: {
  44. App,
  45. },
  46. });
  47. </script>
  48. </body>

子父组件的通讯

下面示例的基本思路:

·

子组件与父组件各定义一个事件,且子组件事件函数中可触发父组件的事件.

  1. 先触发子组件中的事件——执行子组件事件函数;
  2. 在子组件的事件函数中触发父组件的事件,同时向父组件传入数据;
  3. 父组件事件被触发,同时接收传入的数据,执行事件,ok.
  1. <body>
  2. <div id="app"></div>
  3. <script>
  4. // 子组件
  5. let Header = {
  6. template: `
  7. <div>
  8. <button @click="somClick">点我让BaBa变大</button>
  9. </div>
  10. `,
  11. methods: {
  12. somClick: function () {
  13. // Vue中给我提供的触发自定义事件的方式:
  14. this.$emit('change-size', 0.1);
  15. // this.$emit("父组件事件名", "参数(即传入父组件的数据)")
  16. },
  17. },
  18. };
  19. // 父组件
  20. let App = {
  21. // 下面的change-size是自定义的事件名,fatherClick是事件函数
  22. template: `
  23. <div>
  24. <my-header @change-size="fatherClick"></my-header>
  25. <span :style="{ fontSize: postFontSize + 'em' }">我是BaBa</span>
  26. </div>
  27. `,
  28. components: {
  29. 'my-header': Header,
  30. },
  31. data() {
  32. return {
  33. postFontSize: 1,
  34. };
  35. },
  36. methods: {
  37. fatherClick: function (value) {
  38. // value是this.$emit('change-size', 0.1);传过来的参数(0.1)
  39. this.postFontSize += value;
  40. },
  41. },
  42. };
  43. new Vue({
  44. el: '#app',
  45. template: `<App></App>`,
  46. components: {
  47. App,
  48. },
  49. });
  50. </script>
  51. </body>

非父子组件的通讯

  1. <body>
  2. <div id="app">
  3. <zyk01></zyk01>
  4. <zyk02></zyk02>
  5. </div>
  6. <script>
  7. // 用作中间调度器
  8. let Event = new Vue();
  9. let zyk01 = {
  10. template: `
  11. <div>
  12. <h1>zyk01</h1>
  13. <button @click="click01">点击向zyk02传数据</button>
  14. </div>
  15. `,
  16. methods: {
  17. click01: function () {
  18. // Event.$emit('事件函数名', "要传的数据");
  19. Event.$emit('click02', "这是zyk01向zyk02发送的消息");
  20. },
  21. },
  22. };
  23. let zyk02 = {
  24. template: `
  25. <div>
  26. <h1>zyk02</h1>
  27. <span>{{ say }}</span>
  28. </div>
  29. `,
  30. data() {
  31. return {
  32. say: '',
  33. };
  34. },
  35. mounted() {
  36. let that = this;
  37. // 监听中间调度器中的方法:$on("事件函数名", "要执行的函数")
  38. Event.$on('click02', function (data) {
  39. console.log(data);
  40. that.say = data;
  41. })
  42. }
  43. };
  44. const app = new Vue({
  45. el: '#app',
  46. components: {
  47. zyk01: zyk01,
  48. zyk02: zyk02,
  49. },
  50. });
  51. </script>
  52. </body>


混入

混入可提高代码的重用性.

  1. <body>
  2. <div id="app">
  3. <test01></test01>
  4. <test02></test02>
  5. </div>
  6. <script>
  7. let mixs = {
  8. methods: {
  9. show: function (name) {
  10. console.log(name + "来了");
  11. },
  12. hide: function (name) {
  13. console.log(name + "走了");
  14. },
  15. },
  16. };
  17. let Test01 = {
  18. // mouseenter:获取光标 mouseleave:失去光标
  19. template: `
  20. <div>
  21. <button @mouseenter="show('鼠标01')" @mouseleave="hide('鼠标01')">鼠标01</button>
  22. </div>
  23. `,
  24. mixins: [mixs], // !
  25. };
  26. let Test02 = {
  27. template: `
  28. <div>
  29. <button @mouseenter="show('鼠标02')" @mouseleave="hide('鼠标02')">鼠标02</button>
  30. </div>
  31. `,
  32. mixins: [mixs], // !
  33. };
  34. new Vue({
  35. el: '#app',
  36. components: {
  37. 'test01': Test01,
  38. 'test02': Test02,
  39. },
  40. });
  41. </script>
  42. </body>


插槽

有时候我们需要向组件传递一些数据,这时候可以使用插槽.

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
  5. <title>test</title>
  6. <style>
  7. .box {
  8. width: 50px;
  9. height: 50px;
  10. background-color: green;
  11. float: left;
  12. margin-left: 5px;
  13. }
  14. </style>
  15. </head>
  16. <body>
  17. <div id="app">
  18. <global-component>test01</global-component>
  19. <global-component>test02</global-component>
  20. <global-component>test03</global-component>
  21. <global-component>test04</global-component>
  22. <global-component>test05</global-component>
  23. </div>
  24. <script>
  25. // 下面的<slot></slot>标签,就是插槽(内容分发)
  26. Vue.component("global-component", {
  27. template: `
  28. <div class="box">
  29. <slot></slot>
  30. </div>
  31. `,
  32. });
  33. new Vue({
  34. el: '#app',
  35. });
  36. </script>
  37. </body>
  38. </html>


具名插槽

该操作使用了组件的复用,通过使用具名插槽,我们可以在同一个组件内写入不同的页面,并且给不同的内容命名.

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
  5. <title>test</title>
  6. <style>
  7. .box {
  8. width: 50px;
  9. height: 65px;
  10. background-color: green;
  11. float: left;
  12. margin-left: 5px;
  13. }
  14. </style>
  15. </head>
  16. <body>
  17. <div id="app">
  18. <global-component>
  19. <!--定义具名插槽-->
  20. <div slot="test01">test01</div>
  21. <div slot="test02">test02</div>
  22. <div slot="test03">test03</div>
  23. <div>test04</div>
  24. <div>test05</div>
  25. </global-component>
  26. </div>
  27. <script>
  28. Vue.component("global-component", {
  29. // <slot name="指定上面定义的具名插槽"></slot>
  30. // 注意显示顺序,是按照调用的先后排序的
  31. // 最后面的<slot></slot>是默认插槽(未命名插槽),它会作为所有未匹配到插槽的内容的统一出口
  32. template: `
  33. <div class="box">
  34. <slot name="test01"></slot>
  35. <slot name="test03"></slot>
  36. <slot name="test02"></slot>
  37. <slot></slot>
  38. </div>
  39. `,
  40. });
  41. new Vue({
  42. el: '#app',
  43. });
  44. </script>
  45. </body>
  46. </html>


使用组件的注意事项

单个根元素

当构建一个内容页面的组件时,我们的组件可能包含多个HTML标签。

  1. <h1>Hello World</h1>
  2. <h2>Hello Vue</h2>

然而如果你在模板中尝试这样写,Vue 会显示一个错误,并解释道 every component must have a single root element (每个组件必须只有一个根元素)。你可以将模板的内容包裹在一个父元素内,来修复这个问题,例如:

  1. <div>
  2. <h1>Hello World</h1>
  3. <h2>Hello Vue</h2>
  4. </div>

解析特殊的HTML元素

有些HTML元素,必须< ul >、< ol >、< table >和< select >,对于哪些元素可以出现在其内部是有严格限制的,而有些元素,例如< li >、< tr >和< option >,只能出现在其它某些特定元素的内部。

这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:

  1. <table>
  2. <blog-post-row></blog-post-row>
  3. </table>

这个自定义组件 < blog-post-row > 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is 特性给了我们一个变通的办法:

  1. <table>
  2. <tr is="blog-post-row"></tr>
  3. </table>

需要注意的是,如果我们从以下来源使用模板的话,这条限制是不存在的:

  1. 字符串 (例如:template: '...')
  2. 单文件组件 (.vue)
  3. <script type="text/x-template">


使用组件实现导航栏

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>导航栏</title>
  6. <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
  7. <!-- 引入样式 -->
  8. <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  9. <!-- 引入组件库 -->
  10. <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  11. <style>
  12. body {
  13. margin: 0;
  14. padding: 0;
  15. }
  16. .header {
  17. position: fixed;
  18. top: 0;
  19. left: 0;
  20. width: 100%;
  21. }
  22. .el-menu {
  23. display: flex;
  24. align-items: center;
  25. justify-content: center;
  26. }
  27. .footer {
  28. position: fixed;
  29. bottom: 0;
  30. left: 0;
  31. width: 100%;
  32. }
  33. .header img {
  34. position: absolute;
  35. left: 80px;
  36. top: -4px;
  37. width: 118px;
  38. height: 70px;
  39. z-index: 999;
  40. }
  41. </style>
  42. </head>
  43. <body>
  44. <div id="app">
  45. </div>
  46. <template id="header">
  47. <div class="header">
  48. <img src="https://www.luffycity.com/static/img/head-logo.a7cedf3.svg"/>
  49. <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal">
  50. <el-menu-item index="1">标题01</el-menu-item>
  51. <el-menu-item index="2">标题02</el-menu-item>
  52. <el-menu-item index="3">标题03</el-menu-item>
  53. <el-menu-item index="4">标题04</el-menu-item>
  54. <el-menu-item index="5">标题05</el-menu-item>
  55. <el-menu-item index="6">标题06</el-menu-item>
  56. <el-menu-item index="7">标题07</el-menu-item>
  57. <el-menu-item index="8">标题08</el-menu-item>
  58. </el-menu>
  59. </div>
  60. </template>
  61. <template id="footer">
  62. <div class="footer">
  63. <el-menu class="el-menu-demo" mode="horizontal" background-color="black">
  64. <el-menu-item index="1">关于我们</el-menu-item>
  65. <el-menu-item index="2">联系我们</el-menu-item>
  66. <el-menu-item index="3">商业合作</el-menu-item>
  67. <el-menu-item index="4">帮助中心</el-menu-item>
  68. <el-menu-item index="5">意见反馈</el-menu-item>
  69. <el-menu-item index="6">新手指南</el-menu-item>
  70. </el-menu>
  71. </div>
  72. </template>
  73. <script>
  74. let pageHeader = {
  75. template: "#header",
  76. data() {
  77. return {
  78. activeIndex: "1",
  79. }
  80. }
  81. };
  82. let pageFooter = {
  83. template: "#footer",
  84. };
  85. let App = {
  86. template: `
  87. <div>
  88. <div>
  89. <page-header></page-header>
  90. </div>
  91. <div>
  92. <page-footer></page-footer>
  93. </div>
  94. </div>
  95. `,
  96. components: {
  97. 'page-header': pageHeader,
  98. 'page-footer': pageFooter,
  99. }
  100. };
  101. new Vue({
  102. el: "#app",
  103. template: `<app></app>`,
  104. components: {
  105. 'app': App,
  106. }
  107. })
  108. </script>
  109. </body>
  110. </html>

"

【Vue组件系统】的更多相关文章

  1. vue组件系统

    1. 全局组件的注册 <body>    <div id="app">        <!--<global-component>< ...

  2. Vue 组件系统

    vue.js既然是框架,那就不能只是简单的完成数据模板引擎的任务,它还提供了页面布局的功能.本文详细介绍使用vue.js进行页面布局的强大工具,vue.js组件系统. 每一个新技术的诞生,都是为了解决 ...

  3. 【Vue】详解Vue组件系统

    Vue渲染的两大基础方式 new 一个Vue的实例 这个我们一般会使用在挂载根节点这一初始化操作上: new Vue({ el: '#app' }) 注册组件并使用—— 全局注册 通过Vue.comp ...

  4. Vue框架之组件系统

    1,Vue组件系统之全局组件 1.1Vue全局组件的在实例化调用Vue的模板中导入组件的名称 <!DOCTYPE html> <html lang="zh-cn" ...

  5. Vue.js之组件系统

    vue.js既然是框架,那就不能只是简单的完成数据模板引擎的任务,它还提供了页面布局的功能.本文详细介绍使用vue.js进行页面布局的强大工具,vue.js组件系统. Vue.js组件系统 每一个新技 ...

  6. vue学习之四组件系统

    vue.js既然是框架,那就不能只是简单的完成数据模板引擎的任务,它还提供了页面布局的功能.本文详细介绍使用vue.js进行页面布局的强大工具,vue.js组件系统. 一.Vue.js组件系统 每一个 ...

  7. JS组件系列——又一款MVVM组件:Vue(二:构建自己的Vue组件)

    前言:转眼距离上篇 JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查) 已有好几个月了,今天打算将它捡起来,发现好久不用,Vue相关技术点都生疏不少.经过这几个月的时间,Vue ...

  8. canvas实现倒计时效果示例(vue组件内编写)

    前言: 此事例是在vue组件中,使用canvas实现倒计时动画的效果.其实,实现效果的逻辑跟vue没有关系,只要读懂canvas如何实现效果的这部分逻辑就可以了 canvas动画的原理:利用定时器,给 ...

  9. 一套代码小程序&Web&Native运行的探索06——组件系统

    接上文:一套代码小程序&Web&Native运行的探索05——snabbdom 对应Git代码地址请见:https://github.com/yexiaochai/wxdemo/tre ...

随机推荐

  1. Spring boot unable to determine jdbc url from datasouce

    1. 首先删除 @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) 2. 在配置文件里添加完整的dataso ...

  2. Oracle 中的 Incarnation 到底是个什么?概念理解篇

    高中时候,我深深“爱”上了一位女孩子.那个年纪确实不懂什么是真正的“爱”,反正每天满脑子都是她,只要见到她就会紧张和激动,确切的说是深深的喜欢.你告诉我这叫初恋?不,我的初恋应该是小学3年级,三六班. ...

  3. format的使用

    v="敬爱可亲的{0},最喜欢在{1}地方干{2}" name1=input("名字>") lang=input("地点>") ...

  4. Tensorflow中multiply()函数与matmul()函数的用法区别

    1.tf.multiply()函数:矩阵对应元素相乘 官网定义: multiply(x,y,name=None) 参数: x: 一个类型为:half, float32, float64, uint8, ...

  5. 05 部署mysql关系数据库

    01 安装Mysql 在官网https://dev.mysql.com/上找到自己需要的版本并执行安装 sudo apt-get install mysql-server-5.7 02 运行和退出 # ...

  6. SPDK-nvmf与不同传输类型的公共接口

    SPDK-nvmf与不同传输类型的公共接口 不同类型的传输层到nvmf的公共命令请求接口 nvmf_fc_hwqp_handle_request() -->cmd_iu = buffer-> ...

  7. 题解【AcWing176】装满的油箱

    题面 一开始拿到这个问题并不好做,于是考虑拆点. 考虑将一个点拆成 \(c+1\) 个,每个点表示(编号,剩余油量). 然后 \(\text{Dijkstra}\) 最短路即可. 每次跑 \(\tex ...

  8. Pytest学习6-跳过或xfail失败的用例

    Skip跳过用例 跳过(Skip)指,你希望如果某些条件得到满足你的测试用例才执行,否则Pytest应该完全跳过运行该用例 1. 跳过测试用例的最简单方法是使用skip装饰器标记它,可以传递一个可选的 ...

  9. manifold learning

    MDS, multidimensional scaling, 线性降维方法, 目的就是使得降维之后的点两两之间的距离尽量不变(也就是和在原是空间中对应的两个点之间的距离要差不多).只是 MDS 是针对 ...

  10. Quality and CCPC

    English foundation: the fractional part 小数部分 disclaimer 免责声明 fictitious  虚构的,编造的;假定的,虚设的;小说式的;假装的 No ...