Vue
Posted shuita
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue相关的知识,希望对你有一定的参考价值。
概述
1.前端开发模式的发展
1.静态页面
最初的网页以html为主,是纯静态的网页。网页是只读的,信息流只能从服务端到客户端单向流通。开发人员也只关心页面的样式和内容。
2.异步刷新,操作DOM
1995年,网景工程师Brendan Eich 花了10天时间设计了javascript语言。随着JavaScript的诞生,我们可以操作页面的DOM元素及样式,页面有了一些动态的效果,但是依然是以静态为主。
3.ajax盛行:
2005年开始,ajax逐渐被前端开发人员所重视,因为不用刷新页面就可以更新页面的数据和渲染效果。此时的开发人员不仅仅要编写HTML样式,还要懂ajax与后端交互,然后通过JS操作Dom元素来实现页面动态效果。比较流行的框架如jQuery就是典型代表。
4.MVVM,关注模型和视图
M:即Model,模型,包括数据和一些基本操作
V:即View,视图,页面渲染结果
VM:即View-Model,模型与视图间的双向操作(无需开发人员干涉)
在MVVM之前,开发人员从后端获取需要的数据模型,然后要通过DOM操作Model渲染到View中。而后当用户操作视图,我们还需要通过DOM获取View中的数据,然后同步到Model中。
而MVVM中的VM要做的事情就是把DOM操作完全封装起来,开发人员不用再关心Model和View之间是如何互相影响的:
只要Model发生了改变,View上自然就会表现出来。
当用户修改了View,Model中的数据也会跟着改变。
把开发人员从繁琐的DOM操作中解放出来,把关注点放在如何操作Model上。
2.认识Vue
是一套用于构建用户界面的渐进式框架(可以有选择性的使用该框架的一个或一些组件)。
前端框架三巨头:Vue.js,React.js,AngularJS,vue以其轻量易用著称
入门
1.创建静态web工程
2.安装vue
官网下载https://github.com/vuejs/vue
公共的CDN(引用在线的vue.js)
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
npm安装(推荐)
#初始化
npm init -y
#下载vue模块
npm install vue --save
3.vue渲染
new Vue()来创建Vue实例
然后构造函数接收一个对象,对象中有一些属性:
el:是element的缩写,通过id选中要渲染的页面元素,本例中是一个div
data:数据,数据是一个对象,里面有很多属性,都可以渲染到视图中
name:这里指定了一个name属性
页面中的 h2 元素中,通过{{name}}的方式,来渲染刚刚定义的name属性。
<body>
<div id="app">
<h2>{{name}}123</h2>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
name:"刘洋"
}
})
</script>
</body>
4.双向绑定
没有任何dom操作,这就是双向绑定的魅力。
输入框的变化引起了data中的num的变化,同时页面输出也跟着变化。
input与num绑定,input的value值变化,影响到了data中的num值
页面 {{num}} 与数据num绑定,因此num值变化,引起了页面效果变化
<body>
<div id="app">
<input type="text" v-model="num">
<h2>
{{name}}的房子有{{num}}套
</h2>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
name:"刘洋",
num:10
}
})
</script>
5.事件处理
这里用 v-on 指令绑定点击事件,而不是普通的 onclick ,然后直接操作num ,普通onclick是无法直接操作num的。
<body>
<div id="app">
<input type="text" v-model="num"><button v-on:click="num++">点</button>
<h2>
{{name}}的房子有{{num}}个
</h2>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
name:"刘洋",
num:10
}
})
</script>
</body>
Vue实例
1.创建
2.模板或元素
每个Vue实例都需要关联一段Html模板,Vue会基于此模板进行视图渲染;可以通过el属性来指定。
3.数据
当Vue实例被创建时,它会尝试获取在data中定义的所有属性,用于视图的渲染,并且监视data中的属性变化,当data发生改变,所有相关的视图都将重新渲染,这就是“响应式“系统。
4.方法
<div id="app">
<button v-on:click="add">点我</button>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{ },
methods:{
add:function(){
console.log("点我了...233")
}
}
})
</script>
5.生命周期,钩子函数
Vue为生命周期中的每个状态都设置了钩子函数(监听函数)。
钩子函数不要使用箭头函数的方式编写。
具体有:beforeCreate,created,beforeMount,mounted,updated,beforeUpdate,destroyed,beforeDestroy
created钩子函数常用场景:用于初始化数据
<body>
<div id="app">
{{msg}}
</div>
<script>
var app = new Vue({
el:"#app",
data:{
msg:""
},
created(){
this.msg="hello,LY";
}
});
</script>
</body>
vue内部的this变量就是当前的Vue实例,在Vue对象内部,必须使用 this 才能访问到Vue中定义的data内属性、方法等。
指令
1.插值表达式
1.花括号
该表达式支持JS语法,可以调用js内置函数(必须有返回值)
表达式必须有返回结果。例如 1 + 1,没有结果的表达式不允许使用,如:var a = 1 + 1;
可以直接获取Vue实例中定义的数据或函数
插值表达式不能用在标签的属性中。
2.插值闪烁
使用花括号方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的花括号,加载完毕后才显示正确数据,称为插值闪烁。(最新vue是几乎没有此问题)
3.v-text和v-html
使用v-text和v-html指令来替代花括号
v-text:将数据输出到元素内部,如果输出的数据有HTML代码,会作为普通文本输出
v-html:将数据输出到元素内部,如果输出的数据有HTML代码,会被渲染
并且不会出现插值闪烁,当没有数据时,会显示空白。
<body>
<div id="app">
{{msg}}
</div>
<script>
var app = new Vue({
el:"#app",
data:{
msg:""
},
created(){
this.msg="hello,LY";
}
});
</script>
</body>
2.v-model
v-text和v-html可以看做是单向绑定,数据影响了视图渲染,但是反过来就不行。
v-model是双向绑定,视图(View)和模型(Model)之间会互相影响。
既然是双向绑定,一定是在视图中可以修改数据,这样就限定了视图的元素类型。目前v-model的可使用元素有: input ,select ,textarea ,checkbox ,radio ,components(Vue中的自定义组件),基本上除了最后一项,其它都是表单的输入项。
<body>
<div id="app">
<input type="checkbox" value="java" v-model="language">java<br>
<input type="checkbox" value="php" v-model="language">PHP<br>
<input type="checkbox" value="C++" v-model="language">C++<br>
<h2>{{language.join(",")}}</h2>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
language:[]
}
});
</script>
</body>
多个 checkbox 对应一个model时,model的类型是一个数组,单个checkbox值是boolean类型
radio对应的值是input的value值
input 和 textarea 默认对应的model是字符串
select 单选对应字符串,多选对应也是数组
3.v-on
用于给页面元素绑定事件。v-on:事件名="js片段或函数名"或@事件名="js片段或函数名"
<body>
<div id="app">
<!--直接写js片段-->
<button @click="num++">增加</button>
<!--使用函数名,该函数必须要在vue实例中定义-->
<button @click="decrement">减少</button>
<h2>
num = {{num}}
</h2>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
num:1
},
methods:{
decrement(){
this.num--;
}
}
});
</script>
</body>
? 事件修饰符
方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
.stop :阻止事件冒泡
.prevent :阻止默认事件发生
.capture :使用事件捕获模式
.self :只有元素自身触发事件才执行。(冒泡或捕获的都不执行)
.once :只执行一次
<body>
<div id="app">
事件冒泡测试:<br>
<div style="background-color: lightblue;width: 100px;height: 100px"
@click="print(‘你点击了div‘)">
<button @click.stop="print(‘点击了button‘)">点我试试</button>
</div>
<br>阻止默认事件:<br>
<a href="https://shuitayangyang.github.io/" @click.prevent="print(‘点击超链接‘)">LT</a>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
},
methods:{
print(msg){
console.log(msg)
}
}
});
</script>
</body>
4.v-for
一般情况下,要遍历的数据可以通过钩子函数created发送异步请求获取数据。
1.遍历数组
遍历数据渲染页面,v-for="item in items"
items:要遍历的数组,需要在vue的data中定义好。
item:循环变量
<body>
<div id="app">
<ul><li v-for="user in users">{{user.name}}--{{user.age}}--{{user.gender}}</li> </ul>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
users:[
{"name":"张三","age":8,"gender":"男"},
{"name":"李四","age":12,"gender":"女"},
{"name":"王五","age":4,"gender":"男"}
]
}
});
</script>
</body>
2.数组角标
在遍历的过程中,如果需要知道数组角标,可以指定第二个参数:v-for="(item,index) in items"
items:要迭代的数组
item:迭代得到的数组元素别名
index:迭代到的当前元素索引,从0开始。
<div id="app">
<ul>
<li v-for="(user,index) in users">
{{index}}--{{user.name}}--{{user.age}}--{{user.gender}}
</li>
</ul>
</div>
3.遍历对象
v-for="value in object" ,得到的是对象的值
v-for="(value,key) in object" ,第一个是值,第二个是键
v-for="(value,key,index) in object" ,第三个是索引,从0开始
<ul>
<li v-for="(value,key,index) in person"> {{index}}--{{key}}--{{value}} </li>
</ul>
4.key
使用key这个功能可以有效的提高渲染的效率;key一般使用在遍历完后,又增、减集合元素的时候更有意义。为每项提供一个唯一 key 属性。
<ul>
<li v-for="(item,index) in items" :key="index"></li>
</ul>
5.v-if和v-show
1.v-if
条件判断,当得到结果为true时,所在的元素才会被渲染。(v-if="布尔表达式" )
<body>
<div id="app">
<button @click="show = !show">点我</button>
<h2 v-if="show"> Hello VueJS. </h2>
</div>
<script>
var app = new Vue({
el:"#app",
data: {
show:true
}
});
</script>
</body>
2.与v-for结合
当v-if和v-for出现在一起时,v-for优先级更高。也就是说,会先遍历,再判断条件。
<ul>
<li v-for="(user,index) in users" v-if="user.gender==‘女‘">
{{index}}--{{user.name}}--{{user.age}}--{{user.gender}}
</li>
</ul>
3.v-else
v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
v-else-if
<div v-if="type === ‘A‘"> A </div>
<div v-else-if="type === ‘B‘"> B </div>
<div v-else-if="type === ‘C‘"> C </div>
<div v-else> Not A/B/C </div>
4.v-show
带有 v-show 的元素始终会被渲染并保留在 DOM 中。 v-show 只是简单地切换元素的 CSS 属性 display 。 实现文本内容的隐藏
6.v-bind
v-bind的作用:可以对所有元素的属性设置vue实例的数据。
1.属性上使用vue数据
v-bind:属性名="Vue中的变量"
<div v-bind:class="color"></div> 或 <div :class="color"></div>
2.class属性的特殊用法
<button @click="bool=!bool">点我改变下面色块颜色</button>
<div :class="{red:bool,blue:!bool}"> 点击按钮改变背景颜色。 </div>
首先class绑定的是一个对象: {red:bool, blue: !bool}
red和blue这两个样式的生效标记恰好相反,一个生效,另一个失效。
现在只需要一个按钮即可,点击时对bool取反,自然实现了样式的切换
7.计算属性
<h2>computed计算方式;你的生日为:{{birth}} </h2>
<script>
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>
计算属性本质就是方法,但是一定要返回数据。然后页面渲染时,可以把这个方法当成一个变量来使用。
应用场景:可以应用在插值或者指令表示式复杂的时候。可以将一些属性数据经过方法处理之后返回。
8.watch
使用场景:可以监控视图中数据的变化而做出响应;如:下拉框列表中,当如果选择了对于的下拉框选项之后,要根据最新的值去加载一些其它数据的话。
1.监控
监控一个值的变化。
<script>
var app = new Vue({
el:"#app",
data: {
message:"hello vue"
},
watch:{
message(newValue, oldValue){
console.log("新值:" + newValue + ";旧值:" + oldValue);
}
}
});
</script>
2.深度监控
如果监控的是一个对象,需要进行深度监控,才能监控到对象中属性的变化。
<script>
var app = new Vue({
el:"#app",
data: {
person:{"name":"itcast", "age":12}
},
watch:{
person: {
//开启深度监控,可以监控到对象属性值的变化
deep: true,
//监控的处理方法
handler(obj){
console.log("name = " + obj.name + ", age=" + obj.age);
}
}
}
});
</script>
以前定义监控时,person是一个函数,现在改成了对象,并且要指定两个属性:
deep:代表深度监控,不仅监控person变化,也监控person中属性变化
handler:就是以前的监控处理函数
组件化
把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。
全局注册:在任何vue实例中都可以引用,如:一般网站的头部导航菜单
局部注册:可以在有需要的页面引入组件,如:商城网站首页页面中各种活动模块
1.定义全局组件
通过Vue的component方法来定义一个全局组件。
<script>
//定义组件
const counter = {
template: "<button @click=‘num++‘>你点击了{{num}}次;我记住了</button>",
data(){
return {num: 0}
}
};
//全局注册组件;参数1:组件名称,参数2:组件
Vue.component("counter", counter);
var app = new Vue({
el:"#app"
});
</script>
组件其实也是一个Vue实例,因此它在定义时也会接收:data、methods、生命周期函数等
不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有el属性。
但是组件渲染需要html模板,所以增加了template属性,值就是HTML模板
全局组件定义完毕,任何vue实例都可以直接在HTML中通过组件名称来使用组件了。
data的定义方式比较特殊,必须是一个函数。
2. 组件的复用
定义好的组件,可以任意复用多次。
<div id="app">
<!--使用定义好的全局组件-->
<counter></counter>
<counter></counter>
<counter></counter>
</div>
每个组件互不干扰,都有自己的num值。
一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
3.局部注册
一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着Vue的加载而加载。对于一些并不频繁使用的组件,会采用局部注册。
var app = new Vue({
el:"#app",
//局部注册组件
components:{
counter: counter
}
});
components就是当前vue对象子组件集合。
其key就是子组件名称
其值就是组件对象的属性
效果与刚才的全局注册是类似的,不同的是,这个counter组件只能在当前的Vue实例中使用
4.组件通信
通常一个单页应用会以一棵嵌套的组件树的形式来组织:
页面首先分成了顶部导航、左侧内容区、右侧边栏三部分
左侧内容区又分为上下两个组件
右侧边栏中又包含了3个子组件
各个组件之间以嵌套的关系组合在一起,那么这个时候不可避免的会有组件间通信的需求。
1.父向子传递props
父组件使用子组件,同时传递title属性:
<body>
<div id="app">
<!--使用定义好的全局组件-->
<introduce :title="msg"></introduce>
</div>
<script>
//定义组件
const introduce = {
//使用props属性title的值渲染模版
template: "<h2>{{title}}</h2>",
//定义接收来自父组件的属性
props:["title"] };
//全局注册组件;参数1:组件名称,参数2:组件
Vue.component("introduce", introduce);
var app = new Vue({
el:"#app",
data:{
msg: "父组件中的msg属性的内容"
}
});
</script>
</body>
2.传递复杂数据
<body>
<div id="app">
<h2>面向对象</h2>
<!-- 接受来自父组件的属性值,使用v-bind指向父组件的属性lessons;注意使用my-list -->
<my-list :items="lessons"></my-list>
</div>
<script>
//定义组件
const myList = {
//可以使用双引号、单引号或者如下使用的 ` 飘号
template: ` <ul><li v-for="item in items" :key="item.id">{{item.id}}--{{item.name}}</li> </ul> `,
//定义接收来自父组件的属性
props: {
//定义模版中使用的属性
items: {
//必须为数组类型
type: Array,
//默认为空数组
default: []
}
}
};
var app = new Vue({
el: "#app",
data: {
lessons:[
{"id":1, "name":"继承"},
{"id":2, "name":"封装"},
{"id":3, "name":"多态"}
]
},
//注册组件
components: {
//如果组件key和value一致可以简写如下
myList
}
});
</script>
</body>
这个子组件可以对 items 进行迭代,并输出到页面。
但是组件中并未定义items属性。
通过props来定义需要从父组件中接收的属性
items:是要接收的属性名称
type:限定父组件传递来的必须是数组,否则报错;type的值可以是Array或者Object(传递对象的时候使用)
default:默认值,
default,如果是对象则需要写成方法的方式返回默认值。如:
default(){
return {"xxx":"默认值"};
}
3.子向父的通信
子组件不能直接修改父组件传递参数的引用或者基本类型参数值。
vue提供了一个内置的this.$emit函数,用来调用父组件绑定的函数
通过v-on指令将父组件的函数绑定到子组件上,然后,当子组件中按钮被点击时,调用绑定的函数
<body>
<div id="app">
<h2>num = {{num}}</h2>
<!--使用定义好的全局组件-->
<counter @plus="numPlus" @reduce="numReduce" :snum="num"></counter>
</div>
<script>
//定义组件
const counter = {
//组件只能是一个元素里面包裹其他元素;如下面,一个div包含两个按钮
template:
` <div>
<button @click="incrNum">+</button>
<button @click="decrNum">-</button>
</div> `,
props:["snum"],
methods: {
//点击模板中使用的方法
incrNum(){
return this.$emit("plus");
},
decrNum(){
return this.$emit("reduce");
}
}
};
//全局注册组件;参数1:组件名称,参数2:组件
Vue.component("counter", counter);
var app = new Vue({
el:"#app",
data:{
num:0
},
methods:{
//父组件中定义操作num的方法
numPlus(){
this.num++;
},
numReduce(){
this.num--;
}
}
});
</script>
</body>
ajax
Vuejs 并没有直接处理ajax的组件,但可以使用axios或vue-resource组件实现对异步请求的操作。
1.vue-resource
vue-resource是Vue.js的插件提供了使用XMLHttpRequest或JSONP进行Web请求和处理响应的服务。 当vue更新到2.0之后,作者就宣告不再对vue-resource更新,而是推荐axios。
2.axios
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
#如果使用npm则可以如下安装
npm install axios
或者也可以直接使用公共的CDN(内容分发网络)服务:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
3.axios应用
1.方法说明
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]])
1)config请求配置
这些是创建请求时可以用的配置选项。只有 url 是必需的。如果没有指定 method ,请求将默认使用 get 方法。
{
// `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 // 默认的
}
2)响应结构
{
// `data` 由服务器提供的响应
data: {},
// `status` 来自服务器响应的 HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: ‘OK‘,
// `headers` 服务器响应的头
headers: {},
// `config` 是为请求提供的配置信息
config: {}
}
使用 then 时,你将接收下面这样的响应:
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 时,或传递 rejection callback 作为 then 的第二个参数时,响应可以通过 error 对象可被使用。
2.axios方法示例
注意:如果使用axios访问跨域数据的时候,只需要在服务提供方中,在方法上面使用SpringMVC的跨域注解即可解决数据跨域问题(请求的地址与当前服务器的ip或者端口号不同都是跨域请求)。如在方法上添加:@CrossOrigin(origins = "*")
如果请求的地址是使用了网关,那么在网关服务器上配置跨域就可以了;不能同时在网关服务器和服务提供服
务工程中同时配置。
可以通过向 axios 传递相关配置来创建请求
<script>
var app = new Vue({
el:"#app",
data: {
users:[]
},
created(){
//加载数据
axios({
method:"get",
url: "data.json"
}).then((res)=>{
console.log(res);
//将获取数据设置到users属性
app.users = res.data;
}).catch(error=>{
alert(error);
});
}
});
</script>
axios.get("data.json")
axios.post("data.json")
以上是关于Vue的主要内容,如果未能解决你的问题,请参考以下文章