Vue指令实现输入框校验

import Vue from 'vue';function checkRule(placeholder, value, verifyType, $vm) { if (placeholder.startsWith('请输入')) { placeholder = placeholder.substr(3); } else { placeholder = '内容'; } if (value === '' && verifyType === null) { $vm.$toast.fail(`${placeholder}不能为空`); return false; } switch (verifyType) { case 'ip': if (!$vm.$utils.verifyIp(value)) { $vm.$toast.fail('ip填写不正确'); return false; } break; }}let bindClass = '';Vue.directive('auto-switch', { bind(el, binding) { if (binding.value.class) { el.classList.add(`v-check-${binding.value.class}-list`); bindClass = `v-check-${binding.value.class}-list`; return bindClass; } }, inserted(el, binding) { let autoFocus = 0; if (binding.value.index) { autoFocus = binding.value.index; } let inputArray = el.querySelectorAll('.van-field__control'); inputArray[autoFocus].focus(); for (let i = 0; i < inputArray.length; i++) { inputArray[i].setAttribute('focusIndex', i); inputArray[i].addEventListener('keyup', event => { if (event.keyCode === 13) { let verifyType = event.target.getAttribute('verifyType'), attrIndex = Number(event.target.getAttribute('focusIndex')), $vm = window.vm.__proto__, { placeholder, value } = event.target; if (binding.value.verify) { if (checkRule(placeholder, value, verifyType, $vm) === false) { return false; } } if (attrIndex < inputArray.length - 1) { inputArray[attrIndex + 1].focus(); } } }); } }});Vue.directive('check-submit', { inserted(el, binding) { el.addEventListener('click', () => { let inputArray = document.querySelectorAll(`.${bindClass} .van-field__control`); for (let i = 0; i < inputArray.length; i++) { let verifyType = inputArray[i].getAttribute('verifyType'), $vm = window.vm.__proto__, { placeholder, value } = inputArray[i]; if (checkRule(placeholder, value, verifyType, $vm) === false) { return false; } } let submit = binding.value.fn; submit(); }); }});

August 19, 2019 · 1 min · jiezi

Go-性能分析之案例一

思考相信大家在实际的项目开发中会遇到这么一个事,有的程序员写的代码不仅bug少,而且性能高;而有的程序员写的代码能否流畅的跑起来,都是一个很大问题。而我们今天要讨论的就是一个关于性能优化的案例分析。 案例分析我们先来构造一些基础数据(长度为10亿的切片,并赋上值): var testData = GenerateData()// generate billion slice datafunc GenerateData() []int { data := make([]int, 1000000000) for key, _ := range data { data[key] = key % 128 } return data}// get lengthfunc GetDataLen() int { return len(testData)}案例一// case onefunc CaseSumOne(result *int) { data := GenerateData() for i := 0; i < GetDataLen(); i++ { *result += data[i] }}// case twofunc CaseSumTwo(result *int) { data := GenerateData() dataLen := GetDataLen() for i := 0; i < dataLen; i++ { *result += data[i] }}执行结果$ go test -bench=.goos: windowsgoarch: amd64BenchmarkCaseSumOne-8 1 7439749000 ns/opBenchmarkCaseSumTwo-8 1 2529266700 ns/opPASSok _/C_/go-code/perform/case-one 14.059s问题分析CaseSumTwo执行效率是CaseSumOne的2.94倍,快了近三倍,这是为什么呢?其实很容易猜到,这里有一个连续的函数调用“GetDataLen()”,案例二// case threefunc CaseSumThree(result *int) { data := GenerateData() dataLen := GetDataLen() tmp := *result for i:= 0; i < dataLen; i++ { tmp += data[i] } *result = tmp}执行$ go test -bench=.goos: windowsgoarch: amd64BenchmarkCaseSumOne-8 1 7439749000 ns/opBenchmarkCaseSumTwo-8 1 2529266700 ns/opBenchmarkCaseSumThree-8 1 1657554600 ns/opPASSok _/C_/go-code/perform/case-one 15.717s待续

June 15, 2019 · 1 min · jiezi

Vue基本语法和父子组件传参(prop、emit)

