likes
comments
collection
share

Vue 大事件个人向思路小结

作者站长头像
站长
· 阅读数 61

1.使用element组件时 常规的兜底校验方式

 methods: {
    login () {
    // logRef是自己在上面设置的自定义属性方法
      this.$refs.logRef.validate(async valid => {
        if (!valid) return // 这里的valid 返回的是一个布尔值
        // console.log('我要登录了')

        // 使用async 和 await 来获取ajax 请求得到的promise对象执行then() 的数据
        // 可以解决回调地狱问题 讲其他数据拿出来 以免嵌套过深导致个人混乱
        const { data: res } = await this.$http.post('/api/login', this.logForm)
        // console.log(res)
        if (res.code !== 0) return this.$message.error(res.message)
        this.$message.success(res.message)

        // 登陆成功 网页跳转到首页  但是先要存储token
        this.$store.commit('user/updateToken', res.token)

        // 跳转至登录页 '/' 为路由规则中自己所设置的默认路径
        this.$router.push('/')

        // 本地存储 token   登录的'钥匙'
      })
    }
  }
  // 

2.将validator的方法放在 data 里面的原因

  // 1.在vue组件里面  data初始化太早了 不方面直接访问methods 所以函数放在data里面
  // 2.写在data里面 会有函数作用域  里面的方法只能在当前函数访问 
  // 2.1 作用域查找规则: 首先找当前作用域, 由于export default是一个对象 没有作用域 可以全局访问到
  // 如果将方法写在其他位置 可能会出现重名或者其他冲突问题
  // 将validator的方法定义在外面也可以 写在data外面后就变全局了 this 是undefined 不能直接使用
  // 所以饿了吗不得不写在data里面 这也是必然的
  // 总之就是放在外面的话 export default 是一个对象 没有作用域 可以在当前组件直接this调用 但是可能会出现名字冲突等问题
  // 写在data() 函数里面 设置的方法就有了局部作用域 不会和外面的其他函数方法冲突 并且这里面可以直接谁用
  // 注意: 
  // data 比 computed 更早一点初始化, 所以在 computed 里可以使用 data 中的数据, 而data中不能使用
  // computed 的数据, 如果非要使用, 可以等 computed 加载完毕后使用
export default {
  name: 'Reg',
  data () {
    // 模仿 element官网 在这里写代码
    // 参数一 rule 规则对象 一般不用
    // 参数二 value 当前校验项的数据
    // 参数三 callback 回调函数 决定是否校验通过 直接调用不传参表示校验通过 调用传入错误对象 表示校验失败
    // 这里使用 箭头函数的原因是 this 指向不是本身的事件源 这里适合用来做判断校验
    // 使用的是前置守卫 通过就传参 不通过也执行回调函数 但是不传参
    const samePwd = (rule, value, callback) => {
      if (value !== this.regForm.password) {
        // 如果验证失败 则调用回调函数时  指定一个 Error 对象
        callback(new Error('两次输入的密码不一致!'))
      } else {
        // 如果验证成功 则直接调用 callback 回调函数即可
        callback()
      }
    }
    return {
      // 注册表单的数据对象
      regForm: {
        username: '',
        password: '',
        repassword: ''
      },
      //  // 注册表单的验证规则对象
      regRules: {
        username: [
          { required: true, message: '请输入用户名', trigger: 'blur' },
          {
            pattern: /^[a-zA-z0-9]{1,10}/,
            message: '用户名必须是1-10的字母数字',
            trigger: 'blur'
          }
        ],
        password: [
          { required: true, message: '请输入密码', trigger: 'blur' },
          {
            pattern: /^\S{6,15}$/,
            message: '密码必须是6-15的非空字符',
            trigger: 'blur'
          }
        ],
        repassword: [
          { required: true, message: '请输入密码', trigger: 'blur' },
          {
            pattern: /^\S{6,15}$/,
            message: '密码必须是6-15的非空字符',
            trigger: 'blur'
          },
          { validator: samePwd, trigger: 'blur' }
        ]
      }
    }
  }
}

3.选择图片后 切换图片的按钮才解锁能点击的办法实现

<template>
  <el-card class="box-card">
    <div slot="header" class="clearfix">
      <span>更换头像</span>
    </div>
    <div>
      <!-- 图片,用来展示用户选择的头像 -->
      <img v-if="avatar" :src="avatar" alt="" />
      <img v-else src="../../../assets/images/avatar.jpg" alt="" />

      <!-- 按钮区域 -->
      <div class="btn-box">
        <!-- accept: 当前文件选择框可以接受的文件类型 -->
        <!-- MIME_TYPE: application/json text/plain text/html text/css Content-Type: application/json -->
        <!-- 为什么 MIME TYPE 会出现?   使用http 协议在互联网上通信 只支持两种格式的数据: 文本/二进制 -->
        <!-- 用于表示在互联网上传输的文件类型  -->
        <input @change="changeFile" accept="image/*" ref="inp" style="display: none" type="file">
        <el-button @click="$refs.inp.click()" type="primary" icon="el-icon-plus">选择图片</el-button>
        <el-button @click="upload" type="success" icon="el-icon-upload" :disabled="!avatar">上传头像</el-button>
      </div>
    </div>
  </el-card>
</template>

Vue 大事件个人向思路小结

