CSS相关

div填充整个页面

  • 解决小白边
1
2
3
4
5
html, body {
margin: 0;
padding: 0;
height: 100%;
}

div位置移动

1
2
3
4
5
.box-card1 {
width: 520px;
margin-left: 430px;
margin-top: 140px;
}

元素移动

style="float: left"

背景图填充整个div

1
2
3
4
5
6
.login{
height: 100%;
width: 100%;
position: fixed;
background-image: url("https://unpkg.com/nan-picture/img/3标签.jpg");
}

div添加下划线(阴影)

1
2
3
.row-bg {
border-bottom: medium solid #E0E0E0;
}

更多介绍

控制字体行间距

1
2
3
.i-info{
line-height: 28px;
}

a标签字体去掉下划线

1
<a href="/" style="text-decoration:none">

Js实现页面跳转

1
<a shref='http://localhost:8181/download/2/web安全.md' download="web安全.md"></a>

例如a标签的跳转,可下载文件等。

1
2
window.location.href = 'http://www.baidu.com'  //当前页面打开
window.open('http://www.baidu.com') //新窗口打开

Vue相关

Element的下拉菜单点击事件无反应

1
<el-dropdown-item @click.native="out">退出</el-dropdown-item>

在@click后加.native


Vue中使用Cookie

安装:npm install js-cookie --save

在main.js中全局注册:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import jsCookie from 'js-cookie'

Vue.prototype.$cookie = jsCookie;

Vue.config.productionTip = false

new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
1
this.$cookie.set("token",res.data.data)//关闭浏览器自动失效

注意:axios默认不携带cookie,需设置axios.defaults.withCredentials = true


在Vue中如何使用markdown编辑器

安装:npm install mavon-editor --save

在main.js中全局注册:

1
2
3
4
5
6
// 全局注册
import Vue from 'vue'
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
// use
Vue.use(mavonEditor)

在页面使用组件即可:

1
<mavon-editor v-model="ruleForm.content"></mavon-editor>

效果如下:

对于后台请求过来的markdown格式文章如何解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template中使用该组件: :value是要展示的markdown格式内容
<mavon-editor
:value="this.blog.content"
:subfield="prop.subfield"
:defaultOpen="prop.defaultOpen"
:toolbarsFlag="prop.toolbarsFlag"
:editable="prop.editable"
:scrollStyle="prop.scrollStyle"
></mavon-editor>

script中添加该组件相关的计算属性:
computed: {
prop () {
let data = {
subfield: false,// 单双栏模式
defaultOpen: 'preview',//edit: 默认展示编辑区域 , preview: 默认展示预览区域
editable: false,
toolbarsFlag: false,
scrollStyle: true
}
return data
}
},

更多配置看mavonEditor的Github


Element UI导航菜单组件双击报错解决

1
2
3
4
5
6
7
8
9
10
11
12
13
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

//导航菜单组件双击报错解决
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}

前端路由权限拦截

  • 我们后台的操作界面需要登录后才可以访问,所以我们在路由映射的meta里配置该路由是否需要权限才能访问:requireAuth: true/false
  • 用户登录成功时通过设置sessionStorage(存储客户端临时信息的对象)标志该用户已登录:sessionStorage.setItem('isLogin',true)
  • 一旦所有窗口或标签页被关闭,那么所有通过sessionStorage存储的数据也就被清空了。
  • 通过全局前置守卫,判断每次将要进入的路由是否需要权限,如果不需要权限或需要权限且已经登录,那么直接放行,否则重定向到登录页面。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const routes = [
...
{
path: '/login',
component: () => import("../views/Login"),
meta: {
title: "管理员登录"
}
},
{
path: '/manage',
component: () => import("../views/Manage"),
children: [
{
path: '',
redirect: 'editTable'
},
{
path: 'editTable',
component: () => import("../components/EditTable"),
meta: {
title: "后台管理",
requireAuth: true
}
]
}
]

const router = new VueRouter({
routes,
mode: 'history'
})

//路由权限拦截
router.beforeEach((to, from, next) => {
if (to.meta.requireAuth) {
const isLogin = sessionStorage.getItem("isLogin")
if (isLogin) {
next()
} else {
next({
path: '/login'
})
}
} else {
next()
}
})

为了优化用户体验,避免多次登录,我们可以设置跳转登录页面的方法为:

1
2
3
4
5
if (sessionStorage.getItem("isLogin")){
this.$router.push('/manage')
}else {
this.$router.push('/login')
}

一刷新页面vuex的state数据丢失

因为store里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,store里面的数据就会被重新赋值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<div id="app">
<router-view></router-view>
</div>
</template>

<script>
export default {
name: 'App',
created() {
//在页面加载时读取sessionStorage里的状态信息
if (sessionStorage.getItem("store")) {
this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem("store"))))
}

