一步一步学vue

author author     2022-09-14     485

关键词:

为了提升代码的逼格,之后代码改为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 &copy; 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 &copy; 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

本篇是是vue路由的开篇,会以一个简单的demo对vue-router进行一个介绍,主要覆盖以下几个常用场景:1、路由跳转2、嵌套路由3、路由参数 1、Vue-Router  一般来说,路由定义就是定义地址访问规则,然后由路由引擎根据这些... 查看详情

一步一步学vue

  前言:我以后在文章最后再也不说我下篇博文要写什么,之前说的大家也可以忽略,如果你不忽略,会失望的??,不过说出去的话还是要表示一下的,简单介绍一下路由钩子:  正如其名,vue-router 提供的导航钩子主要... 查看详情

一步一步学vue

本篇完成如下场景:1、系统包含首页、客户信息查询、登录三个模块2、默认进入系统首页,如果要进行用户查询,则需要进行登录授权3、查询用户后点击列表项,则进入详情页面基于上述场景需求描述,在客户端我们考虑,需... 查看详情

一步一步学vue

...不同,我们会对其进行增删改查的基本操作,之后进行进一步的完善,按照常规的系统使用经验,一般我们新增和编辑都是在模态框中处理,这里我们不会去构建复杂的模态框,只用一个简单的div层来代替,后期接下来的文章中... 查看详情

一步一步学rendermonkey

http://blog.csdn.net/tianhai110/article/details/5668832 转载请注明出处:http://blog.csdn.net/tianhai110/ 网上一些关于renderMonkey的教程:《RenderMonkey的基本使用方法》http://www.cnblogs.com/mixiyou/archive/2009/10/05/ 查看详情

一步一步学习vue

本篇继续学习vuex,还是以实例为主;我们以一步一步学Vue(四)中讲述的例子为基础,对其改造,基于vuex重构一遍,这是原始的代码:todolist.js;(function(){varlist=[];varTodo=(function(){varid=1;returnfunction(title,desc){this.title=title;this.desc=desc... 查看详情

一步一步学jvm-垃圾回收算法

标记-清除算法        算法分为标记和清除两个阶段:首先标记所有需要回收的对象,在标记完成后统一回收所有被标记的对象。        该算法存在的缺点:  1、 ... 查看详情

一步一步学nlp:熟悉nlp

NLP学习AI工程师必备的核心技能现实生活中的问题---->数学优化问题---->通过合适的工具解决whatisNLPNLP=NLP+NLUNLU:语音/文本->意思(meaning)Natural+langugeUnderstandingNLG:意思->文本/语音Natural+LangugeGenerationwhatis... 查看详情

一步一步学nlp:熟悉nlp

NLP学习AI工程师必备的核心技能现实生活中的问题---->数学优化问题---->通过合适的工具解决whatisNLPNLP=NLP+NLUNLU:语音/文本->意思(meaning)Natural+langugeUnderstandingNLG:意思->文本/语音Natural+LangugeGenerationwhatis... 查看详情

一步一步学多线程-synchronized

  当线程执行请求synchronized方法或块时,monitor会设置几个虚拟逻辑数据结构来管理这些多线程。      请求的线程会首先被加入到线程排队队列中,线程阻塞,当某个拥有线程锁的线程unlock之后,则排队队列里的线程... 查看详情

一步一步学jvm-垃圾回收

  垃圾回收器在对对象进行回收前,首先要判断对象是否还“活着”。判断方法有以下两种引用计数法        给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1。当引用失... 查看详情

一步一步学zookeeper-zookeeper初了解

角色        Zookeeper中的角色主要有以下三类        领导者(Leader)             查看详情

一步一步学jvm-运行时数据区域

程序计数器(ProgramCounterRegister)        像我们平时读书一样,当我们在去做别的事情之前,我们会对我们读到什么地方了做一个标记,方便我们再回来的时候接着重新读。如果这本书有很多人读呢... 查看详情

一步一步学jvm-垃圾回收器

Serial收集器        Serial收集器是最基本、历史最悠久的收集器。这个收集器是一个单线程的收集器。它在进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。Serial收集器是新生代的收... 查看详情

一步一步学java:入门的基础知识

​​ JAVA入门的基础知识学的再多,也要记得复习复习基础知识丫;​ 基本类型及其转换数字中有byte,short,char,int,long,float,double的类型*在使用过程中:要注意在float后面加上F,在long后面加L;longi=10L;floatm=56.345F;char后... 查看详情

一步一步学jvm-java内存模型

主内存与工作内存        Java内存模型的主要目标是定义程序中各个变量的访问规则。即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。这里的变量和Java编程中所说的变量有所区... 查看详情

linux一步一步学linux——dnsdomainname命令(174)(代码片段)

00.目录文章目录00.目录01.命令概述02.命令格式03.常用选项04.参考示例05.附录01.命令概述dnsdomainname命令用于定义DNS系统中FQDN名称中的域名。dnsdomainname=hostname-d02.命令格式用法:dnsdomainname[-v]03.常用选项--help 显示帮助文档--ve... 查看详情

一步一步学ef系列6ioc之autofac

前言     之前的前5篇作为EF方面的基础篇,后面我们将使用MVC+EF并且使用IOC,Repository,UnitOfWork,DbContext来整体来学习。因为后面要用到IOC,所以本篇先单独先学习一下IOC,我们本本文单独主要学习Autofac,其实... 查看详情