头部引用js文件
<head>
<meta charset="UTF-8">
<title>测试</title>
<script src="node_modules/vue/dist/vue.js"></script>
</head>
node环境安装vue
npm init -y 初始化项目
# save 的意思是将模块安装到项目目录下,并在package文件的dependencies节点写入依赖
npm install vue --save 安装 ,出错请用管理员身份重试
HTML模板概念
这里HTML块级元素都可以作为模板,需要在Vue实例中绑定该元素的id号,用el声明绑定哪个元素id作为模板,data声明变量,该变量用于模板中引用,通过{{ 变量名 }}方式引用
<div id="app">
<h2>{{name}} 非常酷!</h2>
</div><script>
var app = new Vue({
el:"#app",//el即element,要渲染的页面元素
data: {
name:"黑马"
}
});
</script>
绑定 v-bind 用法
{{name}} 这是Vue插值表达式,但它只能用于文本插值,而不能用于标签属性,否则会报错。因此想动态改变标签的属性值,需要用到v-bind的这个功能。我们大概可以这样去使用它:
<div v-bind:class="color"></div>
通过v-bind: 去标注一个属性,属性值的内容会优先被拿到Vue实例中作为名字,去查找对应的数据,未找到则作为文本。
当然这样的写法太过麻烦。因此我们还可以这样写:
<div :class="color"></div>
仅仅用一个冒号 : 就可以代替,效果一致。
注意,因为class属性可以填多个值,因此这样的属性值也可以采用json的形式,key为类名,value为布尔变量,用来决定该类是否启用。常用来切换style样式。
<div :class="{red:bool,blue:!bool}"> 点击按钮改变背景颜色 </div> //如果 :class 的内容太多,可以这样: <div id="app"> <div v-bind:class="classObject"></div> </div> <script> new Vue({ el: '#app', data: { bool: true, classObject: { 'text-danger': bool } }, //当然classObject不仅仅可以是纯数据,还可以通过方法的返回值 computed: { classObject: function () { return { base: true, active: this.isActive && !this.error.value, 'text-danger': this.error.value && this.error.type === 'fatal', } } } }) </script>
在Vue 实例中定义bool的值为true。
这样,动态改变bool,即可动态改变元素属性。
双向绑定 v-model
<input type="text" v-model="变量名">
例子:
<input type="text" v-model="message"> <script type="text/javascript"> var app=new Vue({ el:"#app", data:{ message:"hello world!!", } }); </script>
样例结果:
修改input文本框内容,变量message的值也会改变。
修改message的值,input文本框的值也会同步改变。
值得注意的是,这个和v-bind不能一起用,会崩溃的
事件处理
<input type="text" v-model="num"><button v-on:click="num++">点我</button>
<script>
var app = new Vue({
el:"#app",//el即element,要渲染的页面元素
data: {
num: 1
}
});
</script>
定义方法
var vm = new Vue({
el:"#app",
data:{
},
methods:{
add:function(){
console.log("点我了...233")
}
}
})
生命周期
Vue实例有生命周期的概念,包括创建,初始化,....,销毁等等,每个阶段都定义了回调函数,称为钩子函数
钩子函数
let app = new Vue({
el:"#app",
data:{
//初始化为空
msg:""
},
created(){
this.msg = "hello vue. created";
}
});
在Vue内部,this可以访问内部成员
插值闪烁
当页面加载完成但Vue内容未渲染完成时,会在对应渲染的地方显示出原始的 {{ }} ,渲染完成后消失。
v-text和v-html
指定 内容 展示在被标记元素的内部,v-text直接展示文本信息,v-html会将内容按照html格式解析
v-on:事件名="js片段或函数名"
v-on: 可以缩写成@
<a href="https://www.baidu.com" v-on:click.stop=""></a> <a href="https://www.baidu.com" @click.stop=""></a>
v-on.stop:阻止事件冒泡
v-on.prevent:阻止默认事件发生 比如上方例子会无法点击
v-on.capture:使用事件捕获模式
v-on.self:只有元素自身触发事件才执行,冒泡不执行
v-on.once:只执行一次
v-on.
left
- 左键事件v-on.
right
- 右键事件v-on.
middle
- 中间滚轮事件v-on:keyup值得注意,Vue为我们设置了超简单的按键监听。
例如我们想要对某个元素做一个回车键监听,大概有如下几种方式:
<input v-on:keyup.13="submit"> <input @keyup.13="submit"> <input v-on:keyup.enter="submit"> <input @keyup.enter="submit">
因为键盘码有很多,不常用,而且不容易记忆,Vue为常用的键起了别名,我们可以调用别名实现对按钮的监听。
.enter
.tab
.delete
(捕获 "删除" 和 "退格" 键).esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta
大概就这些
v-for="item in items"
items为数组时,方式 2 种 : v-for="item in items",v-for=" (item,index) in items"
vue实例会为v-for传入每个值给item,每个值的数组下标给index,index从0开始。
items为对象时,方式 3 种:
v-for = "value in object"
v-for = "(value,key) in object"
v-for = "(value,key,index) in object"
:key="index"
该功能用于标识每一个v-for生成的元素,实现查找定位,当Vue中的数据修改了,以便及时的去更改对应的元素而不至于重新渲染整个v-for。还有就是通过key的标识实现重新排序,和重用。
v-if v-else v-else-if 和 v-show
v-if是条件渲染指令,如果内容结果为true,则加载显示,若为false,则移除该元素。该功能是实时的,即便是已经加载了元素,但一旦v-if的内容被检测到改为false,则会立即触发v-if 的效果。
当然还有v-else、v-else-if两个指令,效果一样,只不过他们要跟在v-if后面,作为一个渲染分支,v-if行不通,就会自动去渲染v-else,或者去判断v-else-if是否需要渲染。
v-show是用来控制元素是否展示的,如果值为true,则为style 的display为元素默认,如果值为false,则style的display为none,该功能也是实时的
两者页面效果相同,但本质不一样,v-show="false"看不见元素,但也能获取到该元素对象,进行操作,v-if="false"则彻底移除该元素。
<button @click="show=!show">切换</button> <h2 v-if="show">hello vue</h2> <h2 v-show="show"> 你好安其拉 </h2>
<script type="text/javascript"> var app=new Vue({ el:"#app", data:{ show:true, } }); </script>
计算属性computed
总结methods与computed区别:
- 调用方式不同。computed直接以对象属性方式调用,不需要加括号,而methods必须要函数执行才可以得到结果。
- 绑定方式不同。methods与compute纯get方式都是单向绑定,不可以更改输入框中的值。compute的get与set方式是真正的双向绑定。
- 是否存在缓存。methods没有缓存,调用相同的值计算还是会重新计算。competed有缓存,在值不变的情况下不会再次计算,而是直接使用缓存中的值。
<div id="app"> <h2> 你的生日是: {{new Date(birthday).getFullYear()}}-- {{new Date(birthday).getMonth()+1}}-- {{new Date(birthday).getDay()}} </h2> <hr> <h2> {{birth}} </h2> </div> <script type="text/javascript"> var app=new Vue({ el:"#app", data:{ birthday:1429032123201 }, computed:{ birth(){ const date=new Date(this.birthday); return date.getFullYear()+"--"+(date.getMonth()+1)+"--"+date.getDay(); } } }); </script>
watch基本和深度监控
在Vue实例中设置的数据或对象都可以监控它值的改变,一般结合v-model绑定使用,当页面上的值修改时,Vue实例中的data部分对应的数据也会自动修改,此时如果我们有需求去监听该值变化,可以使用watch功能。下方案例,通过按钮的点击事件,更改data数据,从而测试页面数据情况,以及监控情况(日志输出)。
<div id="app"> <input type="text" v-model="birthday"><hr> <br> <input type="text" v-model="JSON.stringify(person)"> <input type="text" v-model="person.age"> <hr> <br> <select> <option v-for="item in person">{{item}}</option> </select> <button @click="person.age++">+++</button> </div> <script type="text/javascript"> var app=new Vue({ el:"#app", data:{ birthday:1429032123201, person:{"name":"我的名字","age":22} }, watch:{ //普通的单个值无需开启深度监控,对象类型需要开启 birthday(newValue,oldValue){ console.log(`新值${newValue} 旧值${oldValue}`); }, person:{ //开启深度监控,监控对象属性值的变化 deep:true, handler(obj){ console.log(obj.name+"****"+obj.age); } } } }); </script>
组件的概念counter
我们在编写前端的过程中,会有很多元素块相同,例如淘宝搜索商品的页面,会出现N多个商品模块,这时候就可以通过Vue组件去做,将一个完整的商品模块制作为一个组件,然后通过自定义组件对象名作为标签,在页面中引用。
当然后端工程师也可以做....但后端耗费服务器,前端耗费客户端,开发者当然首选耗费客户端......
我们制作好组件之后,引用时又分为两种,全局引用和局部引用,因为Vue的语法都只在Vue模板中才能使用,因此这里的全局引用,指的是在Vue实例之外声明,可以在任意的Vue模板中引用。而局部引用,是在Vue实例内部的 components 中声明,只能在自己的模板中引用,其他地方引用无效。
注意:如果在全局和局部都声明了同一个组件,则会采用全局引用的作用。
<div id="app2"> //引用组件 <counter></counter> <counter></counter> <counter></counter> </div> <div id="app"> //引用组件 <counter></counter> <counter></counter> <counter></counter> </div> <script type="text/javascript"> //定义组件 const counter={ template:"<button @click='num++'>{{num}}</button>", data(){ return {num:0} } }; //注册组件 //全局组件 Vue.component("counter",counter); //局部组件 var app2=new Vue({ el:"#app2", components:{ // counter:counter } }); var app=new Vue({ el:"#app", components:{ // counter:counter } }); </script>
定义组件
注意,在定义模板所需数据的时候,需要以如下data()的方式返回JSON串
const counter={ template:"<button @click='num++'>{{num}}</button>", data(){ return {num:0} } };
组件通信
父向子通信
首先我们自己定义一个组件,父向子通信其实就是指Vue实例向组件传递数据,组件通过设置props属性,并在其中定义接收的参数名。
Vue.component("introduce",{ // 直接使用props接收到的属性来渲染页面 template:'<h3>{{title}}</h3>', props:[title] // 通过props来接收一个父组件传递的属性 }) var app = new Vue({ el:"#app", data:{ msg: "父组件中的msg属性的内容" } });
使用组件:
<introduce :title="msg"></introduce>
这时候组件会调佣自己template的信息以及传入Vue实例内部的参数。
父向子传递复杂数据
<div id="app"> <my-list :items="lessos"></my-list> </div> <script type="text/javascript"> const myList={ template:`<nav><li v-for='item in items' :key='item.id'> {{item.id}}--{{item.name}} </li></nav>`, props:{ //定义接收数据类型,Array或者Object,default设置接不到数据后的默认数据。 items:{ type:Array, default:[] } } }; var app=new Vue({ el:"#app", data:{ //定义组件要用的数据 lessos:[ {"id":1,"name":"java"}, {"id":2,"name":"php"}, {"id":3,"name":"web"} ] }, components:{ myList } }); </script>
子向父传递数据
子向父传递数据主要是通过子组件调用父实例的方法,然后在方法设置传递参数,达到传递数据的效果。具体做法:
<div id="app"> <h2>{{num}}</h2> <h2>{{msg}}</h2> <my-list @plus="numPlus" @reduce="numReduce"></my-list> </div> <script type="text/javascript"> const myList={ template:`<div><button @click='incrNum'>+</button><button @click='decrNum'>-</button></div>`, methods:{ incrNum(){ //this.$emit调用自定义属性并传入参数 return this.$emit("plus","我是子数据,加"); }, decrNum(){ return this.$emit("reduce","我是子数据,减"); } } }; var app=new Vue({ el:"#app", data:{ num:0, msg:"我是现在还是父信息" }, components:{ myList }, methods:{ numPlus(msg){ this.msg=msg; this.num++; }, numReduce(msg){ this.num--; this.msg=msg; } } }); </script>
Vuejs ajax
vue-resource是Vue.js的插件,提供了使用XMLHttpRequest或JSONP进行web请求和处理响应的服务。当vue更新到2.0之后,作者就宣告不在对vue-resource更新,而推荐使用axios。
axios
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
1.安装axios
npm install axios -S
2.全局注册,在main.js中 引入
import axios from 'axios'
3.注册
Vue.prototype.$http = axios
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
(promise是ES6标准通用的一个处理异步操作的工具,他可以等待异步结果,并返回成功或者失败的信息,触发成功或失败的回调函数)
axios可以使用的方法有:
axios(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])config配置
{ // `url` 是用于请求的服务器 URL url: '/user', // `method` 是创建请求时使用的方法 method: 'get', // 默认是 get // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。 // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL baseURL: 'https://some-domain.com/api/', // `transformRequest` 允许在向服务器发送前,修改请求数据 // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法 // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream transformRequest: [function (data) { // 对 data 进行任意转换处理 return data; }], // `transformResponse` 在传递给 then/catch 前,允许修改响应数据 transformResponse: [function (data) { // 对 data 进行任意转换处理 return data; }], // `headers` 是即将被发送的自定义请求头 headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json' }, // `params` 是即将与请求一起发送的 URL 参数 // 必须是一个无格式对象(plain object)或 URLSearchParams 对象 params: { ID: 12345 }, // `data` 是作为请求主体被发送的数据 // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH' // 在没有设置 `transformRequest` 时,必须是以下类型之一: // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams // - 浏览器专属:FormData, File, Blob // - Node 专属: Stream data: { firstName: 'Fred' }, // `timeout` 指定请求超时的毫秒数(0 表示无超时时间) // 如果请求话费了超过 `timeout` 的时间,请求将被中断 timeout: 1000, // `withCredentials` 表示跨域请求时是否需要使用凭证 withCredentials: false, // 默认的 // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream' responseType: 'json', // 默认的 // `maxContentLength` 定义允许的响应内容的最大尺寸 maxContentLength: 2000, // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否 则,promise 将被 rejecte validateStatus: function (status) { return status >= 200 && status < 300; // 默认的 }, // `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目 // 如果设置为0,将不会 follow 任何重定向 maxRedirects: 5 // 默认的 }
响应体的结构:
{ // `data` 由服务器提供的响应 data: {}, // `status` 来自服务器响应的 HTTP 状态码 status: 200, // `statusText` 来自服务器响应的 HTTP 状态信息 statusText: 'OK', // `headers` 服务器响应的头 headers: {}, // `config` 是为请求提供的配置信息 config: {} }
例子
//通用请求 axios({ url:"data.json", methods:"get" }).then(res=>{ console.log(res); app.users=res.data; }).catch(err=>alert(err)); //get axios.get('/user/12345') .then(function(response) { console.log(response.data); console.log(response.status); console.log(response.statusText); console.log(response.headers); console.log(response.config); }).catch(function (error) { console.log(error.data); console.log(error.status); console.log(error.statusText); console.log(error.headers); console.log(error.config); } ); // post axios.post("data.json").then(res=>{ console.log(res); app.users=res.data; }).catch(error=>alert(error));
在使用 catch 时,或传递 rejection callback 作为 then 的第二个参数时,响应可以通过 error 对象可被使用。
axios的跨域解决方案:
注意:如果使用axios访问跨域数据的时候,只需要在服务提供方中,在方法上面使用SpringMVC的跨域注解即可解决数据跨域问题。如在方法上添加:@CrossOrigin(origins = "http://localhost:10000")
如果请求的地址是使用了网关,那么在网关服务器上配置跨域就可以了;不能同时在网关服务器和服务提供服务工程中同时配置。