vue自定义listView
2019-10-23 本文已影响0人
HCL黄
222.gif
1、这里注意
2、
3、
这里注意
第一步打开HBuilderX,新建项目命名为textApp
A2796E2A-3CC9-43D5-B2F3-43878867F091.png第二步新建目录命名为components
1848999C-304D-42F3-A895-DDC51053CE38.png第三步新建vue文件命名为listView
D77F012E-08B9-4A1C-8AED-F515381BE8B2.png第四步在listView.vue文件编辑代码
<template>
<view>
<view class="content">
<view class="centerV">
<view v-for="(item, index) in lists" :key='index' class="centerV-item" :class="index!=0?'centerV-itemT':''">
<view v-for="(subItem, subIndex) in lists[index]" :key='subIndex' class="centerV-subItem" @click="didClickItem(subItem)">
<!-- 上边内容 -->
<view class="subItem-topV">
<view class="subItem-left">
<image class="subLeft-img" :src="subItem.icon"></image>
<text class="subLeft-title">{{subItem.title}}</text>
<!-- 0:#AAAAAA 12px 1:#FFAC1C 14px -->
<text class="subLeft-subTitle" :class="subItem.subTitleType==1?'subLeft-subTitle1' :''">{{subItem.subTitle}}</text>
</view>
<view class="subItem-right">
<!-- rightType = 0:普通样式 1:输入框样式 -->
<view v-if="subItem.rightType==0" class="subRight-normalV">
<text v-if="subItem.detail.length==0" class="subRight-title">{{subItem.detailPlaceholder}}</text>
<text v-else class="subRight-title1">{{subItem.detail}}</text>
<!-- 0:蓝色下箭头 1:灰色右箭头 2:问好图标 -->
<image class="subRight-img" :class="subItem.rightIconType==0?'blueDown-img' :subItem.rightIconType==1?'grayArrow-img' :subItem.rightIconType==2?'blueMark-img' :''"
:src="subItem.rightIcon"></image>
</view>
<!-- rightType = 0:普通样式 1:输入框样式 -->
<view v-else-if="subItem.rightType==1" class="subRight-inputV">
<!-- <textarea @input="textareaInput" class="cnt-textarea textareaFont" placeholder="请输入内容" placeholder-style="color:#999999"/> -->
<input :id="subItem.title" @input="inputChange" class="inputV-input" :type="subItem.inputType" :placeholder="subItem.inputPlaceholder"
placeholder-style="color:#999999" />
<text class="inputV-text">{{subItem.inputUnit}}</text>
</view>
</view>
</view>
<!-- 下边分割线 -->
<view v-if="subIndex!=lists[index].length-1" class="subItem-btmV"></view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
pLists: {
typs: Array, // 类型数组
default: [], // 默认值
required: true, // 是否必传
}
},
mounted() {
this.lists = this.pLists; // 内部接收
},
data() {
return {
lists: [] // 定义属性
}
},
methods: {
// 为detail赋值
setDetailValue: function(string, value) {
var datas = this.lists;
for (let i = 0; i < datas.length; i++) {
var item = datas[i];
for (let j = 0; j < item.length; j++) {
var subItem = item[j];
var title = subItem.title;
if (title == string) {
subItem.detail = value;
}
}
}
},
// 为subTitle赋值
setSubTitleValue: function(string, value) {
var datas = this.lists;
for (let i = 0; i < datas.length; i++) {
var item = datas[i];
for (let j = 0; j < item.length; j++) {
var subItem = item[j];
var title = subItem.title;
if (title == string) {
subItem.subTitle = value;
}
}
}
},
// 点击每一行
didClickItem: function(subItem) {
var title = subItem.title;
this.$emit('didClickItem', title);
},
// 监听输入框改变
inputChange: function(event) {
console.log(event.detail.value);
console.log(event.currentTarget.id);
var value = event.detail.value;
var ID = event.currentTarget.id;
var datas = this.lists;
for (let i = 0; i < datas.length; i++) {
var item = datas[i];
for (let j = 0; j < item.length; j++) {
var subItem = item[j];
var title = subItem.title;
if(title == ID) {
subItem.detail = value;
}
}
}
}
},
}
</script>
1、这里注意export default
里的props
对外属性定义,主要是让外面传对应的数据进来
2、didClickItem
方法里的this.$emit
是子组件来触发父组件的方法,这里的this是父组件
3、this.$emit('didClickItem', title);
括号里是方法名和参数
第五步在index.vue文件编辑代码
<template>
<view>
<view class="content">
<view class="topV">
<image class="topV-img" src="../../static/fd_008.png"></image>
<text class="topV-text">我是顶部广告信息</text>
</view>
<!-- 中间列表 -->
<tableView class="centerV" ref="child" :pLists="lists" @didClickItem="didClickItem"></tableView>
<view class="bottomV">
<!-- 合作服务协议 -->
<view class="btm-agreeV">
<view class="agreeV-left" @click="didClickAgree">
<image class="aLeft-img" :src="isAgree?'../../static/fd_012.png':'../../static/fd_011.png'"></image>
<text class="aLeft-text">阅读并同意</text>
</view>
<view class="agreeV-right" @click="didClickService">《合作服务协议》</view>
</view>
<!-- 发布按钮 -->
<view class="btm-releaseV" @click="didClickBtn">
<text class="releaseV-text">发布</text>
</view>
</view>
</view>
<view style="height: 94upx;"></view>
<view class="phoneV" @click="didClickPhone">
<text class="phoneV-normalText">如有其他疑问请咨询客服:</text>
<text class="phoneV-highlightedText">{{phone}}</text>
</view>
</view>
</template>
这里注意ref="child"
是将child
指向tableView这个组件,后面就可以使用this.$refs.child
来调用组件里面的方法了
<script>
import tableView from "@/components/listView.vue"
export default {
data() {
return {
isAgree: false, // 是否勾选合作服务协议
phone: '123456', // 客服电话
lists: [
[{
icon: '../../static/fd_001.png',
title: '第一组第一行',
subTitle: '',
subTitleType: 0, // 0:#AAAAAA 12px 1:#FFAC1C 14px
detailPlaceholder: '右边占位说明',
detail: '',
rightIcon: '../../static/fd_013.png',
rightIconType: 0, // 0:蓝色下箭头 1:灰色右箭头 2:问好图标
rightType: 0, // 0:普通样式 1:输入框样式
inputType: '', // 当rightType==1时,该值有效。text文本,number数字,idcard身份证 digit带小数点的数字键盘
inputPlaceholder: '', // 当rightType==1时,该值有效。
inputUnit: '', // 当rightType==1时,该值有效。
},
{
icon: '../../static/fd_002.png',
title: '第一组第二行',
subTitle: '',
subTitleType: 0, // 0:#AAAAAA 12px 1:#FFAC1C 14px
detailPlaceholder: '右边占位说明',
detail: '',
rightIcon: '../../static/fd_010.png',
rightIconType: 1, // 0:蓝色下箭头 1:灰色右箭头 2:问好图标
rightType: 0, // 0:普通样式 1:输入框样式
inputType: '', // 当rightType==1时,该值有效。text文本,number数字,idcard身份证 digit带小数点的数字键盘
inputPlaceholder: '', // 当rightType==1时,该值有效。
inputUnit: '', // 当rightType==1时,该值有效。
}
],
[{
icon: '../../static/fd_003.png',
title: '第二组第一行',
subTitle: '',
subTitleType: 0, // 0:#AAAAAA 12px 1:#FFAC1C 14px
detailPlaceholder: '右边占位说明',
detail: '',
rightIcon: '../../static/fd_010.png',
rightIconType: 1, // 0:蓝色下箭头 1:灰色右箭头 2:问好图标
rightType: 0, // 0:普通样式 1:输入框样式
inputType: '', // 当rightType==1时,该值有效。text文本,number数字,idcard身份证 digit带小数点的数字键盘
inputPlaceholder: '', // 当rightType==1时,该值有效。
inputUnit: '', // 当rightType==1时,该值有效。
},
{
icon: '../../static/fd_004.png',
title: '第二组第二行',
subTitle: '(非必填)',
subTitleType: 0, // 0:#AAAAAA 12px 1:#FFAC1C 14px
detailPlaceholder: '右边占位说明',
detail: '',
rightIcon: '../../static/fd_010.png',
rightIconType: 1, // 0:蓝色下箭头 1:灰色右箭头 2:问好图标
rightType: 0, // 0:普通样式 1:输入框样式
inputType: '', // 当rightType==1时,该值有效。text文本,number数字,idcard身份证 digit带小数点的数字键盘
inputPlaceholder: '', // 当rightType==1时,该值有效。
inputUnit: '', // 当rightType==1时,该值有效。
},
{
icon: '../../static/fd_005.png',
title: '第二组第三行',
subTitle: '(另外描述)',
subTitleType: 0, // 0:#AAAAAA 12px 1:#FFAC1C 14px
detailPlaceholder: '右边占位说明',
detail: '',
rightIcon: '../../static/fd_013.png',
rightIconType: 0, // 0:蓝色下箭头 1:灰色右箭头 2:问好图标
rightType: 0, // 0:普通样式 1:输入框样式
inputType: '', // 当rightType==1时,该值有效。text文本,number数字,idcard身份证 digit带小数点的数字键盘
inputPlaceholder: '', // 当rightType==1时,该值有效。
inputUnit: '', // 当rightType==1时,该值有效。
}
],
[{
icon: '../../static/fd_006.png',
title: '第三组第一行',
subTitle: '200元',
subTitleType: 1, // 0:#AAAAAA 12px 1:#FFAC1C 14px
detailPlaceholder: '右边占位说明',
detail: '',
rightIcon: '../../static/fd_009.png',
rightIconType: 2, // 0:蓝色下箭头 1:灰色右箭头 2:问好图标
rightType: 0, // 0:普通样式 1:输入框样式
inputType: '', // 当rightType==1时,该值有效。text文本,number数字,idcard身份证 digit带小数点的数字键盘
inputPlaceholder: '', // 当rightType==1时,该值有效。
inputUnit: '', // 当rightType==1时,该值有效。
}],
[
{
icon: '../../static/fd_006.png',
title: '第四组第一行',
subTitle: '',
subTitleType: 0,// 0:#AAAAAA 12px 1:#FFAC1C 14px
detailPlaceholder: '',
detail: '',
rightIcon: '',
rightIconType: 0, // 0:蓝色下箭头 1:灰色右箭头 2:问好图标
rightType: 1, // 0:普通样式 1:输入框样式
inputType: 'number', // 当rightType==1时,该值有效。text文本,number数字,idcard身份证 digit带小数点的数字键盘
inputPlaceholder: '输入框占位说明', // 当rightType==1时,该值有效。
inputUnit: '(元)', // 当rightType==1时,该值有效。
}
]
]
}
},
onLoad() {
},
methods: {
// 点击勾选按钮
didClickAgree: function() {
this.isAgree = !this.isAgree;
},
// 点击合作服务协议
didClickService: function() {
console.log('点击合作服务协议');
},
// 点击发布按钮
didClickBtn: function() {
var message = '';
var datas = this.lists;
for (let i = 0; i < datas.length; i++) {
var item = datas[i];
if (message || message.length != 0) break;
for (let j = 0; j < item.length; j++) {
var subItem = item[j];
if (!subItem.detail || subItem.detail.length == 0) {
var title = subItem.title;
if (title == '第一组第一行') {
message = '请选择第一组第一行的内容'
} else if (title == '第一组第二行') {
message = '请选择第一组第二行的内容'
} else if (title == '第二组第一行') {
message = '请选择第二组第一行的内容'
} else if (title == '第二组第三行') {
message = '请选择第二组第三行的内容'
} else if(title == '第四组第一行') {
message = '请在第四组第一行输入内容'
}
// 跳出循环
break;
}
}
}
if (message.length != 0) {
uni.showToast({
title: message,
icon: 'none',
duration: 2000
})
return;
}
if (!this.isAgree) {
uni.showToast({
title: '请阅读并同意《合作服务协议》',
icon: 'none',
duration: 2000
})
return;
}
console.log('可以发布了');
},
// 点击客服电话
didClickPhone: function() {
console.log('点击客服电话');
},
// 点击每一行
didClickItem: function(title) {
if (title == '第一组第一行') {
console.log('点击第一组第一行');
// 获取到的是组件实例,可以使用组件的所有方法
this.$refs.child.setDetailValue('第一组第一行', '第一组第一行内容')
} else if (title == '第一组第二行') {
this.$refs.child.setDetailValue('第一组第二行', '第一组第二行内容')
} else if (title == '第二组第一行') {
this.$refs.child.setDetailValue('第二组第一行', '第二组第一行内容')
} else if (title == '第二组第二行') {
this.$refs.child.setDetailValue('第二组第二行', '第二组第二行内容')
} else if (title == '第二组第三行') {
this.$refs.child.setDetailValue('第二组第三行', '第二组第三行内容')
} else if (title == '第三组第一行') {
this.$refs.child.setDetailValue('第三组第一行', '第三组第一行内容')
}
},
},
components: {
tableView
}
}
</script>
这里需要注意的是
- 导入
import tableView from "@/components/listView.vue"
,并且在components
定义为tableView
也可以自己命名自己喜欢的,然后这样才能在<template>
里使用<tableView></tableView>
- 属性
lists
的数据可以根据自己需要进行修改,注释都有说明 -
didClickBtn
方法检测内容是否填写采用的是比较笨的方式,后续有时间了再来优化 -
didClickItem
方法就是前面我们在子组件里定义的,有个title
参数传过来,然后我们就可以使用this.$refs.child.setDetailValue
对子组件进行赋值操作
下面布局就不多说了,都是简单的flex布局
<style>
page {
background-color: rgb(241, 241, 241);
}
.content {}
/* 最顶部内容 */
.topV {
background-color: #FFFFFF;
height: 80upx;
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
}
.topV-img {
margin-left: 30upx;
margin-right: 10upx;
width: 32upx;
height: 32upx;
}
.topV-text {
color: #FF9500;
font-family: PingFang-SC-Medium;
font-size: 28upx;
}
/* 中间内容 */
.centerV {
margin-top: 30upx;
}
/* 底部内容 */
.bottomV {
display: flex;
flex-direction: column;
margin-top: 30upx;
}
/* 服务协议 */
.btm-agreeV {
display: flex;
flex-direction: row;
height: 34upx;
}
.agreeV-left {
display: flex;
flex-direction: row;
align-items: center;
}
.aLeft-img {
width: 28upx;
height: 28upx;
margin-right: 20upx;
margin-left: 30upx;
}
.aLeft-text {
font-family: PingFang-SC-Medium;
font-size: 24upx;
color: #787878;
}
.agreeV-right {
font-family: PingFang-SC-Medium;
font-size: 26upx;
color: #3ABBFF;
}
/* 发布按钮 */
.btm-releaseV {
margin-top: 60upx;
margin-left: 30upx;
margin-right: 30upx;
background-color: #3ABBFF;
height: 88upx;
border-radius: 10upx;
display: flex;
align-items: center;
justify-content: center;
}
.releaseV-text {
font-family: PingFang-SC-Medium;
color: #FFFFFF;
font-size: 34upx;
}
/* 客服电话 */
.phoneV {
display: flex;
justify-content: center;
position: fixed;
left: 0;
right: 0;
bottom: 0;
line-height: 94upx;
background-color: rgb(241, 241, 241);
z-index: 999;
}
.phoneV-normalText {
font-family: PingFang-SC-Medium;
color: #999999;
font-size: 28upx;
}
.phoneV-highlightedText {
font-family: PingFang-SC-Medium;
color: #3ABBFF;
font-size: 28upx;
}
</style>