vue for webapp 中的总结&&填坑

GitHub:https://github.com/liu9183/vue-for-sellApp

历时三个星期,在教程和文档的抽丝剥茧中敲完,中间体会以此为记

本项目使用的vue-cli脚手架,安装过程简单交代, 如想详细了解,请参考官方文档

1.新建工程文件vue-for-sellapp

2.cd vue-for-sellapp

3.npm install vue-cli

4.vue init webpack  //项目基于webpack模板

5.npm install  //安装依赖

6.npm run dev //启动服务器,默认端口8080


现在挑几个重点难点说一说

一、vue-router

vuejs将多个组件组合为一个应用,却没有解决不同页面的切换问题,也就是说同一个页面区域内,可能需要根据用户的手动切换进行不同的渲染,展示不同的内容。

vue-router提供了很好的路由指向功能,看如下代码

<div class="tab">
    		   <div class="tab-item">
    		   	<router-link to="/goods">商品</router-link>
    		   </div>
    		   <div class="tab-item">
    		        <router-link to="/ratings">评论</router-link>
    		   </div>
    		   <div class="tab-item">
    		   	<router-link to="/seller">商家</router-link>
    		   </div>
    	</div>
    	
    		<router-view :seller="seller"></router-view> <!--路由匹配到的组件将自此处渲染 -->
    	

代码中的<router-link to=""></router-link>标签提供了路由指向功能,当我们点击“商品”时便会把定义好的goods组件渲染到 

<router-view :seller="seller"></router-view>

之中,同时将seller对象传入到匹配到的组件中(这里称其为子组件 ),在此子组件中通过props接收到父组件传入的seller对象,一个很巧妙的数据流动方式。

<router-link to="/goods">商品</router-link>默认的渲染结果是<a href="/goods">商品<a>

当我们点击了“商品”时, <router-link> 对应的路由匹配成功,将自动设置 class 属性值 .router-link-active,我们便可通过此类名为点击事件添加样式。

到此为止,我们都在讲vue-router的原理和使用,那么它是如何引入到项目中的呢,我们看项目的入口文件main.js

import Vue from 'vue';
import VueRouter from 'vue-router'; //首先引入依赖,命名为VueRouter
import VueResource from 'vue-resource';
import App from './App.vue';
import goods from './components/goods/goods.vue';
import ratings from './components/ratings/ratings.vue';
import seller from './components/seller/seller.vue';


Vue.use(VueRouter);//插件注册
Vue.use(VueResource);


const router = new VueRouter({
	routes:[
	  {
	  	path:'/goods',//为每个组件定义路由路径,使用此路径便可以调用对应组件
	    component:goods
	  },
	  {
	  	path:'/ratings',
	    component:ratings
	  },
	  {
	  	path:'/seller',
	    component:seller
	  }
	]
});

let sellapp=new Vue({
	el:'#app',
	template: '<App/>',
	components:{ App },
	router    //为实例注入路由,从而让整个应用都有路由功能

})
在这里有的开发者对Vue.use()函数抱有很多幻想,这里推荐一篇文章 Vue.use源码分析

至于vue-resource先不做讨论

 二、生命周期钩子


生命周期分八个状态对应八个函数,自始至终分别是

1.beforeCreate()

2.created()-------实例已经被创建完成并调用,数据观测(data observer),属性和方法的运算,watch/event事件回调已准备就绪,但是实例尚未挂载,没有进行DOM树构建 和渲染

3.beforeMount()

4.mounted()-------el 被新创建的vm.$el 替换,组件挂载成功

5.beforeUpdate()-------数据更新时调用,此时还没发生DOM重新渲染以及打补丁,可以在这个钩子中进一步更改状态,这不会触发附加的重渲染过程

6.updated()-------数据更改导致DOM重新渲染和打补丁,在这之后调用该钩子,当这个钩子被调用时,组件DOM已经更新,所以可以执行依赖更新后的DOM节点的操作

7.beforeDestroy()

8.destroyed()

三、深入响应式原理

基于本项目所涉及,这里只提一下vm.$nextTick()

看如下代码

_initScroll() {
				this.$nextTick(() => {
					if(!this.scroll) {
						this.scroll = new BScroll(this.$refs.seller, { 
							click: true
						});
					} else {
						this.scroll.refresh();
					}

				})
			}
将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。

