类似问卷网的调查问卷页面

点击题型按钮后在边添加题型

在这里插入图片描述

使用vuex状态管理

//初始化默认标题与选项
itemTitle : '请输入题目',
  itemSelections : ["选项1","选项2","选项3","选项4"],
  //设置题型空数组,点击后添加题型
  questionnaire: {   
        questItemtitle: '问卷标题',
        questItemcontent:'感谢您能抽出几分钟时间来参加本次答题,现在我们就马上开始吧!',
        deadline:  '',
        state: '',
        //放题型
        questItemList: []
    },
    //放单选的题型
   questItem: {
      itemSelections:[]
    },

判断是哪一种题型后添加对应的题型

//添加题目
      addItem(event){
          let type = event.target.innerText.split(" ");//以空格来分割
          let types = "";//定义变量
          for (var i = 0; i < type.length; i++) {
              types+=type[i];//拼接没有空格的字符串
          }
          console.log(types);
          if (types=='单选题') {
            let question_type='radio'
            this.$store.state.questItem.type = question_type // 设置问题的类型,应该存到vuex的state中可以提供全局使用
            //分发事件
            //通知vuex去增加
            this.$store.dispatch('addSelections')//分发消息触发store中的action调用
            //this.addSelections(itemTitle, itemSelections)
          }else if (types=='多选题') {
            let question_type='checkbox'
            this.$store.state.questItem.type = question_type // 设置问题的类型,应该存到vuex的state中可以提供全局使用
            this.$store.dispatch('addSelections')//分发消息触发store中的action调用
          }else if (types=='文本框') {
            let question_type='textarea'
            this.$store.state.questItem.type = question_type // 设置问题的类型,应该存到vuex的state中可以提供全局使用
            console.log(this.$store.state.questItem);
            this.$store.dispatch('addSelections')//分发消息触发store中的action调用
            console.log(this.$store.state.questionnaire.questItemList);
          }
          },

之后会触发vuex中actions提交给mutations
来管理

//单选、多选题
  ADDSELECTIONS(state){
    if(state.itemTitle === '' || state.itemSelections === '') {
      return
  }
  state.questItem.title = state.itemTitle
  state.questItem.selections = state.itemSelections
  state.questItem.name = Date.now()
  state.questionnaire.questItemList.push(state.questItem)
  console.log(state.questionnaire.questItemList);
  this.commit('HANDLECANCEL')
  },
  HANDLECANCEL(state){
    state.questItem = {}
  },

这样子便可以添加题型

删除与复制功能

在对应的每一道题型中将questItem传入removeQuestItem与 reuseQuestItem两个方法里面
例如多选题,会循环

<!-- 多选题 -->
                <div v-if="questItem.type == 'checkbox'"  class="question_change">
                    <!-- <el-checkbox>daj</el-checkbox> -->
                    <div  :v-model="questItem.name+index" label="1"
                    v-for="(selection,index) in questItem.selections"
                    :id="String( questItem.name+index)"
                    :type="questItem.type"
                    :class="questItem.type"
                    contentEditable='true'
                    :key="index" class="question_change_inner">
                    <span class="fangkuang"></span>
                    <span class="wenzi">{{selection}}</span>
                    </div>
                </div>

// 删除
            removeQuestItem(questItem) {
                this.$store.state.questionnaire.questItemList.splice(questItem, 1)
            },
            // 复用
            reuseQuestItem(questItem) {
                let index = this.$store.state.questionnaire.questItemList.indexOf(questItem)
                // 为了完整的克隆一个对象,先把对象转换成JSON,再转换成对象
                let newQuestItem = JSON.parse(JSON.stringify(questItem))
                if(newQuestItem.type !== 'textarea') {
                    newQuestItem.name = Date.now()
                }
                this.$store.state.questionnaire.questItemList.splice(index+1, 0, newQuestItem)
            },

实现编辑功能

一行代码可实现编辑功能

contentEditable='true'

编辑框获取焦点后的样式

[contenteditable]:focus{
    padding: 5px 10px;
    width: 100%;
    }

编辑后动态更新数据

在网上找资料后发现div开启contentEditable='true’后可类似一个输入框,我们使用输入框更新数据的方式,来让div里的数据更新,这里我使用的方法也是比较普通的,如果有更好的想法,欢迎大家一起讨论

在这里插入图片描述