//在页面刷新时将vuex里的信息保存到sessionStorage里
window.addEventListener("beforeunload", () => {
sessionStorage.setItem("store", JSON.stringify(this.$store.state))
})
}
}
</script>
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
}
</style>

Element 侧边栏、头部固定

1
2
3
4
5
6
7
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
</el-container>

布局如上,要求当el-main长度过长时可以滚动,但是顶部和侧边固定,添加如下样式即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.el-aside {
display: block;
position: absolute;
left: 0;
top: 60px;
bottom: 0;
}
.el-main {
position: absolute;
left: 200px;
right: 0;
top: 60px;
bottom: 0;
overflow-y: scroll;
}

Element 路由刷新和导航栏菜单状态保持一致

当网页刷新或回退时,导航栏的当前激活菜单与路由地址不匹配。我们可以通过侦听器(watch)侦听路由地址的变化使它们一致:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<template>
<div>
<el-menu
:default-active="activeIndex"
router
class="el-menu-vertical-demo"
>
<el-menu-item index="/center/homePage">
<i class="el-icon-s-home"/>
<span slot="title">首页</span>
</el-menu-item>
<el-menu-item index="/center/notesPage">
<i class="el-icon-notebook-2"/>
<span slot="title">笔记</span>
</el-menu-item>
</el-menu>
</div>
</template>

<script>
export default {
name: "SideBar",
data() {
return {
activeIndex: "/center/homePage"
}
},
watch: {
$route () {
this.setCurrentRoute()
}
},
methods: {
setCurrentRoute () {
this.activeIndex = this.$route.path
},
},
created () {
this.setCurrentRoute()
},
}
</script>

<style scoped>
</style>


另外一种,适用于一个菜单包含多个地址的,比较实用的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<template>
<div>
<el-menu
:default-active="activeIndex"
class="el-menu-vertical-demo">
<el-menu-item index="1" @click="toHomePage">
<i class="el-icon-s-home"/>
<span slot="title">首页</span>
</el-menu-item>
<el-menu-item index="2" @click="toCoursePage">
<i class="el-icon-reading"/>
<span slot="title">课程</span>
</el-menu-item>
<el-menu-item index="3">
<i class="el-icon-message-solid"/>
<span slot="title">通知</span>
</el-menu-item>
<el-menu-item index="4" @click="toNotesPage">
<i class="el-icon-notebook-2"/>
<span slot="title">笔记</span>
</el-menu-item>
<el-menu-item index="5">
<i class="el-icon-chat-dot-square"/>
<span slot="title">讨论</span>
</el-menu-item>
</el-menu>
</div>
</template>

<script>
export default {
name: "SideBar",
data() {
return {
activeIndex: '1',
path: ''
}
},
methods: {
setCurrentRoute() {
this.path = this.$route.path
if (this.path === '/center/homePage') {
this.activeIndex = '1'
} else if (this.path === '/center/course') {
this.activeIndex = '2'
} else if (this.path.includes('ote')) {
this.activeIndex = '4'
}
},
toHomePage() {
this.$router.push('/center/homePage')
},
toCoursePage() {
this.$router.push('/center/course')
},
toNotesPage() {
this.$router.push('/center/notesPage')
},
},
watch: {
$route() {
this.setCurrentRoute()
}
},
created() {
this.setCurrentRoute()
}
}
</script>

<style scoped>
</style>

Element中竖向分割线长度调整

f12检查元素,复制样式到vue文件中进行修改

1
2
3
4
5
6
7
8
9
10
<style scoped>
.el-divider--vertical {
display: inline-block;
width: 1px;
height: 9em;
margin: 0 8px;
vertical-align: middle;
position: relative;
}
</style>

在Vue中使用阿里矢量图标

