一步一步学Vue
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一步一步学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的主要内容,如果未能解决你的问题,请参考以下文章