ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

uniapp + uView使用AntV F6 + table表格插件使用

2022-06-24 11:33:39  阅读:839  来源: 互联网

标签:uniapp 插件 const item uView content width var return


首先看页面效果:

AntV官网下载F6文件到项目中

<template>

<view class="page">

<!-- 导航栏 -->

<b-nav-bar class="title">

<template slot="left">

<view @click="nativeBack" class="iconfont icon-zuofanhui nBack ml15"></view>

</template>

<view>{{navTitle}}</view>

</b-nav-bar>

<!-- 树状图 -->

<view class="page over_hidden">

<!-- #ifdef APP-PLUS || H5 -->

<view :id="option.id" :option="option" :treeDom="treeDom" :change:treeDom="treeGraph.changeTreeGraphSize"

:change:option="treeGraph.changeTreeGraphData"

style="width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;"></view>

<!-- #endif -->

<!-- #ifndef APP-PLUS || H5 -->

<view>非 APP、H5 环境不支持</view>

<!-- #endif -->

</view>

<!-- 表格弹窗 -->

<u-popup :show="showLinkTable" mode="bottom" :round="10" class="tablePopup">

<view class="tableHeader">

<scroll-view class="tableTitle" scroll-x="true">

<view style="display: inline-block;">{{tableTitle}}</view>

</scroll-view>

<view class="tableIcon" @click="closePopup">

<text class="iconfont icon-shanchu1"></text>

</view>

</view>

<view class="tableContent">

<view class="time">

最新时间:{{newTime}}

</view>

<lyy-table :headerFixed="true" :columnFixed="1" :emptyString="''" :contents="contentsData"

:headers="columnsData" :sortWays="handleSortByColumn(contentsData)"

@click="oneRowClick(contentsData)" class="lyyTable" @row-click="rowclick"></lyy-table>

</view>

</u-popup>

<!-- 点击问号注释说明弹窗 -->

<u-popup :show="showExplain" mode="bottom" :round="10" class="explainPopup">

<view class="explainHeader">

<scroll-view class="explainTitle" scroll-x="true">

<view style="display: inline-block;">{{explainTitle}}</view>

</scroll-view>

<view class="explainIcon" @click="canclePopup">

<text class="iconfont icon-shanchu1"></text>

</view>

</view>

<view class="explainContent">

{{nodeInterpret}}

</view>

</u-popup>

</view>

</template>

 

<script>

import { // 引入vuex中存储的iOS刘海屏高度

mapState

} from 'vuex';

export default {

data() {

return {

navTitle: '', // 标题

option: { // 导图数据

id: "canvasId",

data: '',

},

treeDom: { // 导图宽高

width: null,

height: null

}

}

},

computed: {

...mapState(['stabarHeight']) //刘海屏高度存储在vuex里面

},

mounted() {

uni

.createSelectorQuery()

.select("#canvasId")

.boundingClientRect((data) => {

this.treeDom = data;

})

.exec();

},

methods: {

nativeBack() {

uni.navigateTo({

url: `/pages/look-company/index/index`

})

},

}

}

</script>

</script>

 

<script module="treeGraph" lang="renderjs">

import F6 from '@/static/common/js/F6/f6.min.js' // 引入F6文件

import TreeGraph from '@/static/common/js/F6/extends/graph/treeGraph.js' // 引入F6文件

import { // 接口方法

queryFirstnodeList,

fetchGraphChildren,

queryCompanyTable

} from '@/api/company.js'

import { // js文件中公共方法引入

computeWidthHeight,

addCollapseNode,

handleChildrenData,

getArcPosition

} from './graphConfig';

import { // 自己写的获取session方法

getSession

} from '@/util/storage';

F6.registerGraph('TreeGraph', TreeGraph)

// 折叠图标

const COLLAPSE_ICON = function COLLAPSE_ICON(x, y, r) {

return [

['M', x - r, y],

['L', x + r, y],

]

}

// 展开图标

const EXPAND_ICON = function EXPAND_ICON(x, y, r) {

return [

['M', x - r, y],

['L', x + r, y],

['M', x, y - r],

['L', x, y + r]

]

}

 

// 默认边和箭头样式

const defaultEdgeStyle = {

stroke: '#3849B4',

endArrow: {

path: 'M 0,0 L 5,4 L 5,-4 Z',

lineWidth: 1,

fill: '#3849B4',

},

}

