此实例主要涉及vue的组件,computed等知识。
上js代码:
// The raw data to observe
var stats = [ // 定义初始的数据
{ label: 'A', value: 100 },
{ label: 'B', value: 100 },
{ label: 'C', value: 100 },
{ label: 'D', value: 100 },
{ label: 'E', value: 100 },
{ label: 'F', value: 100 }
]
// A resusable polygon graph component
Vue.component('polygraph', { // 定义并注册一个图形组件
props: ['stats'], // 传递父组件传递来的数据
template: '#polygraph-template',
replace: true,
computed: {
// 实时响应图形中的point,通过改变stat的value,来改变图形
points: function () {
var total = this.stats.length
return this.stats.map(function (stat, i) { // 遍历stats中的每个值,计算出各个点的位置
var point = valueToPoint(stat.value, i, total)
return point.x + ',' + point.y
}).join(' ')
}
},
components: {
// 一个子组件,可调整stats中value的值
'axis-label': {
props: {
stat: Object,
index: Number,
total: Number
},
template: '#axis-label-template',
replace: true,
computed: {
point: function () {
return valueToPoint(
+this.stat.value + 10,
this.index,
this.total
)
}
}
}
}
})
// 通过数学方法来画图
function valueToPoint (value, index, total) {
var x = 0
var y = -value * 0.8
var angle = Math.PI * 2 / total * index
var cos = Math.cos(angle)
var sin = Math.sin(angle)
var tx = x * cos - y * sin + 100
var ty = x * sin + y * cos + 100
return {
x: tx,
y: ty
}
}
// 创建根实例
new Vue({
el: '#demo',
data: {
newLabel: '',
stats: stats
},
methods: {
add: function (e) {
e.preventDefault() // 取消事件的默认动作
if (!this.newLabel) return
this.stats.push({
label: this.newLabel,
value: 100
})
this.newLabel = ''
},
remove: function (stat) {
if (this.stats.length > 3) {
this.stats.$remove(stat) // $remove 是vue添加的方法,从目标数组中查找并删除元素,在内部它调用 splice()
} else {
alert('Can\'t delete more!')
}
}
}
})
再来看看我们的html代码:
<!-- polygraph组件的template,其中包含子组件的调用 -->
<script type="text/x-template" id="polygraph-template">
<g>
<polygon :points="points"></polygon>
<circle cx="100" cy="100" r="80"></circle>
<axis-label
v-for="stat in stats"
:stat="stat"
:index="$index"
:total="stats.length">
</axis-label>
</g>
</script>
<!-- axis label组件的template,用于调整数值来改变图像 -->
<script type="text/x-template" id="axis-label-template">
<text :x="point.x" :y="point.y">{{stat.label}}</text>
</script>
<!-- 根实例 -->
<div id="demo">
<!-- 在这使用polygraph组件 -->
<svg width="200" height="200">
<polygraph :stats="stats"></polygraph>
</svg>
<!-- 可控制数值大小,并添加删除元素 -->
<div v-for="stat in stats">
<label>{{stat.label}}</label>
<input type="range" v-model="stat.value" min="0" max="100">
<span>{{stat.value}}</span>
<button @click="remove(stat)">X</button>
</div>
<form id="add">
<input name="newlabel" v-model="newLabel">
<button @click="add">Add a Stat</button>
</form>
<pre id="raw">{{stats | json}}</pre>
</div>
<p style="font-size:12px">* input[type="range"] requires IE10 or above.</p>
最后是css代码:
body {
font-family: Helvetica Neue, Arial, sans-serif;
}
polygon {
fill: #42b983;
opacity: .75;
}
circle {
fill: transparent;
stroke: #999;
}
text {
font-family: Helvetica Neue, Arial, sans-serif;
font-size: 10px;
fill: #666;
}
label {
display: inline-block;
margin-left: 10px;
width: 20px;
}
#raw {
position: absolute;
top: 0;
left: 300px;
}
写到最后你会感受到编程的神奇,vue的便捷。