vue 2.0 搭建项目

239 阅读4分钟

创建项目

  1. 通过 cil 本地搭建
npm install --global @vue/cli
  1. 创建一个新的工程,并选择‘manually select features’ 选项
vue create my-porject-name

创建 vue2 的项目选择这些选项 please pick a preset: vue2

pick the package manager to use when installing dependencies: yarn

包管理工具是 yarn image.png

下载完成后出现这些文件 image.png

了解 vue-cli 生成的文件有哪些

node_modules:项目引用的外包
public: 放入静态资源
src: main.js 入口文件 app.vue 入口UI页面
.gitignore 忽略提交的代码
babel.config bable 配置  
jsconfig 源于tsconfig.json,是TypeScript的配置文件。jsconfig.json相当于tsconfig.json的“allowJs”属性设置为true。
package.json npm包管理,管理项目
README 阅读项目
vue.config 控制打包器入口
yarn.lock 锁定依赖包

目的: 实现路径切换 集成路由 vue-router

localhost:8080/#/apphome

项目代码下载npm包: npm install --legacy-peer-deps vue-router@3.5.2

image.png

image.png

写代码 main.js 挂在router image.png

route/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
//引入一个路由组件
import AppHome from '../pages/Home/index.vue'

// 引入路由
Vue.use(VueRouter) 

export default new VueRouter({
    routes:[
    {
        name:'appHome',
        path:'/appHome',
        component: AppHome,
    }]
})

将路由组件显示到页面上

App.vue

<template>
  <div id="app">
    app
    <router-view />
  </div>
</template>

<script>
export default {
  name: 'App',
  components: {
  }
}
</script>
<style>
</style>

浏览器 搜索 输入url: localhost:8080/#/appHome就能切换路由了

集成vueX

为什么使用vueX

问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力

问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝

了解vueX

这个状态自管理应用包含以下几个部分:

  • state,驱动应用的数据源;
  • view,以声明方式将 state 映射到视图;
  • actions,响应在 view 上的用户输入导致的状态变化。

以下是一个表示“单向数据流”理念的简单示意:

细了解vuex如何运转

image.png

学了基本的知识之后上手代码

第一步:先安装vuex模块依赖

操作:黑窗口指令: npm install vuex@2.0.0

image.png

第二步: vue 项目下,注入vuex模块

操作:

1. 创建需要文件和文件夹

image.png

2. 编写代码

3. 注入store

App.vue
import Vue from 'vue'
import router from './router'
import App from './App.vue'
// 全局注入store
import store from './store'

Vue.config.productionTip = false

new Vue({
 render: h => h(App),
 router,
 store,// 注入store
}).$mount('#app')

4. vue使用vuex功能

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import home from './modules/home'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
  // 这里是根vuex状态
    count: 0
  },
  mutations: {
  // 这里是根vuex状态
    increment (state) {
      state.count++
    }
  },
  action: {
  // 这里是根vuex状态
  }
  modules: { // 子vuex状态模块注册
    home,
  }
})

export default store

5. Module使用

使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module) 。每个模块拥有自己的 state、mutation、action、getter、

代码编写 store/modules/index.js

const homeModles=  {
    namespaced: true,
    state: { a: 1 },
    mutations: {  },
    actions: {  },
    getters: {  }
}

export default homeModles

将文件导入到刚才的 store/index.js

6. 这样就完成了vuex的注册,在页面上在组件中单独打印下store.state

组件中访问vuex的store

this.$store.state

访问模块的下的store

this.$store.state.home

image.png

vueX state

结合项目代码了解

查看page页面下的home文件夹

image.png page/Home/index.vue

<template>
  <div>
    home
    <button v-on:click="getVueState"> vuex </button>
    {{list}}
    {{count}}
    {{count2}}
  </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
  name: 'AppHome',
  data() {
    return {
      list: this.$store.state.home.list
    }
  },
  methods:{
    getVueState() {
      console.log(this.$store, this.$router);
    }
  },
  computed:  mapState({
    // 箭头函数可使代码更简练
    count: (state) => state.home.count,
    count2:  (state) => state.home.count2,
    // 传字符串参数 'count' 等同于 `state => state.count`
  })
}
</script>