https://www.iconfont.cn/

  1. 将想要的图标添加至自己的项目中,在项目里点击symbol,查看在线链接,例如://at.alicdn.com/t/font_2372769_xa9myt9i5o.js

  2. 浏览器访问该链接,在项目src/assets下新建iconfont.js文件,并将所有代码复制到js文件中

  3. 在App.vue中引入:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <script>
    import './assets/iconfont.js'
    ...
    </script>
    <style>
    .icon {
    width: 1em;
    height: 1em;
    vertical-align: -0.15em;
    fill: currentColor;
    overflow: hidden;
    }
    </style>

    使用如下:

    1
    2
    3
    <svg class="icon" aria-hidden="true" style="font-size: 33px">
    <use xlink:href="#icon-gonggao1"></use>
    </svg>

官方文档的symbol方式如下:

symbol引用


这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 这种用法其实是做了一个svg的集合,与上面两种相比具有如下特点:

  • 支持多色图标了,不再受单色限制。
  • 通过一些技巧,支持像字体那样,通过font-size,color来调整样式。
  • 兼容性较差,支持 ie9+,及现代浏览器。
  • 浏览器渲染svg的性能一般,还不如png。

使用步骤如下:

第一步:拷贝项目下面生成的symbol代码:

1
>//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js

第二步:加入通用css代码(引入一次就行):

1
2
3
4
5
6
7
8
><style type="text/css">
.icon {
width: 1em; height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
></style>

第三步:挑选相应图标并获取类名,应用于页面:

1
2
3
><svg class="icon" aria-hidden="true">
<use xlink:href="#icon-xxx"></use>
></svg>

Element 中修改默认样式无效

第一种:使用深度作用选择器 /deep/

1
2
3
4
5
<style scoped>
.el-card__body /deep/ {
padding: 0px;
}
</style>

第二种:使用父级类名加>>> 深入符号直接强制更改

1.在父元素中写一个类名

img

2.然后通过f12审查元素找到子级默认样式的类名:

img

3.为不改变全局样式,使用父级类名加>>> 深入符号直接强制更改,即可完成效果:

img

浏览器控制台关于sockjs.js报错

错误如下:sockjs.js?9be2:1606 GET http://192.168.43.226:8080/sockjs-node/info?t=1584966826465 net::ERR_CONNECTION_TIMED_OUT

网上找到的原因说是:sockjs-node是一个JavaScript库,提供跨浏览器JavaScript的API,创建了一个低延迟、全双工的浏览器和web服务器之间通信通道。在项目运行以后,network会一直调用这个接口。如果没有使用,那么就一直会报这个异常。

解决方法:

1)找到/node_modules/sockjs-client/dist/sockjs.js文件
2)在1600行左右,注释掉self.xhr.send(payload);这一行,然后就可以解决了。

VUE表单验证报错(’validate’ )

报错如下:

1
[Vue warn]: Error in v-on handler: "TypeError: Cannot read property 'validate' of undefined"

解决:refs和ref名字保持一致,如果不行可以把refs后面的[ ]去掉试试

1
2
3
4
<el-form :model="unitForm" ref="unitForm" label-width="100px" class="demo-dynamic">
...
submitForm(unitForm) {
this.$refs.unitForm.validate((valid) => {

VUE表单验证报错(有值却报错)

Form表单验证踩坑(表单验证明明有值,却提示错误)

prop对应的不单单是rules规则里面的验证项,同时对应着我们form-item下的v-model的值。prop绑定的类要与el-form-item下的v-model的值相对应。

我是因为rules绑定了数组的某个字段而失败,修改后(注意prop的值):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<el-form-item
v-for="(unit, index) in unitForm.units"
:label="'第' + (index+2) + '章'"
:key="index"
:prop="`units[${index}].unitName`"
:rules="{required: true, message: '章节名称不能为空', trigger: 'blur'}">
<el-input v-model="unit.unitName" style="width: 270px"></el-input>
<el-button @click.prevent="removeUnit(unit)" style="margin-left: 20px">删除</el-button>
</el-form-item>

...

data() {
return {
unitForm: {
units: [{
unitId: '',
unitName: ''
}
],
unit1: {
unitId: '1',
unitName: 'dwqqw'
}
}
};
},

Element中抽屉去除标题自带蓝色框

1
2
3
/deep/ :focus {
outline: 0;
}