xiaohuihui
for me

Vue学习

2020-05-25 18:41:06
Word count: 6.3k | Reading time: 26min

Vue学习

Vue基础语法

v-bind: 动态绑定属性 可简写为: 可绑定class属性或者style属性 :class或:style或input里面的值:input

v-on: 事件监听 可简写为@ 一般监听点击事件@click

把监听事件用在封装的组件上是不会产生监听效果的,如果我们想要监听一个组件的原生事件时,必须给对应的事件加上.native修饰符,才能进行接听。

image-20200613175315588

v-for 遍历数组

v-show 用于控制元素的渲染

v-model 实现数据的双向绑定

组件通信:

父传子:用props属性来传;
子传父:$emit发射事件来传;
父访问子:$resf对象去访问;
子访问父:直接访问根$root;

父传子-props

​ 值肯定是定义在父组件中的,供所有子组件共享。所以要在父组件的data中定义值,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!--如果使用驼峰命名法的时候,v-bind处的绑定的变量,应该用以下此方法命名-->
<bb :c-message='message'></bb>
</div>

<template id="bb">
<div>
<h1>我是子组件</h1>
<h2>{{cMessage}}</h2>
</div>
</template>

<script>
const app = new Vue({
el:'#app',
data:{
message:'hello Vue,与你的第一次相遇'
},
components:{
bb:{
template:"#bb",
props:{
cMessage:{
type:String,
default:'',
required:true //必传
}
}
}
}
})
</script>
</body>
</html>

子传父

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--父组件模板-->
<div id="app">
<!--父组件接收事件,对接受的事件实现相应的方法-->
<child-cpn @increment-click="changeTotal" @decrement-click="changeTotal"></child-cpn>
<h2>点击次数:{{total}}</h2>
</div>

<!--子组件模板-->
<template id="childCpn">
<div>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>

<script>
const app = new Vue({
el:'#app',
data:{
total:0
},
methods:{
//子组件发射给父组件之后,调用父组件的方法
changeTotal(counter){
this.total = counter;
}
},
components:{
//子组件
'child-cpn':{
template:'#childCpn',
data(){
return{
counter:0
}
},
methods:{
increment(){
this.counter++;
//发射给父组件事件 第一个参数为发射给父组件的事件,第二个参数为对应的数据。全部传给父组件
this.$emit('increment-click',this.counter);
},
decrement(){
this.counter--;
this.$emit('decrement-click',this.counter);
}
}
}
}
})
</script>
</body>
</html>

子组件data必须为函数

根组件除外的组件中的data必须为函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<h2>{{message}}</h2>
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>

<template id="cpn">
<div>
<h2>当前计数:{{counter}}</h2>
<button @click='increment'>+</button>
<button @click='decreament'>-</button>
</div>
</template>
<script>
//1.注册组件
Vue.component('cpn',{
template:'#cpn',
//为什么是函数,因为不用函数的时候,每次调用一个变量的时候,都只调用了一个相同的内存地址,会牵一发而动全身,而当我们使用了函数的时候,js用函数模拟类,函数返回的是对象,每次调用的都会是不同内存地址,所以值会不相同,不会牵一发而动全身
data(){
return{
counter:0
}
},
methods:{
increment(){
this.counter++;
},
decreament(){
this.counter--;
}
}
})
const app = new Vue({
el:'#app',
data:{
message:'Hello Vue'
}
})
</script>


</body>
</html>

js高阶函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<script>
const nums = [10,30,50,200,145,60,666];
//1.filter函数的使用
let newNums = nums.filter(function(n){
return n<100; //filter函数返回一个booleans值,真和假,为真则把值加入新数组中,为假则弃之
})
console.log(newNums);


//2.map函数的使用
let new2Nums = newNums.map(function(n){
return n*2; //map函数也返回一个新数组,它的返回值为数据类型的值
})
console.log(new2Nums); //20,60,100,120


//3.reduce函数的使用 reduce对数组中所有内容进行汇总
let total = new2Nums.reduce(function(preValue,n){
return preValue+n;
},0)
console.log(total);
/*
第一次:preValue 0 n 20;
第二次:preValue 20 n 60; preValue值就是对上一次遍历的俩个参数进行相加
第三次:preValue 80 n 100;
第四次:preValue 180 n 120;
*/



