第一章 uniapp实现兼容多端的树状族谱关系图,创建可缩放移动区域

完成效果"

uniapp树状族谱关系图

本章效果:

1.设置可移动缩放区域

template:

html 复制代码
<view class="tree cx-fex cx-fex-itemsc cx-fex-c">
<movable-area class="movable-area" v-show="treeData.length"
			:style="{'paddingBottom': `calc(${systemInfo.safeAreaInsetBottom}px + 136rpx)`, 'box-sizing': 'border-box', 'width': `${windowSizeComputed.width}`, 'height': `calc(${windowSizeComputed.height}px - ${systemInfo.safeAreaInsetBottom}px - 136rpx)`}">
			<movable-view :x="left" :y="top" direction="all" scale :scale-value="scaleNum" scale-min="0.01"
				class="movable-view" :out-of-bounds="false" :style="{ 'width': `fit-content`, 'height': `fit-content` }"
				@scale="movableViewScale" @change="movableViewScale">
				<view class="content">
					<tree-item ref="treeItem" :tree-data="treeData" :tree-first="true" :pageType="pageType" init />
				</view>
			</movable-view>

		</movable-area>
		<view class="addBtn" v-show="!treeData.length" @click="addAncestors">
			+ 点击马上添加族人
		</view>
<bottom-button @touch="pageSubmit">
			{{ pageType == 'preview' ? '下载族谱' : '发布' }}
		</bottom-button>

</view>

script:

javascript 复制代码
computed:{
    ...mapState(['systemInfo']),
    //屏幕宽高
			windowSizeComputed: {
				get() {
					let {
						width,
						height
					} = this.x_y
					let {
						systemInfo
					} = this
					return {
						width: width || '100%',
						height: height || systemInfo.windowHeight
					}
				},
				set(width, height) {
					this.x_y = {
						width,
						height
					}
				}
			},
},
data:{
    //族谱数据
	treeData: [
		// {
		// 	name: "章龙操",
		// 	sex: 1,
		// 	address: "江西省抚州市",
		// 	desc: 1,
		// 	type: ['刘配氏', '章配氏'],
		// 	child: [],
		// 	checked: true,
		// 	addressCopy: ['江西省', '抚州市', '临川区']
		// },
	],
}

css:

