自己整理常见问题

npm i报 code E404

1 npm config get registry

2 npm config set registry https://registry.npmjs.org/

3 npm unistall vue-loader -D

4 npm install vue-loader@13.7.2 -D

svn基本使用

1 下载svn及中文语言包

2 附带英文图案

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKfgflVk-1623896595753)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210517170441064.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XgKLfd96-1623896595756)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210517170448116.png)]

3 获取账号密码

4 输入服务器地址,进行代码拉取

5 右键文件夹,选择导出。也可选择版本或者最新。

6 检出和导出 检出受服务器控制,可进行提交。导出就仅仅是导出,无法提交。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-39YrV0LK-1623896595758)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518113440924.png)]

浏览器窗口变化

检测浏览器窗口变化,可以动态改变图片大小。onresize会触发两次,[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GdmhRjwa-1623896595760)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518093643253.png)]

常用的js中的offsetwidth,clientwidth,innerwidth

<script>
	元素视图属性

      offsetWidth 水平方向 width + 左右padding + 左右border-width
      offsetHeight 垂直方向 height + 上下padding + 上下border-width
      
      clientWidth 水平方向 width + 左右padding
      clientHeight 垂直方向 height + 上下padding
      
      offsetTop 获取当前元素到 定位父节点 的top方向的距离
      offsetLeft 获取当前元素到 定位父节点 的left方向的距离
      
      scrollWidth 元素内容真实的宽度,内容不超出盒子高度时为盒子的clientWidth
      scrollHeight 元素内容真实的高度,内容不超出盒子高度时为盒子的clientHeight

      
      
      
      Window视图属性
      
     (低版本IE浏览器[<IE9]不支持) 【自测包含滚动条,但网络教程都说不包含???】
      innerWidth 浏览器窗口可视区宽度(不包括浏览器控制台、菜单栏、工具栏) 
      innerHeight 浏览器窗口可视区高度(不包括浏览器控制台、菜单栏、工具栏)

      
      
      
      Document文档视图
      
     (低版本IE的innerWidth、innerHeight的代替方案)
      document.documentElement.clientWidth 浏览器窗口可视区宽度(不包括浏览器控制台、菜单栏、工具栏、滚动条)
      document.documentElement.clientHeight 浏览器窗口可视区高度(不包括浏览器控制台、菜单栏、工具栏、滚动条)
      
      document.documentElement.offsetHeight 获取整个文档的高度(包含body的margin)
      document.body.offsetHeight 获取整个文档的高度(不包含body的margin)
      
      document.documentElement.scrollTop 返回文档的滚动top方向的距离(当窗口发生滚动时值改变)
      document.documentElement.scrollLeft 返回文档的滚动left方向的距离(当窗口发生滚动时值改变)
      Document文档视图结束
      
      元素方法
      1. getBoundingClientRect() 获取元素到body
       bottom: 元素底边(包括border)到可视区最顶部的距离
       left: 元素最左边(不包括border)到可视区最左边的距离
       right: 元素最右边(包括border)到可视区最左边的距离
       top: 元素顶边(不包括border)到可视区最顶部的距离
       height: 元素的offsetHeight
       width: 元素的offsetWidth
       x: 元素左上角的x坐标 
       y: 元素左上角的y坐标 
      
      2. scrollIntoView() 让元素滚动到可视区
元素方法结束
</script>

检测输入的内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jQnkr6x8-1623896595762)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518094616872.png)]

document.onkeydown 键盘事件

e.keycode 键盘对应的状态码

e = e || window.event是js在事件处理兼容IE和非IE的写法

加上e = e || window.event ;e存在就用e不存在就用windon.event。

输出e和window.event的结果是一样的。

(window.event == undefined火狐浏览器会出现这个情况。

object.assign() 对象的深拷贝

用法
let obj=Object.assign(target, ...sources)    【target:目标对象】,【souce:源对象(可多个)】

this.$nextTick(()=>{})

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ie5PnEBP-1623896595763)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518101726924.png)]