const nums2 = [10,30,50,200,145,60,669]
//对以上三个函数进行链式操作
let total2 = nums2.filter(function(n){
return n<100;
}).map(function(n){
return n*2;
}).reduce(function(preValue,n){
return preValue+n;
},0)

console.log(total2);
</script>

Vue生命周期

脚手架CLI2

初始化项目:vue init webpack 项目名

eslint是用来检测代码规范的,一般选择不用

npm run dev 运行项目

npm run build 打包项目

如果安装额外插件的时候,–save是指运行时依赖,–save -dev是指开发时依赖。

runtime-compiler和runtime-only的区别 ,区别在main.js文件里面,

runtime-compiler编译过程:template->ast(抽象语法树)->rander(函数)->virtual dom->true dom->UI

runtime-only编译过程:rander->virtual dom->UI

相比性能而言,runtime-only性能更高,代码量更少,轻6KB

image-20200526103144975

runtime-only直接使用render函数编译,render函数相当于的参数h相当于createElement函数,

image-20200526103338938

上图的传入对象是App,rander函数省略了template的编译,那么App里面的template到底是如何执行的?其实App转化成了一个对象,而里面的tempalte被转化成了rander函数,是被谁转化的呢,是被package.json文件里面的vue-template-compiler插件转化的。

npm run dev 流程图:

image-20200526121325392

npm run build 流程图:

image-20200526121357552

脚手架CLI3

初始化项目:vue create 项目名

npm run serve 运行项目

npm run build 打包项目

启动界面话配置服务器:vue ui

路由

前端渲染和后端渲染的区别

后端路由:后端处理URL和页面之间的映射关系,当我们页面中需要请求不同的路径内容时,交给服务器来进行处理,服务器渲染好整个页面,并将页面返回给客户端,这种情况下渲染好的页面,不需要单独加载任何的js和css,可以直接交给浏览器展示,这样有利于SEO的优化。

前后端分离:后端只负责提供数据,不负责任何阶段的内容。

前端渲染:浏览器中大量显示的数据,先有ajax请求,调用相应的api接口,然后向数据库拿数据,然后这些数据拿到前端,由js代码执行。当访问一个网站的时候,静态服务器会把所以的html css js 代码都加载出来,然后这个时候,前端路由切换相应的页面,这个时候,就不用再次去请求静态服务器了,路由直接为你去找已经加载好的全部资源,然后再调用相应的组件。特点:改变URL的时候,页面是不进行刷新的,不需要向服务器请求资源。

安装路由:npm install vue-router –save

使用路由第一步:通过Vue.use来安装VueRouter插件;第二步:创建VueRouter对象;第三步导出模块,将router对象传入到Vue实例中。

标签是一个v-router中已经内置的组件,它会被渲染成一个标签,跳转路径使用的是属性to,而属性tag的话可以决定渲染成什么样的组件,比如button。active-class属性当路由匹配成功时,会自动给当前元素设置一个router-link-active的class。

会根据当前的路径,动态渲染出不同的组件.

动态路由

动态路由通过v-bind绑定url和拼接url的方式,来动态获取路由

image-20200528135745322

然后进行动态展示

image-20200528135810476

如果使用默认路由的话,使用redirect来设置。

url的hash和html5的history

location.hash = ‘aaa’ ,相当于切换页面,但是不会刷新页面

history.pushState({},’’,’home’) , 此个方法也不会刷新页面,此方法相当于数据结构的栈,push进行入栈操作,最后压入的东西永远在最前面,然后使用history.bcak()的时候,它就会进行出栈,把原来在栈顶的操作移除掉

history.go()能根据指定的参数,进行页面返回前进。

history.forward根据参数进行前进。

history.replaceState({},’’,’home’) 指替换,不能返回之前的url

路由懒加载

当打包构建应用的时候,javascrit包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才能加载对应组件,用到时再加载。

image-20200528154241259

路由参数传递

to属性可以传对象,里面的query属性可传参数

image-20200528161332200

image-20200528161405521

image-20200528161542565

keep alive问题

keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。

