
HBuilderX连接MuMu模拟器教程
第一步 下载MuMu模拟器
下载MuMu模拟器就不介绍了,自行去百度下载,我下载的是安卓6的版本,下载完成后直接安装。
第二步 开始进行adb连接 (连接时请不要关闭MuMu模拟器)
1、打开MuMu模拟器安装路径下的bin文件夹(具体路径为"安装路径的文件夹\emulator\nemu\vmonitor\bin"),然后点击文件夹路径,输入CMD,再点击回车按键呼出CMD运行窗口(如下图);

2、选中路径
3、输入cmd,然后点击回车按键
4、输入以下代码(具体可参考下图):
adb_server.exe connect 127.0.0.1:7555
adb_server shell
若使用模拟器版本≥2.7.9.0,获取Root权限需要操作:
方法1:设置中心-基本设置-root权限开启,权限同意后,重新进行adb连接(不用重启模拟器)
方法2:执行adb_server.exe connect 127.0.0.1:7555 && adb root,权限同意后,重新进行adb连接(不用重启模拟器)
第三步 配置HBuilderX
1、点开HBuilderX的“设置”
2、点击“运行配置”,把“1”中的adb路径复制在图中的位置,端口号设置为7555,和“4”中的端口号一致
3、开始真机运行
此时可以成功把项目运行到模拟器。
如果文章对您有帮助的话,留个赞在走吧~~~
第一步 下载MuMu模拟器
下载MuMu模拟器就不介绍了,自行去百度下载,我下载的是安卓6的版本,下载完成后直接安装。
第二步 开始进行adb连接 (连接时请不要关闭MuMu模拟器)
1、打开MuMu模拟器安装路径下的bin文件夹(具体路径为"安装路径的文件夹\emulator\nemu\vmonitor\bin"),然后点击文件夹路径,输入CMD,再点击回车按键呼出CMD运行窗口(如下图);
2、选中路径
3、输入cmd,然后点击回车按键
4、输入以下代码(具体可参考下图):
adb_server.exe connect 127.0.0.1:7555
adb_server shell
若使用模拟器版本≥2.7.9.0,获取Root权限需要操作:
方法1:设置中心-基本设置-root权限开启,权限同意后,重新进行adb连接(不用重启模拟器)
方法2:执行adb_server.exe connect 127.0.0.1:7555 && adb root,权限同意后,重新进行adb连接(不用重启模拟器)
第三步 配置HBuilderX
1、点开HBuilderX的“设置”
2、点击“运行配置”,把“1”中的adb路径复制在图中的位置,端口号设置为7555,和“4”中的端口号一致
3、开始真机运行
此时可以成功把项目运行到模拟器。
如果文章对您有帮助的话,留个赞在走吧~~~
收起阅读 »
基于vue3的uni-app路由库uni-mini-router助你实现跳转、传参、拦截等路由功能
介绍
uni-mini-router
是一个基于vue3
和uni-app
框架的轻量级路由库,它提供了类似Vue Router
的API和功能,可以帮助开发者实现在uni-app中进行路由跳转、传参、拦截等常用操作。
uni-mini-router
支持多种跳转方式,包括普通跳转、重定向、切换TabBar页面等。它也提供了一些高级特性,如路由拦截、编程式导航等。
总之,如果你在uni-app
开发过程中需要使用到路由功能,可以考虑使用uni-mini-router
来简化你的开发工作。
安装uni-mini-router
Yarn
yarn add uni-mini-router -D
npm
npm install uni-mini-router --save
生成路由表
我们提供了两种方式来生成路由表:uni-parse-pages和uni-read-pages-vite,这两种方式都可以实现将pages.json
中的路由信息转化为uni-mini-router
需要的路由表信息,其中uni-read-pages-vite
依赖vite
,在编译时将读取pages.json
生成的路由表注入全局变量,而uni-parse-pages
不依赖vite
,在应用每次热重载时都会从pages.json
中读取信息生成路由表。
由于uni-app
在编译到小程序端时无法触发vite
的热更新,所以目前只有使用uni-parse-pages
生成路由表才可以实现路由信息热更新的功能。
注意!!!
uni-parse-pages
在uni-mini-router@0.1.0
版本起获得支持,在之前的版本使用会有问题。
以下两种方式二选一:
使用uni-parse-pages生成路由表(0.1.0起支持)
安装
Yarn
yarn add uni-parse-pages -D
npm
npm install uni-parse-pages --save
使用uni-read-pages-vite生成路由表
安装
Yarn
yarn add uni-read-pages-vite
npm
npm install uni-read-pages-vite
配置
配置uni-read-pages-vite
配置 vite.config.ts
通过 define
注入全局变量 查看文档
注意:在 Vite 中使用
define
注入的全局变量并不是热更新的,因为这些变量是在构建时被注入到代码中的,而不是在运行时动态生成的。这意味着如果您更新了page.json
,则需要重新构建应用程序才能使更改生效。
配置vite.config.ts
CLI创建的项目配置
//vite.config.ts
import { defineConfig } from "vite";
import uni from "@dcloudio/vite-plugin-uni";
import TransformPages from 'uni-read-pages-vite'
export default defineConfig({
plugins: [uni()],
define: {
ROUTES: new TransformPages().routes, // 注入路由表
}
});
HbuilderX创建的项目配置
//vite.config.ts
import { defineConfig } from "vite";
import uni from "@dcloudio/vite-plugin-uni";
import TransformPages from 'uni-read-pages-vite'
export default defineConfig({
plugins: [uni()],
define: {
ROUTES: new TransformPages(__dirname).routes, // 注入路由表
}
});
声明文件type.d.ts
.d.ts
文件的作用是描述JavaScript
库、模块或其他代码的类型声明和元数据,以便编辑器和开发者能够更好地理解和使用该代码。在编译时,TypeScript
编译器会使用.d.ts
文件来验证代码正确性,并帮助开发者在开发过程中提供更好的代码提示和自动补全功能。
在项目src目录下(HbuilderX创建的项目可以在根目录下)创建type.d.ts
文件。
//type.d.ts
declare const ROUTES: []
配置uni-mini-router
项目src目录下(HbuilderX创建的项目可以在根目录下)创建router文件夹,并在该文件夹创建index.ts
配置router/index.ts
根据生成路由表方式的不同,我们这里也提供了两种配置router的方式,也是二选一
uni-parse-pages
import { createRouter } from 'uni-mini-router'
// 导入pages.json
import pagesJson from '../pages.json'
// 引入uni-parse-pages
import pagesJsonToRoutes from 'uni-parse-pages'
// 生成路由表
const routes = pagesJsonToRoutes(pagesJson)
const router = createRouter({
routes: [...routes] // 路由表信息
})
export default router
uni-read-pages-vite
此处的ROUTES就是配置vite.config.ts步骤中注入的
import { createRouter } from 'uni-mini-router'
const router = createRouter({
routes: [...ROUTES] // 路由表信息
})
export default router
配置main.ts
import { createSSRApp } from 'vue'
import App from './App.vue'
import router from './router'
export function createApp() {
const app = createSSRApp(App)
app.use(router)
return {
app
}
}
配置pages.json
在pages.json中为页面路由指定name
字段后,即可以使用name
跳转
注意:此处定义的
name
字段必须全局唯一。
// pages.json
{
"pages": [{
"path": "pages/home/Home",
"name": "home", // 路由 name 用于命名路由的跳转
"style": {
"mp-alipay": {
"allowsBounceVertical": "NO"
},
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/login/Login",
"name": "login",
"style": {
"mp-alipay": {
"allowsBounceVertical": "NO"
},
"navigationBarTitleText": ""
}
},
{
"path": "pages/mine/Mine",
"name": "mine",
"style": {
"navigationBarTitleText": "",
"navigationBarBackgroundColor": "#E7F0FF"
}
}
],
"tabBar": {
"color": "#bfbfbf",
"selectedColor": "#0165FF",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/home/Home",
"iconPath": "static/icon_home.png",
"selectedIconPath": "static/icon_home_selected.png",
"text": "首页"
},
{
"pagePath": "pages/mine/Mine",
"iconPath": "static/icon_mine.png",
"selectedIconPath": "static/icon_mine_selected.png",
"text": "我的"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFF",
"backgroundColor": "#F8F8F8"
}
}
配置自动按需导入(可选)
unplugin-auto-import:是一个为 Vite
、Webpack
、Rollup
和 esbuild
按需自动导入 API,支持 TypeScript
的插件,我们基于此插件实现自动按需导入。
不使用按需导入,则需要手动import
import { useRouter } from 'uni-mini-router'
const router = useRouter()
router.push('/')
使用按需导入后
const router = useRouter()
router.push('/')
安装unplugin-auto-import
yarn add uni-mini-router -D
配置unplugin-auto-import
详细配置方案见unplugin-auto-import,这里给出支持uni-mini-router
的简易配置
//vite.config.ts
import { defineConfig } from 'vite'
import TransformPages from 'uni-read-pages-vite'
import uni from '@dcloudio/vite-plugin-uni'
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
base: './',
plugins: [
uni(),
AutoImport({
imports: [
'vue',
'uni-app',
'pinia',
{
from: 'uni-mini-router',
imports: ['createRouter', 'useRouter', 'useRoute']
}
],
dts: 'src/auto-imports.d.ts', // 这里src目录必须是已存在的,如果是HbuilderX创建的项目是没有src目录的,可以配置为 dts: 'auto-imports.d.ts'
eslintrc: {
enabled: true,
globalsPropValue: true
}
})
],
define: {
ROUTES: new TransformPages().routes
}
})
总结
unplugin-auto-import
可以帮助我们实现按需自动导入第三方库的API,提升开发效率,但是它也同样存在一些缺点,例如:
-
可能会影响代码可读性:自动导入模块可能会导致代码可读性降低,因为开发者可能不知道哪些模块被自动导入了。
-
可能会导致性能问题:自动导入模块可能会导致性能问题,因为它需要扫描整个代码库来查找缺失的模块。
所以在提升开发效率的同时也要兼顾可读性和性能问题,尽量将一些被广泛认知和使用、不用关注实现、不变的内容作为自动按需引入的对象,而项目内的代码如果自动按需引入是否会增加开发人员的心智负担,则需要我们做出相应的权衡。
使用
编程式导航
注意:这里
name
和params
搭配使用,而path
可以与query
一起使用。
基础用法
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'uni-mini-router'
import { getCurrentInstance } from 'vue'
// 使用hooks(推荐)
let router = useRouter()
// 或者 使用全局挂载的router
router = instence?.appContext.config.globalProperties.$Router
// 字符串路径
router.push('/user')
// 带有路径的对象
router.push({ path: '/user' })
// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })
// 带查询参数,结果是 /user?username=eduardo
router.push({ path: '/user', query: { username: 'eduardo' } })
</script>
在user.vue接收传入的对象参数
<script setup lang="ts">
onLoad((option) => {
if (option && option.username) {
const username = option.username
}
})
</script>
传递对象参数
url有长度限制,太长的字符串会传递失败,可改用窗体通信、全局变量,另外参数中出现空格等特殊字符时需要对参数进行编码,如下为使用encodeURIComponent对参数进行编码的示例。
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'uni-mini-router'
import { getCurrentInstance } from 'vue'
let router = useRouter()
const user = {
name:'小星星',
label:"小熊熊"
}
// 命名的路由,传递对象参数
router.push({ name: 'user', params: { user: encodeURIComponent(JSON.stringify(user)) } })
// path+query,传递对象参数
router.push({ path: '/user', query: { user: encodeURIComponent(JSON.stringify(user)) } })
</script>
在user.vue接收传入的对象参数
<script setup lang="ts">
onLoad((option) => {
if (option && option.user) {
const user = JSON.parse(decodeURIComponent(option.user))
}
})
// 返回
function back() {
router.back()
}
</script>
导航守卫
uni-mini-router
支持全局前置导航守卫 beforeEach
和全局后置导航守卫 afterEach
,主要用来通过跳转或取消的方式守卫导航。
全局前置守卫 beforeEach
你可以使用 router.beforeEach
注册一个全局前置守卫:
const router = createRouter({ ... })
router.beforeEach((to, from, next) => {
// next入参 false 以取消导航
next(false)
})
beforeEach
守卫方法接收三个参数:
to
: 即将要进入的目标from
: 当前导航正要离开的路由next
: 用于reslovebeforeEach
钩子,需要确保next
在导航守卫中都被严格调用一次-next()
: 执行默认路由跳转逻辑next(false)
: 终止跳转逻辑next({ path: '/' })
: 跳转到不同的页面next({ path: '/', navType: 'replaceAll' })
: 改变当前跳转类型并跳转到不同的页面,可以通过navType
指定新的跳转类型。(实例为中断当前导航,改用replaceAll
方法跳转到新的页面)
全局后置钩子 afterEach
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身
const router = createRouter({ ... })
router.afterEach((to, from) => {
console.log(to)
console.log(from)
})
它对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。
API 文档
createRouter
▸ createRouter(options): Router
创建一个可以被 Vue 应用使用的 Router 实例。
参数
名称 | 类型 | 描述 |
---|---|---|
options | RouterOptions |
RouterOptions |
返回值
Router
useRouter
▸ useRouter(): Router
返回路由器实例。相当于在模板中使用 \$Router。
不可以脱离 Vue 上下文使用
返回值
Router
useRoute
▸ useRoute(): Route
返回当前的路由地址信息。相当于在模板中使用 \$Route。
不可以脱离 Vue 上下文使用,且只能在页面
mount
之后才可与使用。当使用场景为外部链接跳转进入或H5页面刷新时,默认从当前链接中取得query参数并放在Route
的query
字段中,这种场景建议走onLoad
声明周期获取参数。
返回值
Route
Router实例方法
push方法
▸ router.push(target:RouteLocationRaw): void
保留当前页面,跳转到应用内的某个页面,相当于使用 uni.navigateTo(OBJECT)
。
pushTab方法
▸ router.pushTab(target:RouteLocationRaw): void
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面,相当于使用 uni.switchTab(OBJECT)
。
replace方法
▸ router.replace(target:RouteLocationRaw): void
关闭当前页面,跳转到应用内的某个页面,相当于使用 uni.redirectTo(OBJECT)
。
replaceAll方法
▸ router.replaceAll(target:RouteLocationRaw): void
关闭所有页面,打开到应用内的某个页面,相当于使用 uni.reLaunch(OBJECT)
。
back方法
▸ router.back(level?: number): void
关闭当前页面,返回上一页面或多级页面,相当于使用 uni.navigateBack(OBJECT)
。
演示项目:Vue3-Uni-TS-Template基础模板
使用文档:地址
插件市场地址:uni-mini-router
介绍
uni-mini-router
是一个基于vue3
和uni-app
框架的轻量级路由库,它提供了类似Vue Router
的API和功能,可以帮助开发者实现在uni-app中进行路由跳转、传参、拦截等常用操作。
uni-mini-router
支持多种跳转方式,包括普通跳转、重定向、切换TabBar页面等。它也提供了一些高级特性,如路由拦截、编程式导航等。
总之,如果你在uni-app
开发过程中需要使用到路由功能,可以考虑使用uni-mini-router
来简化你的开发工作。
安装uni-mini-router
Yarn
yarn add uni-mini-router -D
npm
npm install uni-mini-router --save
生成路由表
我们提供了两种方式来生成路由表:uni-parse-pages和uni-read-pages-vite,这两种方式都可以实现将pages.json
中的路由信息转化为uni-mini-router
需要的路由表信息,其中uni-read-pages-vite
依赖vite
,在编译时将读取pages.json
生成的路由表注入全局变量,而uni-parse-pages
不依赖vite
,在应用每次热重载时都会从pages.json
中读取信息生成路由表。
由于uni-app
在编译到小程序端时无法触发vite
的热更新,所以目前只有使用uni-parse-pages
生成路由表才可以实现路由信息热更新的功能。
注意!!!
uni-parse-pages
在uni-mini-router@0.1.0
版本起获得支持,在之前的版本使用会有问题。
以下两种方式二选一:
使用uni-parse-pages生成路由表(0.1.0起支持)
安装
Yarn
yarn add uni-parse-pages -D
npm
npm install uni-parse-pages --save
使用uni-read-pages-vite生成路由表
安装
Yarn
yarn add uni-read-pages-vite
npm
npm install uni-read-pages-vite
配置
配置uni-read-pages-vite
配置 vite.config.ts
通过 define
注入全局变量 查看文档
注意:在 Vite 中使用
define
注入的全局变量并不是热更新的,因为这些变量是在构建时被注入到代码中的,而不是在运行时动态生成的。这意味着如果您更新了page.json
,则需要重新构建应用程序才能使更改生效。
配置vite.config.ts
CLI创建的项目配置
//vite.config.ts
import { defineConfig } from "vite";
import uni from "@dcloudio/vite-plugin-uni";
import TransformPages from 'uni-read-pages-vite'
export default defineConfig({
plugins: [uni()],
define: {
ROUTES: new TransformPages().routes, // 注入路由表
}
});
HbuilderX创建的项目配置
//vite.config.ts
import { defineConfig } from "vite";
import uni from "@dcloudio/vite-plugin-uni";
import TransformPages from 'uni-read-pages-vite'
export default defineConfig({
plugins: [uni()],
define: {
ROUTES: new TransformPages(__dirname).routes, // 注入路由表
}
});
声明文件type.d.ts
.d.ts
文件的作用是描述JavaScript
库、模块或其他代码的类型声明和元数据,以便编辑器和开发者能够更好地理解和使用该代码。在编译时,TypeScript
编译器会使用.d.ts
文件来验证代码正确性,并帮助开发者在开发过程中提供更好的代码提示和自动补全功能。
在项目src目录下(HbuilderX创建的项目可以在根目录下)创建type.d.ts
文件。
//type.d.ts
declare const ROUTES: []
配置uni-mini-router
项目src目录下(HbuilderX创建的项目可以在根目录下)创建router文件夹,并在该文件夹创建index.ts
配置router/index.ts
根据生成路由表方式的不同,我们这里也提供了两种配置router的方式,也是二选一
uni-parse-pages
import { createRouter } from 'uni-mini-router'
// 导入pages.json
import pagesJson from '../pages.json'
// 引入uni-parse-pages
import pagesJsonToRoutes from 'uni-parse-pages'
// 生成路由表
const routes = pagesJsonToRoutes(pagesJson)
const router = createRouter({
routes: [...routes] // 路由表信息
})
export default router
uni-read-pages-vite
此处的ROUTES就是配置vite.config.ts步骤中注入的
import { createRouter } from 'uni-mini-router'
const router = createRouter({
routes: [...ROUTES] // 路由表信息
})
export default router
配置main.ts
import { createSSRApp } from 'vue'
import App from './App.vue'
import router from './router'
export function createApp() {
const app = createSSRApp(App)
app.use(router)
return {
app
}
}
配置pages.json
在pages.json中为页面路由指定name
字段后,即可以使用name
跳转
注意:此处定义的
name
字段必须全局唯一。
// pages.json
{
"pages": [{
"path": "pages/home/Home",
"name": "home", // 路由 name 用于命名路由的跳转
"style": {
"mp-alipay": {
"allowsBounceVertical": "NO"
},
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/login/Login",
"name": "login",
"style": {
"mp-alipay": {
"allowsBounceVertical": "NO"
},
"navigationBarTitleText": ""
}
},
{
"path": "pages/mine/Mine",
"name": "mine",
"style": {
"navigationBarTitleText": "",
"navigationBarBackgroundColor": "#E7F0FF"
}
}
],
"tabBar": {
"color": "#bfbfbf",
"selectedColor": "#0165FF",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/home/Home",
"iconPath": "static/icon_home.png",
"selectedIconPath": "static/icon_home_selected.png",
"text": "首页"
},
{
"pagePath": "pages/mine/Mine",
"iconPath": "static/icon_mine.png",
"selectedIconPath": "static/icon_mine_selected.png",
"text": "我的"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFF",
"backgroundColor": "#F8F8F8"
}
}
配置自动按需导入(可选)
unplugin-auto-import:是一个为 Vite
、Webpack
、Rollup
和 esbuild
按需自动导入 API,支持 TypeScript
的插件,我们基于此插件实现自动按需导入。
不使用按需导入,则需要手动import
import { useRouter } from 'uni-mini-router'
const router = useRouter()
router.push('/')
使用按需导入后
const router = useRouter()
router.push('/')
安装unplugin-auto-import
yarn add uni-mini-router -D
配置unplugin-auto-import
详细配置方案见unplugin-auto-import,这里给出支持uni-mini-router
的简易配置
//vite.config.ts
import { defineConfig } from 'vite'
import TransformPages from 'uni-read-pages-vite'
import uni from '@dcloudio/vite-plugin-uni'
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
base: './',
plugins: [
uni(),
AutoImport({
imports: [
'vue',
'uni-app',
'pinia',
{
from: 'uni-mini-router',
imports: ['createRouter', 'useRouter', 'useRoute']
}
],
dts: 'src/auto-imports.d.ts', // 这里src目录必须是已存在的,如果是HbuilderX创建的项目是没有src目录的,可以配置为 dts: 'auto-imports.d.ts'
eslintrc: {
enabled: true,
globalsPropValue: true
}
})
],
define: {
ROUTES: new TransformPages().routes
}
})
总结
unplugin-auto-import
可以帮助我们实现按需自动导入第三方库的API,提升开发效率,但是它也同样存在一些缺点,例如:
-
可能会影响代码可读性:自动导入模块可能会导致代码可读性降低,因为开发者可能不知道哪些模块被自动导入了。
-
可能会导致性能问题:自动导入模块可能会导致性能问题,因为它需要扫描整个代码库来查找缺失的模块。
所以在提升开发效率的同时也要兼顾可读性和性能问题,尽量将一些被广泛认知和使用、不用关注实现、不变的内容作为自动按需引入的对象,而项目内的代码如果自动按需引入是否会增加开发人员的心智负担,则需要我们做出相应的权衡。
使用
编程式导航
注意:这里
name
和params
搭配使用,而path
可以与query
一起使用。
基础用法
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'uni-mini-router'
import { getCurrentInstance } from 'vue'
// 使用hooks(推荐)
let router = useRouter()
// 或者 使用全局挂载的router
router = instence?.appContext.config.globalProperties.$Router
// 字符串路径
router.push('/user')
// 带有路径的对象
router.push({ path: '/user' })
// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })
// 带查询参数,结果是 /user?username=eduardo
router.push({ path: '/user', query: { username: 'eduardo' } })
</script>
在user.vue接收传入的对象参数
<script setup lang="ts">
onLoad((option) => {
if (option && option.username) {
const username = option.username
}
})
</script>
传递对象参数
url有长度限制,太长的字符串会传递失败,可改用窗体通信、全局变量,另外参数中出现空格等特殊字符时需要对参数进行编码,如下为使用encodeURIComponent对参数进行编码的示例。
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'uni-mini-router'
import { getCurrentInstance } from 'vue'
let router = useRouter()
const user = {
name:'小星星',
label:"小熊熊"
}
// 命名的路由,传递对象参数
router.push({ name: 'user', params: { user: encodeURIComponent(JSON.stringify(user)) } })
// path+query,传递对象参数
router.push({ path: '/user', query: { user: encodeURIComponent(JSON.stringify(user)) } })
</script>
在user.vue接收传入的对象参数
<script setup lang="ts">
onLoad((option) => {
if (option && option.user) {
const user = JSON.parse(decodeURIComponent(option.user))
}
})
// 返回
function back() {
router.back()
}
</script>
导航守卫
uni-mini-router
支持全局前置导航守卫 beforeEach
和全局后置导航守卫 afterEach
,主要用来通过跳转或取消的方式守卫导航。
全局前置守卫 beforeEach
你可以使用 router.beforeEach
注册一个全局前置守卫:
const router = createRouter({ ... })
router.beforeEach((to, from, next) => {
// next入参 false 以取消导航
next(false)
})
beforeEach
守卫方法接收三个参数:
to
: 即将要进入的目标from
: 当前导航正要离开的路由next
: 用于reslovebeforeEach
钩子,需要确保next
在导航守卫中都被严格调用一次-next()
: 执行默认路由跳转逻辑next(false)
: 终止跳转逻辑next({ path: '/' })
: 跳转到不同的页面next({ path: '/', navType: 'replaceAll' })
: 改变当前跳转类型并跳转到不同的页面,可以通过navType
指定新的跳转类型。(实例为中断当前导航,改用replaceAll
方法跳转到新的页面)
全局后置钩子 afterEach
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身
const router = createRouter({ ... })
router.afterEach((to, from) => {
console.log(to)
console.log(from)
})
它对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。
API 文档
createRouter
▸ createRouter(options): Router
创建一个可以被 Vue 应用使用的 Router 实例。
参数
名称 | 类型 | 描述 |
---|---|---|
options | RouterOptions |
RouterOptions |
返回值
Router
useRouter
▸ useRouter(): Router
返回路由器实例。相当于在模板中使用 \$Router。
不可以脱离 Vue 上下文使用
返回值
Router
useRoute
▸ useRoute(): Route
返回当前的路由地址信息。相当于在模板中使用 \$Route。
不可以脱离 Vue 上下文使用,且只能在页面
mount
之后才可与使用。当使用场景为外部链接跳转进入或H5页面刷新时,默认从当前链接中取得query参数并放在Route
的query
字段中,这种场景建议走onLoad
声明周期获取参数。
返回值
Route
Router实例方法
push方法
▸ router.push(target:RouteLocationRaw): void
保留当前页面,跳转到应用内的某个页面,相当于使用 uni.navigateTo(OBJECT)
。
pushTab方法
▸ router.pushTab(target:RouteLocationRaw): void
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面,相当于使用 uni.switchTab(OBJECT)
。
replace方法
▸ router.replace(target:RouteLocationRaw): void
关闭当前页面,跳转到应用内的某个页面,相当于使用 uni.redirectTo(OBJECT)
。
replaceAll方法
▸ router.replaceAll(target:RouteLocationRaw): void
关闭所有页面,打开到应用内的某个页面,相当于使用 uni.reLaunch(OBJECT)
。
back方法
▸ router.back(level?: number): void
关闭当前页面,返回上一页面或多级页面,相当于使用 uni.navigateBack(OBJECT)
。
演示项目:Vue3-Uni-TS-Template基础模板
使用文档:地址
插件市场地址:uni-mini-router
收起阅读 »
ios系统数字键盘问题
可在input时间判断最后一位是 小数点 或 零时 直接return
> <input v-model="quantity" placeholder="请输入" @input="handleNum" inputmode="decimal" type="digit" step="0.0000001" @blur="numBlur1()" style="border:0px;outline:none;"/>
> handleNum(){
const str = this.netQuantity + ''
const flag = str.indexOf('.')
const flag1 = str.lastIndexOf('.')
const flag2 = str.lastIndexOf('0')
if(flag > 0 && flag1 === str.length-1){
if(flag === flag1) {
return
} else {
const toast = this.$createToast({
txt: '请输入正确的数字格式',
type: 'info'
})
toast.show()
this.netQuantity = 0
return
}
}
if(flag2 === str.length-1){
return
}
}
可在input时间判断最后一位是 小数点 或 零时 直接return
> <input v-model="quantity" placeholder="请输入" @input="handleNum" inputmode="decimal" type="digit" step="0.0000001" @blur="numBlur1()" style="border:0px;outline:none;"/>
> handleNum(){
const str = this.netQuantity + ''
const flag = str.indexOf('.')
const flag1 = str.lastIndexOf('.')
const flag2 = str.lastIndexOf('0')
if(flag > 0 && flag1 === str.length-1){
if(flag === flag1) {
return
} else {
const toast = this.$createToast({
txt: '请输入正确的数字格式',
type: 'info'
})
toast.show()
this.netQuantity = 0
return
}
}
if(flag2 === str.length-1){
return
}
}