此处有坑,看下面代码(seller.vue组件中)

   watch: {
			'seller' () {
				this._initScroll();
				//console.log("watch执行了"); 
				//console.log(this.$refs.info);
				//console.log(this.seller.infos);				
				//this._initPics();
			}
		},
		mounted() {
			this._initScroll();  
			//console.log("mounted执行了");
			//console.log(this.$refs.info);
			//console.log(this.seller.infos);
			
			//this._initPics();
		}
_initScroll()

    _initScroll() {
				this.$nextTick(() => { 
					if(!this.scroll) {
						this.scroll = new BScroll(this.$refs.seller, { 
							click: true
						});
					} else {
						this.scroll.refresh();
						
				}

				})
			}
很明显,我要在seller组件中实现页面滚动,为什么需要mounted钩子以及watch监视seller对象共用呢,宝宝心里苦啊,原本以为vue生命周期中mounted钩子调用阶段页面DOM早已构建渲染好,直接滑动便可,确实,我在主页面http://localhost:8080/#/到点击进入http://localhost:8080/#/seller中确实实现了seller页的滚动,可当我再次刷新seller页面(http://localhost:8080/#/seller)时,页面又不能滚动了……

查看控制台输出,发现this.seller.infos获取不到,也就是seller对象并没有传进来,但是this.$refs.info却获取到了,不明白为什么seller对象得不到页面数据渲染却成功了。

然后经过一番纠结困恼,我添加了seller对象监视,在监视到seller对象变化时,再次调用_initScroll(),如此这般,问题竟然奇迹般解决了,不管是seller页面刷新还是从主页面进入seller页,滚动都没问题,我尝试将this.$nextTick方法弃用,发现又不行了……

总结一下:刷新seller页面时,seller对象异步获取,在还没有获取成功便执行了_initScroll(),此时页面依赖seller对象提供的数据撑开,子元素没有超出父元素的界限,自然不会触发滚动,而使用watch监控seller变化,在seller变化完成后又执行_initSrcoll(),便可以触发滚动

四、父子组件通信

我们知道子组件想获取父组件的对象,可以用props进行传递,那么父组件要获取子组件传递的信息该如何实现呢??

本项目为例,在ratings组件中嵌入了ratingselect子组件,而子组件获取用户的点击信息要传递到父组件进行条件展示,比如客户点击了“满意”按钮,那么父组件要响应展示评论中好评的部分。

看下面代码

<div class="rating-type">
			<span @click="select(2,$event)" class="block positive" :class="{'active':selectType===2}">{{desc.all}}<span
          class="count">{{ratings.length}}</span></span>
			<span @click="select(0,$event)" class="block positive" :class="{'active':selectType===0}">{{desc.positive}}<span
          class="count">{{positives.length}}</span></span>
			<span @click="select(1,$event)" class="block negative" :class="{'active':selectType===1}">{{desc.negative}}<span
          class="count">{{negatives.length}}</span></span>
		</div>

select方法

	select(type, event) {
				if(!event._constructed) {
					return;
				}
				this.$emit('select', type);
			}
vue为我们提供了$emit方法,将type绑定到指定的方法(第一个参数指定方法名)上,在这里是select

好了,我们来看父组件如何拿到select方法。

<ratingselect :select-type="selectType" :only-content="onlyContent" :ratings="ratings" @select="select" @toggle="toggle"></ratingselect>

很清楚,在ratingselect组件挂载到父组件ratings时就已经通过v-on传了进来,@select便是将子组件的select方法传到父组件,后面的字符串便是在父组件中对应的函数名,这里还是用select。

最后,看一下在父组件中的函数使用

	select(type){
				this.selectType = type;
				this.$nextTick(() => {
				
					this.scroll.refresh();
				});
			}

五、web存储

参见我的另一篇博客web storage

六、解析url

项目在部署使用过程中,难免遇到与个人信息绑定的东西,比如id为1234的用户点击收藏后,再次刷新http://localhost:8080/?id=1234#/seller,则依然显示已收藏,这就需要计算机得到用户id,并且缓存相关信息,再次刷新后读取缓存

那么如何从URL中得到用户信息呢

见我一篇博文解析url,生成对应JSON对象

七、初涉Express框架

在本项目中express来获取data.json中的数据,并向客户端传送JSON响应


我已在另一篇博客比较细致地介绍了Express的基本原理和使用方法,请参见——Express框架学习笔记

未完待续……………………………………………………




  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值