Vue核心知识点 一、vue.config.js 基本配置 二、vue组件间传值 三、Vue Router 四、Vuex 基础用法 五、Vuex 高级用法 六、Element UI 七、弹出类型组件 八、表格组件

module.exports = {
  // 基本路径 cli3.3以前版本用baseUrl
  publicPath: '/',
  // 输出文件目录
  outputDir: 'dist',
  // 用于嵌套生成的静态资源
  assetsDir: '',
  // 生产环境sourMap
  productionSourceMap: false,
  // webpack配置
  configureWebpack: () => {},
  chainWebpack: () => {},
  
  // css相关配置
  css: {
    // 启动css modules
    modules: false,
    // 是否使用css分离插件
    extract: true,
    // 开启 css sourcemaps?
    sourceMap: false,
    // css 预处理器配置项
    loaderOptions: {}
  },
  
  // webpack-dev-server 相关配置
  devServer: {
    host: '0.0.0.0',
    port: 8080,
    proxy: {} // 设置代理
  },
  // 第三方插件配置
  pluginOptions: {
    // ...
  }
}

二、vue组件间传值

1. 父子组件传值

(1) props(父传子) / $emit(子传父)

(2) $parent / $children

// App => Father => Child
// Father.vue
mounted () {
  console.log(this.$children[0].val) // 访问子组件 Child 的某个数据(子传父)
  console.log(this.$parent.val) // 访问父组件 App 的某个数据(父传子)
  console.log(this.$parent.handleClick) // 也可以是某个方法
}

(3) $refs(访问具体DOM节点)

ref 后面自定义节点名称,从而实现在 js 中访问,访问的方式是 this.$refs.自定义名称

<!-- Father.vue -->
<child ref="child"></child>
// Father.vue
mounted () {
  console.log(this.$refs.child)
}

2. 非父子组件传值

(1) 事件总线

原理:建立一个公有的 js 文件,专门来传递消息。

// 在 util 文件夹下新建 bus.js
import Vue from 'vue'
export default new Vue()

// 在需要传递消息或者接收消息的地方引入
import bus from './bus.js'

// 点击事件中传递自定义事件,发送消息
bus.$emit('msg', val)

// 监听事件,接收消息
bus.$on('msg', val => {
  console.log(val)
})

(2) $attrs / $listeners

爷传孙:$attrs 将父组件中不包含 props 的属性传入子组件,通常配合 inheritAttrs 选项一起使用。

// 祖孙组件传值 App => Father => Child
// App.vue 绑定属性将祖辈组件中 msg、title 传递给父组件
<father :msg="msg" :title="title"></father>
// Father.vue 在父组件上绑定 v-bind="$attrs" 
<child v-bind="$attrs"></child>
// Child.vue 孙子组件获取到祖父组件的数据
mounted () {
  console.log(this.$attrs)
}

$listeners 监听子组件中数据变化,传递给父组件。(略)

(3) vuex

见第四章、第五章


三、Vue Router

1. 路由的基本配置

(1) router 配置(路由懒加载)

// index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    {
      path: '/home',
      name: 'home',
      component: () => import('../components/Home.vue') // 懒加载:动态导入,按需加载
    }
  ]
})

export default router

(2) 路由视图

App.vue,在合适的位置加上以下代码:

<router-view></router-view>

Vue核心知识点
一、vue.config.js 基本配置
二、vue组件间传值
三、Vue Router
四、Vuex 基础用法
五、Vuex 高级用法
六、Element UI
七、弹出类型组件
八、表格组件

2. 路由的跳转

(1) router-link

<router-link to="/home">跳转</router-link>
<router-view></router-view>

(2) 编程式导航 this.$router.push( { ... } )

<button @click="handleGo">js 跳转</button>
<router-view></router-view>
methods: {
  handleGo () {
    this.$router.push({
      path: 'home'
    })
  },
  // handleGo () {
  //  this.$router.push({
  //    name: 'home'
  //  })
  // }
}