3.8.3版本 打包白屏修复
3.8.3 版本打包白屏的,请重新打包自定义基座。线上打包机已更新。
客服中午通知我线上打包机更新了,我重新打包基座,白屏问题已解决。
3.8.3 版本打包白屏的,请重新打包自定义基座。线上打包机已更新。
客服中午通知我线上打包机更新了,我重新打包基座,白屏问题已解决。

更新HBuilder X后,找不到app基座问题
每次更新HBuilder X后,都会出现找不到app基座问题
原因:Hbuilder X更新后都会把adb版本覆盖为1.0.32
路径:D:\Program Files\HBuilderX\update\backup\plugins\launcher\tools\adbs
找到我的AndriodStudio 自带的adb位置
查看这个adb版本
复制这个版本到HBuilder X中,然后重新启动HBuilderX
问题解决
每次更新HBuilder X后,都会出现找不到app基座问题
原因:Hbuilder X更新后都会把adb版本覆盖为1.0.32
路径:D:\Program Files\HBuilderX\update\backup\plugins\launcher\tools\adbs
找到我的AndriodStudio 自带的adb位置
查看这个adb版本
复制这个版本到HBuilder X中,然后重新启动HBuilderX
问题解决
收起阅读 »
关于uniapp的HBX 3.8.3版本的出现的一系列问题解决方案
关于uniapp的HBX 3.8.3版本的出现的一系列问题解决方案
1.导致打包后出现空白页或者只有底部按钮。
- 导致某些功能不能正常使用
3。升级后导致的
这些问题都来源于官方更新的问题。
解决方法:
把Cli降低版本,一切问题正常
关于uniapp的HBX 3.8.3版本的出现的一系列问题解决方案
1.导致打包后出现空白页或者只有底部按钮。
- 导致某些功能不能正常使用
3。升级后导致的
这些问题都来源于官方更新的问题。
解决方法:
把Cli降低版本,一切问题正常