<style>

</style>

  1. 维护home页面的vuex state

image.png

store/modukes/home.js

const homeModles=  {
    namespaced: true,
    state: { 
        list: 1,
        count: 0,
        count2: 1,
    },
    mutations: {  },
    actions: {  },
    getters: {  }
}

export default homeModles
  1. 上面代码维护了home的vuex的state, 有list, count, count2

  2. 使用了mapState 辅助函数

     解决: 组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余
    

vuex mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation

你不能直接调用一个 mutation 处理函数。这个选项更像是事件注册:“当触发一个类型为 increment 的 mutation 时,调用此函数

image.png

vuex 使用mutations 如果使用modules下,两个文件理同时命名相同的方法,会同时触发。

modules/home

  mutations: {
    increment (state) {
      state.count++
    }
  },

modules/login

  mutations: {
    increment (state) {
      state.count++
    }
  },

解决方式: 1.创建文件

image.png

mutation/index.js

export const INCREMENT_MUTATION = 'INCREMENT_MUTATION'
  1. 引入 常量注册mutations事件注册方法

store/modules/home

import { INCREMENT_MUTATION } from '../mutation/index'
const homeModles=  {
    namespaced: true,
    state: { 
        list: 1,
        count: 0,
        count2: 1,
    },
    mutations: { 
        [INCREMENT_MUTATION](state) {
            state.count++
        }
     },
    actions: {  },
    getters: {  }
}

export default homeModles

mutation 传参 1.

store.commit('increment', 10)

在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读: 2.

// ...
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
store.commit('increment', {
  amount: 10
})

vuex action

为什么使用它

在 mutation 中混合异步调用会导致你的程序很难调试。例如,当你调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和哪个先回调呢?这就是为什么我们要区分这两个概念。

在组件中分发 Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

让我们来注册一个简单的 action:

const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

你在组件中使用 this.$store.dispatch('xxx') 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(需要先在根节点注入 store):

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', //`this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}

Getter

通过属性访问

Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值:

store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]

Getter 也可以接受其他 getter 作为第二个参数:

getters: {
  // ...
  doneTodosCount (state, getters) {
    return getters.doneTodos.length
  }
}
store.getters.doneTodosCount // -> 1

我们可以很容易地在任何组件中使用它:

computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}

集成ElementUI

安装

npm 安装

推荐使用 npm 的方式安装,它能更好地和 webpack 打包工具配合使用。

npm i element-ui -S

按需引入

借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。

首先,安装 babel-plugin-component babel-preset-es2015 @babel/preset-env:

npm install babel-plugin-component -D
npm i babel-preset-es2015
npm i -D @babel/preset-env