export default {

data() {

return {

graph: null,

treeData: {},

graphReady: false,

companyName: '', // 公司名称

companyCode: '', // 公司代码

topTreeData: [], // 二级节点

showLinkTable: false, // 是否显示表格弹窗

tableId: '', // 表格id

tableName: '', // 表名

contentsData: [], //表格数据

columnsData: [], //表头数据

tableTitle: '', // 表格标题

newTime: '', //最新时间

showExplain: false, // 是否显示点击问号注释说明弹窗

explainTitle: '', // 注释说明弹窗标题

nodeInterpret: '', // 注释说明弹窗内容

}

},

created() {

this.initData() // 初始化一、二级节点数据

},

mounted() {

this.init() // 初始化F6

},

onLoad(option) {

this.navTitle = `${option.title}(${option.code})` // 页面标题

this.companyName = option.title // 公司名

this.companyCode = option.code // 公司代码

},

methods: {

// 初始化一、二级节点

async initData() {

await this.requestTopTreeNode()

this.setDefaultNode()

},

// 获取二级分类节点

async requestTopTreeNode() {

try {

let res = await queryFirstnodeList({

token: sessionStorage.getItem('token')

})

res = res.data || []

res.forEach((item) => {

item.level = 2

item.hasChildren = true // 隐藏展示/折叠图表

item.collapsed = true // 当前折叠状态

item.isGetChildren = false // 是否已加载了children

})

this.topTreeData = res

} catch (err) {

err.msg && this.$alert(err.msg, '提示')

}

},

// 设置初始树数据

setDefaultNode(data) {

if (!data) {

const children = JSON.parse(JSON.stringify(this.topTreeData))

data = {

id: 'root',

name: this.companyName,

children,

level: 1

}

this.treeData = data

}

if (this.graphReady) {

this.showLinkTable = false

this.graph.data(this.treeData)

this.graph.render()

this.graph.fitCenter()

} else {

const unwatch = this.$watch('graphReady', (val) => {

if (val) {

this.setDefaultNode(data)

unwatch()

}

})

}

},

// 初始化

init() {

this.treeDom.width = wx.getSystemInfoSync().screenWidth // 获取屏幕宽度,让图水平居中

let sysInfo = getSession('systemInfo')

if (sysInfo.platform.indexOf('ios') > -1) {

this.treeDom.height = wx.getSystemInfoSync().screenHeight - 44 - this.stabarHeight // 获取ios屏幕高度,让图垂直居中

} else {

this.treeDom.height = wx.getSystemInfoSync().screenHeight - 44 // 获取安卓屏幕高度,让图垂直居中

}

// 绘制节点

F6.registerNode('icon-node', {

draw(cfg, group) {

const styles = this.getShapeStyle(cfg);

const {

labelCfg = {}

} = cfg;

// const w = styles.width;

// const h = styles.height;

let keyShape = {}

// 根节点,高度固定,宽度根据公司名调整

if (cfg.level === 1) {

const w = 75

const h = 30

keyShape = group.addShape('rect', {

attrs: {

width: w,

height: h,

x: -w / 2,

y: -h / 2,

fill: '#3849B4',

radius: 12,

},

})

group.addShape('text', {

attrs: {

...labelCfg.style,

text: cfg.name,

x: 0,

y: 0,

fontSize: 11,

fill: '#ffffff',

},

})

} else {

// 不管二/三级几点是否有展开/折叠图标宽度都不计算上,在layout中会考虑

let w = 75

let h = 30

let content = ''

// 三级以上节点宽高动态计算

if (cfg.level >= 3) {

const res = computeWidthHeight({

content: cfg.content

})

w = res.width - 30

h = res.height

content = res.content

}

cfg.hasChildren && addCollapseNode(group, w, cfg)

// 配置了有展开/折叠图标则渲染

// 二级分类节点,宽高固定

if (cfg.level === 2) {

keyShape = group.addShape('rect', {

attrs: {

fill: '#EEF2F8',

stroke: '#3849B4',

radius: 6,

width: w,

height: h,

fontSize: 11,

x: -w / 2,

y: -h / 2

},

})

group.addShape('text', {

attrs: {

...labelCfg.style,

text: cfg.name,

x: 0,

y: 0,

fontSize: 11

},

name: 'collapse-icon'

})

} else {

// 三级以上节点配置

keyShape = group.addShape('rect', {

attrs: {

width: w,

height: h,

x: -w / 2,

y: -h / 2,

fill: '#E5E5E5',

radius: 6,

fontSize: 11

},

})

// 上部关系节点名称

group.addShape('rect', {

attrs: {

x: 1 - w / 2,

y: 1 - h / 2,

width: w - 2,

height: 32,

fill: '#EEF2F8',

radius: [6, 6, 0, 0],

fontSize: 11

},

})

group.addShape('text', {

attrs: {

...labelCfg.style,

text: cfg.name,

x: 1,

y: 18 - h / 2,

},

name: 'collapse-icon'

})

// 判断是否有说明文字(即?)

if (cfg.nodeInterpret) {

group.addShape('text', {

attrs: {

...labelCfg.style,

x: w / 2 - 12,

y: 19 - h / 2,

fontFamily: 'iconfont', // 对应css里面的font-family: "iconfont";

textAlign: 'right',

fill: '#999999',

text: '\ue715',

cursor: 'pointer',

lineHeight: 12,

fontSize: 11

},

name: 'interpret-icon',

})

}

// 下方实体节点内容

group.addShape('rect', {

attrs: {

x: 1 - w / 2,

y: 34 - h / 2,

width: w - 2,

height: h - 35,

fill: '#ffffff',

fontSize: 11,

radius: [0, 0, 6, 6]

},

})

// 可能有多行文字

for (let i = 0, l = content.length; i < l; i++) {

const attrs = {

...labelCfg.style,

text: content[i],

x: 0,

y: 34 - h / 2 + 14 + 14 * i,

textAlign: 'center',

fill: '#999999',

fontSize: 11,

lineHeight: 14

}

// 如果只有一行文字,设置y居中

if (l === 1) {

attrs.y = 17

}

const config = {

attrs

}

// 可点击节点样式

if (cfg.showType === '3') {

config.attrs.fill = '#3849B4'

config.attrs.cursor = 'pointer'

config.name = 'link-text'

} else {

config.name = 'collapse-icon'

}

group.addShape('text', config)

}

}

}

return keyShape;

},

update(cfg, item) {

const group = item.getContainer();

const icon = group.find((e) => e.get('name') === 'collapse-icon');

// 如果不展示展开/折叠,调整样式造成视觉隐藏

if (!cfg.hasChildren) {

icon.attr('lineWidth', 0)

icon.attr('cursor', 'auto')

const iconBox = group.find((e) => e.get('name') === 'marker-box')

iconBox.attr('width', 0)

iconBox.attr('stroke', '#ffffff')

} else {

icon.attr('symbol', cfg.collapsed ? EXPAND_ICON : COLLAPSE_ICON);

}

}

}, 'rect');

// 绘制连线

F6.registerEdge('flow-line', {

draw(cfg, group) {

const {

startPoint,

endPoint,

targetNode,

sourceNode,

style: {

stroke,

endArrow

}

} = cfg;

let path = null

// 是否向左

const isLeft = startPoint.x > endPoint.x

// 因为设置的连接点为容器的中心

const sourceNodeWidth = sourceNode._cfg.originStyle.width

startPoint.x = startPoint.x + (isLeft ? -sourceNodeWidth / 2 : sourceNodeWidth / 2)

const targetNodeWidth = targetNode._cfg.originStyle.width

endPoint.x = endPoint.x + (isLeft ? targetNodeWidth / 2 : -targetNodeWidth / 2)

startPoint.x = startPoint.x + (sourceNode._cfg.model.hasChildren ? (isLeft ? -16 : 16) : 0)

// 如果两个节点中心点纵向距离小于10直接绘一条线

if (Math.abs(startPoint.y - endPoint.y) < 8) {

path = [

['M', startPoint.x, startPoint.y],

['L', startPoint.x + (isLeft ? -10 : 10), startPoint.y],

['L', startPoint.x + (isLeft ? -10 : 10), endPoint.y],

['L', endPoint.x, endPoint.y]

]

} else {

// 判断弧线部分向上/下

const isTop = startPoint.y < endPoint.y

// 计算弧线开始/结束坐标

const arcStartX = startPoint.x + (isLeft ? -10 : 10)

const arcStartY = endPoint.y + (isTop ? -4 : 4)

const arcEndX = arcStartX + (isLeft ? -4 : 4)

const arcEndY = endPoint.y

// 取到弧线的控制点坐标(上下2个控制点)

const arcControlList = getArcPosition(arcStartX, arcStartY, arcEndX, arcEndY, 16)

const arcControlItem = isLeft ? (isTop ? arcControlList.bottom : arcControlList.top) :

(isTop ? arcControlList.top : arcControlList.bottom)

// 绘制路径

path = [

['M', startPoint.x, startPoint.y],

['L', arcStartX, startPoint.y],

['L', arcStartX, arcStartY],

['Q', arcControlItem.x, arcControlItem.y, arcEndX, arcEndY],

['L', endPoint.x, arcEndY]

];

}

const shape = group.addShape('path', {

attrs: {

stroke,

path,

endArrow

}

});

return shape;

}

});

// 实例化F6

this.graph = new F6.TreeGraph({

container: this.option.id,

width: this.treeDom.width,

height: this.treeDom.height,

animate: true,

// fitView: true, // 画布自适应

// fitCenter: true, //图将会被平移,图的中心将对齐到画布中心,但不缩放。优先级低于 fitView。

minZoom: 0.2,

maxZoom: 1.5,

linkCenter: true, //指定边是否连入节点的中心

modes: {

default: ['drag-canvas', 'zoom-canvas'],

},

defaultNode: {

type: 'icon-node',

anchorPoints: [

[0, 0.5],

[1, 0.5],

],

labelCfg: {

style: {

fill: '#3849B4',

fontSize: 12,

textAlign: 'center',

textBaseline: 'middle',

},

},

},

defaultEdge: {

type: 'flow-line',

style: defaultEdgeStyle,

},

layout: { // 节点自定义布局

type: 'compactBox',

direction: 'H',

getId(d) {

return d.id;

},

getHeight(d) {

if (d.level >= 3) {

const {

height

} = computeWidthHeight({

content: d.content

})

return height

} else {

return 30

}

},

getWidth(d) {

const {

level

} = d

if (level === 1) {

return 75

} else if (level === 2) {

return 75

} else {

let {

width

} = computeWidthHeight({

content: d.content

})

  if (d.hasChildren) {

width += 16

}

return width

}

},

getVGap() {

return 20;

},

getHGap(d) {

if (d.x > 0) {

return 60

} else {

return 25

}

}

},

})

// 监听点击事件

this.graph.on('node:tap', this.graphNodeClick);

this.graphReady = true

this.graph.data(this.treeData);

this.graph.render();

},

// 元素点击事件

async graphNodeClick(evt) {

const {

item,

target

} = evt;

// const targetType = target.get('type');

const name = target.get('name')

const model = item.getModel()

// 增加元素

if (model.hasChildren && name === 'collapse-icon') {

this.haneldCollapse(item)

} else if (name === 'link-text') {

this.handleLink(item)

//显示加载框

uni.showLoading({

title: '加载中',

mask: true

});

} else if (name === 'interpret-icon') {

this.showExplain = true

this.nodeInterpret = model.nodeInterpret

this.explainTitle = model.name

}

},

// 处理展开折叠

async haneldCollapse(item) {

const {

graph

} = this

const model = item.getModel()

let collapsed = model.collapsed

let hasChildren = model.hasChildren

if (model.collapsed && !model.isGetChildren) {

const id = model.id.split('_')[0];

try {

const res = await fetchGraphChildren(id, this.companyCode);

if (!res.data || res.data.length == 0) {

model.hasChildren = false;

} else {

const children = handleChildrenData(res.data, model.level + 1);

if (children.length) {

model.children = children;

} else {

model.hasChildren = false

}

}

} catch (err) {

model.hasChildren = false

}

model.isGetChildren = true;

}

collapsed = !collapsed;

model.collapsed = collapsed;

graph.updateChild(model, model.id);

const updateParams = {

collapsed

}

if (hasChildren !== model.hasChildren) {

updateParams.hasChildren = model.hasChildren

}

graph.updateItem(item, updateParams);

},

// 获取可点击实体表格信息

async handleLink(item) {

const model = item.getModel()

this.tableId = model.id.split('_')[0];

this.tableName = model.content.join('')

let params = {

id: this.tableId,

name: this.tableName

}

const res = await queryCompanyTable(params)

if (res.code == 0) {

this.tableTitle = res.data.name

this.newTime = res.data.latestTime

// this.contentsData = res.data.resultList

this.showLinkTable = true

res.data.titles.forEach(item => {

this.handleSortByColumn({

data: res.data.resultList,

order: 'asc',

property: item.field

})

let obj = {

label: item.fieldTitle,

key: item.field,

width: (40 + item.fieldTitle.length * 16) + 'px',

sort: true

}

// obj.label == ''

this.columnsData.push(obj)

})

//隐藏加载框

uni.hideLoading();

} else {

//隐藏加载框

uni.hideLoading();

uni.$u.toast(res.msg)

}

},

      // 点击表格第一列跳转当前页面  

rowclick(e) {

uni.redirectTo({

url: `/pages/look-company/companyDetail/companyDetail?title=${e.Stknme}&code=${e.Stkcd}`

})

},

// 排序要求''排在最底下

handleSortByColumn({

data,

order,

property

}) {

let dataList = data

if (order) {

// 是否是升序

const isAsc = order === 'asc'

let effectiveArr = data.filter((item) => item[property] !== '')

const invalidArr = data.filter((item) => item[property] === '')

effectiveArr = effectiveArr.sort((a, b) => {

if (a[property] > b[property]) {

return isAsc ? 1 : -1

} else {

return isAsc ? -1 : 1

}

})

dataList = effectiveArr.concat(invalidArr)

this.contentsData = dataList

}

},

// 关闭表格弹窗

closePopup() {

this.showLinkTable = false

},

// 关闭点击问号注释弹窗

canclePopup() {

this.showExplain = false

},

// 清除画布

handleClear() {

this.graph && this.graph.destroy()

this.graph = null

this.graphReady = false

},

},

beforeDestroy() {

this.handleClear()

},

}

