验证码机制
在后端里,总是认为前端有可能会被伪造。页面上的验证码是后端随机产生的(也可以前端生成,但不建议)
步骤:
- 1.后端调用相关的绘图第三方类库,或是(平台PHP,.NET,Java)系统核心绘图类库进行图片的绘制
- 2.绘制的那些随机的数字、字母都是后端预先定义好的
- 3.绘制图片的URl地址通过网络发送给客户端,然后,客服端可以通过img标签去引用这个验证码的地址
- 4.后端在绘制完毕验证码后,随机选择生成的字母不能丢弃而是需要保存到session中,可用于识别哪个用户
- 5.当客服端输入验证码完毕后会提交表单,后端会拿到相关数据与session中的验证码进行比较,一样则通过
前端发展史:
原生JS----jQuery之类的类库----模板引擎----MVVM框架
- 原生JS:API难懂,还得兼容各种浏览器
- jQuery:解决了浏览器兼容问题,但还是得频繁的操作DOM元素,不断的拼接字符串,心力交瘁
- 模板引擎:只需要调用模板引擎提供的一些方法就可以把DOM元素生成,不需要开发者自己渲染页面
- MVVM框架:
MVVM一直与MVC一起出现在文章中,要注意区别他俩:- MVC是后端开发分层开发概念
- MVVM是前端视图层的概念,主要关注于视图层分离
Model: 数据的拥有者,实现具体的业务逻辑,是业务逻辑模型而不是数据模型。
View: 具体的用户界面,如按钮、列表、图片。
Controller: 负责将 View 中用户的动作传达给 Model,将 Model 的数据通过 View 展现出来。
MVVM
模型(Model):数据模型
视图(View):调用ViewModel的方法并响应变化。
视图模型(ViewModel):业务逻辑。
前端三大主流框架:
- Vue.js
很火,能开发手机APP,需要借助weex
适合做单页面应用程序 - React.js
很流行,也能开发手机APP
适合做单页面应用程序 - Angular.js
适合做单页面应用程序
框架和库的区别:
框架
提供一套完整的解决方案,对项目的侵入性较大,项目如果需要更换框架,则需要重新架构整个项目
库
提供小功能,类似一个插件,对项目侵入性小,如果某个库无法完成需求,可以很容易切换到其他库实现需求。
例如从jQuery切换到zepto,从EJS切换到art-template
Vue.js 是什么
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
vue让开发者不用关注DOM操作,只关注业务逻辑
Vue.js的代码与MVVM之间的对应关系
一个简单的例子Vue的基本代码结构和插值表达式
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
......
<div id="app">
<p>{{msg}}</p>
</div>
......
<script>
var vm = new Vue({
el:"#app",
data:{
msg:"123"
}
})
</script>
当用script引入vue时,window中多了一个vue的构造函数,通过new,创建一个vue对象vm。
el:表示这个vue实例控制的页面区域,不能绑定到body上面去
data:存放el中要用到的数据,通过指令或者插值表达式渲染到页面。
指令:在后面的模块学习
插值表达式{{}}:花括号里边写数据的名字
vue的指令
-
v-cloak:解决页面加载闪烁
当网络很差,或者其他一些原因导致页面加载闪烁,出现指令或者标签,非常影响用户观感,可以用这个指令解决。
通常是下面这样两种情况时会发生闪烁:
<p>{{msg}}</p>//插件表达式时闪烁
<p v-html="msg"></p>
解决办法:给挂载元素添加v-cloak指令,再在style里边定义一个样式就可以了
<style>
[v-cloak] {
display: none;
}
</style>
.......
<div id="app" v-cloak>
<p>{{msg}}</p>
</div>
......
<script>
var vm = new Vue({
el:"#app",
data:{
msg:"123"
}
})
</script>
-
v-text
写法:
<p v-text="msg"></p>
作用:将msg显示在页面上。
v-text指令与插件表达式的区别与相同点
- v-text没有加载闪烁问题
- v-text会覆盖元素原本的内容,但插值表达式只会替换占位符
- v-text 与差值表达式都会把msg当成普通文本来处理
<p>{{msg2}}</p>
<p v-text="msg2"></p>
......
msg2:"<h1>我是h1标签</h1>"
都把标签当成普通文本处理
那么,如何渲染msg2呢?
-
v-html
渲染带有标签的文本,会覆盖原本的内容
//添加这句
<p v-html="msg2">hhhh
<span>jjjj</span>
</p>
用v-html渲染出来了
v-bind 绑定属性
写法:
<div :class="div"></div>
<div v-bind:class="div"></div>
<div id="app">
<input type="text" value="按钮" title="myTitle">
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
myTitle:"这里是input标签的title"
}
})
</script>
给title属性绑定值,但这样明显不对
那该怎么办呢?用v-bind标签
<div id="app">
<input type="text" value="按钮" v-bind:title="myTitle">
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
myTitle:"这里是input标签的title"
}
})
</script>
这才是我们想要的结果
v-bind指令在解析变量时,当成了js表达式去解析,故而可以有如下写法:
<input type="text" value="按钮" v-bind:title="myTitle + '123'">
image.png
v-on 添加事件
写法:
......
<input type="text" value="按钮" v-on:click="alert('aaaa')">
//或者
<div @click="test">点击</div>
......
<script>
var vm = new Vue({
el:"#app",
methods:{
test:function(){
alert("点击");
}
}
})
</script>
事件修饰符
- .stop:相当于JavaScript中的event.stopPropagation(),防止事件冒泡
......
<div class="outer" @click="outer">
<div class="middle" @click="middle">
<button class="inner" @click="inner">点击</button>
</div>
</div>
<p v-text="text"></p>
......
<script>
var vm = new Vue({
el:"#app",
data:{
text:"测试事件冒泡"
},
methods:{
outer:function(){
this.text="outer";
console.log("outer");
},
middle:function(){
this.text="middle";
console.log("middle");
},
inner:function(){
this.text = "inner";
console.log("inner");
}
}
})
</script>
点击后,页面最终显示outer
可以看到事件的执行顺序是这样的
这种情况就是事件冒泡,原生JS通过event.stopPropagation()阻止,在vue中,可以通过.stop来阻止。
<div class="outer" @click="outer">
<div class="middle" @click="middle">
<button class="inner" @click.stop="inner">点击</button>
</div>
</div>
可以看到只执行了inner函数
- .prevent:相当于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播)
比如a链接有默认的跳转行为,下面的demo点击后会执行函数并跳转页面,可若我们不想跳转页面的话,该怎么办呢?
<div class="container">
<a href="http://baidu.com" @click="linkClick">跳转到百度</a>
</div>
......
linkClick:function(){
console.log("触发了链接的点击事件");
}
改为下面这样就好了
<a href="http://baidu.com" @click.prevent="linkClick">跳转到百度</a>
触发了事件也取消了跳转页面
-
.capture:添加事件侦听器时使用事件捕获,与事件冒泡的方向相反,事件捕获由外到内
图片来自其他博客,详见参考
略微修改阻止冒泡的demo代码
<div class="outer" @click.capture="outer">
<div class="middle" @click="middle">
<button class="inner" @click="inner">点击</button>
</div>
</div>
<p v-text="text"></p>
先outer,再inner最后middle
这是因为先因为捕获机制执行了outer,再默认冒泡机制执行inner和middle,如果想从外到内依次执行的话,给middle也加上捕获机制
<div class="outer" @click.capture="outer">
<div class="middle" @click.capture="middle">
<button class="inner" @click="inner">点击</button>
</div>
</div>
<p v-text="text"></p>
从外到内一次执行
- .self:只会触发当事件在该元素本身的事件(不包含子元素)
<div class="outer" @click="outer">
<div class="middle" @click.self="middle">
<button class="inner" @click="inner">点击</button>
</div>
</div>
<p v-text="text"></p>
点击按钮并没有执行outer,但是执行了outer,这是.self跟.stop的区别
- .once:事件只会触发一次
<div class="container">
<a href="http://baidu.com" @click.prevent.once="linkClick">跳转到百度</a>
</div>
点击第一次,阻止了默认行为,触发了点击函数,点击第二次的时候,没有触发点击函数,默认行为也执行了(即跳转到了百度页面),调换事件修饰符位置效果也一样
注意事件修饰符可以连用
区别事件修饰符的应用场合
.self:只阻止自己的冒泡,外层还能继续冒泡
.stop:阻止了自己及往外层的的冒泡行为
v-model:表单元素的数据双向绑定
只能用于表单元素中
比如有一input,我们想要获取输入的值,按照学习,应该是用v-bind绑定我们的value属性
<div class="container">
<input type="text" v-bind:value="msg">
</div>
......
msg:"双向数据绑定",
先将数据从M渲染到了V
但并没有将用户在V修改的数据绑到M
原因就是v-bind只能单向绑定。修改为:
<div class="container">
<input type="text" v-model="msg">
</div>
v-model也能正确的渲染
可以看到,用户的输入绑定到了M
在vue中使用样式
一、使用class样式
原生形式:
<style>
.red{
color:red;
}
.italic{
font-style: italic;
}
.thin{
font-weight: 10;
}
.active{
letter-spacing:0.5em;
}
</style>
<body>
<div class="" id="app">
<h1 class="red italic thin">这是一个h1标签</h1>
</div>
</body>
</html>
<script>
var vm = new Vue({
el:"#app",
data: {
},
methods: {
}
});
</script>
1.数组
直接传递一个数组,这里的class需要使用v-bind绑定,类名需要写引号,不写的话会去data里面找数据
<h1 :class="['red','italic','thin']">这是一个h1标签</h1>
2.数组中使用三元表达
会先去data里面找flag变量,为true则返回'active'
<h1 :class="['red','italic','thin',flag?'active':'']">这是一个h1标签</h1>
......
flag:true
3.数组中嵌套对象
因为三元表达式麻烦,不好写,也不好理解,所有可以用这种形式
flag为true时有active,false时没有active
<h1 :class="['red','italic','thin',{'active':flag}]">这是一个h1标签</h1>
//或
<h1 :class="['red','italic','thin',{active:flag}]">这是一个h1标签</h1>
进一步可以定义到data里边
<h1 :class="classList">看一看,瞧一瞧哪!!!!</h1>
.......
flag:true,
classList:['red','italic','thin',this.flag?'active':'']
4.直接使用对象
对象里属性就是类名,属性值是一个标识符。由于对象的属性可带引号,可以不带引号,故这里类名加不加引号无所谓
<h1 :class="{red:true,italic:true}">这是一个h1标签</h1>
//或
<h1 :class="{'red':true,'italic':true}">这是一个h1标签</h1>
//或
<h1 :class="{red:true,'italic':true}">这是一个h1标签</h1>
咱们可以进一步把对象定义到data里边,再通过属性引用
<h1 :class="classObj">这是一个h1标签</h1>
.......
classObj : {red:true,italic:true}
二、使用内联样式
1.直接在元素上通过:style
的形式,书写样式对象
2.将样式对象定义到data
对象中,直接引用到:style
中
3.在:style
中通过数组,引用多个data
上的样式对象
v-for:循环
1.迭代数组
按照以前学的,咱可以这样迭代数组
<p>{{list[0]}}</p>
<p>{{list[1]}}</p>
<p>{{list[2]}}</p>
<p>{{list[3]}}</p>
<p>{{list[4]}}</p>
......
list:[1,2,3,4,5]
但是这样太low了,我们可以使用v-for指令
<p v-for="item in list">{{item}}</p>
//或
<p v-for="(item,index) in list">索引值:{{index}},每一项的内容:{{item}}</p>
迭代纯数组
<p v-for="item in user">id是:{{item.id}},name为:{{item.name}}</p>
<p v-for="(item,index) in user">索引值:{{index}},id是:{{item.id}},name为:{{item.name}}</p>
......
user:[
{id:1,name:"zs"},
{id:2,name:"sd"},
]
迭代对象数组
2.迭代对象中的属性
<p v-for="(val,key) in people">值:{{val}},键:{{key}}</p>
//或
<p v-for="(val,key,index) in people">值:{{val}},键:{{key}},索引值值:{{index}}</p>
......
people:{
id:1,
gender:"女",
name:"Jan"
}
渲染出了键值对=和索引值
3.迭代数字
<p v-for="count in 10">这是第{{count}}次循环</p>
注意count从1开始计数
总结:
in 后面可以放 普通数组,对象数组,对象,数字
v-for中的key
在2.2.0+的版本中,当在组件中使用v-for时,或者一些特殊情况下,key是必须要写的。
当vue.js用v-for正在更新已渲染的元素列表时,他默认是使用就地复用策略,如果数据项的顺序被改变,Vue将不是移动DOM元素来匹配数据项的顺序,而是简单复用此时每个元素,并且确保他在特定索引下显示已被渲染的每个元素。
为了给Vue一个提示,以便它能跟踪每个节点的身份,从而复用和重新排序现有元素,需要为每项提供一个唯一key属性。
在尾部添加
<div>
<label>ID:<input type="text" v-model="id"></label>
<label>姓名: <input type="text" v-model="name"></label>
<input type="button" value="添加" @click="addGaint">
</div>
<p v-for="(item,index) in gaint">
<input type="checkbox">{{item.id}} {{item.name}}
</p>
......
data:{
gaint:[
{id:1,name:"李斯"},
{id:2,name:"嬴政"},
{id:3,name:"赵高"},
{id:4,name:"韩非"},
{id:5,name:"荀子"}
],
id:0,
name:""
},
methods:{
addGaint:function(){
this.gaint.push({id:this.id,name:this.name});
}
}
无论选没选中,在尾部添加都没有bug
在头部添加
addGaint:function(){
this.gaint.unshift({id:this.id,name:this.name});
}
直接添加时,吕不韦被正常渲染在了第一个,我们选中荀子后再点击添加,结果如下图
吕不韦正常渲染出来了,但是选中状态从荀子变为了韩非
这就是因为没有标识,记住的是选中了第6个而不是选中的荀子。
解决方案就是加上key(key只能是Number或者String,而且用v-bind绑定),它能强制地让我们data里的属性跟页面上地显示关联起来
<p v-for="(item,index) in gaint" :key="item.id">
<input type="checkbox">{{item.id}} {{item.name}}
</p>
再选中荀子添加,添加完后选中的还是荀子
v-if ,v-show
总结:一般来说,v-if有更高的切换消耗(因为每次切换都涉及到DOM元素的删除和创建),而v-show有更高的初始渲染消耗(比如一直为false,不太可能变为true的标签,用这个的话也要进行渲染)。
因此,如果需要频繁切换v-show较好,如果在运行时条件不大可能改变v-if较好。
<button @click="flag = !flag">切换</button>
//这里不能简写为!flag,因为这样的话就不会重新赋值
<p v-if="flag">这是v-if控制的标签</p>
<p v-show="flag">这是v-show控制的标签</p>
......
data:{
flag:true,
}
flag为false时,v-if控制的标签被移除了
网友评论