19.使用 vue-cli脚手架创建模板项目
/**
* 脚手架2:
* 安装脚手架命令 脚手架2的命令
* npm install -g vue-cli
* 下载模版命令
* vue init webpack my-project 配置中除了eslint为y,其它都为n
*
* npm run dev 或 npm start 运行项目命令---不会自动打开浏览器
在config目录中的index.js文件中的第18行代码:autoOpenBrowser: true 修改为true,自动打开浏览器
在build目录中的webpack.base.conf.js文件中第25行: app: './src/main.js' 是整个项目的入口文件
* npm run build 打包 产生dist目录
* serve dist 运行打包文件
*
* 如果你用的是yarn 下载的,那么运行项目的时候 yarn 是不需要写run的
*
* node_modules 依赖包目录
* eslint检查的问题
* build目录是webpack的相关的设置
* config目录配置文件,里面的index.js中可以设置是否让浏览器自动打开
* dist目录---打包后的目录文件
* node-modules--依赖包---相关的文件
* static---存放的是静态资源,css样式,图片,字体
* babelrc---文件--babel的相关配置----mint-ui中配置
* .eslintignore---->可以直接用 *.vue 或者*.js 的方式全局的忽略检查
* .eslintrc.js 文件中 rules---一项一项的配置eslint的相关检查----看我操作
* index.html----项目主入口html文件
* package.json配置文件
* src目录
* main.js程序的主入口的js文件
* App.vue父级组件文件
* assets目录---图片---直接干掉----不用
* components目录-------里面放的都是组件文件(.vue后缀的文件,叫组件文件)
* 组件:html+css+js----形成的一个.vue文件---组件
* 组件:具有一定功能效果的集合,里面包含html+css+js
* 抽取了多个的组件,就形成了组件化
* 源码的分析:
* scoped:有可能会影响父子级组件之间的样式
脚手架3:
脚手架3的下载命令
npm install -g @vue/cli
注意:如果电脑中安装了脚手架2了,不能直接安装脚手架3,必须要先干掉电脑中脚手架2,然后再安装脚手架3
npm uninstall vue-cli -g 干掉脚手架2
通过脚手架3下载模版的命令
vue create app-client3
脚手架3 启动 的命令和 打包 打包命令
npm run serve(开发环境)
npm run build(生产环境)
serve dist
脚手架3中浏览器自动打开的设置,package.json 中 进行设置
"scripts": {
"serve": "vue-cli-service serve --open",//添加--open
},
脚手架3main.js文件
new Vue({
render: h => h(App),//在内存中渲染App组件
}).$mount('#app') // 获取id为app的html容器通过$mount进行挂载
脚手架3关闭eslint检测
1.在package.json文件中的"rules": {}关闭相关的eslint语法检查
2.或者在vue.config.js文件中进行配置的方式关闭eslint语法检查
module.exports = {
lintOnSave:false
}
3.或者在package.json文件中删掉eslint依赖和eslintConfig配置
*/
20.main.js和App.vue模板
1)main.js
import Vue from 'vue'
import App from './App.vue'//1.引入组件
new Vue({
el: '#app',
components: {App}, // 2.注册组件标签
template: '<App/>' // 3.使用组件模板
})
2)在App根主组件引入其他组件
<template>
<div>
//3.使用组件模板
<HelloWorld/>
</div>
</template>
<script>
//1.引入组件
import HelloWorld from './components/HelloWorld.vue'
export default {
name:'App',// 当前组件名字
//2.注册组件标签
components: {
HelloWorld
}
}
</script>
!! // scoped让组件样式独立存在,不会受其它组件样式影响
<style scoped>
.logo {
width: 100px;
height: 100px;
}
</style>
21.组件间的通信
1)props(父-->子)
1.父组件传输属性给子组件
//comments是data属性
<List :comments="comments"/>
2.子组件接收父组件属性
方法1:
export default {
// 接收属性,指定属性名
props:['comments']
}
方法2:
export default {
// 接收属性,指定属性名、属性值的类型
props:{
comments:Object
}
}
方法3(完整版):
export default {
// 接收属性,指定属性名、属性值得类型和必要性
props:{
comments:{
type:Object,
required:true,
default:{} 指定comments的默认值
}
}
}
2)自定义事件 (事件父-->子,属性子-->父)
1. 绑定事件监听 (父)
通过 v-on 绑定 :@delete_todo="deleteTodo"
delete_todo是自定义事件名称,deleteTodo是自定义事件触发的回调函数
2. 触发事件 (子)
//eventName是触发自定义事件名称,data是传递给事件回调函数数据
this.$emit(eventName, data)
3. 解绑事件(子)
this.$off(eventName) // 取消对应的事件
this.$off() // 取消全部的事件
3)vue 插槽
设置在自组件内部的插槽像一个盒子,位置由子组件决定,放什么内容由父组件决定。
实现了内容分发,提高了组件自定义的程度,让组件变的更加灵活
1)默认插槽:无需name属性,取子组件肚子里第一个元素节点作为默认插槽。
<!-- 子组件,组件名:child-component -->
<div class="child-page">
<h1>子页面</h1>
<slot></slot> <!-- 替换为 <p>hello,world!</p> -->
</div>
<!-- 父组件 -->
<div class="parent-page">
<child-component>
<p>hello,world!</p>
</child-component>
</div>
<!-- 渲染结果 -->
<div class="parent-page">
<div class="child-page">
<h1>子页面</h1>
<p>hello,world!</p>
</div>
</div>
2.具名插槽:
在多个插槽的情况下使用,利用name标识插槽。
<!-- 子组件,组件名:child-component -->
<div class="child-page">
<h1>子页面</h1>
<slot name="header"></slot>
<slot></slot> <!-- 等价于 <slot name="default"></slot> -->
<slot name="footer"></slot>
</div>
<!-- 父组件 -->
<div class="parent-page">
<child-component>
<template v-slot:header>
<p>头部</p>
</template>
<template v-slot:footer>
<p>脚部</p>
</template>
<p>身体</p>
</child-component>
</div>
<!-- 渲染结果 -->
<div class="parent-page">
<div class="child-page">
<h1>子页面</h1>
<p>头部</p>
<p>身体</p>
<p>脚部</p>
</div>
</div>
3.作用域插槽:
子组件给父组件传递数据。
<!-- 子组件,组件名:child-component -->
<div class="child-page">
<h1>子页面</h1>
<slot name="header" data="data from child-component."></slot>
</div>
<!-- 父组件 -->
<div class="parent-page">
<child-component>
<template v-slot:header="slotProps">
<p>头部: {{ slotProps.data }}</p>
</template>
</child-component>
</div>
<!-- 渲染结果 -->
<div class="parent-page">
<div class="child-page">
<h1>子页面</h1>
<p>头部: data from child-component.</p>
</div>
</div>
4) ref(子-->父)
<Footer ref="Footer"></Footer>
// 获取子组件进行一系列操作
this.$refs.Footer.innerHTML
5)事件总线(任意组件)
通过在Vue原型上添加一个$bus实例对象,这样不同组件通过this.$bus.$on()绑定的事件就是同一个事件,
不同组件就可以通过this.$bus.$emit()去触发
1.定义事件总线
Vue.prototype.$bus=new Vue()
2.绑定事件
// delete_todo是自定义事件名称,data是触发事件是传递过来的数据
this.$bus.$on('delete_todo', function (data) {})
3.触发事件
//eventName是触发自定义事件名称,data是传递给事件回调函数数据
this.$bus.$emit(eventName, data)
4.解绑事件
this.$off(eventName) // 取消对应的事件
this.$off() // 取消全部的事件
6)订阅消息与发布消息(任意组件间通信)
1.下载pubsub 库
npm i pubsub-js
import PubSub from 'pubsub-js'
2.订阅消息(相当于绑定事件)
//前后msg都是订阅消息名称,data需要的数据
this.token=PubSub.subscribe('msg', function(msg, data){})
3.发布消息
//data传递过去的数据
PubSub.publish('msg', data)
4.取消订阅消息
// 参数不传就取消所有订阅的消息
PubSub.unsubscribe(this.token)
7) vuex(后面单独讲)
7) Vue.observable({count:0,name:'李四'})
让一个对象可响应,实现多个组件共享数据状态
//首先创建一个 store.js,包含一个 store和一个 mutations,分别用来指定共享的数据和改变数据的方法。
//store.js
import Vue from 'vue';
//store={count:0,name:'李四'},并且该对象可响应
export let store =Vue.observable({count:0,name:'李四'});
export let mutations={
setCount(count){
store.count=count;
},
changeName(name){
store.name=name;
}
}
export let getters={
getCount(){
return store.count
}
}
//使用
import HomeHeader from '../components/HomeHeader'
import {store,mutations,getters} from '@/store'
export default {
data () {
return {
name1:'主页的name'
}
},
components: {
HomeHeader
},
computed:{
//获取store中的状态数据
count(){
return store.count
},
name(){
return store.name
},
getCount(){
return getters.getCount()
}
},
methods:{
//获取改变store中状态数据的方法
setCount:mutations.setCount,
changeName:mutations.changeName
}
}
8) 组件通信高级部分
1.v-model深入(父传给子属性和修改父级属性的方法)
1)父级中
// v-model的本质:使用value属性配合input事件来实现的
// 相当于传递了一个value属性和更新value的@input事件,事件的第二个参数就是value的最新值
<CustomInput v-model="msg3" />
<CustomInput :value="msg3" @input="msg3=$event" />
2)子组件中
// value值父级中的msg3,父组件中的$event是子组件中的$event.target.value
<input :value="value" @input="$emit('input',$event.target.value)" />
2.属性修饰符sync(父传给子属性和修改父级属性的方法)
1)父级中
// 第一个和第二个是一样的,相当于父组件给子组件传递了money和更新money的update:money方法
// 发布事件的第二个参数就是修改后的money
<Child :money.sync="total" />
<Child :money="total" @update:money="total=$event" />
2)子组件中
<button @click="$emit('update:money',money-100)">花钱</button>
3.$attrs与$listeners(父传子)
1)父级中
<LinkButton title="添加" type="primary" icon="el-icon-plus" @click="add" />
2)子组件中
// v-bind="$attrs"相当于v-bind="{ type: primary, icon: el-icon-plus }"
// title属性在props中接收,所以$attrs对象中不包含title属性
// $attrs属性也是对象,该对象内部包含标签(组件)上传递的所有的属性(不包括prop,class,style)
// $listeners属性也是对象,该对象内部包含标签(组件)上传递的所有事件
// v-on="$listeners"相当于v-on="{ click: add}
<el-button v-bind="$attrs" v-on="$listeners"></el-button>
4.$children与$parent(父修改子,子修改父)
1)父级中
// 获取当前父级组件中的所有的子级组件,进行遍历操作
this.$children.forEach(child => {
child.pullMoney(500)
this.money += 1000
})
2)子组件中
// 可以操作父级组件的属性
this.$parent.money += money
22.vue 常用UI 组件库
1) Mint UI (用于移动端)
主页: http://mint-ui.github.io/#!/zh-cn
说明: 饿了么开源的基于 vue 的移动端 UI 组件库
1.下载:
npm install --save mint-ui
!! 2. 实现按需打包 :这样就可以不用引入样式了,用到什么样式会自动引入
1. 下载 npm install --save-dev babel-plugin-component
2. 修改 babel 配置
"plugins": ["transform-runtime",["component", [
{
"libraryName": "mint-ui", "style": true
}
]]]
3) 在main.js文件中编程
import {Button} from 'mint-ui'
// 将组件映射成全局标签,这样所有组件就可以使用这个组件了,Button.name是框架提供的组件标签mt-button
!! Vue.component(Button.name, Button)
!! 补充:还可可以在要使用的组件当中引入,这样只有该组件可以使用
import { MessageBox } from 'mint-ui';
编程App.vue
<template>
<mt-button @click="handleClick" type="primary" style="width: 100%">Test</mt-button>
</template>
<script>
import {Toast} from 'mint-ui'
export default {
methods: {
handleClick () { Toast('点击了测试'); }
}
}
</script>
2) Element (用于PC端)
1.button按钮属性
1)icon:图标
2)size:大小
3)type:类型
4)loading:为true加载状态不能点击按钮,false相反
2.table表格属性
1):data:展示的数据
2)stripe:斑马纹
3)border:边框
4)selection-change:单选框选项发生改变触发的回调
5)height:高度
3.table-column表格列属性
1)prop:展示的列数据(列标签中方内容,prop就没效果了)
2)type="index":展示的列数据为下标,优先级高于prop
3)align:对齐方式
4)v-loading:值为true显示加载效果,值为false不显示加载效果
5)label:标题
6)type=selection:出现单选框
7)width:宽度
8)fixed="right":当前列固定
9)sortable:上下排序标识
补充:<template slot-scope="scope"></template>:scope里面包含$index和row的属性的对象
$index:当前的下标,row:当前这一行的数据对象(trademark)
4.message信息框属性
1)error():错误信息
2)success():成功信息
3)warning():警告信息
5.pagination分页属性
1)current-page:默认第几页被选中
2)page-sizes="[3, 6, 9, 12]":可以设置每页显示的条数
3)page-size:默认每页条数
4)total:总的条数
5)layout:代表的是页面中分页布局的显示顺序
6)background:背景颜色
7)@current-change:页码发生变化触发的回调
8)@size-change:设置每页显示的条数触发的回调
6.dialog对话框属性
1)title:标题
2)visible.sync:控制对话框的显示与隐藏
3)before-close:对话框关闭前的回调
4)show-close="false":不显示叉号
5)close-on-click-modal="false":点击灰色地方对话框不消失
7.form表单属性
1)rules:表单验证
2)inline:表单项成行排列
3)model:表单内使用到的数据
4)label-width:所有表单前面文字宽度,一般用来对齐表单项
8.form-item表单项属性
1)label:表单项前面显示的标题
2)label-width:表单前面文字宽度
3)prop:表单验证项添加prop属性
9.input框属性
1)autocomplete:是否显示输入过的内容 off/on
2)readonly:只读
10.autocomplete远程搜索
1)fetch-suggestions:搜索时触发的回调,参数一:搜索内容,参数二:一个回调函数,接收一个要展示的数组
2)select:点击提示内容触发
10.input-number计数器
1)min:最小值
2)max:最大值
10.select下拉框属性
1)@change:下拉框内容发送变化触发的回调,组件会自动把下拉框的值作为参数传给回调函数
2)placeholder:提示信息
11.option下拉框属性
1)label:显示给用户看的选择项
2)value:下拉框真正的值
3)key:每项下拉框的唯一标识
12.upload属性
1)action:文件上传地址
2)on-success:图片上传成功的回调
3)before-upload:图片上传成功前的回调
4)multiple:支持一次性选择多张图片
5)file-list:展示的图片
6)on-preview:预览图片触发的回调
7)on-remove:删除图片触发的回调
8)list-type="picture-card":图片成照片墙形式
13.confirm框
// 参数一:提示内容,参数二:标题,参数三:配置对象,then按确定按钮执行,catch按取消按钮执行
this.$confirm(`确定删除${trademark.tmName}吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {})
.catch(() => {})
14.card卡片属性
15.Tag标签属性
1)type:类型
2)closable:显示x号
3)@close:点击x号触发的回调
16.Popconfirm气泡确认框属性
1)title:提示标题
2)slot="reference":给那个标签按钮加上这个属性,在点击标签按钮的时候就会出现气泡确认框属性
17.drawer抽屉属性
1)visible:是否显示
2)before-close:关前回调
3)direction:打开方向
4)withHeader:是否带头部标题
18.layout布局,<el-row></el-row>:行, <el-col :span="24"></el-col>:行里面的一项,一行总共24分,特殊点5分的话字体加粗靠右
19.Carousel 走马灯(轮播图)属性
1)trigger:轮播图的触发方式
2)autoplay:是否自动播放
3)arrow:切换箭头的显示时机
4)height:高度
20.carousel-item轮播图一项
21.dropdown:下拉菜单
1)command:点击下拉菜单项触发,点击项作为事件参数
22.dropdown-item:下拉菜单项
1)command:下拉菜单项,作为点击回调的参数
2)divided:给下拉菜单项添加分割线
23.breadcrumb:面包屑
1)separator="/":用斜杆分割面包屑每项
24.breadcrumb-item:面包屑每项
1)to:点击面包屑要跳转的路由地址
25.scrollbar:滚动栏,内容超出生成滚动条
26.menu:菜单栏
router:检测menu-item的index属性,跳转到相应的路由地址
default-active:当前展示的路由路径
27.menu-item:菜单栏每一项
index:绑定路由地址,点击时router会监视index值,跳转到对应的路由页面
28.submenu:含有多个子元素的菜单栏每一项
index:绑定路由地址,点击时router会监视index值,跳转到对应的路由页面
29.date-picker:时间选择器
type="date":类型为时间选择器
value-format:时间格式
v-model:时间
30.radio-group:一组单选框
1)v-model:选择项
31.radio:每项单选框
1)label:展示内容
2)name:名字
32.tabs:选项卡
1)type="border-card":加边框
2)v-model="tabPosition":默认选中项
33.tab-pane:选项卡每项
1)label:显示在选项卡上的标题
2)name:名字
23.vue 项目中常用的 2 个 ajax 库
1)vue-resource(在主js文件引入使用,少用)
vue 插件, 非官方库, vue1.x 使用广泛
1.下载
npm install vue-resource --save
2.使用
!! // 在main.js文件中引入模块
import VueResource from 'vue-resource'
// 使用插件,内部会给vm对象和组件对象添加一个属性$http,$http有get()和post()方法
Vue.use(VueResource)
// 通过 vue组件对象发送 ajax 请求
this.$http
.get('/someUrl')
.then((response) => {
console.log(response.data) //返回结果数据
},
(response) => {
console.log(response.statusText) //错误信息
})
2)axios(那个组件使用在哪里引入)
1.下载
npm install axios --save
2.使用
// 引入模块
import axios from 'axios'
// 发送 ajax 请求
axios
.get(url)
.then(response => {
console.log(response.data) // 得到返回结果数据
})
.catch(error => {
console.log(error.message)
})
24.vue-router(路由)
1) 路由:一种映射关系:地址和组件的关系,路由链接(相当于a标签)和路由视图(组件页面)的一种关系,专门用来实现单页面应用程序(SPA)
2) github: https://github.com/vuejs/vue-router
3) 中文文档: http://router.vuejs.org/zh-cn/
4) 下载: npm install vue-router --save
5) 使用路由3步
1.创建一个router的目录,内部有一个index.js文件,在index.js文件中创建、配置并暴露路由
// 引入Vue
import Vue from 'vue'
// 引入vue-router
import VueRouter from 'vue-router'
// 声明使用插件
Vue.use(VueRouter)
// 创建、配置并暴露路由器
export default new VueRouter({
mode:'history' , // 路由方式:history---地址栏中没有# hash ----地址栏中有#(默认)
// 配置路由
routes: [
{ path: '/about', component: About },
{ // 路由重定向,页面开始默认显示的路由组件
path: '/',
redirect: '/about',
},
{ // 嵌套路由
path: '/about',
component: About,
!! // 子路由可以是/about/news也可以是news
children: [ { path: '/about/news', component: News } } ]
},
{//*号代表所有路由都没有匹配到,重定向到错误页面
path: '*',
redirect: '/404'
},
scrollBehavior (to, from, savedPosition) {//路由跳转页面停留的位置
return {//顶部
x:0,
y:0
}
}
})
2. 在main.js文件中让路由和实例对象建立联系
import router from './router'
new Vue({ router })
3. 使用路由
1) <router-link>: 用来生成路由链接
<router-link to="/xxx"></router-link>
2) <router-view>: 用来显示当前路由组件界面
<router-view></router-view>
4. 如何向路由组件传递参数
1)声明式路由传参
1.params方式传参
//用:id占位
routes: [
!! {
name: 'about',//使用对象name方式传参添加name属性(命名路由)
path: '/about/:id?',//添加?代表传不传参数都会跳转路由
component: About
}
]
//传参
<router-link :to="`/about/${message.id}`"></router-link> //字符串
或者
<router-link :to="{ name: 'about' ,params:{id:message.id}"></router-link> //对象
// 接收参数(在传递和接收路由组件上都可以通过此方式获取参数)
this.$route.params.id
2.query方式传参
{
name: 'about',//使用对象name方式传参添加name属性(命名路由)
path: '/about',
component: About
}
//传参
<router-link to="/about?age=18&name='joke'">About</router-link> //字符串
或者
<router-link :to="{path:'/about',query:{id:message.id}}"></router-link> //对象
或者
<router-link :to="{name:'about',query:{id:message.id}}"></router-link> //对象
//获取参数
this.$route.query.id
3.meta方式传参
{
path: '/about',
component: About,
meta: {//传参
isShow: true
}
}
<router-link to="/about">About</router-link>
//获取参数
this.$route.meta.isShow
4.props方式传参
1)布尔模式
//用:id占位
{
path: '/about/:id',
component: About,
props:true
}
//传参
<router-link to="/about/12345">About</router-link>
//接收参数
props:['id']
2.对象模式
{
path: '/about',
component: About,
props:{
msg:'脑瓜疼'
}
}
<router-link to="/about">About</router-link>
props:['msg']:接收参数
3.函数模式
//用:id占位
routes: [
{
path: '/about/:id',
component: About,
props: (route) => ({ id: route.params.id }
},
]
//传参
<router-link :to="`/about/${message.id}`"></router-link>
//接收参数
props:['id']
2)编程式路由传参
1.params传参
//用:id占位
routes: [
{
name: 'search' ,//使用对象name方式传参添加name属性(命名路由)
path: '/about/:id',
component: About
}
]
//传参
this.$router.push('/search/123')
或者:
this.$router.push({ name: 'search' ,params:{keyword:this.keyword}})
//接收参数
this.$route.params.id:获取路由参数(在传递和接收路由组件上都可以通过此方式获取参数)
2.query传参
routes: [
{
name: 'search' ,//使用对象name方式传参添加name属性
path: '/about',
component: About
}
]
//传参
this.$router.push(`/search?keyword=${this.keyword}`)
或者
this.$router.push({ name: 'search' ,query:{keyword:this.keyword}})
或者
this.$router.push({ path: '/search' ,query:{keyword:this.keyword}})
//接收参数
this.$route.params.keyword:获取路由参数
5.路由属性
1)$route(在实列中)
1. this.$route.path:获取路由路径
2. this.$route.params:获取路由参数
2)$router(在实列中)
1. this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
相当于<router-link></router-link>
2. this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
相当于<router-link replace ></router-link>
3. this.$router.back(): 请求(返回)上一个记录路由
4. this.$router.go(-1): 请求(返回)上一个记录路由
5. this.$router.go(1): 请求下一个记录路由
6)声明式路由和编程式路由
1.声明式路由:利用router-link和router-view来实现路由跳转
2.编程式路由:利用$router的API来实现路由跳转
7)缓存路由组件
默认情况下, 被切换的路由组件对象会死亡释放, 再次回来时是重新创建的
如果可以缓存路由组件对象, 可以提高用户体验
1.缓存全部路由
<keep-alive>
<router-view></router-view>
</keep-alive>
2.指定路由缓存
<keep-alive include="该路由的name名称">
<router-view></router-view>
</keep-alive>
3.缓存部分路由
在路由中添加下面属性
meta: {keepAlive: true // 缓存}
meta: {keepAlive:false // 不缓存 }
然后在页面
<keep-alive >
//当前进入的路由 meta里面 keepAlive为true时走这里
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
//当前进入的路由 meta里面 keepAlive为false时走这里 下面 if 判断进行了取反处理
<router-view v-if="!$route.meta.keepAlive"></router-view>
8)路由守卫
路由守卫可以监视路由地址的变化,一旦地址发送变化可以做一系列的事情
应用: 在跳转到某个界面之前,进行用户的权限的限制(是否登录),离开这个界面前,做相关的收尾的一些操作
1.全局路由守卫:全局中只要发生路由跳转就会拦截下来做判断进而做一系列事情,包含全局前置守卫(常用)和全局后置守卫(在router目录的index.js文件下)
router.beforeEach((to, from, next) => {
to:目标的路由route对象
from:当前的路由route对象
next:用来控制路由跳转的函数 next()同意跳转 next(地址)跳转到指定的path的路由
}
export default router
2.路由独享守卫:只要跳转到指定路由就会拦截下来做判断进而做一系列事情,包含前置守卫和后置守卫(在router目录的routes.js文件下)
{
path: '/addcartsuccess',
component: AddCartSuccess,
beforeEnter: (to, from, next) => {}
}
3.组件内守卫:只要跳转到指定路由就会拦截下来做判断进而做一系列事情(和路由独享守卫差不多,就是写的地方不一样而已),包含前置守卫和后置守卫(组件内使用,方法和methods同级)
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
// vm为实例对象
next(vm => {})
}
9)给点击的路由组件添加样式
.router-link-active {
color: red !important;
}
!! 注意:在路由中引入样式要用绝对路径代替相对路径
// /代表从项目运行根目录开始查找
<link rel="stylesheet" href="/static/css/bootstrap.css">
代替:
<link rel="stylesheet" href="./static/css/bootstrap.css">
10)<router-link></router-link>属性
1.<router-link replace></router-link>:路由的跳转采用replace的方式
2.<router-link tag='li'></router-link>:路由连接变成li标签
25.vuex(vue插件)
1) 对 vue 应用中多个组件的共享状态进行集中式的管理(读/写)
2) github 站点: https://github.com/vuejs/vuex
3) 在线文档: https://vuex.vuejs.org/zh-cn/
4) vuex核心对象store
1.定义、配置并暴露store对象(在vuex文件夹下的store.js文件或在store文件夹的index.js文件下)
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state,
getters,
actions,
mutations
})
1) state:包含了多个状态数据的对象
const state = {
count: 0
}
2) getters:包含多个状态数据的计算属性的get()方法的对象
const getters = {
evenOrOdd (state) {
return state.count%2===0 ? '偶数' : '奇数'
}
}
第一个参数:state状态数据
3) actions:包含多个间接改变状态数据的方法
1.同步代码
const actions = {
increment ({commit, state,dispatch,getters},data) {
//第一个参数INCREMENT通知mutations执行那个回调函数
//第二个参数是传递给mutations的数据
commit('INCREMENT',data)
}
}
第一个参数:context相当于store对象,解构{commit, state}
第二个参数:组件中dispatch actions函数的第二个参数(传递过来的值)
2. 异步代码(定时器, ajax)
const actions = {
setTimeout(()=>{
increment ({commit, state}) {
commit('INCREMENT')
}
},1000)
}
补充:如何根据提交的异步action的成功或者失败做不同的处理?(在项目把商品加入购物车有用到)
* 方式1:
* 使用callback回调处理
* 在组件内部,分发异步action的时候,使用dispatch()方法的时候,传入一个回调函数callback
* 在异步action中,在请求处理成功或者失败的时候,调用这个回调函数callback,如果成功就向callback中传入空字符串,失败就传入错误的信息
* 在callback回调函数内部,判断传入的是空串还是错误信息,根据空串或者错误信息来进行跳转处理
* 方式2:
* 在组件中,普通的方式分发action, this.$store.dispatch('action的名字',参数)
* 在异步action中,请求处理成功或者失败后,返回相关的错误消息
* 在组件中,通过await得到当前的action返回的错误消息(可能是空串,也可能是有值错误消息),根据判断来处理对应的问题
4) mutations:包含多个直接改变状态数据的方法
const mutations = {
// state是状态数据
// data是actions传递过来的数据
INCREMENT (state,data) {
state.count++
} }
2.在main.js中让store和实例对象建立联系(实列对象上多了个$store属性)
import store from './store'
new Vue({ store })
3.组件中读写store属性方式
1.方式1
读(获取或计算属性):
this.$store.state.count
this.$store.getters.add
写(操作属性):
this.$store.dispatch("delete",data) 触发actions函数的调用,data是传递过去的数据
this.$store.commit("delete",data) 直接触发mutations函数的调用,data是传递过去的数据
2.方式2(Vuex的辅助函数)
// mapState, mapGetters, mapActions,mapMutations
// 分别可以映射调用store对象上state/getters/actions/mutations上的属性
import {mapState, mapGetters, mapActions,mapMutations} from 'vuex'
export default {
读(获取或计算属性):
computed: {
...mapState(['count']),
...mapGetters(['evenOrOdd']),
}
写(操作属性):
methods: {
...mapActions(['increment']),
...mapMutations({increment:'INCREMENT'}),
}
}
4. modules(store对象的第五大属性对象)
1) 包含多个 module
2) 一个 module是一个 store 的配置对象
3) 与一个组件对应(包含有共享数据)
4) 读写状态数据
1.方式1(可以传递data)
读(获取或计算属性):
this.$store.state.home.count //需要加上home模块
this.$store.getters.add
写(操作属性):
this.$store.dispatch("delete",data) 触发actions函数的调用,data是传递过去的数据
this.$store.commit("delete",data) 直接触发mutations函数的调用,data是传递过去的数据
2.方式2(Vuex的辅助函数) (不可以传递data)
// mapState, mapGetters, mapActions,mapMutations
// 分别可以映射调用store对象上state/getters/actions/mutations上的属性
import {mapState, mapGetters, mapActions,mapMutations} from 'vuex'
export default {
读(获取或计算属性):
computed: {
...mapState({count:state=>state.home.count}), //需要加上home模块,用对象的方式
...mapGetters(["evenOrOdd"])
}
写(操作属性):
methods: {
...mapActions(['increment']),
...mapMutations({increment:'INCREMENT'}),
}
}
5.命名空间namespaced:true
加上命名空间后再组件中调用dispatch和commit只会调用根模块的actions和mutations,想要触发其它模块下的dispatch和commit
可以这样用this.$store.dispatch('模块名/action名')
6.subscribe()和replaceState()方法
1)mutation调用后执行subscribe()方法
store.subscribe((mutation, state) => {})
2)替换state属性
store.replaceState(state);