</script>

 

<style lang="scss" scoped>

.page {

background: #ffffff;

overflow: hidden;

 

.title {

font-size: 32rpx;

text-align: center;

border-bottom: 1px solid #DCDEE3;

 

.nBack {

height: 100%;

display: flex;

align-items: center;

justify-content: center;

}

}

 

.tablePopup {

width: 100%;

background-color: #ffffff;

 

.tableHeader {

width: 100%;

height: 100rpx;

display: flex;

justify-content: space-between;

align-items: center;

border-bottom: 1px solid #DCDEE3;

 

.tableTitle {

font-size: 30rpx;

font-family: PingFang SC;

font-weight: bold;

color: #333333;

margin-left: 30rpx;

width: 80%;

height: 100rpx;

line-height: 100rpx;

white-space: nowrap;

}

 

.tableIcon {

width: 44rpx;

height: 44rpx;

background-color: #F4F4F4;

margin-right: 30rpx;

border-radius: 50%;

display: flex;

justify-content: center;

align-items: center;

 

.icon-shanchu1 {

font-size: 32rpx;

color: #C0C0C0;

 

}

}

}

 

.tableContent {

width: 100%;

height: 800rpx;

margin: 0rpx 0rpx 30rpx;

 

.time {

font-size: 22rpx;

height: 68rpx;

color: #999999;

margin-left: 30rpx;

line-height: 68rpx;

}

 

.lyyTable {

width: 100%;

height: calc(100% - 68rpx) !important;

overflow: hidden;

font-size: 24rpx;

}

}

}

 

.explainPopup {

width: 100%;

background-color: #fff;

 

.explainHeader {

width: 100%;

height: 100rpx;

display: flex;

justify-content: space-between;

align-items: center;

border-bottom: 1px solid #DCDEE3;

 

.explainTitle {

font-size: 30rpx;

font-family: PingFang SC;

font-weight: bold;

color: #333333;

margin-left: 30rpx;

width: 80%;

height: 100rpx;

line-height: 100rpx;

white-space: nowrap;

}

 

.explainIcon {

width: 44rpx;

height: 44rpx;

background-color: #F4F4F4;

margin-right: 30rpx;

border-radius: 50%;

display: flex;

justify-content: center;

align-items: center;

 

.icon-shanchu1 {

font-size: 32rpx;

color: #C0C0C0;

 

}

}

}

 

.explainContent {

padding: 38rpx 57rpx 38rpx 30rpx;

font-size: 24rpx;

color: #666666;

}

}

}

 