this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。

假设我们更改了某个dom元素内部的文本,而这时候我们想直接打印出这个被改变后的文本是需要dom更新之后才会实现的,也就好比我们将打印输出的代码放在setTimeout(fn, 0)中;所以一般用在mounted中对dom节点进行操作。在created中获取不到dom节点,但是使用**this.$nextTick(()=>{})**就可以获取到

meta路由元信息做路由跳转验证

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9l2hqsce-1623896595763)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518110246258.png)]

1 requireAuth为true,表示路由需要验证。最简单,使用的方法

2 判断路径中是否包含某一字段,有弊端。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oViqYxG2-1623896595764)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518110848167.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b3X0DGjP-1623896595765)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518113604940.png)]

meta的其他属性

router.beforeEach((to, from, next)=>{
   if(to.meta.content) {     //路由发生变化时候修改meta中的content
      let head = document.getElementByTagName(‘head’)
      let meta = document.createElemnet('meta')
      document.querySelector('meta[name="keywords"]').setAttribute('content',to.meta.content.keywords)
      document.querySelector('meta[name="description"]').setAttribute('content',to.meta.content.description)
      meta.content = to.meta.content
      dead[0].appendChild(meta)
      
   }
   if(to.meta.title) {   //路由发生变化时候修改页面中的title
       document.title = to.meta.title
   }
   next()
})

~[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PaPLy79n-1623896595765)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518114616553.png)]

获取meta属性[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LHodsM3w-1623896595766)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518115732026.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qSZi4Fg3-1623896595767)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518144730209.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k5cTPGRp-1623896595768)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518144755138.png)]

用法一


通过name属性,为一个页面中不同的router-view渲染不同的组件,如:将上面代码的Hello渲染在 name为Hello的router-view中,将text渲染在name为text的router-view中。不设置name的将为默认的渲染组件。

<template>
  <div id="app">
     <router-view></router-view>
     <router-view  name="Hello"></router-view> //将渲染Hello组件
     <router-view  name="text"></router-view>   //将渲染text组件
  </div>
</template>
用法二
可以用name传参 使用$route.name获取组件name值
 <template>
  <div id="app">
    <p>{{ $route.name }}</p> //可以获取到渲染进来的组件的name值
    <router-view></router-view>
  </div>
</template>
用法三
用于pramas传参的引入 pramas必须用name来引入 query可以用name或者path来引入(不明白vue-router传参的可以参考我的另一篇文章vue-router中 query传参和params传参的区别和注意事项)

   var router = new VueRouter({
      routes: [
        { name:'register', path: '/register/:id/:name', component: register }
      ]
    })
   <router-link :to="{name:'register',params:{id:10,name:'lili'}}">注册</router-link>

vue的路由模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BeZ90H50-1623896595769)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518111312893.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tjNc8SG6-1623896595770)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518144409900.png)]

hash模式和history模式

1、大家都知道vue是一种单页应用,单页应用就是仅在页面初始化的时候加载相应的html/css/js一单页面加载完成,不会因为用户的操作而进行页面的重新加载或者跳转,用javascript动态的变化html的内容

优点: 良好的交互体验,用户不需要刷新页面,页面显示流畅, 良好的前后端工作分离模式,减轻服务器压力,
缺点: 不利于SEO,初次加载耗时比较多

2、hash模式

vue-router默认的是hash模式—使用URL的hash来模拟一个完整的URL,于是当URL改变的时候,页面不会重新加载,也就是单页应用了,当#后面的hash发生变化,不会导致浏览器向服务器发出请求,浏览器不发出请求就不会刷新页面,并且会触发hasChange这个事件,通过监听hash值的变化来实现更新页面部分内容的操作

对于hash模式会创建hashHistory对象,在访问不同的路由的时候,会发生两件事:
HashHistory.push()将新的路由添加到浏览器访问的历史的栈顶,和HasHistory.replace()替换到当前栈顶的路由

img

img

3、history模式