//点击之后实现可编辑状态
        changeText(event){
            //看看是哪一个属性的
            let operation = event.srcElement.className.split(' ')[0]
            if(operation=="questItemtitle") {
                this.innerText.questItemtitle =event.target.innerText;
            }else if(operation=="questItemcontent") {
                this.innerText.questItemcontent =event.target.innerText;
            }
            else if(operation=="question_change_inner"||operation=="questItem_small"){
               if (operation=="questItem_small") {
                //当点击标题时获取标题的序号num,并且获取小标题small_title
                let num=Number(event.path[1].children[0].innerText)
                let small_title=event.target.innerText
                //更新每一道题目的标题
                this.$store.state.questionnaire.questItemList[num-1].title=small_title
                }else if(operation=="question_change_inner"){
                //获取题目序号
                let new_num=Number(event.path[2].children[0].children[0].innerText)
                let new_small_title=event.path[2].children[0].children[1].innerText
                this.$store.state.questionnaire.questItemList[new_num-1].title=new_small_title
                //
                let arr=event.path[1].innerText.split('\n')
                //更新每一道题目的数组
                this.$store.state.questionnaire.questItemList[new_num-1].selections=arr
                }
                
            }
                this.$emit('input',this.innerText);
                //解决光标前置问题
                setTimeout(()=>{
                this.keepLastIndex(event.target)
                })
            },

这个功能会让鼠标的光标输入后自动跳转到最前面,我们要实现点击后在点击的位置进行编辑,在changeText(event)这个方法最后面

setTimeout(()=>{
                this.keepLastIndex(event.target)
                })

解决光标前置问题

使用这三个方法

  //让光标实现在点击后的位置进行编辑
       setCaretPosition(ctrl, pos){
        if(ctrl.setSelectionRange){
            ctrl.focus();
            ctrl.setSelectionRange(pos,pos);
        } else if (ctrl.createTextRange) {
            let range = ctrl.createTextRange();
            range.collapse(true);
            range.moveEnd('character', pos);
            range.moveStart('character', pos);
            range.select();
        }
        },
       getCursortPosition(ctrl) {
        let CaretPos = 0;   // IE Support
        if (document.selection) {
            ctrl.focus();
            let Sel = document.selection.createRange();
            Sel.moveStart ('character', -ctrl.value.length);
            CaretPos = Sel.text.length;
        }
        // Firefox support
        else if (ctrl.selectionStart || ctrl.selectionStart == '0')
            CaretPos = ctrl.selectionStart;
        return (CaretPos);
        },
       //光标一直在前面的问题
       keepLastIndex(obj) {
             let input_val = obj.innerText;
        let input_arr = input_val.split();
        for(let i=0;i<input_arr.length;i++) {
            if (input_arr[i] == ' ') {
                setCaretPosition(obj, i*2);
                return;
            }
        }
        }, 

拖拽功能

实现对题型的拖拽
在这里插入图片描述
在这里插入图片描述
安装npm i -S vuedraggable
使用:页面引入import draggable from "vuedraggable"
定义组件:components: { draggable },

model:是指题型保存起来的数组
draggable=".questItem" 是指定题型的class

<draggable v-model="$store.state.questionnaire.questItemList" draggable=".questItem"  chosenClass="chosen" forceFallback="true">
 </draggable>

添加题目,滚动条移动到新增题目的位置

在updated ()中this.$refs.scroll是包裹所有题型的div,也就是最外层div
在这里插入图片描述

updated () {
                //滚动条滚动,要等页面渲染完毕才可以
                    this.$nextTick(() => {
                            this.$nextTick(() => {
                            console.log("this.$refs.scroll",this.$refs.scroll.scrollHeight);
                            this.$refs.scroll.scrollTop = this.$refs.scroll.scrollHeight;
                        })
                    })
            },
            ```
也可设置滚动条的样式,让其不要太粗,不然不好看

/定义滑块颜色、内阴影及圆角/
.AllItem::-webkit-scrollbar {/滚动条整体样式/
width:4px;/高宽分别对应横竖滚动条的尺寸/
height:4px;
}
.AllItem::-webkit-scrollbar-thumb {/滚动条里面小方块/
border-radius:5px;
background:rgba(0,0,0,0.2);
}```
在这里插入图片描述

最后问卷还会再进行修改,并且添加其他的功能,目前做的还不完整

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值