/deep/ .uni-table-th {

color: #3849B4;

background-color: #F7F8FB !important;

font-size: 24rpx;

}

 

/deep/ .uni-table-td {

font-size: 24rpx;

}

</style>

storage.js文件获取session方法:   // sessionStorage获取 export function getSession(key) {   return getObjectValue(sessionStorage.getItem(getMixKey(key))) } graphConfig.js文件公共方法:   /** 获取Path贝塞尔曲线控制点坐标  * @param {Number} startX 弧线起始x坐标  * @param {Number} startY 弧线起始Y坐标  * @param {Number} endX 弧线结束X坐标  * @param {Number} endY 弧线结束Y坐标  * @param {Number} angle 弧线角度  */ export function getArcPosition (startX, startY, endX, endY, angle) {   const PI = Math.PI;   // 两点间的x轴夹角弧度   const yOffset = endY - startY   const xOffset = endX - startX   let xAngle = Math.atan2(yOffset, xOffset);   // 转为角度   xAngle = 360 * xAngle / (2 * PI);   // 两点间的长度   const L = Math.sqrt(yOffset * yOffset + xOffset * xOffset);   // 计算等腰三角形斜边长度   const L2 = L / 2 / Math.cos(angle * 2 * PI / 360);   // 求第一个顶点坐标,位于下边   const top = {};   // 求第二个顶点坐标,位于上边   const bottom = {};   top.x = startX + Math.round(L2 * Math.cos((xAngle + angle) * 2 * PI / 360));   top.y = startY + Math.round(L2 * Math.sin((xAngle + angle) * 2 * PI / 360));   bottom.x = startX + Math.round(L2 * Math.cos((xAngle - angle) * 2 * PI / 360));   bottom.y = startY + Math.round(L2 * Math.sin((xAngle - angle) * 2 * PI / 360));   return { top, bottom } } // 折叠图标 const COLLAPSE_ICON = function COLLAPSE_ICON(x, y, r) { return [ ['M', x - r, y], ['L', x + r, y], ] }   // 展开图标 const EXPAND_ICON = function EXPAND_ICON(x, y, r) { return [ ['M', x - r, y], ['L', x + r, y], ['M', x, y - r], ['L', x, y + r] ] }   // 添加展开/折叠节点(canvas) export function addCollapseNode (group, w, cfg) {   const isLeft = cfg.x < 0   const x = isLeft ? -w / 2 - 11 : w / 2 - 1   const radius = isLeft ? [2, 0, 0, 2] : [0, 2, 2, 0]   group.addShape('rect', {     attrs: {       x,       y: -8,       width: 10,       height: 18,       stroke: '#E5E5E5',       fill: '#EEF2F8',       radius,     },     name: 'marker-box',   });   //+/-   group.addShape('marker', {     attrs: {       x: x + (isLeft ? 6 : 6),       y: 1,       r: 3,       stroke: '#A9ADB7',       lineWidth: 1,       cursor: 'pointer',       symbol: cfg.collapsed ? EXPAND_ICON : COLLAPSE_ICON     },     name: 'collapse-icon',   }) }   // 默认边和箭头样式 export const defaultEdgeStyle = {   stroke: '#3849B4',   endArrow: {     path: 'M 0,0 L 5,4 L 5,-4 Z',     lineWidth: 1,     fill: '#3849B4',   }, }     /**  * 计算节点宽度和高度  * @param {Array} content 要展示的实体内容  * @param {StrNumbering} vPadding 横向内部padding  * @param {Number} hPadding 纵向内部padding  * @param {Number} defaultWidth 默认宽度  * @param {Number} maxWidth  最大宽度  * @param {Number} defaultHeight  默认高度  * @param {Number} maxHeight  最大高度  * @param {Number} otherHeight  其他占用高度  * @returns  */ export function computeWidthHeight ({ content, vPadding = 12, hPadding = 16, defaultWidth = 200, maxWidth = 240, defaultHeight = 50, maxHeight = 160, otherHeight = 34 }) {   let rowNum = content.length   let width = defaultWidth   let defaultLength = Math.floor((width - 2 - vPadding) / 12)   let res = []   // 判断150宽度能否满足每一行数据要求   const isDissatisfy = content.some((item) => computeStrOccupyLength(item) > defaultLength)   // 如果不满足则切割字符串   if (isDissatisfy) {     width = maxWidth     defaultLength = Math.floor((width - 2 - vPadding) / 12)     for (let i = 0, l = content.length; i < l; i++) {       let item = content[i]       const matchItems = splitStr(item, defaultLength)       rowNum += (matchItems.length - 1)       res.push(...matchItems)     }   } else {     res = content   }   let height = Math.max(defaultHeight, rowNum * 14 + hPadding)   height = Math.min(height, maxHeight) + otherHeight   return {     width,     height,     content: res   } }   // 计算字符串占用长度 function computeStrOccupyLength (str) {   let num = 0   str.split('').forEach((s) => {     if (/[0123456789.?()-:]/.test(s)) {       num += 0.5     } else {       num += 1     }   })   return Math.ceil(num) }   // 根据数量截取字符串 function splitStr (str, maxNum) {   let num = maxNum   const res = []   let tmp = []   str.split('').forEach((s, i) => {     tmp.push(s)     if (/[0123456789.?()-:]/.test(s)) {       num -= 0.5     } else {       num -= 1     }     if (num < 1 || i === str.length - 1) {       res.push(tmp.join(''))       tmp = []       num = maxNum     }   })   return res }   // 处理添加子节点 export function handleChildrenData (data, level) {   const res = [];   data.forEach((item) => {     const { children, name, parentId, nodeInterpret } = item;     children.forEach((subItem, index) => {       let content = subItem.name;       if (content) {         const { showType, isChildren } = subItem;         const id = `${subItem.id}_${index}`;         content = content.split('\n').filter((item) => item);         res.push({           id,           parentId,           content,           name,           nodeInterpret,           showType,           level,           collapsed: true,           hasChildren: Boolean(isChildren),         });       }     });   });   return res; }  