3. 动态路由

(1) 基本配置

// router 目录下的 index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    {
      path: '/home/:id', // 动态路由,id 是自定义的参数名
      name: 'home',
      component: () => import('../components/Home.vue')
    }
  ]
})

export default router

通过 $route.params.动态参数名 可以访问到动态参数:

<!-- Home.vue -->
<template>
  <div>
    <h2>Home 页</h2>
    <p>路由动态参数:{{$route.params.id}}</p>
  </div>
</template>

(2) 编程式导航的传参

传参有两种形式,

  • 一种是查询字段的传参。(path + query)
// App.vue (path + query)
methods: {
  handleGo () {
    this.$router.push({
    	path: 'home',
    	query: {
        name: 'jack',
        gender: 'male',
        age: 18
      }
		})
  }
}

点击跳转按钮后,数据被传递到了 url 中:

Vue核心知识点
一、vue.config.js 基本配置
二、vue组件间传值
三、Vue Router
四、Vuex 基础用法
五、Vuex 高级用法
六、Element UI
七、弹出类型组件
八、表格组件

  • 一种是动态路由参数的传参。(name + params)
// App.vue (name + params)
methods: {
  handleGo () {
    this.$router.push({
      name: 'home',
      params: {
        id: 123
      }
    })
  }
}

Vue核心知识点
一、vue.config.js 基本配置
二、vue组件间传值
三、Vue Router
四、Vuex 基础用法
五、Vuex 高级用法
六、Element UI
七、弹出类型组件
八、表格组件

4. 嵌套路由

在 Home 页的一个区域显示一个路由页面,这个新的路由页面属于 home 路由,因此就要将它写在home路由规则下。

Home.vue
	|- Child.vue

(1) 路由规则配置

在 home 路由下添加 children 选项,配置新的路由规则。

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    {
      path: '/home/:id',
      name: 'home',
      component: () => import('../components/Home.vue'),
      children: [ // 新路由 Child.vue 写在 children 选项下
        {
          path: '/child',
          component: () => import('../components/Child.vue')
        }
      ]
    }
  ]
})

export default router

(2) 路由视图

router-view 也理应写在 Home.vue 下。

<!-- Home.vue -->
<template>
  <div>
    <h2>Home 页</h2>
    <p>路由动态参数:{{$route.params.id}}</p>
    
    <!-- Child.vue 的视图将会在此处展示 -->
    <router-view></router-view>
    
  </div>
</template>

<script>
export default {
  name: 'home'
}
</script>

<style lang='stylus' scoped>

</style>

5. 导航守卫

在 main.js 中加入以下代码:

// main.js
router.beforeEach((to, from, next) => {
  console.log('从这出发:', from.path)
  console.log('到达此处:', to.path)
  next()
})

在 '/' 处点击按钮后,跳转到 '/home/123'

Vue核心知识点
一、vue.config.js 基本配置
二、vue组件间传值
三、Vue Router
四、Vuex 基础用法
五、Vuex 高级用法
六、Element UI
七、弹出类型组件
八、表格组件


四、Vuex 基础用法

公共数据仓库。

Vue核心知识点
一、vue.config.js 基本配置
二、vue组件间传值
三、Vue Router
四、Vuex 基础用法
五、Vuex 高级用法
六、Element UI
七、弹出类型组件
八、表格组件

  • State
    • 数据
  • Mutations
    • 数据怎么变(同步)
  • Actions
    • 异步改变

1. store 仓库创建

// store 目录下的 index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  // 公共数据
  state: {
    count: 0
  },
  
  // 数据怎么变(同步):每个方法下都有一个参数 state 可以访问到公共数据
  mutations: {
    add (state) {
      state.count++
    },
    decrese (state) {
      state.count--
    }
  },
  
  // 异步修改数据:方法下有一个形参 context,通过 context.commit('变更方法名') 来提交变更方法,告诉它数据怎么变
  actions: {
    // 模拟异步操作
    delayAdd (context) {
      // 一秒后,调用 add 方法
      setTimeout(() => {
        context.commit('add')
      }, 1000)
    }
  }
})

