一步一步学Vue(十二)
为了提升代码的逼格,之后代码改为Vue文件组件,之前代码虽然读起来容易理解,而且适合在小的项目中使用,但是有如下缺点:
- 全局定义(Global definitions) 强制要求每个 component 中的命名不得重复
- 字符串模板(String templates) 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的
\
- 不支持CSS(No CSS support) 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
- 没有构建步骤(No build step) 限制只能使用 HTML 和 ES5 JavaScript, 而不能使用预处理器,如 Pug (formerly Jade) 和 Babel
文件扩展名为 .vue
的 single-file components(单文件组件) 为以上所有问题提供了解决方法,并且还可以使用 Webpack 或 Browserify 等构建工具。
所以基于这种考虑,我们以后会使用单文件模式去编写代码,并且为了看上去更洋气一些,我们的代码会以IView作为基础组件,不熟悉的同学正好可以简单了解一些,本节主要基于单文件组件重构上节的代码。
vue官方提供了很好的命令行工具,vue-cli,可通过npm直接安装 npm install -g vue-cli;对此我不做过多介绍,google到的内容你看都看不过来。
我们基于webpack-simple 脚手架搭建我们的项目,运行 vue init webpack-simple demo,接着一步一步走就ok了,然后进入demo 文件夹,执行npm install 安装依赖即可,安装完毕后执行npm run dev 即可启动程序:
看到上述结果表示已经运行成功,从package.json的script节可以看到,开发模式下启动了热加载模式,无需手动刷新浏览器即可完成代码重载。
既然使用IView,那么我们先安装IView ,npm install --save iview; 并在webpack 入口页面引入并启用
修改我们的webpack.config.js,保证支持css引入以及字体文件导入(npm install --save-dev css-loader style-loader url-loader):
var path = require('path')
var webpack = require('webpack') module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: ['style-loader','css-loader' ]
},
{
test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/,
loader: 'url-loader?limit=1024'
},
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
devServer: {
historyApiFallback: true,
noInfo: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
} if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
此时我们的iview已经可用了,我们这里引入了iview全部组件,如果按需引入,则需要对每一个组件进行分别引入。首先搭建我们布局页(直接简单修改iview layout代码):
<template>
<div class="layout" :class="{'layout-hide-text': spanLeft < 5}">
<Row type="flex">
<i-col :span="spanLeft" class="layout-menu-left">
<Menu active-name="1" theme="dark" width="auto">
<div class="layout-logo-left">
Demo Project
</div>
<Menu-item name="1">
<Icon type="ios-navigate" :size="iconSize"></Icon>
<span class="layout-text">TODOList</span>
</Menu-item> </Menu>
</i-col>
<i-col :span="spanRight">
<div class="layout-header">
<i-button type="text" @click="toggleClick">
<Icon type="navicon" size="32"></Icon>
</i-button>
</div> <div class="layout-content">
<div class="layout-content-main">内容区域</div>
</div>
<div class="layout-copy">
2011-2016 © demo
</div>
</i-col>
</Row>
</div>
</template>
<script>
export default {
data () {
return {
spanLeft: 5,
spanRight: 19
}
},
computed: {
iconSize () {
return this.spanLeft === 5 ? 14 : 24;
}
},
methods: {
toggleClick () {
if (this.spanLeft === 5) {
this.spanLeft = 2;
this.spanRight = 22;
} else {
this.spanLeft = 5;
this.spanRight = 19;
}
}
}
}
</script> <style scoped>
.layout{
border: 1px solid #d7dde4;
background: #f5f7f9;
position: relative;
border-radius: 4px;
overflow: hidden;
}
.layout-breadcrumb{
padding: 10px 15px 0;
}
.layout-content{
min-height: 200px;
margin: 15px;
overflow: hidden;
background: #fff;
border-radius: 4px;
}
.layout-content-main{
padding: 10px;
min-height:768px;
}
.layout-copy{
text-align: center;
padding: 10px 0 20px;
color: #9ea7b4;
}
.layout-menu-left{
background: #464c5b;
}
.layout-header{
height: 60px;
background: #fff;
box-shadow: 0 1px 1px rgba(0,0,0,.1);
}
.layout-logo-left{
width: 90%;
height: 30px;
background: #5b6270;
border-radius: 3px;
margin: 15px auto;
text-align:center;
line-height:30px;
color:#fff;
}
.layout-ceiling-main a{
color: #9ba7b5;
}
.layout-hide-text .layout-text{
display: none;
}
.ivu-col{
transition: width .2s ease-in-out;
}
</style>
运行npm run dev:可看到如下效果:
接下来引入我们的vuex,使用npm install --save vuex ,并对main.js做如下修改:
import Vue from 'vue'
import IView from 'iview';
import Vuex from 'vuex';
import App from './App.vue'
import 'iview/dist/styles/iview.css'; import store from './store'; Vue.use(IView);
Vue.use(Vuex); new Vue({
el: '#app',
store,
render: h => h(App)
})
创建store.js,并添加如下代码(代码来源于上一篇博文中代码):
var list=[]; export default {
state: {
items: [], // todoContainer中items,
//初始化表单所用
initItem: {
title: '',
desc: '',
id: ''
}
}, mutations: {
search (state, payload) {
state.items = list.filter(v => v.title.indexOf(payload.title) !== -1);
},
save (state, payload) {
if (state.initItem.id) {
var o = list.filter(v => v.id === payload.id);
o.title = payload.title;
o.desc = payload.desc;
state.items = state.items.map(v => {
if (v.id == payload.id) {
return payload;
}
return v;
}); } else {
var id=state.items.length+1;
state.items.push({id:id,title:payload.title, desc:payload.desc});
} list = state.items;
},
remove (state, payload) {
state.items = state.items.filter(v => v.id !== payload.id);
},
edit (state, payload) {
state.initItem = state.items.filter(v => v.id === payload.id)[0];
}
}
};
创建components文件夹,并按照单文件组件的规范创建组件:
SearchBar.vue
<template>
<div class="row toolbar">
keyword:
<Input type="text" v-model="keyword" ></Input>
<Button type="primary" @click="search()">search</Button>
</div>
</template> <script>
export default {
data: function () {
return {
keyword: ''
}
},
methods: {
search() {
this.$store.commit("search", {
title: this.keyword
});
}
}
}
</script>
TodoList.vue:
<template>
<Table border :columns="columns" :data="items"></Table>
</template>
<script>
export default{
data(){
return {
columns:[
{
title:'Id',
key:'id'
},
{
title:'title',
key:'title',
},
{
title:'desc',
key:'desc'
},
{
title:'actions',
//TODO:操作 }
]
}
},
props:[
'items'
],
methods:{
edit: function () {
this.$store.commit('edit',this.todo);
},
remove: function () {
this.$store.commit('remove',{id:this.todo.id});
}
}
}
</script>
TodoForm.vue:
<template>
<div class="col-md-6">
<div>
<label for="title">title:</label>
<input type="hidden" v-bind:value="todo.id" />
<Input v-model="todo.title" ></Input>
</div>
<div>
<label for="desc">desc</label>
<Input v-model="todo.desc" ></Input>
</div>
<div>
<Button type="primary" v-on:click="ok()">Ok</Button>
</div>
</div>
</template>
<script>
export default{
props: ['initItem'], computed: {
todo: function () {
return { id: this.initItem.id, title: this.initItem.title, desc: this.initItem.desc };
}
}, methods: {
ok: function () {
this.$store.commit("save",this.todo);
}
}
}
</script>
修改app.vue 完成组件注册和初始化:
<template>
<div class="layout" :class="{'layout-hide-text': spanLeft < 5}">
<Row type="flex">
<i-col :span="spanLeft" class="layout-menu-left">
<Menu active-name="1" theme="dark" width="auto">
<div class="layout-logo-left">
Demo Project
</div>
<Menu-item name="1">
<Icon type="ios-navigate" :size="iconSize"></Icon>
<span class="layout-text">TODOList</span>
</Menu-item> </Menu>
</i-col>
<i-col :span="spanRight">
<div class="layout-header">
<i-button type="text" @click="toggleClick">
<Icon type="navicon" size="32"></Icon>
</i-button>
</div> <div class="layout-content">
<div class="layout-content-main">
<search-bar></search-bar>
<todo-list :items="items"></todo-list>
<todo-form :init-item="initItem"></todo-form>
</div>
</div>
<div class="layout-copy">
2011-2016 © demo
</div>
</i-col>
</Row>
</div>
</template>
<script>
import SearchBar from './components/SearchBar.vue';
import TodoForm from './components/TodoForm.vue';
import TodoList from './components/TodoList.vue'; export default {
data () {
return {
spanLeft: 5,
spanRight: 19
}
},
components:{
'search-bar':SearchBar,
'todo-form':TodoForm,
'todo-list':TodoList
},
computed: {
iconSize () {
return this.spanLeft === 5 ? 14 : 24;
},
initItem: function () {
return this.$store.state.initItem;
},
items: function () {
return this.$store.state.items;
}
},
methods: {
toggleClick () {
if (this.spanLeft === 5) {
this.spanLeft = 2;
this.spanRight = 22;
} else {
this.spanLeft = 5;
this.spanRight = 19;
}
}
}
}
</script> <style scoped>
.....
</style>
此时保存,直接在浏览器可以看到如下效果:
今天时间不充足,重构就到这里,第一次使用单文件组件还是手生,代码调试比较费时间,一步一步的来吧。下一篇继续改造,里面包含了很多bug,大家可以试着修复或者完善一下。
good night。
一步一步学Vue(十二)的更多相关文章
- MINA、Netty、Twisted一起学(十二):HTTPS
由于HTTPS协议是由HTTP协议加上SSL/TLS协议组合而成,在阅读本文前可以先阅读一下HTTP服务器和SSL/TLS两篇博文,本文中的代码也是由这两篇博文中的代码组合而成. HTTPS介绍 上一 ...
- 从头开始学JavaScript (十二)——Array类型
原文:从头开始学JavaScript (十二)--Array类型 一.数组的创建 注:ECMAscript数组的每一项都可以保存任何类型的数据 1.1Array构造函数 var colors = ne ...
- Java从零开始学四十二(DOM解析XML)
一.DOM解析XML xml文件 favorite.xml <?xml version="1.0" encoding="UTF-8" standalone ...
- Java从零开始学三十二(正则表达式)
一.为什么要有正则 正则表达式可以方便的对数据进行匹配,可以执行更加复杂的字符串验证.拆份.替换功能. 例如:现在要求判断一个字符串是否由数字组成,则可以有以下的两种做法: 不使用正则完成 使用正则完 ...
- 从零开始学安全(十二)●建立自己的DNS服务器
我们的环境windows server 2012 虚拟机 打开服务器的添加角色和向导功能 添加DNF服务器安装 点击 在正向查找区域 反键新建区域 这里我一般输入一级域名 这是输入baidu.co ...
- 三分钟教你学Git(十二) 之 fast-forward
什么是fast forward, 顾名思义,就是高速向前进,Git怎么做到高速的呢? 原来假设Git判定能够fast forward的时候,直接改动当前HEAD指针的指向然后再改动当前HEAD指针.说 ...
- 从头学pytorch(十二):模型保存和加载
模型读取和存储 总结下来,就是几个函数 torch.load()/torch.save() 通过python的pickle完成序列化与反序列化.完成内存<-->磁盘转换. Module.s ...
- Mina、Netty、Twisted一起学(十):线程模型
要想开发一个高性能的TCP服务器,熟悉所使用框架的线程模型非常重要.MINA.Netty.Twisted本身都是高性能的网络框架,如果再搭配上高效率的代码,才能实现一个高大上的服务器.但是如果不了解它 ...
- 一步一步学android控件(之十六)—— CheckBox
根据使用场景不同,有时候使用系统默认的CheckBox样式就可以了,但是有时候就需要自定义CheckBox的样式.今天主要学习如何自定义CheckBox样式.在CheckBox状态改变时有时需要做一些 ...
随机推荐
- 用 Google 挖掘赚钱思路
为程序员,如果学了一堆技术却没有用武之地,实在可惜,如何把自己积累的技术利用起来?通俗一点,程序员有哪些赚钱的门路? 比较常见的一种方式是接私活,不过私活的复杂度不一,沟通成本会非常高,另一方面,私活 ...
- Random随机数种子生成,减少生成重复随机数的可能
我们都知道使用Random可以生成随机数,默认的无参的构造函数New Random().使用与时间相关的默认种子值,初始化 System.Random 类的新实例. 这种方式生成随机数时重复的概率很大 ...
- smarty模板基础知识
1.定义 Smarty是一个使用php写出来的模板引擎,它分离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与html代码混杂在一起PHP代码逻辑分离. 简单的讲,目的就是要使PH ...
- 【Android Developers Training】 33. 接收来自其它应用的简单数据
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- example001点击隐藏
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 1.如何安装matlab2016a
下载:见网盘 安装教程: 解压安装文件,安装文件为 iso 格式,但是不能通过虚拟光驱安装,需要将 iso 文件用解压软件解压.注意,R2016b_win64_dvd1.iso 和 R2016b_wi ...
- CSS 实现流布局以及多列混合布局
基本流布局 <!DOCTYPE html > <html> <head> <meta charset="utf-8"> <ti ...
- Linux进阶命令-sort、uniq、 cut、sed、grep、find、awk
命令难度总体来说有简入难,参数都是工作中常常用到的.如果涉及到一些生僻的参数还请百度或man一下. sort(参考学习网站:http://www.cnblogs.com/dong008259/arch ...
- AppDelegate减负之常用三方封装 - 友盟分享 / 三方登录篇
之前完成了 AppDelegate减负之常用三方封装 - 友盟推送篇: http://www.cnblogs.com/zhouxihi/p/7113511.html 今天接着来完成 - 友盟分享和三方 ...
- English - Green Peanut Butter
There is a guy. He wants to drink 12 cups of green peanut butter. He needs green peanut butter. So h ...