表格插件文件:

去插件市场下载表格插件:

我这里改了排序,数据为空默认展示,列点击事件源代码,直接复制就好:

<template>

<view :style="{height}" :prop="ready" :change:prop="tableRender.documentReady">

<scroll-view scroll-x scroll-y class="container" @scrolltolower="scrolltolower">

<uni-table stripe border :loading="loading" style="min-height: 100%;">

<uni-tr id="lyy-thead" :class="headerFixed?'fixed-head':''" style="display: flex;">

<uni-th v-for="(item,index) in headers" :key="index" :width="item.width" align="center" :style="{

          display:item.hidden?'none':'flex',width:item.width,justifyContent: 'center',

                  left:columnFixed>0?fixedLeft(index):'unset',

                  right:columnFixed<0?fixedRight(index):'unset',

                  position:isFixed(index)?'sticky':'unset',

                  borderLeft:columnFixed<0&&isFixed(index)?'1px solid #f0f0f0':'unset',

                  zIndex:index<=columnFixed-1?999:99,

                  backgroundColor:'inherit'

          }">

<view @click="doSort(item)" style="display: flex;flex-direction: row;justify-content: center;">

<text :style="{lineHeight:'20px'}">{{item.label}}</text>

<view class="header-icon"

style="line-height:6px;display:flex;flex-direction:column;margin-left:5px;justify-content: center;"

