Vue 基础总结(2.x)

GitHub源码 :https://github.com/OYCodeSite/VueCode.git

vue 环境搭建

一、初始化项目

  1. 生成package.json
yarn init -y
  1. 创建入口js: src/index.js
console.log('Hello Webpack!')
document.getElementById('root').innerHTML = '<h1>Hello222</h1>'
  1. 创建页面文件: index.html
<div id="root"></div>

二、webpack基本使用

  1. 下载依赖包
yarn add -D webpack webpack-cli
yarn add -D html-webpack-plugin
  1. 创建webpack配置: webpack.config.js
    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')

    module.exports = {
      // 模式: 生产环境
      mode: 'production',
      // 入口
      entry: {
        app: path.resolve(__dirname, 'src/index.js')
      },
      // 出口(打包生成js)
      output: {
        filename: 'static/js/[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
      },
      // 模块加载器
      module: {
        rules: [

        ]
      },
      // 插件
      plugins: [
        new HtmlWebpackPlugin({
          template: 'index.html',
          filename: 'index.html'
        })
      ]
    }
  1. 生成环境打包并运行
配置打包命令:  "build": "webpack --mode production"
打包项目: yarn build
运行打包项目: serve dist

三、开发环境运行

  1. 现在的问题
每次修改项目代码后, 必须重新打包, 重新运行
  1. 下载依赖包
yarn add -D webpack-dev-server
  1. 配置开发服务器
devServer: {
    open: true, // 自动打开浏览器
    quiet: true, // 不做太多日志输出
}
  1. 配置开启source-map调试
devtool: 'cheap-module-eval-source-map'
  1. 开发环境运行
配置命令: "dev": "webpack-dev-server --mode development"
执行命令: yarn dev

四、打包处理 ES6/CSS/图片

  1. 处理ES6
a. 下载依赖包
	yarn add -D babel-loader @babel/core @babel/preset-env
b. 配置
{
        test: /\.js$/,
        //exclude: /(node_modules|bower_components)/,
        include: path.resolve(__dirname, 'src'),
        use: {
            loader: 'babel-loader',
            options: {
            presets: ['@babel/preset-env']
		}
	}
}
  1. 处理CSS
a. 下载依赖包
    yarn add -D css-loader style-loader
b. 配置
{
    test: /\.css$/,
    use: ['style-loader', 'css-loader'], // 多个loader从右到左处理
}
  1. 处理图片
 a. 下载依赖包
        yarn add -D url-loader@2.3.0 file-loader@4.3.0
 b. 配置
 {
 	test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
 	loader: 'url-loader',
 	options: {
 		limit: 1000,
 		name: 'static/img/[name].[hash:7].[ext]' // 相对于output.path
 	}
 }
  1. 测试
a. 添加图片: src/assets/imgs/logo.png
b. 添加css: src/assets/css/my.css
img {
	width: 200px;
	height: 200px;
}
c. index.js
import logo from './assets/imgs/logo.png'
import  './assets/css/my.css'

const image = new Image()
image.src = logo
document.body.appendChild(image)
document.getElementById('root').innerHTML = '<h1>Hello222</h1>'

五、搭建vue的环境

1). 文档:
    https://vue-loader.vuejs.org/zh/

2). 下载依赖包:
    yarn add vue
    yarn add -D vue-loader vue-template-compiler

3). 配置
    const VueLoaderPlugin = require('vue-loader/lib/plugin')

    {
      test: /\.vue$/,
      include: path.resolve(__dirname, 'src'),
      loader: 'vue-loader'
    }

    {
      test: /\.css$/,
      use: ['vue-style-loader', 'css-loader'],
    }

    new VueLoaderPlugin()

    // 引入模块的解析
    resolve: {
      extensions: ['.js', '.vue', '.json'], // 可以省略的后缀名
      alias: { // 路径别名(简写方式)
        'vue$': 'vue/dist/vue.esm.js',  // 表示精准匹配
      }
    }

4). 编码: 
    src/App.vue
    src/index.js

六、解决开发环境ajax请求跨域问题

  1. 利用webpack-dev-server进行请求代理转发
webpack-dev-server内部利用http-proxy-middle包对特定请求进行转发操作
  1. 配置:
