商城后台管理系统 02 添加规格参数-动态表单

1,不能弹

2,只有在点击了添加才能启用

动态增减表单项

除了在 Form 组件上一次性传递所有的验证规则外还可以在单个的表单域上传递属性的验证规则
复制代码
<el-form :model="dynamicValidateForm" ref="dynamicValidateForm" label-width="100px" class="demo-dynamic">
  <el-form-item
    prop="email"
    label="邮箱"
    :rules="[
      { required: true, message: '请输入邮箱地址', trigger: 'blur' },
      { type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }
    ]"
  >
    <el-input v-model="dynamicValidateForm.email"></el-input>
  </el-form-item>
  <el-form-item
    v-for="(domain, index) in dynamicValidateForm.domains"
    :label="'域名' + index"
    :key="domain.key"
    :prop="'domains.' + index + '.value'"
    :rules="{
      required: true, message: '域名不能为空', trigger: 'blur'
    }"
  >
    <el-input v-model="domain.value"></el-input><el-button @click.prevent="removeDomain(domain)">删除</el-button>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="submitForm('dynamicValidateForm')">提交</el-button>
    <el-button @click="addDomain">新增域名</el-button>
    <el-button @click="resetForm('dynamicValidateForm')">重置</el-button>
  </el-form-item>
</el-form>
<script>
  export default {
    data() {
      return {
        dynamicValidateForm: {
          domains: [{
            value: ''
          }],
          email: ''
        }
      };
    },
    methods: {
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            alert('submit!');
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      },
      removeDomain(item) {
        var index = this.dynamicValidateForm.domains.indexOf(item)
        if (index !== -1) {
          this.dynamicValidateForm.domains.splice(index, 1)
        }
      },
      addDomain() {
        this.dynamicValidateForm.domains.push({
          value: '',
          key: Date.now()
        });
      }
    }
  }
</script>
禁用状态
按钮不可用状态。
你可以使用disabled属性来定义按钮是否可用,它接受一个Boolean值。
复制代码
<el-row>
  <el-button disabled>默认按钮</el-button>
  <el-button type="primary" disabled>主要按钮</el-button>
  <el-button type="success" disabled>成功按钮</el-button>
  <el-button type="info" disabled>信息按钮</el-button>
  <el-button type="warning" disabled>警告按钮</el-button>
  <el-button type="danger" disabled>危险按钮</el-button>
</el-row>

<el-row>
  <el-button plain disabled>朴素按钮</el-button>
  <el-button type="primary" plain disabled>主要按钮</el-button>
  <el-button type="success" plain disabled>成功按钮</el-button>
  <el-button type="info" plain disabled>信息按钮</el-button>
  <el-button type="warning" plain disabled>警告按钮</el-button>
  <el-button type="danger" plain disabled>危险按钮</el-button>
</el-row>
添加规格参数-动态表单 实现代码如下
复制代码
1, src/views/Params/ParamsInfo/ParamsDialog.vue
<template>
	<el-dialog title="添加规格参数" :visible.sync="dialogVisible" width="50%" :before-close="handleClose">
		<!-- 显示规格类目 -->
		<TreeGoods @sendTreeData="sendTreeData" />
		<span slot="footer" class="dialog-footer">
			<el-button @click="dialogVisible = false">取 消</el-button>
			<el-button type="primary" @click="innerVisible=true" :disabled="isDisabled">确定并添加分组</el-button>
		</span>
		<!-- 二级弹框--嵌套 -->
		<el-dialog width="45%" title="商品规格参数配置" :visible.sync="innerVisible" append-to-body>
			<div class="title">当前选中的商品: {{ treeData.name }}</div>
			<el-button type="primary" @click="addDomain">新增规格列表</el-button>

			<hr />

			<!-- 动态增减表单项  start-->
			<el-form :model="dynamicValidateForm" ref="dynamicValidateForm" label-width="100px" class="demo-dynamic">
				<!-- <el-form-item prop="email" label="邮箱" :rules="[
			      { required: true, message: '请输入邮箱地址', trigger: 'blur' },
			      { type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }
			    ]">
					<el-input v-model="dynamicValidateForm.email"></el-input>
				</el-form-item> -->
				<el-form-item v-for="(domain, index) in dynamicValidateForm.domains" :label="'域名' + index"
					:key="domain.key" :prop="'domains.' + index + '.value'" :rules="{
			      required: true, message: '域名不能为空', trigger: 'blur'
			    }">
					<el-input v-model="domain.value"></el-input><el-button
						@click.prevent="removeDomain(domain)">删除</el-button>
				</el-form-item>
				<el-form-item>
					<el-button type="primary" @click="submitForm('dynamicValidateForm')">提交</el-button>
					<!-- <el-button @click="addDomain">新增规格列表</el-button> -->
					<el-button @click="resetForm('dynamicValidateForm')">重置</el-button>
				</el-form-item>
			</el-form>
			<!-- 动态增减表单项  end-->
			<span slot="footer" class="dialog-footer">
				<el-button @click="dialogVisible = false">取 消</el-button>
				<el-button type="primary" @click="innerVisible=false">确 定</el-button>
			</span>
		</el-dialog>
	</el-dialog>