router-view也是一个组件,如果直接被包在keep-alive里面,所有匹配到的视图组件都会被缓存。

vue生命周期钩子

当我们使用生命周期函数去渲染的时候会发现,当我们切换组件的时候,原来所在的组件会被destroy,而点击一个页面的时候会触发created函数。

image-20200528224531971 image-20200528224544861

标签包到标签中,就可使用keep-alive,就不会被destroyed,可以大大提高性能

image-20200528225016287

keep-alive存在的时候才可使用生命周期函数activated()和deactivated()函数。

使用

可以排除组件。

导航守卫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Detail from '../views/Detail.vue'
// import User from '../views/User.vue'
// import { component } from 'vue/types/umd'

//路由懒加载
const User = () => import(/* webpackChunkName: "about" */ '../views/User.vue')
const DetailNews = () => import('../views/DetailNews.vue')
const DetailMessage = () => import('../views/DetailMessage.vue')
const Profile = () => import('../views/Profile.vue')
const Test = () =>import('../views/Test.vue')


//1.通过Vue.use(插件),安装插件
Vue.use(VueRouter)

//配置映射关系
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta:{
title:'首页'
}
},
{
path:'/test',
name:'Test',
component:Test
},
{
path: '/detail',
name: 'Detail',
component: Detail,
meta:{
title:'详情页'
},
// component: () => import(/* webpackChunkName: "about" */ '../views/Detail.vue')
children:[
{
//设置默认页面
path:'',
redirect:'news'
},
{
path:'news',
component:DetailNews
},
{
path:'message',
component:DetailMessage
}
]
},
{
path: '/user/:userId',
name: 'User',
component: User,
meta:{
title:'用户页'
}
},
{
path: '/profile',
name: 'Profile',
component: Profile
},
{
path: '/about',
name: 'About',
meta:{
title:'关于'
},
//路由懒加载
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
// //添加默认路径
// {
// path:'',
// //使用redirect重定向
// redirect:'/home'
// }
]

//2.创建VueRouter对象
const router = new VueRouter({
//配置路由与组件之间的映射关系
routes,
mode:'history' //加上此属性可以避免路径上有瞄点的出现,相当于使用history模式,不适用hash模式
})


//前置钩子 页面跳转之前执行
//全局导航守卫
router.beforeEach((to,from,next)=>{
document.title = to.meta.title;
next()
})


//3.导出模块,将router对象传入到Vue实例中
export default router

tabbar

创建tabbar:vue create tabbar

Promise

promise是异步编程的一种解决方案。一种常见的场景就是网络请求,当我们封装一个网络请求的函数时,因为不能立刻拿到结果,所以不能像简单的3+4+7一样的将结果返回,所以我们往往会传入另外一个函数,在数据请求成功之时,将数据通过传入的函数回调出去。当网络请求简单的时候,倒是没多大的影响,但是当我们的网络请求非常复杂的时候,代码多且不易维护,我们就要用到promise。

一般情况下有异步操作时,使用Promise对这个异步操作进行封装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script>
new Promise(function(resolve,reject){
setTimeout(function(){
//成功的时候调用resolve
resolve('hello world');
},1000)
}).then(function(data){
console.log(data);
console.log(data);
console.log(data);
console.log(data);
console.log(data);
})
</script>

<script>
new Promise(function(resolve,reject){
setTimeout(function(){
//失败的时候调用reject
reject('error message');
},1000)
}).then(function(data){
console.log(data);
console.log(data);
console.log(data);
console.log(data);
console.log(data);
}).catch(function(err){
console.log(err); //输出错误的信息
})
</script>

当有多个回调时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//Promise回调  链式编程
new Promise(function(resolve,reject){
//第一次网络请求
setTimeout(function(){
resolve() //如果resolve函数中有参数data,那么then包装的回调函数中的参数也是data
},1000)
}).then(function(){
//第一次拿到结果的处理代码
console.log('hello world');
console.log('hello world');
console.log('hello world');
console.log('hello world');
console.log('hello world');


return new Promise(function(resolve,reject){
//第二次网络请求的代码
setTimeout(function(){
resolve()
},1000)
}).then(function(){
//第二次处理的代码
console.log('hello vue');
console.log('hello vue');
console.log('hello vue');
console.log('hello vue');
console.log('hello vue');

return new Promise(function(resolve,reject){
//第三次网络请求的代码
setTimeout(function(){
resolve()
},1000)
}).then(function(){
//第三次处理的代码
console.log('hello es6');
console.log('hello es6');
console.log('hello es6');
console.log('hello es6');
console.log('hello es6');
})
})
})