// 在 export default {} 对象里面 设置一个 变量  avatar: ''  赋值为空
// 原本的input选择框的 file类型很丑 这里用display: none隐藏起来 上面绑定 ref设置自定义方法 inp
// 点击别的按钮"选择图片时" 触发自定义事件的点击触发事件 this.$refs.inp.click()
// 在原来的选择框上再绑定一个change事件 用来判断自己点击后是否选择了图片
// 使用v-if 来确定自己是否选择了头像 在预览上看到
// 具体写法如下所示
export default {
  name: 'UserAvatar',
  data () {
    return {
      avatar: ''
    }
  },
  methods: {
    changeFile (e) {
      // 我要一个object 可以传入一个 Array
      // Blob是父类对象 File 是 子类对象
      // files
      // console.log(e.target.files[0])
      // e.target 里面有 files 属性 他是一个伪数组 里面装的是图片对象
      // img 标签的 src 属性只能设置两种值
      // URL 和 BASE64 (Data URL)
      const files = e.target.files
      if (files.length > 0) {
        // files[0] : 是一个对象
        // 目标: 将这个对象转成 BASE64 格式的字符串
        // FileReader 文件读取器

        // 1. 创建 FileReader 对象
        const fr = new FileReader()

        // 2. 读取文件转成 BASE64
        fr.readAsDataURL(files[0])

        // 3.监听事件 得到结果
        // 必须使用箭头函数
        fr.onload = (e) => {
          // console.log(e.target.result)
          // 4.通过 e.target.result
          this.avatar = e.target.result
        }
      } else {
        this.avatar = ''
      }
    },
    async upload () {
      // 发请求
      const { data: res } = await this.$http.patch('/my/update/avatar', { avatar: this.avatar })
      // 根据结果提醒用户
      if (res.code !== 0) return this.$message.error(res.message)
      this.$message.success(res.message)
      // 获取用户信息
      this.$store.dispatch('user/getUserInfo')
    }
  }
}

4.使用饿了吗 的侧边栏框的注意事项

<!-- 菜单项分为两种类型 :
          1.有子菜单的: el-submenu
          2.没有子菜单的: el-menu-item -->

        <el-menu
          router
          default-active="/home"
          class="el-menu-vertical-demo"
          background-color="#23262E"
          text-color="#fff"
          active-text-color="#409EFF"
        >
          <!-- template 标签是虚拟标签 不会渲染到 DOM 树上 只是起到了包裹的作用 -->
          <!-- v-for 的 key 不能设置在 template 上 所以需要设置给他的子元素们 他们使用 v-if 来控制渲染 -->
          <!-- v-for 循环渲染template -->

          <template v-for="item in menus">
            <!-- menu-item 没有子菜单 直接包裹 i 和 span -->
            <el-menu-item
              :index="item.indexPath"
              :key="item.indexPath"
              v-if="!item.children"
            >
              <i :class="item.icon"></i>
              <span>{{ item.title }}</span>
            </el-menu-item>

            <!-- sub有子菜单 包裹一个template(里面有i 和 span)   和 menu-item-->
            <el-submenu :index="item.indexPath" :key="item.indexPath" v-else>
              <template slot="title">
                <i :class="item.icon"></i>
                <span>{{ item.title }}</span>
              </template>
              <el-menu-item
                :index="sub.indexPath"
                v-for="sub in item.children"
                :key="sub.indexPath"
              >
                <i :class="sub.icon"></i>
                <span>{{ sub.title }}</span>
              </el-menu-item>
            </el-submenu>
          </template>
        </el-menu>

具体数据如下:

{
    "code": 0,
    "message": "获取左侧菜单成功!",
    "data": [
        {
            "indexPath": "/home",
            "title": "首页",
            "icon": "el-icon-s-home",
            "children": null
        },
        {
            "indexPath": "2",
            "title": "文章管理",
            "icon": "el-icon-s-order",
            "children": [
                {
                    "indexPath": "/art-cate",
                    "title": "文章分类",
                    "icon": "el-icon-s-data"
                },
                {
                    "indexPath": "/art-list",
                    "title": "文章列表",
                    "icon": "el-icon-document-copy"
                }
            ]
        },
        {
            "indexPath": "3",
            "title": "个人中心",
            "icon": "el-icon-user-solid",
            "children": [
                {
                    "indexPath": "/user-info",
                    "title": "基本资料",
                    "icon": "el-icon-s-operation"
                },
                {
                    "indexPath": "/user-avatar",
                    "title": "更换头像",
                    "icon": "el-icon-camera"
                },
                {
                    "indexPath": "/user-pwd",
                    "title": "重置密码",
                    "icon": "el-icon-key"
                }
            ]
        }
    ]
}

效果图

Vue 大事件个人向思路小结

5.组件下拉框的 触发方式 要用 'change'                   tirgger: 'change'

下拉框的value值没有选择 无法直接看到 未选择 的情况 可以通过兜底校验看到

其他的基本使用 'blur' 的触发方式

6.vue组件的style 里面的scoped 以及深度选择器

// scoped:
// 1. 给当前组件中所有元素加一个 data-v-hash, 如果用了组件, 只会给组件的根元素加这个属性
// 会导致组件内的元素样式无法生效
// 2. 给所有选择器加一个属性交集选择器

// 深度选择器: 让组件内的元素也可以生效
// 原理: 将之前的交集选择器变成 后代选择器, [data-v-hash] .ql-editor
// 注意: 用深度选择器有时候权重还是不够 必要时可以加上 !important
/deep/ .ql-editor {
  height: 300px;
}

7.渲染需要的数据不能立即得到导致加载失败

 比如menus需要异步操作进行ajax请求才能获取到 不会立刻得到 所以直接用是undefined
 使用虚拟标签  只有出现数据了才会渲染
 循环渲染 同步信息框 

Vue 大事件个人向思路小结

Vue 大事件个人向思路小结

8.插槽传值 获取id等其他数据 插槽v-slot传值 具体原理还不清楚 还需后期研究 先放着

Vue 大事件个人向思路小结

9.饿了么表单插件几个 小功能

Vue 大事件个人向思路小结

转载自:https://juejin.cn/post/7079775970516795428
评论
请登录