本文基於“體育即時比分系統”的實際開發經驗總結,僅供技術交流。該系統在實現過程中,主要解決了實時比分更新、賠率數據同步、賽事分析展示等關鍵問題,並採用了以下技術棧:
後端:PHP(ThinkPHP 框架)
安卓端:Java
iOS端:Objective-C
PC/H5 前端:Vue.js
其中,比分分析頁面聚焦於展示比賽雙方的近期戰績、比賽賠率、關鍵數據分析等信息,結合 WebSocket 實現實時數據推送,提高用户體驗。
前端實現(Vue.js)
前端主要通過 Vue.js 進行開發,並調用後端 API 獲取比賽數據。以下是 Vue 組件代碼示例:
1. 比賽分析頁面組件
<template>
<div class="match-analysis">
<div class="team-header">
<div class="team" v-for="team in teams" :key="team.id">
<img :src="team.logo" class="team-logo" />
<span class="team-name">{{ team.name }}</span>
</div>
</div>
<div class="odds">
<span v-for="odd in odds" :key="odd.id">{{ odd.value }}</span>
</div>
<div class="history">
<div v-for="(match, index) in matchHistory" :key="index" class="match-item">
<span>{{ match.date }}</span>
<span>{{ match.opponent }}</span>
<span :class="{'win': match.result === 'W', 'lose': match.result === 'L'}">{{ match.result }}</span>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
teams: [],
odds: [],
matchHistory: []
};
},
methods: {
async fetchMatchData() {
try {
const response = await axios.get('/api/match/details');
this.teams = response.data.teams;
this.odds = response.data.odds;
this.matchHistory = response.data.history;
} catch (error) {
console.error('獲取數據失敗', error);
}
}
},
mounted() {
this.fetchMatchData();
}
};
</script>
<style scoped>
.match-analysis {
padding: 20px;
background-color: #fff;
}
.team-header {
display: flex;
justify-content: space-between;
}
.team-logo {
width: 40px;
height: 40px;
}
.history .match-item {
display: flex;
justify-content: space-between;
padding: 10px;
}
.win {
color: green;
}
.lose {
color: red;
}
</style>
後端實現(ThinkPHP)
ThinkPHP 負責提供 API,前端通過 axios 調用後端接口獲取比賽信息。
2. ThinkPHP 控制器示例
<?php
namespace app\api\controller;
use think\Controller;
use think\Db;
class Match extends Controller {
public function details() {
// 獲取比賽基本信息
$match_id = input('get.match_id');
$match = Db::name('matches')->where('id', $match_id)->find();
// 獲取雙方球隊信息
$teams = Db::name('teams')->where('id', 'in', [$match['team1_id'], $match['team2_id']])->select();
// 獲取賠率信息
$odds = Db::name('odds')->where('match_id', $match_id)->select();
// 獲取比賽歷史記錄
$history = Db::name('match_history')->where('match_id', $match_id)->order('date', 'desc')->limit(5)->select();
return json([
'teams' => $teams,
'odds' => $odds,
'history' => $history
]);
}
}
移動端實現
3. Android 端(Java 示例代碼)
public class MatchDetailActivity extends AppCompatActivity {
private TextView team1Name, team2Name, oddsView;
private RecyclerView historyRecycler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_match_detail);
team1Name = findViewById(R.id.team1_name);
team2Name = findViewById(R.id.team2_name);
oddsView = findViewById(R.id.odds);
historyRecycler = findViewById(R.id.history_recycler);
loadMatchData();
}
private void loadMatchData() {
String url = "https://api.example.com/match/details?match_id=123";
RequestQueue queue = Volley.newRequestQueue(this);
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null,
response -> {
try {
team1Name.setText(response.getJSONObject("teams").getString("team1_name"));
team2Name.setText(response.getJSONObject("teams").getString("team2_name"));
oddsView.setText(response.getJSONArray("odds").toString());
} catch (JSONException e) {
e.printStackTrace();
}
}, error -> {
Log.e("API_ERROR", error.toString());
}
);
queue.add(request);
}
}
iOS 端實現(Objective-C 示例)
#import "MatchDetailViewController.h"
@interface MatchDetailViewController ()
@property (nonatomic, strong) UILabel *team1Label;
@property (nonatomic, strong) UILabel *team2Label;
@property (nonatomic, strong) UILabel *oddsLabel;
@end
@implementation MatchDetailViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.team1Label = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 200, 30)];
self.team2Label = [[UILabel alloc] initWithFrame:CGRectMake(20, 150, 200, 30)];
self.oddsLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 200, 300, 30)];
[self.view addSubview:self.team1Label];
[self.view addSubview:self.team2Label];
[self.view addSubview:self.oddsLabel];
[self loadMatchData];
}
- (void)loadMatchData {
NSURL *url = [NSURL URLWithString:@"https://api.example.com/match/details?match_id=123"];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error == nil) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
self.team1Label.text = json[@"teams"][0][@"name"];
self.team2Label.text = json[@"teams"][1][@"name"];
self.oddsLabel.text = [NSString stringWithFormat:@"賠率: %@", json[@"odds"]];
});
}
}];
[task resume];
}
@end