个人博客项目总结
文章目录
- 个人博客项目总结
- vue
- 一、深度选择器
- 二、 r o u t e r 和 router和 router和route的区别和联系
- 三、element- ui 组件库的使用
- 四、接口调用
- 五、报错码的意思
- 六、把对象添加到数组中的方法
- 七、qs.stringify() 和 JSON.stringify() (序列化)
- 八、 把后台的数据转化成适合组件用的结构(留言管理)
- 九、v- md -editor上传本地图片
- 十、点击两次才能选中多选框的原因
- 十一、当跳转到别的页面的时候,markdown编译器无法保存编写的内容。(保存无效)
- 十二、定时器使用,setInterval() 和 setTimeout()
- 十三、 *el-table加上row-key="id"会出现 Error in render: "Error: for nested data item, row-key is required."错误*
- 十四、keep-alive的activated和deactivated阶段
- 十五、Watch
- 十六、vue路由传参
- 十七、VUE+ element ui面包屑实现动态路由
- 十八、当提交留言和下拉刷新冲突
- css
- javaScript
vue
一、深度选择器
我们使用scoped实现组件的私有化,不对全局造成样式污染,表示当前style属性只属于当前模块。但我们难免会用到一些框架如element vant 等,我们想要修改其中样式时,如果使用了scoped,则需要深度选择器来进行样式的更改
三种方法:>>> /deep/ ::v-deep
<style lang='css' scoped>
//1.
.a >>> .b{
}
//2.
.a{
/deep/ .b{
}
}
//3.
.a{
::v-deep .b{
}
}
</style>
二、 r o u t e r 和 router和 router和route的区别和联系
-
router
router为VueRouter的实例,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局对象,他包含了所有的路由,包含了许多关键的对象和属性。
举例:history对象
router . push({path:‘home’});
在我们看来是切换路由,
本质是向history栈中添加一个路由,
即是在添加一个history记录。跳转链接用this.$router . push,和router-link,效果一样。方法:
$router . replace({path:‘home’});//替换路由,没有历史记录
-
route
route相当于当前正在跳转的路由对象, 每一个路由都会有一个route对象,是一个局部的对象,可以从里面获取name,path,params,query等。 this.$route指的是当前路由对象,path/meta/query/params
- $route .path
字符串,等于当前路由对象的路径,会被解析为绝对路径,如"/home/news"
。 - $route .params
对象,包含路由中的动态片段和全匹配片段的键值对 - $route .query 对象
包含路由中查询参数的键值对。例如,对于 /home/news/detail/01?favorite=yes,
会得到route.query.favorite == ‘yes’ 。 - $route .router
路由规则所属的路由器(以及其所属的组件)。 - $route .matched
数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。 - $route .name
当前路径的名字,如果没有使用具名路径,则名字为空。 $route.path, $route.params, $route.name, $route.query
这几个属性很容易理解,主要用于接收路由传递的参数
- $route .path
-
routes
routes:指创建vue-router路由实例的配置项。用来配置多个route路由对象
三、element- ui 组件库的使用
<template>
<div class="index">
<el-container id="el-container">
<!-- 侧边导航栏 -->
<slide-bar></slide-bar>
<el-container>
<!-- 头部 -->
<el-header>
</el-header>
<!-- 主体 -->
<el-main>
<router-view/>
</el-main>
</el-container>
</el-container>
</div>
</template>
-
v-for渲染表格数据内容,但是单独的一列需要修改或者上传图片应该怎么办。
解决方法:不用v-for,用插槽改变,多看组件的文档。
<el-table-column prop="email" label="QQ"></el-table-column>
<el-table-column prop="headImg" *label*="头像">
<template slot-scope*="scope">
<el-avatar size="small" :src="scope.row.headImg"></el-avatar>
</template>
</el-table-column>
<el-table-column prop="nickname" label="昵称"></el-table-column>
- sex和图像的转化问题
错误的
//设置女的sex为0,男的sex为1
// sexValue(){
// console.log("转换性别形式");
// for(let i=0;i<this.tableData.length;i++){
// console.log(this.tableData)
// if(this.tableData[i].sex=0){
// this.tableData[i].sex="女"
// }else{
// this.tableData[i].sex="男"
// }
// }
// },
//后台数据sex=0/1,但是界面渲染的是男、女
这个方法改变的是后台数据,不适合
四、接口调用
get post put delete 四种方法
PUT(增),DELETE(删),POST(改),GET(查)
传给的参数(分为必须或者不必须),传回的参数固定,但是可以需要什么渲染什么。
axios的几种方法,
get---->params 要用?拼接
export* function initData(url, params) {
*return* request({
url: url + '?' + qs.stringify(params, {
indices: false
}),
method: 'get'
})
}
get,delete一样
post,put一样
五、报错码的意思
400: 提交信息不完整或者不符合规则
- Http Request Headers 缺失
- Http Request Body内容缺失或者类型错误(例如我要json,你发 xml )
- 超过指定时间范围内的可访问次数
- 标题或内容非法
401:没有登录
404:连接接口写错了, 路径错误或拼写错误
405:方法不被允许
408:请求超时
412:请求参数错误
500:服务器错误
特殊情况:network里显示200,但是console里显示500
六、把对象添加到数组中的方法
array .push( list 1);(留言管理)
七、qs.stringify() 和 JSON.stringify() (序列化)
qs.stringify()
1.qs.stringify
是把一个参数对象格式化为一个字符串。
2.指定数组编码格式
let params = [1, 2, 3];
// indices(默认)
qs.stringify({a: params}, {arrayFormat: 'indices'})
// 结果是'a[0]=1&a[1]=2&a[2]=3'
// brackets
qs.stringify({a: params}, {arrayFormat: 'brackets'})
// 结果是'a[]=1&a[]=2&a[]=3'
// repeat
qs.stringify({a: params}, {arrayFormat: 'repeat'})
// 结果是'a=1&a=2&a=3'
3.处理 json 格式的参数
在默认情况下,json格式的参数会用 []
方式编码,
let json = { a: { b: { c: 'd', e: 'f' } } }; qs.stringify(json);
//结果 'a[b][c]=d&a[b][e]=f'
但是某些服务端框架,并不能很好的处理这种格式,所以需要转为下面的格式
qs.stringify(json, {allowDots: true});//结果 'a.b.c=d&a.b.e=f'
例子:假设我要提交的数据如下
var a = {name:'hehe',age:10};
区别
qs.stringify序列化结果如下
name=hehe&age=10
JSON.stringify序列化结果如下:
"{"a":"hehe","age":10}"
八、 把后台的数据转化成适合组件用的结构(留言管理)
//条件查询留言
async get_words(){
let get_words_con = {
nickname: this.form.nickname,
lwContent: this.form.lwContent,
page: this.form.page,
size: this.form.size,
}
console.log(get_words_con)
await getWords(get_words_con).then((res) => {
console.log(res, "res")
this.words.totalElements=res.data.totalElements
// console.log(res.data.totalElements);
//leaveWordArray為留言數組
var leaveWordArray = res.data.array;
let array = []; //定义一个临时数组,聚集所有对象,防止调用一次,就多增加数据的错误
for (let i = 0; i < leaveWordArray.length; i++) {
var list1 = leaveWordArray[i].leaveOne; //list1一級評論
if (leaveWordArray[i].leaveTwoList.length > 0) {
list1.children = leaveWordArray[i].leaveTwoList;
}
array.push(list1); //把每个对象都加入到数组里
// console.log(list1);
// this.tableData.forEach(list1);
}
this.tableData = array;
// console.log("---------------------");
// console.log(this.tableData,"this.tableData");
})
.catch((err) => {
console.log("返回错误", err);
});
},
九、v- md -editor上传本地图片
//上传图片菜单默认为禁用状态 设置 disabled-menus 为空数组可以开启。 @upload-image="handleUploadImage"调用此方法
<v-md-editor v-model="content" height="400px" :disabled-menus="[]" @upload-image="handleUploadImage"></v-md-editor>
//上传图片的方法
handleUploadImage(event, insertImage, files) {
// 拿到 files 之后上传到文件服务器,然后向编辑框中插入对应的内容
console.log(files,"files");
var params = new FormData();
params.append("pic",files[0])//pic参数需要与接口参数相一致
//上传文件接口
uploadImg(params)
.then(res => {
console.log(res,"res")//返回res为图片的地址
insertImage({
url:res,
width: 'auto',
height: 'auto',
})
})
.catch(err => {
console.log("返回错误", err);
});
},
//上传文件
export function uploadImg(data) {
return request({
url:'api/upload',
method: 'post',
data:data,
headers:{'Content-Type':'multipart/form-data'}
//一直要设置方法头为{'Content-Type':'multipart/form-data'}
})
}
十、点击两次才能选中多选框的原因
对比方法的差异
错误方法:
<el-checkbox label="置顶" @change="changeTop"
v-model="flag"></el-checkbox>
// 改变置顶格式,把boolean转化为0/1
changeTop() {
console.log(this.flag,"this.flag");
this.flag = !this.flag;//设置方法改变flag的值
if (this.flag == false) {
this.top = 0
} else {
this.top = 1;
}
},
正确方法:
<el-checkbox label="置顶" @change="changeTop"
v-model="flag"></el-checkbox>
//flag值不需要设置方法改变,
//选中复选框的时候flag=true,未选中的时候flag=false
// 改变置顶格式,把boolean转化为0/1
changeTop() {
console.log(this.flag,"this.flag");
if (this.flag == false) {
this.top = 0
} else {
this.top = 1;
}
},
//但是会出现一个问题,就是@change这个方法只能知道选中状态是否改变,是不知道到底是选中还是未选中。所以触发change方法后需要清空原本的top,flag值,避免上一次的选择干扰到这一次的选择。
十一、当跳转到别的页面的时候,markdown编译器无法保存编写的内容。(保存无效)
<el-main>
<keep-alive>
<router-view/>
</keep-alive>
</el-main>
用到keep-alive(路由守卫),把切换侧边栏展示的内容保存下来。
当文本框输入的内容改变,用的是@change、@input
change方法和input方法的区别
-
change事件指的是当输入框内容发生改变时触发的事件,前提是失去了焦点,才会触发到change事件。可在单选框,复选框,文件上传等情况时使用。
-
当change事件当作文件上传时,可能会遇到连着上传相同文件时,第二次没有反应,或者上传一次文件会调好几次接口。
-
【针对于change事件上传文件调用多次接口问题】:在每次调用change事件之前先解绑,再加事件即可
unbind()
解绑$(that).children('input').unbind(). change(function () {})
-
【连着上传相同文件时,第二次没有反应】:
二个文件相同会导致不会触发change事件
-
-
input事件是指当输入框内容发生改变时就会触发,实时触发,不用失去焦点
十二、定时器使用,setInterval() 和 setTimeout()
相同点:
- setTimeout()和setInterval()经常被用来处理延时和定时任务
- 两个函数的参数相同,第一个参数是要执行的code或句柄,第二个是延迟的毫秒数。
不同点:
- setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式
- setInterval()则可以在每隔指定的毫秒数循环调用函数或表达式,直到clearInterval把它清除
JavaScript其实是运行在单线程的环境中的,这就意味着定时器仅仅是计划代码在未来的某个时间执行,而具体执行时机是不能保证的,因为页面的生命周期中,不同时间可能有其他代码在控制JavaScript进程。在页面下载完成后代码的运行、事件处理程序、Ajax回调函数都是使用同样的线程,实际上浏览器负责进行排序,指派某段程序在某个时间点运行的****优先级****
自动保存的定时器使用
<v-md-editor @input="save" v-model="content" height="400px" :disabled-menus="[]" @upload-image="handleUploadImage">
</v-md-editor>
//保存文本
save(){
clearTimeout(this.timer)
this.timer= setTimeout(()=>{
this.publish=0
this.is_publish()
console.log("3秒");
},1000)
实现了连续写文本的时候不保存,当停下来一秒后保存
十三、 el-table加上row-key="id"会出现 Error in render: "Error: for nested data item, row-key is required."错误
原因在于id的值要独一无二,需要用随机数
<el-table
:data="tableData"
style="width: 100%; margin-bottom: 20px"
default-expand-all
row-key="id"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
></el-table>
//条件查询留言
async get_words(){
let get_words_con = {
nickname: this.form.nickname,
lwContent: this.form.lwContent,
page: this.form.page,
size: this.form.size,
}
console.log(get_words_con)
await getWords(get_words_con).then((res) => {
console.log(res, "res")
this.words.totalElements=res.data.totalElements
// console.log(res.data.totalElements);
//leaveWordArray為留言數組
var leaveWordArray = res.data.array;
let array = []; //定义一个临时数组,聚集所有对象,防止调用一次,就多增加数据的错误
for (let i = 0; i < leaveWordArray.length; i++) {
var list1 = leaveWordArray[i].leaveOne; //list1一級評論
list1.id=this.showReply();
if (leaveWordArray[i].leaveTwoList.length > 0) {
list1.children = leaveWordArray[i].leaveTwoList;
for(let a =0; a<list1.children.length; a++){
list1.children[a].id=this.showReply();
}
}
array.push(list1); //把每个对象都加入到数组里
// console.log(list1);
// this.tableData.forEach(list1);
}
this.tableData = array;
// console.log("---------------------");
// console.log(this.tableData,"this.tableData");
})
.catch((err) => {
console.log("返回错误", err);
});
},
//随机数
showReply() {
// 0x 表示16进制数据的开头
//可以直接return (((1+Math.random())*0x10000)|0).toString(16);
//也可用如下,随机数*时间戳,再转化为16进制
//Number.toString(16) 表示将其转换为16进制
// Number | 0 表示取整数部分
let stamp = new Date().getTime();
return (((1+Math.random())*stamp)|0).toString(16);
},
十四、keep-alive的activated和deactivated阶段
当使用keep-alive的时候,我们正常的钩子函数就没办法执行了,这个时候activated和deactivated就会执行。
我们做一个项目的时候,一个功能是引用了组件中的数据,我们需要每次进去的时候都最新的值给传递过去,更新掉 。
注意点:
- activated和deactivated是配合keep-alive一起使用的
- activated和deactivated没有keep-alive的时候是不会被触发的
- 在存在keep-alive的时候可以将activated当作created进行使用
- deactivated是组件销毁的时候触发,此时的destory是不执行的
十五、Watch
Watch概述
一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。
immediate(立即处理 进入页面就触发)
deep(深度监听)
对象和数组都是引用类型,引用类型变量存的是地址,地址没有变,所以不会触发watch。这时我们需要进行深度监听,就需要加上一个属性 deep,值为 true
Watch和computed的区别
Watch
watch用于观察和监听页面上的vue实例,当你需要在数据变化响应时,执行异步操作,或高性能消耗的操作,那么watch为最佳选择
computed
可以关联多个实时计算的对象,当这些对象中的其中一个改变时都会触发这个属性
具有缓存能力,所以只有当数据再次改变时才会重新渲染,否则就会直接拿取缓存中的数据。
十六、vue路由传参
1、 this.$router .push进行编程式路由跳转
2、 router-link 进行页面按钮式路由跳转
3、 this.$route .params 获取路由传递参数
4、this.$route .query 获取路由传递参数
5、 params 和 query 都是传递参数的,params不会在url上面出现,并且params参数是路由的一部分,是一定要存在的 query则是我们通常看到的url后面的跟在?后面的显示参数
在子组件中获取参数的时候是route . params 而 不 是 route .params 而不是route .params而不是router ,这很重要
this.$router.push({
path: "writeArticle",
query: { blogId: row.blogId },
});//组件一(bmanage)
this.blogId = this.$route.query.blogId;//组件二(writeArticle)
十七、VUE+ element ui面包屑实现动态路由
<el-breadcrumb separator="/">
<el-breadcrumb-item>Blog</el-breadcrumb-item>
<el-breadcrumb-item v-for="item in levelList" :key="item.path" :to="item.path">{{item.meta.title}} </el-breadcrumb-item>
</el-breadcrumb>
export default {
name: "index",
components: {
slideBar,
},
data(){
return{
levelList: []
}
},
//监听路由的变化
watch: {
$route() {
this.getBreadcrumb()
}
},
methods: {
//面包屑
getBreadcrumb() {
let matched = this.$route.matched.filter
(item => item.name)
for (let i = 0; i < matched.length; i++) {
if (matched[i].meta.title==null) {
matched.splice(i,1)
}
}
this.levelList = matched
}
},
十八、当提交留言和下拉刷新冲突
问题:提交留言新增加了一条数据,但是调用显示数据的方法时没有显示出来,必须要手动刷新一下才可以。
解决方法:刷新页面------location.reload();
css
1.侧边栏占据浏览器的100%
使用一个方法,在渲染之后设置侧边栏的高度为获取的窗口高度。使用动态窗口的效果。弊端是当使用控制台console时,会导致高端的变化,用户观感效果差。
//渲染之后设置侧边栏的高度为获取的窗口高度,
mounted() {
var winHeight = 700;
if (window.innerHeight) winHeight = window.innerHeight;
else if (document.body && document.body.clientHeight)
winHeight = document.body.clientHeight;
console.log(winHeight);
document.getElementById("el-container").style.minHeight = winHeight + "px";
console.log(document.getElementById("el-container").style.minHeight);
},
2. css去除input的边框,点击也不出现
.**title* input{
width:70%;
border:none;//重要的一点
outline:none;
float:left;
border-bottom: 1px solid #6a6e6e;
}
.title input:active{
border:none;
outline: none;
border-bottom: 1px solid #6a6e6e;
}
javaScript
1.侧边栏占据浏览器的100%
使用一个方法,在渲染之后设置侧边栏的高度为获取的窗口高度。使用动态窗口的效果。弊端是当使用控制台console时,会导致高端的变化,用户观感效果差。
//渲染之后设置侧边栏的高度为获取的窗口高度,
mounted() {
var winHeight = 700;
if (window.innerHeight) winHeight = window.innerHeight;
else if (document.body && document.body.clientHeight)
winHeight = document.body.clientHeight;
console.log(winHeight);
document.getElementById("el-container").style.minHeight = winHeight + "px";
console.log(document.getElementById("el-container").style.minHeight);
},