promise三种状态:

pending:等待状态,比如正在进行网络请求,或者定时器没有到时间。

fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且回调.then()

reject:拒绝状态,当我们主动回调了reject时,就处于该状态,并且回调.catch()

1
2
3
4
5
6
7
8
9
10
11
12
<script>
new Promise(function(resolve,reject){
setTimeout(function(){
resolve('hello world');
reject('error message');
},1000)
}).then(function(data){
console.log(data);
},function(err){
console.log(err);
})
</script>

//第一个参数为resolve函数的处理,第二个参数为reject的处理

Promise的链式操作简写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
new Promise(function(resolve,reject){
setTimeout(function(){
resolve('aaa');
},1000)
}).then(function(res){
console.log(res,'第一层的10行处理代码');

return Promise.reject('error message')
}).then(function(res){
console.log(res,'第二层的10行处理代码');

return Promise.resolve(res+'222')
}).then(function(res){
console.log(res,'第三层的10行处理代码')
}).catch(function(res){
console.log(res);
})

Promise的all()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<script>
//all方法会判断多个方法都请求成功才会回调
Promise.all([
new Promise(function(resolve,reject){
$.ajax({
url:'url1',
success:function(data){
resolve(data)
}
})
}),
new Promise(function(resolve,reject){
$.ajax({
url:'url2',
success:function(data){
resolve(data)
}
})
})
]).then(function(results){ //返回值是一个数组
results[0] //第一个请求的结果
results[1] //第二个请求的结果
})
</script>

Vuex

vuex是一个专门为Vue.js应用程序开发的状态管理模式。

假如多个组件都有一个变量共享的话,我们要把这个变量放到哪里,如果放到组件里面的话,当其它组件来调用这个变量的话就会显得很麻烦,如果组件多就是个大问题,所以我们都会把多个组件共享的全部变量全部存储在一个对象里面。相当于这个变量是个公共资源,当组件用到的时候,去这个公共资源里面找。

猜疑?为什么我们不自己封装一个对象,然后把公共资源放到对象里,用的时候各个组件再调用呢?

答:当我们使用对象的时候,当我们改变对象里面的值时,组件里之前调用的值是不会改变的,就像不使用单例模式前我们实例化的时候,第一次的对象值跟第二次的对象值结果不一样。每次实例化的时候都会开辟不同的内存地址,所以值是不一样的。但是Vuex就不一样了,它会响应式,即使你在对象里改变了值,它以前的值也会改变的。

所以Vuex就是一个在多个组件间共享状态的插件。

img

actions是用来回调的,回调一般用在后端。Devtools是用来记录state状态的,可根据Devtools来查找是哪个组件改的记录。

State单一状态树:尽量只使用一个store,便于管理和维护。

getters:有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数,我们就用到getter函数对state中的东西作出筛选和过滤,getters是内容。

mutations:相应规则:Vuex的store中的state是响应式的,当state中数据发生改变时,Vue组件会自动更新。mutation操作一般用在同步操作,如果用在异步的话,效果不是那么的好,devtools插件会捕捉不到有时。所有异步的话就要用Action。

Actions:代替mutation进行异步操作。但是它并没有跳过mutation环节,mutation环节是必不可少的。

以下为Action的步骤代码:

image-20200603145214369

image-20200603145233514

然后在store里进行异步:

image-20200603145310861

image-20200603145730767

Modules:Module就是模块的意思,因为Vue的state使用单一状态树,意味着很多状态都交给Vuex来管理,当应用非常多的时候,store对象就会变得非常复杂化,可读性差。为了解决这个问题,vuex提供了module,而每个module都有自己的states,mutations

,actions,getters,小李把这现象称为疯狂套娃模式。在调用modules的时候,就如下图调用,我用的是a模块里的东西。

