Vue组件化设计启发
2020-06-06 本文已影响0人
夏海峰
现代化MVVM框架两大主要特点,分别是响应式和组件化。前者在声明式、虚拟DOM、Diff运算的基础上,实现了模型与视图的同步更新;后者犹如搭积木一样,把UI需求、业务需求剥离(封装)成一个个方便复用的组件。这为复杂的数据化应用提供了高效的解决方案。
在使用类似MVVM框架的时候,一定要理解响应式、声明式等底层原理。有了这样的理论基础,还要能够科学地良好地快速地进行组件设计。组件设计常与数据息息相关,相同的需求、不同的数据结构,常常会导致不同的组件设计方案。可以这么讲,数据结构是影响组件设计的最主要因素。
组件化(组件设计)特别能够体现出前端开发者的能力水平。我个人习惯把组件划分为两类:一类是纯UI组件,根据后端数据进行UI渲染,几乎不涉及到数据操作;另一类是业务组件,常常需要涉及到业务数据的处理。我个人认为一个合格的前端开发者,必须要具备良好的数据思维。
下面给出两个小例子:不一定能充分说明问题,但仍然能体现出数据结构对于组件设计的重要影响,大家可以重点关注其中声明式数据结构的差异,从而导致的组件设计思路的不同。希望能够启发初级前端开发者认识到数据之于组件的重要性。
例(1)<!DOCTYPE html>
<html lang="en">
<head>
<style>
.item {
display: inline-block;
background: #eee; padding: 5px 10px;
margin: 10px; cursor: pointer;
}
.on {
color: orange; font-weight: bold;
}
</style>
</head>
<body>
<div id='app'>
<div>标赔</div>
<my-row :list='list1' v-model='index'></my-row>
<div>让球</div>
<my-row :list='list2' v-model='index'></my-row>
<my-row :list='list3' v-model='index'></my-row>
<h2>你选择的结果是:<span v-text='rate.title'></span></h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
// my-row表示demo效果中的“一行”
Vue.component('my-row', {
props: {
list: {
type: Array,
required: true
},
value: {
type: Number,
required: true
}
},
template: `
<div>
<span
:class="{'on': item.id == value}"
class='item'
v-for='item in list'
:key='item.id'
v-text='item.title'
@click='change(item)'>
</span>
</div>
`,
methods: {
change(item) {
this.$emit('input', item.id)
}
}
})
var app = new Vue({
el: '#app',
data: {
list1: [{id:1,title:'1.01'}, {id:2,title: '1.02'}, {id:3,title:'1.03'}, {id:4,title: '1.04'}],
list2: [{id:5,title:'1.05'}, {id:6,title: '1.06'}, {id:7,title:'1.07'}, {id:8,title: '1.08'}],
list3: [{id:9,title:'1.09'}, {id:10,title: '1.10'}, {id:11,title:'1.11'}, {id:12,title: '1.12'}],
index: 1,
},
computed: {
rate: function() {
return [...this.list1, ...this.list2, ...this.list3].find(ele=>ele.id==this.index)
}
}
})
</script>
</body>
</html>
例(2)
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.item {
display: inline-block;
background: #eee; padding: 5px 10px;
margin: 10px; cursor: pointer;
}
.on {
color: orange; font-weight: bold;
}
</style>
</head>
<body>
<div id='app'>
<my-bet :list='list' v-model='index'></my-bet>
<h2>你选择的结果是:<span v-text='rate.title'></span></h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component('my-bet', {
props: {
list: {
type: Array,
required: true
},
value: {
type: Number,
required: true
}
},
template: `
<div>
<div v-for='(item,index) in list' :key='index'>
<div v-text='item.title'></div>
<div v-for='(item,index) in item.list' :key='index'>
<span class='item' v-text='item.title'></span>
<span
class='item'
v-for='item in item.list'
v-text='item.title'
:key='item.id'
:class='{"on":value==item.id}'
@click='change(item)'>
</span>
</div>
</div>
</div>
`,
methods: {
change: function(item) {
this.$emit('input', item.id)
}
}
})
var app = new Vue({
el: '#app',
data: {
list: [
{
title: '标赔',
list: [
{
title: 'A',
list: [{id:1,title:'1.01'}, {id:2,title: '1.02'}, {id:3,title:'1.03'}]
}
]
},
{
title: '让球',
list: [
{
title: 'B',
list: [{id:4,title:'1.04'}, {id:5,title: '1.05'}, {id:6,title:'1.06'}],
},
{
title: 'C',
list: [{id:7,title:'1.07'}, {id:8,title: '1.08'}, {id:9,title:'1.09'}]
}
]
}
],
index: 1
},
computed: {
rate: function() {
var rate = 0
this.list.map(ele=>{
ele.list.map(ele=>{
ele.list.map(ele=>{
if(ele.id == this.index) rate = ele
})
})
})
return rate
}
}
})
</script>
</body>
</html>
END!!!