精华内容
下载资源
问答
  • 本文主要包括MVVM思想vue 简介安装node.js基本语法安装插件Vue 基础指令花括号、插值闪烁、v-text、v-htmlv-bindv-modelv-onv-forv-if、v-showv-else、v-else-if1.MVVM思想M:即Model,模型,包括数据一些基本操作v:...

    2e030687e75b2d59fd051426594f29b3.png

    本文主要包括

    1. MVVM思想

    2. vue 简介

    3. 安装node.js

    4. 基本语法

    5. 安装插件

    6. Vue 基础指令

    • 花括号、插值闪烁、v-text、v-html

    • v-bind

    • v-model

    • v-on

    • v-for

    • v-if、v-show

    • v-else、v-else-if

    1.MVVM思想

    c906ce6ac7ef893363ec1e0a7eeea867.png

    M:即Model,模型,包括数据和一些基本操作

    v:即View,视图,页面渲染结果

    VM:即View-Model,模型与视图间的双向操作(无需开发人员干涉)

    在MWM之前,开发人员从后端获取需要的数据模型,然后要通过DOM操作Model渲染到View中。而后当用户操作视图,我们还需要通过DOM获取View中的数据,然后同步到Model中。而MVVM中的VM要做的事情就是把DOM操作完全封装起来,开发人员不用再关心Model和View之间是如何互相影响的:
    • 只要我们Model发生了改变, View上自然就会表现出来。

    • 当用户修改了View, Model中的数据也会跟着改变。把开发人员从繁琐的DOM操作中解放出来,把关注点放在如何操作Model上。

    2.vue 简介

    官网:https://cn.vuejs.org/v2/guide/Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。3.安装nodeJs

    Nodejs英文网:https://nodejs.org/en/   

    Nodejs中文网:http://nodejs.cn/ 

    1)Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。2)Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。3)Node.js 的包管理器 npm,是全球最大的开源库生态系统。安装官方下载地址:http://nodejs.cn/download/

    90b8378555394737be7c879e8a712091.png

    也可以关注我的公众号,回复 nodeJs 获得安装包下载940ae9d0187104a8be2236d45a5222bb.png安装完成即可输入命令npm -v 查看版本c8f62ba971cacfb258d754930240a78d.png4.基本语法1)npm init -y 初始化目录结构

    227e42dde2e92ef97a6582c70ca755c4.png

    可以看到多了package.json 文件2)运行 npm install vue 安装vue

    e5cedc29f5ac9ada3d24bbb432ec8c11.png

    可以看到node_modules下就有vue 目录3)建立index.html 并引入vue.js
    <script src="./node_modules/vue/dist/vue.js" >script>
    4)建立div 并且建立Vue 对象,并通过el 元素选择器指定对应得id,通过data进行数据绑定
    <div id="app">        <h1> {{name}} , 你好h1>    div>    <script src="./node_modules/vue/dist/vue.js">script>    <script>        let vm = new Vue({            el: '#app',            data:{                name: "张三"            }        })script>
    5)在浏览器,修改值页面上会动态发生变化

    6df987215a05ae53f9beb391b58bd4ce.png

    5.安装插件1)为方便开发VScode 中安装 Vue 2 Snippets 语法提示插件

    8cb20b6a5e0526831b9eb3ee5ca45b99.png

    2)在chrome 浏览器Vue.js devtools ,关注公众号回复 vue插件 获取

    1589278db7105a96771a9e7f71fb70e1.png

    6.指令学习

    1、插值表达式

    1)、花括号

    格式:{{表达式}}说明:
    • 该表达式支持1s语法,可以调用i内置函数(必须有返回值)

    • 表达式必须有返回结果。例如1+1,没有结果的表达式不允许使用,如: leta=1+1;

    • 可以直接获取yue,实例中定义的数据或函数

    2)、插值闪烁·

    使用{{}}方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的{{}},加载完毕后才显示正确数据,我们称为插值闪烁。

    我们网速调慢一些,然后刷新页面,试试看刚才的案例:

    9e5d15095d4f993e1b52b9ef71e8fc71.png

    3)v-text 和v-html配合{{}} 渲染页面内容 ,只能写在标签体里面,要修改html标签属性要使用v-bind
    <div id="app">        {{msg}}  {{1+1}}  {{hello()}}<br/>        <span v-html="msg">span>        <br/>        <span v-text="msg">span>    div>    <script src="../node_modules/vue/dist/vue.js">script>    <script>        new Vue({            el:"#app",            data:{                msg:"

    Hello

    ", link:"http://www.baidu.com" }, methods:{ hello(){ return "World" } } })script>

    2.v-bind

    动态渲染,标签中属性的值,属于单向绑定页面修改不影响,data中的属性值

    1)如果isActive 为true class 就会添加active 样式class

    2)color1的值就是颜色的值

        <div id="app">         <a v-bind:href="link">gogogoa>                <span v-bind:class="{active:isActive,'text-danger':hasError}"          :style="{color: color1,fontSize: size}">你好span>    div>    <script src="../node_modules/vue/dist/vue.js">script>    <script>        let vm = new Vue({            el:"#app",            data:{                link: "http://www.baidu.com",                isActive:true,                hasError:true,                color1:'red',                size:'36px'            }        })script>

    3.v-model

    双向绑定data 的数据,会选中时修改data 中的language数组的值

            <div id="app">        精通的语言:            <input type="checkbox" v-model="language" value="Java"> java<br/>            <input type="checkbox" v-model="language" value="PHP"> PHP<br/>            <input type="checkbox" v-model="language" value="Python"> Python<br/>        选中了 {{language.join(",")}}    div>    <script src="../node_modules/vue/dist/vue.js">script>    <script>        let vm = new Vue({            el:"#app",            data:{                language: []            }        })script>

    4.v-on

    作用主要包括:事件修饰符、按键修饰符

    事件,可以绑定,点击等事件,通过@click.prevent.stop阻止默认行为,阻止事件冒泡

    按键修饰符,可以加载复杂的事件,比如通过@click.ctrl设置ctrl+鼠标单击

    <div id="app">                <button v-on:click="num++">点赞button>                <button @click="cancle">取消button>        <h1>有{{num}}个赞h1>                <div style="border: 1px solid red;padding: 20px;" v-on:click.once="hello">            大div            <div style="border: 1px solid blue;padding: 20px;" @click.stop="hello">                小div <br />                <a href="http://www.baidu.com" @click.prevent.stop="hello">去百度a>            div>        div>                <input type="text" v-model="num" v-on:keyup.up="num+=2" @keyup.down="num-=2" @click.ctrl="num=10"><br />        提示:    div>    <script src="../node_modules/vue/dist/vue.js">script>    <script>        new Vue({            el:"#app",            data:{                num: 1            },            methods:{                cancle(){                    this.num--;                },                hello(){                    alert("点击了")                }            }        })script>

    5.v-for

    循环遍历对象,

    通过"(user,index) in users"获取数组索引 通过:key="user.name"指定唯一值

    对象可以通过"(v,k,i) in user"获取key ,value 形式

    <div id="app">        <ul>            <li v-for="(user,index) in users" :key="user.name" v-if="user.gender == '女'">                               当前索引:{{index}} ==> {{user.name}}  ==>   {{user.gender}} ==>{{user.age}} <br>                                                对象信息:                <span v-for="(v,k,i) in user">{{k}}=={{v}}=={{i}};span>                            li>        ul>        <ul>            <li v-for="(num,index) in nums" :key="index">li>        ul>    div>    <script src="../node_modules/vue/dist/vue.js">script>    <script>                 let app = new Vue({            el: "#app",            data: {                users: [{ name: '柳岩', gender: '女', age: 21 },                { name: '张三', gender: '男', age: 18 },                { name: '范冰冰', gender: '女', age: 24 },                { name: '刘亦菲', gender: '女', age: 18 },                { name: '古力娜扎', gender: '女', age: 25 }],                nums: [1,2,3,4,4]            },        })script>

    6.v-if、v-show

    通过判断,展示或隐藏

    v-if 隐藏是直接整个dom 元素都没有了

    v-show 隐藏是通过style = display:none 隐藏了

        <div id="app">        <button v-on:click="show = !show">点我呀button>                <h1 v-if="show">if=看到我....h1>                <h1 v-show="show">show=看到我h1>    div>    <script src="../node_modules/vue/dist/vue.js">script>    <script>        let app = new Vue({            el: "#app",            data: {                show: true            }        })script>

    7.v-else、v-else-if

    条件判断,只要有一个符合,就不会继续往下走

     <div id="app">        <button v-on:click="random=Math.random()">点我呀button>        <span>{{random}}span>        <h1 v-if="random>=0.75">            看到我啦?! <= 0.75        h1>        <h1 v-else-if="random>=0.5">            看到我啦?! <= 0.5        h1>        <h1 v-else-if="random>=0.2">            看到我啦?! <= 0.2        h1>        <h1 v-else>            看到我啦?! > 0.2        h1>    div>    <script src="../node_modules/vue/dist/vue.js">script>            <script>                 let app = new Vue({            el: "#app",            data: { random: 1 }        })     script>

    -END-

    fcb35d3d8e530ea7bb6add45dfc9dd20.png

    ~

    bea4bfe5ca0ae11eb1cbba91692e3533.png
    展开全文
  • 新的一年新的开始github仓库地址 脚手架源码 ivue-cli 模板配置 webpack开始继续上一篇文章的讲解,让我们继续来看如何实现 init 功能。(如您想阅读上一篇内容可以点击这里)新建一个脚手架的配置文件scaffold-...

    新的一年新的开始

    github仓库地址

    脚手架源码 ivue-cli
    模板配置 webpack

    开始

    继续上一篇文章的讲解,让我们继续来看如何实现 init 功能。(如您想阅读上一篇内容可以点击这里)

    新建一个脚手架的配置文件scaffold-config-dev.json

    lib->scaffold->templates->scaffold-config-dev.json
    {
        "version": "0.1.0",
        "defaults": {
            "framework": "Vue",
            "template": "Basic"
        },
        "frameworks": [
            {
                "value": "Vue",
                "name": "Vue2",
                "subList": {
                    "template": [
                        {
                            "value": "Basic",
                            "name": "Basic",
                            "git": "https://github.com/lavas-project/lavas-template-vue.git",
                            "branch": "release-basic",
                            "desc": "基础模版,包含 Ivue Material Ui",
                            "locals": {
                                "zh_CN": {
                                    "desc": "基础模版,包含 Ivue Material Ui n包含额外配置选项 (默认包含 Babel)"
                                },
                                "en": {
                                    "desc": "Basic Template, contains Ivue Material Ui nIncludes additional configuration options (default Babel)"
                                }
                            }
                        },
                        {
                            "value": "Basic-MPA",
                            "name": "Basic-MPA",
                            "git": "https://github.com/lavas-project/lavas-template-vue.git",
                            "branch": "release-basic-mpa",
                            "desc": "多页面模版,包含 Ivue Material Ui 和 PWA 工程化相关必需内容",
                            "locals": {
                                "zh_CN": {
                                    "desc": "多页面模版,包含 Ivue Material Ui n(默认包含 Babel, Router,Sass)"
                                },
                                "en": {
                                    "desc": "Mpa Template, contains Ivue Material Ui n(default Babel,Router,Sass)"
                                }
                            }
                        },
                        {
                            "value": "PWA-SPA",
                            "name": "PWA-SPA",
                            "git": "https://github.com/lavas-project/lavas-template-vue.git",
                            "branch": "release-pwa-spa",
                            "desc": "PWA 单页面模版,包含 Ivue Material Ui 和 PWA 工程化相关必需内容",
                            "locals": {
                                "zh_CN": {
                                    "desc": "PWA 单页面模版,包含 Ivue Material Ui 和 PWA 工程化相关必需内容 n(默认包含 Babel,Router,Sass)"
                                },
                                "en": {
                                    "desc": "PWA Basic Template, contains Ivue Material Ui and PWA n(default Babel,Router,Sass)"
                                }
                            }
                        },
                        {
                            "value": "PWA-MPA",
                            "name": "PWA-MPA",
                            "git": "https://github.com/lavas-project/lavas-template-vue.git",
                            "branch": "release-pwa-mpa",
                            "desc": "PWA 多页面模版,包含 Ivue Material Ui 和 PWA 工程化相关必需内容",
                            "locals": {
                                "zh_CN": {
                                    "desc": "PWA 多页面模版,包含 Ivue Material Ui 和 PWA 工程化相关必需内容 n(默认包含 Babel,Router,Vuex,Sass)"
                                },
                                "en": {
                                    "desc": "PWA Mpa Template, contains Ivue Material Ui and PWA n(default Babel,Router,Vuex,Sass)"
                                }
                            }
                        }
                    ]
                }
            }
        ],
        "schema": {
            "framework": {
                "type": "list",
                "name": "前端框架",
                "description": "项目所选择的基础框架",
                "locals": {
                    "zh_CN": {
                        "name": "前端框架",
                        "description": "项目所选择的基础框架"
                    },
                    "en": {
                        "name": "framework",
                        "description": "The framework chosen for the project"
                    }
                },
                "required": true,
                "link": "frameworks",
                "default": "vue",
                "checkbox": false,
                "disable": true,
                "depLevel": 0,
                "list": [],
                "jsonType": "string"
            },
            "template": {
                "type": "list",
                "name": "模版类型",
                "description": "初始化项目时选中的模版类型",
                "locals": {
                    "zh_CN": {
                        "name": "模版类型",
                        "description": "初始化项目时选中的模版类型"
                    },
                    "en": {
                        "name": "template",
                        "description": "The type of template selected when initializing the project"
                    }
                },
                "dependence": "framework",
                "default": "Basic",
                "ref": "template",
                "depLevel": 1,
                "checkbox": false,
                "required": true,
                "list": [],
                "jsonType": "string"
            },
            "checkbox": {
                "type": "checkbox",
                "key": "checkbox",
                "name": "选择选项",
                "description": "检查项目所需的功能",
                "required": true,
                "checkbox": true,
                "list": [
                    {
                        "value": "router",
                        "name": "Router",
                        "checked": false
                    },
                    {
                        "value": "vuex",
                        "name": "Vuex",
                        "checked": false
                    },
                    {
                        "value": "css",
                        "name": "CSS Pre-processors",
                        "checked": false
                    },
                    {
                        "value": "typescript",
                        "name": "Typescript",
                        "checked": false
                    }
                ],
                "depLevel": 0,
                "jsonType": "string"
            },
            "csssProcessors": {
                "type": "list",
                "key": "csssProcessors",
                "name": "选择CSS预处理器",
                "description": "(支持PostCSS,Autoprefixer和CSS模块默认情况下)",
                "required": true,
                "checkbox": true,
                "list": [
                    {
                        "value": "scss",
                        "name": "Sass/SCSS"
                    },
                    {
                        "value": "less",
                        "name": "Less"
                    },
                    {
                        "value": "stylus",
                        "name": "Stylus"
                    }
                ],
                "depLevel": 0,
                "jsonType": "string"
            }
        }
    }

    创建 init 命令

    commander 下新建文件在该目录下管理主逻辑代码commander->scaffold->index.js
    'use strict';
    
    // init 安装脚手架命令
    const init = require('./action');
    // 提示文件
    const locals = require('../../locals')();
    
    module.exports = function (program) {
    
        // define init command
        program
            .command('init')
            .description(locals.INIT_DESC)
            .option('-f, --force', locals.INIT_OPTION_FORCE)
            .action(options => init({
                force: options.force
            }));
    };
    locals.js 文件中添加提示
    module.exports = {
      .....
      INIT_DESC: '初始化 ivue-cli 项目',
      INIT_OPTION_FORCE: '是否覆盖已有项目',
      .....
    };
    以上创建了 init 命令的运行

    init 命令的代码实现

    首先检查当前网络环境, 创建检查网络环境方法isNetworkConnectlib->utils->index.js
    const dns = require('dns');
    
    /**
     * 检测当前网络环境
     *
     * @return {Boolean} 是否联网
     */
    exports.isNetworkConnect = function () {
        return new Promise((reslove) => {
            dns.lookup('baidu.com', (err) => reslove(!(err && err.code === 'ENOTFOUND')));
        });
    }
    创建一个文件管理错误提示locals->zh_CN->index.js
    module.exports = {
        .....
        NETWORK_DISCONNECT: '创建工程需要下载云端模版',
        NETWORK_DISCONNECT_SUG: '请确认您的设备处于网络可访问的环境中',
        WELECOME: `欢迎使用`,
        GREETING_GUIDE: '开始新建一个项目',
        .....
    };
    新建 action.js用于init命令核心代码文件,同时引用 isNetworkConnect 检测网络commander->scaffold->action.js
    const utils = require('../../lib/utils')
    const log = require('../../lib/utils/log');
    const locals = require('../../locals')();
    
    module.exports = async function (conf) {
        // 检测当前网络环境
        let isNetWorkOk = await utils.isNetworkConnect();
    
        // 离线提示
        if (!isNetWorkOk) {
            log.error(locals.NETWORK_DISCONNECT);
            log.error(locals.NETWORK_DISCONNECT_SUG);
            return;
        }
    
        log.info(locals.WELECOME);
        log.info(locals.GREETING_GUIDE + 'n');
    
        .....
    }
    当没有网络时会输出以下内容:

    37cd8b0c013c466e514da8d3a2666403.png


    否则输出如下内容:

    33f1203986f7a95237eb5721607fbc99.png

    初始化过程的6个步骤

    现在开始让我们来看看初始化过程的初始化过程的6个步骤

    第一步:从云端配置获取 Meta 配置。确定将要下载的框架和模板 lish

    1.添加提示locals->zh_CN->index.js
    module.exports = {
        .....
        LOADING_FROM_CLOUD: '正在拉取云端数据,请稍候',
        .....
    };
    2.安装包
    // 下载中动画效果
    "ora": "^1.3.0"

    使用后效果如图:

    cc847ead5821ed6fc95364f27104211c.png
    3.引用下载配置的方法 getMetaSchema,下载完成后调用spinner.stop() 停止下载中效果commander->scaffold->action.js
    const scaffold = require('../../lib/scaffold');
    
        // 第一步:从云端配置获取 Meta 配置。确定将要下载的框架和模板 lish
        let spinner = ora(locals.LOADING_FROM_CLOUD + '...');
        spinner.start();
        let metaSchema = await scaffold.getMetaSchema();
        spinner.stop();
    4.getMetaSchema()方法实现, 新建一个store.js用于缓存数据lib/scaffold
    /**
     * @file 简单的 store
     */
    
    'use strict';
    
    const store = {};
    
    module.exports = {
        /**
         * setter
         *
         * @param {String} name store key
         * @param {Any} value store value
         */
        set (name, value) {
            store[name] = value;
        },
    
        /**
         * getter
         *
         * @param {String} name store key
         * @return {[type]} store value
         */
        get (name) {
            return store[name];
        }
    }
    设置公共配置,新建一个config.js
    /**
     * @file  scaffold 相关配置
     */
    'use strict';
    const jsonP = require('./templates/scaffold-config-dev.json');
    
    module.exports = {
        /**
         * 全局的配置文件地址
         *
         * @type {String}
         */
        GLOBAL_CONF_URL: {
            production: jsonP,
            development: jsonP
        },
    }
    获取meta配置,新建getMeta.js
    const store = require('./store');
    const conf = require('./config');
    
    // 如果是开发环境就使用开发环境的 CONF 数据,避免污染线上的 CONF 数据
    const confUrl = conf.GLOBAL_CONF_URL[
        process.env.NODE_ENV === 'development'
            ? 'development'
            : 'production'
    ];
    
    /**
     * 请求全局的配置 JOSN 数据
     *
     * @return {Object}   JSON 数据
     */
    module.exports = async function () {
        let data = store.get('data');
    
        // 如果 store 中已经存在了,2s 后再尝试更新下是不是有最新的数据
        if (data) {
            let timer = setTimeout(async () => {
                let json = await confUrl;
    
                store.set('data', json);
                clearTimeout(timer);
            }, 2000);
    
            return data;
        }
    
        // 如果 store 里面没有,我们马上就获取一份最新的数据
        data = await confUrl;
        store.set('data', data);
    
        return data;
    }
    以上新建了获取配置的方法接下来,在 lib/scaffold中新建文件schema.js,获取meta配置项
    const getMeta = require('./getMeta');
    
    /**
     * 获取元 Schema, 即模板选择的 Schema
     *
     * @return {Object} 元 Schema
     */
    exports.getMetaSchema = async function () {
        // 获取整个配置文件 scaffold-config-dev.json
        let meta = await getMeta();
        ....
    }
    我们还需要去获 scaffold-config-dev.json 中的 schema字段的内容所以我们需要 新建parseConfToSchema方法整理schema字段
    /**
     * 把约定的 JSON CONF 内容解析成可自动化处理的 schema
     *
     * @param {Object}  conf 按照约定格式的配置 json 文件
     * @return {Object} schema
     */
    function parseConfToSchema (conf = {}) {
    
        let properties = conf.schema || {};
    
        Object.keys(properties).forEach((key) => {
            let item = properties[key];
    
            if (item.type === 'list') {
                if (item.link && !item.dependence) {
                    properties[key].list = conf[item.link];
                }
                else if (item.dependence) {
                    properties[item.dependence].list.forEach((depItem) => {
                        if (depItem.value === conf.defaults[item.dependence]) {
                            properties[key].list = depItem.subList ?
                                (depItem.subList[key] || [])
                                : [];
                        }
                    });
                }
            }
        });
    
        return properties;
    }
    新建parseConfToSchema后,引用parseConfToSchema方法获取schema字段里的配置,并且把配置保存到store里面缓存起来减少请求次数
    /**
     * 获取元 Schema, 即模板选择的 Schema
     *
     * @return {Object} 元 Schema
     */
    exports.getMetaSchema = async function () {
        // 获取整个配置文件 scaffold-config-dev.json
        let meta = await getMeta();
    
        // 获取配置文件 scaffold-config-dev.json 的 schema
        let metaSchema = parseConfToSchema(meta);
    
        store.set('metaSchema', metaSchema);
    
        return metaSchema;
    }
    5.到这来我们已经完成了meta配置的获取了,然后我们需要把方法暴露给index.js进行代码管理index.js
    const store = require('./store');
    
    /**
     * 获取元 Schema - 涉及模版下载的 Schema
     *
     * @return {Promise<*>}   Meta Schema
     */
    exports.getMetaSchema = async function () {
        return store.get('metaSchema') || await Schema.getMetaSchema();
    }
    现在让我们运行init看看输出的内容
    // 第一步:从云端配置获取 Meta 配置。确定将要下载的框架和模板 lish
        let spinner = ora(locals.LOADING_FROM_CLOUD + '...');
        spinner.start();
        let metaSchema = await scaffold.getMetaSchema();
        spinner.stop();
    
        console.log(metaSchema)

    63dc42789de02213d3f9dada869764ca.png
    以上就是获取到的模板配置内容

    第二步:等待用户选择将要下载的框架和模板

    到了这一步是我们需要让用户选择哪个模板的时候了

    我们需要有一个表单让用户去选择commander->scaffold->action.js
    const formQ = require('./formQuestion');
    
        // 第二步:等待用户选择将要下载的框架和模板
        let metaParams = await formQ(metaSchema);
    添加提示locals->zh_CN->index.js
    module.exports = {
      .....
      INPUT_INVALID: '输入不符合规范',
      PLEASE_INPUT: '请输入',
      PLEASE_INPUT_NUM_DESC: '请选择一个数字指定',
      PLEASE_INPUT_NUM: '请输入数字',
      PLEASE_INPUT_RIGHR_NUM: '请输入正确的数字',
      PLEASE_SELECT: '请选择一个',
      PLEASE_SELECT_DESC: '按上下键选择',
      .....
    };
    安装需要的包
    // 将node.js现代化为当前ECMAScript规范
     "mz": "^2.7.0",
     // node fs 方法添加promise支持
     "fs-extra": "^4.0.1",
     // 常见的交互式命令行用户界面的集合
     "inquirer": "^6.2.0",
    1.首先新建formQuestion.js用于用户表单选择
    新建公共方法questionInputquestionYesOrNoquestionListquestionCheckboxPlusgetGitInfocommander->scaffold->formQuestion.js
    const exec = require('mz/child_process').exec;
    const fs = require('fs-extra');
    const os = require('os');
    const inquirer = require('inquirer');
    const path = require('path');
    
    const locals = require('../../locals')();
    const log = require('../../lib/utils/log');
    
    'use strict';
    
    /**
     * 获取当前用户的 git 账号信息
     *
     * @return {Promise} promise 对象
     */
    async function getGitInfo () {
        let author;
        let email;
    
        try {
            // 尝试从 git 配置中获取
            author = await exec('git config --get user.name');
            email = await exec('git config --get user.email');
        }
        catch (e) {
        }
    
        author = author && author[0] && author[0].toString().trim();
        email = email && email[0] && email[0].toString().trim();
    
        return { author, email };
    }
    
    /**
     * 询问 input 类型的参数
     *
     * @param  {string} key    参数的 key
     * @param  {Object} schema schema 内容
     * @param  {Object} params 当前已有的参数
     * @return {Object}        question 需要的参数
     */
    async function questionInput (key, schema, params) {
        let con = schema[key];
        let { name, invalidate } = con;
        let defaultVal = con.default;
        // 语言 locals - zh_CN
        let itemLocals = con.locals && con.locals[locals.LANG];
    
        if (itemLocals) {
            // locals - zh_CN - name
            name = itemLocals.name || name;
            // 模板类型
            defaultVal = itemLocals.default || defaultVal;
            invalidate = itemLocals.invalidate || invalidate;
        }
    
        con.validate = () => !!1;
    
        // 如果输入项是 author 或者 email 的,尝试去 git config 中拿默认内容
        if (key === 'author' || key === 'email') {
            let userInfo = await getGitInfo();
            defaultVal = userInfo[key] || con.default;
        }
    
        if (key === 'dirPath') {
            defaultVal = path.resolve(process.cwd(), con.default || '');
            con.validate = value => {
                let nowPath = path.resolve(process.cwd(), value || '');
    
                if (!fs.existsSync(nowPath)) {
                    return invalidate || locals.INPUT_INVALID;
                }
                else {
                }
    
                return true;
            }
        }
    
        // 匹配输入是否符合规范
        if (con.regExp) {
            let reg = new RegExp(con.regExp);
    
            con.validate = value => {
                if (!reg.test(value)) {
                    return invalidate || locals.INPUT_INVALID;
                }
                return true;
            }
        }
    
        return {
            // 密码
            'type': con.type === 'password' ? 'password' : 'input',
            'name': key,
            // 提示信息
            'message': `${locals.PLEASE_INPUT}${name}: `,
            // 默认值
            'default': defaultVal,
            // 验证
            'validate': con.validate
        }
    }
    
    /**
     * 询问 boolean 类型的参数
     *
     * @param  {string} key    参数的 key
     * @param  {Object} schema schema 内容
     * @param  {Object} params 当前已有的参数
     * @return {Object}        question 需要的参数
     */
    async function questionYesOrNo (key, schema, params) {
        let con = schema[key];
        // 名称
        let name = con.name;
        // 语言
        let itemLocals = con.locals && con.locals[locals.LANG];
    
        // 获取相应语言的提示
        if (itemLocals) {
            name = itemLocals.name || name;
        }
    
        return {
            'type': 'confirm',
            'name': key,
            'default': false,
            'message': `${name}? :`
        }
    }
    
    /**
     * 询问 list 类型的参数 (多选或者单选)
     *
     * @param  {string} key    参数的 key
     * @param  {Object} schema schema 内容
     * @param  {Object} params 当前已有的参数
     * @return {Object}        question 需要的参数
     */
    function questionList (key, schema, params) {
        let con = schema[key];
    
        // 来源列表
        let sourceLish = [];
        // 选择列表
        let choiceList = [];
        let text = '';
        let valueList = [];
        let listName = con.name;
        // 模板类型
        let listLocals = con.locals && con.locals[locals.LANG];
    
        // 获取相应语言的提示
        if (listLocals) {
            listName = listLocals.name;
        }
    
        // 依赖
        if (!con.dependence) {
            sourceLish = con.list;
        }
        // 层级
        else if (con.depLevel > 0) {
            // 表示是级联的操作
            let dependence = con.dependence;
            // 类型 template
            let ref = con.ref;
            let depList = schema[dependence].list;
            let depValue = params[dependence] || schema[dependence].list[0];
    
            depList.forEach((depItem) => {
                if (depItem.value === depValue) {
                    sourceLish = (depItem.subList && depItem.subList[ref]);
                }
            });
        }
    
        sourceLish.forEach((item, index) => {
            let url = '';
            let { desc, name } = item;
            let itemLocals = item.locals && item.locals[locals.LANG];
    
            // 相应语言的提示
            if (itemLocals) {
                desc = itemLocals.desc || desc;
                name = itemLocals.name || name;
            }
    
            desc = log.chalk.gray('n    ' + desc);
    
            choiceList.push({
                value: item.value,
                name: `${name}${desc}${url}`,
                short: item.value
            });
            valueList.push(item.value);
            text += ''
                + log.chalk.blue('n    [' + log.chalk.yellow(index + 1) + '] ' + name)
                + desc;
        });
    
        // 如果是 windows 下的 git bash 环境,由于没有交互 GUI,所以就采用文本输入的方式来解决
        if (os.platform() === 'win32' && process.env.ORIGINAL_PATH) {
            return {
                'type': 'input',
                'name': key,
                'message': locals.PLEASE_INPUT_NUM_DESC + ' ' + listName + ':' + text
                    + 'n' + log.chalk.green('?') + ' ' + locals.PLEASE_INPUT_NUM + ':',
                'default': 1,
                'valueList': valueList,
                // 验证
                'validate' () {
                    if (!/d+/.test(value) || +value > valueList.length || +value <= 0) {
                        return locals.PLEASE_INPUT_RIGHR_NUM;
                    }
                    return true;
                }
            };
        }
    
        return {
            'type': 'list',
            'name': key,
            'message': `${locals.PLEASE_SELECT}${listName} (${log.chalk.green(locals.PLEASE_SELECT_DESC)}):`,
            'choices': choiceList,
            'default': choiceList[0].value || '',
            'checked': !!con.checkbox,
            'pageSize': 1000
        }
    }
    
    
    /**
     * 询问 checkbox-plus 类型的参数 (多选或者单选)
     *
     * @param  {string} key    参数的 key
     * @param  {Object} schema schema 内容
     * @param  {Object} params 当前已有的参数
     * @return {Object}        question 需要的参数
     */
    function questionCheckboxPlus (key, schema, params) {
        let con = schema[key];
    
        // 来源列表
        let sourceLish = con.list;
        // 选择列表
        let choiceList = [];
    
        sourceLish.forEach((item, index) => {
            let { name } = item;
            let itemLocals = item.locals && item.locals[locals.LANG];
    
            if (itemLocals) {
                name = itemLocals.name || name;
            }
    
            choiceList.push({
                value: item.value,
                name: name,
    
                checked: item.checked
            });
    
        });
    
        return {
            'type': con.type,
            'name': key,
            'message': con.name,
            'choices': choiceList
        }
    }
    2.公共方法新建完成后,让我们开始编写表单代码commander->scaffold->formQuestion.js
    /**
     * 解析schme, 生成 form 表单
     *
     * @param  {Object} schema  传入的 schema 规则
     * @return {Object}         获取的 form 参数
     */
    module.exports = async function (schema) {
        let params = {};
    
        // 只有basic模板才可以进行配置定制
        if (schema.key) {
            let opts = {};
            let data = {};
    
            // 配置选择,复选框
            opts = await questionCheckboxPlus(schema.key,
                {
                    [schema.key]: schema
                }, params);
    
            // 输出选择的配置
            data = await inquirer.prompt([opts]).then(function (answers) {
                return {
                    [schema.key]: answers[schema.key]
                };
            });
    
            params = Object.assign({}, params, data);
    
            return params
        }
        else {
            for (let key of Object.keys(schema)) {
                let con = schema[key];
                let type = con.type;
                let opts = {};
                let data = {};
    
                switch (type) {
                    case 'string':
                    case 'number':
                    case 'password':
                        // 输入密码
                        opts = await questionInput(key, schema, params);
                        break;
                    case 'boolean':
                        // 确认
                        opts = await questionYesOrNo(key, schema, params);
                        break;
                    case 'list':
                        // 列表
                        opts = await questionList(key, schema, params);
                        break;
                }
    
                // 如果 list 只有一个 item 的时候,就不需要用户选择了,直接给定当前的值就行
                if (type === 'list' && con.list.length === 1) {
                    data[key] = con.list[0].value;
                }
                else if (!con.disable && !con.key) {
                    data = await inquirer.prompt([opts]);
                    if (opts.valueList) {
                        data[key] = opts.valueList[+data[key] - 1];
                    }
                }
    
                params = Object.assign({}, params, data);
    
            }
        }
    
        return params;
    };
    由于我们可以对Basic模板进行配置的定制所以现在需要修改commander->scaffold->action.js里面的代码
    const formQ = require('./formQuestion');
    
        // 第二步:等待用户选择将要下载的框架和模板
        let metaParams = await formQ(metaSchema);
    
        let checkboxParams;
        let cssParams;
        // 只有基础模板才可以自定义选项
        if (metaParams.template === 'Basic') {
    
            // 获取用户选择的参数
            checkboxParams = await formQ(metaSchema.checkbox);
    
            // 是否选择了css
            if (checkboxParams.checkbox.indexOf('css') > -1) {
                cssParams = await formQ(metaSchema.csssProcessors);
            }
        }
    修改后如上
    到了这里再让我们运行init看看输出的是什么

    4992026bcba0578ec0ba4b7f750006a0.png


    选择basic模板后返回可配置的选项

    a62190f091d68372a1cc143372e40fe9.png

    第三步:通过用户选择的框架和模板,下载模板

    这一步是让脚手架去下载用户选择的模板
    添加提示locals->zh_CN->index.js
    module.exports = {
        ......
        META_TEMPLATE_ERROR: '获取模版 Meta 信息出错',
        DOWNLOAD_TEMPLATE_ERROR: '下载模版出错,请检查当前网络',
        ......
    };
    安装需要的包
    "lodash": "^4.17.4",
    "ajv": "^5.1.3",
    "axios": "^0.17.1"
    "compressing": "^1.3.1"
    1.新建download方法,返回模板的 Schema 信息lib->scaffold->index.js
    /**
     * 通过指定的 meta 参数下载模版,下载成功后返回模板的 Schema 信息
     *
     * @param {Object} metaParams 导出参数
     * @return {*} 下载的临时路径 或者 报错对象
     */
    exports.download = async function (metaParams = {}) {
    
    }
    2.新建导出所有文件路径的方法extendsDefaultFields去导出所有的文件lib->scaffold->index.js
    const store = require('./store');
    const Schema = require('./schema');
    
    const path = require('path');
    const _ = require('lodash');
    
    /**
     * 获取导出的所有的 fields (包含 default 参数)
     *
     * @param  {Object} fields  传入的 fields
     * @param  {Obejct} templateConf    模版的配置
     * @return {Object}         输出的 fields
     */
    async function extendsDefaultFields (fields = {}, templateConf = {}) {
        let defaultFields = {};
        let schema = store.get('schema') || await Schema.getSchema(templateConf)
    
        Object.keys(schema).forEach((key) => (defaultFields[key] = schema[key].default))
    
        /* eslint-disable fecs-use-computed-property */
        // defaultFields.name = fields.name || 'ivue-cli'
        defaultFields.name = fields.name || 'ivue-cli';
    
        defaultFields.dirPath = path.resolve(process.cwd(), fields.dirPath || '', defaultFields.name);
    
        return _.merge({}, defaultFields, fields);
    }
    3.然后我们在schema.js中增加getSchema方法用于生成用户输入的表单lib->scaffold->schema.js
    /**
     * 获取 Schema, 用于生成用户输入的表单
     *
     * @param {Object} templateConf 每个模版的 config
     * @return {Object} 返回的 JSON Schema
     */
    exports.getSchema = function (templateConf = {}) {
        return parseConfToSchema(templateConf);
    }
    4.然后回到lib->scaffold->index.js文件创建download方法下载成功后返回模板的 schema字段的信息lib->scaffold->index.js
    /**
     * 通过指定的 meta 参数下载模版,下载成功后返回模板的 Schema 信息
     *
     * @param {Object} metaParams 导出参数
     * @return {*} 下载的临时路径 或者 报错对象
     */
    exports.download = async function (metaParams = {}) {
       // 输出导出路径相关配置
        metaParams = await extendsDefaultFields(metaParams);
    }
    到了这里我们看看metaParams输出的是什么
    以下输出包含了我们需要在哪里创建文件的路径,和模板名称、类型

    461e3f85915b6cbb019adebe2917b878.png
    5.接下来我们去创建真正的 download 方法下载一个指定的模版
    新建文件lib->scaffold->template.js,创建下载指定的模版方法lib->scaffold->template.js
    /**
     * 下载一个指定的模版
     *
     * @param  {Object} metaParams  导出模版所需字段, 从 mataSchema 中得出
     * @return {Objecy}             导出的结果
     */
    exports.download = async function (metaParams = {}) {
    
    }
    先来获取模板的信息,创建getTemplateInfo方法获取模版信息lib->scaffold->template.js
    const getMeta = require('./getMeta');
    const store = require('./store');
    
    /**
     * 获取模版信息
     *
     * @param  {Object} metaParam 元参数
     * @return {Object} framework 和 template 信息
     */
    async function getTemplateInfo (metaParam) {
        try {
            // 获取全部配置
            let meta = await getMeta();
            let frameworkValue = metaParam.framework || meta.defaults.framework || 'vue';
            let templateValue = metaParam.template || meta.defaults.template || 'template'
    
            // 对应的模板信息
            let framework = meta.frameworks.filter(item => item.value === frameworkValue)[0];
            // 仓库地址等信息
            let template = framework.subList.template.filter(item => item.value === templateValue)[0];
            // 版本号
            let version = meta.version;
    
    
            store.set('framework', framework);
            store.set('template', template);
            store.set('version', version);
    
            return {
                framework,
                template,
                version
            };
        }
        catch (e) {
            // 如果这一步出错了,只能说明是 BOS 上的 Meta 配置格式错误。。
            throw new Error(locals.META_TEMPLATE_ERROR);
        }
    }
    回到download方法中添加getTemplateInfo方法输出模板详细信息lib->scaffold->template.js
    /**
     * 下载一个指定的模版
     *
     * @param  {Object} metaParams  导出模版所需字段, 从 mataSchema 中得出
     * @return {Objecy}             导出的结果
     */
    exports.download = async function (metaParams = {}) {
        let { framework, template, version } = await getTemplateInfo(metaParams);
    }
    接下来我们来看看getTemplateInfo方法输出的信息:
    输出包含了模板的仓库地址,描述,等信息

    c4f11eaa2f1697e8553e33fed1f92037.png
    6.设置从云端下载到本地的路径
    download方法中添加如下代码lib->scaffold->template.js
    const conf = require('./config');
    const path = require('path');
    
    /**
     * 下载一个指定的模版
     *
     * @param  {Object} metaParams  导出模版所需字段, 从 mataSchema 中得出
     * @return {Objecy}             导出的结果
     */
    exports.download = async function (metaParams = {}) {
        let { framework, template, version } = await getTemplateInfo(metaParams);
    
        // 下载到本地的路径
        let storeDir = path.resolve(
            conf.LOCAL_TEMPLATES_DIR,
            framework.value, template.value + '_' + version
        )
    }
    其中conf.LOCAL_TEMPLATES_DIR 为本地模版存放路径lib->scaffold->config.js
    const path = require('path');
    const utils = require('../utils');
    
    module.exports = {
        /**
         * 本地模版存放路径
         *
         * @type {String}
         */
        LOCAL_TEMPLATES_DIR: path.resolve(utils.getHome(), 'tmp'),
        .....
    }
    utils.getHome() 为获取云端仓库的跟目录lib->utils->index.js
    const os = require('os');
    const path = require('path');
    const fs = require('fs-extra');
    
    /**
     * 获取项目根目录
     *
     * @return {string} 目录 Path
     */
    exports.getHome = function () {
        let dir = process.env[
            os.platform() === 'win32'
                ? 'APPDATA'
                : 'HOME'
        ] + path.sep + '.ivue-project'
    
        // 如果这个目录不存在,则创建这个目录
        !fs.existsSync(dir) && fs.mkdirSync(dir);
    
        return dir;
    };
    7.接下来我们需要去验证用户的输入是否与配置中的验证规则相匹配
    schema.js 中添加getMetaJsonSchema方法lib->scaffold->schema.js
    /**
     * 获取 meta JSON Schema, 用于验证 json 表单
     *
     * @return {Object} 返回的 JSON Schema
     */
    exports.getMetaJsonSchema = async function () {
        let meta = await getMeta();
        let metaSchema = parseConfToSchema(meta);
    
        store.set('metaSchema', metaSchema);
    
        return metaSchema;
    }
    回到download方法中添加验证用户输入lib->scaffold->template.js
    /**
     * 下载一个指定的模版
     *
     * @param  {Object} metaParams  导出模版所需字段, 从 mataSchema 中得出
     * @return {Objecy}             导出的结果
     */
    exports.download = async function (metaParams = {}) {
        let { framework, template, version } = await getTemplateInfo(metaParams);
    
        let storeDir = path.resolve(
            conf.LOCAL_TEMPLATES_DIR,
            framework.value, template.value + '_' + version
        )
    
        // 验证是否是json字符串
        let ajv = new Ajv({ allErrors: true });
        let metaJsonSchema = store.get('metaJsonSchema') || await schema.getMetaJsonSchema();
    
        // 验证用户输入
        let validate = ajv.compile(metaJsonSchema);
        let valid = validate(metaParams);
    
        if (!valid) {
            throw new Error(JSON.stringify(validate.errors));
        }
    }
    8.验证通过后我们开始从服务器上拉取模板
    新增downloadTemplateFromCloud方法用于下载模板,从服务器上拉取模版lib->scaffold->template.js
    /**
     * 通过指定框架名和模版名从服务器上拉取模版(要求在模版 relase 的时候注意上传的 CDN 路径)
     *
     * @param {string} framework 框架名称
     * @param {string} template 模版名称
     * @param {string} targetPath 模版下载后存放路径
     */
    
    async function downloadTemplateFromCloud (framework, template, targetPath) {
        const outputFilename = path.resolve(targetPath, 'template.zip');
    
        // existsSync:  如果路径存在,则返回 true,否则返回 false。
        // removeSync 删除文件、目录
        fs.existsSync(targetPath) && fs.removeSync(targetPath);
        // 确保目录存在。如果目录结构不存在,则创建它
        fs.mkdirsSync(targetPath);
    
        framework = (framework || 'vue').toLowerCase();
        template = (template || 'basic').toLowerCase().replace(/s/, '-');
    
        try {
            // 请求模板
            let result = await axios.request({
                responseType: 'arraybuffer',
                url: 'https://codeload.github.com/qq282126990/webpack/zip/release-' + template,
                method: 'get',
                headers: {
                    'Content-Type': 'application/zip'
                }
            });
    
            fs.writeFileSync(outputFilename, result.data);
    
            // 解压缩是反响过程,接口都统一为 uncompress
            await compressing.zip.uncompress(outputFilename, targetPath);
            fs.removeSync(outputFilename);
        }
        catch (e) {
            throw new Error(locals.DOWNLOAD_TEMPLATE_ERROR);
        }
    回到download方法,添加方法downloadTemplateFromCloud通过指定框架名和模版名从服务器上拉取模版,模板内容将下载到storeDir路径下lib->scaffold->template.js
    ......
    //  通过指定框架名和模版名从服务器上拉取模版
    await downloadTemplateFromCloud(framework.value, template.value, storeDir);
    .....
    下载后如图:

    c1a117bc5bdd5654e3dc34a700bc16e5.png
    9.接下来我们去获取模板下载后的meta.json文件download方法中添加代码,获取文件夹名称以及下载后的meta.json的内容lib->scaffold->template.js
    ......
    // 获取文件夹名称
    const files = fs.readdirSync(storeDir);
    
    store.set('storeDir', `${storeDir}/${files}`);
    
    let templateConfigContent = fs.readFileSync(path.resolve(`${storeDir}/${files}`, 'meta.json'), 'utf-8');
    
    let templateConfig = JSON.parse(templateConfigContent);
    
    store.set('templateConfig', templateConfig);
    
    return templateConfig;
    ......
    10.然后我们需要吧代码统一管理到index.jslib->scaffold->index.js
    const template = require('./template');
    
    /**
     * 通过指定的 meta 参数下载模版,下载成功后返回模板的 Schema 信息
     *
     * @param {Object} metaParams 导出参数
     * @return {*} 下载的临时路径 或者 报错对象
     */
    exports.download = async function (metaParams = {}) {
        metaParams = await extendsDefaultFields(metaParams);
    
        return await template.download(metaParams);
    }
    11.最后我们导出download方法
    新增通过用户选择的框架和模板,下载模板的代码commander->scaffold->action.js
    // 第三步:通过用户选择的框架和模板,下载模板
    spinner.start();
    let templateConf = await scaffold.download(metaParams, checkboxParams);
    spinner.stop();
    12.由于我们可以对基础模本进行自定义选项所以还需要增加以下代码来下载对应的选项配置
    新增包
    // ETPL是一个强复用,灵活,高性能的JavaScript的模板引擎,适用于浏览器端或节点环境中视图的生成
    "etpl": "^3.2.0"
    lib->scaffold->index.js中新增方法setMainJs设置webpack模板的main.js文件,setCheckboxParams通过指定的参数渲染下载成功的模板,setCssParams配置css
    由于customize文件夹内容过多此处不进行展示,详情可以查看这里lib->scaffold->index.js
    const etpl = require('etpl');
    const fs = require('fs-extra');
    const path = require('path');
    
    // 设置router 配置
    const routerConfig = require('../../../../customize/router');
    // 设置 vuex 配置
    const vuexConfig = require('../../../../customize/vuex');
    // 设置 typescriptConfig 配置
    const typescriptConfig = require('../../../../customize/typescript');
    
    /**
     * main.js
     *
     * @param {String} storeDir 文件根目录
     * @param {String} currentDir 当前文件目录
     * @param {Function} etplCompile 字符串转换
     * @param {Array} params 需要设置的参数
     */
    function setMainJs (storeDir, currentDir, etplCompile, params) {
    
        // 模块
        let nodeModules = '';
        // 路径列表
        let urls = '';
        // 配置
        let configs = '';
        // 名字列表
        let names = '';
    
    
        params.forEach((key) => {
            // 插入路由配置
            if (key === 'router') {
                nodeModules += `${nodeModules.length === 0 ? '' : 'n'}import VueRouter from 'vue-router'${nodeModules.length === 0 ? 'n' : ''}`;
    
                urls += `${urls.length === 0 ? '' : 'n'}import router from './router'`;
    
                configs += `nVue.use(VueRouter)`;
    
                names += `${names.length === 0 ? '' : 'n'}    router,`;
            }
    
            // 插入vuex配置
            if (key === 'vuex') {
                urls += `${urls.length === 0 ? '' : 'n'}import store from './store'`;
    
                names += `${names.length === 0 ? '' : 'n'}    store,`;
            }
        });
    
        // main.js
        let mainJs =
            `import Vue from 'vue'
    ${nodeModules}
    import App from './App.vue'
    ${urls}${urls.length > 0 ? 'n' : ''}
    import IvueMaterial from 'ivue-material'
    import 'ivue-material/dist/styles/ivue.css'
    ${configs}
    Vue.use(IvueMaterial)
    
    Vue.config.productionTip = false
    
    new Vue({
    ${names}${names.length > 0 ? 'n' : ''}    render: h => h(App),
    }).$mount('#app')
    `;
    
        mainJs = etplCompile.compile(mainJs)();
    
        let name
        if (params.indexOf('typescript') > -1) {
            name = 'main.ts';
        }
        else {
            name = 'main.js';
        }
    
        // 重新写入文件
        fs.writeFileSync(path.resolve(`${storeDir}/src`, name), mainJs);
    }
    
    /**
     * 通过指定的参数渲染下载成功的模板
     *
     * @param {Array} params 需要设置的参数
     */
    exports.setCheckboxParams = async function (params = []) {
        const storeDir = store.get('storeDir');
        const templateConfig = store.get('templateConfig');
        const etplCompile = new etpl.Engine(templateConfig.etpl);
        const currentDir = './packages/customize/router/code'
    
        params.forEach((key) => {
            // 插入路由配置
            if (key === 'router') {
                routerConfig.setFile(storeDir, etplCompile,params);
            }
    
            // 插入 vuex 配置
            if (key === 'vuex') {
                vuexConfig.setFile(storeDir, etplCompile, params);
            }
    
            // 插入 typescript 配置
            if (key === 'typescript') {
                typescriptConfig.setFile(storeDir, etplCompile);
            }
        });
    
        // 修改 main.js
        setMainJs(storeDir, currentDir, etplCompile, params);
    
        // 设置 shims-vue.d.ts
        if (params.indexOf('typescript') > -1) {
            setShimsVueDTs(storeDir, currentDir, etplCompile, params);
        }
    }
    
    
    /**
     * 配置css参数
     *
     * @param {Array} params 需要设置的参数
     */
    exports.setCssParams = async function (params = '') {
        const storeDir = store.get('storeDir');
        const templateConfig = store.get('templateConfig');
        const etplCompile = new etpl.Engine(templateConfig.etpl);
    
        let nodeModules = {};
    
        // scss
        if (params === 'scss') {
            nodeModules = {
                'node-sass': '^4.12.0',
                'sass-loader': '^7.2.0'
            };
        }
        // less
        else if (params === 'less') {
            nodeModules = {
                'less': '^3.0.4',
                'less-loader': '^7.2.0'
            };
        }
        // stylus
        else if (params === 'stylus') {
            nodeModules = {
                'stylus': '^0.54.5',
                'stylus-loader': '^3.0.2'
            };
        }
    
        // 设置css版本号
        setCssPackConfig(storeDir, etplCompile, nodeModules);
    }
    最后在 commander->scaffold->action.js 中添加如下代码设置用户选择的参数:commander->scaffold->action.js
    module.exports = async function (conf) {
        ......
        // 设置用户选择的参数
        // 只有基础模板才可以自定义选项
        if (metaParams.template === 'Basic') {
            await scaffold.setCheckboxParams(checkboxParams.checkbox);
    
            // 是否选择了css
            if (cssParams) {
                await scaffold.setCssParams(cssParams.csssProcessors);
            }
        }
        ......
    }

    第四步:根据下载的模板的 meta.json 获取当前模板所需要用户输入的字段 schema

    模板下载完成后我们需要用户对模板的字段进行设置,如设置作者名称、作者邮箱、项目描述、项目名称。所以我们需要获取模板中的meta.json 文件。知道那些字段是需要用户去设置的。1.新增getSchema方法,获取meta.json配置lib->scaffold->index.js
    /**
     * 获取 Schema - 涉及模版渲染的 Schema
     *
     * @param {Object} templateConf 模版自己的配置
     * @return {Promise<*>}   Schema
     */
    exports.getSchema = async function (templateConf = {}) {
        if (!templateConf) {
            // 如果实在没有提前下载模板,就现用默认的参数下载一个
            templateConf = await Schema.download();
        }
        return Schema.getSchema(templateConf);
    }
    2.然后在 commander->scaffold->action.js 添加一下代码,输出获取到的配置commander->scaffold->action.js
    module.exports = async function (conf) {
        ......
        // 第四步:根据下载的模板的 meta.json 获取当前模板所需要用户输入的字段 schema
        let schema = await scaffold.getSchema(templateConf);
        ......
    }

    第五步:等待用户输入 schema 所预设的字段信息

    到了这里我们需要用上一步的配置去让用户进行输入commander->scaffold->action.js
    // 第五步:等待用户输入 schema 所预设的字段信息
    let params = await formQ(schema);
    我们再次运行init看看输出的是什么

    e631bb70f6b3d8f27d60f4e65ee92c59.png


    如上输出使用户可以自定义自己的package.json
    输入完成后如图:

    9434b72a24b03037c6b5c1e4098a84f5.png
    由于字数过多,最后一步,请看下一章
    如有错误欢迎提出 issues 或者 star

    最后

    新的一年也要加油呀

    d800e350b2fce7b09d77db0964473a48.png
    展开全文
  • "title"标题示例代码:data = [ { title: '新日小卫士二代', }, { title: '车子质量合格', }, { title: '我买的骑士1号仪表台进水怎么回事?', }, { title: '风雅欧妮大灯高低调节', }]"title"标题"desc"描述...

    "title"标题

    ed7543ed78ea851111be781bebe7c877.png

    示例代码:

    data = [  {    title: '新日小卫士二代',  },  {    title: '车子质量不合格',  },  {    title: '我买的骑士1号仪表台进水怎么回事?',  },  {    title: '风雅欧妮大灯高低调节',  }]

    "title"标题和"desc"描述

    2e5468e75e277688a962a7e23f5fef85.png

    示例代码:

    data= [  {    title: '新日小卫士二代',    desc: '京东购新日小卫士二代一辆,收货后就发现后轮毂变形!公司厂承诺全图联保,官网查得邯郸市有很多保修点,实际一个都不存在!'  },  {    title: '车子质量不合格',    desc: '刚买的电车,发现车把有些不对称,店家车子装上电瓶就想给换,找个维修师傅简单调了下,今天家人骑车发现车把还是有些斜!车子不合格怎能出厂出售?以后不'  },  {    title: '我买的骑士1号仪表台进水怎么回事?',    desc: '刚买的骑士1号,在外面淋了一会雨,发现里面进水了,第二天打电话给销售商,回复说正常,没关系。我觉得这算正常吗?再普通的电动车仪表台也不会进水。'  },  {    title: '风雅欧妮大灯高低调节',    desc: '哪位大神能不能告诉一下风雅欧妮大灯怎么调节'  }]

    "disable" 禁用

    a96cf8be5a17ec7cc942806adeddf037.png

    示例代码:

    data = [  {    title: '新日小卫士二代',    disable: true  },  {    title: '车子质量不合格',    disable: true  },  {    title: '我买的骑士1号仪表台进水怎么回事?',  },  {    title: '风雅欧妮大灯高低调节',  }]

    "reverse" 反向

    d77d9b40c637a8f3b1e2d410642552d7.png

    示例代码:

    data = [  {    title: '新日小卫士二代',    disable: true  },  {    title: '车子质量不合格',    disable: true  },  {    title: '我买的骑士1号仪表台进水怎么回事?',  },  {    title: '风雅欧妮大灯高低调节',  }]

    "selectedColor" 自定义选中颜色

    5b0dc0c197789a3b14027044606d08c2.png

    示例代码:

    data =[  {    title: '新日小卫士二代',  },  {    title: '车子质量不合格',  },  {    title: '我买的骑士1号仪表台进水怎么回事?',  },  {    title: '风雅欧妮大灯高低调节',  }]

    "selected" 默认选中

    9f6f395664d83088c10b260916b80833.png

    示例代码:

    data =[  {    title: '新日小卫士二代',    selected: true  },  {    title: '车子质量不合格',    selected: true  },  {    title: '我买的骑士1号仪表台进水怎么回事?',  },  {    title: '风雅欧妮大灯高低调节',  }]

    Checkbox组件接收props参数:

    dataSource: { (类型 Array)

    设置数据源

    reverse: { (类型 Boolean)

    默认值 false

    布局是否反向

    selectedColor: { (类型 String)

    默认值 "#1bb5f1"

    设置选中颜色

    change事件:

    点击时触发

    返回已选中的数据

    具体的Checkbox组件源码,请前往github地址获取。

    https://github.com/AntJavascript/WidgetUI3.0/blob/master/Checkbox.vue

    展开全文
  • 具体网上百度了,看一下v-showv-if的区别吧 猜测:由于el-table-column会生成多行标签元素,根据v-show是支持template语法的,推断v-show能显示隐藏多个元素 转载于:https://www.cnblogs.c...

     

     

    记录一下自己踩的坑,控制element内的table的某列显示隐藏不能用v-show,而是要用v-if

    具体网上百度了,看一下v-show和v-if的区别吧

    猜测由于el-table-column会生成多行标签元素,根据v-show是不支持template语法的,推断v-show不能显示隐藏多个元素

     

    转载于:https://www.cnblogs.com/chr506029589/p/11121607.html

    展开全文
  • 等,现在流行Vue,React , Anagular 三大框架,下面看看怎么使用Vue实现实现逻辑产品经理的评审功能需求如下 根据大分类到子分类层级选择,无层级限制(根据UI的横板宽度,适合做多级,但深度很深的场景并多)...
  • jq,vue动态选中checkbox和radio

    千次阅读 2019-04-11 13:49:04
    之前遇到了一个checkbox和radio选中的问题,有一个好用jq控制选中,但是具体出现的问题忘记了,先存个档,以后再补充 html: <!DOCTYPE html> <html> <head> <meta charset="utf-8" />...
  • 多选框时,却只需要点击其中一个就让其他的选项失效,其实也是可以使用单选框来做,但是设计图的图标是多选框长得一模一样,又想去修改ant-vue单选框的样式,于是就做了这个demo html部分 <a-checkbox-group v-...
  • "title"标题示例代码:data = [ { title: '新日小卫士二代', }, { title: '车子质量合格', }, { title: '我买的骑士1号仪表台进水怎么回事?', }, { title: '风雅欧妮大灯高低调节', }]"title"标题"desc"描述...
  • 前言关于checkbox多选框是再常见不过的了,几乎很多地方都会用到,这两天在使用vue框架时需要用到checkbox多选功能,实在着实让我头疼,vue和原生checkbox用法太一样,之前对于vue中用到过的checkbox也只是别人写...
  • 注意:此处的checkbox是用原生的input 标签,并是<el-checobox>标签, 如果使用el标签,只有change事件,没有click事件,能传参 $event ,所以就无法获取到是否选中的状态,后续会有很多问题。所以建议...
  • 前言关于checkbox多选框是再常见不过的了,几乎很多地方都会用到,这两天在使用vue框架时需要用到checkbox多选功能,实在着实让我头疼,vue和原生checkbox用法太一样,之前对于vue中用到过的checkbox也只是别人写...
  • 显示解决方法:设置属性 transfer="true"解决问题 选中问题解决方法: 循环的时候key不要用index
  • vue.js选中动态绑定的radio的指定项上一文,介绍了vue.js动态添加、删除绑定的radio选项,本文介绍如何选中radio的某一项绑定的数据上文的model是一致的,选中radio或者checkbox需要注意的是:不管你的checked属性...
  • 前几天有人说这个好像不行,当时是直接从项目分离,没有后台好像你们都运行了。算了,重新整理一下。代码只是把它变为demo了,因为没有后台分页就算了,只要记住一点v-model相当于一个数组,它会帮你存储数组,...
  • 轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb简单易学:国人开发,中文文档,存在语言障碍 ,易于理解学习;虚拟DOM:dom操作是非常耗费性能的, 不再使用原生的dom操作节点,极大解放...
  • 我要实现的就是当选中第一个checkbox后,第二个会checkbox自动勾选,然后第二个勾选影响第一个,只有第一个checkbox会影响第二个checkbox。并把值返回给后端 如图所示: ![图片说明]...
  • 因为要学做项目了,写博客的记录已经赶上课程的学习进度,记录知识在博客真的是一个耗费时间精力的事情啊,这其中还要查资料、弄懂知识点,而且也到了再一次梳理知识集中问老师的时候。赶着时间学习,会有一种赶...
  • 本文啰嗦css布局内容。主要描述双向绑定数据的获取。第一步:看静态页面最终效果图HTML结构布局。图一说明:点击灰色背景区域的父级地址名称,紧邻的下方白色背景的子集订单被选中。点击全选按钮所有...
  • vue有很多现成的UI框架,博主的手机端用的是mintUI,但是mintUI样式能整改为想要的样子,因此纯手工封装了一个checkBox组件(纯css实现效果,需要一样的可自制样式) 先来一个效果图: 二、正文 1、说明 ...
  • 1.前端使用el-tree中checkbox全选反选的功能实现时,setCheckedKeys置为空数组时,还存在选中的数据没有进行清空. this.$refs.tree.setCheckedKeys([]) 还是不行 2.换成setChecked setChecked怎么使用的呢具体可以...
  • 选中不选中,不是看checked的属性值,而是看有没有checked这个属性,所以,动态选中,不用v-model,也不用checked=’true’,判断是否需要渲染checked这个属性就好了. view 改一下: "<input type='radio' :nam
  • 今天有个朋友说要做个效果:Vue实现拖拽排序,要有 checked,输出结果是排序后的,要全选,未选中能拖动。 其实我之前基于 Sortable 做过一个类似的效果。也给他看过了,没看太明白,他就自己基于 vuedraggable ...
  • vue+element-ui使用CheckBox总结 在vue中如下布局 在vue+element-ui下,支持 v-model数据双向绑定,收费列表头是循环出来的 v-model 绑定数据出错,当前行数据能最后正确绑定,能以 :v-model="‘xxxx’" ...
  • 选中不选中,不是看checked的属性值,而是看有没有checked这个属性,所以,动态选中,不用v-model,也不用checked='true',判断是否需要渲染checked这个属性就好了.view 改一下:"{{option.text}}"...
  • -- checkbox单独使用时,需要绑定v-model,直接用v-bind绑定一个布尔值,为真时选中,为假时选 --&gt; &lt;label&gt;checkbox做单选使用&lt;/label&gt; &lt;br&gt; &lt;...
  • (2)当一级复选框选中时,二级复选框全选,当二级复选框非全选时,一级复选项为不选中状态,当二级复选框为全选时,一级复选框为选中状态。 (3)全部全选,全部取消选中。 (4)记录选中的二级复选框id,方便...
  • 今天遇到一个vue诡异的数据绑定问题,下面我给大家分享一下我解决问题思路方式,以及为什么要这样。一、问题现象使用vant的checkbox组件时无法使用v-model来双向绑定选中状态!但是重新打开checbox所在的pop弹窗,...
  • vue中冒号:是v-bind的缩写。 一直最常见的做法是代表绑定一个变量。 但是我今天用到复选框是时候缺出现选中的情况 <el-checkboxv-model="checked">备选项</el-checkbox> checked:1但是没有选中 ...

空空如也

空空如也

1 2 3
收藏数 49
精华内容 19
关键字:

checkbox选中和不选中vue

vue 订阅