个人博客项目总结

个人博客项目总结

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和 routerroute的区别和联系

  1. router

    router为VueRouter的实例,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局对象,他包含了所有的路由,包含了许多关键的对象和属性。

    举例:history对象

    router . push({path:‘home’});
    在我们看来是切换路由,
    本质是向history栈中添加一个路由,
    即是在添加一个history记录。跳转链接用this.$router . push,和router-link,效果一样。

    方法:

    $router . replace({path:‘home’});//替换路由,没有历史记录

  2. route

    route相当于当前正在跳转的路由对象, 每一个路由都会有一个route对象,是一个局部的对象,可以从里面获取name,path,params,query等。 this.$route指的是当前路由对象,path/meta/query/params

    1. $route .path
      字符串,等于当前路由对象的路径,会被解析为绝对路径,如 "/home/news"
    2. $route .params
      对象,包含路由中的动态片段和全匹配片段的键值对
    3. $route .query 对象
      包含路由中查询参数的键值对。例如,对于 /home/news/detail/01?favorite=yes,
      会得到route.query.favorite == ‘yes’ 。
    4. $route .router
      路由规则所属的路由器(以及其所属的组件)。
    5. $route .matched
      数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
    6. $route .name
      当前路径的名字,如果没有使用具名路径,则名字为空。
    7. $route.path, $route.params, $route.name, $route.query这几个属性很容易理解,主要用于接收路由传递的参数
  3. routes

    routes:指创建vue-router路由实例的配置项。用来配置多个route路由对象

三、element- ui 组件库的使用

  1. 布局问题

    导航栏和展示页面的互不干扰------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>
  1. 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>
  1. 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: 提交信息不完整或者不符合规则

  1. Http Request Headers 缺失
  2. Http Request Body内容缺失或者类型错误(例如我要json,你发 xml )
  3. 超过指定时间范围内的可访问次数
  4. 标题或内容非法

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方法的区别
  1. change事件指的是当输入框内容发生改变时触发的事件,前提是失去了焦点,才会触发到change事件。可在单选框,复选框,文件上传等情况时使用。

  2. 当change事件当作文件上传时,可能会遇到连着上传相同文件时,第二次没有反应,或者上传一次文件会调好几次接口。

  3. 【针对于change事件上传文件调用多次接口问题】:在每次调用change事件之前先解绑,再加事件即可 unbind() 解绑

     $(that).children('input').unbind().
    change(function () {})
    
    1. 【连着上传相同文件时,第二次没有反应】:

      二个文件相同会导致不会触发change事件

  4. input事件是指当输入框内容发生改变时就会触发,实时触发,不用失去焦点

十二、定时器使用,setInterval() 和 setTimeout()

相同点:

  1. setTimeout()和setInterval()经常被用来处理延时和定时任务
  2. 两个函数的参数相同,第一个参数是要执行的code或句柄,第二个是延迟的毫秒数。

不同点:

  1. setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式
  2. 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);
  },
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值