v-if="item.sort">

<text class="iconfont icon-arrow-up"

:style="{color:lastSortItem===item.key&&sortWay=='asc'?'#3849B4':'#bcbcbc'}" />

 

<text class="iconfont icon-arrow-down"

:style="{color:lastSortItem===item.key&&sortWay=='desc'?'#3849B4':'#bcbcbc'}" />

</view>

 

</view>

</uni-th>

</uni-tr>

<!--<uni-tr v-if="headerFixed" :style="{height: theadHeight}">

            </uni-tr>

            <!-- <uni-td class="no_data" align="center">暂无数据</uni-td> -->

<view v-if="contents.length<1" class="no_data">暂无数据</view>

<uni-tr v-else v-for="(content,sindex) in sortContents" :key="sindex"

style="display:flex;table-layout: fixed;min-width: 100%;" @click.native="getRow(content)">

<!-- @click.native="rowClick(content)">-->

<uni-td v-for="(header,hindex) in headers" class="tableCell" :data-wrap="overflow" :key="hindex"

align="center" :style="{display:header.hidden?'none':'flex',textAlign:'center',width:header.width,

                  left:columnFixed>0?fixedLeft(hindex):'unset',

                  right:columnFixed<0?fixedRight(hindex):'unset',

  justifyContent:'center',

  alignItems:'center',

                  position:isFixed(hindex)?'sticky':'unset',

                  borderLeft:columnFixed<0&&isFixed(hindex)?'1px solid #f0f0f0':'unset',

                  zIndex:hindex<=columnFixed-1?9:'unset',

                  backgroundColor:'inherit',

  overflow:'hidden'}">

<template v-if="header.format!==undefined">

<lyy-progress

v-if="header.format.type==='progress'&&!isNaN(parseFloat(content[header.key]))"

:percent="content[header.key].toFixed(2)" show-info round></lyy-progress>

<view v-else-if="header.format.type==='html'" v-html="content[header.key]"></view>

<text v-else>{{content[header.key]}}</text>

</template>

<text v-else>{{content[header.key]}}</text>

</uni-td>

</uni-tr>

<uni-tr v-if="contents.length>0&&totalRow.length>0" style="min-width: 100%;display: flex;" @click.native="getRow(content)">

<uni-td v-for="(header,index) in headers" :key="Math.random()" align="center" :style="{textAlign: 'center',display:header.hidden?'none':'table-cell',width:header.width,

                  left:columnFixed>0?fixedLeft(index):'unset',

                  right:columnFixed<0?fixedRight(index):'unset',

                  position:isFixed(index)?'sticky':'unset',

                  borderLeft:columnFixed<0&&isFixed(index)?'1px solid #f0f0f0':'unset',

                  zIndex:index<=columnFixed-1?9:'unset',

                  backgroundColor:'inherit'}">

<text v-if="index==0">合计</text>

<view v-else>

<!--<progress v-if="typeof header.format!=='undefined'&& header.format.type==='progress'" :percent="renderTotalRow(header)" :show-info="true" stroke-width="10" :active="true"></progress>-->

<lyy-progress

v-if="typeof header.format!=='undefined'&& header.format.type==='progress'&&!isNaN(parseFloat(renderTotalRow(header)))"

:percent="renderTotalRow(header)" :show-info="true" round></lyy-progress>

<text v-else>{{ renderTotalRow(header)}}</text>

</view>

</uni-td>

</uni-tr>

</uni-table>

<!-- <uni-load-more v-show="showLoadMore" :status="loadMore"></uni-load-more> -->

</scroll-view>

</view>

</template>

 

<script>

import lyyProgress from './lyy-progress'

/**

* lyyTable ver1.3.8

* @description lyyTable表格组件 ver1.3.8

*/