</template>

<script>
	import TreeGoods from '@/views/Goods/GoodsList/TreeGoods.vue'
	export default {
		components: {
			TreeGoods
		},
		data() {
			return {
				dialogVisible: false,
				innerVisible: false,
				isDisabled: true, // 默认是不可以点击
				treeData: {}, // 接收 tree 数据
				dynamicValidateForm: { // 动态表单数据
					domains: [{
						value: ''
					}],
					// email: ''
				},
			};
		},
		methods: {
			// 获取点击 tree 的数据
			sendTreeData(val) {
				console.log('获取 tree 的数据', val);
				this.treeData = val;
				this.isDisabled = false;
			},
			handleClose(done) {
				this.$confirm('确认关闭?')
					.then(_ => {
						done();
					})
					.catch(_ => {});
			},
			submitForm(formName) {
				this.$refs[formName].validate((valid) => {
					if (valid) {
						alert('submit!');
					} else {
						console.log('error submit!!');
						return false;
					}
				});
			},
			resetForm(formName) {
				this.$refs[formName].resetFields();
			},
			removeDomain(item) {
				var index = this.dynamicValidateForm.domains.indexOf(item)
				if (index !== -1) {
					this.dynamicValidateForm.domains.splice(index, 1)
				}
			},
			addDomain() {
				this.dynamicValidateForm.domains.push({
					value: '',
					key: Date.now()
				});
			}
		}
	};
</script>

<style>
</style>







2, src/views/Params/ParamsInfo/Specification.vue
<template>
	<div class="params">
		<!-- 二级菜单 -->
		<!-- 1, 目录位置 -->
		<div class="nav">
			<el-breadcrumb separator="/">
				<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
				<el-breadcrumb-item><a href="/">规格管理</a></el-breadcrumb-item>
				<el-breadcrumb-item :to="{ path: '/params' }">规格参数</el-breadcrumb-item>
				<el-breadcrumb-item :to="{ path: '/params/specifications' }">规格包装</el-breadcrumb-item>
			</el-breadcrumb>
		</div>
		<!-- 2, 搜索框 -->
		<div class="header">
			<el-input v-model="inp" />
			<el-button type="primary">查看</el-button>
			<el-button type="primary" @click="showParams">添加</el-button>
		</div>

		<!-- 3, 表格区域 展示视图数据 -->
		<el-table :data="tableData" class="my-table">
			<el-table-column prop="itemCatId" label="规格参数ID" width="120">
			</el-table-column>
			<el-table-column prop="id" label="类目ID" width="120">
			</el-table-column>
			<el-table-column prop="specsName" label="规格名称" width="120">
			</el-table-column>
			<el-table-column prop="paramsData" label="规格参数" show-overflow-tooltip>
			</el-table-column>

			<!-- <el-table-column prop="date" label="日期" width="180">
			</el-table-column>
			<el-table-column prop="name" label="姓名" width="180">
			</el-table-column>
			<el-table-column prop="address" label="地址">
			</el-table-column>
			<el-table-column prop="email" label="邮件">
			</el-table-column> -->
			<el-table-column label="操作" width="280">
				<template slot-scope="scope">
					<el-button type="info" size="mini">查看</el-button>
					<el-button type="primary" size="mini" @click="handleEdit(scope.$index, scope.row)"
						icon="el-icon-edit">编辑</el-button>
					<el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)"
						icon="el-icon-delete">删除</el-button>
				</template>
			</el-table-column>
		</el-table>

		<!-- 4, 分页展示  接收页码- -->
		<MyPagination :total="total" :pageSize="pageSize" @changePage="changePage" :currentPage="currentPage" />

		<!-- 5, 弹框 -->
		<ParamsDialog ref="dialog" />
	</div>
</template>

