Vue自定义组件

Vue自定义组件

现在比较流行的就是组件化、模块化,因为这可以给我们带来快速和方便、提高开发效率。在ReactAngularVue已经为自定义可复用组件提供了方便快捷的方式,这就是我们今天要说的内容-在Vue中如何自定义可复用组件。

简单示例

全局定义注册

首先,我们先在main.js定义一个简单的全局组件:

1
2
3
Vue.component('MyComponent', {
template: '<span>自定义组件</span>'
})

局部注册定义

我们直接在HelloWorld.vue定义我们的组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
let myComponent={
template: '<span>自定义组件</span>'
}
export default {
components:{
"MyComponent":myComponent
},
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>

组件使用

HelloWorld.vue引入我们自定义的组件:

1
2
3
4
5
<template>
<div class="hello">
<my-component></my-component>
</div>
</template>

最后我们可以看到:

这里组件的名字支持:

  • 短横线,如:my-component,用法:<my-component></my-component>
  • 小驼峰,如:myComponent,用法:<my-component></my-component>
  • 大驼峰,如:MyComponent,用法:<my-component></my-component>

组件Prop属性

既然自定组件,那么肯定会有一些属性字段需要动态绑定值,这里我们就要借助Prop来实现我们的组件属性。我們先來熟悉一下Prop屬性的用法:

  • 數組類型,如:props: ['authorName','age'];
  • 對象,對象方式支持指定屬性的值類型:
    1
    2
    3
    4
    props: {
    authorName: String,
    age:Number,
    }
    對象方式支持屬性值驗證,如:
    1
    2
    3
    4
    props: {
    authorName: {type:String,required: true},
    age:{type:Number,default: 100},
    }
    這裡的類型支持一下幾種:
  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名。

Prop示例

我們將上面的組件稍作修改:

1
2
3
4
5
6
7
8
9
let myComponent = {
template: "<span>自定义组件的作者:{{authorName}},年齡:{{age}}歲</span>",
props: {
authorName: String,
age:Number,
}
};

<my-component author-name="eyiadmin" age="1024"></my-component>

最終呈現:
.
我們剛才的值的靜態屬性值,如果我們想動態綁定屬性值怎麼做呢?直接上代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default {
components: {
myComponent: myComponent
},
name: "HelloWorld",
data() {
return {
msg: "Welcome to Your Vue.js App",
name:'eyiadmin',
age:1024
};
}
};

<my-component v-bind:author-name="name" v-bind:age="age"></my-component>
或者這樣
<my-component :author-name="name" :age="age"></my-component>
傳入對象

我們把屬性值當做對象傳遞,這樣我們就需要做一些調整:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export default {
components: {
myComponent: myComponent
},
name: "HelloWorld",
data() {
return {
msg: "Welcome to Your Vue.js App",
authorInfo: {
authorName: "eyiadmin",
age: 1024
}
};
}
};
# 指定對象屬性值
<my-component :author-name="authorInfo.authorName" :age="authorInfo.age"></my-component>
# 傳遞整個對象
<my-component v-bind="authorInfo"></my-component>

最終效果和上面一樣,就不再附效果圖。在VueProp類型只支持单向数据流,即父级 prop 的更新会向下流动到子组件中,但是反过来则不行。但是我們會有場景用到子組件改變父組件的值,這個我們後面再說。

組件插槽

Vueslot有什麼用呢?剛才我們在自定義組件的時候,我們的使用方式是這樣的:

1
<my-component :author-name="authorInfo.authorName" :age="authorInfo.age"></my-component>

但是我們不能這樣:

1
2
3
<my-component :author-name="authorInfo.authorName" :age="authorInfo.age">hello world</my-component>
或者
<my-component :author-name="authorInfo.authorName" :age="authorInfo.age"><my-component :author-name="authorInfo.authorName" :age="authorInfo.age"></my-component></my-component>

顯然,有時候我們是希望能不能不能這樣的變為可以這樣。這時候slot就可以發揮作用了。我們將我們的組件模版稍作調整:

1
template: "<span>自定义组件的作者:{{authorName}},年齡:{{age}}歲<br/><slot></slot></span>"

這下我們就可以這樣用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
export default {
components: {
myComponent: myComponent
},
name: "HelloWorld",
data() {
return {
msg: "Welcome to Your Vue.js App",
authorInfo: {
authorName: "eyiadmin",
age:1024
},
childInfo: {
authorName: "eyiadmin_child",
age:100
}
};
}
};

<my-component v-bind="authorInfo">
<my-component v-bind="childInfo"></my-component>
</my-component>

我就可以看到
,
我們再來簡單看看element的使用方式,就拿我們常用的header為例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<header class="el-header" :style="{ height }">
<slot></slot>
</header>
</template>

<script>
export default {
name: 'ElHeader',
componentName: 'ElHeader',
props: {
height: {
type: String,
default: '60px'
}
}
};
</script>

Headerindex.js中來註冊,這個註冊是按需引入的時候註冊。

1
2
3
4
5
6
7
8
import Header from './src/main';

/* istanbul ignore next */
Header.install = function(Vue) {
Vue.component(Header.name, Header);
};

export default Header;

我們可以在src/index.js看到全局註冊的方式:

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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/* Automatically generated by './build/bin/build-entry.js' */

import Pagination from '../packages/pagination/index.js';
import Dialog from '../packages/dialog/index.js';
import Autocomplete from '../packages/autocomplete/index.js';
import Dropdown from '../packages/dropdown/index.js';
import DropdownMenu from '../packages/dropdown-menu/index.js';
import DropdownItem from '../packages/dropdown-item/index.js';
import Menu from '../packages/menu/index.js';
import Submenu from '../packages/submenu/index.js';
import MenuItem from '../packages/menu-item/index.js';
import MenuItemGroup from '../packages/menu-item-group/index.js';
import Input from '../packages/input/index.js';
import InputNumber from '../packages/input-number/index.js';
import Radio from '../packages/radio/index.js';
import RadioGroup from '../packages/radio-group/index.js';
import RadioButton from '../packages/radio-button/index.js';
import Checkbox from '../packages/checkbox/index.js';
import CheckboxButton from '../packages/checkbox-button/index.js';
import CheckboxGroup from '../packages/checkbox-group/index.js';
import Switch from '../packages/switch/index.js';
import Select from '../packages/select/index.js';
import Option from '../packages/option/index.js';
import OptionGroup from '../packages/option-group/index.js';
import Button from '../packages/button/index.js';
import ButtonGroup from '../packages/button-group/index.js';
import Table from '../packages/table/index.js';
import TableColumn from '../packages/table-column/index.js';
import DatePicker from '../packages/date-picker/index.js';
import TimeSelect from '../packages/time-select/index.js';
import TimePicker from '../packages/time-picker/index.js';
import Popover from '../packages/popover/index.js';
import Tooltip from '../packages/tooltip/index.js';
import MessageBox from '../packages/message-box/index.js';
import Breadcrumb from '../packages/breadcrumb/index.js';
import BreadcrumbItem from '../packages/breadcrumb-item/index.js';
import Form from '../packages/form/index.js';
import FormItem from '../packages/form-item/index.js';
import Tabs from '../packages/tabs/index.js';
import TabPane from '../packages/tab-pane/index.js';
import Tag from '../packages/tag/index.js';
import Tree from '../packages/tree/index.js';
import Alert from '../packages/alert/index.js';
import Notification from '../packages/notification/index.js';
import Slider from '../packages/slider/index.js';
import Loading from '../packages/loading/index.js';
import Icon from '../packages/icon/index.js';
import Row from '../packages/row/index.js';
import Col from '../packages/col/index.js';
import Upload from '../packages/upload/index.js';
import Progress from '../packages/progress/index.js';
import Spinner from '../packages/spinner/index.js';
import Message from '../packages/message/index.js';
import Badge from '../packages/badge/index.js';
import Card from '../packages/card/index.js';
import Rate from '../packages/rate/index.js';
import Steps from '../packages/steps/index.js';
import Step from '../packages/step/index.js';
import Carousel from '../packages/carousel/index.js';
import Scrollbar from '../packages/scrollbar/index.js';
import CarouselItem from '../packages/carousel-item/index.js';
import Collapse from '../packages/collapse/index.js';
import CollapseItem from '../packages/collapse-item/index.js';
import Cascader from '../packages/cascader/index.js';
import ColorPicker from '../packages/color-picker/index.js';
import Transfer from '../packages/transfer/index.js';
import Container from '../packages/container/index.js';
import Header from '../packages/header/index.js';
import Aside from '../packages/aside/index.js';
import Main from '../packages/main/index.js';
import Footer from '../packages/footer/index.js';
import Timeline from '../packages/timeline/index.js';
import TimelineItem from '../packages/timeline-item/index.js';
import Link from '../packages/link/index.js';
import Divider from '../packages/divider/index.js';
import Image from '../packages/image/index.js';
import Calendar from '../packages/calendar/index.js';
import Backtop from '../packages/backtop/index.js';
import InfiniteScroll from '../packages/infinite-scroll/index.js';
import PageHeader from '../packages/page-header/index.js';
import CascaderPanel from '../packages/cascader-panel/index.js';
import Avatar from '../packages/avatar/index.js';
import Drawer from '../packages/drawer/index.js';
import Popconfirm from '../packages/popconfirm/index.js';
import locale from 'element-ui/src/locale';
import CollapseTransition from 'element-ui/src/transitions/collapse-transition';

const components = [
Pagination,
Dialog,
Autocomplete,
Dropdown,
DropdownMenu,
DropdownItem,
Menu,
Submenu,
MenuItem,
MenuItemGroup,
Input,
InputNumber,
Radio,
RadioGroup,
RadioButton,
Checkbox,
CheckboxButton,
CheckboxGroup,
Switch,
Select,
Option,
OptionGroup,
Button,
ButtonGroup,
Table,
TableColumn,
DatePicker,
TimeSelect,
TimePicker,
Popover,
Tooltip,
Breadcrumb,
BreadcrumbItem,
Form,
FormItem,
Tabs,
TabPane,
Tag,
Tree,
Alert,
Slider,
Icon,
Row,
Col,
Upload,
Progress,
Spinner,
Badge,
Card,
Rate,
Steps,
Step,
Carousel,
Scrollbar,
CarouselItem,
Collapse,
CollapseItem,
Cascader,
ColorPicker,
Transfer,
Container,
Header,
Aside,
Main,
Footer,
Timeline,
TimelineItem,
Link,
Divider,
Image,
Calendar,
Backtop,
PageHeader,
CascaderPanel,
Avatar,
Drawer,
Popconfirm,
CollapseTransition
];

const install = function(Vue, opts = {}) {
locale.use(opts.locale);
locale.i18n(opts.i18n);

components.forEach(component => {
Vue.component(component.name, component);
});

Vue.use(InfiniteScroll);
Vue.use(Loading.directive);

Vue.prototype.$ELEMENT = {
size: opts.size || '',
zIndex: opts.zIndex || 2000
};

Vue.prototype.$loading = Loading.service;
Vue.prototype.$msgbox = MessageBox;
Vue.prototype.$alert = MessageBox.alert;
Vue.prototype.$confirm = MessageBox.confirm;
Vue.prototype.$prompt = MessageBox.prompt;
Vue.prototype.$notify = Notification;
Vue.prototype.$message = Message;

};

/* istanbul ignore if */
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue);
}

