Vue
一、入门
1.1 概念
个人BB:
这是一份去年其实就写完的Vue入门基础,当时是跟着官网把vue基本的内容全部自己写了一遍,以求更好的掌握,今年才真的在项目上实际使用Vue,也知道这份入门也就真的只有入门的程度。
今年实际写Vue项目之后,其实出了不少问题,我把之间没看过的vuex和vrouter看完了,又重新翻了一遍vue的api文档,去了解了深入响应式原理。又去看了现在常用的es6语法。觉得自己又能写出不少东西了,而且也想要求自己写一些东西。
做项目尚有文档产出,何况是学习呢。
下面有个项目可能会比较忙,但后续估计会更新uni-app的一些学习和项目的一些记录和心得
Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框架。
Vue 只关注视图层, 采用自底向上增量开发的设计。
Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
1.2 优点
轻量级,体积小,开源、吸取了其他两个框架的优点、拥有计算属性。
1.3 入门案例
1.3.1 IDEA安装Vue插件
1.3.2 代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<h3 id="name">{{message}}</h3>
</body>
<script>
var vm=new Vue({
el:'#name',
data:{
message:"回家睡觉"
}
});
</script>
</html>
1.3.3 结果
1.3.4 意义
看起来平淡无奇,但这本身是一种MVVM(Model-View-ViewModel)模式的实现,让视图与业务逻辑分开。
好处:
低耦合,高重用度、独立开发、可测试
也是一种数据双向绑定的实现。
直观体验,终于不刷新也可以改变页面数据了!
1.4 生命周期
二、语法
2.1 指令
在Vue中所有指令都以v-开头
自定义属性
2.2 v-html
v-html和{{}}作用一样
<div id="app">
<div v-html="message"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
message: '<h1>不转义直接输出</h1>'
}
})
</script>
2.3 v-bind
2.3.1 绑定对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<input v-bind:value="message" id="name"/>
</body>
<script>
var vm=new Vue({
el:'#name',
data:{
message:"回家睡觉"
}
});
</script>
</html>
2.3.2 绑定属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="name" v-bind:class="div"></div>
</body>
<script>
var vm=new Vue ({
el: '#name',
data: {
div: "div1"
}
});
</script>
<style>
.div1 {
border: 2px solid red;
border-radius: 5px;
width: 500px;
height: 50px;
}
</style>
2.3.3绑定style
<div v-bind:style="styleObject">绑定样式对象</div>'
<!-- CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) -->
<div v-bind:style="{ color: activeColor, fontSize: fontSize,background:'red' }">内联样式
</div>
<!--组语法可以将多个样式对象应用到同一个元素 -->
<div v-bind:style="[styleObj1, styleObj2]"></div>
<script>
new Vue({
el: '#app',
data: {
styleObject: {
color: 'green',
fontSize: '30px',
background:'red'
},
activeColor: 'green',
fontSize: "30px"
},
styleObj1: {
color: 'red'
},
styleObj2: {
fontSize: '30px'
}
</script>
2.3.4绑定对象和绑定数组的区别
绑定对象的时候,对象的属性即要渲染的类名,对象的属性值对应的是 data 中的数据
绑定数组的时候数组里面存的是data 中的数据
2.4 v-cloak
作用比较简单,当页面加载比较慢时,页面会出现vue源码,所以用v-cloak设定样式,页面加载完再移除样式,
大概只有好看的作用
<head>
<meta charset="UTF-8">
<title>Vue</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<style type="text/css">
[v-cloak]{
display: none;
}
</style>
<body>
<div id="app">
<div v-cloak >{{msg}}</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: 'Hello Vue'
}
});
</script>
</body>
2.5 v-text
和v-html差不多,但没有加载过慢的问题,单向绑定,标签里的值改变,vue里的值不会表
和v-html区别,v-html不会转义字符,标签会生效,v-text输出转义后的字符
<body>
<div id="app">
<div v-text="msg" ></div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: '张三<br/>李四'
}
});
</script>
</body>
2.5 v-pre
显示原始信息,不对这个元素进行编译。
可以加快静态资源的渲染。
<span v-pre>{{ this will not be compiled }}</span>
<!-- 显示的是{{ this will not be compiled }} -->
<span v-pre>{{msg}}</span>
<!-- 即使data里面定义了msg这里仍然是显示的{{msg}} -->
<script>
new Vue({
el: '#app',
data: {
msg: 'Hello Vue.js'
}
});
</script>
2.6 v-on
绑定事件
形式可以简写如:v-on:click =@click
可以在methods里写复数个方法
如果直接绑定函数名,默认传入事件参数
如果多个参数,事件参数必须在最后一个,名称必须为$event。
<body>
<div id="app">
<button v-bind:class="div" @click="up">{{msg}}</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: 1,
div:"bbs"
},
methods:{
up:function () {
alert("函数执行");
}
}
});
</script>
<style>
.bbs{
width: 200px;
height: 200px;
border: 2px solid ;
}
</style>
</body>
2.7 v-once
一次性插入数据,只在第一次生效,以后改变绑定数据,也不会生效
<!-- 即使data里面定义了msg 后期我们修改了 仍然显示的是第一次data里面存储的数据即 Hello Vue.js -->
<span v-once>{{ msg}}</span>
<script>
new Vue({
el: '#app',
data: {
msg: 'Hello Vue.js'
}
});
</script>
2.8 v-model
数据双向绑定
当数据发生变化时,视图变化,视图改变时,数据也随之变化
<body>
<div id="app">
<div >{{msg}}</div>
<input v-model="msg" />
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: '1'
}
});
</script>
</body>
2.9 v-if
判断,基础
<body>
<div id="app">
<p v-if="msg">如果条件成立,就显示这条</p> <!--输出-->
<p v-if="msg!=false">如果条件成立,也输出这条</p> <!--输出-->
<p v-else-if="msg===false">这条还可以这么写</p> <!--不输出-->
<p v-else>其他情况下输出这条</p> <!--不输出-->
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg:true
}
});
</script>
</body>
2.10 v-show和v-if的区别
v-show和v-if看起来相似,其实有着本质区别
**v-show本质就是标签display设置为none,控制隐藏
**v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,故v-show性能更好一点。
v-if是动态的向DOM树内添加或者删除DOM元素
v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件
2.11 v-for
循环,核心
不推荐同时使用 v-if 和 v-for**
当 v-if 与 v-for 一起使用时, v-for 具有比 v-if 更高的优先级。**
<body>
<ul id="example-1">
<!-- 循环结构-遍历数组
item 是我们自己定义的一个名字 代表数组里面的每一项
items对应的是 data中的数组-->
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
<script>
new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
</script>
</body>
<body>
<!-- 循环结构-遍历对象
v 代表 对象的value
k 代表对象的 键
i 代表索引
--->
<ul id="example-1">
<div v-if='v==13' v-for='(v,k,i) in obj'>{{v + '---' + k + '---' + i}}</div>
</ul>
<script>
new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
],
obj: {
uname: 'zhangsan',
age: 13,
gender: 'female'
}
}
})
</script>
</body>
2.12 事件修饰符
Vue将操作Dom封装,使用事件修饰符来完成一些常用行为。
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面,阻止默认事件-->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 即阻止冒泡也阻止默认事件 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
//使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。
//因此,用 v-on:click.prevent.self 会阻止所有的点
//击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
2.13 按键修饰符
就是以前的监听事件
常用的按键修饰符
.enter => enter键
.tab => tab键
.delete (捕获“删除”和“退格”按键) => 删除键
.esc => 取消键
.space => 空格键
.up => 上
.down => 下
.left => 左
.right => 右
<body>
<div id="app">
<div>
<button v-on:keyup.enter="handle1">点击2</button>
</div>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
num: 0
},
methods: {
handle1: function(event) {
console.log("你按下了enter键")
}
}
});
</script>
2.14 自定义按键修饰符别名
在vue中可以通过 config.keyCodes 修改按键别名 。
<body>
<div id="app">
<div>
<button v-on:keyup.f="handle1">按f</button>
</div>
</div>
<script type="text/javascript">
Vue.config.keyCodes.f=70;
var vm = new Vue({
el: '#app',
methods: {
handle1: function(event) {
alert("你确定要进入坦克?")
}
}
});
</script>
</body>
2.15 自定义指令
自定义指令和自定义组件差不多。
2.15.1 全局指令
<body>
<input id="app" v-focus>
<script>
Vue.directive('focus',{
inserted: function(el) {
el.focus();
}
});
var vm=new Vue({
el:'#app'
});
</script>
</body>
2.15.2 全局指令带参数
<body>
<input id="app" v-focus="msg">
<script>
Vue.directive('focus',{
bind:function (el,binding) {
el.style.backgroundColor=binding.value.color;
}
});
var vm=new Vue({
el:'#app',
data: {
msg: {
color: 'blue'
}
}
});
</script>
</body>
2.15.3 局域自定义指令
用法与全局差不多
定义在directives中
局域自定义指令优先级大于父类优先级
三、属性
3.1 组件注册
在Vue中可以自定义组件模板,是十分方便的一个功能
组件参数的data值必须是函数同时这个函数要求返回一个对象
组件模板必须是单个根元素
组件模板的内容可以是模板字符串
自定义组件必须使用短横线
<body>
<div id="app">
<span>{{msg}}</span>
<a-mu></a-mu>
</div>
<script>
Vue.component('a-mu',{
template: '<div>这是一个默认模板</div>'
});
var vm=new Vue({
el:'#app',
data: {
msg: '测试数据'
}
})
</script>
</body>
3.1.1组件中可传的参数
Vue.component('button-counter', {
// 1、组件参数的data值必须是函数
// 同时这个函数要求返回一个对象
data: function(){
return {
count: 0
}
},
// 2、组件模板必须是单个根元素
// 3、组件模板的内容可以是模板字符串
template: `
<div>
<button @click="handle">点击了{{count}}次</button>
<button>测试123</button>
# 6 在字符串模板中可以使用驼峰的方式使用组件
<HelloWorld></HelloWorld>
</div>
`,
methods: {
handle: function(){
this.count += 2;
}
}
})
var vm = new Vue({
el: '#app',
data: {
}
});
3.2数据绑定
<body>
<div id="app">
<amu v-bind:message="msg" ></amu>
</div>
<script>
Vue.component('amu',{
props:['message'],
template: '<div>{{message}}</div>'
});
var vm=new Vue({
el:'#app',
data: {
msg: '测试数据'
}
})
</script>
</body>
3.3 计算属性 Computed
3.3.1回调函数
自己定义
没有调用
最后执行
-
模板中放入太多的逻辑会让模板过重且难以维护 使用计算属性可以让模板更加的简洁
-
计算属性是基于它们的响应式依赖进行缓存的
-
computed比较适合对多个变量或者对象进行处理后返回一个结果值,也就是数多个变量中的某一个值发生了变
化则我们监控的这个值也就会发生变化
响应式依赖进行缓冲,就是Message改变后,页面不刷新也不改变。
这么做的原因是 性能比较高,如果每次 都改变的话,每次都要计算。
如果不需要缓冲,就可以写成方法。
<body>
<div id="app">
<div>{{message}}</div>
<div>{{reserveMessage}}</div>
</div>
<script>
var vm= new Vue({
el:'#app',
data: {
message:'这是一条测试数据'
},
computed: {
reserveMessage: function () {
return this.message.split('').reverse().join('');
}
}
});
</script>
</body>
getter:get 显示
setter:set 监视双向绑定,数据回写
3.4 watch 侦察属性
- watch里面都是data里面的属性
- 如果异步或者开销比较大的操作
- 当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听
<body>
<div id="demo">{{ fullName }}</div>
<script>
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
</script>
</body>
3.5 过滤器 filter
- Vue.js允许自定义过滤器,可被用于一些常见的文本格式化。
- 过滤器可以用在两个地方:双花括号插值和v-bind表达式。
- 过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示支持级联操作
- 过滤器不改变真正的 data ,而只是改变渲染的结果并返回过滤后的版本全局注册时是filter,没有s的。
- 而局部过滤器是filters,是有s的
和directive差不多有 全局fitler和局域fitler
可以使用多个filter,使用 | 分割。
<body>
<div id="example-1" class="demo">
<input type="text" v-model="message">
<p>{{ message | capitalize }}</p>
</div>
</div>
<script>
new Vue({
el: '#example-1',
data: function () {
return {
message: 'john'
}
},
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
});
</script>
</body>
3.6 组件插槽
匿名插槽,数据在插槽里
当组件渲染的时候,这个 元素将会被替换为“组件标签中嵌套的内容”。
插槽内可以包含任何模板代码,包括 HTML
就是在组件里嵌套别的组件,还可以进行数据绑定等操作,让vue更加灵活
必须在组件里实现声明有插槽,不然不能用
<alert-box ID="slots-demo">
Something bad happened.
</alert-box>
<script>
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
new Vue({ el: '#slots-demo' })
</script>
<style>
.demo-alert-box {
padding: 10px 20px;
background: #f3beb8;
border: 1px solid #f09898;
}
</style>
</body>
具名插槽
用 name指定slot的名字
渲染顺序取决于模板的顺序,而不是组件中的顺序。
使用插槽绑定数据,说实话,以我的角度看 比较烦
<body>
<alert-box ID="slots-demo">
<up-half slot="up-half" :title="title"></up-half>
<down-half slot="down-half" :message="message"></down-half>
</alert-box>
<script>
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<slot name="up-half"></slot>
<slot name="down-half"></slot>
</div>`
})
Vue.component('up-half',{
props:['title'],
template:
'<div>{{title}}</div>'
});
Vue.component('down-half',{
props:['message'],
template:
'<div>{{message}}</div>'
})
new Vue({
el: '#slots-demo',
data: {
title: '标题',
message: '内容'
}
})
</script>
<style>
.demo-alert-box {
padding: 10px 20px;
background: #f3beb8;
border: 1px solid #f09898;
}
</style>
</body>
3.7 自定义事件
3.7.1 只自定义一个时间名
<div id="app">
<p>{{msg}}</p>
<out-alert v-on:plus="outalert" ></out-alert>
</div>
<script>
Vue.component('out-alert',{
template: `
<button v-on:click="$emit('plus')">
help me!
</button>
`
})
var vm=new Vue({
el: '#app',
data: {
msg: 0
},
methods: {
outalert: function () {
this.msg+=1;
}
}
});
</script>
3.7.2 配合额外参数
<body>
<div id="app">
<p>{{msg}}</p>
<out-alert v-on:plus="outalert" ></out-alert>
</div>
<script>
Vue.component('out-alert',{
data: function(){
return{
count: 0
}
},
template: '<button v-on:click="pluscount">{{count}}</button>',
methods: {
pluscount: function () {
//this.count+=1;
//自定义事件
this.$emit('plus')
}
}
})
var vm=new Vue({
el: '#app',
data: {
msg: 0
},
methods: {
outalert: function () {
this.msg+=1;
}
}
});
</script>
</body>
四、异步通信
4.1 axios框架
实现基本的get、put、post、delete请求
主要就是从指定路径拿到返回相应携带数据,然后then里面放后续操作,catch里面放失败的处理
<body>
<div id="app">
{{ info }}
</div>
<script type = "text/javascript">
new Vue({
el: '#app',
data () {
return {
info: null
}
},
mounted () {
axios
.get('http://localhost:63342/vuetest/first-Vue/static/data.json')
.then(response => (this.info = response))
.catch(function (error) { // 请求失败处理
console.log(error);
});
}
})
</script>
</body>
4.2 axios 全局配置
# 配置公共的请求头
axios.defaults.baseURL = 'https://api.example.com';
# 配置 超时时间
axios.defaults.timeout = 2500;
# 配置公共的请求头
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
# 配置公共的 post 的 Content-Type
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
4.3 axios拦截器
在我看来等同于预处理或者后处理
请求拦截器
请求拦截器的作用是在请求发送前进行一些操作
例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易
响应拦截器
响应拦截器的作用是在接收到响应后进行一些操作
例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页
# 1. 请求拦截器
axios.interceptors.request.use(function(config) {
console.log(config.url)
# 1.1 任何请求都会经过这一步 在发送请求之前做些什么
config.headers.mytoken = 'nihao';
# 1.2 这里一定要return 否则配置不成功
return config;
}, function(err){
#1.3 对请求错误做点什么
console.log(err)
})
#2. 响应拦截器
axios.interceptors.response.use(function(res) {
#2.1 在接收响应做些什么
var data = res.data;
return data;
}, function(err){
#2.2 对响应错误做点什么
console.log(err)
})
4.4 async和await
async作为一个关键字放到函数前面
任何一个 async 函数都会隐式返回一个 promise
await 关键字只能在使用 async 定义的函数中使用
await后面可以直接跟一个 Promise实例对象
await函数不能单独使用
# 1. async 基础用法
# 1.1 async作为一个关键字放到函数前面
async function queryData() {
# 1.2 await关键字只能在使用async定义的函数中使用 await后面可以直接跟一个 Promise实例对象
var ret = await new Promise(function(resolve, reject){
setTimeout(function(){
resolve('nihao')
},1000);
})
// console.log(ret.data)
return ret;
}
# 1.3 任何一个async函数都会隐式返回一个promise 我们可以使用then 进行链式编程
queryData().then(function(data){
console.log(data)
})
#2. async 函数处理多个异步函数
axios.defaults.baseURL = 'http://localhost:3000';
async function queryData() {
# 2.1 添加await之后 当前的await 返回结果之后才会执行后面的代码
var info = await axios.get('async1');
#2.2 让异步代码看起来、表现起来更像同步代码
var ret = await axios.get('async2?info=' + info.data);
return ret.data;
}
queryData().then(function(data){
console.log(data)
})