<script>
	import MyPagination from '@/components/MyPagination.vue';
	import ParamsDialog from '@/views/Params/ParamsInfo/ParamsDialog.vue'
	export default {
		components: {
			MyPagination,
			ParamsDialog
		},
		data() {
			return {
				inp: '', // 输入框
				tableData: [],
				total: 10,
				pageSize: 1,
				currentPage: 1,

				// tableData: [{
				// 	id: '2016-05-02',
				// 	itemCatId: '王小虎',
				// 	specsName: '上海市普陀区金沙江路 1518 弄',
				// 	paramsData: '2570650096@qq.com'
				// }, {
				// 	id: '2016-05-02',
				// 	itemCatId: '王小虎',
				// 	specsName: '上海市普陀区金沙江路 1518 弄',
				// 	paramsData: '2570650096@qq.com'
				// }, {
				// 	id: '2016-05-02',
				// 	itemCatId: '王小虎',
				// 	specsName: '上海市普陀区金沙江路 1518 弄',
				// 	paramsData: '2570650096@qq.com'
				// }, {
				// 	id: '2016-05-02',
				// 	itemCatId: '王小虎',
				// 	specsName: '上海市普陀区金沙江路 1518 弄',
				// 	paramsData: '2570650096@qq.com'
				// }], // 
			}
		},
		methods: {
			// 点击显示弹框--配置规格参数
			showParams() {
				this.$refs.dialog.dialogVisible = true;
			},
			// 点击分页 切换
			changePage(num) {
				this.http(num);
			},
			// 获取规格参数列表

			http(page) {
				this.$api.getParams({
						page
					})
					.then(res => {
						console.log(res.data);
						if (res.data.status === 200) {
							this.tableData = res.data.data;
							// 获取分页
							this.total = res.data.total;
							this.pageSize = res.data.pageSize;
						}
					})
			}
		},
		created() {
			this.http(1)
		}
	}
</script>

<style lang="less" scoped>
	.params {
		margin: 10px;
	}

	.nav {
		padding: 10px;
	}

	.header {
		display: flex;
		background: #fff;
		padding: 10px;
		border: 1px solid #eee;

		button {
			margin-left: 20px;
		}
	}

	.my-table {
		margin: 10px auto;
	}
</style>








3, src/views/Goods/GoodsList/TreeGoods.vue
<template>
	<!-- props="props" 渲染的数据 
		配置选项:
		label: 'name', // 指定节点标签为节点对象的某个属性值
		children: 'zones', // 指定子树为节点对象的某个属性值
		isLeaf: 'leaf' // 指定节点是否为叶子节点,仅在指定了 lazy 属性的情况下生效
	:load="loadNode"  // 加载子树数据的方法,仅当 lazy 属性为true 时生效 自动执行函数 -- 异步请求数据
	lazy			 // 是否懒加载子节点,需与 load 方法结合使用
	show-checkbox>	 // 节点是否可被选择  选择框
	accordion		 // 是否每次只打开一个同级树节点展开
	node-click		 // 节点被点击时的回调  共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。
	
	 -->
	<el-tree :props="props" :load="loadNode" lazy accordion @node-click="nodeClick">
	</el-tree>
</template>

<script>
	export default {
		data() {
			return {
				props: {
					label: 'name', // 指定节点标签为节点对象的某个属性值
					children: 'zones', // 指定子树为节点对象的某个属性值
					isLeaf: 'leaf' // 指定节点是否为叶子节点,仅在指定了 lazy 属性的情况下生效
				},
			};
		},
		methods: {
			// 点击 tree 获取数据
			nodeClick(data, node) {
				console.log(data, node);
				// 传递数据给父组件
				this.$emit('sendTreeData', data)
			},
			loadNode(node, resolve) { // resolve() 成功的返回数据结果
				// console.log('load--自动执行', node);
				if (node.level === 0) {
					// 进入页面 获取第一层的tree数据
					// this.$api.getSelectCategory()
					// 	.then(res => {
					// 		console.log('一级tree', res.data);
					// 		return resolve(res.data.result);
					// 	})
					return resolve([{
						name: '家用电器'
					}, {
						name: '手机/运营商/数码'
					}, {
						name: '电脑/办公'
					}, {
						name: '家具/家居'
					}]);
				}
				// 合并 所有级别(level)大于等1
				// if (node.level >= 1) { // 合并
				// 	// 请求当前的点击的 tree 下面的数据
				// 	this.$api.getSelectCategory({
				// 			id: node.data.cid
				// 		})
				// 		.then(res => {
				// 			console.log('二级tree', res.data);
				// 			if (res.data.status === 200) {
				// 				return resolve(res.data.result);
				// 			} else {
				// 				return resolve([])
				// 			}
				// 		})
				// }
				if (node.level == 1) {
					// 请求当前的点击的 tree 下面的数据
					// this.$api.getSelectCategory({ // 动态从数据库中拿数据
					// 		id: node.data.cid
					// 	})
					// 	.then(res => {
					// 		console.log('二级tree', res.data);
					// 		if (res.data.status === 200) {
					// 			return resolve(res.data.result);
					// 		} else {
					// 			return resolve([])
					// 		}
					// 	})
					return resolve([{
						name: '电视'
					}, {
						name: '空调'
					}, {
						name: '洗衣机'
					}, {
						name: '冰箱'
					}], [{
						name: '手机通讯'
					}, {
						name: '运营商'
					}, {
						name: '摄影'
					}, {
						name: '摄像'
					}], [{
						name: '电脑整机'
					}, {
						name: '电脑配件'
					}, {
						name: '外设产品'
					}, {
						name: '游戏设备'
					}], [{
						name: '厨具'
					}, {
						name: '家纺'
					}, {
						name: '灯具'
					}, {
						name: '家具'
					}]);
				}
				// if (node.level == 2) {
				// 	// 请求当前的点击的 tree 下面的数据
				// 	this.$api.getSelectCategory({
				// 			id: node.data.cid;
				// 		})
				// 		.then(res => {
				// 			console.log('三级tree', res.data);
				// 			if (res.data.status === 200) {
				// 				return resolve(res.data.result);
				// 			} else {
				// 				return resolve([])
				// 			}
				// 		})
				// 	return resolve([{
				// 		name: '超薄电视'
				// 	}, {
				// 		name: '全屏电视'
				// 	}]);
				// }
			}
		}
	};
