vue从入门到女装??:从零开始搭建后台管理系统(二)vue组件化

683 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

组件化

页面上小到一个按钮都可以是一个单独的文件.vue,这些小组件直接可以像乐高积木一样通过互相引用而组装起来

img

以element-ui的button组件示例,下图的每一个button都是一个单独的组件,以达到代码的最大化复用:

img

组件注册

全局注册

要注册一个全局组件,可以使用 Vue.component(tagName, options),注册在跟实例下。

Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})
局部注册

你不必把每个组件都注册到全局。你可以通过某个 Vue 实例/组件的实例选项 components 注册仅在其作用域中可用的组件。

var Child = {
  template: '<div>A custom component!</div>'
}

new Vue({
  // ...
  components: {
    // <my-component> 将只在父组件模板中可用
    'my-component': Child
  }
})

封装组件

** 封装组件的三种方法: **

vue单页面组件

这种方法常用在vue文件中

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  name: 'hello',
  data () {
    return {
      msg: '欢迎!'
    }
  }
}
</script>
script模板
  <script type="text/x-template" id="myComponent">//注意 type 和id。
      <div>This is a component!</div>
  </script>
  <script>
    //全局注册组件
    Vue.component('my-component',{
        template: '#myComponent'
    })

    new Vue({
        el: '#app'
    })
  </script>
html模板
  <template id="myComponent">
      <div>This is a component!</div>
  </template>
  
  <script>
    Vue.component('my-component',{
        template: '#myComponent'
    })
    new Vue({
        el: '#app'
    })
  </script>

或者

    <script>
    var myComponent = 
            `<div>This is a component!</div>
             <p>----Calamus</p>`;
    Vue.component('my-component',{
        template: myComponent
    })
    new Vue({
        el: '#app'
    })
  </script>

开发组件

安装vue
  • script标签导入
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
  • vue-cli安装

img

  # 全局安装 vue-cli
  $ npm install --global vue-cli
  # 创建一个基于 webpack 模板的新项目
  $ vue init webpack my-project

注意:一些eslink e2e等工具是语法检查用的,建议最开始关闭,不然比较麻烦

img

  # 安装依赖
  $ cd my-project
  $ npm install
  # 运行
  $ npm run dev

运行之后打开localhost:8080,即时vue安装好的页面了

img

  # 打包编译
  $ npm run build

打包成功之后项目目录下会多出dist文件夹,即是打包编译好的项目文件

img

注意:build之后出现页面空白,打开调试发现js、css等资源加载404,是webpack配置相对路径错误导致,如图路径给为 './'即可

img

注意:build之后出现font等字体文件加载错误,也是webpack配置问题,修改build->webpack.base.conf.js 里css-loader的limit值,比你的font文件大即可

img

  • bower安装
  $ bower install vue
开发一个canvas组件示例

