https://znasr.gitee.io/mywebsite
1.优化
//封装按钮 避免用户频繁点击 减少http请求 disable 控制是否可以点击
<template>
<div>
<div class="submit-box" @click="submitAction">
<div
:class="['submit', ...btnClass, { disable: disable }]"
:style="{ background: bgColor }"
>
<slot name="btnCon">提交</slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: "submitBtn",
props: {
disable: {
type: Boolean,
default: false
},
btnClass: {
type: Array,
default: () => []
},
bgColor: {
type: String,
default: ""
}
},
data() {
return {
time: 0
};
},
methods: {
submitAction() {
if (this.disable) return;
let now = new Date().getTime();
if (now - this.time > 1000) {
this.time = new Date().getTime();
this.$emit("submitAction");
}
}
}
};
</script>
<style scoped lang="less">
@import "../assets/css/main";
.submit-box {
width: 100%;
.submit {
width: 82%;
height: 1.11rem;
border-radius: 0.22rem;
margin: 0 auto;
background: #b11d2f;
text-align: center;
line-height: 1.11rem;
font-size: 30px;
font-weight: 400;
color: #fff;
border-radius: 40px;
}
.disable {
background: #ddd !important;
}
}
</style>
// 防止重复提交指令
const preventReClick = Vue.directive('preventReClick', {
bind(el, binding) {
el.addEventListener('click', () => {
if (!el.disabled) {
el.disabled = true;
setTimeout(() => {
el.disabled = false;
}, binding.value || 2000);
}
});
}
});
export { preventReClick };
import { preventReClick } from './direct';
Vue.use(preventReClick);
//按钮添加指令
<el-button v-prevent-re-click>登录</el-button>
// 防抖 防止用户频繁操作。只执行最后一次函数操作
throttling(fn, delay) {
// timer是闭包中的
let timer = null;
return (function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, arguments);
timer = null;
}, delay);
})();
}
//数组去重
unique(arr, prop) {
let newArr = [];
let Arr = [];
for (var i = 0; i < arr.length; i++) {
if (!arr[i].value) continue;
if (newArr.indexOf(arr[i][prop]) == -1) {
newArr.push(arr[i][prop]);
Arr.push(arr[i]);
}
}
return Arr;
},
/**
* 对象数组排序
* @param {*} prop 参数名字
* @param {*} rev 默认升序 arr.sort((a,b)=>{b-a})
* @returns arr.sort(sortby('age')) //根据年纪进行排序
*/
sortby(prop, rev = true) {
return function (a, b) {
let val1 = a[prop];
let val2 = b[prop];
return rev ? val1 - val2 : val2 - val1;
};
},
/**
* 保留两位整数补零
* @param n
* @returns {string}
*/
export function numZero(n) {
return n < 10 ? "0" + n : "" + n;
}
/**
* 获取Url的参数
* @param name
* @returns {string}
*/
export function getParam(name) {
const LocString = String(window.document.location.href);
let rs = new RegExp("(^|)" + name + "=([^&]*)(&|$)", "gi").exec(LocString),
tmp;
if (tmp === rs) {
return tmp[2];
}
return "";
}
/**
* 获取客户端是 Android 还是IOS 还是PC
* @returns {string}
*/
export function getDeviceType() {
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
// 判断iPhone|iPad|iPod|iOS
return "IOS";
} else if (/(Android)/i.test(navigator.userAgent)) {
// 判断Android
return "Android";
} else {
// pc
return "PC";
}
}
/**
* 日期数据格式转换
* @param time 时间戳
* @returns {string}
*/
export function fommterDate(time) {
let date = new Date(time);
return (
date.getFullYear() + "/" + (date.getMonth() + 1) + "/" + date.getDate()
);
}
/**
* 拼接url后边的参数
* @param params
* @returns {string}
*/
export function jsonToStr(params) {
let str = "";
for (let i in params) {
str += "&" + i + "=" + params[i];
}
return "?" + str.substring(1);
}
/**
* 判断是否为微信
* @returns {boolean}
*/
export function isWechat() {
var ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == "micromessenger") {
return true;
} else {
return false;
}
}
制作图标字体网站
IcoMoon App - Icon Font, SVG, PDF & PNG Generator
阿里巴巴图标库
iconfont-阿里巴巴矢量图标库
使用雪碧图
- 将多张图片合并到一张图片中,可以减小图片的总大小。
- 将多张图片合并成一张图片后,下载全部所需的资源,只需一次请求。可以减小建立连接的消耗。
2.使用cdn的方式外部加载一些资源,比如vue-router、axios等Vue的周边插件,在webpack.config.js里面,externals里面设置一些不必要打包的外部引用模块。然后在入门文件index.html里面通过cdn的方式引入需要的插件。
Vuex 为什么要分模块并且加命名空间?
模块: 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能会变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
命名空间: 默认情况下,模块内部的 action、mutation、getter是注册在全局命名空间的 --- 这样使得多个模块能够对同一 mutation 或 action 做出响应。如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced:true 的方式使其成为带命名的模块。当模块被注册后,他所有 getter、action、及 mutation 都会自动根据模块注册的路径调整命名。
mixins基础概况
混入 (mixins): 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
举个栗子:
定义一个混入对象
把混入对象混入到当前的组件中
mixins的特点
1 方法和参数在各组件中不共享
2 值为对象的选项,如methods,components等,选项会被合并,键冲突的组件会覆盖混入对象的
3 混合对象里的钩子函数在组件里的钩子函数之前调用
vue插槽 封装组建经常用到
// 子组建
<template>
<div class="child">
// 具名插槽
<slot name="up"></slot>
<h3>这里是子组件</h3>
// 具名插槽
<slot name="down"></slot>
// 匿名插槽
<slot></slot>
</div>
</template>
<template>
<div class="father">
<h3>这里是父组件</h3>
<child>
<div class="tmpl" slot="up">
<span>菜单1</span>
<span>菜单2</span>
</div>
<div class="tmpl" slot="down">
<span>菜单-1</span>
<span>菜单-2</span>
</div>
<div class="tmpl">
<span>菜单->1</span>
<span>菜单->2</span>
</div>
</child>
</div>
</template>
v-if 和 v-for 为什么不建议一起使用
v-for和v-if不要在同一标签中使用,因为解析时先解析v-for在解析v-if。如果遇到需要同时使用时可以考虑写成计算属性的方式。
computed 和 watch 的区别和运用的场景。
computed 是计算属性,依赖其它属性计算值,并且 computed 的值有缓存,职友集当计算值变化才会返回内容,他可以设置getter和setter。
watch 监听到值的变化就会执行回调,在回调中可以进行一系列的操作。
计算属性一般用在模板渲染中,某个值是依赖其它响应对象甚至是计算属性而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑。
- 加载渲染过程
- 父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
- 子组件更新过程
- 父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
- 父组件更新过程
- 父beforeUpdate -> 父updated
- 销毁过程
- 父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
-
这里只列举针对 Vue 的性能优化,整个项目的性能优化是一个大工程。
- 对象层级不要过深,否则性能就会差。(数组降纬)
- 不需要响应式的数据不要放在 data 中(可以使用 Object.freeze() 冻结数据)
- v-if 和 v-show 区分使用场景
- computed 和 watch 区分场景使用
- v-for 遍历必须加 key,key最好是id值,且避免同时使用 v-if
- 大数据列表和表格性能优化 - 虚拟列表 / 虚拟表格
- 防止内部泄露,组件销毁后把全局变量和时间销毁
- 图片懒加载
- 路由懒加载
- 异步路由
- 第三方插件的按需加载
- 适当采用 keep-alive 缓存组件
- 防抖、节流的运用
- 服务端渲染 SSR or 预渲
- key的讲解
- Vue2.0 v-for 中 :key 到底有什么用? - 知乎
vue的双向绑定原理及实现 - ____chen - 博客园
常用的插件
vuex持久化 vuex-persistedstate
lib-flexible/flexible; // 淘宝rem适配方案 移动端
Vue.component("Header", Header); // 自定义组建
@xunlei/vue-lazy-component //组件级懒加载方案
https://github.com/xunleif2e/vue-lazy-component/tree/master/demo