美文网首页
iView修改表单未保存离开页面提示,scrollIntoVie

iView修改表单未保存离开页面提示,scrollIntoVie

作者: chenjundi | 来源:发表于2020-07-23 17:08 被阅读0次

    之前一直在用element-ui,这次我们改用iView框架。

    关于修改表单未保存离开页面这里我们只考虑两种情况,一种是直接关闭浏览器(直接关闭页面),一种是路由跳转(包含浏览器前进后退),以下是两种提示页面的截图:

    企业微信截图_15954762187108.png
    企业微信截图_15954762307954.png
    直接关闭浏览器的提示方式:

    当浏览器窗口关闭或者刷新时,会触发beforeunload事件。当前页面不会直接关闭,可以点击确定按钮关闭或刷新,也可以取消关闭或刷新。

    | Bubbles | No |
    | Cancelable | Yes |
    | Interface | Event |
    | Event handler property | onbeforeunload |

    事件使网页能够触发一个确认对话框,询问用户是否真的要离开该页面。如果用户确认,浏览器将导航到新页面,否则导航将会取消。

    根据规范,要显示确认对话框,事件处理程序需要在事件上调用preventDefault()

    但是请注意,并非所有浏览器都支持此方法,而有些浏览器需要事件处理程序实现两个遗留方法中的一个作为代替:

    • 将字符串分配给事件的returnValue属性
    • 从事件处理程序返回一个字符串。

    了解了这个方法,我们在data里定义这三个属性:

    data () {
        return {
          isEdited: false, // 判断表单是否被修改
          formData: {}, // 表单保存的数据
          initData: {} // 拷贝一份初始表单数据,这里的数据不会改变
        }
      }
    

    methods里定义beforeunload方法:

    methods: {
        beforeunload (e) {
          // 表单被修改
          if (this.isEdited) {
            const confirmationMessage = '你确定离开此页面吗?'
            e.returnValue = confirmationMessage
            return confirmationMessage
          }
        }
      }
    

    在进入页面和销毁页面前绑定beforeunload方法:

    mounted () {
        // 初始表单数据赋值
        this.initData = Object.assign({}, this.formData)
        // 拦截判断是否离开当前页面
        window.addEventListener('beforeunload', this.beforeunload)
      },
    beforeDestroy () {
        // 销毁拦截判断是否离开当前页面
        window.removeEventListener('beforeunload', this.beforeunload)
      }
    

    我们判断的逻辑是对比初始数据和修改表单后的数据,如果一致说明没有改变表单数据,否则就说明用户编辑过表单。通过watch去监听formData

    watch: {
        formData: {
          deep: true,
          handler (val) {
            // 把两个对象转换成字符串比较
            if (JSON.stringify(this.initData) === JSON.stringify(val)) {
              this.isEdited = false
            } else {
              this.isEdited = true
            }
          }
        }
      }
    
    vue路由跳转的提示方式:

    这需要你有另一个vue的页面,然后我们只需要在上面的基础上加上beforeRouteLeave方法就行了。

    beforeRouteLeave (to, from, next) {
        // 表单被修改
        if (this.isEdited) {
          this.$Modal.confirm({
            title: '系统监测到你有未保存表单,是否直接离开?',
            content: '',
            onOk: () => {
              next()
            },
            onCancel: () => {
              next(false)
            }
          })
        } else {
          next()
        }
      }
    

    完整代码:

    <template>
      <div class="main">
        <h3>基本信息</h3>
        <!-- 表单 -->
        <Form
          ref="form"
          :model="formData"
          :rules="formValidate"
          label-position="top"
        >
          <!-- 姓名 -->
          <Divider
            orientation="left"
            id="name"
          >
            <h5>姓名</h5>
          </Divider>
          <Row
            :gutter="20"
            class="main-block"
          >
            <Col span="12">
            <FormItem
              label="姓名"
              prop="name"
            >
              <Input
                placeholder="请输入姓名"
                v-model.trim="formData.name"
                clearable
              ></Input>
            </FormItem>
            </Col>
          </Row>
          <!-- 年龄 -->
          <Divider
            orientation="left"
            id="age"
          >
            <h5>年龄</h5>
          </Divider>
          <Row
            :gutter="20"
            class="main-block"
          >
            <Col span="12">
            <FormItem
              label="年龄"
              prop="age"
            >
              <Input
                placeholder="请输入年龄"
                v-model.trim="formData.age"
                clearable
              ></Input>
            </FormItem>
            </Col>
          </Row>
          <!-- 性别 -->
          <Divider
            orientation="left"
            id="gender"
          >
            <h5>性别</h5>
          </Divider>
          <Row
            :gutter="20"
            class="main-block"
          >
            <Col span="12">
            <FormItem
              label="性别"
              prop="gender"
            >
              <RadioGroup v-model="formData.gender">
                <Radio label="男"></Radio>
                <Radio label="女"></Radio>
              </RadioGroup>
            </FormItem>
            </Col>
          </Row>
          <!-- 称呼 -->
          <Divider
            orientation="left"
            id="tag"
          >
            <h5>称呼</h5>
          </Divider>
          <Row
            :gutter="20"
            class="main-block"
          >
            <Col span="12">
            <FormItem
              label="称呼"
              prop="tag"
            >
              <Select
                placeholder="请选择称呼"
                v-model="formData.tag"
                clearable
              >
                <Option
                  v-for="(item, index) in tagList"
                  :value="item.value"
                  :key="index"
                >{{item.label}}</Option>
              </Select>
            </FormItem>
            </Col>
          </Row>
        </Form>
        <div class="btn-layer">
          <Button
            type="primary"
            style="margin-right:10px;"
            @click="onSubmit"
          >保存</Button>
          <Button @click="onCancel">重置</Button>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'HelloWorld',
      props: {
        msg: String
      },
      data () {
        return {
          isEdited: false, // 判断表单是否被修改
          initData: {},
          formData: {
            name: '',
            age: '',
            gender: '男',
            tag: ''
          },
          formValidate: {
            name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
            age: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
            gender: [{ required: true, message: '请输入性别', trigger: 'change' }],
            tag: [{ required: true, message: '请输入子会会议名称', trigger: 'change' }]
          },
          tagList: [
            { label: '先生', value: 'Mr.' },
            { label: '女士', value: 'Ms.' }
          ]
        }
      },
      methods: {
        onSubmit () {
          this.$refs.form.validate(valid => {
            if (valid) {
              this.isEdited = false
              this.$Message.success('创建成功')
            } else {
              this.$nextTick(() => {
                document.getElementsByClassName('ivu-form-item-error')[0].scrollIntoView({ behavior: 'smooth' })
              })
            }
          })
        },
        onCancel () {
          this.$refs.form.resetFields()
        },
        beforeunload (e) {
          if (this.isEdited) {
            const confirmationMessage = '你确定离开此页面吗?'
            e.returnValue = confirmationMessage
            return confirmationMessage
          }
        }
      },
      mounted () {
        this.initData = Object.assign({}, this.formData)
        // 拦截判断是否离开当前页面
        window.addEventListener('beforeunload', this.beforeunload)
      },
      beforeDestroy () {
        // 销毁拦截判断是否离开当前页面
        window.removeEventListener('beforeunload', this.beforeunload)
      },
      watch: {
        formData: {
          deep: true,
          handler (val) {
            if (JSON.stringify(this.initData) === JSON.stringify(val)) {
              this.isEdited = false
            } else {
              this.isEdited = true
            }
          }
        }
      },
      beforeRouteLeave (to, from, next) {
        if (this.isEdited) {
          this.$Modal.confirm({
            title: '系统监测到你有未保存表单,是否直接离开?',
            content: '',
            onOk: () => {
              next()
            },
            onCancel: () => {
              next(false)
            }
          })
        } else {
          next()
        }
      }
    }
    </script>
    
    <style scoped>
    .main {
      padding: 50px;
      max-width: 1200px;
      margin: 0 auto;
      border: 1px solid #ccc;
    }
    .main h3 {
      text-align: center;
      margin-bottom: 50px;
    }
    .main .btn-layer {
      margin: 30px 0;
      text-align: center;
    }
    .main .main-block {
      margin-bottom: 100px;
    }
    </style>
    
    

    这里我们还结合了Element.scrollIntoView()方法,当表单验证未通过时可以让页面直接滚动到报错的那个位置。

    scrollIntoViewOptions 可选
    一个包含下列属性的对象:
    behavior 可选
    定义动画过渡效果, "auto"或 "smooth" 之一。默认为 "auto"。
    block 可选
    定义垂直方向的对齐, "start", "center", "end", 或 "nearest"之一。默认为 "start"。
    inline 可选
    定义水平方向的对齐, "start", "center", "end", 或 "nearest"之一。默认为 "nearest"。

    相关文章

      网友评论

          本文标题:iView修改表单未保存离开页面提示,scrollIntoVie

          本文链接:https://www.haomeiwen.com/subject/wrwclktx.html