export default {

name: "lyyTable",

components: {

lyyProgress

},

data() {

return {

ready: 1,

lastSortItem: '', //上一次排序列

sortWay: 'none', //默认无排序

sortIndex: 0,

sortContents: [], //排序时的表格内容

footContent: {},

scrollHeight: '',

theadHeight: ''

}

},

props: {

//表格高度 1.3.8

// #ifdef H5

height: {

type: String,

default: 'calc(100vh - 44px - env(safe-area-inset-top))'

},

// #endif

// #ifndef H5

height: {

type: String,

default: '100vh'

},

// #endif

overflow: {

type: String,

default: 'nowrap',

validator: val => ['wrap', 'nowrap'].indexOf(val) > -1

},

//显示加载

loading: {

type: Boolean,

default: false

},

//上拉加载文字,参考uni-load-more

loadMore: {

type: String,

default: 'more'

},

//是否显示上拉加载组件

showLoadMore: {

type: Boolean,

default: false

},

//固定表头

headerFixed: {

type: Boolean,

default: false

},

//固定首列 ver1.3.3弃用

/*firstColumnFixed: {

    type: Boolean,

    default: false

},*/

//固定列数 ver1.3.3新增

columnFixed: {

type: Number,

default: 0

},

//排序方式

sortWays: {

type: Array,

default: () => ['none', 'asc', 'desc']

},

//数据为空时的占位符

emptyString: {

type: String,

default: '-'

},

//表头

headers: {

type: Array,

default: () => [],

},

//表格数据

contents: {

type: Array,

default: () => []

},

//合计列

totalRow: {

type: Array,

default: () => []

}

},

mounted() {

//uni.setStorageSync('contents',this.contents)

this.sortContents = JSON.parse(JSON.stringify(this.contents))

this.renderContents()

this.createTotalRow()

if (this.overflow == 'nowrap') {

this.ready = this.headers.length * this.contents.length

}

//ver 1.2.0 修复 uni-table width 问题

/*this.$nextTick(() => {

    console.log('abc',this.$refs)

    const query = uni.createSelectorQuery().in(this)

    query.select('.uni-table').boundingClientRect(dom=>{

        console.log(123456,dom)

    }).exec()

    this.$refs['uni-table'].removeAttribute('style')

})*/

//ver 1.2.0 新增 固定表头

/*if (this.headerFixed) {

    /*var wHeight = document.body.clientHeight

    var tablePoseY = document.getElementById('lyy-tbody').getBoundingClientRect().y

    document.getElementById('lyy-tbody').style.height = wHeight - tablePoseY + 'px'

    const query = uni.createSelectorQuery().in(this)

 

    query.select('#lyy-thead').boundingClientRect(dom => {

        console.log(dom)

        this.theadHeight = dom.height + 'px'

    }).exec()

}*/

},

watch: {

contents: {

//console.log(value)

handler(value) {

this.sortContents = JSON.parse(JSON.stringify(value))

console.log('len--------', value.length)

this.renderContents()

this.createTotalRow()

this.lastSortItem = ''

this.sortWay = 'none'

for (var header of this.headers) {

this.renderTotalRow(header)

}

//this.$forceUpdate()

this.$nextTick(function() {

if (this.overflow == 'nowrap') {

this.ready = this.headers.length * this.contents.length

}

})

},

deep: true

 

},

//监听排序变化

sortChange(value) {

var that = this

var contents = JSON.parse(JSON.stringify(that.contents))

switch (value.sortWay) {

case 'none':

that.sortContents = contents

this.renderContents()

break

case 'asc': //正序

that.sortContents = that.sortContents.sort(function(a, b) {

//需要排序的列为数字时直接计算

if (!isNaN(Number(a[that.lastSortItem])) && !isNaN(Number(b[that

.lastSortItem]))) {

if (a[that.lastSortItem] == '' || b[that.lastSortItem] == ''){

return b[that.lastSortItem] - a[that.lastSortItem]

}else {

return a[that.lastSortItem] - b[that.lastSortItem]

}

 

}

//非数字转为ASCII排序(1.3.7弃用)

//1.3.7更改排序方式,使中文排序更符合中国习惯

else {

//(1.3.7弃用) return a[that.lastSortItem].charCodeAt() - b[that.lastSortItem].charCodeAt()

return a[that.lastSortItem].localeCompare(b[that.lastSortItem], 'zh-cn')

}

})

break

case 'desc': //倒序

that.sortContents = that.sortContents.sort(function(a, b) {

if (!isNaN(Number(a[that.lastSortItem])) && !isNaN(Number(b[that

.lastSortItem]))) {

return b[that.lastSortItem] - a[that.lastSortItem]

}

//非数字转为ASCII排序(1.3.7弃用)

//1.3.7更改排序方式,使中文排序更符合中国习惯

else {

//(1.3.7弃用) return b[that.lastSortItem].charCodeAt() - a[that.lastSortItem].charCodeAt()

return b[that.lastSortItem].localeCompare(a[that.lastSortItem], 'zh-cn')

}

})

break

}

that.$forceUpdate()

}

},

computed: {

//将排序方式、上次排序列作为一个整体进行监听,不然会出现切换排序列不排序的现象

sortChange() {

var {

sortWay,

lastSortItem

} = this

return {

sortWay,

lastSortItem

}

}

},

methods: {

//点击排序表头时存储上次排序列名,并循环切换排序方式

doSort(item) {

if (item.sort) {

if (this.lastSortItem !== item.key) {

this.lastSortItem = item.key

this.sortIndex = 0

this.sortIndex++

this.sortWay = this.sortWays[this.sortIndex]

} else {

if (this.sortIndex < 2) {

this.sortIndex++

this.sortWay = this.sortWays[this.sortIndex]

} else {

this.sortIndex = 0

this.sortWay = this.sortWays[0]

}

}

}

},

// 表格行点击事件

getRow(data) {

this.$emit("row-click",data)

},

//表格内容渲染

renderContents() {

const headers = this.headers

//防止修改穿透

var contents = JSON.parse(JSON.stringify(this.contents))

//var contents=uni.getStorageSync('contents')

let sortContents = JSON.parse(JSON.stringify(this.sortContents))

var newArr = []

var result = ''

sortContents.forEach(function(content, index) {

var item = content

headers.forEach(function(header) {

//字符类型格式化

if (typeof header.format !== 'undefined' && (header.format.type === 'string' ||

header.format.type === 'html')) {

var template = header.format.template

var keys = header.format.keys

//console.log(typeof template)

if (typeof template === 'function') {

var arg = []

keys.forEach((el, i) => {

arg.push(contents[index][el])

})

result = template(arg)

//console.log(result)

} else {

keys.forEach((el, i) => {

var value = contents[index][el]

var reg = new RegExp('\\{' + i + '}', 'g')

template = template.replace(reg, value)

})

result = template

}

item[header.key] = result

}

//计算类型格式化

else if (typeof header.format !== 'undefined' && (header.format.type ===

'compute' || header.format.type === 'progress')) {

//console.log(header.format.template)

var temp = header.format.template

var keys = header.format.keys

//1.3.7 使计算列支持function

if (typeof temp === 'function') {

var arg = []

keys.forEach((el, i) => {

arg.push(contents[index][el])

})

item[header.key] = temp(arg)

//console.log(result)

} else {

keys.forEach((el, i) => {

var reg = new RegExp('\\{' + i + '}', 'g')

temp = temp.replace(reg, contents[index][el])

})

//console.log(temp)

item[header.key] = eval(temp)

//this.sortContents[index][header.key]=result

}

}

})

newArr.push(item)

})

this.sortContents = newArr

},

createTotalRow() {

if (this.totalRow.length > 0 && this.sortContents[0] !== undefined) {

/*var obj = {...this.contents[0]}

console.log(obj)

for (var i in obj) {

    this.footContent[i] = obj[i]

}*/

this.footContent = JSON.parse(JSON.stringify(this.sortContents[0]))

for (var i in this.footContent) {

var result = 0

if (this.sortContents.length > 0) {

for (var j in this.sortContents) {

result += parseFloat(this.sortContents[j][i]) || 0

}

}

this.footContent[i] = result

}

}

},

//合计列渲染

renderTotalRow(header) {

var content = JSON.parse(JSON.stringify(this.footContent))

var result = this.emptyString

if (this.totalRow.indexOf(header.key) > -1) {

if (typeof header.format !== 'undefined' && header.format.type === 'progress') {

var temp = header.format.template

var keys = header.format.keys

for (var index in keys) {

var reg = new RegExp('\\{' + index + '}', 'g')

temp = temp.replace(reg, content[keys[index]])

}

result = eval(temp)

result = isNaN(result) ? 0 : result.toFixed(2)

} else {

if (content[header.key] != null && !isNaN(content[header.key])) {

result = content[header.key]

}

}

}

return result

},

//行点击事件

rowClick(data) {

this.$emit('rowClick', data)

},

//上拉加载事件

scrolltolower(e) {

if (e.detail.direction == 'bottom') {

this.$emit('onPullup')

}

},

//固定列left计算

fixedLeft(index) {

var headers = this.headers.filter(item => !item.hidden)

var left = 'calc(1px'

for (var i = 1; i < index + 1; i++) {

left += ' + ' + headers[i - 1].width

}

left += ')'

return left

},

//v1.3.5

//固定列right计算

fixedRight(index) {

var headers = this.headers.filter(item => !item.hidden)

var columnFixed = Math.abs(this.columnFixed)

if (index >= headers.length + this.columnFixed) {

var right = 'calc(1px'

for (var i = index; i < headers.length - 1; i++) {

if (index + 1 == headers.length) {

break

} else {

right += ' + ' + headers[i + 1].width

}

}

right += ')'

return right

} else {

return 'unset'

}

},

//v1.3.5

isFixed(index) {

if (this.columnFixed > 0) {

return index <= this.columnFixed - 1

} else if (this.columnFixed < 0) {

var headers = this.headers.filter(item => !item.hidden)

return index >= headers.length + this.columnFixed

} else {

return false

}

}

}

}