【已解决】修改config.json后,仍出现“未找到scene=bind-mobile-by-sms,的短信模版templateId”的错误
今天成功实现手机短信验证码找回密码功能!分享点经验教训:
1)我是个人用户,今天下午5点提交了身份证和我的网址备案证明,不到两个小时就开通了。
2)调试代码遇到即使修改了uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json当一直出现“未找到scene=bind-mobile-by-sms,的短信模版templateId”的错误提示,后续仔细查找文档和代码才发现,要在sms增加:
"scene": {
"bind-mobile-by-sms": {
"templateId": "18088",
"codeExpiresIn": 600
},
"login-by-sms": {
"templateId": "18088",
"codeExpiresIn": 600
},
"reset-pwd-by-sms": {
"templateId": "18088",
"codeExpiresIn": 600
}
}。而且修改后最好上传公共配置后连接云函数,最终成功。我是移动手机号,体验还是挺快的。
教训:
再次吐槽Dcloud的文档写作太不从用户思维出发,我先后调入了如下几个坑:
1)被文档中说一键登录比短信好就顺着那个思路走,但后来才意识到你得首先是app,我自己就是做个小网站用户登录觉得app太费事,到最后就折腾放弃了。
2)接着又被微信登录所吸引,谁知道又是一堆坑,得服务号才行,对个人开发者又多了门槛
3)不知怎么就被文档有一种感觉,个人很难申请短信认证,所以前面就只好凑合用用户名密码,但找回密码是问题。
4)于是还曾看着文档说email,就差点冲动去增加一个email服务器。
5)今天也是实在受够了密码找回的麻烦事了,就硬着头皮再次鼓捣短信,居然很大个人就申请手机验证码就通过了。7点多遇到修改config.json的难题后,不甘心半途而废,就看源代码,发现sms.scene这个地方,再联想到文档中https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html中有个地方比源代码config.json多了scene那部分,就尝试了几次,成功了。
再次建议Dcloud能把文档按用户使用过程来描述,在吹牛每个功能很强大的同时,就第一时间写清楚它的使用范围和前提条件。Dcloud对我们这些从头开始学习的人来说的确优点非常多,大量开源代码和免费低价功能很好,但文档的坑也浪费了太多时间。社区的问题检索功能也太差,要是能用chatgpt给优化一下信息查询,相信dcloud会得到更多人的认可。
今天成功实现手机短信验证码找回密码功能!分享点经验教训:
1)我是个人用户,今天下午5点提交了身份证和我的网址备案证明,不到两个小时就开通了。
2)调试代码遇到即使修改了uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json当一直出现“未找到scene=bind-mobile-by-sms,的短信模版templateId”的错误提示,后续仔细查找文档和代码才发现,要在sms增加:
"scene": {
"bind-mobile-by-sms": {
"templateId": "18088",
"codeExpiresIn": 600
},
"login-by-sms": {
"templateId": "18088",
"codeExpiresIn": 600
},
"reset-pwd-by-sms": {
"templateId": "18088",
"codeExpiresIn": 600
}
}。而且修改后最好上传公共配置后连接云函数,最终成功。我是移动手机号,体验还是挺快的。
教训:
再次吐槽Dcloud的文档写作太不从用户思维出发,我先后调入了如下几个坑:
1)被文档中说一键登录比短信好就顺着那个思路走,但后来才意识到你得首先是app,我自己就是做个小网站用户登录觉得app太费事,到最后就折腾放弃了。
2)接着又被微信登录所吸引,谁知道又是一堆坑,得服务号才行,对个人开发者又多了门槛
3)不知怎么就被文档有一种感觉,个人很难申请短信认证,所以前面就只好凑合用用户名密码,但找回密码是问题。
4)于是还曾看着文档说email,就差点冲动去增加一个email服务器。
5)今天也是实在受够了密码找回的麻烦事了,就硬着头皮再次鼓捣短信,居然很大个人就申请手机验证码就通过了。7点多遇到修改config.json的难题后,不甘心半途而废,就看源代码,发现sms.scene这个地方,再联想到文档中https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html中有个地方比源代码config.json多了scene那部分,就尝试了几次,成功了。
再次建议Dcloud能把文档按用户使用过程来描述,在吹牛每个功能很强大的同时,就第一时间写清楚它的使用范围和前提条件。Dcloud对我们这些从头开始学习的人来说的确优点非常多,大量开源代码和免费低价功能很好,但文档的坑也浪费了太多时间。社区的问题检索功能也太差,要是能用chatgpt给优化一下信息查询,相信dcloud会得到更多人的认可。
收起阅读 »
HBuilder X 升级到最新版后length报错
vendor.js? [sm]:7 [Vue warn]: Error in render: "TypeError: Cannot read property 'length' of undefined"
vendor.js? [sm]:7 [Vue warn]: Error in render: "TypeError: Cannot read property 'length' of undefined"

