Vue基本语法
一、Hello Vue
1.1 引入 Vue.js 文件
Vue.js 提供了两个版本的文件:
-
开发环境:包含了使用帮助的命令行警告
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
-
生成环境:优化了尺寸和速度
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
这里我们采用开发环境版本的 Vue.js
文件
1.2 定义视图对象并添加插值表达式
<!--2.定义视图对象,并添加一个插值表达式 -->
<div id="app">
{{message}}
</div>
1.3 创建Vue对象绑定到之前申明的视图对象上,并设置 message 值
<script>
<!--3.创建Vue对象绑定到之前申明的视图对象上,并设置 message 值-->
var app = new Vue({
el: "#app",
data: {
message: "Hello Vue!"
}
});
</script>
完整代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello Vue</title>
<!--1.导入 JS 文件-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!--2.定义视图对象,并添加一个插值表达式 -->
<div id="app">
{{message}}
</div>
<script>
<!--3.创建Vue对象绑定到之前申明的视图对象上,并设置 message 值-->
var app = new Vue({
el: "#app",
data: {
message: "Hello Vue!"
}
});
</script>
</body>
</html>
二、Vue 常用属性
2.1 el
只在用 new
创建实例时生效,用于指定挂载元素,表示Vue 的作用域。如之前的实例 #app 就是将 Id
值为 app
的元素挂载到 vue 对象上去。
2.2 data
Vue 实例的数据对象,可以包含多种类型的数据:
<div id="app">
{{string}}
<br>
{{integer}}
<br>
{{array[2]}}
<br>
{{user.name}} -- {{user.age}}
</div>
<script>
var app = new Vue({
el: "#app",
data: {
string: "文本类型的数据",
integer:18,
array:[
new Date("2020-12-01"),
new Date("2020-12-02"),
new Date("2020-12-03"),
new Date("2020-12-04")
],
user:{
name:"张三",
age:23
}
}
});
</script>
2.3 computed
计算属性,它的结果会被缓存,除非依赖的响应式属性变化才会重新计算。注意,如果某个依赖 (比如非响应式属性) 在该实例范畴之外,则计算属性是不会被更新的。
<div id="app">
{{userinfo}}
</div>
<script>
var app = new Vue({
el:"#app",
data:{
name:"张三",
age:18,
},
computed:{
userinfo:function(){
return "姓名:"+ this.name +";年龄:"+ this.age;
}
}
});
</script>
2.4 methods
方法对象,申明 Vue 对象的行为:
<div id="app">
<!-- v-on:click 绑定按钮单击事件 -->
<button v-on:click="showName()">显示用户姓名</button>
<button v-on:click="showAge()">显示用户年龄</button>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
name:"张三",
age:18
},
methods:{
showName :function(){
alert("name:"+this.name)
},
showAge :function(){
alert("age:"+this.age);
}
}
});
</script>
2.5 watch
侦听器,当需要在数据变化时执行异步或开销较大的操作时可以采取这种方式:
<div id="app">
<button v-on:click="toUpperCase">转大写</button>
<button v-on:click="toLowerCase ">转小写</button>
<br>
{{message}}
</div>
<script>
var app = new Vue({
el:"#app",
data:{
message:"hello vue"
},
methods:{
toUpperCase:function(){
this.message = this.message.toUpperCase();
},
toLowerCase:function(){
this.message = this.message.toLowerCase();
}
},
watch: {
message:function(newValue, oldValue) {
console.log("原值:"+oldValue);
console.log("新值:"+newValue);
}
},
});
</script>
点击转大写按钮,然后点击转小写按钮,查看控制台输出:
原值:hello vue
新值:HELLO VUE
原值:HELLO VUE
新值:hello vue
2.6 template
模版对象,用来动态添加 DOM:
<div id="app1">
</div>
<!--==============-->
<div id="app2">
</div>
<template id="template">
<h1>引入template标签的形式</h1>
</template>
<!--==============-->
<div id="app3">
</div>
<script type="x-template" id="x-template">
<h1> 引入script的形式</h1>
</script>
<script>
new Vue({
el:"#app1",
template:"<h1>通过直接书写HTML的形式添加</h1>"
});
new Vue({
el:"#app2",
template:"#template"
});
new Vue({
el:"#app3",
template:"#x-template"
});
</script>
三、Vue 生命周期
3.1 介绍
函数名称 | 说明 |
---|---|
beforeCreate | 组件实例刚被创建,组件属性绑定前,如data属性等 |
created | 组件实例创建完成,属性绑定完成,但DOM未生成,$el 属性不存在 |
beformMount | 模板编译/挂载之前 |
mounted | 模板编译/挂载之后 |
beforeUpdaate | 组件更新之前 |
updated | 组件更新之后 |
activated | for keep-alive,组件被激活时调用 |
deactivated | for keep-alive,组件被移除时调用 |
beforeDestory | 组件销毁前调用 |
destoyed | 组件销毁后调用 |
3.2 使用场景
- beforeCreate 可以在此时加一些 loading 效果,在created时进行移除
- created 需要异步请求数据的方法可以在此时执行,完成数据的初始化
- mounted 当需要操作 DOM 的时候执行,可以配合
$.nextTick
使用进行单一事件对数据的更新后更新 DOM - updated 当数据更新需要做统一业务处理的时候使用
四、事件
4.1 监听事件
在 Vue
中可以用 v-on
指令监听 DOM
事件,并在触发时运行一些 JavaScript
代码:
<div id="app">
<!--为按钮增加单击事件,如果不需要传参可以不写方法括号-->
<button v-on:click="increment">自增</button>
<button v-on:click="decrement">自减</button>
<button v-on:click="add(2)">增加指定步长</button>
<!--可以将事件缩写为@click-->
<button @click="subtract(2)">减少指定步长</button>
<br>
{{value}}
</div>
<script>
var app = new Vue({
el:"#app",
data:{
value:0
},
methods:{
increment:function(){
this.value++;
},
decrement:function(){
this.value--;
},
add:function(step){
this.value+=step;
},
subtract:function(step){
this.value -= step;
}
}
});
</script>
4.2 事件修饰符
修饰符是由点开头的指令后缀来表示的:
.stop
.prevent
.capture
.self
.once
.passive
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
4.3 按键修饰符
在监听键盘事件时,我们经常需要检查常见的键值。Vue
允许为 v-on
在监听键盘事件时添加按键修饰符:
<!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` -->
<input v-on:keyup.13="submit">
记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:
<input v-on:keyup.enter="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">
全部的按键别名:
- .enter
- .tab
- .delete (捕获“删除”和“退格”键)
- .esc
- .space
- .up
- .down
- .left
- .right
可以通过全局 config.keyCodes 对象自定义按键修饰符别名:
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
4.4 .exact 修饰符
.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>
4.5 鼠标按钮修饰符
- .left
- .right
- .middle
这些修饰符会限制处理函数仅响应特定的鼠标按钮。
五、指令语法
5.1 v-if
根据表达式条件结果是否为真,来控制视图是否渲染:
<div id="app">
<h1 v-if="value>0">数值大于零</h1>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
value:1
}
});
</script>
5.2 v-else-if
和 **v-if ** 搭配使用,用于另一个条件分支成立的情况:
<div id="app">
<h1 v-if="value>0">数值大于零</h1>
<h1 v-else-if="value<0">数值小于零</h1>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
value:-5
}
});
</script>
5.3 v-else
和 **v-if ** 搭配使用,表示其他未明确申明的条件分支:
<div id="app">
<h1 v-if="value>0">数值大于零</h1>
<h1 v-else-if="value<0">数值小于零</h1>
<h1 v-else>数值等于零</h1>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
value:0
}
});
</script>
5.4 v-show
v-show 和 v-if 一样根据表达式结果来控制视图的渲染。两者的区别在于 v-if 是 DOM 元素的动态添加/删除,而 v-show 是修改 display CSS 属性,从性能比较上来看 v-show 更具优势:
<div id="app">
<h1 v-show="value>0">数值大于零</h1>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
value:5
}
});
</script>
5.5 v-for
v-for 基于数据循环渲染视图:
<div id="app">
<ul>
<!--:key 表示主键-->
<!--index 表示索引下标-->
<li v-for="(city,index) in citys" :key="city.id">
{{index}} -- 城市编码:{{city.id}} -- 城市名称:{{city.name}}
</li>
</ul>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
citys:[
{
id:10001,
name:"北京"
},
{
id:10002,
name:"上海"
},
{
id:10003,
name:"广东"
},
{
id:10004,
name:"深圳"
},
{
id:10005,
name:"杭州"
}
]
}
});
</script>
5.6 v-bind
用于绑定数据和元素属性,可以缩写为 :属性名
<div id="app">
<a v-bind:href="url">百度一下</a>
<br>
<a :href="url">百度一下</a>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
url:"http://www.baidu.com"
}
});
</script>
5.7 v-model
用于创建双向数据绑定,负责监听用户的输入事件以更新数据。
只有这些输入组件可以使用:
* input
* select
* textarea
* components
修饰符:
* 如果想将数据同步时机从 Input 事件调整为change 事件之后,可以给 v-model 添加 lazy 修饰符;
* 如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符;
* 如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符;
<div id="app">
<button @click="resetValue">重置值</button>
<button @click="showValue">显示当前值</button>
<br>
<!--增加number修饰符,表示输入的是数值型-->
<input v-model.number="value"/>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
value:0
},
methods:{
resetValue:function(){
this.value=0;
},
showValue:function(){
alert(this.value);
}
}
});
</script>
5.8 v-text
文本内容绑定,等同于 {{ 数据字段名称}}
形式
<div id="app">
<h3 v-text="message"></h3>
<br>
{{message}}
</div>
<script>
var app = new Vue({
el:"#app",
data:{
message:"Hello Vue!"
}
});
</script>
5.9 v-html
原样输出 HTML 样式文本:
<div id="app">
<div v-html="htmlValue"></div>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
htmlValue:"<h1> HelloVue!"
}
});
</script>
六、组件
6.1 介绍
组件就是可复用的 Vue
实例,它们与 new Vue
接收相同的选项,例如 data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像 el
这样根实例特有的选项。
注:组件中的 data 必须是函数。
这是因为如果像 Vue
实例那样,传入一个对象,由于 JS
中对象类型的变量实际上保存的是对象的引用,所以当存在多个这样的组件时,会共享数据,导致一个组件中数据的改变会引起其他组件数据的改变。
而使用一个返回对象的函数,每次使用组件都会创建一个新的对象,这样就不会出现共享数据的问题来了。
6.2 创建组件
<div id="app">
<!--可以对注册的组件进行任意的复用,每个组件都有各自的数据维护-->
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
<script>
<!--全局注册组件,详情查看组件注册-->
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">你点击了 {{ count }} 次</button>'
});
var app = new Vue({
el:"#app"
});
</script>
6.3 父组件向子组件传递数据
通过 Prop(组件上自定义的 attribute) 向子组件传递数据
<div id="app">
<!--绑定title属性,用来调整title属性值-->
<input v-model="title"/>
<br>
<!--父组件传递属性数据-->
<button-counter v-bind:title="title"></button-counter>
<!--父组件传递固定数据-->
<button-counter my-msg="父组件传递固定数据"></button-counter>
</div>
<script>
Vue.component('button-counter', {
// 属性
props:["my-msg","title"],
template: '<div><h1>{{myMsg}}</h1><h1>{{title}}</h1></div>'
});
var app = new Vue({
el:"#app",
data:{
title:"父组件传递属性数据"
}
});
</script>
6.4 子组件向父组件传值
子组件主要通过 事件传递 的形式将数据给父组件:
<div id="app">
<!--将事件和父组件方法做绑定-->
<usernam-view @show-user-name="getInput"></usernam-view>
<br>
{{value}}
</div>
<script>
//申明子组件
Vue.component('usernam-view', {
data (){
return {
username:""
}
},
template: '<input v-model="username" @change="handleChange"></input>',
methods:{
handleChange : function(){
// 通过事件将值传递到父组件
this.$emit('show-user-name',this.username)
}
}
});
var app = new Vue({
el:"#app",
data:{
value:""
},
methods:{
getInput:function(input){
this.value = input;
},
}
});
</script>
6.5 父组件向子组件传递模板内容
当子组件的模板内容需要父组件传递时,可以通过在子组件中申明 slot 标签,父组件将模板内容传递进去,这种方式叫做插槽:
<div id="app">
<component-view>
<h1>没有名称的 slot </h1>
<template slot="header">
<h1> slot 名称为 header 的</h1>
</template>
<template slot="content">
<h1>slot 名称为 content 的</h1>
</template>
</component-view>
</div>
<script>
Vue.component('component-view', {
data (){
return {
username:""
}
},
template: `
<div>
<strong>信息</strong>
<slot></slot>
<slot name="header"></slot>
<slot name="content"></slot>
</div>
`
});
var app = new Vue({
el:"#app"
});
</script>
七、 组件注册
组件注册分为全局注册和局部注册。
7.1 全局注册
全局注册通过 Vue.component 来实现:
Vue.component('my-component-name', {
// ... 选项 ...
})
全局注册后的组件,可以在任何地方使用,与之相反的则是局部注册。
7.2 局部注册
局部注册的组件在其子组件中不可用:
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
<script>
<!--定义组件-->
var buttonCounter = {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">你点击了 {{ count }} 次</button>',
}
var app = new Vue({
el:"#app",
components:{
"button-counter": buttonCounter
}
});
</script>
八、ajax 请求
Vue.js 2.0 版本推荐使用 axios 来完成 ajax 请求。
8.1 介绍
Axios 是一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中。
Github开源地址: https://github.com/axios/axios
请求配置项:
{
// `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"},
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params: {
ID: 12345
},
// `paramsSerializer` 是一个负责 `params` 序列化的函数
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function(params) {
return Qs.stringify(params, {arrayFormat: "brackets"})
},
// `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, // 默认的
// `adapter` 允许自定义处理请求,以使测试更轻松
// 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
adapter: function (config) {
/* ... */
},
// `auth` 表示应该使用 HTTP 基础验证,并提供凭据
// 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
auth: {
username: "janedoe",
password: "s00pers3cret"
},
// `responseType` 表示服务器响应的数据类型,可以是 "arraybuffer", "blob", "document", "json", "text", "stream"
responseType: "json", // 默认的
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
xsrfCookieName: "XSRF-TOKEN", // default
// `xsrfHeaderName` 是承载 xsrf token 的值的 HTTP 头的名称
xsrfHeaderName: "X-XSRF-TOKEN", // 默认的
// `onUploadProgress` 允许为上传处理进度事件
onUploadProgress: function (progressEvent) {
// 对原生进度事件的处理
},
// `onDownloadProgress` 允许为下载处理进度事件
onDownloadProgress: function (progressEvent) {
// 对原生进度事件的处理
},
// `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, // 默认的
// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:
// `keepAlive` 默认没有启用
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// "proxy" 定义代理服务器的主机名称和端口
// `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
// 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
proxy: {
host: "127.0.0.1",
port: 9000,
auth: : {
username: "mikeymike",
password: "rapunz3l"
}
},
// `cancelToken` 指定用于取消请求的 cancel token
// (查看后面的 Cancellation 这节了解更多)
cancelToken: new CancelToken(function (cancel) {
})
}
响应结构:
{
// `data` 由服务器提供的响应
data: {},
// `status` HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: "OK",
// `headers` 服务器响应的头
headers: {},
// `config` 是为请求提供的配置信息
config: {}
}
8.2 安装
使用 cdn:
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.js"></script>
或
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.min.js"></script>
使用 npm:
# 针对 vue-cli 创建的项目,需要 CMD 进入项目目录下执行
npm install axios
8.3 GET 请求
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>axios</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.js"></script>
<body>
<div id="app">
<button @click="loadUserInfo">获取用户信息</button>
</div>
<script>
var app = new Vue({
el:"#app",
methods:{
loadUserInfo:function(){
axios
.get('http://localhost:8080/api/userInfo/123')
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
})
},
}
});
</script>
</body>
</html>
8.4 POST 请求
<div id="app">
<button @click="createUser">创建用户</button>
</div>
<script>
var app = new Vue({
el:"#app",
methods:{
createUser:function(){
axios
.post('http://localhost:8080/api/create',{
userId:"1234",
userName:"张三",
age:19
})
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
})
},
}
});
</script>