然后,将 .babel.config.js 修改为:

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset',
    ["@babel/preset-env", { "useBuiltIns": "entry" }]
  ],
  plugins: [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

接下来,如果你只希望引入部分组件,比如 Button 和 Select,那么需要在 main.js 中写入以下内容:

import Vue from 'vue';
import { Button, Select } from 'element-ui';
import App from './App.vue';

Vue.component(Button.name, Button);
Vue.component(Select.name, Select);
/* 或写为
 * Vue.use(Button)
 * Vue.use(Select)
 */

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

完整组件列表和引入方式(完整组件列表以 components.json 为准)

import Vue from 'vue';
import {
  Pagination,
  Dialog,
  Autocomplete,
  Dropdown,
  DropdownMenu,
  DropdownItem,
  Menu,
  Submenu,
  MenuItem,
  MenuItemGroup,
  Input,
  InputNumber,
  Radio,
  RadioGroup,
  RadioButton,
  Checkbox,
  CheckboxButton,
  CheckboxGroup,
  Switch,
  Select,
  Option,
  OptionGroup,
  Button,
  ButtonGroup,
  Table,
  TableColumn,
  DatePicker,
  TimeSelect,
  TimePicker,
  Popover,
  Tooltip,
  Breadcrumb,
  BreadcrumbItem,
  Form,
  FormItem,
  Tabs,
  TabPane,
  Tag,
  Tree,
  Alert,
  Slider,
  Icon,
  Row,
  Col,
  Upload,
  Progress,
  Spinner,
  Badge,
  Card,
  Rate,
  Steps,
  Step,
  Carousel,
  CarouselItem,
  Collapse,
  CollapseItem,
  Cascader,
  ColorPicker,
  Transfer,
  Container,
  Header,
  Aside,
  Main,
  Footer,
  Timeline,
  TimelineItem,
  Link,
  Divider,
  Image,
  Calendar,
  Backtop,
  PageHeader,
  CascaderPanel,
  Loading,
  MessageBox,
  Message,
  Notification
} from 'element-ui';

Vue.use(Pagination);
Vue.use(Dialog);
Vue.use(Autocomplete);
Vue.use(Dropdown);
Vue.use(DropdownMenu);
Vue.use(DropdownItem);
Vue.use(Menu);
Vue.use(Submenu);
Vue.use(MenuItem);
Vue.use(MenuItemGroup);
Vue.use(Input);
Vue.use(InputNumber);
Vue.use(Radio);
Vue.use(RadioGroup);
Vue.use(RadioButton);
Vue.use(Checkbox);
Vue.use(CheckboxButton);
Vue.use(CheckboxGroup);
Vue.use(Switch);
Vue.use(Select);
Vue.use(Option);
Vue.use(OptionGroup);
Vue.use(Button);
Vue.use(ButtonGroup);
Vue.use(Table);
Vue.use(TableColumn);
Vue.use(DatePicker);
Vue.use(TimeSelect);
Vue.use(TimePicker);
Vue.use(Popover);
Vue.use(Tooltip);
Vue.use(Breadcrumb);
Vue.use(BreadcrumbItem);
Vue.use(Form);
Vue.use(FormItem);
Vue.use(Tabs);
Vue.use(TabPane);
Vue.use(Tag);
Vue.use(Tree);
Vue.use(Alert);
Vue.use(Slider);
Vue.use(Icon);
Vue.use(Row);
Vue.use(Col);
Vue.use(Upload);
Vue.use(Progress);
Vue.use(Spinner);
Vue.use(Badge);
Vue.use(Card);
Vue.use(Rate);
Vue.use(Steps);
Vue.use(Step);
Vue.use(Carousel);
Vue.use(CarouselItem);
Vue.use(Collapse);
Vue.use(CollapseItem);
Vue.use(Cascader);
Vue.use(ColorPicker);
Vue.use(Transfer);
Vue.use(Container);
Vue.use(Header);
Vue.use(Aside);
Vue.use(Main);
Vue.use(Footer);
Vue.use(Timeline);
Vue.use(TimelineItem);
Vue.use(Link);
Vue.use(Divider);
Vue.use(Image);
Vue.use(Calendar);
Vue.use(Backtop);
Vue.use(PageHeader);
Vue.use(CascaderPanel);

Vue.use(Loading.directive);

Vue.prototype.$loading = Loading.service;
Vue.prototype.$msgbox = MessageBox;
Vue.prototype.$alert = MessageBox.alert;
Vue.prototype.$confirm = MessageBox.confirm;
Vue.prototype.$prompt = MessageBox.prompt;
Vue.prototype.$notify = Notification;
Vue.prototype.$message = Message;
{
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

遇到的问题 Error: Plugin/Preset files are not allowed to export objects, only functions. In C:\Users\vue_test\node_modules\babel preset-es2015\lib\index.js

原因:脚手架版本较新,与babel依赖包不兼容

解决方法:在babel的配置文件中,将预设包中的"es2015"修改为"@babel/preset-env"

上面就解决了;

页面使用

直接使用

<template>
  <div id="app">
    {{d}}
    <el-button>默认按钮</el-button>
    <el-button type="success">成功按钮</el-button>
    <el-button type="info">信息按钮</el-button>
    <el-button type="warning">警告按钮</el-button>
    <el-button type="danger">危险按钮</el-button>
    <router-view />
  </div>
</template>