</script>

<style>
</style>







4, src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Layout from '@/views/Layout/index.vue'
import Home from '@/views/Home/index.vue'
import Login from '@/views/Login/Login.vue'

// 异步
const Goods = () => import('../views/Goods/GoodsList/Goods.vue')
const Params = () => import('../views/Params/Params.vue')
const Specifications = () => import('../views/Params/ParamsInfo/Specifications.vue')
const Advert = () => import('../views/Advert/Advert.vue')
const My = () => import('../views/My/My.vue')
const Logistics = () => import('../views/Logistics/Logistics.vue')
const Order = () => import('../views/Order/index.vue')
const OrderList = () => import('../views/Order/OrderList/index.vue')
const OrderBack = () => import('../views/Order/OrderBack/index.vue')

// 子级路由
const AddGoods = () => import('../views/Goods/GoodsList/AddGoods.vue')


Vue.use(VueRouter)

const routes = [{
		path: '',
		component: Layout,
		// 路由的元信息
		meta: {
			isLogin: false
		},
		children: [{
			path: '/',
			name: 'Home',
			component: Home
		}, {
			path: '/goods',
			name: 'Goods',
			component: Goods
		}, {
			path: '/add-goods',
			name: 'AddGoods',
			component: AddGoods
		}, {
			path: '/params',
			name: 'Params',
			component: Params,
			redirect: '/params/specifications',
			children: [{
				path: 'specifications',
				name: 'Specifications',
				component: Specifications
			}]
		}, {
			path: '/advert',
			name: 'Advert',
			component: Advert
		}, {
			path: '/my',
			name: 'My',
			component: My
		}, {
			path: '/logistics',
			name: 'Logistics',
			component: Logistics
		}, {
			path: '/order',
			name: 'Order',
			component: Order,
			redirect: '/order/order-list',
			children: [{
				path: 'order-list',
				component: OrderList
			}, {
				path: 'order-back',
				component: OrderBack
			}]
		}]
	},
	{
		path: '/login',
		name: 'Login',
		component: Login,
	}
]

const router = new VueRouter({
	mode: 'history',
	base: process.env.BASE_URL,
	routes
})



export default router
相关推荐
Alair‎6 小时前
103React数据处理
开发语言·前端·javascript
黛色正浓6 小时前
【React18+TypeScript】React 18 for Beginners
javascript·react.js·typescript
Zhi.C.Yue6 小时前
React 状态更新中的双缓冲机制、优先级调度
前端·javascript·react.js
nnnnna6 小时前
插槽(Slots)(完整详细版)
前端·vue.js
hellsing6 小时前
UniPush 2.0 实战指南:工单提醒与多厂商通道配置
前端·javascript
king王一帅6 小时前
告别 AI 输出的重复解析:正常 markdown 解析渲染也能提速 2-10 倍以上
前端·javascript·ai编程
dudke6 小时前
js的reduce详解
开发语言·javascript·ecmascript
代码or搬砖6 小时前
ES6新增的新特性以及用法
前端·javascript·es6
小番茄夫斯基6 小时前
Monorepo 架构:现代软件开发的代码管理革命
前端·javascript·架构