# 一.Layout

# 组件目录

# element-plus
├── packages
│   ├── components
│   │  ├── row             # row组件
│   │  │ ├── src
│   │  │ │ └── row.ts
│   │  │ ├── style
│   │  │ │ ├── css.ts
│   │  │ │ └── index.ts
│   │  └── index.ts        # 组件注册的入口文件
1
2
3
4
5
6
7
8
9
10
# element-plus
├── packages
│   ├── components
│   │  ├── col             # col组件
│   │  │ ├── src
│   │  │ │ └── col.ts
│   │  │ ├── style
│   │  │ │ ├── css.ts
│   │  │ │ └── index.ts
│   │  └── index.ts        # 组件注册的入口文件
1
2
3
4
5
6
7
8
9
10

# row.ts

  • 简化后的代码
import { defineComponent, computed, h, provide } from "vue"

export default defineComponent({
  name: "ElRow",
  props: {
    tag: {
      type: String,
      default: "div",
    },
    gutter: {
      type: Number,
      default: 0,
    },
    justify: {
      type: String,
      default: "start",
    },
    align: {
      type: String,
      default: "top",
    },
  },
  setup(props, { slots }) {
    const gutter = computed(() => props.gutter)
    provide("ElRow", {
      // row组件下面一般会有col组件,col组件内部会有一个inject方法接受上面的gutter值
      gutter,
    })
    const style = computed(() => {
      const ret = {
        marginLeft: "",
        marginRight: "",
      }
      if (props.gutter) {
        ret.marginLeft = `-${props.gutter / 2}px`
        ret.marginRight = ret.marginLeft
      }
      return ret
    })
    return () =>
      h(
        //使用render方式渲染这个组件,tag默认为div元素,可以根据用户传入的值而定
        props.tag,
        {
          class: [
            "el-row",
            props.justify !== "start" ? `is-justify-${props.justify}` : "",
            props.align !== "top" ? `is-align-${props.align}` : "",
          ],
          style: style.value,
        },
        slots.default?.() //render下面,默认插槽的方式
      )
  },
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

最新代码 (opens new window)

大体流程

  • 1.通过入口文件将 row 组件注册到 vue 组件中
  • 2.用户使用 row 组件,添加各种 props 和方法
  • 3.row 组件内部接收 props
  • 4.监听 gutter 变化,传递给子组件
  • 5.监听 gutter 变化,生成样式对象
  • 6.通过返回一个 render 对象,渲染组件的标签和类以及样式和插槽

# col.ts

import { defineComponent, computed, inject, h } from 'vue'
import type { PropType } from 'vue'

type SizeObject = {
  span: number
  offset: number
}
const ElCol = defineComponent({
  name: 'ElCol',
  props: {
    tag: {
      type: String,
      default: 'div',
    },
    span: {
      type: Number,
      default: 24,
    },
    offset: {
      type: Number,
      default: 0,
    },
    pull: {
      type: Number,
      default: 0,
    },
    push: {
      type: Number,
      default: 0,
    },
    xs: {
      type: [Number, Object] as PropType<number | SizeObject>,
      default: () => ({} as SizeObject),
    },
    sm: {
      type: [Number, Object] as PropType<number | SizeObject>,
      default: () => ({} as SizeObject),
    },
    md: {
      type: [Number, Object] as PropType<number | SizeObject>,
      default: () => ({} as SizeObject),
    },
    lg: {
      type: [Number, Object] as PropType<number | SizeObject>,
      default: () => ({} as SizeObject),
    },
    xl: {
      type: [Number, Object] as PropType<number | SizeObject>,
      default: () => ({} as SizeObject),
    },
  },
  setup(props, { slots }) {
    const { gutter } = inject('ElRow', { gutter: { value: 0 } })
    const style = computed(() => {
      if (gutter.value) {
        return {
          paddingLeft: gutter.value / 2 + 'px',
          paddingRight: gutter.value / 2 + 'px',
        }
      }
      return {}
    })
    const classList = computed(() => {
      const ret: string[] = []
      const pos = ['span', 'offset', 'pull', 'push'] as const
      pos.forEach((prop) => {
        const size = props[prop]
        if (typeof size === 'number') {
          if (prop === 'span') ret.push(`el-col-${props[prop]}`)
          else if (size > 0) ret.push(`el-col-${prop}-${props[prop]}`)
        }
      })
      const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const
      sizes.forEach((size) => {
        if (typeof props[size] === 'number') {
          ret.push(`el-col-${size}-${props[size]}`)
        } else if (typeof props[size] === 'object') {
          const sizeProps = props[size]
          Object.keys(sizeProps).forEach((prop) => {
            ret.push(
              prop !== 'span'
                ? `el-col-${size}-${prop}-${sizeProps[prop]}`
                : `el-col-${size}-${sizeProps[prop]}`
            )
          })
        }
      })
      // this is for the fix
      if (gutter.value) {
        ret.push('is-guttered')
      }
      return ret
    })
    return () =>
      h(
        props.tag,
        {
          class: ['el-col', classList.value],
          style: style.value,
        },
        slots.default?.()
      )
  },
})
export default ElCol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

最新代码 (opens new window)

大体流程

  • 1.通过入口文件将 col 组件注册到 vue 组件中
  • 2.用户使用 col 组件,添加各种 props 和方法
  • 3.col 组件内部接收 props
  • 4.监听 gutter 变化,传递给子组件
  • 5.监听 gutter 变化,生成样式对象
  • 6.通过返回一个 render 对象,渲染组件的标签和类以及样式和插槽