devServer: {
    proxy: {
        // 处理以/api开头路径的请求
        // '/api': 'http://localhost:4000'
        '/api': {
            target: 'http://localhost:4000', // 转发的目标地址
            pathRewrite: {
                '^/api' : ''  // 转发请求时去除路径前面的/api
            },
            changeOrigin: true, // 支持跨域
        }
    }
}
1). 利用webpack-dev-server进行请求代理转发
    webpack-dev-server内部利用http-proxy-middle包对特定请求进行转发操作
2). 配置:
    devServer: {
      proxy: {
        // 处理以/api开头路径的请求
        // '/api': 'http://localhost:4000'
        '/api': {
          target: 'http://localhost:4000', // 转发的目标地址
          pathRewrite: {
            '^/api' : ''  // 转发请求时去除路径前面的/api
          },
          changeOrigin: true, // 支持跨域
        }
      }
    }

七、配置async/await的编译环境

  1. 下载包
yarn add @babel/runtime-corejs2
  1. 配置
presets: [
   ['@babel/preset-env', {
       useBuiltIns: 'usage',
       'corejs': 2 // 处理一些新语法的实现
   }]
]

八、解决mint-ui按需引入配置异常的问题

  1. 文档上的配置
"plugins": [
    ["component", [
        {
            "libraryName": "mint-ui",
            "style": true
        }
    ]]
]
  1. 异常信息
Error: .plugins[0][1] must be an object, false, or undefined
  1. 原因
文档编写时, 是根据老的babel版本编写的, 新版本的babel配置有变化
以前是数组, 现在只能是对象
  1. 修正
"plugins": [
    ["component", {
        "libraryName": "mint-ui",
        "style": true
    }]
]

九、解决history模式路由请求404的问题

devServer: historyApiFallback: true, // 任意的 404 响应都被替代为 index.html
output: publicPath: '/', // 引入打包的文件时路径以/开头

vue 组件化

一、vue单文件组件

<template>
  <div>xxx</div>
</template>
<script>
  export default {
    props: []/{}
    data(){},
    computed: {}
    methods: {},
    watch: {}
    filters: {}
    directives: {}
    components: {}
  }
</script>
<style scoped>
</style>

二、组件化编码的基本流程

  1. 拆分界面, 抽取组件

  2. 编写静态组件

  3. 编写动态组件

    • 初始化数据, 动态显示初始化界面
    • 实现与用户交互功能
  4. 设计data
    类型: [{id: 1, title: ‘xxx’, completed: false}]
    名称: todos
    位置: 如果只是哪个组件用, 交给它, 如果是哪些组件用, 交给共同的父组件

  5. 关于状态数据的更新
    data数据定义在哪个组件, 更新数据的行为就定义在哪个组件
    如果子组件要更新父组件的数据, 调用父组件的更新函数来更新父组件的数据
    一个组件接收属性数据不要直接修改, 只是用来读取显示的

三、组件间通信

  1. 组件通信的5种方式

props
vue的自定义事件
全局事件总线
slot
vuex

  1. props
父子组件间通信的基本方式
属性值的2大类型:
    一般/非函数: 父组件-->子组件
    函数: 子组件-->父组件
问题: 
    隔层组件间传递: 必须逐层传递(麻烦)
    兄弟组件间: 必须借助父组件(麻烦)
  1. vue自定义事件
  • 给子组件标签绑定事件监听
  • 子组件向父组件的通信方式
  • 功能类似于function props
  • 不适合隔层组件和兄弟组件间的通信
  1. 全局事件总线
  • 利用vm对象的 o n ( ) / on()/ on()/emit()/$off()
  • 利用vm对象是组件对象的原型对象
  • 创建vm对象作为全局事件总线对象保存到Vue的原型对象上, 所有的组件对象都可以直接可见:
    • Vue.prototype.$bus = new Vue()
    • 任意组件A可以通过this. b u s . bus. bus.on()绑定监听接收数据
    • 任意组件B可以通过this. b u s . bus. bus.emit()分发事件, 传递数据
  1. slot
  • 父组件向子组件通信
  • 通信是带数据的标签

注意: 标签是在父组件中解析

  1. vuex
  • 多组件共享状态(数据的管理)
  • 组件间的关系也没有限制
  • 功能比事件总线强大, 更适用于vue项目

vue单文件组件

<template>
  <div>xxx</div>
</template>
<script>
  export default {
    props: []/{}
    data(){},
    computed: {}
    methods: {},
    watch: {}
    filters: {}
    directives: {}
    components: {}
  }
