您好,登錄后才能下訂單哦!
小編給大家分享一下vue組件化開發指的是什么意思,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
在vue中,組件化開發指的是將復雜的業務拆分為多個組件,每個組件依賴的CSS、JS、模板、圖片等資源放在一起開發和維護。因為組件是資源獨立的,所以組件在系統內部可復用,且可以極大簡化代碼量,對后期的需求變更和維護也更加友好。
本教程操作環境:windows7系統、vue2.9.6版,DELL G3電腦。
什么叫做組件化
vue.js 有兩大法寶,一個是數據驅動,另一個就是組件化,那么問題來了,什么叫做組件化,為什么要組件化?接下來我就針對這兩個問題一一解答,所謂組件化,就是把頁面拆分成多個組件,每個組件依賴的 CSS、JS、模板、圖片等資源放在一起開發和維護。 因為組件是資源獨立的,所以組件在系統內部可復用,組件和組件之間可以嵌套,如果項目比較復雜,可以極大簡化代碼量,并且對后期的需求變更和維護也更加友好。
1、組件化開發指的是將復雜的業務拆分為一個又一個的組件
2、組件化開發的組件一般來說要靈活
3、組件化開發涉及到了Vue的js組件封裝,需要掌握Vue基礎、Vue實例方法與屬性、Vue.extend、Vue插件等知識
如何進行組件化開發
先看下圖:
這是 vue.js 中的一個報錯,原因是使用了一個未經注冊的組件 lx-xxx
,這個報錯告訴我們一個道理:使用自定義組件之前必須注冊。
那么如何注冊一個組件呢? Vue.js 提供了 2 種組件的注冊方式,全局注冊和局部注冊。
在 vue.js 中我們可以使用 Vue.component(tagName, options) 進行全局注冊,例如
Vue.component('my-component', { // 選項 })
Vue.js 也同樣支持局部注冊,我們可以在一個組件內部使用 components 選項做組件的局部注冊,例如:
import HelloWorld from './components/HelloWorld' export default { components: { HelloWorld } }
區別:全局組件是掛載在 Vue.options.components
下,而局部組件是掛載在 vm.$options.components
下,這也是全局注冊的組件能被任意使用的原因。
所謂工欲善其事,必先利其器,在正式開發一個組件之前,我們先要掌握一些必備的知識,這里我只會簡單介紹一下,詳情參考官網。
name
組件的名稱,必填
<lx-niu/> <lx-niu></lx-niu/> name: 'lxNiu'
js 中使用駝峰式命令,HTML 使用kebab-case命名。
props
組件屬性,用于父子組件通信,可通過this.msg訪問
<div>{{msg}}</div> props: { msg: { type: String, default: '' } } show: Boolean // 默認false msg: [String, Boolean] // 多種類型
computed
處理data或者props中的屬性,并返回一個新屬性
<div>{{newMsg}}</div> computed: { newMsg() { return 'hello ' + this.msg } },
注:因為props,data和computed在編譯階段都會作為vm的屬性合并,所以不可重名
render
用render函數描述template
<lx-niu tag='button'>hello world</lx-niu> <script type="text/javascript"> export default { name: 'lxNiu', props: { tag: { type: String, default: 'div' }, }, // h: createElement render(h) { return h(this.tag, {class: 'demo'}, this.$slots.default) } } </script>
render 中的 h 其實就是 createElement,它接受三個參數,返回一個 vnode
h 參數解釋:
args1: {string | Function | Object} 用于提供DOM的html內容
args2: {Object} 設置DOM樣式、屬性、綁定事件之類
args3: {array} 用于設置分發的內容
注:vue編譯順序: template–> compile --> render --> vnode --> patch --> DOM
slot
<lx-niu> <div slot='header'>header</div> <div class="body" slot='body'> <input type="text"> </div> <div slot='footer'>footer</div> <button class='btn'>button</button> </lx-niu> <template> <div> <slot name='header'></slot> <slot name='body'></slot> <slot name='footer'></slot> <slot></slot> </div> </template> <script> export default { name: 'lxNiu', mounted() { this.$slots.header // 包含了slot="foo"的內容 this.$slots.default // 得到一個vnode,沒有被包含在具名插槽中的節點,這里是button } } </script>
class
定義子組件的類名
// 父組件 <lx-niu round type='big'/> // 子組件 <div :class="[ type ? 'lx-niu__' + type : '', {'is-round': round}, ]">控制</div> //真實DOM <div class='lx-niu__big is-round'>hello</div>
style
向子組件傳遞樣式
// 父組件 <lx-niu :bodyStyle='{color: "red"}'/> // 子組件 <template> <div :style='bodyStyle'>hello world</div> </template> <script> export default { name: 'lxNiu', props: { bodyStyle: {}, }, } </script>
其他屬性
$attrs
v-bind="$attrs" 將除class和style外的屬性添加到父組件上,如定義input:
<input v-bind="$attrs">
v-once
組件只渲染一次,后面即使數據發生變化也不會重新渲染,比如例子中val不會變成456
<template> <div> <button @click="show = !show">button</button> <button @click="val = '456'">button</button> <div v-once v-if="show"> <span>{{val}}</span> </div> </div> </template> <script> export default { data() { return{ show: false, val: '123' } }, }; </script>
mixins
// mixin.js export default { data() { return{ msg: 'hello world' } }, methods: { clickBtn() { console.log(this.msg) } }, } // index.vue <button @click="clickBtn">button</button> import actionMixin from "./mixin.js"; export default { methods: {}, mixins: [actionMixin] }
比如我們要注冊一個 lx-button 這樣一個組件,那么目錄和偽代碼如下:
index.vue
<template> <button>lxButton</button> </template> <script> export default { name: 'lxButton' } </script>
index.js
import lxButton from './src/index' lxButton.install = (Vue) => { Vue.component(lxButton.name, lxButton) } export default lxButton
其中 install
是 Vue.js 提供了一個公開方法,這個方法的第一個參數是 Vue 構造器,第二個參數是一個可選的選項對象。MyPlugin.install = function (Vue, options){}
參考: 開發插件
https://cn.vuejs.org/v2/guide/plugins.html#%E5%BC%80%E5%8F%91%E6%8F%92%E4%BB%B6
watch-彈窗實現原理
<button @click="dialogVisible = true">顯示</button> <lx-niu :visible.sync="dialogVisible"></lx-niu> <script> export default { data() { return { dialogVisible: false } }, watch: { dialogVisible(val) { console.log('father change', val) } } } </script>
定義組件
<template> <div v-show="visible"> <button @click="hide">關閉</button> </div> </template> <script> export default { name: 'lxNiu', props: { visible: Boolean }, watch: { visible(val) { console.log('child change:', val) } }, methods: { hide() { this.$emit('update:visible', false); } }, } </script>
點擊父組件中的顯示
按鈕,改變傳入子組件中的值,點擊子組件中的關閉
,改變父組件中值。
注:@click=“dialogVisible = true” 點擊時將dialogVisible的值改為true
注::visible.sync: 雙向數據綁定,配合update:visible使用,實現子組件修改父組件中的值
官網解釋: sync
col組件實例
export default { name: 'ElCol', props: { span: { type: Number, default: 24 }, tag: { type: String, default: 'div' }, offset: Number, pull: Number, push: Number, xs: [Number, Object], sm: [Number, Object], md: [Number, Object], lg: [Number, Object], xl: [Number, Object] }, computed: { gutter() { let parent = this.$parent; while (parent && parent.$options.componentName !== 'ElRow') { parent = parent.$parent; } return parent ? parent.gutter : 0; } }, render(h) { let classList = []; let style = {}; if (this.gutter) { style.paddingLeft = this.gutter / 2 + 'px'; style.paddingRight = style.paddingLeft; } ['span', 'offset', 'pull', 'push'].forEach(prop => { if (this[prop] || this[prop] === 0) { classList.push( prop !== 'span' ? `el-col-${prop}-${this[prop]}` : `el-col-${this[prop]}` ); } }); ['xs', 'sm', 'md', 'lg', 'xl'].forEach(size => { if (typeof this[size] === 'number') { classList.push(`el-col-${size}-${this[size]}`); } else if (typeof this[size] === 'object') { let props = this[size]; Object.keys(props).forEach(prop => { classList.push( prop !== 'span' ? `el-col-${size}-${prop}-${props[prop]}` : `el-col-${size}-${props[prop]}` ); }); } }); return h(this.tag, { class: ['el-col', classList], style }, this.$slots.default); } };
col組件使用render函數,而不是template來實現組件,原因有兩個:
該組件有大量的類判斷,如果采用template代碼比較冗余,使用js代碼更加簡潔
直接render描述性能更好
官網解釋: render-function
button組件實例
<template> <button class="el-button" @click="handleClick" :disabled="buttonDisabled || loading" :autofocus="autofocus" :type="nativeType" :class="[ type ? 'el-button--' + type : '', buttonSize ? 'el-button--' + buttonSize : '', { 'is-disabled': buttonDisabled, 'is-loading': loading, 'is-plain': plain, 'is-round': round, 'is-circle': circle } ]" > <i class="el-icon-loading" v-if="loading"></i> <i :class="icon" v-if="icon && !loading"></i> <span v-if="$slots.default"><slot></slot></span> </button> </template> <script> export default { name: 'ElButton', inject: { elForm: { default: '' }, elFormItem: { default: '' } }, props: { type: { type: String, default: 'default' }, size: String, icon: { type: String, default: '' }, nativeType: { type: String, default: 'button' }, loading: Boolean, disabled: Boolean, plain: Boolean, autofocus: Boolean, round: Boolean, circle: Boolean }, computed: { _elFormItemSize() { return (this.elFormItem || {}).elFormItemSize; }, buttonSize() { return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size; }, buttonDisabled() { return this.disabled || (this.elForm || {}).disabled; } }, methods: { handleClick(evt) { this.$emit('click', evt); } } }; </script>
局部組件實例
<template> <div class="login"> <login-header /> <login-request /> <login-footer /> </div> </template> <script> import loginHeader from './login-header'; import loginRequest from './login-request'; import loginFooter from './login-footer'; export default { components: { [loginHeader.name]: loginHeader, [loginRequest.name]: loginRequest, [loginFooter.name]: loginFooter } }; </script>
看完了這篇文章,相信你對“vue組件化開發指的是什么意思”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。