2. 在视图中使用公共数据

(1) 常规方式

在需要用到公共数据的地方,通过计算属性引进 store 仓库中数据。

通过 this.$store.state.数据名 可以获取到公共数据。

// vue 实例
computed: {
  count () {
    return this.$store.state.count
  }
},
<template>
  <div>
    <p>公共数据来了!它是:===> <span style="color:red">{{count}}</span></p>
  </div>
</template>

(2) 辅助函数:mapState

https://vuex.vuejs.org/zh/guide/state.html#mapstate-%E8%BE%85%E5%8A%A9%E5%87%BD%E6%95%B0

当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键。(注意,放在计算属性中!)

import { mapState } from 'vuex' // 首先导入辅助函数 mapState

export default {
  computed: {
    ...mapState({ // 通过展开运算符将对象展开
      // 传字符串参数 'count' 等同于 `state => state.count`
      count: 'count'
      
      // 箭头函数可使代码更简练
    	// count: state => state.count
    })
  }
}

关于展开运算符:https://blog.csdn.net/adsadadaddadasda/article/details/79391881

3. 触发 Mutations 修改数据(同步)

(1) 修改数据 this.$store.commit('xxx')

<!-- html -->
<p>公共数据来了!它是:===> <span style="color:red">{{count}}</span></p>
<button @click="handleAdd">改变公共数据 (add)</button>
// vue 实例
// vue 组件 => commit('变更方法名') => Mutations => state => vue 组件
methods: {
  handleAdd () {
    this.$store.commit('add') // 此时触发的就是 store 仓库中 Mutations 下的 add 方法
  }
}
// store 中的变更方法名
mutations: {
  add (state) {
    state.count++
  },
  decrese (state) {
    state.count--
  }
}

(2) 辅助函数:mapMutation

https://vuex.vuejs.org/zh/guide/mutations.html#%E5%9C%A8%E7%BB%84%E4%BB%B6%E4%B8%AD%E6%8F%90%E4%BA%A4-mutation

你可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。(注意,放在 methods 中!)

import { mapMutations } from 'vuex' // 首先导入辅助函数 mapMutations

export default {
  methods: {
    ...mapMutations({
      handleAdd: 'add' // // 将 this.handleAdd() 映射为 this.$store.commit('add')
    })
  }
}

4. 触发 Actions 修改数据(一般为异步)

(1) 修改数据 this.$store.dispatch('xxx')

<!-- html -->
<p>公共数据来了!它是:===> <span style="color:red">{{count}}</span></p>
<button @click="handleAdd">改变公共数据 (add)</button>
// vue 实例
// vue 组件 => dispatch('异步方法名') => Actions => commit('变更方法名') => Mutations => vue 组件
methods: {
  handleAdd () {
    this.$store.dispatch('delayAdd')
  }
}
// store 中的 actions 异步方法名
actions: {
  delayAdd (context) {
    // 一秒后,调用 Mutations 中的 add 方法
    setTimeout(() => {
      context.commit('add')
    }, 1000)
  }
}

(2) 辅助函数:mapActions

https://vuex.vuejs.org/zh/guide/actions.html#%E5%9C%A8%E7%BB%84%E4%BB%B6%E4%B8%AD%E5%88%86%E5%8F%91-action

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

import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions({
      handleAdd: 'delayAdd' // // 将 this.handleAdd() 映射为 this.$store.dispatch('delayAdd')
    })
  }
}

五、Vuex 高级用法

1. Vuex 中的计算属性:Getters

getters 中的数据依赖于 state 中的数据。

// store
state: {
  count: 0
},
getters: {
  doubleCount (state) {
    return state.count * 2
  }
}