</script>
<style scoped>
</style>

vue-ajax

一、vue 项目中常用的2个ajax库

  • vue-resource

    vue 插件,非官方库, vue1.x 使用广泛

    **在线文档:**https://github.com/pagekit/vue-resource/blob/develop/docs/http.md

  • axios

    通用的ajax请求库,官方推荐, vue2.x 使用广泛

    **在线文档:**https://github.com/pagekit/vue-resource/blob/develop/docs/http.md

安装插件:

// yarn 安装
yarn add vue-resource axios


// nmp 安装
npm install vue-resource --save
npm install axios --save

二、vue-resource、axios 的使用

案例效果

ajax_test (4)

vue-resource:

编码:

index.js

import Vue from 'vue'
import VueResource from 'vue-resource' 
import APP from './APP.vue' // 引入自定义组件

Vue.config.productionTip = false;

// 声明使用Vue插件
Vue.use(VueResource); // 内部给所有的组件对象都添加一个属性对象: $http

new Vue({
    el: '#root',
    render: h => h(APP),
});

APP.vue

<template>
  <div>
      <p v-if="!repoName">loading...</p>
      <p v-else>
          most star repo is
          <a :href="repoUrl">{{repoName}}</a>
      </p>
  </div>
</template>

<script type="text/ecmascript-6">
  export default {
      data(){
          return{
              repoName : '',
              repoUrl: ''
          }
      },
    mounted(){
        // 利用vue-resource发送ajax请求获取数据
        this.$http.get('https://api.github.com/search/repositories?q=v&sort=stars')
        .then(response =>{
            const result = response.data;
            const {name,html_url} = result.items[0];
            this.repoName = name;
            this.repoUrl = html_url;
        })
        .catch(error =>{
            alert('请求出错了');
        });
    },


  }
</script>

axios

index.js

import Vue from 'vue'
import APP from './APP.vue' // 引入自定义组件

Vue.config.productionTip = false;


new Vue({
    el: '#root',
    render: h => h(APP),
});

APP.vue

<template>
  <div>
      <p v-if="!repoName">loading...</p>
      <p v-else>
          most star repo is
          <a :href="repoUrl">{{repoName}}</a>
      </p>
  </div>
</template>

<script type="text/ecmascript-6">
import axios from 'axios'
  export default {
      data(){
          return{
              repoName : '',
              repoUrl: ''
          }
      },
    mounted(){
        // 利用axious 发送ajax 请求获取数据
        axios.get('https://api.github.com/search/repositories',{
            params: {
                q : 'v',
                sort: 'stars'
            }
        })
        .then(response =>{
            const result = response.data;
            const {name, html_url} = result.items[0];
            this.repoName = name;
            this.repoUrl = html_url;
        })
        .catch(error =>{
            alert('请求出错了');
        })
    },


  }
</script>

三、使用express 快速搭建后台接口

编码:

server.js

/*
    后台服务器应用模块: 使用express快速搭建后台路由
 */

const express = require('express');
const axios = require('axios');
const app = express();


// 注册后台路由(转发请求)
app.get('/repositories/:q', (rep, res) =>{
    const q = rep.params.q;
    axios({
        method: 'GET',
        url: 'https://api.github.com/search/repositories',
        params: {
            q,
            sort: 'stars'
        }
    }).then(response =>{
        const {name, html_url} = response.data.items[0];
        res.send({
            status: 0,
            data: {name, html_url}
        });
    });

});

app.listen('4000', () =>{
    console.log("server listen on http://localhost:4000");
})

测试:

启动express: node server.js

image-20210113123341827

  • http://localhost:4000/repositories/v

image-20210113123245518

vuex

一、vuex的核心概念

1、state

vuex管理的状态对象
它应该是唯一的
const state = {
  xxx: initValue
}

2、mutations

包含多个直接更新state的方法(回调函数)的对象
谁来触发: action中的commit('mutation名称')
只能包含同步的代码, 不能写异步代码
const mutations = {
  yyy (state, {data1}) {
    // 更新state的某个属性
  }
}

3、actions

包含多个事件回调函数的对象
通过执行: commit()来触发mutation的调用, 间接更新state
谁来触发: 组件中: $store.dispatch('action名称', data1)  // 'zzz'
可以包含异步代码(定时器, ajax)
const actions = {
  zzz ({commit, state}, data1) {
    commit('yyy', {data1})
  }
}