效果展示: demo下载 img

  <template>
      <canvas id="canvas">
      </canvas>
  </template>
  <script>
  export default {
      name:'CLCanvasBg',
      props: {
        //原点数量
          dotsNum: {
              type: Number,
              default: 50
          },
          //彩色还是黑白
          isColor: {
              type: Boolean,
              default: true
          },
          //圆的颜色
          roundColor: {
              type: String,
              default: "#999"
          },
          //直线颜色
          lineColor: {
              type: String,
              default: "#ccc"
          }
      },
      mounted() {
          const canvas = document.getElementById("canvas");
          const ctx = canvas.getContext("2d");
          const rndCl = () => Math.floor(Math.random() * 225);
          const width = window.innerWidth;
          const height = window.innerHeight;
          var base_list = [];
          canvas.width = width;
          canvas.height = height;
          // 绘制园
          const drawRounds = (obj, index) => {
              let { x, y, r, color } = obj;
              ctx.beginPath();
              ctx.arc(x, y, r, 0, 2 * Math.PI);
              if (this.isColor) {
                  ctx.fillStyle = color;
              } else {
                  ctx.fillStyle = this.roundColor
              }
              ctx.fill();
              ctx.closePath();
          }

          //判断移动方向
          const controlDirection = (obj) => {
              if (obj.x >= (width - obj.r)) {
                  obj.controlX = "left";
              } else if (obj.x <= parseInt(obj.r / 2)) {
                  obj.controlX = "right";
              }
              if (obj.y >= (height - obj.r)) {
                  obj.controlY = "bottom";
              } else if (obj.y <= parseInt(obj.r / 2)) {
                  obj.controlY = "top"
              }
              return obj
          }
          //划线
          const drawLine = (list) => {
              list.map((item, index) => {
                  ctx.beginPath();
                  ctx.moveTo(item.x1, item.y1);
                  ctx.lineTo(item.x2, item.y2);
                  ctx.LineWeight = 1;
                  if (this.isColor) {
                      ctx.strokeStyle = item.color;
                  } else {
                      ctx.strokeStyle = this.lineColor
                  }
                  ctx.stroke();
                  ctx.closePath();
              })
          }
          //绘制
          const draw = (list) => {
              let dots_arr = [];
              let line_arr = [];
              list.map((item, index) => {
                  let xy = controlDirection(item);
                  let obj = roundMove(xy);
                  dots_arr.push(obj);
              });
              dots_arr.map((item1, index1) => {
                  dots_arr.map((item2, index2) => {
                      if (item1 !== item2) {
                          let x = item1.x - item2.x;
                          let y = item1.y - item2.y;
                          if (Math.abs(x) < 150 && Math.abs(y) < 150) {
                              let obj = {
                                  x1: item1.x,
                                  y1: item1.y,
                                  x2: item2.x,
                                  y2: item2.y,
                                  color: item1.color
                              }
                              line_arr.push(obj)
                          }
                      }
                  })
              })
              drawLine(line_arr);
              dots_arr.map((item, index) => {
                  drawRounds(item, index)
              })
              base_list = dots_arr;
              setTimeout(() => {
                  // if(this.paused){
                  reDraw()
                  // }
              }, 50)
          }
          const reDraw = () => {
              ctx.clearRect(0, 0, width, height);
              draw(base_list)
          }
          //移动
          const roundMove = (obj) => {
              switch (obj.controlX) {
                  case "right":
                      obj.x++;
                      break;
                  case "left":
                      obj.x--;
                      break;
                  default:
              }
              switch (obj.controlY) {
                  case "top":
                      obj.y++;
                      break;
                  case "bottom":
                      obj.y--;
                      break;
                  default:
              }
              return obj
          }
          //创造圆点
          const creatDots = () => {
              let arr = [];
              for (let i = 0; i < this.dotsNum; i++) {
                  let obj = {};
                  obj.x = parseInt(Math.random() * width);
                  obj.y = parseInt(Math.random() * height);
                  obj.r = parseInt(Math.random() * 10);
                  obj.controlX = parseInt(Math.random() * 10) > 5 ? "left" : "right"
                  obj.controlY = parseInt(Math.random() * 10) > 5 ? "bottom" : "top"
                  obj.color = `rgba(${rndCl()},${rndCl()},${rndCl()},.3)`
                  arr.push(obj)
              }
              return arr
          }
          draw(creatDots())
          //鼠标移动
          const moveXY = (event) => {
              let obj = {};
              obj.x = event.clientX;
              obj.y = event.clientY;
              obj.r = 0;
              base_list[0] = obj;
              base_list[0]["r"] = 1;
          }
          //鼠标点击
          const addXY = (event) => {
              let obj = {};
              obj.x = event.clientX;
              obj.y = event.clientY;
              obj.r = parseInt(Math.random() * 10);
              obj.color = `rgba(${rndCl()},${rndCl()},${rndCl()},.3)`;
              obj.controlX = parseInt(Math.random() * 10) > 5 ? 'left' : 'right'
              obj.controlY = parseInt(Math.random() * 10) > 5 ? 'bottom' : 'top'
              base_list.push(obj);
          }
          window.addEventListener("mousemove", moveXY);
          window.addEventListener("click", addXY)
      },

  }
  </script>
  <style>
      #canvas{
          position: fixed;
          z-index: -1;
          top: 0;
          left: 0;
      }
  </style>

在线运行示例:

img

组件三要素
  • prop

prop需要转化成对应的kebab-case (短横线分隔式命名)

组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。父组件的数据需要通过 prop 才能下发到子组件中
  • 自定义事件

  • slot

    <app>
    <app-header></app-header>
    <app-footer></app-footer>
    </app>

为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发 (即 Angular 用户熟知的“transclusion”)。Vue.js 实现了一个内容分发 API,参照了当前 Web Components 规范草案,使用特殊的 元素作为原始内容的插槽。

    <div>
    <h2>我是子组件的标题</h2>
    <slot>
        {{slot作用域}}
    </slot>
    </div>