首页
视频
留言
壁纸
直播
下载
友链
统计
推荐
vue
在线工具
Search
1
ElasticSearch ES 安装 Kibana安装 设置密码
421 阅读
2
记一个报错GC overhead limit exceeded解决方法
344 阅读
3
Teamcity + Rancher + 阿里云Code 实现Devops 自动化部署
230 阅读
4
JAVA秒杀系统的简单实现(Redis+RabbitMQ)
209 阅读
5
分布式锁Redisson,完美解决高并发问题
206 阅读
JAVA开发
前端相关
Linux相关
电商开发
经验分享
电子书籍
个人随笔
行业资讯
其他
登录
/
注册
Search
标签搜索
AOP
支付
小说
docker
SpringBoot
XML
秒杀
K8S
RabbitMQ
工具类
Shiro
多线程
分布式锁
Redisson
接口防刷
Jenkins
Lewis
累计撰写
146
篇文章
累计收到
14
条评论
首页
栏目
JAVA开发
前端相关
Linux相关
电商开发
经验分享
电子书籍
个人随笔
行业资讯
其他
页面
视频
留言
壁纸
直播
下载
友链
统计
推荐
vue
在线工具
搜索到
11
篇与
的结果
2022-12-01
网站哀悼色实现方案-整个网页黑色调(哀悼色)CSS实现
整个网页黑色调(哀悼色)CSS实现body{ -webkit-filter: grayscale(100%); /* Chrome, Safari, Opera */ filter: grayscale(100%); }
2022年12月01日
50 阅读
0 评论
1 点赞
2022-08-23
数组对象push时去重
{mtitle title="方法一"/}var arr = [{id: '1', name: 'abc'}, {id: '3', name: 'abc'}]; var obj = {id: '2', name: 'abc'}; if (!JSON.stringify(arr).includes(JSON.stringify(obj))) { arr.push(obj); } console.log(JSON.stringify(arr));{mtitle title="方法二"/}var arr = [{match_id: '1', name: 'abc'}, {match_id: '3', name: 'abc'}]; var obj = {match_id: '2', name: 'abc'}; var map = arr.map(item=>({[item.match_id]: item})); if(map[obj.match_id]){ map[obj.match_id] = obj;// 更新对象 arr = Object.values(map); // map 转 arr } else { arr.push(obj); } console.log(JSON.stringify(arr)); // [{"match_id":"1","name":"abc"},{"match_id":"3","name":"abc"},{"match_id":"2","name":"abc"}]
2022年08月23日
38 阅读
0 评论
0 点赞
2022-07-29
vue3 父子组件之间的传值
第一种使用 defineProps,defineEmits父传子:parent.vue<template> <div> <child :value="value" @add="childClick" :msg="msg" /> <br /> <div>{{msg1}}</div> <br /> <button @click.stop="parentClick()">父组件按钮</button> </div> </template> <script setup lang="ts"> /** * 引入必要的模块 */ import { ref } from 'vue' import child from './Child .vue' /** * 定义数据 */ const value = ref<number>(0); const msg = ref<string>('我是父组件传递过来的值啊~~'); const msg1 = ref<string>('') /** * 定义方法 */ const parentClick = ()=> { value.value++ } const childClick = (value)=>{ msg1.value = value } </script>子组件:child.vue<template> <div> <h1>{{ props.msg }}</h1> <h1>{{ props.value }}</h1> <button @click="onChildClick">子组件按钮</button> </div> </template> <script setup lang="ts"> /** * 定义数据 */ const props = defineProps({ value: { type: Number },msg:{type:String} }) const emit = defineEmits(['add']) /** * 定义方法 */ const onChildClick = ()=> { emit('add', '我是子组件传过来的值') } </script>第二种父级组件向多层子组件传值 provide 和 inject父级组件:import { provide} from 'vue'; provide('parentMsg','我是父组件');子组件:import {inject} from 'vue'; const sonMsg = inject(parentMsg)孙子组件import {inject} from 'vue'; const grandsonMsg = inject(parentMsg)
2022年07月29日
58 阅读
0 评论
0 点赞
2022-07-27
联动获取行数据方法
联动获取行数据方法:@change="v => propChange(v,scope.row)">
2022年07月27日
43 阅读
0 评论
0 点赞
2022-07-08
驼峰与下划线互相转换(JS + JAVA)
{mtitle title="JS 版本"/}/** * 将驼峰转为下划线 */ function camelToUnderline(camelStr){ return camelStr.replace(/[A-Z]/g,function(s){ return ' '+s.toLowerCase(); }).trim().replaceAll(' ','_'); } /** * 下划线转小驼峰 */ function underlineToSmallCamel(str){ return str.toLowerCase().replace(/_([a-z])/g,function(s, s1){ return s1.toUpperCase(); }) } /** * 华氏温度(32℉) 转化为摄氏温度(0℃) */ function f2c(s) { return s.replace(/(\d+(\.\d*)?)℉/g, function($0,$1,$2) { return (($1-32) * 5/9) + '℃'; }); }{mtitle title="JAVA 版本"/}/** * */ package com; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * @author xp test5.java 2018年12月27日 */ public class test5 { public static void main(String[] args) { //underscoreName("abcAbcaBc"); //camelName("abc_abca_bc"); //upcaseCamelName("abc_abca_bc"); Map<String, Object> data= new HashMap<String, Object>(); data.put("Abc_Abca_Bc_TEXT", ""); camelMap(data); //underscopeMap(data); } //驼峰转大写+下划线,abcAbcaBc->ABC_ABCA_BC public static String underscoreName(String name) { StringBuilder result = new StringBuilder(); if ((name != null) && (name.length() > 0)) { result.append(name.substring(0, 1).toUpperCase()); for (int i = 1; i < name.length(); i++) { String s = name.substring(i, i + 1); if ((s.equals(s.toUpperCase())) && (!Character.isDigit(s.charAt(0)))) { result.append("_"); } result.append(s.toUpperCase()); } } System.err.println("underscoreName:"+result.toString()); return result.toString(); } //下划线转驼峰,abc_abca_bc->abcAbcaBc public static String camelName(String name) { StringBuilder result = new StringBuilder(); if ((name == null) || (name.isEmpty())) { return ""; } if (!name.contains("_")) { return name.toLowerCase(); } String[] camels = name.split("_"); for (String camel : camels) { if (!camel.isEmpty()) { if (result.length() == 0) { result.append(camel.toLowerCase()); } else { result.append(camel.substring(0, 1).toUpperCase()); result.append(camel.substring(1).toLowerCase()); } } } System.err.println("camelName:"+result.toString()); return result.toString(); } //下划线转首字母大写驼峰,abc_abca_bc->AbcAbcaBc public static String upcaseCamelName(String name) { StringBuilder result = new StringBuilder(); if ((name == null) || (name.isEmpty())) { return ""; } if (!name.contains("_")) { result.append(name.substring(0, 1).toUpperCase()); result.append(name.substring(1).toLowerCase()); return result.toString(); } String[] camels = name.split("_"); for (String camel : camels) { if (!camel.isEmpty()) { result.append(camel.substring(0, 1).toUpperCase()); result.append(camel.substring(1).toLowerCase()); } } System.err.println("upcaseCamelName:"+result.toString()); return result.toString(); } public static Map<String, Object> camelMap(Map<String, Object> data) { if (data == null) { return null; } Map<String, Object> ret = new HashMap<>(); Iterator<String> keyIt = data.keySet().iterator(); while (keyIt.hasNext()) { String key = (String) keyIt.next(); ret.put(camelName(key), data.get(key)); if (key.endsWith("_TEXT")) { String key1 = key.substring(0, key.lastIndexOf("_")); ret.put(camelName(key1) + "_Text", data.get(key)); } } System.err.println("data:"+data); System.err.println("camelMap:"+ret); return ret; } public static Map<String, Object> underscopeMap(Map<String, Object> data) { if (data == null) { return null; } Map<String, Object> ret = new HashMap<>(); Iterator<String> keyIt = data.keySet().iterator(); while (keyIt.hasNext()) { String key = (String) keyIt.next(); ret.put(underscoreName(key), data.get(key)); } System.err.println("underscopeMap:"+ret); return ret; } }
2022年07月08日
98 阅读
0 评论
0 点赞
2022-06-21
JS判断数组是否有重复元素
// 例如有这样的一个数据 const arr = [{code:1001,name:'小米'},{code:1002,name:'大米'},{code:1001,name:'xiaomi'}]; // 判断是否有重复的指标 function isRepeat(arr){ var hash = {}; for(var i in arr) { if(hash[arr[i].code]) return true; hash[arr[i].code] = true; } return false; }
2022年06月21日
40 阅读
0 评论
0 点赞
2022-04-18
两天前端学习 - vue
一、双向绑定<body> <div id="app"> <input type="text" v-model="num"> <h2>{{name}},非常帅!!!有{{num}}个人为他点赞。 </h2> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> // 创建 vue 实例 let app = new Vue({ el: "#app", // el 即 element,该 vue 实例要渲染的页面元素 data: { // 渲染页面需要的数据 name: "张三", num: 5, } }); </script> </body>双向绑定: 效果:我们修改表单项,num 会发生变化。我们修改 num,表单项也会发生变化。为了实 时观察到这个变化,我们将 num 输出到页面。 我们不需要关注他们为什么会建立起来关联,以及页面如何变化,我们只需要做好数据和视图的关联即可(MVVM)二、事件处理<body> <div id="app"> <input type="text" v-model="num"> <button v-on:click="num++">关注</button> <h2>{{name}},非常帅!!!有{{num}}个人为他点赞。 </h2> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> // 创建 vue 实例 let app = new Vue({ el: "#app", // el 即 element,该 vue 实例要渲染的页面元素 data: { // 渲染页面需要的数据 name: "张三", num: 5 }, }); </script> </body>这里用v-on指令绑定点击事件,而不是普通的onclick,然后直接操作 num普通 click 是无法直接操作 num 的。未来我们会见到更多 v-xxx,这些都是 vue 定义的不同功能的指令。 简单使用总结:1)、使用 Vue 实例管理 DOM2)、DOM 与数据/事件等进行相关绑定3)、我们只需要关注数据,事件等处理,无需关心视图如何进行修改三、v-text 和 v-html 使用{{}}方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的{{}}, 加载完毕后才显示正确数据,我们称为插值闪烁。可以使用 v-text 和 v-html 指令来替代{{}} 说明:v-text:将数据输出到元素内部,如果输出的数据有 HTML 代码,会作为普通文本输出v-html:将数据输出到元素内部,如果输出的数据有 HTML四、v-bind html 属性不能使用双大括号形式绑定,我们使用 v-bind 指令给 HTML 标签属性绑定值; 而且在将 v-bind 用于 class 和 style 时,Vue.js 做了专门的增强。4.1 绑定 class<div class="static" v-bind:class="{ active: isActive, 'text-danger' : hasError }"> </div> <script> let vm = new Vue({ el: "#app", data: { isActive: true, hasError: false } }) </script>4.2 绑定 style v-bind:style 的对象语法十分直观,看着非常像 CSS,但其实是一个 JavaScript 对象。style 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,这种方式记得用单引号括起 来) 来命名。 例如:font-size-->fontSize<div id="app" v-bind:style="{ color: activeColor, fontSize: fontSiz e + 'px' }"></div> <script> let vm = new Vue({ el: "#app", data: { activeColor: 'red', fontSize: 30 } }) </script>结果:4.3 绑定其他任意属性<div id="app" v-bind:style="{ color: activeColor, fontSize: fontS ize + 'px' }" v-bind:user="userName"> </div> <script> let vm = new Vue({ el: "#app", data: { activeColor: 'red', fontSize: 30, userName: 'zhangsan' } }) </script>效果: 4.4 v-bind 缩写 五、v-for 遍历数据遍历数据渲染页面是非常常用的需求,Vue 中通过 v-for 指令来实现。5.1 普通遍历语法:v-for="item in items"items:要遍历的数组,需要在 vue 的 data 中定义好。item:迭代得到的当前正在遍历的元素示例:<div id="app"> <ul> <li v-for="user in users"> {{user.name}} - {{user.gender}} - {{user.age}} </li> </ul> </div> <script src="../node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> let app = new Vue({ el: "#app", data: { users: [{ name: '柳岩', gender: '女', age: 21 }, { name: '张三', gender: '男', age: 18 }, { name: '范冰冰', gender: '女', age: 24 }, { name: '刘亦菲', gender: '女', age: 18 }, { name: '古力娜扎', gender: '女', age: 25 }] }, }) </script>5.2 带数字角标:在遍历的过程中,如果我们需要知道数组角标,可以指定第二个参数: 语法:v-for="(item,index) in items"items:要迭代的数组item:迭代得到的数组元素别名index:迭代到的当前元素索引,从 0 开始。5.3 遍历对象v-for 除了可以迭代数组,也可以迭代对象。语法基本类似 语法:v-for="value in object" v-for="(value,key) in object" v-for="(value,key,index) in object"1 个参数时,得到的是对象的属性值2 个参数时,第一个是属性值,第二个是属性名3 个参数时,第三个是索引,从 0 开始<div id="app"> <ul> <li v-for="(value, key, index) in user"> {{index + 1}}. {{key}} - {{value}} </li> </ul> </div> <script src="../node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> let vm = new Vue({ el: "#app", data: { user: { name: '张三', gender: '男', age: 18 } } }) </script>5.4 KEY 用来标识每一个元素的唯一特征,这样 Vue 可以使用“就地复用”策略有效的提高渲染的效率。<ul> <li v-for="(item,index) in items" :key=”index”></li> </ul> <ul> <li v-for="item in items" :key=”item.id”></li> </ul>如果 items 是数组,可以使用 index 作为每个元素的唯一标识。如果 items 是对象数组,可以使用 item.id 作为每个元素的唯一标识。六、计算属性和侦听器6.1 计算属性(computed) 某些结果是基于之前数据实时计算出来的,我们可以利用计算属性。来完成 示例:<div id="app"> <ul> <li>西游记:价格{{xyjPrice}},数量: <input type="number" v-model="xyjNum"></li> <li>水浒传:价格{{shzPrice}},数量: <input type="number" v-model="shzNum"></li> <li>总价:{{totalPrice}}</li> </ul> </div> <script src="../node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> let app = new Vue({ el: "#app", data: { xyjPrice: 56.73, shzPrice: 47.98, xyjNum: 1, shzNum: 1 }, computed: { totalPrice() { return this.xyjPrice * this.xyjNum + this.shzPrice * th is.shzNum; } }, }) </script> 6.2 侦听(watch)watch 可以让我们监控一个值的变化。从而做出相应的反应。 示例:<div id="app"> <ul> <li>西游记:价格{{xyjPrice}},数量: <input type="number" v-model="xyjNum"></li> <li>水浒传:价格{{shzPrice}},数量: <input type="number" v-model="shzNum"></li> <li>总价:{{totalPrice}}</li> {{msg}} </ul> </div> <script src="../node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> let app = new Vue({ el: "#app", data: { xyjPrice: 56.73, shzPrice: 47.98, xyjNum: 1, shzNum: 1, msg: "" }, computed: { totalPrice() { return this.xyjPrice * this.xyjNum + this.shzPrice * th is.shzNum; } }, watch: { xyjNum(newVal, oldVal) { if (newVal >= 3) { this.msg = "西游记没有更多库存了"; this.xyjNum = 3; } else { this.msg = ""; } } } }) </script>6.3 过滤器(filters) 过滤器不改变真正的data,而只是改变渲染的结果,并返回过滤后的版本。在很多不同的 情况下,过滤器都是有用的,比如尽可能保持 API 响应的干净,并在前端处理数据的格式。 示例:展示用户列表性别显示男女<body> <div id="app"> <table> <tr v-for="user in userList"> <td>{{user.id}}</td> <td>{{user.name}}</td> <!-- 使用代码块实现,有代码侵入 --> <td>{{user.gender===1? "男":"女"}}</td> </tr> </table> </div> </body> <script src="../node_modules/vue/dist/vue.js"></script> <script> let app = new Vue({ el: "#app", data: { userList: [{ id: 1, name: 'jacky', gender: 1 }, { id: 2, name: 'peter', gender: 0 }] } }); </script> 6.3.1 局部过滤器注册在当前 vue 实例中,只有当前实例能用let app = new Vue({ el: "#app", data: { userList: [ { id: 1, name: 'jacky', gender: 1 }, { id: 2, name: 'peter', gender:0 } ] }, filters: { genderFilter(gender) { return gender === 1 ? '男~' : '女~' } } });{{user.gender | genderFilter}}6.3.2 全局过滤器// 在创建 Vue 实例之前全局定义过滤器: Vue.filter('capitalize', function (value) { return value.charAt(0).toUpperCase() + value.slice(1) })任何 vue 实例都可以使用: {{user.name | capitalize}}过滤器常用来处理文本格式化的操作。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式7.组件化 在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航,但是如果每个页面都独自开发,这无疑增加了我们开发的成本。所以我们会把页面的不同部 分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。在 vue 里,所有的 vue 实例都是组件。 7.1 全局组件 我们通过 Vue 的 component 方法来定义一个全局组件。<div id="app"> <!--使用定义好的全局组件--> <counter></counter> </div> <script src="../node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> // 定义全局组件,两个参数:1,组件名称。2,组件参数 Vue.component("counter", { template: '<button v-on:click="count++">你点了 我 {{ count }} 次,我记住了.</button>', data() { return { count: 0 } } }) let app = new Vue({ el: "#app" }) </script>组件其实也是一个 Vue 实例,因此它在定义时也会接收:data、methods、生命周期函 数等不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有 el 属性。但是组件渲染需要 html 模板,所以增加了 template 属性,值就是 HTML 模板全局组件定义完毕,任何 vue 实例都可以直接在 HTML 中通过组件名称来使用组件了data 必须是一个函数,不再是一个对象。7.2 组件复用定义好的组件,可以任意复用多次:<div id="app"> <!--使用定义好的全局组件--> <counter></counter> <counter></counter> <counter></counter> </div>组件的 data 属性必须是函数!一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。详细了解: 点击这里 7.3 局部组件 一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着 Vue 的加载而加载。 因此,对于一些并不频繁使用的组件,我们会采用局部注册。 我们先在外部定义一个对象,结构与创建组件时传递的第二个参数一致:const counter = { template: '<button v-on:click="count++">你点了 我 {{ count }} 次,我记住了.</button>', data() { return { count:0 } } };然后在 Vue 中使用它:let app = new Vue({ el: "#app", components: { counter: counter // 将定义的对象注册为组件 } })components 就是当前 vue 对象子组件集合。其 key 就是子组件名称其值就是组件对象名效果与刚才的全局注册是类似的,不同的是,这个 counter 组件只能在当前的 Vue 实例 中使用简写:let app = new Vue({ el: "#app", components: { counter // 将定义的对象注册为组件 } })八、生命周期钩子函数8.1 生命周期 每个 Vue 实例在被创建时都要经过一系列的初始化过程 :创建实例,装载模板,渲染模 板等等。Vue 为生命周期中的每个状态都设置了钩子函数(监听函数)。每当 Vue 实例处于 不同的生命周期时,对应的函数就会被触发调用。 生命周期:你不需要立马弄明白所有的东西。8.2 钩子函数beforeCreated:我们在用 Vue 时都要进行实例化,因此,该函数就是在 Vue 实例化时调 用,也可以将他理解为初始化函数比较方便一点,在 Vue1.0 时,这个函数的名字就是 init。created:在创建实例之后进行调用。beforeMount:页面加载完成,没有渲染。如:此时页面还是{{name}}mounted:我们可以将他理解为原生 js 中的 window.onload=function({.,.}),或许大家也在用 jquery,所以也可以理解为 jquery 中的$(document).ready(function(){….}),他的功能就 是:在 dom 文档渲染完毕之后将要执行的函数,该函数在 Vue1.0 版本中名字为 compiled。 此时页面中的{{name}}已被渲染成张三beforeDestroy:该函数将在销毁实例前进行调用 。destroyed:改函数将在销毁实例时进行调用。beforeUpdate:组件更新之前。 updated:组件更新之后。示例:<body> <div id="app"> <span id="num">{{num}}</span> <button v-on:click="num++">赞!</button> <h2>{{name}},非常帅!!!有{{num}}个人点赞。 </h2> </div> </body> <script src="../node_modules/vue/dist/vue.js"></script> <script> let app = new Vue({ el: "#app", data: { name: "张三", num: 100 }, methods: { show() { return this.name; }, add() { this.num++; } }, beforeCreate() { console.log("=========beforeCreate============="); console.log("数据模型未加载:" + this.name, this.num); console.log("方法未加载:" + this.show()); console.log("html 模板未加载: " + document.getElementById("num")); }, created: function() { console.log("=========created============="); console.log("数据模型已加载:" + this.name, this.num); console.log("方法已加载:" + this.show()); console.log("html 模板已加载: " + document.getElementById("num")); console.log("html 模板未渲染: " + document.getElementById("num").innerText); }, beforeMount() { console.log("=========beforeMount============="); console.log("html 模板未渲染: " + document.getElementById("num").innerText); }, mounted() { console.log("=========mounted============="); console.log("html 模板已渲染: " + document.getElementById("num").innerText); }, beforeUpdate() { console.log("=========beforeUpdate============="); console.log("数据模型已更新:" + this.num); console.log("html 模板未更新: " + document.getElementById("num").innerText); }, updated() { console.log("=========updated============="); console.log("数据模型已更新:" + this.num); console.log("html 模板已更新: " + document.getElementById("num").innerText); } }); </script>九、vue 模块化开发npm install webpack -g :全局安装 webpacknpm install -g @vue/cli-init :全局安装 vue 脚手架vue init webpack appname :vue 脚手架使用 webpack 模板初始化一个 appname 项目npm start = npm run dev :启动项目npm run build :将项目打包模块化开发: 运行流程进入页面首先加载 index.html 和 main.js 文件。main.js 导入了一些模块【vue、app、router】,并且创建 vue 实例,关联 index.html 页面的元素。使用了 router,导入了 App 组件。并且使用<App/>标签 引用了这个组件第一次默认显示 App 组件。App 组件有个图片和,所以显示了图片。 但是由于代表路由的视图,默认是访问/#/路径(router 路径默认使用 HASH 模式)。在 router 中配置的/是显示 HelloWorld 组件。所以第一次访问,显示图片和 HelloWorld 组件。我们尝试自己写一个组件,并且加入路由。点击跳转。需要使用Go to Foo标签。Vue 单文件组件Vue 单文件组件模板有三个部分;<template> <div class="hello"> <h1>{{ msg }}</h1> </div> </template> <script> export default { name: 'HelloWorld', data() { return { msg: 'Welcome to Your Vue.js App' } } } </script> <style scoped> h1, h2 { font-weight: normal; } </style>VSCODE 添加用户代码片段迅速生成vue文件文件-->首选项-->用户代码片段-->点击新建代码片段--取名 vue.json 确定{ "生成 vue 模板": { "prefix": "vue", "body": [ "<template>", "<div></div>", "</template>", "", "<script>", "//这里可以导入其他文件(比如:组件,工具 js,第三方插件 js,json 文件,图片文件等等)", "//例如:import 《组件名称》 from '《组件路径》';", "", "export default {", "//import 引入的组件需要注入到对象中才能使用", "components: {},", "props: {},", "data() {", "//这里存放数据", "return {", "", "};", "},", "//计算属性 类似于 data 概念", "computed: {},", "//监控 data 中的数据变化", "watch: {},", "//方法集合", "methods: {", "", "},", "//生命周期 - 创建完成(可以访问当前 this 实例)", "created() {", "", "},", "//生命周期 - 挂载完成(可以访问 DOM 元素)", "mounted() {", "", "},", "beforeCreate() {}, //生命周期 - 创建之前", "beforeMount() {}, //生命周期 - 挂载之前", "beforeUpdate() {}, //生命周期 - 更新之前", "updated() {}, //生命周期 - 更新之后", "beforeDestroy() {}, //生命周期 - 销毁之前", "destroyed() {}, //生命周期 - 销毁完成", "activated() {}, //如果页面有 keep-alive 缓存功能,这个函数会触发 ", "}", "</script>", "<style lang='scss' scoped>", "//@import url($3); 引入公共 css 类", "$4", "</style>" ], "description": "生成 vue 模板" } }导入 element-ui 快速开发 1、安装 element-ui: npm i element-ui 2、在 main.js 中引入 element-ui 就可以全局使用了。import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI) 3、将 App.vue 改为 element-ui 中的后台布局 4、添加测试路由、组件,测试跳转逻辑 (1) 、参照文档 el-menu 添加 router 属性 (2) 、参照文档 el-menu-item 指定 index 需要跳转的地址
2022年04月18日
37 阅读
0 评论
0 点赞
2022-04-18
两天前端学习 - ES6
一、简介 ECMAScript 6.0(以下简称 ES6,ECMAScript 是一种由 Ecma 国际(前身为欧洲计算机制造商 协会,英文名称是 European Computer Manufacturers Association)通过 ECMA-262标准化的脚本 程序设计语言)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了,并且 从 ECMAScript 6 开始,开始采用年号来做版本。即 ECMAScript 2015,就是 ECMAScript6。 它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。 每年一个新版本。二、新特性2.1 let 声明变量// var 声明的变量往往会越域 // let 声明的变量有严格局部作用域 { var a = 1; let b = 2; } console.log(a); // 1 console.log(b); // ReferenceError: b is not defined // var 可以声明多次 // let 只能声明一次 var m = 1 var m = 2 let n = 3 // let n = 4 console.log(m) // 2 console.log(n) // Identifier 'n' has already been declared // var 会变量提升 // let 不存在变量提升 console.log(x); // undefined var x = 10; console.log(y); //ReferenceError: y is not defined let y = 20;2.2 const 声明常量(只读变量)// 1. 声明之后不允许改变 // 2. 一但声明必须初始化,否则会报错 const a = 1; a = 3; //Uncaught TypeError: Assignment to constant variable2.3 解构表达式数组解构let arr = [1,2,3]; //以前我们想获取其中的值,只能通过角标。ES6 可以这样: const [x,y,z] = arr;// x,y,z 将与 arr 中的每个位置对应来取值 // 然后打印 console.log(x,y,z);对象解构const person = { name: "jack", age: 21, language: ['java', 'js', 'css'] } // 解构表达式获取值,将 person 里面每一个属性和左边对应赋值 const { name, age, language } = person; // 等价于下面 // const name = person.name; // const age = person.age; // const language = person.language; // 可以分别打印 console.log(name); console.log(age); console.log(language); //扩展:如果想要将 name 的值赋值给其他变量,可以如下,nn 是新的变量名 const { name: nn, age, language } = person; console.log(nn); console.log(age); console.log(language);2.4 字符串扩展 2.4.1 几个新的 API ES6 为字符串扩展了几个新的 API:includes():返回布尔值,表示是否找到了参数字符串。startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。let str = "hello.vue"; console.log(str.startsWith("hello"));//true console.log(str.endsWith(".vue"));//true console.log(str.includes("e"));//true console.log(str.includes("hello"));//true2.4.2 字符串模板 模板字符串相当于加强版的字符串,用反引号 `,除了作为普通字符串,还可以用来定义多行 字符串,还可以在字符串中加入变量和表达式。// 1、多行字符串 let ss = `<div><span>hello world<span></div> ` console.log(ss) // 2、字符串插入变量和表达式。变量名写在 ${} 中,${} 中可以放入 JavaScript 表达式。 let name = "张三"; let age = 18; let info = `我是${name},今年${age}了`; console.log(info) // 3、字符串中调用函数 function fun() { return "这是一个函数" } let sss = `O(∩_∩)O 哈哈~,${fun()}`; console.log(sss); // O(∩_∩)O 哈哈~,这是一个函数2.5 函数优化函数参数默认值//在 ES6 以前,我们无法给一个函数参数设置默认值,只能采用变通写法: function add(a, b) { // 判断 b 是否为空,为空就给默认值 1 b = b || 1; return a + b; } // 传一个参数 console.log(add(10)); //现在可以这么写:直接给参数写上默认值,没传就会自动使用默认值 function add2(a , b = 1) { return a + b; } // 传一个参数 console.log(add2(10));不定参数不定参数用来表示不确定参数个数,形如,...变量名,由...加上一个具名参数标识符组成。 具名参数只能放在参数列表的最后,并且有且只有一个不定参数。function fun(...values) { console.log(values.length) } fun(1, 2) //2 fun(1, 2, 3, 4) //4箭头函数ES6 中定义函数的简写方式一个参数时://以前声明一个方法 // var print = function (obj) { // console.log(obj); // } // 可以简写为: var print = obj => console.log(obj); // 测试调用 print(100);多个参数时:// 两个参数的情况: var sum = function (a, b) { return a + b; } // 简写为: //当只有一行语句,并且需要返回结果时,可以省略 {} , 结果会自动返回。 var sum2 = (a, b) => a + b; //测试调用 console.log(sum2(10, 10));//20 // 代码不止一行,可以用`{}`括起来 var sum3 = (a, b) => { c = a + b; return c; }; //测试调用 console.log(sum3(10, 20));//30实战:箭头函数结合解构表达式//需求,声明一个对象,hello 方法需要对象的个别属性 //以前的方式: const person = { name: "jack", age: 21, language: ['java', 'js', 'css'] } function hello(person) { console.log("hello," + person.name) } //现在的方式 var hello2 = ({ name }) => { console.log("hello," + name) }; //测试 hello2(person);2.6 对象优化 2.6.1 新增的API ES6 给 Object 拓展了许多新的方法,如:keys(obj):获取对象的所有 key 形成的数组values(obj):获取对象的所有 value 形成的数组entries(obj):获取对象的所有 key 和 value 形成的二维数组。格式:[[k1,v1],[k2,v2],...]assign(dest, ...src) :将多个 src 对象的值 拷贝到 dest 中。(第一层为深拷贝,第二层为浅拷贝)const person = { name: "jack", age: 21, language: ['java', 'js', 'css'] } console.log(Object.keys(person));//["name", "age", "language"] console.log(Object.values(person));//["jack", 21, Array(3)] console.log(Object.entries(person));//[Array(2), Array(2), Arra y(2)] const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; //Object.assign 方法的第一个参数是目标对象,后面的参数都是源对象。 Object.assign(target, source1, source2); console.log(target)//{a: 1, b: 2, c: 3}2.6.2 声明对象简写const age = 23 const name = "张三" // 传统 const person1 = { age: age, name: name } console.log(person1) // ES6:属性名和属性值变量名一样,可以省略 const person2 = { age, name } console.log(person2) //{age: 23, name: "张三"}2.6.3 对象的函数属性简写let person = { name: "jack", // 以前: eat: function (food) { console.log(this.name + "在吃" + food); }, // 箭头函数版:这里拿不到 this eat2: food => console.log(person.name + "在吃" + food), // 简写版: eat3(food) { console.log(this.name + "在吃" + food); } } person.eat("apple");2.6.4 对象拓展运算符 拓展运算符(...)用于取出参数对象所有可遍历属性然后拷贝到当前对象。// 1、拷贝对象(深拷贝) let person1 = { name: "Amy", age: 15 } let someone = { ...person1 } console.log(someone) //{name: "Amy", age: 15} // 2、合并对象 let age = { age: 15 } let name = { name: "Amy" } let person2 = { ...age, ...name } //如果两个对象的字段名重复,后面对象字 段值会覆盖前面对象的字段值 console.log(person2) //{age: 15, name: "Amy"}2.7 map 和 reduce 数组中新增了 map 和 reduce 方法。map: map():接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回。let arr = ['1', '20', '-5', '3']; console.log(arr) arr = arr.map(s => parseInt(s)); console.log(arr)reduce:语法: arr.reduce(callback,[initialValue])reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元 素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调 用 reduce 的数组。callback (执行数组中每个值的函数,包含四个参数)1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))2、currentValue (数组中当前被处理的元素)3、index (当前元素在数组中的索引)4、array (调用 reduce 的数组)initialValue (作为第一次调用 callback 的第一个参数。)const arr = [1,20,-5,3]; //没有初始值: console.log(arr.reduce((a,b)=>a+b));//19 console.log(arr.reduce((a,b)=>a*b));//-300 //指定初始值: console.log(arr.reduce((a,b)=>a+b,1));//20 console.log(arr.reduce((a,b)=>a*b,0));//-02.8 Promise 在 JavaScript 的世界中,所有代码都是单线程执行的。由于这个“缺陷”,导致 JavaScript 的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现。一旦有一连 串的 ajax 请求 a,b,c,d... 后面的请求依赖前面的请求结果,就需要层层嵌套。这种缩进和层 层嵌套的方式,非常容易造成上下文代码混乱,我们不得不非常小心翼翼处理内层函数与外层函数的数据,一旦内层函数使用了上层函数的变量,这种混乱程度就会加剧......总之,这 种层叠上下文的层层嵌套方式,着实增加了神经的紧张程度。案例:用户登录,并展示该用户的各科成绩。在页面发送两次请求: 1.查询用户,查询成功说明可以登录2.查询用户成功,查询科目3.根据科目的查询结果,获取去成绩 分析:此时后台应该提供三个接口,一个提供用户查询接口,一个提供科目的接口,一个提 供各科成绩的接口,为了渲染方便,最好响应 json 数据。在这里就不编写后台接口了,而 是提供三个 json 文件,直接提供 json 数据,模拟后台接口:{ "id": 1, "name": "zhangsan", "password": "123456" }{ "id": 10, "name": "chinese" }{ "id": 100, "score": 90 }//回调函数嵌套的噩梦:层层嵌套。 $.ajax({ url: "mock/user.json", success(data) { console.log("查询用户:", data); $.ajax({ url: `mock / user_corse_$ { data.id }.json`, success(data) { console.log("查询到课程:", data); $.ajax({ url: `mock / corse_score_$ { data.id }.json`, success(data) { console.log("查询到分数:", data); }, error(error) { console.log("出现异常了:" + error); } }); }, error(error) { console.log("出现异常了:" + error); } }); }, error(error) { console.log("出现异常了:" + error); } });我们可以通过 Promise 解决以上问题。2.8.1 Promise 语法const promise = new Promise(function (resolve, reject) { // 执行异步操作 if (/* 异步操作成功 */) { resolve(value);// 调用 resolve,代表 Promise 将返回成功的结果 } else { reject(error);// 调用 reject,代表 Promise 会返回失败结果 } } ); // 使用箭头函数可以简写为: const promise = new Promise((resolve, reject) =>{ // 执行异步操作 if (/* 异步操作成功 */) { resolve(value);// 调用 resolve,代表 Promise 将返回成功的结果 } else { reject(error);// 调用 reject,代表 Promise 会返回失败结果 } });这样,在 promise 中就封装了一段异步执行的结果。2.8.2 处理异步结果 如果我们想要等待异步执行完成,做一些事情,我们可以通过 promise 的 then 方法来实现。 如果想要处理 promise 异步执行失败的事件,还可以跟上 catch:promise.then(function (value) { // 异步执行成功后的回调 }).catch(function (error) { // 异步执行失败后的回调 })2.8.3 Promise 改造以前嵌套方式new Promise((resolve, reject) = >{ $.ajax({ url: "mock/user.json", success(data) { console.log("查询用户:", data); resolve(data.id); }, error(error) { console.log("出现异常了:" + error); } }); }).then((userId) = >{ return new Promise((resolve, reject) = >{ $.ajax({ url: `mock / user_corse_$ { userId }.json`, success(data) { console.log("查询到课程:", data); resolve(data.id); }, error(error) { console.log("出现异常了:" + error); } }); }); }).then((corseId) = >{ console.log(corseId); $.ajax({ url: `mock / corse_score_$ { corseId }.json`, success(data) { console.log("查询到分数:", data); }, error(error) { console.log("出现异常了:" + error); } }); });2.8.4 优化处理 优化:通常在企业开发中,会把 promise 封装成通用方法,如下:封装了一个通用的 get 请 求方法;let get = function(url, data) { // 实际开发中会单独放到 common.js 中 return new Promise((resolve, reject) = >{ $.ajax({ url: url, type: "GET", data: data, success(result) { resolve(result); }, error(error) { reject(error); } }); }) }使用封装的 get 方法,实现查询分数get("mock/user.json").then((result) = >{ console.log("查询用户:", result); return get(`mock / user_corse_$ { result.id }.json`); }).then((result) = >{ console.log("查询到课程:", result); return get(`mock / corse_score_$ { result.id }.json`) }).then((result) = >{ console.log("查询到分数:", result); }). catch(() = >{ console.log("出现异常了:" + error); });通过比较,我们知道了 Promise 的扁平化设计理念,也领略了这种上层设计带来的好处。 我们的项目中会使用到这种异步处理的方式。2.9 模块化 什么是模块化? 模块化就是把代码进行拆分,方便重复利用。类似 java 中的导包:要使用一个包,必须先 导包。而 JS 中没有包的概念,换来的是 模块。 模块功能主要由两个命令构成:export和import。 export命令用于规定模块的对外接口。 import命令用于导入其他模块提供的功能2.9.1 export 比如我定义一个 js 文件:hello.js,里面有一个对象const util = { sum(a,b){ return a + b; } }我可以使用 export 将这个对象导出:const util = { sum(a,b){ return a + b; } } export {util}; // 简写方式 export const util = { sum(a,b){ return a + b; } }export不仅可以导出对象,一切 JS 变量都可以导出。比如:基本类型变量、函数、数组、 对象。 当要导出多个值时,还可以简写。比如我有一个文件:user.js:var name = "jack" var age = 21 export {name,age}省略名称 上面的导出代码中,都明确指定了导出的变量名,这样其它人在导入使用时就必须准确写出 变量名,否则就会出错。 因此 js 提供了default关键字,可以对导出的变量名进行省略 例如// 无需声明对象的名字 export default { sum(a,b){ return a + b; } } //这样,当使用者导入时,可以任意起名字2.9.2 export 使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。例如我要使用上面导出的 util:// 导入 util import util from 'hello.js' // 调用 util 中的属性 util.sum(1,2) // 要批量导入前面导出的 name 和 age: import {name, age} from 'user.js' console.log(name + " , 今年"+ age +"岁了")但是上面的代码暂时无法测试,因为浏览器目前还不支持 ES6 的导入和导出功能。除非借 助于工具,把 ES6 的语法进行编译降级到 ES5,比如Babel-cli工具 我们暂时不做测试,大家了解即可。
2022年04月18日
35 阅读
0 评论
0 点赞
2022-01-28
Flex 布局教程:语法篇
一、Flex 布局是什么?{dotted startColor="#ff6c6c" endColor="#1989fa"/}Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为 Flex 布局。 .box{ display: flex; }行内元素也可以使用 Flex 布局。 .box{ display: inline-flex; } Webkit 内核的浏览器,必须加上-webkit前缀。 .box{ display: -webkit-flex; /* Safari */ display: flex; } 注意,设为 Flex 布局以后,子元素的float、clear和vertical-align属性将失效。二、基本概念{dotted startColor="#ff6c6c" endColor="#1989fa"/}采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。三、容器的属性{dotted startColor="#ff6c6c" endColor="#1989fa"/}以下6个属性设置在容器上。- flex-direction - flex-wrap - flex-flow - justify-content - align-items - align-content3.1 flex-direction属性flex-direction属性决定主轴的方向(即项目的排列方向)。 .box { flex-direction: row | row-reverse | column | column-reverse; }它可能有4个值。- row(默认值):主轴为水平方向,起点在左端。 - row-reverse:主轴为水平方向,起点在右端。 - column:主轴为垂直方向,起点在上沿。 - column-reverse:主轴为垂直方向,起点在下沿。3.2 flex-wrap属性默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。 .box{ flex-wrap: nowrap | wrap | wrap-reverse; }它可能取三个值。(1)nowrap(默认):不换行。(2)wrap:换行,第一行在上方。(3)wrap-reverse:换行,第一行在下方。3.3 flex-flowflex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。 .box { flex-flow: <flex-direction> || <flex-wrap>; }3.4 justify-content属性justify-content属性定义了项目在主轴上的对齐方式。 .box { justify-content: flex-start | flex-end | center | space-between | space-around; }它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。- flex-start(默认值):左对齐 - flex-end:右对齐 - center: 居中 - space-between:两端对齐,项目之间的间隔都相等。 - space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。3.5 align-items属性align-items属性定义项目在交叉轴上如何对齐。 .box { align-items: flex-start | flex-end | center | baseline | stretch; }它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。- flex-start:交叉轴的起点对齐。 - flex-end:交叉轴的终点对齐。 - center:交叉轴的中点对齐。 - baseline: 项目的第一行文字的基线对齐。 - stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。3.6 align-content属性align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。 .box { align-content: flex-start | flex-end | center | space-between | space-around | stretch; }该属性可能取6个值。- flex-start:与交叉轴的起点对齐。 - flex-end:与交叉轴的终点对齐。 - center:与交叉轴的中点对齐。 - space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。 - space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。 - stretch(默认值):轴线占满整个交叉轴。四、项目的属性以下6个属性设置在项目上。- order - flex-grow - flex-shrink - flex-basis - flex - align-self4.1 order属性order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。 .item { order: <integer>; }4.2 flex-grow属性flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。.item { flex-grow: <number>; /* default 0 */ }如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。4.3 flex-shrink属性flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。 .item { flex-shrink: <number>; /* default 1 */ } 如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。负值对该属性无效。4.4 flex-basis属性flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。 .item { flex-basis: <length> | auto; /* default auto */ }它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。4.5 flex属性flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。 .item { flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ] }该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。4.6 align-self属性align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。 .item { align-self: auto | flex-start | flex-end | center | baseline | stretch; }该属性可能取6个值,除了auto,其他都与align-items属性完全一致。
2022年01月28日
49 阅读
0 评论
0 点赞
2021-10-21
前端一些实用的函数
/** * @description: 滚动至页面顶部 * @param {*} * @return {*} */ const goToTop = () => window.scrollTo(0, 0); /** * @description: 校验身份证 * @param {*} * @return {*} */ export const validateIDCard = value => /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(value); /** * @description: 校验支付宝账号 * @param {*} * @return {*} */ export const validateAlipay = value => /^1\d{10}$|^[a-zA-Z\d._-]*\@[a-zA-Z\d.-]{1,10}\.[a-zA-Z\d]{1,20}$/.test(value); /** * @description: 校验银行卡 * @param {*} * @return {*} */ export const validateBankCode = value => /^\d{13,19}$/.test(value); /** * @description: 校验手机号 * @param {*} * @return {*} */ export const validatePhone = value => /^1\d{10}$/.test(value); /** * @description: 函数节流 * @param {*} * @return {*} */ export const throttle = function (fn, delay = 1000) { let prev = 0; return function () { const now = Date.now(); if (now - prev > delay) { fn.apply(this, arguments); prev = Date.now(); } } } /** * @description: 获取随机字符串 * @param {*} * @return {*} */ export const randomString = () => Math.random().toString(36).substr(2); /** * @description: 将 BASE64 转换文件 * @param {*} * @return {*} */ export const dataURLtoFile = (dataurl, filename) => { const arr = dataurl.split(','); const mime = arr[0].match(/:(.*?);/)[1]; if (!filename) filename = `${Date.parse(new Date())}.jpg`; const bstr = window.atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], filename, { type: mime }); } /** * @description: 压缩图片 * @param {*} * @return {*} */ export const compressImg = file => { const fileSize = parseFloat(Number.parseInt(file.size, 10) / 1024 / 1024).toFixed(2); const reader = new FileReader(); reader.readAsDataURL(file); return new Promise((resolve) => { reader.onload = e => { const img = new Image(); img.src = e.target.result; img.onload = () => { const w = img.width; const h = img.height; const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); let base64; canvas.setAttribute('width', w); canvas.setAttribute('height', h); ctx.drawImage(img, 0, 0, w, h); if (fileSize <= 1) { base64 = canvas.toDataURL(file.type, 1); } else if (fileSize <= 3) { base64 = canvas.toDataURL(file.type, 0.8); } else if (fileSize <= 5) { base64 = canvas.toDataURL(file.type, 0.5); } else { base64 = canvas.toDataURL(file.type, 0.1); } let fileName = file.name; fileName = fileName.replace(/^(.+)\.(.+)$/, (fullName, name, suffix) => name + Math.floor(Math.random() * (9999 - 1000) + 1000) + '.' + suffix); resolve(dataURLtoFile(base64, fileName)); }; }; }); } /* 防抖原理:在一定时间内,只有最后一次操作,再过wait毫秒后才执行函数 @param {Function} func 要执行的回调函数 @param {Number} wait 延迟的时间 @param{Boolean} immediate 是否要立即执行 */ let timeout = null; function debounce(func, wait = 500, immediate = false) { // 清除定时器 if (timeout !== null) clearTimeout(timeout); // 立即执行,此类情况一般用不到 if (immediate) { var callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, wait); if (callNow) typeof func === "function" && func(); } else { // 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法 timeout = setTimeout(() => { typeof func === "function" && func(); }, wait); } } export default debounce; /** * @description: 节流 * 节流原理:在一定时间内,只能触发一次 * @param {Function} func 要执行的回调函数 * @param {Number} wait 延时的时间 * @param {Boolean} immediate 是否立即执行 * @return null */ let timer, flag; function throttle(func, wait = 500, immediate = true) { if (immediate) { if (!flag) { flag = true; // 如果是立即执行,则在wait毫秒内开始时执行 typeof func === 'function' && func(); timer = setTimeout(() => { flag = false; }, wait); } } else { if (!flag) { flag = true // 如果是非立即执行,则在wait毫秒内的结束处执行 timer = setTimeout(() => { flag = false typeof func === 'function' && func(); }, wait); } } }; export default throttle /** * time 任何合法的时间格式、秒或毫秒的时间戳 * format 时间格式,可选。默认为yyyy-mm-dd,年为"yyyy",月为"mm",日为"dd",时为"hh",分为"MM",秒为"ss",格式可以自由搭 **/ function timeFormat(dateTime = null, fmt = 'yyyy-mm-dd') { // 如果为null,则格式化当前时间 if (!dateTime) dateTime = Number(new Date()); // 如果dateTime长度为10或者13,则为秒和毫秒的时间戳,如果超过13位,则为其他的时间格式 if (dateTime.toString().length == 10) dateTime *= 1000; let date = new Date(dateTime); let ret; let opt = { "y+": date.getFullYear().toString(), // 年 "m+": (date.getMonth() + 1).toString(), // 月 "d+": date.getDate().toString(), // 日 "h+": date.getHours().toString(), // 时 "M+": date.getMinutes().toString(), // 分 "s+": date.getSeconds().toString() // 秒 // 有其他格式化字符需求可以继续添加,必须转化成字符串 }; for (let k in opt) { ret = new RegExp("(" + k + ")").exec(fmt); if (ret) { fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0"))) }; }; return fmt; } export default timeFormat /** *手机号加密 */ export const phoneFormat = (phone = 0) => { return String(phone).replace(/^(\d{3})\d{4}(\d+)$/, '$1****$2'); }; /** * 验证手机号 */ const REGEXP_PHONE = /^(0|86|17951)?(13[0-9]|15[012356789]|166|17[3678]|18[0-9]|14[57])[0-9]{8}$/; /** * 验证身份证号 */ const REGEXP_IDCARD = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/; /** * 验证电子邮箱格式 */ function email(value) { return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value); } /** * 验证手机格式 */ function mobile(value) { return /^1[23456789]\d{9}$/.test(value) } /** * 验证URL格式 */ function url(value) { return /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/.test(value) } /** * 验证日期格式 */ function date(value) { return !/Invalid|NaN/.test(new Date(value).toString()) } /** * 是否车牌号 */ function carNo(value) { // 新能源车牌 const xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/; // 旧车牌 const creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/; if (value.length === 7) { return creg.test(value); } else if (value.length === 8) { return xreg.test(value); } else { return false; } } /** * 金额,只允许2位小数 */ function amount(value) { //金额,只允许保留两位小数 return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value); } /** *只能输入字母 */ function letter(value) { return /^[a-zA-Z]*$/.test(value); } /** *只能是字母或者数字 */ function enOrNum(value) { //英文或者数字 let reg = /^[0-9a-zA-Z]*$/g; return reg.test(value); } /** * 是否固定电话 */ function landline(value) { let reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/; return reg.test(value); } /** * 是否json字符串 */ function jsonString(value) { if (typeof value == 'string') { try { var obj = JSON.parse(value); if (typeof obj == 'object' && obj) { return true; } else { return false; } } catch (e) { return false; } } return false; } /** * 密码强度校验 * 说明:密码中必须包含字母、数字、特称字符,至少8个字符,最多30个字符 */ const passwordReg = /(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,30}/ const password1 = 'sunshine_Lin12345..' console.log(passwordReg.test(password1)) // true const password2 = 'sunshineLin12345' console.log(passwordReg.test(password2)) // false /** * 全局唯一标识符 * guid(length = 32, firstU = true, radix = 62) * length <Number | null> guid的长度,默认为32,如果取值null,则按rfc4122标准生成对应格式的随机数 * firstU 首字母是否为"u",如果首字母为数字情况下,不能用作元素的id或者class,默认为true * radix 生成的基数,默认为62,用于生成随机数字符串 */ function guid(len = 32, firstU = true, radix = null) { let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); let uuid = []; radix = radix || chars.length; if (len) { // 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位 for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]; } else { let r; // rfc4122标准要求返回的uuid中,某些位为固定的字符 uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; uuid[14] = '4'; for (let i = 0; i < 36; i++) { if (!uuid[i]) { r = 0 | Math.random() * 16; uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; } } } // 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class if (firstU) { uuid.shift(); return 'u' + uuid.join(''); } else { return uuid.join(''); } } export default guid; /** * 对象转URL参数 * queryParams(data, isPrefix = true, arrayFormat = 'brackets') */ /** * 对象转url参数 * @param {*} data,对象 * @param {*} isPrefix,是否自动加上"?" */ function queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') { let prefix = isPrefix ? '?' : '' let _result = [] if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1) arrayFormat = 'brackets'; for (let key in data) { let value = data[key] // 去掉为空的参数 if (['', undefined, null].indexOf(value) >= 0) { continue; } // 如果值为数组,另行处理 if (value.constructor === Array) { // e.g. {ids: [1, 2, 3]} switch (arrayFormat) { case 'indices': // 结果: ids[0]=1&ids[1]=2&ids[2]=3 for (let i = 0; i < value.length; i++) { _result.push(key + '[' + i + ']=' + value[i]) } break; case 'brackets': // 结果: ids[]=1&ids[]=2&ids[]=3 value.forEach(_value => { _result.push(key + '[]=' + _value) }) break; case 'repeat': // 结果: ids=1&ids=2&ids=3 value.forEach(_value => { _result.push(key + '=' + _value) }) break; case 'comma': // 结果: ids=1,2,3 let commaStr = ""; value.forEach(_value => { commaStr += (commaStr ? "," : "") + _value; }) _result.push(key + '=' + commaStr) break; default: value.forEach(_value => { _result.push(key + '[]=' + _value) }) } } else { _result.push(key + '=' + value) } } return _result.length ? prefix + _result.join('&') : '' } export default queryParams; console.log(queryParams({name:'li',age:20})) // 结果:?name=li&age=20 const data = {name: '冷月夜',fruits: ['apple', 'banana', 'orange']} queryParams(this.data, true, 'indices'); // 结果为:?name=冷月夜&fruits[0]=apple&fruits[1]=banana&fruits[2]=orange queryParams(this.data, true, 'brackets'); // 结果为:?name=冷月夜&fruits[]=apple&fruits[]=banana&fruits[]=orange queryParams(this.data, true, 'repeat'); // 结果为:?name=冷月夜&fruits=apple&fruits=banana&fruits=orange queryParams(this.data, true, 'comma'); // 结果为:?name=冷月夜&fruits=apple,banana,orange /** * 数组排序 * sort排序 */ // 对数字进行排序,简写 const arr = [3, 2, 4, 1, 5] arr.sort((a, b) => a - b) console.log(arr) // [1, 2, 3, 4, 5] // 对字母进行排序,简写 const arr = ['b', 'c', 'a', 'e', 'd'] arr.sort() console.log(arr) // ['a', 'b', 'c', 'd', 'e'] /** * 数组排序 * 冒泡排序 */ // 对数字进行排序,简写 const arr = [3, 2, 4, 1, 5] arr.sort((a, b) => a - b) console.log(arr) // [1, 2, 3, 4, 5] // 对字母进行排序,简写 const arr = ['b', 'c', 'a', 'e', 'd'] arr.sort() console.log(arr) // ['a', 'b', 'c', 'd', 'e'] /** * 获取URL参数 * URLSearchParams 方法 */ // 创建一个URLSearchParams实例 const urlSearchParams = new URLSearchParams(window.location.search); // 把键值对列表转换为一个对象 const params = Object.fromEntries(urlSearchParams.entries()); // split方法 function getParams(url) { const res = {} if (url.includes('?')) { const str = url.split('?')[1] const arr = str.split('&') arr.forEach(item => { const key = item.split('=')[0] const val = item.split('=')[1] res[key] = decodeURIComponent(val) // 解码 }) } return res } // 测试 const user = getParams('http://www.baidu.com?user=%E9%98%BF%E9%A3%9E&age=16') console.log(user) // { user: '阿飞', age: '16' }
2021年10月21日
19 阅读
0 评论
0 点赞
2021-10-21
VUE 父子组件传值
{message type="success" content=" 一、父组件把值传给子组件 "/}{card-default label="实现原理" width=""}1.父组件 在引用子组件时,通过属性绑定(v-bind:)的形式,把需要传递给子组件的数据,传递到子组件内部,供子组件使用。2.把父组件传递过来的数据, 在 props数组 中定义一下组件中的 所有props 中的数据,都是通过父组件传递给子组件的props 中的数据都是只读的,无法重新赋值3.在该子组件中使用props数组 中定义好的数据{/card-default}// 父组件:father.vue <template> <div> <h1>父组件</h1> <router-view v-bind:fData="data1" :fMessage="data2"></router-view> </div> </template> <script> export default { data () { return { data1: '父组件数据data1', data2: '父组件数据data2', }; } } </script> // 子组件:son.vue <template> <div> <h1>子组件</h1> <p>下面是父组件传过来的数据</p> <p>第一个数据:{{fData}}</p> <p>第二个数据:{{fMessage}}</p> </div> </template> <script> export default { props: ['fData', 'fMessage'], data () { return { }; } } </script>{dotted startColor="#ff6c6c" endColor="#1989fa"/}{message type="success" content=" 二、父组件把方法传递给子组件 "/}{card-default label="实现原理" width=""}1.父组件向子组件传递方法,使用事件绑定机制 v-on,自定义一个事件属性,传递给子组件2.在子组件中定义一个方法,在方法中,利用 $emit 触发 父组件传递过来的,挂载在当前实例上的事件,还可以传递参数3.在子组件中调用定义的那个方法,就可以触发父组件传递过来的方法了{/card-default}// 父组件:father.vue <template> <div> <h1>父组件</h1> <router-view @show="showFather"></router-view> </div> </template> <script> export default { data () { return { }; }, methods: { showFather (a, b) { console.log('触发了父组件的方法' + '======' + a + '======' + b); } } } </script> // 子组件:son.vue <template> <div> <h1>子组件</h1> <Button type="primary" @click="sonClick">触发父组件方法</Button> </div> </template> <script> export default { data () { return { }; }, methods: { sonClick () { this.$emit('show', 111, 222); } } } </script> {dotted startColor="#ff6c6c" endColor="#1989fa"/}{message type="success" content=" 三、子组件通过事件调用向父组件传值 "/}{card-default label="实现原理" width=""}在子组件中,利用 $emit 触发 父组件传递过来的方法的时候,可以将子组件的数据当做参数传递给父组件{/card-default}// 父组件:father.vue <template> <div> <h1>父组件</h1> <router-view @show="showFather"></router-view> </div> </template> <script> export default { data () { return { fromSon1: '', fromSon2: '' }; }, methods: { showFather (a, b) { this.fromSon1 = a; this.fromSon2 = b; console.log('触发了父组件的方法' + '======' + a + '======' + b); } } } </script> // 子组件:son.vue <template> <div> <h1>子组件</h1> <Button type="primary" @click="sonClick">触发父组件方法</Button> </div> </template> <script> export default { props: ['fData', 'fMessage'], data () { return { sonMessage: '子组件数据sonMessage', sonData: '子组件数据sonData' }; }, methods: { sonClick () { this.$emit('show', this.sonMessage, this.sonData); } } } </script> {dotted startColor="#ff6c6c" endColor="#1989fa"/}{message type="success" content="四、父子组件之间相互传值 "/}// 父组件:father.vue <template> <div> <h1>父组件</h1> <Button type="primary" @click="getData">获取数据</Button> <router-view v-bind:fData="data1" :fMessage="data2" @show="showFather"></router-view> </div> </template> <script> export default { data () { return { data1: '父组件数据data1', data2: '父组件数据data2', fromSon1: '', fromSon2: '' }; }, methods: { showFather (a, b) { this.fromSon1 = a; this.fromSon2 = b; console.log('触发了父组件的方法' + '======' + a + '======' + b); }, getData () { console.log(this.fromSon1); console.log(this.fromSon2); } } } </script> // 子组件:son.vue <template> <div> <h1>子组件</h1> <p>下面是父组件传过来的数据</p> <p>第一个数据:{{fData}}</p> <p>第二个数据:{{fMessage}}</p> <Button type="primary" @click="sonClick">触发父组件方法</Button> </div> </template> <script> export default { props: ['fData', 'fMessage'], data () { return { sonMessage: '子组件数据sonMessage', sonData: '子组件数据sonData' }; }, methods: { sonClick () { this.$emit('show', this.sonMessage, this.sonData); } } } </script>
2021年10月21日
84 阅读
0 评论
1 点赞