4、getters

包含多个计算属性(getter)的对象
谁来读取: 组件中: $store.getters.xxx
const getters = {
  mmm (state) {
    return ...
  }
}

5、modules

包含多个module的对象
一个module是一个包含state/mutations/actions/getters的对象
是将一复杂应用的vuex代码进行多模块拆分的第2种方式

6、store

vuex的核心管理对象, 是组件与vuex通信的中间人
读取数据的属性
    state: 包含最新状态数据的对象
    getters: 包含getter计算属性的对象
更新数据的方法
    dispatch(): 分发调用action
    commit(): 提交调用mutation

二、使用vuex

1. 创建并向外暴露store对象

export default new Vuex.Store({
  state,
  mutations,
  actions,
  getters,
  modules: {
    a,
    b
  }
})

2. 注册store: main.js

import store from './store'
new Vue({
  store
})

3. 组件中通过store与vuex通信

import {mapState, mapGetters} from 'vuex'
export default {
  computed: (
    ...mapState(['xxx']),
    ...mapGetters(['yyy'])
  )
  methods: {
        test () {
            this.$store.dispatch('zzz', data)
            this.$store.commit('zzz', data)
        }
  }
}

三、 Vuex结构图

image-20210125001753385

Vue-router

一、vue-router的基本使用

1). 创建路由器: router/index.js
    new VueRouter({
      mode: 'hash/history'
      routes: [
        { // 一般路由
          path: '/about',
          component: About
        },
        { // 自动跳转路由
          path: '/',
          redirect: '/about'
        }
      ]
    })
2). 注册路由器: main.js
    import router from './router'
    new Vue({
      router
    })
3). 使用路由组件标签:
    <router-link to="/xxx">Go to XXX</router-link>  // 可以不使用
    <router-view></router-view>  // 必须使用
4). 2个对象
    $router: 代表路由器对象, 包含一些实现路由跳转/导航的方法: push()/replace()/back()
    $route: 代表当前路由对象, 包含一些路由相关的属性: path/params/query/meta

二、编写路由的3步

  • 定义路由组件

  • 映射路由

  • 使用显示当前路由组件

三、 嵌套路由

children: [
    {
      path: '/home/news/:id/:title',
      component: news
    },
    {
      path: 'message',
      component: message
    }
]

四、 向路由组件传递数据

params/query: <router-link to="/home/news/123/abc?zzz=1234">
将请求参数映射成props: props=true | props: route => ({id: route.params.id})
变相props: <router-view msg='abc'>

五、动态路由与路由别名

注册路由: 
    {
        name: 'news'
        path: '/home/news/:id/:title',
        component: News
    }
跳转: 
    <router-link to="{name: 'news', params: {id: 1, title: 'abc'}}">
    router.push({name: 'news', params: {id: 1, title: 'abc'}})

六、缓存路由组件

路由组件对象默认的生命周期: 被切换时就会死亡, 切换回来时重新创建
<keep-alive exlude="A,B">
  <router-view></router-view>
</keep-alive>

七、 路由的编程式导航

this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
this.$router.back(): 请求(返回)上一个记录路由

八、 路由的2种模式比较, 解决history模式404问题

hash模式:
    路径中带#: http://localhost:8080/#/home/news
    发请求的路径: http://localhost:8080  项目根路径
    响应: 返回的总是index页面  ==> path部分(/home/news)被解析为前台路由路径

history模式:
    路径中不带#: http://localhost:8080/home/news
    发请求的路径: http://localhost:8080/home/news
    响应: 404错误
    希望: 如果没有对应的资源, 返回index页面, path部分(/home/news)被解析为前台路由路径
    解决: 添加配置
        devServer: historyApiFallback: true, // 任意的 404 响应都被替代为 index.html
        output: publicPath: '/', // 引入打包的文件时路径以/开头

Vue 源码分析

一、debug调试

  1. 调试的目的

    查找bug: 不断缩小可疑代码的范围

    查看程序的运行流程(用于熟悉新接手项目的代码)

  2. 如何开启调试模式

    添加debugger语句: 程序运行前 此方式用打包后才运行的项目

    添加(打)断点: 程序运行前或者过程中 此方式用运行源码js

  3. 如何进行调试操作

    resume: 恢复程序执行(可能执行完或者进入下一个断点处)
    step over: 单步跳转, 尝试执行完当前语句, 进入下一条(如果内部有断点, 自动进入内部断点处)
    step into: 跳入, 进入当前调用函数内部
    step out: 跳出, 一次性执行完当前函数后面所有语句,并出去
    deactivate breakpoints: 使所有断点暂时失效

    call stack: 显示是程序函数调用的过程

    scope: 当前执行环境对应的作用域中包含的变量数据

    breakpoints: 断点列表