VUE实现竞彩足球APP页面赛事比赛场次的选择算法
最近给朋友做了一个竞彩实体店的APP助手项目,项目已经写完,现在给大家分享给大家一些心得。
竞彩实体店的APP助手算法一般包括以下几个方面:
赔率分析算法:通过对历史比赛数据和球队情况进行分析,预测比赛结果并计算出相应的赔率。
赛事推荐算法:根据用户的历史投注记录和偏好,推荐适合用户的比赛和投注方式。
赛果分析算法:对比赛结果进行分析,包括比分、进球数、角球数等,为用户提供更准确的比赛结果预测。
投注模拟算法:通过模拟用户的投注行为,预测用户可能的投注方式和投注金额,并为用户提供相应的建议。
实时数据更新算法:及时更新比赛数据和赔率变化情况,为用户提供最新的比赛信息和投注建议。
这些算法可以结合起来,为用户提供更准确的赛事分析和投注建议,提高用户的投注成功率和体验。
<template>
<view class="box">
<cmd-nav-bar title="竞彩足球" :back="true" font-color="#fff" background-color="#FF3F43" @rightText="rightText"
right-text="足球开奖">
</cmd-nav-bar>
<div class="soccer_wrap">
<!--main-->
<div class="soccer_main" v-show="isMainShow">
<u-sticky bgColor="#fff"
style="margin-bottom: 30px;display: flex;justify-content: center;align-items: center;">
<u-tabs :list="lassificationcList" lineColor="#FF3F43"
:activeStyle="{color: '#FF3F43',fontWeight: 'bold',transform: 'scale(1.05)'}"
@click="changeSelectBall"></u-tabs>
</u-sticky>
<!--混合过关-->
<u-empty icon="http://cdn.uviewui.com/uview/empty/data.png" :show="beidanList.length<=0" mode="data"
text="暂无比赛"></u-empty>
<div class="soccer_hunheguoguan" v-if="changeBall == 0">
<!--每周比赛-->
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,index) in wk.footballMatchList" :key="index">
<div class="games_left">
<span><b>{{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span
class="title_team">{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</span>
</span>
<!--表格-->
<table>
<tr>
<td class="burangqiu">0</td>
<td class="sheng_top">
<p>
<span style="position: relative;"
v-for="(notLet,notLetIndex) in game.notLetOddsList"
:class="{active:notLet.active}"
@tap="selectBtn(game,notLet,weekIdx,index,1)">{{notLet.describe}}
{{notLet.odds}}
<view
v-if="game.notLetOddsList.length>0&¬LetIndex==0&&game.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</span>
<span v-if="game.notLetOddsList.length<=0">未开售</span>
</p>
</td>
<!--点击更多玩法时 传递:接口相关编号、队伍名-->
<td class="morePlay" rowspan="2" @tap="morePlay(game,weekIdx,index)">
<span v-if="game.choiceCount==0">更多<br>玩法</span>
<span v-else>已选<span
style="color: #FF3F43;display: block">{{game.choiceCount}}</span>项</span>
</td>
</tr>
<tr>
<td class="rangqiu" :class="{rangqiuBlue:game.letBall < 0}">
{{game.letBall}}
</td>
<td class="sheng_top">
<p>
<span v-if="game.letOddsList.length<=0">未开售</span>
<span v-else v-for="(lets,letsIndex) in game.letOddsList"
style="position: relative;" :class="{active:lets.active}"
@tap="selectBtn(game,lets,weekIdx,index,2)">{{lets.describe}}
{{lets.odds}}
<view
v-if="game.notLetOddsList.length<=0&&letsIndex==0&&game.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</span>
</p>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!--胜平负-->
<div class="soccer_shengpingfu" v-if="changeBall == 1">
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,index) in wk.footballMatchList">
<div class="games_left">
<span><b> {{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span>{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</em></span>
</span>
<!--表格-->
<table>
<tr v-if="game.notLetOddsList.length<=0">
<td class="sheng_top">
<span>未开售</span>
</td>
</tr>
<tr v-else>
<td class="sheng_top">
<p>
<span @tap="selectBtn(game,notLet,weekIdx,index,1)"
style="position: relative;" :class="{active:notLet.active}"
class="sheng_top_block"
v-for="(notLet,notLetIndex) in game.notLetOddsList">
<span>{{notLet.describe}}</span>
<span :class="{active:notLet.active}">{{notLet.odds}}
<view
v-if="game.notLetOddsList.length>0&¬LetIndex==0&&game.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</span>
</span>
</p>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!--让球平负-->
<div class="soccer_shengpingfu" v-if="changeBall == 2">
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,index) in wk.footballMatchList">
<div class="games_left">
<span><b> {{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span>{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</span>
</span>
<!--表格-->
<table>
<tr>
<td class="sheng_top">
<p>
<span v-if="game.letOddsList.length<=0">未开售</span>
<span v-else @tap="selectBtn(game,lets,weekIdx,index,2)"
style="position: relative;" :class="{active:lets.active}"
class="sheng_top_block"
v-for="(lets,letsIndex) in game.letOddsList">
<span>{{lets.describe}}</span>
<span :class="{active:lets.active}">{{lets.odds}}
<view
v-if="game.notLetOddsList.length<=0&&letsIndex==0&&game.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</span>
</span>
</p>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!--总进球-->
<div class="soccer_zongjinqiu" v-if="changeBall == 3">
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,index) in wk.footballMatchList">
<img src="@/static/images/football/dan.png" />
<div class="games_left">
<span><b> {{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span>{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</span>
</span>
<!--表格-->
<table>
<tr v-if="game.goalOddsList.length>0">
<td class="gameInfoSpan" :class="{active:goal.active}" v-if="idx < 4"
@tap="selectBtn(game,goal,weekIdx,index,3)"
v-for="(goal,idx) in game.goalOddsList" :key="idx">
<span><b>{{idx}}</b>{{goal.odds}}</span>
</td>
</tr>
<tr v-if="game.goalOddsList.length>0">
<td class="gameInfoSpan" v-if="idx >= 4" :class="{active:goal.active}"
@tap="selectBtn(game,goal,weekIdx,index,3)"
v-for="(goal,idx) in game.goalOddsList" :key="idx">
<span><b>{{idx}}<span v-if="idx === 7">+</span></b>{{goal.odds}}</span>
</td>
</tr>
<tr v-if="game.goalOddsList.length<=0">
未开售
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!--比分-->
<div class="soccer_bifen" v-if="changeBall == 4">
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,idx) in wk.footballMatchList">
<img src="@/static/images/football/dan.png" />
<div class="games_left">
<span><b>{{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span>{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</span>
</span>
<!--投注区-->
<div @click="morePlay(game,weekIdx,idx)">
<span v-for="s in game.scoreOddsList" v-if="s.active"
style="color: #FF3F43;font-weight: bold">
{{s.describe}} |
</span>
<span v-if="game.scoreFlag!='false'">
点击展开比分投注区
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!--半全场-->
<div class="soccer_bifen" v-if="changeBall == 5">
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,idx) in wk.footballMatchList">
<img src="@/static/images/football/dan.png" />
<div class="games_left">
<span><b> {{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span>{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</span>
</span>
<!--投注区-->
<div @click="morePlay(game,weekIdx,idx)">
<span v-for="s in game.halfWholeOddsList" v-if="s.active"
style="color: #FF3F43;font-weight: bold">
{{s.describe}} |
</span>
<span v-if="game.halfWholeFlag!='false'">
点击展开半全场
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<BuyFooterSport :count='count' :total='total' :isShowCount="isShowCount" @clean="clean"
@confirm="confirm"></BuyFooterSport>
</div>
<!--隐藏:更多玩法 根据index更改数据 根据isShowMorePlay控制显示-->
<u-popup class="morePlays" :show="isShowMorePlay" mode="bottom" @close="isShowMorePlay = false">
<div class="morePlay">
<!--队伍-->
<h5 class="morePlay_title">
{{football.homeTeam}}
<span>VS</span>
{{football.visitingTeam}}
</h5>
<!--玩法:根据头部index切换更多玩法显示内容-->
<div class="morePlay_select">
<!--1混合-->
<div v-show="changeBall === 0" class="morePlay_hunhe">
<!--左-->
<div class="hunhe_left">
<span class="hunhe_left_top">0</span>
<span class="hunhe_left_bottom">{{football.letBall}}</span>
</div>
<!--右-->
<div class="hunhe_right">
<span v-if="football.notLetOddsList!=undefined&&football.notLetOddsList.length<=0"
style="width: 100%;"><b>未开售</b></span>
<span style="position: relative;"
v-else-if="football.notLetOddsList!=undefined&&football.notLetOddsList.length>0"
v-for="(notLet,notLetIndex) in football.notLetOddsList"
:class="{active:notLet.active}"
@tap="selectBtn(football,notLet,listIdx,childIdx,1)">{{notLet.describe}}
<b :class="{active:notLet.active}">{{notLet.odds}}
<view
v-if="football.notLetOddsList.length>0&¬LetIndex==0&&football.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</b></span>
<span v-if="football.letOddsList!=undefined&&football.letOddsList.length<=0"
style="width: 100%;"><b>未开售</b></span>
<span style="position: relative;"
v-else-if="football.letOddsList!=undefined&&football.letOddsList.length>0"
v-for="(lets,letsIndex) in football.letOddsList" :class="{active:lets.active}"
@tap="selectBtn(football,lets,listIdx,childIdx,2)">{{lets.describe}}
<b :class="{active:lets.active}">{{lets.odds}}</b>
<view v-if="football.notLetOddsList.length<=0&&letsIndex==0&&football.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</span>
</div>
</div>
<!--2总进球-->
<div v-show="changeBall === 0" class="morePlay_zongjinqiu">
<!--左-->
<div class="zongjinqiu_left">
<span>总进球</span>
</div>
<!--右-->
<div class="zongjinqiu_right" v-if="football.goalOddsList!=undefined">
<span v-if="football.goalOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-else @tap="selectBtn(football,a,listIdx,childIdx,3)" :class="{active:a.active}"
v-for="(a,index) in football.goalOddsList" :key="index"><b>{{index}}<em
v-if="index === 7">+</em></b> <b
:class="{active:a.active}">{{a.odds}}</b></span>
</div>
</div>
<!--3半全场-->
<div v-show="changeBall === 0 || changeBall === 5" class="morePlay_banquanchang">
<!--左-->
<div class="banquanchang_left">
<span>半全场</span>
</div>
<!--右-->
<div class="banquanchang_right" v-if="football.halfWholeOddsList!=undefined">
<span v-if="football.halfWholeOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-else :class="{active:a.active}" @tap="selectBtn(football,a,listIdx,childIdx,5)"
v-for="(a,index) in football.halfWholeOddsList"><b>{{bqcItems[index]}}</b>
<b :class="{active:a.active}">{{a.odds}}</b></span>
</div>
</div>
<!--4比分-->
<div v-show="changeBall === 0" class="morePlay_bifen">
<!--左-->
<div class="bifen_left">
<span>比分胜</span>
<span>比分平</span>
<span>比分负</span>
</div>
<!--右-->
<div class="bifen_right" v-if="football.scoreOddsList!=undefined">
<span v-if="football.scoreOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-else @tap="selectBtn(football,b,listIdx,childIdx,4)"
v-for="(b,index) in football.scoreOddsList" :key="index"
:class="{doubleW:index === 12 || index === 30, treW:index === 17,active:b.active}">
<b>{{bifenItems[index]}}</b>
<b :class="{active:b.active}">{{b.odds}}</b>
</span>
</div>
</div>
<!--5比分拆分版-->
<div v-show="changeBall === 4" class="morePlay_bifen_zhusheng">
<!--左-->
<div class="bifen_left">
<span>主胜</span>
</div>
<!--右-->
<div class="bifen_right" v-if="football.scoreOddsList!=undefined">
<span v-if="football.scoreOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-if="index <= 12" v-for="(b,index) in football.scoreOddsList" :key="index"
@tap="selectBtn(football,b,listIdx,childIdx,4)"
:class="{doubleW:index === 12,active:b.active}">
<b>{{bifenItems[index]}}</b>
<b :class="{active:b.active}">{{b.odds}}</b>
</span>
</div>
</div>
<div v-show="changeBall === 4" class="morePlay_bifen_ping">
<!--左-->
<div class="bifen_left">
<span>平</span>
</div>
<!--右-->
<div class="bifen_right" v-if="football.scoreOddsList!=undefined">
<span v-if="football.scoreOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-if="index > 12 && index <= 17" @tap="selectBtn(football,b,listIdx,childIdx,4)"
v-for="(b,index) in football.scoreOddsList" :key="index"
:class="{treW:index === 17,active:b.active}">
<b>{{bifenItems[index]}}</b>
<b :class="{active:b.active}">{{b.odds}}</b>
</span>
</div>
</div>
<div v-show="changeBall === 4" class="morePlay_bifen_kesheng">
<!--左-->
<div class="bifen_left">
<span>客胜</span>
</div>
<!--右-->
<div class="bifen_right" v-if="football.scoreOddsList!=undefined">
<span v-if="football.scoreOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-if="index > 17" v-for="(b,index) in football.scoreOddsList" :key="index"
@tap="selectBtn(football,b,listIdx,childIdx,4)"
:class="{doubleW:index === 30,active:b.active}">
<b>{{bifenItems[index]}}</b>
<b :class="{active:b.active}">{{b.odds}}</b>
</span>
</div>
</div>
</div>
<!--取消/确定-->
<div class="morePlay_action">
<div @click="isShowMorePlay = false">取消</div>
<div @click="isShowMorePlay = false">确定</div>
</div>
</div>
</u-popup>
</div>
</view>
</template>
<script>
import {
footballWinEvenLoseList
} from '@/api/football.js'
import BuyFooterSport from '../common/buy-footer-sport.vue'
export default {
name: 'Soccer',
components: {
BuyFooterSport
},
data() {
return {
lassificationcList: [{
name: '混合过关'
}, {
name: '胜平负'
}, {
name: '让球胜平负'
}, {
name: '总进球'
}, {
name: '比分'
}, {
name: '半全场'
}],
bifenItems: ['1:0', '2:0', '2:1', '3:0', '3:1', '3:2', '4:0', '4:1', '4:2', '5:0', '5:1', '5:2', '胜其他',
'0:0', '1:1', '2:2', '3:3', '平其他', '0:1', '0:2', '1:2', '0:3', '1:3', '2:3', '0:4', '1:4', '2:4',
'0:5', '1:5', '2:5', '负其他'
],
bqcItems: ['胜-胜', '胜-平', '胜-负', '平-胜', '平-平', '平-负', '负-胜', '负-平', '负-负'],
// 混合玩法-更多玩法
isShowMorePlay: false,
isShowCount: false,
changeBall: 0,
isChangeIcon: 0,
isShowGames: 0,
beidanList: [],
isMainShow: true,
football: {},
that: this,
listIdx: "",
childIdx: "",
count: "",
total: "",
selectItem: [],
}
},
filters: {
formatDate(data, that) {
if (null == data) {
return null;
}
return that.globalUtil.timeFormat(data)
},
},
onPullDownRefresh() {
this.fecthSoccerData();
setTimeout(function() {
uni.stopPullDownRefresh()
}, 500);
},
methods: {
/** 选中时改变当前单元格的背景颜色
* @param {Object} wk 当前比赛数据
* @param {Object} item 当前点击的数据
* @param {Object} weekIdx 上上级父级list的index
* @param {Object} index 上级父级list的index
* @param {Object} ,type 类型
*/
selectBtn(wk, item, weekIdx, index, type) {
if (type == 1) {
//不让球
this.beidanList[weekIdx].footballMatchList[index].notLetOddsList.map(data => {
if (item.id == data.id) {
this.$set(data, "active", !item.active)
}
})
} else if (type == 2) {
//让球
this.beidanList[weekIdx].footballMatchList[index].letOddsList.map(data => {
if (item.id == data.id) {
this.$set(data, "active", !item.active)
}
})
} else if (type == 3) {
//总进球
this.beidanList[weekIdx].footballMatchList[index].goalOddsList.map(data => {
if (item.id == data.id) {
this.$set(data, "active", !item.active)
}
})
} else if (type == 4) {
//比分
this.beidanList[weekIdx].footballMatchList[index].scoreOddsList.map(data => {
if (item.id == data.id) {
this.$set(data, "active", !item.active)
}
})
//标识是否选择了比分
this.$set(wk, 'scoreFlag', "false")
} else if (type == 5) {
//半全场
this.beidanList[weekIdx].footballMatchList[index].halfWholeOddsList.map(data => {
if (item.id == data.id) {
this.$set(data, "active", !item.active)
}
})
this.$set(wk, 'halfWholeFlag', "false")
}
//计算选中了几项
if (item.active) {
wk.choiceCount++;
} else {
wk.choiceCount--;
}
//获取选中的数据放入新的数组中
if (this.selectItem.length > 0) {
//标识是否在数组中是否存在
let flag = true
this.selectItem.map((d, idx) => {
//判断id 如果相同进行重新赋值 在将flag置为true
if (d.id == wk.id) {
flag = false
//如果都取消了判断选中项是否为零,为零就删除元素
if (d.choiceCount == 0) {
//index 当前元素索引;1:需要删除的元素个数
this.selectItem.splice(idx, 1);
}
//重新赋值数据
d = item;
}
})
//如果都不存在进行添加到数组中
if (flag) {
this.selectItem.push(wk)
}
} else {
//第一次数组为空的时候添加到数组中
this.selectItem.push(wk)
}
// this.isShowCount=true;
this.count = this.selectItem.length;
// this.total=2;
},
rightText() {
uni.navigateTo({
url: "pages/football/footballResult"
});
},
clean() {
this.count = "";
this.fecthSoccerData();
this.selectItem = []
},
analysis(url) {
if (url == null || url == "" || url == undefined) {
uni.showToast({
title: '暂无分析数据',
icon: 'none'
});
return;
}
uni.navigateTo({
url: "/pages/common/analysis?url=" + encodeURIComponent(url)
});
},
confirm() {
var count;
var flag = true;
this.selectItem.map((item) => {
//循环遍历是否是单关
if (item.isSingle == '1') {
//如果是单关并且让球不为空的清空下,看不让球有没有被选择,选择了就不是单关
if (item.notLetOddsList.length > 0) {
item.letOddsList.map(lets => {
if (lets.active) {
count = this.selectItem.length;
//用来标记是否是单关,传到下单也有用来判断是否有那个单关的下注选项
flag = false;
return;
}
})
}
} else {
//不是单关判断让球,非让球是否有选择数据
item.notLetOddsList.map(notLet => {
if (notLet.active) {
count = this.selectItem.length;
//用来标记是否是单关,传到下单也有用来判断是否有那个单关的下注选项
flag = false
return;
}
})
item.letOddsList.map(lets => {
if (lets.active) {
count = this.selectItem.length;
//用来标记是否是单关,传到下单也有用来判断是否有那个单关的下注选项
flag = false
return;
}
})
}
})
//如果不是单关,选中了让球或者非让球就需要校验场数,比赛是最低二场
if (count < 2 || this.selectItem.length <= 0) {
uni.showToast({
title: '至少选择二场比赛',
icon: 'none'
});
return;
}
if (this.selectItem.length > 8) {
uni.showToast({
title: '最多选择8场比赛',
icon: 'none'
});
return;
}
//总投注选项数不能超过20个
let selectCount = 0;
//每场相乘不能大于16
let rideCount = 1;
this.selectItem.some((map, idx) => {
selectCount += map.choiceCount
let a = 0;
map.letOddsList.some(b => {
if (b.active) {
a++;
return true;
}
})
map.notLetOddsList.some(b => {
if (b.active) {
a++;
return true;
}
})
map.goalOddsList.some(b => {
if (b.active) {
a++;
return true;
}
})
map.halfWholeOddsList.some(b => {
if (b.active) {
a++;
return true;
}
})
map.scoreOddsList.some(b => {
if (b.active) {
a++;
return true;
}
})
rideCount *= a;
})
if (selectCount > 20) {
uni.showToast({
title: '总投注选项数不能超过20个',
icon: 'none'
});
return;
}
if (rideCount > 16) {
uni.showToast({
title: '每场选择玩法数连乘不能超过16个',
icon: 'none'
});
return;
}
uni.navigateTo({
url: "pages/football/footballConfirm?obj=" + encodeURIComponent(JSON.stringify(this
.selectItem)) + "&flag=" + encodeURIComponent(flag)
});
},
// 获取竞彩足球数据
fecthSoccerData() {
uni.showLoading();
footballWinEvenLoseList().then(res => {
this.beidanList = res.voList
setTimeout(function() {
uni.hideLoading();
}, 50);
})
},
// 不同玩法对应投注
changeSelectBall(item) {
this.fecthSoccerData()
this.changeBall = item.index
this.selectItem = [];
this.count = "";
},
// 点击折叠条
clickBanner(index) {
if (this.isShowGames === index) {
this.isShowGames = index + 'a'
this.isChangeIcon = index + 'a'
} else {
this.isShowGames = index
this.isChangeIcon = index
}
},
// 点击打开更多玩法
morePlay(item, listIdx, childIdx) {
// 控制更多玩法显示
this.isShowMorePlay = true
this.football = item;
this.listIdx = listIdx
this.childIdx = childIdx
},
},
onLoad() {
this.fecthSoccerData()
}
}
</script>
<style scoped lang="scss">
/deep/.u-tag {
width: 45px;
height: 20px;
justify-content: center;
align-items: center;
}
/deep/.u-tag__text--medium {
font-size: 11px;
line-height: 11px;
}
page {
background-color: #f7f9fa;
}
/deep/.cmd-nav-bar-right-text {
font-size: 16px !important;
}
/deep/.u-empty {
margin-top: 50% !important;
}
.active {
background-color: #FF3F43 !important;
color: #fff !important;
}
.box {
padding-bottom: 0px;
}
.soccer_wrap {
.soccer_main {
background-color: #f7f9fa;
width: 100%;
padding-bottom: 10px;
/*混合过关*/
.soccer_hunheguoguan {
width: 100%;
padding-bottom: 10px;
.soccer_weekGame {
width: 100%;
/*比赛折叠条*/
.weekGame_banner {
width: 100%;
background-color: white;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 4vmin;
height: 12.8vmin;
box-sizing: border-box;
border-bottom: 1px solid #eee;
.banner_left {
span {
margin-left: 3.46667vmin;
font-size: 3.46667vmin;
}
}
i {
font-size: 5.26667vmin;
color: #c7c7c7;
/*transform: rotate(180deg);*/
}
.icon-jiantou2-change {
transform: rotate(180deg);
}
}
/*比赛*/
.weekGame_games {
width: 100%;
.games {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: flex-start;
height: 30.66667vmin;
margin: 0 2.66667vmin;
border-bottom: 1px solid #e6e6e6;
/*box-sizing: border-box;*/
.games_left {
width: 15vmin;
height: 100%;
font-size: 2.93333vmin;
font-weight: 400;
margin-right: 2.4vmin;
color: #333333;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
span {
text-overflow: ellipsis;
display: block;
margin-bottom: 1.8vmin;
white-space: nowrap;
}
}
.games_right {
/*height: 100%;*/
box-sizing: border-box;
.right_title {
/*box-sizing: border-box;*/
display: flex;
align-items: center;
justify-content: flex-start;
position: relative;
b {
position: absolute;
left: 0;
top: -2vmin;
width: 3.73333vmin;
display: inline-block;
font-weight: 400;
font-size: 5.33333vmin;
-webkit-transform: scale(.5);
transform: scale(.5);
line-height: 1.2;
}
.title_team {
/*margin:0 auto;*/
font-size: 3.2vmin;
height: 35px;
font-weight: 700;
color: #5d5d5d;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
strong {
margin: 0 .66667vmin;
font-weight: 400;
}
em {
font-style: normal;
font-size: 2.4vmin;
font-weight: 400;
}
}
}
table {
width: 100%;
border: 1px solid #e6e6e6;
color: #333333;
tr {
td {
/*vertical-align: middle;*/
font-size: 3.46667vmin;
background-color: white;
}
.burangqiu {
border: none;
width: 3.73333vmin;
font-size: 2.93333vmin;
text-align: center;
background: #e6e6e6;
height: 9.6vmin;
vertical-align: middle
}
.rangqiu {
color: white;
border: none;
width: 3.73333vmin;
font-size: 2.93333vmin;
text-align: center;
background: #FF3F43;
height: 9.6vmin;
vertical-align: middle
}
.rangqiuBlue {
background: #2d8cf0;
}
.sheng_top {
height: 9.6vmin;
box-sizing: border-box;
border: 1px solid #e6e6e6;
font-size: 3.46667vmin;
text-align: center;
justify-content: center;
p {
display: flex;
align-items: center;
height: 100%;
box-sizing: border-box;
justify-content: center;
span {
width: 20.5vmin;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
border-right: 1px solid #e6e6e6;
}
span:last-child {
border: none;
}
}
}
.morePlay {
width: 10.66667vmin;
font-size: 3.46667vmin;
text-align: center;
border: 1px solid #e6e6e6;
color: #999999;
vertical-align: middle;
line-height: 1.5;
}
}
}
}
}
.games:last-child {
border: none;
}
}
}
.soccer_weekGame:last-child {
margin-bottom: 13.33333vmin;
}
}
/*胜平负\让球胜平负*/
.soccer_shengpingfu {
background-color: white;
width: 100%;
.soccer_weekGame {
width: 100%;
/*比赛折叠条*/
.weekGame_banner {
width: 100%;
background-color: white;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 4vmin;
height: 12.8vmin;
box-sizing: border-box;
border-bottom: 1px solid #eee;
.banner_left {
span {
margin-left: 3.46667vmin;
font-size: 3.46667vmin;
}
}
i {
font-size: 5.26667vmin;
color: #c7c7c7;
/*transform: rotate(180deg);*/
}
.icon-jiantou2-change {
transform: rotate(180deg);
}
}
/*比赛*/
.weekGame_games {
width: 100%;
.games {
padding: 3.2vmin 0;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: flex-start;
height: 25.33333vmin;
margin: 0 2.66667vmin;
border-bottom: 1px solid #e6e6e6;
.games_left {
width: 15vmin;
height: 100%;
font-size: 2.93333vmin;
font-weight: 400;
margin-right: 2.4vmin;
color: #333333;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
span {
text-overflow: ellipsis;
display: block;
margin-bottom: 1.8vmin;
white-space: nowrap;
}
}
.games_right {
/*height: 100%;*/
box-sizing: border-box;
width: 100%;
.right_title {
display: flex;
align-items: center;
justify-content: center;
position: relative;
span {
margin-bottom: 2.66667vmin;
font-size: 3.2vmin;
display: inline-block;
font-weight: 700;
color: #5d5d5d;
white-space: nowrap;
strong {
margin: 0 .66667vmin;
font-weight: 400;
}
em {
color: #999;
font-style: normal;
font-size: 2.4vmin;
font-weight: 400;
}
}
}
table {
width: 100%;
border: 1px solid #e6e6e6;
color: #333333;
tr {
td {
/*vertical-align: middle;*/
font-size: 3.46667vmin;
background-color: white;
}
.sheng_top {
height: 11.73333vmin;
box-sizing: border-box;
border: 1px solid #e6e6e6;
font-size: 3.73333vmin;
text-align: center;
p {
display: flex;
align-items: center;
height: 100%;
box-sizing: border-box;
justify-content: center;
/*text-align: center;*/
.sheng_top_block {
width: 25.3vmin;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
border-right: 1px solid #e6e6e6;
flex-direction: column;
span {
margin-bottom: .66667vmin;
}
span:last-child {
color: #666;
}
}
.sheng_top_block:last-child {
border: none;
}
}
}
}
}
}
}
.games:last-child {
border: none;
}
}
}
.soccer_weekGame:last-child {
margin-bottom: 13.33333vmin;
}
}
/*总进球*/
.soccer_zongjinqiu {
background-color: white;
width: 100%;
.soccer_weekGame {
width: 100%;
/*比赛折叠条*/
.weekGame_banner {
width: 100%;
background-color: white;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 4vmin;
height: 12.8vmin;
box-sizing: border-box;
border-bottom: 1px solid #eee;
.banner_left {
span {
margin-left: 3.46667vmin;
font-size: 3.46667vmin;
}
}
i {
font-size: 5.26667vmin;
color: #c7c7c7;
/*transform: rotate(180deg);*/
}
.icon-jiantou2-change {
transform: rotate(180deg);
}
}
/*比赛*/
.weekGame_games {
width: 100%;
.games {
padding: 1.2vmin 0;
position: relative;
/*box-sizing: border-box;*/
display: flex;
align-items: center;
justify-content: flex-start;
height: 27.33333vmin;
margin: 0 2.66667vmin;
border-bottom: 1px solid #e6e6e6;
img {
position: absolute;
top: 0;
left: -11px;
width: 5.06667vmin;
height: 3.2vmin;
}
.games_left {
width: 15vmin;
height: 100%;
font-size: 2.93333vmin;
font-weight: 400;
margin-right: 2.4vmin;
color: #333333;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 20px;
span {
text-overflow: ellipsis;
display: block;
margin-bottom: 1.8vmin;
white-space: nowrap;
}
}
.games_right {
box-sizing: border-box;
.right_title {
display: flex;
align-items: center;
justify-content: center;
position: relative;
span {
margin-bottom: 2.66667vmin;
font-size: 3.2vmin;
display: inline-block;
font-weight: 700;
color: #5d5d5d;
white-space: nowrap;
strong {
margin: 0 .66667vmin;
font-weight: 400;
}
em {
color: #999;
font-style: normal;
font-size: 2.4vmin;
font-weight: 400;
}
}
}
table {
width: 100%;
border: 1px solid #e6e6e6;
color: #333333;
border-bottom: none;
tr {
border: 1px solid #e6e6e6;
background-color: white;
td {
border-bottom: 1px solid #e6e6e6;
color: #666;
width: 20.73333vmin;
height: 7.73333vmin;
box-sizing: border-box;
font-size: 3.2vmin;
text-align: left;
border-right: 1px solid #e6e6e6;
vertical-align: middle;
span {
font-weight: 400;
b {
margin-right: 2vmin;
}
}
}
}
}
}
}
.games:last-child {
border: none;
}
}
}
.soccer_weekGame:last-child {
margin-bottom: 13.33333vmin;
}
}
/*比分*/
.soccer_bifen {
background-color: white;
width: 100%;
.soccer_weekGame {
width: 100%;
/*比赛折叠条*/
.weekGame_banner {
width: 100%;
background-color: white;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 4vmin;
height: 12.8vmin;
box-sizing: border-box;
border-bottom: 1px solid #eee;
.banner_left {
span {
margin-left: 3.46667vmin;
font-size: 3.46667vmin;
}
}
i {
font-size: 5.26667vmin;
color: #c7c7c7;
/*transform: rotate(180deg);*/
}
.icon-jiantou2-change {
transform: rotate(180deg);
}
}
/*比赛*/
.weekGame_games {
width: 100%;
.games {
height: 27.33333vmin;
position: relative;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: flex-start;
margin: 0 2.66667vmin;
border-bottom: 1px solid #e6e6e6;
img {
position: absolute;
top: 0;
left: -11px;
width: 5.06667vmin;
height: 3.2vmin;
}
.games_left {
width: 15vmin;
height: 100%;
font-size: 2.93333vmin;
font-weight: 400;
margin-right: 2.4vmin;
color: #333333;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 20px;
span {
text-overflow: ellipsis;
display: block;
margin-bottom: 1.8vmin;
white-space: nowrap;
}
}
.games_right {
width: 100vmin;
box-sizing: border-box;
overflow: hidden;
/*超出隐藏*/
text-overflow: ellipsis;
/*隐藏后添加省略号*/
white-space: nowrap;
/*强制不换行*/
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
.right_title {
display: flex;
align-items: center;
justify-content: center;
position: relative;
span {
margin-bottom: 4.66667vmin;
display: inline-block;
font-weight: 700;
color: #5d5d5d;
white-space: nowrap;
font-size: 3.2vmin;
strong {
margin: 0 .66667vmin;
font-weight: 400;
}
em {
font-style: normal;
font-size: 2.4vmin;
font-weight: 400;
color: #999;
}
}
}
div {
box-sizing: border-box;
padding: 3.2vmin 0;
height: 9.6vmin;
width: 100%;
border: .26667vmin solid #e6e6e6;
background: #fff;
color: #666;
font-size: 3.46667vmin;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.games:last-child {
border: none;
}
}
}
.soccer_weekGame:last-child {
margin-bottom: 13.33333vmin;
}
}
.weekGame_games {
border-bottom: 1px solid #e6e6e6;
}
}
/*更多玩法*/
.morePlays {
/*height: 500px;*/
width: 100%;
.morePlay {
background-color: #F2F2F2;
width: 100%;
/*头部*/
h5 {
/*font-weight: bold;*/
font-size: 2.93333vmin;
width: 100%;
height: 9.33333vmin;
background: #fff;
margin-bottom: 2.13333vmin;
display: flex;
align-items: center;
justify-content: center;
span {
margin: 0 14.66667vmin;
font-weight: bold;
}
}
/*选择*/
.morePlay_select {
margin: 0 2.93333vmin;
font-size: 1.86667vmin;
/*混合*/
.morePlay_hunhe {
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
margin-bottom: 2.3vmin;
/*左*/
.hunhe_left {
span {
width: 6.9vmin;
height: 70rpx;
display: flex;
align-items: center;
justify-content: center;
}
.hunhe_left_top {
background-color: rgb(224, 224, 224);
}
.hunhe_left_bottom {
background-color: #19BE6B;
color: white;
}
}
/*右*/
.hunhe_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 9.1vmin;
width: 28.8vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
align-items: center;
justify-content: center;
b:last-child {
color: #666;
}
b:first-child {
margin-right: 7vmin;
}
}
}
}
/*总进球*/
.morePlay_zongjinqiu {
margin-bottom: 2.3vmin;
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.zongjinqiu_left {
height: 21.13333vmin;
background-color: #34ccc3;
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
}
}
.zongjinqiu_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
height: 18.13333vmin;
span {
background-color: white;
height: 18.13333vmin/2;
width: 21.5vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
b {
width: 21.5vmin/2;
display: flex;
justify-content: center;
em {
font-style: normal;
}
}
b:last-child {
color: #666;
}
}
}
}
/*半全场*/
.morePlay_banquanchang {
margin-bottom: 2.13333vmin;
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.banquanchang_left {
height: 27.06667vmin;
background-color: #36a8f8;
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
}
}
.banquanchang_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 8.8vmin;
width: 28.8vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
align-items: center;
justify-content: center;
b {
width: 28.82vmin/2;
display: flex;
justify-content: center;
margin-left: 10rpx;
}
b:last-child {
color: #666;
}
}
}
}
/*比分*/
.morePlay_bifen {
margin-bottom: 2.13333vmin;
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.bifen_left {
height: 54.13333vmin;
span {
background-color: #fbb52f;
display: flex;
align-items: center;
justify-content: center;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
border-bottom: 2px solid #fff;
}
span:nth-child(1) {
background-color: #fbb52f;
height: 38%;
}
span:nth-child(2) {
background-color: #D52BB3;
height: 22%;
}
span:nth-child(3) {
background-color: #1cedf2;
height: 38%;
}
}
/*右*/
.bifen_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 10.5vmin;
width: 12.19vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
b:first-child {
margin-bottom: 1.6vmin;
}
b:last-child {
color: #666;
}
}
.doubleW {
width: 12.3vmin*2;
}
.treW {
width: 37vmin;
}
}
}
/*比分-主胜*/
.morePlay_bifen_zhusheng {
margin-bottom: 2.13333vmin;
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.bifen_left {
height: 54.13333vmin/5*2;
background-color: #fbb52f;
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
}
}
/*右*/
.bifen_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 10.5vmin;
width: 12.19vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
b:first-child {
margin-bottom: 1.6vmin;
}
b:last-child {
color: #666;
}
}
.doubleW {
width: 12.3vmin*2;
}
.treW {
width: 37vmin;
}
}
}
/*比分-平*/
.morePlay_bifen_ping {
margin-bottom: 2.13333vmin;
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.bifen_left {
height: 160rpx;
background-color: #5791F9;
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
}
}
/*右*/
.bifen_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 10.5vmin;
width: 12.2vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
b:first-child {
margin-bottom: 1.6vmin;
}
b:last-child {
color: #666;
}
}
.doubleW {
width: 12.3vmin*2;
}
.treW {
width: 37vmin;
}
}
}
/*比分-客胜*/
.morePlay_bifen_kesheng {
margin-bottom: 2.13333vmin;
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.bifen_left {
height: 54.13333vmin/5*2;
background-color: #34ccc3;
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
}
}
/*右*/
.bifen_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 10.5vmin;
width: 12.19vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
b:first-child {
margin-bottom: 1.6vmin;
}
b:last-child {
color: #666;
}
}
.doubleW {
width: 12.3vmin*2;
}
.treW {
width: 37vmin;
}
}
}
}
/*取消/确定*/
.morePlay_action {
width: 100%;
font-size: 4.26667vmin;
display: flex;
div {
width: 50%;
height: 11.73333vmin;
border-radius: 1.1vmin;
display: flex;
align-items: center;
justify-content: center;
}
div:first-child {
background: #ccc;
color: #333333;
}
div:last-child {
background-color: #FF3F43;
color: white;
}
}
}
}
}
</style>
最近给朋友做了一个竞彩实体店的APP助手项目,项目已经写完,现在给大家分享给大家一些心得。
竞彩实体店的APP助手算法一般包括以下几个方面:
赔率分析算法:通过对历史比赛数据和球队情况进行分析,预测比赛结果并计算出相应的赔率。
赛事推荐算法:根据用户的历史投注记录和偏好,推荐适合用户的比赛和投注方式。
赛果分析算法:对比赛结果进行分析,包括比分、进球数、角球数等,为用户提供更准确的比赛结果预测。
投注模拟算法:通过模拟用户的投注行为,预测用户可能的投注方式和投注金额,并为用户提供相应的建议。
实时数据更新算法:及时更新比赛数据和赔率变化情况,为用户提供最新的比赛信息和投注建议。
这些算法可以结合起来,为用户提供更准确的赛事分析和投注建议,提高用户的投注成功率和体验。
<template>
<view class="box">
<cmd-nav-bar title="竞彩足球" :back="true" font-color="#fff" background-color="#FF3F43" @rightText="rightText"
right-text="足球开奖">
</cmd-nav-bar>
<div class="soccer_wrap">
<!--main-->
<div class="soccer_main" v-show="isMainShow">
<u-sticky bgColor="#fff"
style="margin-bottom: 30px;display: flex;justify-content: center;align-items: center;">
<u-tabs :list="lassificationcList" lineColor="#FF3F43"
:activeStyle="{color: '#FF3F43',fontWeight: 'bold',transform: 'scale(1.05)'}"
@click="changeSelectBall"></u-tabs>
</u-sticky>
<!--混合过关-->
<u-empty icon="http://cdn.uviewui.com/uview/empty/data.png" :show="beidanList.length<=0" mode="data"
text="暂无比赛"></u-empty>
<div class="soccer_hunheguoguan" v-if="changeBall == 0">
<!--每周比赛-->
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,index) in wk.footballMatchList" :key="index">
<div class="games_left">
<span><b>{{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span
class="title_team">{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</span>
</span>
<!--表格-->
<table>
<tr>
<td class="burangqiu">0</td>
<td class="sheng_top">
<p>
<span style="position: relative;"
v-for="(notLet,notLetIndex) in game.notLetOddsList"
:class="{active:notLet.active}"
@tap="selectBtn(game,notLet,weekIdx,index,1)">{{notLet.describe}}
{{notLet.odds}}
<view
v-if="game.notLetOddsList.length>0&¬LetIndex==0&&game.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</span>
<span v-if="game.notLetOddsList.length<=0">未开售</span>
</p>
</td>
<!--点击更多玩法时 传递:接口相关编号、队伍名-->
<td class="morePlay" rowspan="2" @tap="morePlay(game,weekIdx,index)">
<span v-if="game.choiceCount==0">更多<br>玩法</span>
<span v-else>已选<span
style="color: #FF3F43;display: block">{{game.choiceCount}}</span>项</span>
</td>
</tr>
<tr>
<td class="rangqiu" :class="{rangqiuBlue:game.letBall < 0}">
{{game.letBall}}
</td>
<td class="sheng_top">
<p>
<span v-if="game.letOddsList.length<=0">未开售</span>
<span v-else v-for="(lets,letsIndex) in game.letOddsList"
style="position: relative;" :class="{active:lets.active}"
@tap="selectBtn(game,lets,weekIdx,index,2)">{{lets.describe}}
{{lets.odds}}
<view
v-if="game.notLetOddsList.length<=0&&letsIndex==0&&game.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</span>
</p>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!--胜平负-->
<div class="soccer_shengpingfu" v-if="changeBall == 1">
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,index) in wk.footballMatchList">
<div class="games_left">
<span><b> {{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span>{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</em></span>
</span>
<!--表格-->
<table>
<tr v-if="game.notLetOddsList.length<=0">
<td class="sheng_top">
<span>未开售</span>
</td>
</tr>
<tr v-else>
<td class="sheng_top">
<p>
<span @tap="selectBtn(game,notLet,weekIdx,index,1)"
style="position: relative;" :class="{active:notLet.active}"
class="sheng_top_block"
v-for="(notLet,notLetIndex) in game.notLetOddsList">
<span>{{notLet.describe}}</span>
<span :class="{active:notLet.active}">{{notLet.odds}}
<view
v-if="game.notLetOddsList.length>0&¬LetIndex==0&&game.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</span>
</span>
</p>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!--让球平负-->
<div class="soccer_shengpingfu" v-if="changeBall == 2">
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,index) in wk.footballMatchList">
<div class="games_left">
<span><b> {{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span>{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</span>
</span>
<!--表格-->
<table>
<tr>
<td class="sheng_top">
<p>
<span v-if="game.letOddsList.length<=0">未开售</span>
<span v-else @tap="selectBtn(game,lets,weekIdx,index,2)"
style="position: relative;" :class="{active:lets.active}"
class="sheng_top_block"
v-for="(lets,letsIndex) in game.letOddsList">
<span>{{lets.describe}}</span>
<span :class="{active:lets.active}">{{lets.odds}}
<view
v-if="game.notLetOddsList.length<=0&&letsIndex==0&&game.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</span>
</span>
</p>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!--总进球-->
<div class="soccer_zongjinqiu" v-if="changeBall == 3">
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,index) in wk.footballMatchList">
<img src="@/static/images/football/dan.png" />
<div class="games_left">
<span><b> {{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span>{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</span>
</span>
<!--表格-->
<table>
<tr v-if="game.goalOddsList.length>0">
<td class="gameInfoSpan" :class="{active:goal.active}" v-if="idx < 4"
@tap="selectBtn(game,goal,weekIdx,index,3)"
v-for="(goal,idx) in game.goalOddsList" :key="idx">
<span><b>{{idx}}</b>{{goal.odds}}</span>
</td>
</tr>
<tr v-if="game.goalOddsList.length>0">
<td class="gameInfoSpan" v-if="idx >= 4" :class="{active:goal.active}"
@tap="selectBtn(game,goal,weekIdx,index,3)"
v-for="(goal,idx) in game.goalOddsList" :key="idx">
<span><b>{{idx}}<span v-if="idx === 7">+</span></b>{{goal.odds}}</span>
</td>
</tr>
<tr v-if="game.goalOddsList.length<=0">
未开售
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!--比分-->
<div class="soccer_bifen" v-if="changeBall == 4">
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,idx) in wk.footballMatchList">
<img src="@/static/images/football/dan.png" />
<div class="games_left">
<span><b>{{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span>{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</span>
</span>
<!--投注区-->
<div @click="morePlay(game,weekIdx,idx)">
<span v-for="s in game.scoreOddsList" v-if="s.active"
style="color: #FF3F43;font-weight: bold">
{{s.describe}} |
</span>
<span v-if="game.scoreFlag!='false'">
点击展开比分投注区
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!--半全场-->
<div class="soccer_bifen" v-if="changeBall == 5">
<div class="soccer_weekGame" v-for="(wk,weekIdx) in beidanList" :key="weekIdx">
<!--比赛折叠条-->
<div class="weekGame_banner" @click="clickBanner(weekIdx)">
<div class="banner_left">
<span>{{wk.startTime}}</span>
<span>共有{{wk.count}}场比赛可投</span>
</div>
<u-icon :name="isChangeIcon === weekIdx?'arrow-up':'arrow-down'"></u-icon>
</div>
<!--比赛-->
<div class="weekGame_games" v-show="isShowGames === weekIdx">
<!--每个比赛-->
<div class="games" v-for="(game,idx) in wk.footballMatchList">
<img src="@/static/images/football/dan.png" />
<div class="games_left">
<span><b> {{game.number}}</b></span>
<u-tag :borderColor="game.color" :bgColor="game.color" :text="game.match">
</u-tag>
<span>{{game.deadline|formatDate(that)}} 截止</span>
<span style="color: rgb(41, 121, 255);" @click="analysis(game.analysis)">分析</span>
</div>
<div class="games_right">
<!--比赛队伍-->
<span class="right_title">
<span>{{game.homeTeam}}<strong>vs</strong>{{game.visitingTeam}}</span>
</span>
<!--投注区-->
<div @click="morePlay(game,weekIdx,idx)">
<span v-for="s in game.halfWholeOddsList" v-if="s.active"
style="color: #FF3F43;font-weight: bold">
{{s.describe}} |
</span>
<span v-if="game.halfWholeFlag!='false'">
点击展开半全场
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<BuyFooterSport :count='count' :total='total' :isShowCount="isShowCount" @clean="clean"
@confirm="confirm"></BuyFooterSport>
</div>
<!--隐藏:更多玩法 根据index更改数据 根据isShowMorePlay控制显示-->
<u-popup class="morePlays" :show="isShowMorePlay" mode="bottom" @close="isShowMorePlay = false">
<div class="morePlay">
<!--队伍-->
<h5 class="morePlay_title">
{{football.homeTeam}}
<span>VS</span>
{{football.visitingTeam}}
</h5>
<!--玩法:根据头部index切换更多玩法显示内容-->
<div class="morePlay_select">
<!--1混合-->
<div v-show="changeBall === 0" class="morePlay_hunhe">
<!--左-->
<div class="hunhe_left">
<span class="hunhe_left_top">0</span>
<span class="hunhe_left_bottom">{{football.letBall}}</span>
</div>
<!--右-->
<div class="hunhe_right">
<span v-if="football.notLetOddsList!=undefined&&football.notLetOddsList.length<=0"
style="width: 100%;"><b>未开售</b></span>
<span style="position: relative;"
v-else-if="football.notLetOddsList!=undefined&&football.notLetOddsList.length>0"
v-for="(notLet,notLetIndex) in football.notLetOddsList"
:class="{active:notLet.active}"
@tap="selectBtn(football,notLet,listIdx,childIdx,1)">{{notLet.describe}}
<b :class="{active:notLet.active}">{{notLet.odds}}
<view
v-if="football.notLetOddsList.length>0&¬LetIndex==0&&football.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</b></span>
<span v-if="football.letOddsList!=undefined&&football.letOddsList.length<=0"
style="width: 100%;"><b>未开售</b></span>
<span style="position: relative;"
v-else-if="football.letOddsList!=undefined&&football.letOddsList.length>0"
v-for="(lets,letsIndex) in football.letOddsList" :class="{active:lets.active}"
@tap="selectBtn(football,lets,listIdx,childIdx,2)">{{lets.describe}}
<b :class="{active:lets.active}">{{lets.odds}}</b>
<view v-if="football.notLetOddsList.length<=0&&letsIndex==0&&football.isSingle=='1'"
style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; border-top: 25px solid #FF3F43; border-right: 25px solid transparent;">
<view
style="position: absolute; left: 1px; top: -25px; color: white; font-size: 11px;">
单</view>
</view>
</span>
</div>
</div>
<!--2总进球-->
<div v-show="changeBall === 0" class="morePlay_zongjinqiu">
<!--左-->
<div class="zongjinqiu_left">
<span>总进球</span>
</div>
<!--右-->
<div class="zongjinqiu_right" v-if="football.goalOddsList!=undefined">
<span v-if="football.goalOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-else @tap="selectBtn(football,a,listIdx,childIdx,3)" :class="{active:a.active}"
v-for="(a,index) in football.goalOddsList" :key="index"><b>{{index}}<em
v-if="index === 7">+</em></b> <b
:class="{active:a.active}">{{a.odds}}</b></span>
</div>
</div>
<!--3半全场-->
<div v-show="changeBall === 0 || changeBall === 5" class="morePlay_banquanchang">
<!--左-->
<div class="banquanchang_left">
<span>半全场</span>
</div>
<!--右-->
<div class="banquanchang_right" v-if="football.halfWholeOddsList!=undefined">
<span v-if="football.halfWholeOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-else :class="{active:a.active}" @tap="selectBtn(football,a,listIdx,childIdx,5)"
v-for="(a,index) in football.halfWholeOddsList"><b>{{bqcItems[index]}}</b>
<b :class="{active:a.active}">{{a.odds}}</b></span>
</div>
</div>
<!--4比分-->
<div v-show="changeBall === 0" class="morePlay_bifen">
<!--左-->
<div class="bifen_left">
<span>比分胜</span>
<span>比分平</span>
<span>比分负</span>
</div>
<!--右-->
<div class="bifen_right" v-if="football.scoreOddsList!=undefined">
<span v-if="football.scoreOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-else @tap="selectBtn(football,b,listIdx,childIdx,4)"
v-for="(b,index) in football.scoreOddsList" :key="index"
:class="{doubleW:index === 12 || index === 30, treW:index === 17,active:b.active}">
<b>{{bifenItems[index]}}</b>
<b :class="{active:b.active}">{{b.odds}}</b>
</span>
</div>
</div>
<!--5比分拆分版-->
<div v-show="changeBall === 4" class="morePlay_bifen_zhusheng">
<!--左-->
<div class="bifen_left">
<span>主胜</span>
</div>
<!--右-->
<div class="bifen_right" v-if="football.scoreOddsList!=undefined">
<span v-if="football.scoreOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-if="index <= 12" v-for="(b,index) in football.scoreOddsList" :key="index"
@tap="selectBtn(football,b,listIdx,childIdx,4)"
:class="{doubleW:index === 12,active:b.active}">
<b>{{bifenItems[index]}}</b>
<b :class="{active:b.active}">{{b.odds}}</b>
</span>
</div>
</div>
<div v-show="changeBall === 4" class="morePlay_bifen_ping">
<!--左-->
<div class="bifen_left">
<span>平</span>
</div>
<!--右-->
<div class="bifen_right" v-if="football.scoreOddsList!=undefined">
<span v-if="football.scoreOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-if="index > 12 && index <= 17" @tap="selectBtn(football,b,listIdx,childIdx,4)"
v-for="(b,index) in football.scoreOddsList" :key="index"
:class="{treW:index === 17,active:b.active}">
<b>{{bifenItems[index]}}</b>
<b :class="{active:b.active}">{{b.odds}}</b>
</span>
</div>
</div>
<div v-show="changeBall === 4" class="morePlay_bifen_kesheng">
<!--左-->
<div class="bifen_left">
<span>客胜</span>
</div>
<!--右-->
<div class="bifen_right" v-if="football.scoreOddsList!=undefined">
<span v-if="football.scoreOddsList.length<=0" style="width: 100%;"><b>未开售</b></span>
<span v-if="index > 17" v-for="(b,index) in football.scoreOddsList" :key="index"
@tap="selectBtn(football,b,listIdx,childIdx,4)"
:class="{doubleW:index === 30,active:b.active}">
<b>{{bifenItems[index]}}</b>
<b :class="{active:b.active}">{{b.odds}}</b>
</span>
</div>
</div>
</div>
<!--取消/确定-->
<div class="morePlay_action">
<div @click="isShowMorePlay = false">取消</div>
<div @click="isShowMorePlay = false">确定</div>
</div>
</div>
</u-popup>
</div>
</view>
</template>
<script>
import {
footballWinEvenLoseList
} from '@/api/football.js'
import BuyFooterSport from '../common/buy-footer-sport.vue'
export default {
name: 'Soccer',
components: {
BuyFooterSport
},
data() {
return {
lassificationcList: [{
name: '混合过关'
}, {
name: '胜平负'
}, {
name: '让球胜平负'
}, {
name: '总进球'
}, {
name: '比分'
}, {
name: '半全场'
}],
bifenItems: ['1:0', '2:0', '2:1', '3:0', '3:1', '3:2', '4:0', '4:1', '4:2', '5:0', '5:1', '5:2', '胜其他',
'0:0', '1:1', '2:2', '3:3', '平其他', '0:1', '0:2', '1:2', '0:3', '1:3', '2:3', '0:4', '1:4', '2:4',
'0:5', '1:5', '2:5', '负其他'
],
bqcItems: ['胜-胜', '胜-平', '胜-负', '平-胜', '平-平', '平-负', '负-胜', '负-平', '负-负'],
// 混合玩法-更多玩法
isShowMorePlay: false,
isShowCount: false,
changeBall: 0,
isChangeIcon: 0,
isShowGames: 0,
beidanList: [],
isMainShow: true,
football: {},
that: this,
listIdx: "",
childIdx: "",
count: "",
total: "",
selectItem: [],
}
},
filters: {
formatDate(data, that) {
if (null == data) {
return null;
}
return that.globalUtil.timeFormat(data)
},
},
onPullDownRefresh() {
this.fecthSoccerData();
setTimeout(function() {
uni.stopPullDownRefresh()
}, 500);
},
methods: {
/** 选中时改变当前单元格的背景颜色
* @param {Object} wk 当前比赛数据
* @param {Object} item 当前点击的数据
* @param {Object} weekIdx 上上级父级list的index
* @param {Object} index 上级父级list的index
* @param {Object} ,type 类型
*/
selectBtn(wk, item, weekIdx, index, type) {
if (type == 1) {
//不让球
this.beidanList[weekIdx].footballMatchList[index].notLetOddsList.map(data => {
if (item.id == data.id) {
this.$set(data, "active", !item.active)
}
})
} else if (type == 2) {
//让球
this.beidanList[weekIdx].footballMatchList[index].letOddsList.map(data => {
if (item.id == data.id) {
this.$set(data, "active", !item.active)
}
})
} else if (type == 3) {
//总进球
this.beidanList[weekIdx].footballMatchList[index].goalOddsList.map(data => {
if (item.id == data.id) {
this.$set(data, "active", !item.active)
}
})
} else if (type == 4) {
//比分
this.beidanList[weekIdx].footballMatchList[index].scoreOddsList.map(data => {
if (item.id == data.id) {
this.$set(data, "active", !item.active)
}
})
//标识是否选择了比分
this.$set(wk, 'scoreFlag', "false")
} else if (type == 5) {
//半全场
this.beidanList[weekIdx].footballMatchList[index].halfWholeOddsList.map(data => {
if (item.id == data.id) {
this.$set(data, "active", !item.active)
}
})
this.$set(wk, 'halfWholeFlag', "false")
}
//计算选中了几项
if (item.active) {
wk.choiceCount++;
} else {
wk.choiceCount--;
}
//获取选中的数据放入新的数组中
if (this.selectItem.length > 0) {
//标识是否在数组中是否存在
let flag = true
this.selectItem.map((d, idx) => {
//判断id 如果相同进行重新赋值 在将flag置为true
if (d.id == wk.id) {
flag = false
//如果都取消了判断选中项是否为零,为零就删除元素
if (d.choiceCount == 0) {
//index 当前元素索引;1:需要删除的元素个数
this.selectItem.splice(idx, 1);
}
//重新赋值数据
d = item;
}
})
//如果都不存在进行添加到数组中
if (flag) {
this.selectItem.push(wk)
}
} else {
//第一次数组为空的时候添加到数组中
this.selectItem.push(wk)
}
// this.isShowCount=true;
this.count = this.selectItem.length;
// this.total=2;
},
rightText() {
uni.navigateTo({
url: "pages/football/footballResult"
});
},
clean() {
this.count = "";
this.fecthSoccerData();
this.selectItem = []
},
analysis(url) {
if (url == null || url == "" || url == undefined) {
uni.showToast({
title: '暂无分析数据',
icon: 'none'
});
return;
}
uni.navigateTo({
url: "/pages/common/analysis?url=" + encodeURIComponent(url)
});
},
confirm() {
var count;
var flag = true;
this.selectItem.map((item) => {
//循环遍历是否是单关
if (item.isSingle == '1') {
//如果是单关并且让球不为空的清空下,看不让球有没有被选择,选择了就不是单关
if (item.notLetOddsList.length > 0) {
item.letOddsList.map(lets => {
if (lets.active) {
count = this.selectItem.length;
//用来标记是否是单关,传到下单也有用来判断是否有那个单关的下注选项
flag = false;
return;
}
})
}
} else {
//不是单关判断让球,非让球是否有选择数据
item.notLetOddsList.map(notLet => {
if (notLet.active) {
count = this.selectItem.length;
//用来标记是否是单关,传到下单也有用来判断是否有那个单关的下注选项
flag = false
return;
}
})
item.letOddsList.map(lets => {
if (lets.active) {
count = this.selectItem.length;
//用来标记是否是单关,传到下单也有用来判断是否有那个单关的下注选项
flag = false
return;
}
})
}
})
//如果不是单关,选中了让球或者非让球就需要校验场数,比赛是最低二场
if (count < 2 || this.selectItem.length <= 0) {
uni.showToast({
title: '至少选择二场比赛',
icon: 'none'
});
return;
}
if (this.selectItem.length > 8) {
uni.showToast({
title: '最多选择8场比赛',
icon: 'none'
});
return;
}
//总投注选项数不能超过20个
let selectCount = 0;
//每场相乘不能大于16
let rideCount = 1;
this.selectItem.some((map, idx) => {
selectCount += map.choiceCount
let a = 0;
map.letOddsList.some(b => {
if (b.active) {
a++;
return true;
}
})
map.notLetOddsList.some(b => {
if (b.active) {
a++;
return true;
}
})
map.goalOddsList.some(b => {
if (b.active) {
a++;
return true;
}
})
map.halfWholeOddsList.some(b => {
if (b.active) {
a++;
return true;
}
})
map.scoreOddsList.some(b => {
if (b.active) {
a++;
return true;
}
})
rideCount *= a;
})
if (selectCount > 20) {
uni.showToast({
title: '总投注选项数不能超过20个',
icon: 'none'
});
return;
}
if (rideCount > 16) {
uni.showToast({
title: '每场选择玩法数连乘不能超过16个',
icon: 'none'
});
return;
}
uni.navigateTo({
url: "pages/football/footballConfirm?obj=" + encodeURIComponent(JSON.stringify(this
.selectItem)) + "&flag=" + encodeURIComponent(flag)
});
},
// 获取竞彩足球数据
fecthSoccerData() {
uni.showLoading();
footballWinEvenLoseList().then(res => {
this.beidanList = res.voList
setTimeout(function() {
uni.hideLoading();
}, 50);
})
},
// 不同玩法对应投注
changeSelectBall(item) {
this.fecthSoccerData()
this.changeBall = item.index
this.selectItem = [];
this.count = "";
},
// 点击折叠条
clickBanner(index) {
if (this.isShowGames === index) {
this.isShowGames = index + 'a'
this.isChangeIcon = index + 'a'
} else {
this.isShowGames = index
this.isChangeIcon = index
}
},
// 点击打开更多玩法
morePlay(item, listIdx, childIdx) {
// 控制更多玩法显示
this.isShowMorePlay = true
this.football = item;
this.listIdx = listIdx
this.childIdx = childIdx
},
},
onLoad() {
this.fecthSoccerData()
}
}
</script>
<style scoped lang="scss">
/deep/.u-tag {
width: 45px;
height: 20px;
justify-content: center;
align-items: center;
}
/deep/.u-tag__text--medium {
font-size: 11px;
line-height: 11px;
}
page {
background-color: #f7f9fa;
}
/deep/.cmd-nav-bar-right-text {
font-size: 16px !important;
}
/deep/.u-empty {
margin-top: 50% !important;
}
.active {
background-color: #FF3F43 !important;
color: #fff !important;
}
.box {
padding-bottom: 0px;
}
.soccer_wrap {
.soccer_main {
background-color: #f7f9fa;
width: 100%;
padding-bottom: 10px;
/*混合过关*/
.soccer_hunheguoguan {
width: 100%;
padding-bottom: 10px;
.soccer_weekGame {
width: 100%;
/*比赛折叠条*/
.weekGame_banner {
width: 100%;
background-color: white;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 4vmin;
height: 12.8vmin;
box-sizing: border-box;
border-bottom: 1px solid #eee;
.banner_left {
span {
margin-left: 3.46667vmin;
font-size: 3.46667vmin;
}
}
i {
font-size: 5.26667vmin;
color: #c7c7c7;
/*transform: rotate(180deg);*/
}
.icon-jiantou2-change {
transform: rotate(180deg);
}
}
/*比赛*/
.weekGame_games {
width: 100%;
.games {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: flex-start;
height: 30.66667vmin;
margin: 0 2.66667vmin;
border-bottom: 1px solid #e6e6e6;
/*box-sizing: border-box;*/
.games_left {
width: 15vmin;
height: 100%;
font-size: 2.93333vmin;
font-weight: 400;
margin-right: 2.4vmin;
color: #333333;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
span {
text-overflow: ellipsis;
display: block;
margin-bottom: 1.8vmin;
white-space: nowrap;
}
}
.games_right {
/*height: 100%;*/
box-sizing: border-box;
.right_title {
/*box-sizing: border-box;*/
display: flex;
align-items: center;
justify-content: flex-start;
position: relative;
b {
position: absolute;
left: 0;
top: -2vmin;
width: 3.73333vmin;
display: inline-block;
font-weight: 400;
font-size: 5.33333vmin;
-webkit-transform: scale(.5);
transform: scale(.5);
line-height: 1.2;
}
.title_team {
/*margin:0 auto;*/
font-size: 3.2vmin;
height: 35px;
font-weight: 700;
color: #5d5d5d;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
strong {
margin: 0 .66667vmin;
font-weight: 400;
}
em {
font-style: normal;
font-size: 2.4vmin;
font-weight: 400;
}
}
}
table {
width: 100%;
border: 1px solid #e6e6e6;
color: #333333;
tr {
td {
/*vertical-align: middle;*/
font-size: 3.46667vmin;
background-color: white;
}
.burangqiu {
border: none;
width: 3.73333vmin;
font-size: 2.93333vmin;
text-align: center;
background: #e6e6e6;
height: 9.6vmin;
vertical-align: middle
}
.rangqiu {
color: white;
border: none;
width: 3.73333vmin;
font-size: 2.93333vmin;
text-align: center;
background: #FF3F43;
height: 9.6vmin;
vertical-align: middle
}
.rangqiuBlue {
background: #2d8cf0;
}
.sheng_top {
height: 9.6vmin;
box-sizing: border-box;
border: 1px solid #e6e6e6;
font-size: 3.46667vmin;
text-align: center;
justify-content: center;
p {
display: flex;
align-items: center;
height: 100%;
box-sizing: border-box;
justify-content: center;
span {
width: 20.5vmin;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
border-right: 1px solid #e6e6e6;
}
span:last-child {
border: none;
}
}
}
.morePlay {
width: 10.66667vmin;
font-size: 3.46667vmin;
text-align: center;
border: 1px solid #e6e6e6;
color: #999999;
vertical-align: middle;
line-height: 1.5;
}
}
}
}
}
.games:last-child {
border: none;
}
}
}
.soccer_weekGame:last-child {
margin-bottom: 13.33333vmin;
}
}
/*胜平负\让球胜平负*/
.soccer_shengpingfu {
background-color: white;
width: 100%;
.soccer_weekGame {
width: 100%;
/*比赛折叠条*/
.weekGame_banner {
width: 100%;
background-color: white;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 4vmin;
height: 12.8vmin;
box-sizing: border-box;
border-bottom: 1px solid #eee;
.banner_left {
span {
margin-left: 3.46667vmin;
font-size: 3.46667vmin;
}
}
i {
font-size: 5.26667vmin;
color: #c7c7c7;
/*transform: rotate(180deg);*/
}
.icon-jiantou2-change {
transform: rotate(180deg);
}
}
/*比赛*/
.weekGame_games {
width: 100%;
.games {
padding: 3.2vmin 0;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: flex-start;
height: 25.33333vmin;
margin: 0 2.66667vmin;
border-bottom: 1px solid #e6e6e6;
.games_left {
width: 15vmin;
height: 100%;
font-size: 2.93333vmin;
font-weight: 400;
margin-right: 2.4vmin;
color: #333333;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
span {
text-overflow: ellipsis;
display: block;
margin-bottom: 1.8vmin;
white-space: nowrap;
}
}
.games_right {
/*height: 100%;*/
box-sizing: border-box;
width: 100%;
.right_title {
display: flex;
align-items: center;
justify-content: center;
position: relative;
span {
margin-bottom: 2.66667vmin;
font-size: 3.2vmin;
display: inline-block;
font-weight: 700;
color: #5d5d5d;
white-space: nowrap;
strong {
margin: 0 .66667vmin;
font-weight: 400;
}
em {
color: #999;
font-style: normal;
font-size: 2.4vmin;
font-weight: 400;
}
}
}
table {
width: 100%;
border: 1px solid #e6e6e6;
color: #333333;
tr {
td {
/*vertical-align: middle;*/
font-size: 3.46667vmin;
background-color: white;
}
.sheng_top {
height: 11.73333vmin;
box-sizing: border-box;
border: 1px solid #e6e6e6;
font-size: 3.73333vmin;
text-align: center;
p {
display: flex;
align-items: center;
height: 100%;
box-sizing: border-box;
justify-content: center;
/*text-align: center;*/
.sheng_top_block {
width: 25.3vmin;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
border-right: 1px solid #e6e6e6;
flex-direction: column;
span {
margin-bottom: .66667vmin;
}
span:last-child {
color: #666;
}
}
.sheng_top_block:last-child {
border: none;
}
}
}
}
}
}
}
.games:last-child {
border: none;
}
}
}
.soccer_weekGame:last-child {
margin-bottom: 13.33333vmin;
}
}
/*总进球*/
.soccer_zongjinqiu {
background-color: white;
width: 100%;
.soccer_weekGame {
width: 100%;
/*比赛折叠条*/
.weekGame_banner {
width: 100%;
background-color: white;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 4vmin;
height: 12.8vmin;
box-sizing: border-box;
border-bottom: 1px solid #eee;
.banner_left {
span {
margin-left: 3.46667vmin;
font-size: 3.46667vmin;
}
}
i {
font-size: 5.26667vmin;
color: #c7c7c7;
/*transform: rotate(180deg);*/
}
.icon-jiantou2-change {
transform: rotate(180deg);
}
}
/*比赛*/
.weekGame_games {
width: 100%;
.games {
padding: 1.2vmin 0;
position: relative;
/*box-sizing: border-box;*/
display: flex;
align-items: center;
justify-content: flex-start;
height: 27.33333vmin;
margin: 0 2.66667vmin;
border-bottom: 1px solid #e6e6e6;
img {
position: absolute;
top: 0;
left: -11px;
width: 5.06667vmin;
height: 3.2vmin;
}
.games_left {
width: 15vmin;
height: 100%;
font-size: 2.93333vmin;
font-weight: 400;
margin-right: 2.4vmin;
color: #333333;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 20px;
span {
text-overflow: ellipsis;
display: block;
margin-bottom: 1.8vmin;
white-space: nowrap;
}
}
.games_right {
box-sizing: border-box;
.right_title {
display: flex;
align-items: center;
justify-content: center;
position: relative;
span {
margin-bottom: 2.66667vmin;
font-size: 3.2vmin;
display: inline-block;
font-weight: 700;
color: #5d5d5d;
white-space: nowrap;
strong {
margin: 0 .66667vmin;
font-weight: 400;
}
em {
color: #999;
font-style: normal;
font-size: 2.4vmin;
font-weight: 400;
}
}
}
table {
width: 100%;
border: 1px solid #e6e6e6;
color: #333333;
border-bottom: none;
tr {
border: 1px solid #e6e6e6;
background-color: white;
td {
border-bottom: 1px solid #e6e6e6;
color: #666;
width: 20.73333vmin;
height: 7.73333vmin;
box-sizing: border-box;
font-size: 3.2vmin;
text-align: left;
border-right: 1px solid #e6e6e6;
vertical-align: middle;
span {
font-weight: 400;
b {
margin-right: 2vmin;
}
}
}
}
}
}
}
.games:last-child {
border: none;
}
}
}
.soccer_weekGame:last-child {
margin-bottom: 13.33333vmin;
}
}
/*比分*/
.soccer_bifen {
background-color: white;
width: 100%;
.soccer_weekGame {
width: 100%;
/*比赛折叠条*/
.weekGame_banner {
width: 100%;
background-color: white;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 4vmin;
height: 12.8vmin;
box-sizing: border-box;
border-bottom: 1px solid #eee;
.banner_left {
span {
margin-left: 3.46667vmin;
font-size: 3.46667vmin;
}
}
i {
font-size: 5.26667vmin;
color: #c7c7c7;
/*transform: rotate(180deg);*/
}
.icon-jiantou2-change {
transform: rotate(180deg);
}
}
/*比赛*/
.weekGame_games {
width: 100%;
.games {
height: 27.33333vmin;
position: relative;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: flex-start;
margin: 0 2.66667vmin;
border-bottom: 1px solid #e6e6e6;
img {
position: absolute;
top: 0;
left: -11px;
width: 5.06667vmin;
height: 3.2vmin;
}
.games_left {
width: 15vmin;
height: 100%;
font-size: 2.93333vmin;
font-weight: 400;
margin-right: 2.4vmin;
color: #333333;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 20px;
span {
text-overflow: ellipsis;
display: block;
margin-bottom: 1.8vmin;
white-space: nowrap;
}
}
.games_right {
width: 100vmin;
box-sizing: border-box;
overflow: hidden;
/*超出隐藏*/
text-overflow: ellipsis;
/*隐藏后添加省略号*/
white-space: nowrap;
/*强制不换行*/
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
.right_title {
display: flex;
align-items: center;
justify-content: center;
position: relative;
span {
margin-bottom: 4.66667vmin;
display: inline-block;
font-weight: 700;
color: #5d5d5d;
white-space: nowrap;
font-size: 3.2vmin;
strong {
margin: 0 .66667vmin;
font-weight: 400;
}
em {
font-style: normal;
font-size: 2.4vmin;
font-weight: 400;
color: #999;
}
}
}
div {
box-sizing: border-box;
padding: 3.2vmin 0;
height: 9.6vmin;
width: 100%;
border: .26667vmin solid #e6e6e6;
background: #fff;
color: #666;
font-size: 3.46667vmin;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.games:last-child {
border: none;
}
}
}
.soccer_weekGame:last-child {
margin-bottom: 13.33333vmin;
}
}
.weekGame_games {
border-bottom: 1px solid #e6e6e6;
}
}
/*更多玩法*/
.morePlays {
/*height: 500px;*/
width: 100%;
.morePlay {
background-color: #F2F2F2;
width: 100%;
/*头部*/
h5 {
/*font-weight: bold;*/
font-size: 2.93333vmin;
width: 100%;
height: 9.33333vmin;
background: #fff;
margin-bottom: 2.13333vmin;
display: flex;
align-items: center;
justify-content: center;
span {
margin: 0 14.66667vmin;
font-weight: bold;
}
}
/*选择*/
.morePlay_select {
margin: 0 2.93333vmin;
font-size: 1.86667vmin;
/*混合*/
.morePlay_hunhe {
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
margin-bottom: 2.3vmin;
/*左*/
.hunhe_left {
span {
width: 6.9vmin;
height: 70rpx;
display: flex;
align-items: center;
justify-content: center;
}
.hunhe_left_top {
background-color: rgb(224, 224, 224);
}
.hunhe_left_bottom {
background-color: #19BE6B;
color: white;
}
}
/*右*/
.hunhe_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 9.1vmin;
width: 28.8vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
align-items: center;
justify-content: center;
b:last-child {
color: #666;
}
b:first-child {
margin-right: 7vmin;
}
}
}
}
/*总进球*/
.morePlay_zongjinqiu {
margin-bottom: 2.3vmin;
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.zongjinqiu_left {
height: 21.13333vmin;
background-color: #34ccc3;
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
}
}
.zongjinqiu_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
height: 18.13333vmin;
span {
background-color: white;
height: 18.13333vmin/2;
width: 21.5vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
b {
width: 21.5vmin/2;
display: flex;
justify-content: center;
em {
font-style: normal;
}
}
b:last-child {
color: #666;
}
}
}
}
/*半全场*/
.morePlay_banquanchang {
margin-bottom: 2.13333vmin;
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.banquanchang_left {
height: 27.06667vmin;
background-color: #36a8f8;
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
}
}
.banquanchang_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 8.8vmin;
width: 28.8vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
align-items: center;
justify-content: center;
b {
width: 28.82vmin/2;
display: flex;
justify-content: center;
margin-left: 10rpx;
}
b:last-child {
color: #666;
}
}
}
}
/*比分*/
.morePlay_bifen {
margin-bottom: 2.13333vmin;
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.bifen_left {
height: 54.13333vmin;
span {
background-color: #fbb52f;
display: flex;
align-items: center;
justify-content: center;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
border-bottom: 2px solid #fff;
}
span:nth-child(1) {
background-color: #fbb52f;
height: 38%;
}
span:nth-child(2) {
background-color: #D52BB3;
height: 22%;
}
span:nth-child(3) {
background-color: #1cedf2;
height: 38%;
}
}
/*右*/
.bifen_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 10.5vmin;
width: 12.19vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
b:first-child {
margin-bottom: 1.6vmin;
}
b:last-child {
color: #666;
}
}
.doubleW {
width: 12.3vmin*2;
}
.treW {
width: 37vmin;
}
}
}
/*比分-主胜*/
.morePlay_bifen_zhusheng {
margin-bottom: 2.13333vmin;
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.bifen_left {
height: 54.13333vmin/5*2;
background-color: #fbb52f;
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
}
}
/*右*/
.bifen_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 10.5vmin;
width: 12.19vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
b:first-child {
margin-bottom: 1.6vmin;
}
b:last-child {
color: #666;
}
}
.doubleW {
width: 12.3vmin*2;
}
.treW {
width: 37vmin;
}
}
}
/*比分-平*/
.morePlay_bifen_ping {
margin-bottom: 2.13333vmin;
/*height: 18.13333vmin;*/
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.bifen_left {
height: 160rpx;
background-color: #5791F9;
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
}
}
/*右*/
.bifen_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 10.5vmin;
width: 12.2vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
b:first-child {
margin-bottom: 1.6vmin;
}
b:last-child {
color: #666;
}
}
.doubleW {
width: 12.3vmin*2;
}
.treW {
width: 37vmin;
}
}
}
/*比分-客胜*/
.morePlay_bifen_kesheng {
margin-bottom: 2.13333vmin;
width: 100%;
font-size: 3.46667vmin;
color: #333333;
display: flex;
align-items: center;
/*左*/
.bifen_left {
height: 54.13333vmin/5*2;
background-color: #34ccc3;
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
writing-mode: vertical-rl;
letter-spacing: .53333vmin;
font-size: 3.2vmin;
width: 6.9vmin;
color: white;
}
}
/*右*/
.bifen_right {
border-top: 1px solid #e6e6e6;
display: flex;
align-items: center;
flex-wrap: wrap;
span {
background-color: white;
height: 10.5vmin;
width: 12.19vmin;
border-right: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
b:first-child {
margin-bottom: 1.6vmin;
}
b:last-child {
color: #666;
}
}
.doubleW {
width: 12.3vmin*2;
}
.treW {
width: 37vmin;
}
}
}
}
/*取消/确定*/
.morePlay_action {
width: 100%;
font-size: 4.26667vmin;
display: flex;
div {
width: 50%;
height: 11.73333vmin;
border-radius: 1.1vmin;
display: flex;
align-items: center;
justify-content: center;
}
div:first-child {
background: #ccc;
color: #333333;
}
div:last-child {
background-color: #FF3F43;
color: white;
}
}
}
}
}
</style>
收起阅读 »