Vue基本语法和组件传参基本语法Vue是一个 MVVM 的框架,数据驱动和 组件化是Vue的核心思想。简单的讲MVVM框架就是:我们只需要在数据层做数据操作,显示层会检测到我们每次的数据变化,然后做出相应的改变,监测数据这个工作就是中间的ViewModel。通过这种模式,我们就可以不用再直接操作DOM节点来进行数据的改变。一、插值{{data}} 在模板里可以实现data数据的展示,如果data数据改变,展示的数据也会响应式的改变。响应式的改变意味着我们不需要强制刷新页面就可以实现数据的变化。这种语法为请输入代码Mustache语法<template> <div class=“main”> <h3>这里是title的值:{{title}}</h3> </div></template>export default { name:‘phonerisk’, data(){ return{ title:’testTitle’ } }}网页上就会显示出来data里面title的值。二、v-htmlv-html可以将一段HTML的代码字符串输出成HTML片段而不是普通的文本。<template> <div class=“main”> <p >这里是<span v-html=‘html’></span></p> </div></template>export default { name:‘phonerisk’, data(){ return{ html:’<span style=“color:blue;font-size:23px;">v-if</span>’ } }}网页上将html字符串渲染成颜色为蓝色的普通文本。v-bindMustache·语法不能用于HTML上,所以我们需要绑定一些属之类的需要使用v-bind。v-bind就是将data里面的数据绑定到HTML上面,从而实现属性的变化。<template> <div class=“main”> <img :src=“imgUrl” /> </div></template>export default { name:‘phonerisk’, data(){ return{ imgUrl:”../../static/img/KFC.e66b2f8e.png" } }}v-bind 可以简写成 :三、v-modelv-model是用于表单输入的数据双向绑定。所谓双向绑定就是视图层的数据变化会引起数据层数据的改变,相反的,数据层的变化也会导致视图层展示数据的变化。<template> <div class=“main”> <input type=“text” v-model=“name”> {{name}} <button @click=‘changeName’>改变名字</button> </div></template>export default { name:‘phonerisk’, data(){ return{ name:‘小明’ } }, methods:{ changeName(){ this.name = “小花”; } }}input输入框绑定name,输入框初始显示‘小明’,在输入框里更改信息的时候,name同时发生改变,点击按钮改变name数值的时候,输入框里面的数据同时发生改变。四、v-onv-on 用于监听DOM事件,如按钮的点击事件、双击事件等。v-on 的简写为 @,如下面的 @click 就等价为 v-on:click。template> <div class=“main”> <button @click=‘yes’>你敢点我吗?</button> </div></template> methods:{ yes(){ alert(“我有啥不敢的!!!”); } }这个案例是监听按钮的点击事件,点击之后调用 yes 函数,然后弹出警告框。 在平时的开发过程中我们可能会使用到 event.preventDefault() 或者 event.stopPropagation() 來阻止事件的继续传播,但是这个是直接操作DOM节点,不符合Vue的思想。所以Vue采用修饰符来进行相关的操作。下面我例举几个常用的,如了解更过,可以查看Vue的官网进行更详细的学习。.stop没有加修饰符<div class=“main” @click=“div”> <button @click.stop=‘yes’>你敢点我吗?</button> </div> methods:{ yes(){ alert(“我有啥不敢的!!!”); }, div(){ alert(“我会DIV”); } }效果如下图:加了 .stop 修饰符之后的效果<button @click.stop=‘yes’>你敢点我吗?</button>效果如下图:.stop 修饰符阻止了事件的继续传播,所以子节点的 click事件没有冒泡到父节点,所以div的点击监听没有监听到内容。.prevent没有加修饰符 <form @submit=“onSubmit”> <button @click=“onSubmit”>提交</button> </form>运行结果如下图:加了 .prevent 修饰符之后的效果<form @submit.prevent =“onSubmit”> <button @click=“onSubmit”>提交</button></form> .prevent 提交表单之后页面不在重新渲染。可以看到没加修饰符的时候页面重新加载,但是在加修饰符之后,页面不在重新加载。.keyup<input v-on:keyup.13=“submit”><input @keyup.enter=“submit”>绑定到输入框里,可以直接按enter键就出发提交的方法,和点击提交按钮一样的效果,官网还提供了其他按键的别名五、v-ifv-if用于做条件化的渲染,当组件的判断条件发生改变,这个组件会被销毁并重建。<template> <div class=“main”> <span v-if=“display”>我叫001</span> <span v-if="!display">我叫002</span> <button @click=“changeShow”>切换</button> </div></template>javascript data(){ return{ display:true } }, methods:{ changeShow(){ this.display = !this.display; }, }运行结果如下图:v-if绑定的变量为 true 的时候,其所在的元素会被渲染出来,反之亦然。六、v-else、v-else-ifv-else 和C语言中的else一样的语法效果。如果条件变量不满足 v-if ,则执行 <v-else> 的内容 <div class=“main”> <span v-if=“display”>我叫001</span> <span v-else>我叫002</span> <button @click=“changeShow”>切换</button> </div>运行效果和上图一致。 v-else-if 是Vue2.1.0版本新增的一个属性。v-else-if 必须用在 v-if 和 v-else 之间才有效果。<template> <div class=“main”> <span v-if=“display === 1”>我叫001</span> <span v-else-if=“display === 2”>我叫002</span> <span v-else>我叫003</span> <button @click=“changeShow”>切换</button> </div></template> data(){ return{ display:1 } }, methods:{ changeShow(){ this.display = (this.display + 1)%3; }, }运行结果如下图:七、v-showv-show 是切换元素的 display 属性的。<template> <div class=“main”> <span v-show=“display”>我叫001</span> <span v-show="!display “>我叫002</span> <button @click=“changeShow”>切换</button> </div></template> data(){ return{ display:true } }, methods:{ changeShow(){ this.display = !this.display; }, }运行效果如下图:八、v-forv-for 用于多次渲染同一模板或者元素。<div class=“main”> <ul v-for="(name, index) in names” :key=“index”> <li>{{index}}、我的名字叫{{name}}</li> </ul> </div> data(){ return{ names:[‘jack’,‘joe’,‘Nancy’, ’lily’] } },运行结果如下图:v-for 多次渲染了li 里面的内容,循环遍历了names 数组,并将结放入 {{name}} 里面。九、v-once v-once 只渲染元素和组件一次,如果内容改变,也会将元素、组件视为静态元素跳过。<div class=“main”> <!– 单个元素 –> <span v-once>This will never change:{{msg}}</span> <!– 有子元素 –> <div v-once> <span>comment:::</span> <span>{{msg}}</span> </div> <!– 循环 –> <ul> <li v-for=“i in names” v-once :key=“i”>{{i}}</li> </ul> <hr> <span>This will change:</span> <!– 单个元素 –> <span>This will never change:{{msg}}</span> <!– 有子元素 –> <div > <span>comment:::</span> <span>{{msg}}</span> </div> <!– 循环 –> <ul> <li v-for=“i in names” :key=“i”>{{i}}</li> </ul> <button @click=“changValue”>testChange</button> </div>data() { return { msg: 111, names: [“jack”, “joe”, “Nancy”, “lily”] }; }, methods: { changValue() { this.msg += 111; this.names[2] = “web”; } }运行效果如下图: 在点击按钮后, msg 会增加,但是上面有v-once指令的元素等则不会重新渲染。十、v-if和v-show的区别前面讲了v-if 和 v-show,两个指令都是用在元素之间的显示和隐藏的切换,那么,这两个指令究竟有什么不同呢?接下来我将用一个示例来讲解他们之间的差异。<template> <div class=“main”> <h3>v-if</h3> <div class=“content” v-if=“display”>1</div> <div class=“content” v-else>2</div> <h3>v-show</h3> <div class=“content” v-show=“display”>1</div> <div class=“content” v-show="!display">2</div> <h3>对比</h3> <div class=“content”>1</div> <div class=“content”>2</div> <button @click=“changeValue”>点击我啦</button> </div></template>data() { return { display: true }; }, methods: { changeValue() { this.display = !this.display; } }.content { display: inline-block; width: 100px; height: 100px; border: solid 1px black; background-color: red;}.content + .content { margin-left: 20px;}运行效果如下图:从上图我们可以看出当display 为 false 的时候,v-if 和v-show显示位置不一样。首先我们解读一下这个代码的css:content类设置了div的长宽和背景色,dispaly属性为 inline-block, .content + .content 设置了如果有两个content 类在一起的时候,后面一个的左边距为20个像素。在dispaly 为 true 的时候,两个div都靠左显示。在 display 为 false 的时候,上面的div在原来的位置重新渲染,但是下面的div却有一个20像素的左边距。所以v-if渲染的时候,不会将不符合条件的元素加载到DOM树里面,而v-show则会将所有的节点都加载到DOM树,然后根据条件,更改节点的display 属性,生成不同的渲染树。 一般来说, v-if需要更高的开销,每次都会改变DOM树,但是v-show 只需要改变元素的 display ,开销更低。十一、v-for和v-if优先级问题当v-for 和v-if 在同一个蒜素里的时候,前者比后者有更高的优先级,所以我们在开发中一定要注意优先级的问题。如果我们是想有条件的跳过循环中的某些项的时候:<template> <div class=“main”> <ul > <li v-for="(count, index) in counts" :key=“index” v-if=“count >30”> {{index + 1}}、我花费了{{count}}元 </li>> {{index + 1}}、我花费了{{count}}元 </li> </ul> </div></template>data() { return { counts:[11,22,33,44,55,66] };运行结果如下图:跳过了count 小于 30 的项 2.如果我们是打算有条件的跳过循环的话那么我们应该将判断写在循环的外面,先判断条件。<template> <div class=“main”> <ul v-if=“counts.length >3”> <li v-for="(count, index) in counts" :key=“index”> {{index + 1}}、我花费了{{count}}元 </li> </ul> </div></template>运行结果如下图:至此,讲完了Vue 的基本语法……撒花✿✿ヽ(°▽°)ノ✿ ...

January 18, 2019 · 3 min · jiezi

Go 语言编译器的 //go: 详解

前言C 语言的 #include一上来不太好说明白 Go 语言里 //go: 是什么,我们先来看下非常简单,也是几乎每个写代码的人都知道的东西:C 语言的 #include。我猜,大部分人第一行代码都是 #include 吧。完整的就是#include <stdio.h>。意思很简单,引入一个 stdio.h。谁引入?答案是编译器。那么,# 字符的作用就是给 编译器 一个 指示,让编译器知道接下来要做什么。编译指示在计算机编程中,编译指示(pragma)是一种语言结构,它指示编译器应该如何处理其输入。指示不是编程语言语法的一部分,因编译器而异。这里 Wiki 详细介绍了它,值得你看一下。Go 语言的编译指示官方文档 https://golang.org/cmd/compil…形如 //go: 就是 Go 语言编译指示的实现方式。相信看过 Go SDK 的同学对此并不陌生,经常能在代码函数声明的上一行看到这样的写法。有同学会问了,// 这不是注释吗?确实,它是以注释的形式存在的。编译器源码 这里可以看到全部的指示,但是要注意,//go: 是连续的,// 和 go 之间并没有空格。常用指示详解//go:noinlinenoinline 顾名思义,不要内联。Inline 内联Inline,是在编译期间发生的,将函数调用调用处替换为被调用函数主体的一种编译器优化手段。Wiki:Inline 定义使用 Inline 有一些优势,同样也有一些问题。优势:减少函数调用的开销,提高执行速度。复制后的更大函数体为其他编译优化带来可能性,如 过程间优化消除分支,并改善空间局部性和指令顺序性,同样可以提高性能。问题:代码复制带来的空间增长。如果有大量重复代码,反而会降低缓存命中率,尤其对 CPU 缓存是致命的。所以,在实际使用中,对于是否使用内联,要谨慎考虑,并做好平衡,以使它发挥最大的作用。简单来说,对于短小而且工作较少的函数,使用内联是有效益的。内联的例子func appendStr(word string) string { return “new " + word}执行 GOOS=linux GOARCH=386 go tool compile -S main.go > main.S 我截取有区别的部分展出它编译后的样子: 0x0015 00021 (main.go:4) LEAL “”..autotmp_3+28(SP), AX 0x0019 00025 (main.go:4) PCDATA $2, $0 0x0019 00025 (main.go:4) MOVL AX, (SP) 0x001c 00028 (main.go:4) PCDATA $2, $1 0x001c 00028 (main.go:4) LEAL go.string.“new “(SB), AX 0x0022 00034 (main.go:4) PCDATA $2, $0 0x0022 00034 (main.go:4) MOVL AX, 4(SP) 0x0026 00038 (main.go:4) MOVL $4, 8(SP) 0x002e 00046 (main.go:4) PCDATA $2, $1 0x002e 00046 (main.go:4) LEAL go.string.“hello”(SB), AX 0x0034 00052 (main.go:4) PCDATA $2, $0 0x0034 00052 (main.go:4) MOVL AX, 12(SP) 0x0038 00056 (main.go:4) MOVL $5, 16(SP) 0x0040 00064 (main.go:4) CALL runtime.concatstring2(SB)可以看到,它并没有调用 appendStr 函数,而是直接把这个函数体的功能内联了。那么话说回来,如果你不想被内联,怎么办呢?此时就该使用 go//:noinline 了,像下面这样写://go:noinlinefunc appendStr(word string) string { return “new " + word}编译后是: 0x0015 00021 (main.go:4) LEAL go.string.“hello”(SB), AX 0x001b 00027 (main.go:4) PCDATA $2, $0 0x001b 00027 (main.go:4) MOVL AX, (SP) 0x001e 00030 (main.go:4) MOVL $5, 4(SP) 0x0026 00038 (main.go:4) CALL “".appendStr(SB)此时编译器就不会做内联,而是直接调用 appendStr 函数。//go:nosplitnosplit 的作用是:跳过栈溢出检测。栈溢出是什么?正是因为一个 Goroutine 的起始栈大小是有限制的,且比较小的,才可以做到支持并发很多 Goroutine,并高效调度。stack.go 源码中可以看到,_StackMin 是 2048 字节,也就是 2k,它不是一成不变的,当不够用时,它会动态地增长。那么,必然有一个检测的机制,来保证可以及时地知道栈不够用了,然后再去增长。回到话题,nosplit 就是将这个跳过这个机制。优劣显然地,不执行栈溢出检查,可以提高性能,但同时也有可能发生 stack overflow 而导致编译失败。//go:noescapenoescape 的作用是:禁止逃逸,而且它必须指示一个只有声明没有主体的函数。逃逸是什么?Go 相比 C、C++ 是内存更为安全的语言,主要一个点就体现在它可以自动地将超出自身生命周期的变量,从函数栈转移到堆中,逃逸就是指这种行为。请参考我之前的文章,逃逸分析。优劣最显而易见的好处是,GC 压力变小了。因为它已经告诉编译器,下面的函数无论如何都不会逃逸,那么当函数返回时,其中的资源也会一并都被销毁。不过,这么做代表会绕过编译器的逃逸检查,一旦进入运行时,就有可能导致严重的错误及后果。//go:noracenorace 的作用是:跳过竞态检测我们知道,在多线程程序中,难免会出现数据竞争,正常情况下,当编译器检测到有数据竞争,就会给出提示。如:var sum intfunc main() { go add() go add()}func add() { sum++}执行 go run -race main.go 利用 -race 来使编译器报告数据竞争问题。你会看到:==================WARNING: DATA RACERead at 0x00000112f470 by goroutine 6: main.add() /Users/sxs/Documents/go/src/test/main.go:15 +0x3aPrevious write at 0x00000112f470 by goroutine 5: main.add() /Users/sxs/Documents/go/src/test/main.go:15 +0x56Goroutine 6 (running) created at: main.main() /Users/sxs/Documents/go/src/test/main.go:11 +0x5aGoroutine 5 (finished) created at: main.main() /Users/sxs/Documents/go/src/test/main.go:10 +0x42==================Found 1 data race(s)说明两个 goroutine 执行的 add() 在竞争。优劣使用 norace 除了减少编译时间,我想不到有其他的优点了。但缺点却很明显,那就是数据竞争会导致程序的不确定性。总结 我认为绝大多数情况下,无需在编程时使用 //go: Go 语言的编译器指示,除非你确认你的程序的性能瓶颈在编译器上,否则你都应该先去关心其他更可能出现瓶颈的事情。 ...

October 21, 2018 · 2 min · jiezi