(1) 常规方式

<!-- html -->
<p>公共数据来了!它是:===> <span style="color:red">state: {{count}}</span></p>
<p>公共数据来了!它是:===> <span style="color:green">getters: {{doubleCount}}</span></p>
<button @click="handleAdd">改变公共数据 (add)</button>
// vue 实例
computed: {
	// ...
  doubleCount () {
    return this.$store.getters.doubleCount
  }
}

当点击按钮时,state.count++,因为 doubleCount 依赖于 state.count,因此会同时发生计算。

(2) 辅助函数:mapGetters

https://vuex.vuejs.org/zh/guide/getters.html#mapgetters-%E8%BE%85%E5%8A%A9%E5%87%BD%E6%95%B0

mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性

import { mapGetters } from 'vuex'

export default {
  computed: {
    // ...mapGetters(['doubleCount']) // 参数名和方法名一致
    
    ...mapGetters({
      doubleCount: 'doubleCount'
    })
  }
}

2. 模块化:Modules

各个模块各司其职,管理自己的数据。

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

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

https://vuex.vuejs.org/zh/guide/modules.html#module

(1) 模块分离

  • 在 store 文件夹下新建一个 js 文件(模块),将这个模块起名为 handleCount。
// handleCount.js
// handleCount模块
export default {
  state: {
    count: 0
  },
  getters: {
    doubleCount (state) {
      return state.count * 2
    }
  },
  mutations: {
    add (state) {
      state.count++
    },
    decrese (state) {
      state.count--
    }
  },
  actions: {
    delayAdd (context) {
      // 一秒后,调用 add 方法
      setTimeout(() => {
        context.commit('add')
      }, 1000)
    }
  }
}
  • 引入 index.js 主模块中
import Vue from 'vue'
import Vuex from 'vuex'
import handleCount from './handleCount' // 引入模块 handleCount

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    handleCount
  }
})

因为使用了模块,所以原来的 state 指向都会发生变化。

例如访问 count 数据,不再是 this.$store.state.count,而是 this.$store.state.handleCount.count。(this.$store.state.模块名.数据名)

  • 使用箭头函数
// vue 实例中的 computed 选项
...mapState({
  count: state => state.handleCount.count
})

(2) 命名空间

如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

https://vuex.vuejs.org/zh/guide/modules.html#%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4

// handleCount 模块
export default {
  namespaced: true, // 添加命名空间字段,其他照旧
  // ...
}

当添加了命名空间选项时,所有的辅助函数的映射效果就会发生错误,这时要手动调整过来:

// 原代码:
// computed
...mapGetters({
  doubleCount: 'doubleCount'
})
// methods
...mapActions({
  handleAdd: 'delayAdd'
})

// <=============================================================================================>

// 调整后:
// computed
...mapGetters({
  doubleCount: 'handleCount/doubleCount'
})
// methods
...mapActions({
  handleAdd: 'handleCount/delayAdd'
})

关于命名空间:https://blog.csdn.net/lzb348110175/article/details/89387495


六、Element UI

1. 安装依赖

cnpm i element-ui --save

--save 表示依赖包被安装到了生产环境中。(简写 -S)

 i  是 install 的简写
-S 就是 --save 的简写
-D 就是 --save-dev 的简写

npm i module_name -S = > npm install module_name --save 写入到 dependencies 对象

npm i module_name -D => npm install module_name --save-dev 写入到 devDependencies 对象

npm i module_name -g 全局安装

关于指令:https://www.cnblogs.com/del88/p/13272767.html

2. 引入 Element

// main.js
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import App from './App.vue'

Vue.use(ElementUI)

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

3. 布局组件使用

<h3>div块 4等分布局</h3>
<el-row :gutter="20">
  <el-col :span='6'><div class="content">1</div></el-col>
  <el-col :span='6'><div class="content">2</div></el-col>
  <el-col :span='6'><div class="content">3</div></el-col>
  <el-col :span='6'><div class="content">4</div></el-col>
