因为项目需要前后端分离,后端竟然不用控制view层了,页面的跳转后端不再干涉,(前端的vue经过打包后成了一张index.html) 后端只需要响应给前端json串就ok,其实这不是爽歪歪?但是觉得还是奇奇怪怪,感觉前端是个黑盒了, 于是忍不住去学习了vue
感觉前端的框架带来的这种前后端分离变化还是特别明显的,后端确实不用再操心view层了,页面的转换有vue通过后端的切换不同的组件,后端基本上没有什么变化,但是相应数据基本上是清一色的json格式的数据了, 此外, 目前碰到的后端的安全框架 SpringSecurity的使用有了些许变化,起码认证成功还是失败,不能往指定的页面跳转了,转而使用消息+状态码提示,因为就一张index.html,还能往哪里跳转?
下面是近几天的学习笔记, 还是再整理一遍,毕竟会忘
认识MVVM框架Vue#
MV VM分别对应着
- model : 数据模型,存放后端传递过来的数据
- view : 视图,其实就是html, 页面
- viewModel : vue 的实例
下面是一个入门的例子: 通过这个例子可以看到:
- 我们new 出来vue的实例,然后把它关联在了html中id为 app的代码块,这样目的是如果我们在这个代码块中使用vue的模板语法,vue可以解析
- data: 这个模块盛放的 mvvm中的第一个m
其实这也可以看出,vue的开发模式,它的出现屏蔽掉了dom操作,我们再也不用document.getElementById(), 然后innnerHtml了, 现在的工作就是把后端给的值填充进data块中的属性字段就ok,一旦发生改变,页面会自动渲染上最新的值
<body> <div id="app"> <input type="text" v-model="username"><!-- 声明式开发 dom监听 --> <p>Haha {{username}}</p> <!-- 数据绑定 --> </div> </body> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ el:'#app', // 元素选择器, 选出根路径 data:{ // Data Model 数据模型 username:'哈哈' } }); </script>
模板语法:#
双大括号 取值:
<p>{{msg}}</p> <p>{{msg.toUpperCase()}}</p> <!-- 可以调用js函数 -->
嵌入文本或html
<p v-text="msg"></p> <!-- 相当于 textContent --> <p v-html="msg"></p> <!-- 相当于 innerHtml -->
强制数据绑定,在原标签前添加 :
<img :src="imaUrl" alt="">
绑定监听事件: @符
- 比较有趣的地方,如果在methods块中,js函数的定义是无参数据的, 在html代码块中可以直接写函数名,而不写小括号,因为java代码写多了,看了想笑 ,(当然(),也可以写上,但是js编程者会认为这是没事找事)
<button @click="text"> 点我111 </button> <button @click="text222('haha')"> 点我222 </button>
计算属性#
计算属性,说白了就是vue给我们的一块糖,让我们定制数据的变化规则,然后vue帮我们渲染在html页面上
现在是2020年的5月23号,当我再回来看computed时,想再补充一下,如何更好的理解计算属性: 所谓计算属性,说白了,其实就是根据data中现有的属性计算得到一个新的属性 ,此外,计算属性函数是不需要我们手动执行的,会自动执行
- 计算属性是针对data中的字段的操作
- 计算属性中的每一个函数,都分两部分: get和set , 默认是get,作用是把这个方法的返回值渲染进页面, set方法,就是重新设置值, 然后get会重新渲染html
- 计算属性是存在缓存的,key就是函数的名字,value就是计算得到的值
例子:
<body> <div id="app"> 姓名: <input type="text" placeholder="FirstName" v-model="secondName"> <br> 姓名1: <input type="text" placeholder="FullName1" v-model="FullName1"> <br> 姓名3: <input type="text" placeholder="FullName3" v-model="FullName3"> <br> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> // 下面的全部回调函数中, this都是vm对象 var vm = new Vue({ el: '#app', data: { firstName: 'A', secondName: 'B', }, computed: { FullName1() { return this.firstName + ' ' + this.secondName; }, // todo 通过计算属性实现双向的数据绑定, 不受其他影响 FullName3: { get() { // 计算并返回当前属性的值 return this.firstName + ' ' + this.secondName; }, set(vel) { // get 执行之后 把结果返回给 set const names = vel.split(' '); alert(names[0]); alert(names[1]); this.firstName = names[0]; this.secondName = names[1]; } } } });
计算属性写在computed块中, 可以看到它常用的两种写法, 在使用是时候都是直接使用函数名就行,因为它并没有参数
- 函数名(){}
- 对象名:{ get(){} , set(){} }
上面的FullName1
以函数的,这种书写格式是对 get方法的默认实现,方法的返回值会被渲染到页面上
FullName3
还重写了set(val){} 方法, 如果我们在FullName3
对应的输入框里面输入新的值, val就是这个新的值,在set方法中,如果对当前vue实例的data中的属性做了改动,这个改动是双向的,页面中所有使用对应字段的地方的值,都会重新渲染
事件的监听:#
它的语法:
// 下面的全部回调函数中, this都是vm对象 var vm = new Vue({ el: '#app', data: { firstName:'', secondName:'' }, computed: {}, method: {}, watch: {/* 监视 */ firstName: function (newVal) { this.firstName = newVal + ' ' + this.secondName; } } });
它会监听data中的属性,当用户改变了data中属性的值,就会触发对应的回调
class和style的绑定#
class和style的属性绑定同样使用的是使用 : 强制属性绑定
首先是写好 css属性,才能进一步使用vue将属性样式绑定在html上
head> <meta charset="UTF-8"> <title>Title</title> <style> .aClass{ font-size: 30px; color: #ff4400; } .bClass{ color: #00b4ff; } .cClass{ color: #1c036c; } </style> </head>
语法:
- :class="data中的css属性"
- :class="{data中的css属性:boolean, data中的css属性:boolean}", 这种对象语法,就是当类名确定但是是否显示不确定时使用,比如让一个导航栏中的一个高亮显示
- :style="{color:activeColor,fontSize:fontSize +'px'}", style有单位的+单位
<body> <div id="text"> <h2>1. class绑定 :: class='X X X '</h2> <p :class="a">123123字符串</p> <p :class="{aClass:isa, bClass:isb}">class是对象,绑定class 类名:boolean </p> <h2>2. style 绑定 </h2> <p :style="{color:activeColor,fontSize:fontSize +'px'}">2. style 绑定 </p> <button @click="update" >点击</button> </div>
下面的vue对象
<script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ el: '#text', data: { a:'aClass', // 关联着最上面的css样式 isa:true, isb:false, activeColor:'red', fontSize:'30' }, methods:{ update() { this.a='bClass' } } })
条件渲染#
<p v-if="ok">deal</p> --> ok是vue中data的数据,ok为true时, 显示 <p v-else>false</p> --> 和 v-if成对出现, ok为false, 显示 <p v-show="ok"> 成功 </p> <p v-show="!ok"> 失败 </p>
列表的渲染 v-for, 及对数组的操作#
下面的例子使用v-for遍历数组中的每一个数据, 遍历的同时使用{{对象.属性}}展示属性,同时可以根据每个li的index绑定上不同的事件
<body> <div id="text"> <ul> <!-- 一旦有 v-for 加上key--> <li v-for="(p,index) in person" :key="index"> {{p.name}} : {{p.age}} : {{index}} <button @click="deleteP(index)"> 删除</button> <button @click="updateP(index,{name:'Cat',age:20})"> 更新</button> </li> </ul> </div> var vm = new Vue({ el: '#text', data: { person: [ /* vue 只会监视person的改变, 不会监视数组中数据的改变*/ {name: 'tom', age: 23}, {name: 'tom2', age: 223}, {name: 'tom2', age: 23}, {name: 'tom3', age: 232}, {name: 'tom5', age: 23} ] }, methods: { deleteP(index) { this.person.splice(index, 1); //从index开始 删除1个 }, updateP(index, person) { // this.person[index]=person; 并没有改变 persons , 从index开始,删除1个 添加person this.person.splice(index, 1, person) }
如果我们更新的js是这样写的, 数组中的内容确实会被改变,但是页面的上数据并不会更新
this.person[index]=person; 并没有改变 persons , 从index开始,删除1个 添加person
因为vue监听的person的改变,person中只有一个数组,虽然数组中的数据变了, 但是数组没变,所以我们使用vue的提供的splice进行数组的操作
splice(下标,数量,[新的对象数组])#
他可以实现数组的增删改的效果
- 删除
//删除起始下标为1,长度为2的一个值(len设置2) var arr2 = ['a','b','c','d'] arr2.splice(1,2); console.log(arr2); //['a','d']
- 修改
//替换起始下标为1,长度为1的一个值为‘ttt’,len设置的1 var arr = ['a','b','c','d']; arr.splice(1,1,'ttt'); console.log(arr); //['a','ttt','c','d']
- 添加
var arr = ['a','b','c','d']; arr.splice(1,0,'ttt'); console.log(arr); //['a','ttt','b','c','d']
其他数组相关的操作
unshift()
添加到第一个shift()
添加到最后一个push()
压栈,栈顶pop()
弹出sort()
排序reverse()
反转
数组的映射,过滤,排序#
js的箭头函数和java8的lambda表达式特别像
- 映射
array.map(item=>item.id) // 可以将数组中的每一个元素映射成他的id属性
- 过滤
persons = person.filter(p => p.name.indexOf(searchModel)>=0); // 保留数组中满足条件的对象
- ES6的语法糖
把对象的指定字段存放进声明的多个常量中
const{searchModel,person,orderType} = this;
- 排序
persons.sort(function (p1,p2) { // 升序 if (orderType===1){ return p1.age-p2.age; } else if (orderType===2){ // 降序 return p2.age-p1.age; }