export default {
version: '2.13.0',
locale: locale.use,
i18n: locale.i18n,
install,
CollapseTransition,
Loading,
Pagination,
Dialog,
Autocomplete,
Dropdown,
DropdownMenu,
DropdownItem,
Menu,
Submenu,
MenuItem,
MenuItemGroup,
Input,
InputNumber,
Radio,
RadioGroup,
RadioButton,
Checkbox,
CheckboxButton,
CheckboxGroup,
Switch,
Select,
Option,
OptionGroup,
Button,
ButtonGroup,
Table,
TableColumn,
DatePicker,
TimeSelect,
TimePicker,
Popover,
Tooltip,
MessageBox,
Breadcrumb,
BreadcrumbItem,
Form,
FormItem,
Tabs,
TabPane,
Tag,
Tree,
Alert,
Notification,
Slider,
Icon,
Row,
Col,
Upload,
Progress,
Spinner,
Message,
Badge,
Card,
Rate,
Steps,
Step,
Carousel,
Scrollbar,
CarouselItem,
Collapse,
CollapseItem,
Cascader,
ColorPicker,
Transfer,
Container,
Header,
Aside,
Main,
Footer,
Timeline,
TimelineItem,
Link,
Divider,
Image,
Calendar,
Backtop,
InfiniteScroll,
PageHeader,
CascaderPanel,
Avatar,
Drawer,
Popconfirm
};

當我們在main.js使用Vue.use注册插件的时候,就会执行對應的install方法來註冊我們的組件。
當然,自定義組件還有很多東西沒有說,今天在忙著吧一百多億的數據遷移到其他數據庫,有點小忙,所有其他的東西後面我們再來細說,比如自定義組件中的自定義事件等。大家如果有深入研究的興趣,可以去https://cn.vuejs.org/,在結合一個開源的UI框架邊學習邊分析源碼,對學習的幫助比較大,例如可以結合element源碼來一起學習。

#
You forgot to set the qrcode for Alipay. Please set it in _config.yml.
You forgot to set the qrcode for Wechat. Please set it in _config.yml.
You forgot to set the business and currency_code for Paypal. Please set it in _config.yml.
You forgot to set the url Patreon. Please set it in _config.yml.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×