大文件切片上传
一、实现大文件切片上传可以按照以下步骤进行操作
1. 切片文件:将大文件切成小片段,每个片段的大小可根据需求来确定。这可以通过使用File.slice()
方法或其他相关方法来完成。
2. 创建上传接口:需要在后端创建一个用于接收切片上传的接口。这个接口需要能够接收切片文件并保存在服务器上,同时还需要记录每个切片的索引以及文件的唯一标识。
3. 切片上传顺序和重试机制:需要确保切片按照正确的顺序上传到服务器,并且在上传过程中出现错误时能够进行重试。可以使用Promise或async/await等方式来实现这个逻辑。
4. 服务器端逻辑:在服务器端,需要接收上传的切片文件并保存到临时位置。同时,还需要记录每个切片的索引和文件的唯一标识。当所有切片都上传完成后,可以将它们合并成完整的文件,并进行相应的处理。
二、切片的核心
定义了一个名为splitFileIntoChunks的函数,用于将文件切割为多个片段。函数接受两个参数:文件对象file和每个切片的大小chunkSize。函数首先获取文件的总大小fileSize,然后计算需要切割的切片数量chunks。接下来,使用一个循环将文件切割为多个切片,每个切片的起始位置start和结束位置end根据切片的索引计算得到。使用file.slice(start, end)方法从原文件中获取对应的切片,并将切片存储到fileChunks数组中。
function splitFileIntoChunks(file, chunkSize) {
const fileSize = file.size;
const chunks = Math.ceil(fileSize / chunkSize);
const fileChunks = [];
for (let i = 0; i < chunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, fileSize);
const chunk = file.slice(start, end);
fileChunks.push(chunk);
}
return fileChunks;
}
三、以uniapp为例,实现一个简单的大文件切片上传
// 切片上传相关配置
const chunkSize = 1024 * 1024; // 每个切片的大小(这里设置为1MB)
let fileIndex = 0; // 当前切片索引
let totalChunks = 0; // 总切片数
let fileKey = ''; // 文件的唯一标识
let fileChunks = []; // 存储切片的数组
// 选择文件并开始上传
function chooseFile() {
uni.chooseFile({
success(res) {
const filePath = res.tempFilePaths[0];
uni.getFileInfo({
filePath,
success(fileInfo) {
// 计算切片数量
totalChunks = Math.ceil(fileInfo.size / chunkSize);
// 生成文件的唯一标识
fileKey = generateFileKey();
// 将文件切割为多个切片
splitFileIntoChunks(filePath);
// 开始上传第一个切片
uploadFile(fileChunks[fileIndex]);
},
fail(error) {
// 获取文件信息失败,进行错误处理
}
});
},
fail(error) {
// 选择文件失败,进行错误处理
}
});
}
// 将文件切割为多个切片
function splitFileIntoChunks(filePath) {
const fileSize = uni.getFileSystemManager().getFileInfo({
filePath
}).size;
fileChunks = [];
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, fileSize);
const chunk = uni.getFileSystemManager().readFileSync(filePath, 'binary', start, end);
fileChunks.push(chunk);
}
}
// 上传切片
function uploadFile(chunk) {
const formData = {
fileKey,
index: fileIndex
};
uni.uploadFile({
url: 'your_upload_url', // 替换为你的上传接口地址
filePath: chunk,
name: 'file',
formData,
success(res) {
// 上传成功处理逻辑
if (res.statusCode === 200) {
const data = JSON.parse(res.data);
if (data.success) {
// 切片上传成功,继续上传下一片
fileIndex++;
if (fileIndex < totalChunks) {
uploadFile(fileChunks[fileIndex]);
} else {
// 所有切片上传完成,进行合并或其他处理
mergeChunks();
}
} else {
// 切片上传失败,进行错误处理
}
} else {
// 上传失败,进行错误处理
}
},
fail(error) {
// 上传失败,进行错误处理
}
});
}
// 切片合并或其他处理
function mergeChunks() {
// 所有切片上传完成后,进行切片合
// 其他处理逻辑
// ...
}
// 生成文件的唯一标识
function generateFileKey() {
// 根据需要生成文件的唯一标识,例如使用时间戳+随机字符串等方式
// 返回文件的唯一标识
}
注意,切片的具体实现可能会因具体的需求和使用的上传方式而有所差异。上述示例仅提供了一个基本的切片函数,你可以根据自己的需要进行修改和调整。上述若有不对之处,欢迎小伙伴们留言讨论,希望以上内容能够帮助到你!
此外,若想查看更多面试题,往这里扫一扫
一、实现大文件切片上传可以按照以下步骤进行操作
1. 切片文件:将大文件切成小片段,每个片段的大小可根据需求来确定。这可以通过使用File.slice()
方法或其他相关方法来完成。
2. 创建上传接口:需要在后端创建一个用于接收切片上传的接口。这个接口需要能够接收切片文件并保存在服务器上,同时还需要记录每个切片的索引以及文件的唯一标识。
3. 切片上传顺序和重试机制:需要确保切片按照正确的顺序上传到服务器,并且在上传过程中出现错误时能够进行重试。可以使用Promise或async/await等方式来实现这个逻辑。
4. 服务器端逻辑:在服务器端,需要接收上传的切片文件并保存到临时位置。同时,还需要记录每个切片的索引和文件的唯一标识。当所有切片都上传完成后,可以将它们合并成完整的文件,并进行相应的处理。
二、切片的核心
定义了一个名为splitFileIntoChunks的函数,用于将文件切割为多个片段。函数接受两个参数:文件对象file和每个切片的大小chunkSize。函数首先获取文件的总大小fileSize,然后计算需要切割的切片数量chunks。接下来,使用一个循环将文件切割为多个切片,每个切片的起始位置start和结束位置end根据切片的索引计算得到。使用file.slice(start, end)方法从原文件中获取对应的切片,并将切片存储到fileChunks数组中。
function splitFileIntoChunks(file, chunkSize) {
const fileSize = file.size;
const chunks = Math.ceil(fileSize / chunkSize);
const fileChunks = [];
for (let i = 0; i < chunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, fileSize);
const chunk = file.slice(start, end);
fileChunks.push(chunk);
}
return fileChunks;
}
三、以uniapp为例,实现一个简单的大文件切片上传
// 切片上传相关配置
const chunkSize = 1024 * 1024; // 每个切片的大小(这里设置为1MB)
let fileIndex = 0; // 当前切片索引
let totalChunks = 0; // 总切片数
let fileKey = ''; // 文件的唯一标识
let fileChunks = []; // 存储切片的数组
// 选择文件并开始上传
function chooseFile() {
uni.chooseFile({
success(res) {
const filePath = res.tempFilePaths[0];
uni.getFileInfo({
filePath,
success(fileInfo) {
// 计算切片数量
totalChunks = Math.ceil(fileInfo.size / chunkSize);
// 生成文件的唯一标识
fileKey = generateFileKey();
// 将文件切割为多个切片
splitFileIntoChunks(filePath);
// 开始上传第一个切片
uploadFile(fileChunks[fileIndex]);
},
fail(error) {
// 获取文件信息失败,进行错误处理
}
});
},
fail(error) {
// 选择文件失败,进行错误处理
}
});
}
// 将文件切割为多个切片
function splitFileIntoChunks(filePath) {
const fileSize = uni.getFileSystemManager().getFileInfo({
filePath
}).size;
fileChunks = [];
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, fileSize);
const chunk = uni.getFileSystemManager().readFileSync(filePath, 'binary', start, end);
fileChunks.push(chunk);
}
}
// 上传切片
function uploadFile(chunk) {
const formData = {
fileKey,
index: fileIndex
};
uni.uploadFile({
url: 'your_upload_url', // 替换为你的上传接口地址
filePath: chunk,
name: 'file',
formData,
success(res) {
// 上传成功处理逻辑
if (res.statusCode === 200) {
const data = JSON.parse(res.data);
if (data.success) {
// 切片上传成功,继续上传下一片
fileIndex++;
if (fileIndex < totalChunks) {
uploadFile(fileChunks[fileIndex]);
} else {
// 所有切片上传完成,进行合并或其他处理
mergeChunks();
}
} else {
// 切片上传失败,进行错误处理
}
} else {
// 上传失败,进行错误处理
}
},
fail(error) {
// 上传失败,进行错误处理
}
});
}
// 切片合并或其他处理
function mergeChunks() {
// 所有切片上传完成后,进行切片合
// 其他处理逻辑
// ...
}
// 生成文件的唯一标识
function generateFileKey() {
// 根据需要生成文件的唯一标识,例如使用时间戳+随机字符串等方式
// 返回文件的唯一标识
}
注意,切片的具体实现可能会因具体的需求和使用的上传方式而有所差异。上述示例仅提供了一个基本的切片函数,你可以根据自己的需要进行修改和调整。上述若有不对之处,欢迎小伙伴们留言讨论,希望以上内容能够帮助到你!
此外,若想查看更多面试题,往这里扫一扫

个人全职工作,时间充裕,全职接单!!!~~
十年前端,app,web端,小程序,全栈经验,这方面的软件开发的比较多,有相关案例,时间充裕,诚心合作,个人全职工作,uniapp 做过很多,并成功上架,日活过千,十分熟练,有需要请联系我 QQ:2981739544
十年前端,app,web端,小程序,全栈经验,这方面的软件开发的比较多,有相关案例,时间充裕,诚心合作,个人全职工作,uniapp 做过很多,并成功上架,日活过千,十分熟练,有需要请联系我 QQ:2981739544