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>

// 在 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"
}
]
}
]
}
效果图

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
使用虚拟标签 只有出现数据了才会渲染
循环渲染 同步信息框


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

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