- 登录输入框,如果没有数据自动聚焦
mounted() {
if (this.loginForm.username === "") {
this.$refs.username.focus();
} else if (this.loginForm.password === "") {
this.$refs.password.focus();
}
},
- 密码框的显示影藏切换
:icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
@click="showPwd"
showPwd() {
if (this.passwordType === "password") {
this.passwordType = "";
} else {
this.passwordType = "password";
}
this.$nextTick(() => {
this.$refs.password.focus();
});
},
- 通过浅拷贝实现属性过滤
const _query = Object.assign({}, query)
delete _query.redirect
- 对token的分类处理
const whiteUrl = ['/login']
service.interceptors.request.use(
config => {
const url = config.url.replace(config.baseURL, '')
if (whiteUrl.some(wl => url === wl)) {
return config
}
config.headers['Authorization'] = `Bearer ${getToken()}`
return config
},
- token - cokie的封装
import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
使用
import { getToken, setToken, removeToken } from '@/utils/auth'
setToken(data.token)
- 对路由的监听
watch: {
$route: {
handler: function (route) {
const query = route.query;
console.log("query", query);
if (query) {
this.redirect = query.redirect;
this.otherQuery = this.getOtherQuery(query);
}
},
immediate: true,
},
},
- 表格排序 + 搜索通用 + 搜索高亮
@sort-change="sortChange"
sortChange(data) {
console.log("data", data);
const { prop, order } = data;
if (prop === "id") {
this.sortByID(order);
}
},
sortByID(order) {
console.log("this.listQuery", this.listQuery);
if (order === "ascending") {
this.listQuery.sort = "+id";
} else {
this.listQuery.sort = "-id";
}
this.handleFilter();
},
handleFilter() {
console.log("listQuery", this.listQuery);
this.listQuery.page = 1;
this.refresh();
},
refresh() {
this.$router.push({
path: "/book/list",
query: this.listQuery,
});
},
beforeRouteUpdate(to, from, next) {
console.log("to", to.path);
console.log("from", from.path);
console.log("next", next.path);
if (to.path === from.path) {
const newQuery = Object.assign({}, to.query);
const oldQuery = Object.assign({}, from.query);
console.log("newQuery", newQuery);
console.log("oldQuery", oldQuery);
console.log("oldQuery", JSON.stringify(oldQuery));
console.log("newQuery", JSON.stringify(newQuery));
if (JSON.stringify(newQuery) !== JSON.stringify(oldQuery)) {
console.log("等不等");
this.getList();
}
}
next();
},
getList() {
this.listLoading = true;
listBook(this.listQuery).then((response) => {
const { data, total } = response;
this.list = data;
this.total = total;
this.listLoading = false;
console.log("lisk", this.list);
this.list.forEach((book) => {
book.titleWrapper = this.wrapperKeyword("title", book.title);
book.authorWrapper = this.wrapperKeyword("author", book.author);
});
});
},
wrapperKeyword(k, v) {
function highlight(value) {
return '<span style="color: #1890ff">' + value + "</span>";
}
if (!this.listQuery[k]) {
return v;
} else {
return v.replace(new RegExp(this.listQuery[k], "ig"), (v) =>
highlight(v)
);
}
},
- 过滤器
filters: {
valueFilter(value) {
return value ? value : "无";
},
}
- 表格里的数据结构 和图片打开
<template slot-scope="{ row: { cover } }">
<a :href="cover" target="_blank">
<img :src="cover" style="width: 120px; height: 180px" />
</a>
</template>
- 分页器二次封装
<template>
<div :class="{'hidden':hidden}" class="pagination-container">
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:total="total"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import { scrollTo } from '@/utils/scroll-to'
export default {
name: 'Pagination',
props: {
total: {
required: true,
type: Number
},
page: {
type: Number,
default: 1
},
limit: {
type: Number,
default: 20
},
pageSizes: {
type: Array,
default() {
return [10, 20, 30, 50]
}
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
}
},
computed: {
currentPage: {
get() {
return this.page
},
set(val) {
this.$emit('update:page', val)
}
},
pageSize: {
get() {
return this.limit
},
set(val) {
this.$emit('update:limit', val)
}
}
},
methods: {
handleSizeChange(val) {
this.$emit('pagination', { page: this.currentPage, limit: val })
if (this.autoScroll) {
scrollTo(0, 800)
}
},
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize })
if (this.autoScroll) {
scrollTo(0, 800)
}
}
}
}
</script>
<style scoped>
.pagination-container {
background: #fff;
padding: 32px 16px;
}
.pagination-container.hidden {
display: none;
}
</style>
使用
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.page"
:limit.sync="listQuery.pageSize"
@pagination="refresh"
/>
- 新手引导
https://www.jianshu.com/p/8cdef1041086
- 表格固定最后一列
fixed="right"
- 吸顶组件
<template>
<div :style="{height:height+'px',zIndex:zIndex}">
<div
:class="className"
:style="{top:(isSticky ? stickyTop +'px' : ''),zIndex:zIndex,position:position,width:width,height:height+'px'}"
>
<slot>
<div>sticky</div>
</slot>
</div>
</div>
</template>
<script>
export default {
name: 'Sticky',
props: {
stickyTop: {
type: Number,
default: 0
},
zIndex: {
type: Number,
default: 1
},
className: {
type: String,
default: ''
}
},
data() {
return {
active: false,
position: '',
width: undefined,
height: undefined,
isSticky: false
}
},
mounted() {
this.height = this.$el.getBoundingClientRect().height
window.addEventListener('scroll', this.handleScroll)
window.addEventListener('resize', this.handleResize)
},
activated() {
this.handleScroll()
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll)
window.removeEventListener('resize', this.handleResize)
},
methods: {
sticky() {
if (this.active) {
return
}
this.position = 'fixed'
this.active = true
this.width = this.width + 'px'
this.isSticky = true
},
handleReset() {
if (!this.active) {
return
}
this.reset()
},
reset() {
this.position = ''
this.width = 'auto'
this.active = false
this.isSticky = false
},
handleScroll() {
const width = this.$el.getBoundingClientRect().width
this.width = width || 'auto'
const offsetTop = this.$el.getBoundingClientRect().top
if (offsetTop < this.stickyTop) {
this.sticky()
return
}
this.handleReset()
},
handleResize() {
if (this.isSticky) {
this.width = this.$el.getBoundingClientRect().width + 'px'
}
}
}
}
</script>
<sticky :z-index="10" :class-name="'sub-navbar ' + postForm.status">
<el-button v-if="!isEdit" @click.prevent.stop="showGuide"
>显示帮助</el-button
>
<el-button
v-loading="loading"
style="margin-left: 10px"
type="success"
class="submit-btn"
@click="submitForm"
>
{{ isEdit ? "编辑电子书" : "新增电子书" }}
</el-button>
</sticky>
- 上传组件的封装
- 多数据表单的设置
假设表单有很多数据,需要在请求回数据,填写。那我们都要把这些数据,设置成响应式吗?
写一个方法
this.setData(data);
在方法里赋值
setData(data) {
const {
title
} = data;
this.postForm = {
title
};
数据清空
toDefault() {
this.postForm = Object.assign({}, defaultForm);
this.fileList = [];
this.contentsTree = [];
},
- 表单数据校验,多级数据做数据的映射
const validateRequire = (rule, value, callback) => {
console.log("rule", rule);
if (value === "") {
this.$message({
message: rule.field + "为必传项",
type: "error",
});
callback(new Error(rule.field + "为必传项"));
} else {
callback();
}
};