</script>

<script module="tableRender" lang="renderjs">

function test(a, b) {

alert(a, b)

}

export default {

methods: {

documentReady(newValue, oldValue, ownerInstance, instance) {

//alert(`${newValue},${oldValue}`)

console.log(newValue, oldValue)

if (newValue > oldValue) {

var cells = document.querySelectorAll('.tableCell')

 

function changeWrap(e) {

console.log(1)

var wrap = e.currentTarget.dataset.wrap

e.currentTarget.dataset.wrap = wrap == 'nowrap' ? 'unset' : 'nowrap'

}

 

function fun(e) {

changeWrap(e)

}

// for (var i = oldValue - 1; i < cells.length; i++) {

// cells[i].addEventListener('click', fun)

// }

}

}

}

}

</script>

<style>

/deep/.uni-table-loading {

display: none !important;

}

</style>

 

<style scoped>

@import './css/iconfont.css';

 

.container {

width: 100vw;

height: 100%;

border-bottom: 1px solid #f0f0f0;

}

 

.uni-table-scroll {

overflow: unset !important;

border-top: none;

}

 

.no_data {

position: fixed;

width: 750upx;

background-color: #FFF;

height: 50px;

text-align: center;

line-height: 50px;

}

 

#lyy-thead {

/*min-width: 750upx;*/

display: table;

background-color: #FFF;

}

 

[data-wrap='unset'] {

white-space: unset !important;

display: flex !important;

}

 

[data-wrap='nowrap'] {

white-space: nowrap !important;

}

[data-wrap='nowrap'] uni-text{

width: 100%;

text-overflow: ellipsis;

overflow: hidden;

}

 

.fixed-head {

position: sticky;

top: 0;

z-index: 99;

border-top: 1px solid #f0f0f0;

}

 

/*修复滑动时偏移1px问题*/

/*.table--border {

border-top: none;

border-left: none;

}*/

 

.uni-table-tr {

background-color: #FFF;

}

</style>

排序字体图标需要缩小,在css文件中iconfont.css文件里面改字体图标样式即可: .iconfont {   font-family: "iconfont" !important;   font-size: 12px !important;   transform: scale(0.7); // 图标缩小,根据需求自己定义缩小值,因浏览器默认字体是12px,设置即可小于12px   font-style: normal;   -webkit-font-smoothing: antialiased;   -moz-osx-font-smoothing: grayscale; }  

标签:uniapp,插件,const,item,uView,content,width,var,return
来源: https://www.cnblogs.com/xiaofang234/p/16408159.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有