二、准备

  1. [].slice.call(lis): 将伪数组转换为真数组
  2. node.nodeType: 得到节点类型
  3. Object.defineProperty(obj, propertyName, {}): 给对象添加/修改属性(指定描述符)
    1. configurable: true/false 是否可以重新define
    2. enumerable: true/false 是否可以枚举(for…in / keys())
    3. value: 指定初始值
    4. writable: true/false value是否可以修改存取(访问)描述符
    5. get: 函数, 用来得到当前属性值
    6. set: 函数, 用来监视当前属性值的变化
  4. Object.keys(obj): 得到对象自身可枚举的属性名的数组
  5. DocumentFragment: 文档碎片(高效批量更新多个节点)
  6. obj.hasOwnProperty(prop): 判断prop是否是obj自身的属性

三、数据代理(MVVM.js)

  1. 通过一个对象代理对另一个对象中属性的操作(读/写)

  2. 通过vm对象来代理data对象中所有属性的操作

  3. 好处: 更方便的操作data中的数据

  4. 基本实现流程

    1. 通过Object.defineProperty()给vm添加与data对象的属性对应的属性描述符
    2. 所有添加的属性都包含getter/setter
    3. 在getter/setter内部去操作data中对应的属性数据

四、模板解析(compile.js)

1.模板解析的关键对象: compile对象
2.模板解析的基本流程:

  • 将el的所有子节点取出, 添加到一个新建的文档fragment对象中
  • 对fragment中的所有层次子节点递归进行编译解析处理
    • 对插值文本节点进行解析
    • 对元素节点的指令属性进行解析
    • 事件指令解析
    • 一般指令解析
  • 将解析后的fragment添加到el中显示

3.解析插值语法节点: textNode.textContent = value

  • 根据正则对象得到匹配出的表达式字符串: 子匹配/RegExp.$1
  • 从data中取出表达式对应的属性值
  • 将属性值设置为 文本节点的textConten

4.事件指令解析: elementNode.addEventListener(‘eventName’, callback.bind(vm))

  • 从指令名中取出事件名
  • 根据指令属性值(表达式)从methods中得到对应的事件处理函数对象
  • 给当前元素节点绑定指定事件名和回调函数的dom事件监听
  • 指令解析完后, 移除此指令属性

5.一般指令解析: elementNode.xxx = value

  • 得到指令名和指令值(表达式)
  • 从data中根据表达式得到对应的值
  • 根据指令名确定需要操作元素节点的什么属性
    • v-text—textContent属性
    • v-html—innerHTML属性
    • v-class–className属性

五、数据劫持–>数据绑定

  1. 数据绑定(model==>View)

    一旦更新了data中的某个属性数据, 所有界面上直接使用或间接使用了此属性的节点都会更新(更新)

  2. 数据劫持

    • 数据劫持是vue中用来实现数据绑定的一种技术
    • 基本思想: 通过defineProperty()来监视data中所有属性(任意层次)数据的变化, 一旦变化就去更新界面
  3. 四个重要对象

Observer

  • 用来对data所有属性数据进行劫持的构造函数

    • 给data中所有属性重新定义属性描述(get/set)
      • 为data中的每个属性创建对应的dep对象

Dep(Depend)

  • data中的每个属性(所有层次)都对应一个dep对象

    • 创建的时机:

      • 在初始化define data中各个属性时创建对应的dep对象

        在data中的某个属性值被设置为新的对象时
        对象的结构
        {
        	id, // 每个dep都有一个唯一的id
        	subs //包含n个对应watcher的数组(subscribes的简写)
        }
        
    • subs属性说明

      当一个watcher被创建时, 内部会将当前watcher对象添加到对应的dep对象的subs中

      当此data属性的值发生改变时, 所有subs中的watcher都会收到更新的通知, 从而最终更新对应的界面

Compile

  • 用来解析模板页面的对象的构造函数(一个实例)
  • 利用compile对象解析模板页面
  • 每解析一个表达式(非事件指令)都会创建一个对应的watcher对象, 并建立watcher与dep的关系
  • complie与watcher关系: 一对多的关系

