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>
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 中:
- 一种是动态路由参数的传参。(name + params)
// App.vue (name + params)
methods: {
handleGo () {
this.$router.push({
name: 'home',
params: {
id: 123
}
})
}
}
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'
四、Vuex 基础用法
公共数据仓库。
- 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.****.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
你可以在组件中使用 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
你在组件中使用 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.****.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)
}
}
}