image-20200603110515384

在真正的开发中,如果把很多东西都放到同一个文件里面,会造成项目看着很乱,所以,我们分别为getters,mutations,actions,modules各自见自己的文件,然后使用模块导出导入的方式,进行一一调用。

image-20200603151422126

image-20200603153339982

axios网络模块封装

一般我们进行网络请求封装的时候都是使用jQuery-Ajax来进行的,但是在Vue中的话,我们已经引入了Vue框架,如果再引入jQuery的话,会造成资源的一种浪费,所以完全没有必要去进行,所以在Vue中我们进行网络请求的时候我们一般都使用axios框架。

jsonp:使用jsonp的原因是为了解决跨域访问的问题。JSONP的核心在于通过<-script>标签的src来帮我们请求数据,当我们的项目部署到domain1.com服务器上的时候,此项目是不能直接访问domain2.com服务器上的资料。这个时候,我们利用<-script>标签上的scr来帮助我们去服务器上请求数据,将数据当作javascript的函数执行,并在执行的过程中,传入我们需要的json,所以封装json的核心就在于我们监听windows上的jsonp进行回调的名称。

安装axios : npm Install axios –save 开发时依赖

调用格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

//axios的基本使用
axios({
url:'http://123.207.32.32:8000/home/multidata',
methods:'get'
}).then(function(res){ //这个res参数不是凭空出来的,当我们学习Promise()时候,resolve函数的处理结果
console.log(res)
})


//axios的并发请求
axios.all([axios({
url:'http://123.207.32.32:8000/home/multidata',
}),axios({
url:'http://123.207.32.32:8000/home/data',
params:{
type:'sell',
page:'4'
}
})]).then(function(result){
console.log(result)
})

当存在多个服务器时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//创建对应的axios实例   第一个服务器的
const instance1 = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000
})

instance1({
url:'/home/multidata'
}).then(function(res){
console.log(res);
})

instance1({
url:'/home/data',
//params为url后面所跟的参数
params:{
type:'pop',
page:1
}
}).then(function(res){
console.log(res);
})


//创建第二个服务器的axios实例
const instance2 = axios.create({
baseURL:'http://193.112.131.5:8000',
timeout:10000
})

为了避免组件对axios的框架,我们就应该创建公共的axios模块,需要时各个组件向公共axios模块调用即可。

先建个network文件,放要封装的axios模块。

image-20200604222148228

然后再main.js里面进行引入。

image-20200604222241768

axios拦截器

请求拦截器的作用是在请求发送前进行一些操作,例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易。

响应拦截器的作用是在接收到响应后进行一些操作,例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
##request.js文件

//单独对axios模块封装
import axios from 'axios'

//导出多个模块
export function request(config){
//1.创建axios实例
const instance = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000,
})


//2.axios的拦截器
//2.1请求拦截
instance.interceptors.request.use(function(config){ //参数里有两个函数,一个成功,一个失败
// console.log(config);
return config //拦截之后要返回回去
},function(err){
console.log(err);
})

//2.2响应拦截
instance.interceptors.response.use(function(res){
// console.log(res);
return res;
},function(err){
console.log(err);
})


//3.发送真正的网络请求
return instance(config); //里面的参数config相当于一个大对象,里面有url的基本配置信息,因为axios本身就是Promise,所以这里return的是Promise,而Promise函数里面默认传参数resolve和reject,而他两本身就是函数,到时候会在.then和.catch中回调出去。
}
1
2
3
4
5
6
7
8
9
##home.js文件

import {request} from './request.js'

