场景:
选择商品展示效果可直观化——穿梭框形式
效果

elementui plus 穿梭框表格 vue 穿梭框_elementUI

<!--活动设置-满减活动列表-新增页面reduce_settings-->
<template>
  <div id="reduce_settings">
    <div style="font-size: 12px;">
      <el-breadcrumb separator-class="el-icon-arrow-right">
        <el-breadcrumb-item :to="{ path: '/CurriculumNav/Comment' }" style="font-size: 12px"><i class="el-icon-s-home" style="color: #15A8FD;font-size: 14px;"></i> 首页</el-breadcrumb-item>
        <el-breadcrumb-item :to="{ path: '/ShopNav/activity_settings' }" style="font-size: 12px">活动设置</el-breadcrumb-item>
        <el-breadcrumb-item :to="{ path: '/ShopNav/activity_reduce' }" style="font-size: 12px">满减活动列表</el-breadcrumb-item>
        <el-breadcrumb-item style="font-size: 12px">编辑</el-breadcrumb-item>
      </el-breadcrumb>
    </div>
    <div class="markingInfobox" v-loading="domeloding">
      <p class="titleP"><span class="titleinfoP">基本信息</span><span class="bluespan"></span></p>
      <div class="formBox">
        <p>活动标题<span class="redspan">*</span>
          <el-input v-model="Title" placeholder="请输入标题" clearable style="width: 300px;"></el-input>
        </p>
        <p>选择商品<span class="redspan">*</span>
          <el-input v-model="goodsName" placeholder="请选择活动商品" disabled style="width: 300px;"></el-input>
          <el-button type="primary" @click="reduceGoodsVisible = true">选择商品</el-button>
          <span style="font-size: 14px;color: #B2B2B2;">不选择商品即默认全部商品满减</span>
        </p>
        <p>活动价格<span class="redspan">*</span>
          满
          <el-input type="number" v-model="reach_amount" placeholder="请输入金额" clearable style="width: 150px;"></el-input>
          减
          <el-input type="number" v-model="reduce_amount" placeholder="请输入金额" clearable style="width: 150px;"></el-input>
        </p>
        <p>活动时间<span class="redspan">*</span>
          <el-date-picker
            v-model="Start"
            type="datetime"
            format="yyyy-MM-dd HH:mm:ss"
            placeholder="请选择开始时间">
          </el-date-picker>
          <span class="timecenter">至</span>
          <el-date-picker
            v-model="End"
            type="datetime"
            format="yyyy-MM-dd HH:mm:ss"
            placeholder="请选择结束时间">
          </el-date-picker>
        </p>
        <p>满减次数<span class="redspan">*</span>
          <el-input  type="number" v-model="Reduce_Num" placeholder="默认不限数量" clearable style="width: 300px;"></el-input>
          <span style="font-size: 14px;color: #B2B2B2;">限制每个订单可购买几组活动商品</span>
        </p>
        <p>展示时间<span class="redspan">*</span>
          <span style="margin-right: 10px;">是否立即展示活动商品信息</span>
          <el-radio v-model="Valid" label="0">是</el-radio>
          <el-radio v-model="Valid" label="1">否</el-radio>
        </p>

      </div>
      <div class="submitmarking">
        <el-button v-if="seckillIDBool" type="primary" @click="editSeckillSubmit">提交编辑保存</el-button>
        <el-button v-else type="primary" @click="seckillSubmit">提交保存</el-button>
      </div>
    </div>

    <!--选择活动商品弹框-->
    <el-dialog
      title="选择活动商品"
      :visible.sync="reduceGoodsVisible"
      width="1000px">
      <div class="TransferBox">
        <!--左边待选择-->
        <div class="SourceBox">
          <!--筛选-->
          <div>
            <el-input placeholder="请输入内容" v-model="searchKey" class="input-with-select">
              <el-select v-model="classification" slot="prepend" placeholder="请选择" style="width: 45px">
                <el-option
                  v-for="item in classificationoptions"
                  :key="item.id"
                  :label="item.title"
                  :value="item.id">
                </el-option>
              </el-select>
              <el-button slot="append" icon="el-icon-search" @click="searchClickFUn"></el-button>
            </el-input>

          </div>
          <el-table
            :border="true"
            height="500"
            v-loading="goodesLoding"
            ref="multipleTable"
            :data="shopOptions"
            tooltip-effect="dark"
            style="width: 100%"
            @selection-change="handleSelectionChange">
            <el-table-column
              type="selection"
              width="46">
            </el-table-column>
            <el-table-column
              prop="title"
              label="商品"
              width="200">
            </el-table-column>
            <el-table-column
              prop="spec_text"
              label="规格">
            </el-table-column>
          </el-table>
        </div>
        <!--按钮-->
        <div class="buttonCentenr">
          <div class="posiBox">
            <p><el-button  @click="deleteGoodesLeft"><i class="el-icon-arrow-left"></i></el-button></p>
            <p><el-button type="primary" @click="AddGoodesRight"><i class="el-icon-arrow-right" ></i></el-button></p>
          </div>

        </div>
        <!--右边已选择-->
        <div class="TargetBox">
          <div class="titletableBox">
            <p>已选择</p>
          </div>
          <el-table
            :border="true"
            height="500"
            :data="TargetShopOptions"
            tooltip-effect="dark"
            @selection-change="deleteChange"
            style="width: 100%">
            <el-table-column
              type="selection"
              width="55">
            </el-table-column>
            <el-table-column
              prop="title"
              label="商品"
              width="200">
            </el-table-column>
            <el-table-column
              prop="spec_text"
              label="规格">
            </el-table-column>
          </el-table>
        </div>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="reduceGoodsVisible = false">取 消</el-button>
        <el-button type="primary" @click="yesshopName">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>