主要使用HTML5的pushState()和replaceState()这两个api来实现的,pushState()可以改变url地址且不会发送请求,replaceState()可以读取历史记录栈,还可以对浏览器记录进行修改

window.history.pushState(stateObject, title, URL)
window.history.replaceState(stateObject, title, URL)

包括back,forward , go 三个方法

history.go(-2);//后退两次
history.go(2);//前进两次
history.back(); //后退
hsitory.forward();//前进

区别:

前面的hashchange,你只能改变#后面的url片段。而pushState设置的新URL可以是与当前URL同源的任意URL。
history模式则会将URL修改得就和正常请求后端的URL一样,如后端没有配置对应/user/id的路由处理,则会返回404错误

v-once

只渲染元素和组件一次,随后的渲染,使用了此指令的元素/组件及其所有的子节点,都会当作静态内容并跳过,这可以用于优化更新性能

常见用法如下:

当修改input框的值时,使用了v-once指令的p元素不会随之改变,而第二个p元素时可以随之改变的

<div id="app">
		<p v-once>{{msg}}</p>  //msg不会改变
		<p>{{msg}}</p>
		<p>
			<input type="text" v-model = "msg" name="">
		</p>
	</div>
	<script type="text/javascript">
		let vm = new Vue({
			el : '#app',
			data : {
				msg : "hello"
			}
		});
	</script>

怎么防止用户点击统一按钮

1 防抖和节流
2 点击按钮后跳转页面,或者将按钮变为不可选,或者将已填写的数据变为空。
禁止短时间内多次点击
export default {
  install(Vue) {
    // 禁止短时间内重复点击
    Vue.directive('preventClick', {
      inserted(button, bind) {
        button.addEventListener('click', () => {
          if (!button.disabled) {
            button.disabled = true;
            setTimeout(() => {
              but.disabled = false
            }, 6000)
          }
        })
      }
    })
  }
}

wangEditor富文本

toISOString

使用 toISOString() 转换日期时,会丢失时区,这也就导致不论我插入的日期是什么,总会少 8 小时。所以直接加上8个小时

toISOString() 方法可以使用ISO标准将 Date 对象转换为字符串。该标准称为 ISO-8601 ,格式为: YYYY-MM-DDTHH:mm:ss.sssZ

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vh5USFZt-1623896595773)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518175511727.png)]

 filters: {
        formatDate(value) {
            var dateee = new Date(value).toJSON();
            var date = new Date(+new Date(dateee) + 8 * 3600 * 1000)
                .toISOString()
                .replace(/T/g, " ")
                .replace(/\.[\d]{3}Z/, "");
            return date;
        },
    },

responseType: “blob”

elementui的tab设置

formatter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-49UVLiyW-1623896595774)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210519133158916.png)]

a标签的下载

检测当前浏览器是否支持download属性:
let canSupportDownload = 'download' in document.createElement('a');
下载一张图片
1. 使用href属性,指定图片地址:
<a href='./img/img01.jpg'>查看图片</a>
这样的情况,我们得到的效果是,页面跳转到指定的url地址。
2. 增加download属性试试:
<a href="./img/img01.jpg" download="dog.jpg">下载图片</a>

.native .sync

.native 当绑定的点击事件不生效时,可以尝试使用。

.sync  用于父子组件   自定义事件   elementui的分页支持该修饰符


//父组件给子组件传入一个函数
 <MyFooter :age="age" @setAge="(res)=> age = res">
 </MyFooter>
 //子组件通过调用这个函数来实现修改父组件的状态。
 mounted () {
      console.log(this.$emit('setAge',1234567));
 }




//父组件将age传给子组件并使用.sync修饰符。
<MyFooter :age.sync="age">
</MyFooter>
//子组件触发事件
 mounted () {
    console.log(this.$emit('update:age',1234567));
 }

update:是被固定的也就是vue为我们约定好的名称部分

vue的过滤器

export default中的name属性

判断是否是nan

let a = isNaN(data)

elementui

elementui样式作用不上去

1 很有可能是scoped的影响,原因未知。