</el-row>

<h3>整块页面布局</h3>
<el-container>
	<el-header>Header</el-header>
	<el-main>Main</el-main>
	<el-footer>Footer</el-footer>
</el-container>

gutter 表示间隔,span 表示占用份数。(一行共 24 份)

el-header el-aside el-main el-footer 的父容器只能是 el-container,el-container 的子容器也只能是前四者。


七、弹出类型组件

1. Dialog 对话框

https://element.eleme.cn/2.0/#/zh-CN/component/dialog#dialog-dui-hua-kuang

<template>
  <div>
    <el-button type="text" @click="dialogVisible = true">点击打开 Dialog</el-button>

    <el-dialog title="提示" :visible.sync="dialogVisible" width="30%" :before-close="handleClose">
      <span>这是一段信息</span>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'pop',
  data () {
    return {
      dialogVisible: false
    }
  },
  methods: {
    handleClose (done) {
      this.$confirm('确认关闭?')
        .then(_ => {
          done()
        })
        .catch(_ => {})
    }
  }
}
</script>

<style lang='stylus' scoped></style>

2. Popover 弹出框

https://element.eleme.cn/2.0/#/zh-CN/component/popover#popover-dan-chu-kuang

<el-popover
  ref="popover1"
  placement="top-start"
  title="标题"
  width="200"
  trigger="hover"
  content="这是一段内容,这是一段内容,这是一段内容,这是一段内容。">
</el-popover>
<el-button v-popover:popover1>hover 激活</el-button>

八、表格组件

1. 基础表格

<el-table
	:data="tableData"
	style=" 100%"
	height="500"
	border
>
  <el-table-column
		prop="date"
		label="日期"
     width="180">
  </el-table-column>
  <el-table-column
		prop="name"
		label="姓名"
		width="180">
  </el-table-column>
  <el-table-column
		prop="address"
		label="地址">
  </el-table-column>

  <el-table-column label="操作">
    <template slot-scope="scope">
      <el-button
				size="mini"
         @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
      <el-button
				size="mini"
         type="danger"
         @click="handleDelete(scope.$index, scope.row)">删除</el-button>
    </template>
  </el-table-column>
</el-table>
export default {
  name: 'tableList',
  data () {
    return {
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1519 弄'
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1516 弄'
      }]
    }
  },
  methods: {
    handleEdit (index, row) {
      console.log(index, row)
    },
    handleDelete (index, row) {
      console.log(index, row)
    }
  }
}

2. el-table 表格常用属性

属性名 作用
height 给表格设置高度,同时固定表头。
show-header 设置是否显示表头。
row-class-name 设置一个函数或者固定的名字作为行的类名。
border 是否显示表格竖直方向的边框,设置后可通过改变边框来设置列宽。

3. el-column 列常用属性

属性名 作用
label 当前列的表头名称
prop 传入的表格 json 数据的 key 值
show-overflow-tooltip 是否设置文字超出列宽时悬浮显示完整内容

4. 通过 v-for 封装更好的表格

<el-table :data='tableData'>
  <el-table-column v-for="(val, key) of tableLabel" :key='key' :prop='key' :label='val'></el-table-column>
  
  <el-table-column label="操作">
    <template slot-scope="scope">
      <el-button
				size="mini"
         @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
      <el-button
         size="mini"
         type="danger"
         @click="handleDelete(scope.$index, scope.row)">删除</el-button>
    </template>
  </el-table-column>
</el-table>
export default {
  name: 'tableList',
  data () {
    return {
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1519 弄'
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1516 弄'
      }],
      tableLabel: {
        date: '日期',
        name: '姓名',
        address: '地址'
      }
    }
  },
  methods: {
    handleEdit (index, row) {
      console.log(index, row)
    },
    handleDelete (index, row) {
      console.log(index, row)
    }
  }
}