```cpp

<script>
  import allApi from '../../assets/js/request.js'
  export default {
    data () {
      return {
        domeloding:false,
        Title:'',//标题
        reach_amount:'',//满【金额】
        reduce_amount:'',//减【金额】
        Start:'',//开始时间
        End:'',//结束时间
        Reduce_Num:'',//满减次数
        Valid:'1',//是否展示
        goodsName:'',//展示的活动商品名称集合

        seckillIDBool:false,//是否为编辑

        /*商品选择弹框数据*/
        reduceGoodsVisible:false,//选择商品弹框
        goodesLoding:true,//商品加载
        shopOptions: [],//商品名称规格数组数据
        multipleSelection: [],//全部商品多选选中
        TargetMultipleSelection: [],//已选商品多选选中
        classificationoptions: [],//商品分类
        classification: '',//商品分类选中ID
        searchKey:'',//商品搜索输入框
        TargetShopOptions:[],//已选择商品数据

        addgoodsListArr:[],//确认传递保存商品数据列表

      }
    },
    components:{

    },
    computed: {

    },
    created(){
      /*判断是否为编辑秒杀活动,是:路由携带SecKillID*/
      if(this.$route.query.seckillID!==undefined){
        this.editReduceInfoCreated();//获取信息
        this.seckillIDBool=true
      }
      /*获取商品列表*/
      let self=this;
      this.axios.post(allApi.GetGoodsInfo,{PageIndex: 1, PageSize: 10000}
      ).then(function (res) {
        if(res.data.IsSuccess){
          self.goodesLoding=false;
            self.shopOptions=res.data.Result.Data
        }else{
          self.goodesLoding=false;
          self.$message.error("请求失败");
        }
      }).catch(function (res) {
        console.log(res)
      });
      /*获取商品分类*/
      this.axios.post(allApi.GetEntityCategory,{}
      ).then(function (res) {
        if(res.data.IsSuccess){
          self.classificationoptions=res.data.Result
        }else{
          self.$message.error("请求失败");
        }
      }).catch(function (res) {
        console.log(res)
      });

    },
    methods: {

      /*左边全部商品数据选中监听*/
      handleSelectionChange(val) {
        this.multipleSelection = val;
      },
      /*右边边商品数据选中监听*/
      deleteChange(val){
        this.TargetMultipleSelection=val;
      },
      /*穿梭框到右边*/
      AddGoodesRight(){
          this.TargetShopOptions=this.multipleSelection;
      },
      /*穿梭到左边*/
      deleteGoodesLeft(){
        let TargetShopOptions=this.TargetShopOptions;//右边已选择表格数据
        let TargetMultipleSelection=this.TargetMultipleSelection;//已选商品多选选中change数据
        let deleteArry=[];//相同id的数据
        TargetShopOptions.forEach(function (value, index, array) {
          TargetMultipleSelection.forEach(function (item, itemindex, itemarray) {
            if(value.id==item.id){
              deleteArry.push(item.id);
            }
          })
        });
        let deletemultipleSelection=this.multipleSelection;//右边已选择change数据
        /*返回去掉已经选中的右边数据*/
        deletemultipleSelection = deletemultipleSelection.filter(function(item){
          return deleteArry.indexOf(item.id) == -1;
        });
        this.TargetShopOptions=deletemultipleSelection;//右边已选择重新赋值
        this.toggleSelection(TargetMultipleSelection)//调用取消左边选中函数事件,将数据传输过去即可,调用ele的toggleRowSelection函数
      },
      /*取消商品已选择函数*/
      toggleSelection(rows) {
        if (rows) {
          rows.forEach(row => {
            this.$refs.multipleTable.toggleRowSelection(row);
          });
        } else {
          this.$refs.multipleTable.clearSelection();
        }
      },
      /*搜索商品获取产品*/
      searchClickFUn(){
        this.goodesLoding=true;
        let self=this;
        this.axios.post(allApi.GetGoodsInfo,{category:this.classification,key:this.searchKey,PageIndex: 1, PageSize: 10000}
        ).then(function (res) {
          if(res.data.IsSuccess){
            self.shopOptions=res.data.Result.Data;
            self.goodesLoding=false;
          }else{
            self.goodesLoding=false;
            self.$message.error("请求失败");
          }
        }).catch(function (res) {
          console.log(res)
        });
      },
      /*弹框确定赋值到页面输入框*/
      yesshopName(){
        this.goodsName='';
        this.addgoodsListArr=this.TargetShopOptions;
        let self=this;
        this.addgoodsListArr.forEach(function (value, index, array) {
          self.goodsName+=value.title+'、';
        });
        self.reduceGoodsVisible=false;
      },



      /*编辑提交保存*/
      editSeckillSubmit(){
        if(this.Mustfill()){
          let goodsID=[];
          this.addgoodsListArr.forEach(function (value, index, array) {
            goodsID.push(value.id)
          });
          let SecKillData={
            Title:this.Title,
            reach_amount:this.reach_amount,
            reduce_amount:this.reduce_amount,
            Start:this.Start.getTime(),
            End:this.End.getTime(),
            Reduce_Num:this.Reduce_Num,
            Valid:this.Valid,
            GoodsList:goodsID,
            ID:this.$route.query.seckillID,
          };
          let self=this;
          this.axios.post(allApi.EditAmount_Reduce,SecKillData
          ).then(function (res) {
            if(res.data.IsSuccess){
              if(res.data.Result){
                self.$message.success("满减商品提交编辑保存成功,请在满减列表查看");
                // self.clearform();//清空
              }else{
                self.$message.error(res.data.ErrorMsg);
              }
            }else{
              self.$message.error("请求失败");
            }
          }).catch(function (res) {
            console.log(res)
          });
        }
      },
      /*提交保存*/
      seckillSubmit(){
        if(this.Mustfill()){
          let goodsID=[];
          this.addgoodsListArr.forEach(function (value, index, array) {
            goodsID.push(value.id)
          });
          let SecKillData={
            Title:this.Title,
            reach_amount:this.reach_amount,
            reduce_amount:this.reduce_amount,
            Start:this.Start.getTime(),
            End:this.End.getTime(),
            Reduce_Num:this.Reduce_Num,
            Valid:this.Valid,
            GoodsList:goodsID
          };
          let self=this;
          this.axios.post(allApi.AddAmount_Reduce,SecKillData
          ).then(function (res) {
            if(res.data.IsSuccess){
              if(res.data.Result){
                self.$message.success("满减商品提交保存成功,请在满减列表查看");
                self.clearform();//清空
              }else{
                self.$message.error(res.data.ErrorMsg);
              }
            }else{
              self.$message.error("请求失败");
            }
          }).catch(function (res) {
            console.log(res)
          });
        }
      },
      /*清空表单*/
      clearform(){
          this.Title='';
          this.goodsName=''

          this.reach_amount='';
          this.reduce_amount='';
          this.Start='';
          this.End='';
          this.Reduce_Num='';
          this.Valid='1';
          this.toggleSelection(this.TargetShopOptions);//清空左边全部商品已选择
          this.TargetShopOptions=[];//清空右边商品已选择
          this.addgoodsListArr=[];//清空传递

      },
      /*获取编辑信息*/
      editReduceInfoCreated(){
        this.domeloding=true;
        let self=this;
        this.axios.post(allApi.GetAmount_ReduceModel ,{id:this.$route.query.seckillID}
        ).then(function (res) {
          if(res.data.IsSuccess){
            self.Title=res.data.Result.title;
            self.goodsName=res.data.Result.goodsName;
            self.reach_amount=res.data.Result.reach_amount;
            self.reduce_amount=res.data.Result.reduce_amount;
            self.Start=new Date(res.data.Result.start);
            self.End=new Date(res.data.Result.end);
            self.Reduce_Num=res.data.Result.reduce_num;
            self.Valid=res.data.Result.valid.toString();
            self.TargetShopOptions=res.data.Result.GoodsList;
            self.addgoodsListArr=res.data.Result.GoodsList;
            self.domeloding=false
            // self.toggleSelection(res.data.Result.GoodsList);//清空左边全部商品已选择
          }else{
            self.$message.error("请求失败");
          }
        }).catch(function (res) {
          console.log(res)
        });
      },
      /*验证必填*/
      Mustfill(){
        if(this.Title==''){
          this.$message.error("活动标题不能为空");
          return false
        }else if(this.reach_amount==''){
          this.$message.error("填写满减金额");
          return false
        }else if(this.reduce_amount==''){
          this.$message.error("填写满减金额");
          return false
        }else if(this.Start=='' || this.End==''){
          this.$message.error("选择活动时间");
          return false
        }else if(this.Reduce_Num==''){
          this.$message.error("填写满减次数");
          return false
        }else{
          return true
        }
      }
    },
    mounted () {//挂载完成

    },
    watch:{//监听

    },
  }
</script>
<style scoped>
  .titletableBox{
    height:40px;
    background-color: rgba(24, 144, 255, 1);
    color: #ffffff;
    line-height: 40px;
    text-align: center;
  }
  .TransferBox{
    display: flex;
  }
  .SourceBox{
    width: 400px;
  }
  .buttonCentenr{
    position: relative;
    width: 150px;
  }
  .posiBox{
    position: absolute;
    top: 100px;
    left: 50px;
  }
  .posiBox p{
    margin-top: 50px;
  }
  .TargetBox{
    width: 400px;
  }
  #reduce_settings{
    height: 100%;
  }
  .markingInfobox{
    background-color: #ffffff;
    position: fixed;
    top: 90px;
    left: 180px;
    bottom: 80px;
    right: 10px;
    overflow-y: auto;
    padding: 30px 50px;
  }
  .titleP{
    position: relative;
  }
  .titleinfoP{
    height:20px;
    line-height: 20px;
    margin-right: 5px;
    color:rgba(21,168,253,1);
    font-size: 18px;
    display: inline-block;
  }
  .bluespan{
    display: inline-block;
    width:3px;
    height:20px;
    background:rgba(21,168,253,1);
    position: absolute;
  }
  .formBox p{
    margin-top: 25px;
    font-size: 16px;
    color: #333333;
  }
  .submitmarking{
    margin-top: 40px;
  }
  .redspan{
    color: red;
    display: inline-block;
    width: 20px;
    text-align: center;
  }
  .timecenter{
    font-size: 14px;
    display: inline-block;
    width: 20px;
    text-align: center;
  }
</style>
<style>
  #reduce_settings .formBox .el-input__inner{
    background-color:rgba(245,247,253,1)!important;
  }
</style>