为避免影响其他页面的样式,可以在最外层添加一个大的div,并设置id

2 设置/deep/ 不用去掉scoped 使用层级选择器,只需要给**最外层**的添加/deep/

3 不使用less或scss,可以使用深度选择器>>>

4 vue支持多个style

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e6gMB9lQ-1623896595775)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518103431304.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EkbIao9p-1623896595776)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210518103445669.png)]

elementui常见样式修改

修改分页器按钮颜色 页数和最大条数变化都会触发事件
    .block {
        .el-pagination {
            color: white;
            .el-pager {
            }
        }
    }


slot插槽自定义属性,需要在layout进行配置
修改下拉框,输入框颜色,以及下拉箭头位置
.el-select {
    height: 32px;
    width: 280px;
    /deep/ .el-input {
        .el-input__suffix {
            right: -122px;
        }
        input {
            width: 280px;
            height: 32px;
            line-height: 32px;
            background: radial-gradient(
                circle,
                rgba(16, 234, 166, 0.26) 0%,
                rgba(16, 234, 166, 0.1) 100%
            );
            opacity: 1;
        }
    }
}
上传图片失败
注意控件 name 的值
input失焦事件
 <el-input
        @blur="onBlur"
        placeholder="请输入物种名称">
 </el-input>

elementui上传图片

1.引入样式,将action改为上传地址
2.注意加name属性
3.调用上传成功的函数,将res的返回结果添加到data中传给后端

elementui表单自带验证

动态绑定rules

设置加载动画

1  给按钮设置提交成功后的加载动画
<el-button
size="small"
v-if="saveBtnShow"
class="camera-btn2"
@click.native="saveDataZzzy"
:loading="loadingButton">保存</el-button>
2  给弹窗设置点击编辑时数据过多引起的数据为空
(1)
加载部分页面
(2)
加载整个页面,在最外面的div添加
<div
v-loading="tckloading"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)">
    
</div>

echarts

echarts样式修改

1.收藏夹有基础配置

修改图标的样式formatter

 this.option = {
                tooltip: {
                    trigger: "item",
                },
                title: {
                    x: "35%",
                    y: "38%",
                    //   subtext: "{a|总数量} \n {b|222}",
                    subtextStyle: {
                        rich: {
                            a: {
                                fontSize: 14,
                                padding: [5, 55],
                            },
                            b: {
                                color: "white",
                                padding: [3, 50],
                                fontSize: 16,
                            },
                        },
                    },
                },
                legend: {
                    //图标位置
                    top: "15%",
                    right: "5%",
                    orient: "vertical",
                    itemGap: 20,
                    formatter: function (name) {
                        for (let i = 0; i < data.length; i++) {
                            if (data[i].Name == name) {
                                let perStr =
                                    (data[i].Percent * 100).toFixed(2) + "%";
                                console.log(
                                    name + "\xa0" + "|" + "\xa0" + perStr
                                );
                                return (
                                    //"\xa0"  相当于是空格
                                    name +
                                    "\xa0" +
                                    "\xa0" +
                                    "\xa0" +
                                    "\xa0" +
                                    "\xa0" +
                                    "|" +
                                    "\xa0" +
                                    "\xa0" +
                                    "\xa0" +
                                    "\xa0" +
                                    perStr
                                );
                            }
                        }
                        // return name;
                    },
                },
                series: [
                    {
                        name: "数据",
                        type: "pie",
                        radius: ["40%", "55%"], //调整大小
                        avoidLabelOverlap: false,
                        center: ["30%", "50%"], //调整位置
                        itemStyle: {
                            normal: {
                                label: {
                                    show: true, //隐藏标示文字
                                },
                                labelLine: {
                                    //引导线长度
                                    show: true,
                                    length: 30,
                                    length2: 60,
                                    maxSurfaceAngle: 80, //隐藏标示线
                                },
                            },
                        },

                        emphasis: {
                            label: {
                                show: true,
                                fontSize: "30",
                                fontWeight: "bold",
                            },
                        },

                        data: data.map((item) => {
                            return {
                                name: item.Name,
                                value: item.Sum,
                            };
                        }),
                    },
                ],
            };