html 复制代码
@mixin formStyle {
		.form {
			height: calc(100% - 200rpx);

			// 家庭成员类型
			.family-item {
				width: 231rpx;
				height: 71rpx;
				line-height: 71rpx;
				text-align: center;
				background: #FFFFFF;
				border-radius: 10rpx;
				border: 1px solid #B98C52;
				margin-bottom: 20rpx;

				&.lastChild {
					width: 100%;
				}
			}

			.for-item {
				height: 25%;
				margin-bottom: 20rpx;

				.label {
					width: 120rpx;

					.required {
						color: red;
					}
				}

				.input {
					width: calc(100% - 120rpx);
					height: 70rpx;
					line-height: 70rpx;

					&.textarea {
						height: auto;
					}

					&.text {
						padding: 0 5px;
						box-sizing: border-box;
						border: 1px solid rgba(231, 231, 231, 1);
						border-radius: 10rpx;
						font-size: 12px;
					}

					.man {
						margin-right: 90rpx;
					}

					.icon {
						width: 24rpx;
						height: 24rpx;
						border-radius: 50%;
						border: 1px solid rgba(231, 231, 231, 1);
						position: relative;
						margin-right: 13rpx;
					}

					.icon.active {
						width: 24rpx;
						height: 24rpx;
						border-radius: 50%;
						border: 1px solid #B98C52;
						position: relative;
						margin-right: 13rpx;

						.iconContent {
							width: 14rpx;
							height: 14rpx;
							border-radius: 50%;
							background: #B98C52;
						}
					}

					.ReleaseAreaText {
						width: 100%;
						height: 240rpx !important;
						max-height: 240rpx;
						border: 1px solid rgba(231, 231, 231, 1);
						border-radius: 10rpx;
						padding: 5px;
						box-sizing: border-box;
					}

					&.desc {
						& /deep/ .uni-select {
							padding: 0 5px;
							box-sizing: border-box;
						}
					}

					&.spouse {
						display: grid;
						grid-template-columns: repeat(3, 1fr);
						gap: 2.5%;

						.item {
							width: 100%;
							padding: 12rpx 0;
							line-height: 1;
							border-radius: 10rpx;
							margin: 8rpx 0;
							text-align: center;
							position: relative;

							&.active {
								background: rgba(179, 136, 80, .1);
								color: #895C22;
							}

							&.off {
								background-color: #f8f8f8;
							}

							.zlc-bianji {
								position: absolute;
								top: -6rpx;
								right: -6rpx;
								font-size: 28rpx;
							}
						}
					}

					.timePicker {
						width: calc(100% - 30rpx);
					}
				}
			}
		}
	}

	@mixin headerStyle {
		.header {
			width: 100%;
			height: 100rpx;
			line-height: 100rpx;

			.title {
				font-weight: 700;
			}

			.icon {
				font-size: 40rpx;
			}
		}
	}

	@mixin footerStyle {
		.footer {
			height: 100rpx;
			line-height: 100rpx;

			.btn {
				width: 280rpx;
				height: 80rpx;
				text-align: center;
				line-height: 80rpx;
				background: #B98D55;
				border-radius: 40rpx;
				color: #fff;
			}
		}
	}

	.tree {
		width: 100%;
		height: 100%;
		background-color: #f8f8f8;
		background-size: 0.5cm 0.5cm;
		background-image:
			linear-gradient(to right, rgba(231, 231, 231, 1) 1px, transparent 1px),
			linear-gradient(to bottom, rgba(231, 231, 231, 1) 1px, transparent 1px);
		// padding-bottom: calc(env(safe-area-inset-bottom) + 116rpx);
		// padding-bottom: calc(constant(safe-area-inset-bottom) + 116rpx);
		box-sizing: border-box;
		overflow: hidden;
		position: relative;

		.movable-area-add {
			width: 70rpx;
			right: 0;
			position: fixed;
			pointer-events: none;
			z-index: 999;

			.movable-view-add {
				width: fit-content;
				height: fit-content;
				pointer-events: auto;

				.addShow {
					width: 90rpx;
					height: 90rpx;
					line-height: 90rpx;
					text-align: center;
					background: #FFFFFF;
					box-shadow: 0rpx 2rpx 13rpx 0rpx rgba(0, 0, 0, 0.05);
					border-radius: 50%;

					font-weight: 400;
					font-size: 26rpx;
					color: #895C22;
				}


			}
		}

		.addBtn {
			width: 352rpx;
			height: 152rpx;
			line-height: 152rpx;
			text-align: center;
			background: #FFFFFF;
			box-shadow: 0rpx 2rpx 13rpx 0rpx rgba(0, 0, 0, 0.05);
			border-radius: 10rpx;
			border: 2px solid #B98C52;
		}

		.main {
			width: 570rpx;
			height: fit-content;
			background: #FFFFFF;
			border-radius: 20rpx;
			padding: 0 34rpx 40rpx;
			box-sizing: border-box;

			&.deletePersonalPopup_main {
				height: 350rpx;
			}

			&.loadPicture_main {
				width: 570rpx;
				height: 1000rpx;

				image {
					width: 100%;
					height: 100%;
				}
			}
			
			&.datePicker{
				width: 100%;
				height: 500rpx;
				
				.header{
					width: 100%;
					height: 100rpx;
					line-height: 100rpx;
					display: flex;
					flex-direction: row;
					align-items: center;
					justify-content: space-between;
					
					.cancel{
						color: #895C22;
					}
					.confirm{
						color: #895C22;
					}
					.tabs{
						width: 300rpx;
						height: 50rpx;
						display: flex;
						flex-direction: row;
						align-items: center;
						.pre{
							width: 50%;
							border-radius: 20rpx 0 0 20rpx;
							text-align: center;
							line-height: 50rpx;
							border-top: 1px solid #895C22;
							border-bottom: 1px solid #895C22;
							border-left: 1px solid #895C22;
							color: #895C22;
							&.on{
								color: #FFFFFF;
								background-color: #895C22;
							}
						}
						.next{
							width: 50%;
							border-radius: 0 20rpx 20rpx 0;
							text-align: center;
							line-height: 50rpx;
							border: 1px solid #895C22;
							color: #895C22;
							&.on{
								color: #FFFFFF;
								background-color: #895C22;
							}
						}
						
						
					}
				}
				.content{
					width: 100%;
					height: 400rpx;
					display: flex;
					flex-direction: row;
					align-items: center;
					justify-content: center;
					.BC{
						display: flex;
						flex-direction: row;
						align-items: center;
						justify-content: center;
						.ipt{
							width: 100rpx;
							height: 50rpx;
							border: 1px solid #895C22;
							border-radius: 10rpx;
							&.month{
								margin-left: 20rpx;
							}
						}
						.label{
							&.month{
								margin-right: 20rpx;
							}
						}
					}
				}
			}

			@include headerStyle();
			@include formStyle();
			@include footerStyle();

			&.ReleasePopup {
				height: fit-content;

				.form {
					.for-item {
						height: fit-content;
						margin-bottom: 20rpx;

						.label {
							width: 140rpx;
						}

						.input {
							width: calc(100% - 140rpx);

							& /deep/ input {
								width: 100%;
								text-align: left;
							}

							&.noBorder {
								border: none;
								height: fit-content;

							}

							&.birthday {
								.zlcIcon {
									font-size: 40rpx;
								}


							}

							& /deep/ .uni-select {
								padding: 0 5px;
								box-sizing: border-box;
							}
						}

						.genealogy_image {
							.imgBox {
								width: fit-content;
								height: fit-content;
								position: relative;

								.cx-icon {
									width: 30rpx;
									height: 30rpx;
									font-size: 30rpx;
									position: absolute;
									right: -9rpx;
									top: -30rpx;
									color: #B98C52;
									// background: #fff;
									border-radius: 50%;

									&::before {
										width: 100%;
										height: 100%;
										border-radius: 50%;
										background: #FFFFFF;
										top: -30rpx !important;
									}
								}

								.item {
									width: 150rpx;
									height: 150rpx;
									border-radius: 20rpx;
									box-shadow: 0rpx 0rpx 10rpx rgba(0, 0, 0, 0.5);
								}
							}

						}
					}
				}
			}
		}

		.content {
			width: fit-content;
			height: fit-content;
		}

		.loadGenealogy {
			position: absolute;
			left: -500%;
			top: -500%;
			width: fit-content;
			height: fit-content;
		}

	}

