「加薪DAY4」Vue.js项目经验总结-冒险岛2
项目介绍
《冒险岛2》岛民社区——一个APP内嵌HTML5页面的社区型专题。收到时他的PSD是这样。
作者:邵晓斌-腾讯重构工程师
@IMWeb前端社区,若未授权禁止转载
《冒险岛2》岛民社区设计稿
项目选型
其实当时拿到这个需求的时候,因为直接定义了其为APP内嵌社区,所以当时的判断是一个重交互型页面,应该为单页应用。原本我们的交互如果不是使用原生javascript的情况下,也使用了jquery等一些dom操作库,那么都到16年(这个前端技术爆发的一年?)所以我们是不是还要用继续用jquery来做呢?那么我们选用的方案是啥呢?答案当时是——MVVM~
那么说到MVVM库,我们首先想到的必然是当前比较火热的几个
- Angular
- React
- Vue
当然其实还有许多许多。
最终我选用了Vue,理由有几点:
- 首先我之前使用过Angular,他俩很像。但是在API上来说Vue比Angular简单多了。而且Angular的断崖式更新的惨案也不绝于耳。想必用过Angular的各位一定记忆犹新。所以我果断还是放弃了Angular。
- 其次我没有选用react,在http://vuejs.org上有vue和react的比较,其中有这样一句话:“React 团队雄心勃勃,计划让 React 成为通用平台的 UI 开发工具,而 Vue 专注于为 Web 提供实用的解决方案。” 所以相比重而复杂的react,我更偏向于小而美的Vue。
- 最终我选择了既有中文文档,同时在github上star颇高,issues维护速度惊人,API和设计都相对简单的Vue.js。
Vue.js介绍
http://Vuejs.org上的一句宣传语:“数据驱动的组件,为现代化的 Web 界面而生”就可以总结Vue.js的全部了。
Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。Vue.js通过双向绑定来实现了View层和Model层的连接,
以数据驱动模型。
在使用 jQuery 手工操作 DOM 时,我们的代码常常是命令式的、重复的与易错的。而DOM在单页WEB应用中的问题有会有当我们重新渲染整个视图的成本是非常昂贵的,而且手动来更新DOM来保持视图和数据的同步很容易导致Bug。所以Vue.js 拥抱数据驱动的视图概念。一旦创建了绑定,DOM 将与数据保持同步。每当修改了数据,DOM 便相应地更新。这样我们应用中的逻辑就几乎都是直接修改数据了,不必与 DOM 更新搅在一起。这让我们的代码更容易撰写、理解与维护。
最后也是Vue很重要的一个概念就是组件系统。按照官网上的写法就是:“因为它提供了一种抽象,让我们可以用独立可复用的小组件来构建大型应用。如果我们考虑到这点,几乎任意类型的应用的界面都可以抽象为一个组件树:
所以Vue.js的核心思想就是数据驱动与组件化,他是一个专注在视图层的Web界面库~
Vue.js简单Demo
这里也是列举官方文档里的最简单的Demo,简单聊聊基础功能。
首先:
<div id="app">
<p>{{message}}</p>
<input type="text" v-model="message">
<button v-on:click="reverseMessage">reverse message</button>
</div>
new Vue({
el: '#appEvent',
data: {
message: '1'
},
methods: {
reverseMessage: function() {
this.message = this.message.split('').reverse().join('');
}
}
});
这里提供了Vue.js实例的构造方法,通过这简单的2行代码实现了图中的输入内容与视图层同步的功能。
我们所作的只是申明绑定了dom和相应的数据,就简单实现了双向绑定。然后通过事件的绑定操作数据这样视图层也同步更新。
我们再来看一下Vue.js的一些基础语法:
数据绑定语法
- 插值
- 文本 {{mag}} {{*msg}}
- html {{{html}}}
- html 属性 id=”item-{{id}}”
- 绑定表达式
- js表达式
- 过滤器
- 指令 v-if、v-show、v-else、v-for(遍历数组或对象) …
等等…
《岛2》社区中制作的一些简单功能(组件)
1.文本输入框
这个功能点上非常简单就是需要提供可输入的文字总量,并在超过时给出提示。所以这里利用Vue.js的双向绑定和样式绑定就可以轻松完成这个简单的功能。
<div class="edit-input-box">
<textarea name="sIntro" id="" class="mon-input" placeholder="分享你身边的趣事吧" v-model="message"></textarea>
<p class="font-num-box">
( <span v-bind:class="{'font-num-error':message.length>140}">{{message.length}}</span> /140)
</p>
<a href="javascript:;" class="edit-submit-btn">发送</a>
</div>
很简单的一步就完成了数据与视图的同步~
2.图片上传
图片上传的话功能点上会相对比较多总结整理的话
- 上传图片
- 新增小图浏览
- 点击提示可删除原上传图片
<div class="upload-img-box cf">
<template v-for="image in uploadList" track-by="$index">
<div class="upload-img-item-warp" v-on:click="delLoadImage($index)">
<div class="upload-img-item" style="background:url({{image}}) center center no-repeat"></div>
<span class="upload-img-del-icon">×</span>
</div>
</template>
<div class="upload-btn">
<input type="file" class="inp-file" v-change="imageChange" name='file' id='J_file' />
</div>
</div>
var upload = Vue.extend({
template:"#uploadItem",
data: { uploadList:[] },
methods:{
delLoadImage:function(index,e){....}
imageChange: function(event) {
var files = event.target.files || event.dataTransfer.files;
if (!files.length) return;
for (var i = 0; i < files.length; i++) {
this.createImage(files[i]);
}
},
createImage: function(file) {
var image = new Image();
var reader = new FileReader();
var vm = this;
reader.onload = function(e) {
vm.images.push(e.target.result);
MXD2_UPLOAD.uploadImg('J_file');
};
reader.readAsDataURL(file);
}
}
})
上传图片依然只能使用type[file]按钮进行上传,在其结构上使用事件绑定指令v-change绑定方法,imageChage,通过执行Api FileReader来读取图片并创建,将图片数据保存在result数组中,通过v-for遍历此数组渲染出小图列表,当删除图片时,只需要通过splice切割数组即可以删除该图,同时渲染出当前列表,而且绑定在这个dom结构上的事件也会在删除的同时被销毁。
3.社区列表
其实社区的列表中的一条就可以拆分多个组件
- 发布的文字信息
- 列表图片
- 时间/位置
- 点赞
- 评论列表
- 功能操作工具条
‘具体社区列表结构如下:
//社区组件内部结构
<div class="monent-item">
<div class="monents-user-face">
<a href="#" class="face-img">
<img v-if="data.sOpenId=='616d615a6d47466c6d5a706d62513d3d'" src="http://ossweb-img.qq.com/images/comm/blank.png" data-oxlazy="http://mxd2.qq.com/act/a20160809moments/manager.jpg"
alt="管理员">
<img v-else src="http://ossweb-img.qq.com/images/comm/blank.png" data-oxlazy="{{data.sUrl}}" alt="{{data.sNickName}}">
</a>
</div>
<div class="monents-detail">
<mon-info></mon-list>
<div class="mon-info">
<a href="" class="mon-info-name" v-bind:class="{'mon-info-name-admin':data.sOpenId=='616d615a6d47466c6d5a706d62513d3d'}">{{data.sNickName}}</a>
<span v-if="data.sOpenId=='616d615a6d47466c6d5a706d62513d3d'" class="admin-icon-span">管理员</span>
<div class="mon-type-box">
<span v-if="data.Recommend" class="mon-hot-icon">推荐</span>
</div>
</div>
<div class="mon-txt">
<a href='#' class='a-topic'>#{{data.sTopic}}#</a>
<span v-if="data.iExt1==1">分享了我的形象"{{data.sIntro}}"</span>
<span v-else>{{data.sIntro}}</span>
</div>
<mon-imglist></mon-imglist>
<mon-frome></mon-frome>
<tool-box id='J_tool_{{data.hot}}_{{data.iContentId}}' :toolShow="toolShow" :owner="owner" :store="store" :data="data" :index="index"></tool-box>
<div class="comment-box">
<like-list></like-list>
<moment-list></moment-list>
</div>
</div>
</div>
//实际调用时自定义结构
<monent-item v-for="(index,item) in searchmonent" :data="item" :owner="owner" :store="store" :index="index"></monent-item>
最终效果如下图:
大型项目
由于在一开始的规划中还未使用vue-cli来构建项目,利用webpack打包,最后来说一下我们如果是大型项目,显然使用模块化的构建方式更显科学。
构建单页应用。
由于Vue2.0已经发布默认使用2.0模板,如果要安装1.0模板 直接在vue init阶段 使用 webpack-simple#1.0 即可构建1.0模板
只有我们就可以使用单文件组件方式来模块化自己的项目,使用.vue文件,其中包括这个组件的全部内容——style,template和script。
然后官方也提供许多插件包括
- axios(ajax)
- vue-devtools(chrome开发者工具)
- vue-router
等等。
最后的最后…
现阶段的前端正在快速道上飞奔,几乎每一天都会有新的知识新的名词出现,前几天还在说前端MVC这两年都在说MVVM,无论是Vue、Angular、React,包括React Native还有之前阿里无线开源Weex等。我们为了赶上这些只有在学习中不断在项目中实践。
岛2项目今后也会在各种方面不断尝试Vue.js来实现各种功能,当然无论是直接用script单文件引入,还是对于一些大型项目使用Webpack构建的SPA。最后还是要赞一句所有这都归功于官方健全的文档,优质的社区资源。
若你阅读该文中有什么疑问,欢迎在下方评论区留言,我们会选择部分问题解答