效果图[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-neZ1AS9r-1623896595777)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210610163942271.png)]

wangeditor富文本

解析富文本

        //转义
        Formatter(row, column) {
            console.log("转义", row);
            var textstr =
                row.NEIRONG.replace(/<[^>]*>|/g, "").substr(0, 15) + "...";
            console.log("textstr", textstr);
            return textstr;
        },

node启动问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IhohosCU-1623896595778)(C:\Users\hky\AppData\Roaming\Typora\typora-user-images\image-20210615165240306.png)]

npm install -g nodemon

无感token刷新

/* 是否有请求正在刷新token */
window.isRefreshing = false
/* 被挂起的请求数组 */
let refreshSubscribers = []

/* push所有请求到数组中 */
function subscribeTokenRefresh(cb) {
  refreshSubscribers.push(cb)
}

/* 刷新请求(refreshSubscribers数组中的请求得到新的token之后会自执行,用新的token去请求数据) */
function onRrefreshed(token) {
  refreshSubscribers.map(cb => cb(token))
}

const fetch = axios.create({
  baseURL: '',
  timeout: '30000'
})

function computedTime() {
  let r = getRefresh();
  if (!r || !r.expires_in) return false;
  let currentTime = Date.parse(new Date()) / 1000;
  let expiresTime = r.expires_in;
  // 600秒后即将过期,true则不需要刷新
  return expiresTime - currentTime <= 600
}
fetch.interceptors.request.use(async (config) => {
  if (config.url !== '/oauth/token') {//获取token的接口不进行拦截
    getToken() && (config.headers.Authorization = getToken());
    if (computedTime()) {
      if (!window.isRefreshing) {
        window.isRefreshing = true;
        let r = getRefresh();
        if (!r) return;
        let refreshData = {
          grant_type: 'refresh_token',
          client_id: r.client_id,
          client_secret: r.client_secret,
          refresh_token: r.refresh_token
        }
        getTokens(refreshData).then((data) => {
          window.isRefreshing = false;
          let rData = {
            client_id: r.client_id,
            client_secret: r.client_secret,
            expires_in: (Date.parse(new Date()) / 1000 + data.expires_in),
            grant_type: 'refresh_token',
            org_id: r.org_id,
            refresh_token: r.refresh_token
          }
          // 存储token,存进cookie里面
          store.commit('setTokenInfo', data.token_type + data.access_token);
          // 存储refresh_token
          store.commit('setRefreshToken', rData);
          onRrefreshed(data.token_type + data.access_token);
          /* 执行onRefreshed函数后清空数组中保存的请求 */
          refreshSubscribers = [];
        }).catch(err => {
          console.log(err);
          router.replace({
            path: '/login'
          })
        })
      }
      /* 把请求(token)=>{....}都push到一个数组中 */
      let retry = new Promise((resolve, reject) => {
        /* (token) => {...}这个函数就是回调函数 */
        subscribeTokenRefresh((token) => {
          config.headers.Authorization = token
          /* 将请求挂起 */
          resolve(config)
        })
      })
      return retry
    } else {
      return config
    }
  } else {
    return config
  }
}, (error) => {
  return Promise.reject(error);
})

a);
onRrefreshed(data.token_type + data.access_token);
/* 执行onRefreshed函数后清空数组中保存的请求 /
refreshSubscribers = [];
}).catch(err => {
console.log(err);
router.replace({
path: ‘/login’
})
})
}
/
把请求(token)=>{…}都push到一个数组中 /
let retry = new Promise((resolve, reject) => {
/
(token) => {…}这个函数就是回调函数 /
subscribeTokenRefresh((token) => {
config.headers.Authorization = token
/
将请求挂起 */
resolve(config)
})
})
return retry
} else {
return config
}
} else {
return config
}
}, (error) => {
return Promise.reject(error);
})


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值