export function getHomeMultidata(){
return request({
url:'/home/multidata'
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
##Home.vue文件

<template>
<div id="home">
<NavBar class="home-nav">
<div slot="center">购物街</div>
</NavBar>
</div>
</template>

<script>

import NavBar from '../../components/common/navbar/NavBar.vue'
import {getHomeMultidata} from '../../network/home.js' //如果不用default导出的话要加大括号

export default {
name:'Home',
components:{
NavBar
},
data(){
return{
banners:[]
}
},
//利用生命周期函数请求数据
created(){
getHomeMultidata().then(res => {
// console.log(res);
this.result = res; //因为函数是局部作用域,里面的数据被调用就会被销毁,也就是说res不指向对象的地址了,所以直接把res的指向赋值给result变量,到时候即使res不指向对象的时候,result也指向那个对象的地址
})
// console.log(this.result);
}
}
</script>

<style scoped>
.home-nav{
background-color: var(--color-tint); /*直接使用css预设的变量*/
color: white;
}
</style>

Vue常见问题

vue-cli下的项目出现Module not found: Error: Can’t resolve ‘stylus-loader’错误解决方案:

1
2
第一步:npm install stylus stylus-loader --save-dev
第二步:npm install


绑定在标签中的res:

res如果绑定在组件中,那么通过this.$refs.refname获取到的是一个组件对象

所有组件都有一个属性$el:用于获取组件中的元素

res如果绑定在普通的元素中,那么通过this.$refs.refname获取到的是一个元素对象

为什么搞res:res相当于唯一的标识符,避免有相同的类名而冲突

所有组件都有一个属性$el:用于获取组件中的元素

ES6箭头函数与普通函数的区别

箭头函数不会创建自己的this:

一般函数都有自己的this,但是箭头函数没有自己的this,它只会从自己的作用域链的上一层继承this。它会捕获自己在定义时所处的外层执行环境的this,并继承这个this值。

Vue项目开发

解决首页中Better-Scroll可滚动区域的问题。

Better-Scroll在决定有多少区域可以滚动的时候,是根据scrollHeight属性决定的:

​ sctollerHight属性是根据Better-Scroll的content中的子组件的高度计算的,但是

​ 在首页中,刚开始计算scrollerHeight属性时,是没有将网络请求到的图片计算在内的。

​ 所以计算出来的是错误的(1300+)

​ 后来图片加载出来之后有了新的高度,但是scrollerHeight属性并没有进行更新。

​ 所以滚动出现了问题。

如何解决这一问题?

​ 监听每一张图片是否加载完成,只要有一张图片加载完成了,执行依次refresh()。

tabControl的吸顶效果

1.获取到tabControl的offsetTop

必须知道滚动到多少的时候才有吸顶效果,这个时候就需要获取tabControl的offsetTop

如果直接再生命周期函数mounted中获取tabControl的offsetTop,那么值是不正确的。所以我们用@load直接监听HomeSwiper组件中的img的加载。然后发出事件,在Home组件中获取正确的值。

让Home保持原来的状态

当我们离开home页,生命周期函数会执行destroy函数,组件会销毁当前状态,所以使用keep-alive。

让Home保持原来的状态:

离开时在生命周期函数deactivated中保存当前的位置信息y

进来时,在生命周期函数activated中调用原来保存的位置信息y

Author: 小灰灰

Link: http://xhh460.github.io/2020/05/25/Vue%E5%AD%A6%E4%B9%A0/

Copyright: All articles in this blog are licensed.

< PreviousPost
mysql进阶
NextPost >
动态链表
CATALOG
  1. 1. Vue学习
    1. 1.0.1. Vue基础语法
    2. 1.0.2. 组件通信:
      1. 1.0.2.1. 父传子-props
      2. 1.0.2.2. 子传父
    3. 1.0.3. 子组件data必须为函数
    4. 1.0.4. js高阶函数
    5. 1.0.5. Vue生命周期
    6. 1.0.6. 脚手架CLI2
    7. 1.0.7. 脚手架CLI3
    8. 1.0.8. 路由
    9. 1.0.9. 动态路由
    10. 1.0.10. url的hash和html5的history
    11. 1.0.11. 路由懒加载
    12. 1.0.12. 路由参数传递
    13. 1.0.13. keep alive问题
    14. 1.0.14. 导航守卫
    15. 1.0.15. tabbar
    16. 1.0.16. Promise
    17. 1.0.17. Vuex
    18. 1.0.18. axios网络模块封装
    19. 1.0.19. Vue常见问题
    20. 1.0.20. ES6箭头函数与普通函数的区别
    21. 1.0.21. Vue项目开发
      1. 1.0.21.1. tabControl的吸顶效果
      2. 1.0.21.2. 让Home保持原来的状态