Watcher

  • 模板中每个非事件指令或表达式都对应一个watcher对象
  • 监视当前表达式数据的变化
  • 创建的时机: 在初始化编译模板时
  • 对象的组成
{
	vm,  //vm对象
	exp, //对应指令的表达式
	cb, //当表达式所对应的数据发生改变的回调函数
	value, //表达式当前的值
	depIds //表达式中各级属性所对应的dep对象的集合对象
	//属性名为dep的id, 属性值为dep
}

总结: dep与watcher的关系: 多对多

  • 一个data中的属性对应对应一个dep, 一个dep中可能包含多个watcher(模板中有几个表达式使用到了属性)
  • 模板中一个非事件表达式对应一个watcher, 一个watcher中可能包含多个dep(表达式中包含了几个data属性)
  • 数据绑定使用到2个核心技术
    • defineProperty()
      • 订阅者-发布者

双向数据绑定

  1. 双向数据绑定是建立在单向数据绑定(model==>View)的基础之上的
  2. 双向数据绑定的实现流程:
    • 在解析v-model指令时, 给当前元素添加input监听
    • 当input的value发生改变时, 将最新的值赋值给当前表达式所对应的data属性

Vue CLI

一、安装

npm install -g @vue/cli
# OR
yarn global add @vue/cli

二、vue的脚手架

  1. 脚手架V2: 相对老的项目
  2. 脚手架v3: 新的项目
  3. 脚手架v4: 最新的(当前用得还少)

三、使用vue的脚手架

脚手架v3

npm install -g @vue/cli

# 创建一个项目
vue create vue-app3 

脚手架v2

Vue CLI >= 3 和旧版使用了相同的 vue 命令,所以 Vue CLI 2 (vue-cli) 被覆盖了。如果你仍然需要使用旧版本的 vue init 功能,你可以全局安装一个桥接工具:

npm install -g @vue/cli-init

# `vue init` 的运行效果将会跟 `vue-cli@2.x` 相同
vue init webpack my-project

四、比较V2与V3创建的项目

  1. v2的配置是直接可见, v3是包装隐藏起来了

  2. 修改配置: v2是直接在配置文件中修改, v3提供了一个专门的配置: vue.config.js, 我们可以根据文档在此文件中添加配置

    depIds //表达式中各级属性所对应的dep对象的集合对象
    //属性名为dep的id, 属性值为dep
    }


>总结: dep与watcher的关系: 多对多

* 一个data中的属性对应对应一个dep, 一个dep中可能包含多个watcher(模板中有几个表达式使用到了属性)
* 模板中一个非事件表达式对应一个watcher, 一个watcher中可能包含多个dep(表达式中包含了几个data属性)
* 数据绑定使用到2个核心技术
  * **defineProperty()**
    * 订阅者-发布者

>**双向数据绑定**

1. 双向数据绑定是建立在单向数据绑定(model==>View)的基础之上的
2. 双向数据绑定的实现流程:
   * 在解析v-model指令时, 给当前元素添加input监听
   * 当input的value发生改变时, 将最新的值赋值给当前表达式所对应的data属性

# Vue CLI

## 一、安装

~~~shell
npm install -g @vue/cli
# OR
yarn global add @vue/cli

二、vue的脚手架

  1. 脚手架V2: 相对老的项目
  2. 脚手架v3: 新的项目
  3. 脚手架v4: 最新的(当前用得还少)

三、使用vue的脚手架

脚手架v3

npm install -g @vue/cli

# 创建一个项目
vue create vue-app3 

脚手架v2

Vue CLI >= 3 和旧版使用了相同的 vue 命令,所以 Vue CLI 2 (vue-cli) 被覆盖了。如果你仍然需要使用旧版本的 vue init 功能,你可以全局安装一个桥接工具:

npm install -g @vue/cli-init

# `vue init` 的运行效果将会跟 `vue-cli@2.x` 相同
vue init webpack my-project

四、比较V2与V3创建的项目

  1. v2的配置是直接可见, v3是包装隐藏起来了
  2. 修改配置: v2是直接在配置文件中修改, v3提供了一个专门的配置: vue.config.js, 我们可以根据文档在此文件中添加配置
  3. vue使用的是不带编译器的版本, 打包文件更小 不写template配置, 直接render配置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值