2.在app.vue获取设备信息

复制代码
<script>
	export default {
		onLaunch: function() {
			console.log('App Launch');
			this.getPhoneHeight();
		},
		onShow: function() {
			console.log('App Show')
		},
		onHide: function() {
			console.log('App Hide')
		},
		methods: {
			getPhoneHeight() { //获取高度
				let that = this;
				let systemInfo = {};
				uni.getSystemInfo({
					success: function(res) {
						if (res.platform == "ios") {
							systemInfo.toBar = 44;
						} else if (res.platform == "android") {
							systemInfo.toBar = 48;
						} else {
							systemInfo.toBar = 44;
						}
						if (res.safeArea.top > 40) {
							systemInfo.isIphoneX = true;
						}
						systemInfo.windowWidth = res.screenWidth; //windowWidth
						systemInfo.windowHeight = res.screenHeight; //windowHeight
						systemInfo.statusBarHeight = res.statusBarHeight; //状态栏的高度
						systemInfo.heightBlank = Number(systemInfo.statusBarHeight) + Number(systemInfo.toBar);
						systemInfo.safeAreaInsetBottom = res.safeAreaInsets.bottom //ios底部安全距离
						that.$store.commit('SET_SYSTEMINFO', systemInfo);
					},
				});
			},
		}
	}
</script>

<style>
	@import url('@/static/css/iconfont.css');

	/*每个页面公共css */
	page {
		background-color: #f8f8f8;
		--default-color: #895C22;
		width: 100%;
		height: 100%;
	}

	:not(not) {
		box-sizing: border-box
	}
</style>

3.vuex仓库代码

复制代码
import {
	stat
} from 'fs';
import Vue from 'vue';
import VueX from 'vuex';
Vue.use(VueX);


const store = new VueX.Store({
	state: {
		systemInfo: null,
	},
	mutations: {
		
		SET_SYSTEMINFO(state, payload) {
			state.systemInfo = payload;
			state.systemInfo.pageMarginTop = state.systemInfo.statusBarHeight * 2 + 90;
		},
	},
})
export default store
相关推荐
然我9 分钟前
react-router-dom 完全指南:从零实现动态路由与嵌套布局
前端·react.js·面试
一_个前端17 分钟前
Vite项目中SVG同步转换成Image对象
前端
202618 分钟前
12. npm version方法总结
前端·javascript·vue.js
用户876128290737419 分钟前
mapboxgl中对popup弹窗添加事件
前端·vue.js
帅夫帅夫20 分钟前
JavaScript继承探秘:从原型链到ES6 Class
前端·javascript
a别念m20 分钟前
HTML5 离线存储
前端·html·html5
goldenocean1 小时前
React之旅-06 Ref
前端·react.js·前端框架
小赖同学啊1 小时前
将Blender、Three.js与Cesium集成构建物联网3D可视化系统
javascript·物联网·blender
子林super1 小时前
【非标】es屏蔽中心扩容协调节点
前端
前端拿破轮1 小时前
刷了这么久LeetCode了,挑战一道hard。。。
前端·javascript·面试