安装项目
安装脚手架
使用可视化界面创建
$ vue ui按需安装即可
安装完关掉就好
VSCode 的打开项目
安装依赖
$ npm i
运行项目
使用命令
$ npm run serve
配置路由
勾选上配置默认是配好的,按需更改就好

vuex
勾选上配置默认是配好的,按需更改就好

模版语言
使用 插入属性
<template>
<div>
{{ msg }}
<!-- 路由视图容器 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
// 生命周期 创建后
created() {
console.log('App.vue created');
},
// 生命周期 渲染后
mounted() {
console.log('App.vue mounted');
},
// 属性
data() {
return {
msg: 'hello world',
};
},
// 方法
methods: {},
// 计算属性
computed: {},
// 监听属性
watch: {},
// filters 过滤器
filters: {},
};
</script>
<style scoped></style>选项式 API
<script>
export default {
// 属性
data() {
return {
msg: 'hello world',
};
},
// 方法
methods: {},
// 计算属性
computed: {},
// 监听属性
watch: {},
// filters 过滤器
filters: {},
// 自定义指令的 directives
directives: {},
};
</script>CSS 引入
全局引入
1. 编写全局样式文件 如 global.css
2. 在main.js文件中引入 该css文件
局部引入
在模版中编写
<style scoped lang="less"></style>组件 CSS
1. 组件内使用的CSS
<style>
.my-component {
background-color: #fff;
padding: 20px;
}
</style>生命周期
目录
vue2 的生命周期
| 方法 | 作用 |
|---|---|
| beforeCreate() | 在创建之前调用,这时候数据、方法、Dom 都未创建无法访问 |
| created() | 在创建之后调用,这个时候可以访问数据、方法、计算属性等 |
| beforeMount() | 挂载之前调用,dom 挂载阶段之前,此时组件的 template 已经解析完成,但还未生成真正的 DOM 节点。 |
| mounted() | 挂载之后调用,这时候的 Dom 树已经构建完成,可以对 DOM 结构进行操作 |
| beforeUpdate() | 在更新之前调用,可以在这里进一步改变数据。注意避免进入死循环的情况 |
| updated() | 在更新之后调用,在这里可以获取到更新后的 DOM 元素的状态 |
| beforeDestroy() | 在组件被销毁之前调用,此时组件实例依旧可以正常访问,可以进行一些清理工作 |
| destroyed() | 在组件销毁之后调用,组件实例已经被清理掉了,事件监听等已经被清除 |
| activated() | 在组件被激活时触发,keep-alive |
| deactivated() | 在组件被缓存时触发,keep-alive |
| errorCaptured()【er rou--ka pu to er de】 | (Vue2.5 版本引入的)用来捕获子组件的渲染错误和无法被 try-catch 捕获到的错误 |
| serverPrefetch | ssr 渲染的场景 |
beforeCreate
1. 创建阶段在实例化之前调用
2. 此阶段的属性和方法还未实例化,DOM结构也没有渲染。故此数据对象,DOM都无法调用
3.$el和$data属性也还不存在
4. 应用: 初始化属性Created
1. 实例化之后调用
2. 此时可以调用数据对象,属性和方法。但是无法访问DOM结构
3. 如果想在次阶段操作DOM可以通过 异步实现该操作。
4. 在此处进行请求数据(axios)可以在子组件之前获取数据,此时子组件还未创建,没有进入子组件的生命周期beforeMount
1. 挂载之前调用,此时组件的 模版(template) 已经解析完成,编译成了虚拟DOM,但是DOM还没有渲染成真正的DOM,这个阶段可以操作虚拟DOM。
2. 模板已经编译成了虚拟 DOM
3. 此阶段可以请求数据,弹药注意Mounted
1. 挂载之后调用,此时DOM结构创建以及渲染完成,在这里可以获取到DOM结构,对DOM结构进行操作。
2. 此时数据对象(属性和方法),DOM结构都已经可以访问了
3. 在这个阶段子组件已经创建完成,子组件的生命周期已经走完前四步
4. 在这个阶段请求数据(axios)可以再子组件之后获取数据,应用场景是子父
5. 在Mounted中修改DOMbeforeUpdate
1. 更新阶段===> beforeUpdate && updated
2. 此阶段在数据产生变化时,在实际更新前触发该生命周期函数,可以对数据进行进一步修改。Updated
1. 数据更新之后调用
2. 这个阶段数据更新已经完成,获取到更新之后的数据beforeDestroy
destroyed
activated
1. 在组件被激活时触发,
2. 应用:详情页面请求数据
1. 在activated中判断id是否相同,相同不再发送http请求deactivated
1. 在组件被缓存时触发'
会将组件添加到缓存队列中。代码示例
<template>
<div ref="myLife">
我是生命周期页面
<div>{{ getAge }}</div>
<button @click="age = 27">改变年龄</button>
<button @click="delDomElement">删除DOM元素</button>
</div>
</template>
<script>
export default {
// 创建阶段 属性和方法创建之前
beforeCreate() {
// 在实例刚被创建之初,组件的数据,属性和方法的初始化还没有开始,DOM还没有生成
console.log('我是beforeCreate');
console.log('数据', this.msg); // undefined
console.log('计算属性', this.getAge); // undefined
console.log('方法', this.getFunc); // undefined
console.log('Dom结构', this.$refs.myLife); // undefined
console.log('=============================');
},
created() {
//实例已经完全创建成功,此时可以访问数据、计算属性,方法,还没有开始挂载和渲染DOm结构
console.log('我是created');
console.log('数据', this.msg); // ture
console.log('计算属性', this.getAge); // true
console.log('方法', this.getFunc()); // true
console.log('Dom结构', this.$refs.myLife); // undefined
console.log('=============================');
},
// 挂载阶段 dom挂载阶段
beforeMount() {
// 在组件挂载到页面之前,此时组件的 template 已经解析完成,但还未生成真正的 DOM 节点。
console.log('我是beforeMount');
console.log('数据', this.msg); // true
console.log('计算属性', this.getAge); //true
console.log('方法', this.getFunc()); //true
console.log('Dom结构', this.$refs.myLife); // undefined
console.log('=============================');
},
mounted() {
// 组件已经挂载到页面上,此时组件的 DOM 树已经构建完成,可以对组件的 DOM 结构进行操作。
console.log('我是mounted');
console.log('数据', this.msg); //true
console.log('计算属性', this.getAge); //true
console.log('方法', this.getFunc()); //true
console.log('Dom结构', this.$refs.myLife); // true
console.log('=============================');
},
// 更新阶段
beforeUpdate() {
// 在 数据和组件 更新之前被调用 --,可以在这个钩子函数中进一步改变数据
console.log('我是beforeUpdate');
console.log('数据.年龄', this.age);
console.log('计算属性', this.getAge);
},
updated() {
// 在数据和组件 更新之后执行 -可以在这里获取准确的更新后 - 的数据或DOM元素状态
console.log('我是updated');
console.log('数据.年龄', this.age);
console.log('计算属性', this.getAge);
},
// 销毁阶段
beforeDestroy() {
// 在组件被销毁之前调用,此时组件实例仍然完全可用
console.log('我是beforeUnmount');
console.log('DOM', this.$refs.myLife);
},
destroyed() {
// 在组件被销毁后调用,这个阶段组件实例已经被销毁了,该钩子函数中的事件监听等属性和方法以及被清理掉了
console.log('我是unmounted');
console.log('DOM', this.$refs.myLife);
},
// keepAlive
//在组件被缓存起来时触发,用于在组件被缓存起来后执行操作。
deactivated() {
console.log('我是activated');
},
//在组件被激活时触发,需要配合 keep-alive 组件使用,用于在组件被重新激活时执行操作。
activated() {
console.log('我是deactivated');
},
// 捕获错误时调用
errorCaptured(err, vm, info) {
console.log('我是errorCaptured');
console.error(`Error caught in ${vm.$options.name} component:\n ${err}`);
console.error(info);
return false;
},
data() {
return {
msg: 'hello world',
name: '钟明楼',
age: 26,
};
},
computed: {
getAge() {
return this.age * 2;
},
},
methods: {
getFunc() {
return '我是方法';
},
delDomElement() {
// 删除DOM元素
this.$refs.myLife.removeChild(this.$refs.myLife.querySelector('div'));
},
},
};
</script>组件
组件化
1. 固定组件 2. 子路由动态组件 3. v-if控制组件的渲染 4.固定组件
局部引入
// 组件内部
// 导入的组件
import Home from './components/HomeView';
import About from './components/AboutView';
export default {
// 局部引入
components: {
Home,
About,
},
};全局引入
// 全局文件引入组件
import Home from './components/HomeView';
import About from './components/AboutView';
import RefView from './components/RefView';
// 进行全局注册
// 单个
Vue.component('Home', Home);
// 批量
Vue.component({
About: About,
RefView: RefView,
});动态组件 --- 使用子路由
<!-- 子路由动态加载的路由组件 -->
// router.js
import { createRouter, createWebHistory } from 'vue-router';
const Dashboard = () => import('./views/Dashboard.vue');
const Profile = () => import('./views/Profile.vue');
const Settings = () => import('./views/Settings.vue');
const routes = [
{
path: '/dashboard',
component: Dashboard,
children: [
{
path: 'profile',
component: Profile
},
{
path: 'settings',
component: Settings
}
]
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;组件传参
父子传参
父组件 在子组件标签中 传递参数
<template>
<div>
<Home
:msg="msg"
:name="name"></Home>
</div>
</template>
export default { data() { return { msg: 'hello world', name: '钟明楼' } }, }子组件 props 接收
export default {
props: {
msg: String,
name: {
// 完整写法
type: String,
default: 'hello world',
required: true,
},
},
data() {
return {};
},
};子父传参
子组件 $emit
<div>
<button @click="postChild('子组件修改后')">修改父组件Child</button>
</div>
<script>
export default {
methods: {
postChild(val) {
this.$emit('postChild', val)
}
},
}
</script>父组件通过 在子组件标签中 @xxx 进行接收 --- 自定义事件
<template>
<div>
<div>Child的值为:{{ Child }}</div>
<About @postChild="postChild"></About>
</div>
</template>
export default {
methods: {
// 子组件传值
postChild(val) {
this.Child = val
}
}, data() {
return {
msg: 'hello world',
name: '钟明楼',
Child: '子组件修改前',
}
},
// 方法
methods: {
// 子组件传值
postChild(val) {
this.Child = val
}
},
}组件双向绑定 -- v-model
1. 父组件在子组件标签中使用 v-model 绑定数据
$ <Child v-model="name" />
2. 子组件中通过props进行接收 固定值为value。 无法更改
$ props: ['value']
3. 子组件通过计算属性(computed)使用数据 固定格式名无法更改
$ computed: {
childValue: {
get() {
return this.value
},
set(val) {
this.$emit('input', val);
},
},
},
4. 标签中直接v-model绑定 childValue
$ <input type="text" v-model="childValue" />实现父组件和子组件之间的双向数据绑定
<!-- 父组件 -->
<template>
<div>
<h1>组件传参</h1>
<div>{{ name }}</div>
v-model传参:<input
type="text"
v-model="name" />
<Child :name.sycn="name" />
</div>
</template>
<script>
import Child from '../components/Assembly/Parent';
export default {
components: {
Child,
},
data() {
return {
name: '明楼',
};
},
};
</script>子组件 ===> 规定格式 value + 计算属性 childValue 改不了
<!-- 子组件 -->
<template>
<div>
<h2>v-model传参</h2>
<input
type="text"
v-model="childValue" />
<div>{{ childValue }}</div>
</div>
</template>
<script>
export default {
props: ['value'],
computed: {
childValue: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
},
},
},
};
</script>组件双向绑定 -- v-bind
1. 使用 v-bind.sync向子组件标签传递数据
$ <Child :AgeProp.sync=age />
2. 子组中通过自定义事件名
$ props:["newAge"]
3. 子组件中通过 :value 进行数据绑定,@input事件完成对数据的修改
$ <input type="text" :value="newAge" @input="bindAge">
4. 修改的事件 ===> 固定emit事件名 update:xxx
$ bindAge(event) {
this.$emit('update:newAge', event.target.value)
}ref
父组件直接通过 ref 访问 子组件
this.$refs. ref 的名称 .调用的子组件方法()
<template>
<div>
<RefView ref="myChild"></RefView>
<div>父Ref访问子方法:{{ RefString }}</div>
<button @click="callChildMethod">父组件通过refs 调用子方法</button>
</div>
</template>
<script>
export default {
methods: {
// $refs 调用子组件的方法
callChildMethod() {
console.log(1);
this.RefString = this.$refs.myChild.refView() // 调用子组件的方法
}
},
}
</script>
<style></style>子组件 -- 被访问的方法
<template>
<h1> 我是 Ref 父访子</h1>
</template>
<script>
export default {
methods: {
refView() {
return '我是Ref子组件的方法,我被获取了'
}
},
}
</script>
<style></style>$Bus 全局事件总线
utils / Bus / index.js
import vue from 'vue';
export const EventBus = new vue();组件 $emit 组件触发 按钮 传递给 其他组件
EventBus.$emit('注册事件监听名', ‘传递的数据’)
<template>
<div>
<button @click="getEventBus"> 子组件传递参数</button>
</div>
</template>
<script>
// 引入 全局文件 Bus.js
import { EventBus } from '@/utils/Bus'
export default {
methods: {
// bus子组件传值
getEventBus() {
EventBus.$emit('getEventBus', '子组件')
}
},
}
</script>接收组件通过 在 created 或 mounted
EventBus.$on(‘事件监听器名’,(传递的数据)=>{})
<template>
<div>
<BusView></BusView>
<div>父Bus访问子方法:{{ BusSring }}</div>
</div>
</template>
<script>
// 引入 全局文件 Bus.js
import { EventBus } from '@/utils/Bus'
export default {
created() {
EventBus.$on('getEventBus', (message) => {
console.log('接收到的消息:', message)
this.BusSring = message
// 对消息进行处理等操作
})
},
}
</script>Provide/inject -- 注入
跨层级传参 祖孙 父子
祖
export default {
// provide注入 跨层级传参
provide: {
provideString: "我是Provide注入的数据",
ProvideFunc: () => {
console.log('我是Provide注入的方法');
}
},
},孙 inject 接收注入的数据
export default {
// 简写
inject: ['provideString', 'ProvideFunc'],
// 完整写法
inject: {
// 属性
provideString: {
from: 'user',
default: '我是默认值'
},
// 方法
ProvideFunc: {
from: 'ProvideFunc',
default: null
}
},
props: {},
data() {
return {}
},
},vuex
见下文
路由
配置路由
import Vue from 'vue';
import VueRouter from 'vue-router';
import HomeView from '../components/HomeView.vue';
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'home',
component: HomeView,
// 子路由 配合 <router-view/> 使用
children: [
{
path: 'about',
component: () => import('../views/AboutView.vue'),
},
],
},
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
export default router;动态添加路由
使用 addrouter 动态添加路由
代码示例 --- 单独添加 --- 批量添加
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/components/Home.vue'
import About from '@/components/About.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
component: Home
}
]
})
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
// 单独添加
router.addRoute('about', {
path: '/about',
component: About
})
// 批量添加
const arrRoute = [
{ path: '/about', component: About },
{ path: '/contact', component: Contact },
];
arrRoute.forEach((route) => {
router.addRoute(route);
});
export default router注意点
1. 报错信息:Uncaught ReferenceError: Cannot access 'router' before initialization
位置需要再 router实例化之后 new VueRouter()之后
2. 暂无路由跳转 && 传参
编程式导航
// 使用 $router.push() 方法进行路由跳转
this.$router.push('/home');
// 使用 $router.replace() 方法进行路由跳转
this.$router.replace('/home');
// 带参数的路由跳转
this.$router.push({ path: '/user', query: { id: 1 } });
// 访问查询参数
this.$route.query.name;
// 使用命名路由和参数
this.$router.push({ name: 'UserProfile', params: { userId: 123 } });
// 接收路由参数
this.$route.params.id,接收参数
声明式导航
<!-- 跳转到指定路径 -->
<router-link to="/path">Go to Path</router-link>
<!-- 使用命名路由 -->
<router-link :to="{ name: 'UserProfile', params: { userId: 123 }}">User Profile</router-link>
<!-- 带有查询参数 -->
<router-link :to="{ path: '/search', query: { keyword: 'vue' }}">Search Vue</router-link>子路由
父路由通过标签 获取子路由数据
<router-view></router-view>导航守卫
共七中
1. to: route 即将要进入的目标
1.
2. form:ruote 当前路由正要离开的路由
3. next:function 一定要调用这个方法进入下个页面 next(false) 不进行跳转取消 后续不再执行守卫的执行先后顺序 === 进入阶段
1. beforeEach 全局前置守卫
2. beforeEnter 路由独享守卫
3. beforeRouteEenter 组件路由前置
4. beforeResolve 全局解析守卫
5. afterEach 全局后置守卫
6. 进入生命周期的流程演示图 === 无子组件

演示图 === 有子组件

全局导航守卫
全局前置守卫
1. beforeEach((to,form,next)=>{})
2. 在进入路由前会进入beforeEach进行判断,
3. 启动beforeEach后必要填写条件 next() 才能进入路由
4. 应用:登录验证,没有登录重定向到登录页,代码
// 全局组件守卫 == 登录验证 == 使用思路
router.beforeEach((to, form, next) => {
console.log('========我是路由前置守卫========');
if (to.path === '/login' || localStorage.getItem('token')) {
next();
} else {
next('/login');
}
});全局解析守卫
1. router.beforeResolve((to,form,next)=>{})
2. 执行时机: 在全局导航守卫之后,但在所有路由组件和异步路由组件都被解析完毕之后、进入下一个页面之前,执行的。
3. 应用: 认证或授权操作,登录超时验证 例如检查用户是否已登录等。代码
// 全局解析守卫
router.beforeResolve((to, from, next) => {
console.log('========我是路由后置守卫========');
// 执行一些逻辑操作 比如 认证或授权操作
next()
})全局后置守卫
1. router.afterEach((to,from)=>{})
2. 在路由跳转后执行,没有next函数,不会影响导航本身
3. 进入next函数之后,生命周期之前
3. 应用场景: 数据埋点,记录跳转日志,跳转动画代码
// 后置全局导航守卫
router.afterEach((to, from) => {
console.log("========我是全局后置守卫========");
// console.log(to, from);
});路由独享守卫
路由独享守卫可以直接在路由配置中定义,只会在该路由匹配时调用
只有一个 beforeEnter
1. 写法与全局守卫不同 -- 是路由中的一个属性对象
beforeEnter: (to, from, next) => {}
2. 执行时机在全局前置守卫之后,全局解析守卫之前执行。
2. 应用:权限控制,需要特定条件才能进入的场景代码 --- 注意用法 --- 写在路由对象里
const router = new VueRouter({
routes: [
{
path: '/admin',
component: Admin,
beforeEnter: (to, from, next) => {
// 检查是否具备管理员权限
if (!isAdmin) {
next('/login'); // 如果没有权限,则跳转到登录页面
} else {
next(); // 具备权限,继续路由跳转
}
},
},
],
});组件内守卫
beforeRouteEnter
在进入路由前被调用
1. 在全局解析守卫beforeResolve之前
2. 在全局前置守卫beforeEach和路由独享守卫beforeEach之后beforeRouteUpdate
1. 在子组件更新时触发:比如切换子路由
2. 应用场景: 切换子路由时进行权限检查beforeRouteLeave
1. 在退出页面时触发,可以弹出提示框,确定是否离开
2. 注意:直接关闭页面不生效
3. 应用场景:数据保存、取消导航 仅在通过路由离开页面生效关闭浏览器应用不生效:
在线时间统计(推荐使用beforeunload)表单修饰符
目录
1. 表单修饰符
2. 事件修饰符
3. 鼠标按键修饰符
4. 键值修饰符
5. v-bind修饰符表单修饰符
**应用与V-model**
1. lazy: <input type="text" v-model.lazy="value">
"当光标离开时,才会将值赋予给value,也就是Chagne事件之后"
2. trim: <input type="text" v-model.trim="value">
"自动过滤用户输入的空格字符"
3. number: <input v-model.number="age" type="number">
"会将用户的值转化为数值类型,如果无法被 parseFloat 解析,则会返回原来的值"事件修饰符
1. stop: <button @click.stop="shout(1)">ok</button>
"阻止事件冒泡,相当于调用了event.stopPropagation
【stop Pro pe gei shen】"
2. prevent:<form v-on:submit.prevent="onSubmit"></form>
"阻止事件的默认行为相当于调用了event.preventDefault方法"
3. self:<div v-on:click.self="doThat">...</div>
"当前元素自身时触发处理函数,"
4. once: <button @click.once="shout(1)">ok</button>
"只会触发一次,第二次就不会触发了"
5. native : <my-component v-on:click.native="doSomething"></my-component>
"在自定义标签中默认只能监听自定义事件,监听原生事件,需要通过native"
6. passive: <div v-on:scroll.passive="onScroll">...</div>
7. capture:
"使事件触发从包含这个元素的顶层开始往下触发"鼠标按钮修饰符
1. left 左键点击 <button @click.left="shout(1)">ok</button>
2. right 右键点击 <button @click.right="shout(1)">ok</button>
3. middle 中间点击 <button @click.middle="shot(1)">ok</button>键盘修饰符
1. 普通键(enter、tab、delete、space、esc)
2. 系统修饰键(Ctrl、alt、shift...)v-bind 修饰符
1. sync
能对props进行一个双向绑定
//父组件
<comp :myMessage.sync="bar"></comp>
//子组件
this.$emit('update:myMessage',params);
"子组件传递的事件名格式必须为update:value,其中value必须与子组件中props中声明的名称完全一致"
2. prop
<input id="uid" title="title1" value="1" :index.prop="index">
设置自定义标签属性,避免暴露数据,防止污染HTML结构
3. camel
将命名变为驼峰命名法,如将view-Box属性名转换为 viewBox
<svg :viewBox="viewBox"></svg>应用场景
1. stop:阻止事件冒泡
2. native:绑定原生事件
3. once:只执行一次
4. self:将事件绑定在自身身上,相当于阻止事件冒泡
5. prevent:阻止默认事件
6. caption:用于事件捕获
7. KeyCode:监听特定按键按下
8. right:右键Vuex
介绍
推荐大型项目使用
1. Vuex是专门为Vue打造的全局状态管理工具 --- 库
2. 推荐大型项目使用
优点: 用起来方便,
缺点: 使用不当容易造成全局数据混乱核心模块
五个核心模块: state、getters、mutations、actions、modules
jsimport { mapState, mapMutations, mapActions, mapGetters } from 'vuex';
| 模块 | 对应调用方法 |
|---|---|
| state | ...mapState([‘xxx’]) |
| getters | ...mapGetters({“xxx”:xxx,}) |
| mutations | ...mapMutations({“xxx”:xxx,}) |
| actions | ...mapActions({“xxx”:xxx,}) |
| modules | ....... |
1. computed中调用
...mapState
...mapGetters
2. methods中调用
...mapMutations
...mapActions示例
vuex
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
// 存储状态 类似 data
state: {
count: 0,
},
getters: {
// 同步方法 修改 state状态 计算属性 类似 computed
getCount(state) {
return state.count * 2;
},
},
mutations: {
// 同步方法 修改 state状态
setCountUp(state, value) {
state.count++;
},
setCountDown(state, value) {
state.count = state.count - 1;
},
},
actions: {
// Fetch API 进行的Get请求
getListData({ commit }) {
fetch('http://127.0.0.1:3000/')
.then((res) => res.json())
.then((res) => {
console.log(res);
});
},
// Fetch API 进行的Post请求
postListData({ commit }) {
console.log('Fetch API Post请求');
fetch('http://127.0.0.1:3000/Fetch', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // 请求头
},
body: JSON.stringify({
name: '明楼',
age: 26,
}),
})
.then((res) => res.json())
.then((res) => {
console.log(res);
});
},
},
modules: {},
});Vuex 的应用 -- 引入 -- 根据不同的 模块使用不同 的 方法
<template>
<div>
<h1>Vuex</h1>
<div>{{ count }}</div>
<div>"Getters":{{ getCount }}</div>
<button @click="setCountDown()">setCountDown</button>
<button @click="setCountUp()">setCountUp</button>
<button @click="getListData()">请求Get</button>
<button @click="postListData()">请求Post</button>
</div>
</template>
<script>
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {
// 方法
methods: {
// 调用Vuex中的方法 调用方法 属性在 computed
...mapMutations({
setCountDown: 'setCountDown',
setCountUp: 'setCountUp',
}),
// 调用actions中的异步方法
...mapActions({
postListData: "postListData",
getListData: "getListData",
})
},
// 计算属性
computed: {
...mapGetters(["getCount",]),
// 获取vuex中的属性状态
...mapState(["count"])
},
}
</script>Keep-Alive
缓存组件
1. 使用方式,使用 keep-alive 标签包裹组件
2. 三个属性: include、exclude、max
3. include: 指定可以进行缓存的组件
4. exclude: 指定不需要进行缓存的组件
5. max: 指定接收最大缓存的数量
6. include、exclude接收的参数类型:String | RegExp | Array
7. nax: 接收数据类型: String | Numberinclude 示例 --- 接收参数类型:String | RegExp | Array
<keep-alive include="componentName"></keep-alive>
<keep-alive :include="['componentName1', 'componentName2']"</keep-alive>
<keep-alive include="componentName"></keep-alive>
<!-- 正则示例 -->
<keep-alive :include="/^Component/" :exclude="/^ComponentB$/">
<!-- 匹配以 "Component" 开头的所有组件,使用 /^ComponentB$/ 来排除 ComponentB 组件 -->
</keep-alive>exclude 示例 --- 接收参数类型:String | RegExp | Array
<keep-alive exclude="componentName"></keep-alive>
<keep-alive :exclude="['componentName1', 'componentName2']"</keep-alive>
<!-- 正则示例 -->
<keep-alive :include="/^Component/" :exclude="/^ComponentB$/">
<!-- 匹配以 "Component" 开头的所有组件,使用 /^ComponentB$/ 来排除 ComponentB 组件 -->
</keep-alive>max 示例 --- 接收的参数类型 Number | String
<keep-alive :max="10"></keep-alive>实现原理
1. keep-alive包裹的组件,Vue 会将该组件实例缓存起来,不再执行销毁的生命周期钩子
2. keep-alive内部维护了一个缓存池,通常是Map或WeakMap结构,来储存缓存的组件实例,缓存在内存中不进行销毁
3. 通过LRU策略(Least Recently Used 最近最少使用原则)策略管理缓存的实例数量示例
父组件
<template>
<div>
<router-link to="/alive">GO To alive</router-link>
<router-link to="/keep">GO To Keep</router-link>
<!-- 缓存组件 -->
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
</template>子组件 alive
<template>
<div>
<h1>alive</h1>
<input
type="text"
v-model="msg" />
</div>
</template>Max 的淘汰机制
1. 使用LRU算法,缓存淘汰策略(最近最少使用原则): Least Recently Used
2. 当访问数据项的时候时,数据项会被移动到链表尾部
3. 当淘汰数据时,链表尾部的数据项会被删除和替换
4. 添加时,检查缓存,没满添加,满了的话删除最近使用最少的链尾的数据项NextTick
$nextTick 的作用
1.在下次DOM更新完毕之后,执行回调函数
2.主要应用场景
- 修改数据后获取更新后的DOM元素信息。
- 在组件更新后执行一些DOM操作或其他操作。
- 异步更新。修改数据后或在组件更新后获取最新的DOM信息,或是执行一些其他操作。
3. 利用的JavaScript事件循环的微任务宏任务会在同步任务之后执行的机制,在DOM结构渲染完完毕后的mounted阶段、数据对象更新完毕后的updated阶段最后nextTick 的更新机制
在内部维护了一个任务队列
根据不同的环境进行降级操作
1. Promise.then
2. MutationObserver
3. setImmediate
4. setTimeout使用场景
1. 想要在修改数据后获取到准确的更新值插槽
介绍
1. 什么是插槽
插槽是vue中的内置组件,可以直接调用使用
2. 插槽的作用
1. 可以让我们数据传递更加灵活
2. 作用域插槽可以让父组件访问子组件作用域中的数据,实现更灵活的代码编写,
3. 多个匿名插槽,会出现多个渲染(插了3条数据,两个匿名插槽,出现6条数据)三种插槽
1. 具名插槽
具名插槽是具有名称的插槽 可以起个名字name="xxx"
2. 匿名插槽
没有名字的插槽
3. 作用域插槽
Element-ui组件 data直接传给了组件 可以通过 template+作用域插槽,来获取数据
4. 注意点
1. 在子组件标签内的标签会被统一放进匿名插槽 自上而下。
2. 具名插槽需要<template v-slot:centent></template>标签内填写标签
3. 作用域插槽
1. <template v-slot:header="data">{{data.data}}</template>
2. <slot name="header" :data="{ name: name, age: age }"></slot>具名插槽和匿名插槽(默认)
子组件
1. 子组件使用slot占位
<slot></slot>
<slot name='centent'></slot>父组件
1. 在引入的子组件标签内使用template插入数据
2. 没有template的会自上而下被放进匿名插槽,也就是直接卸载子组件中的标签数据会被放进匿名插槽
<Child>
<template v-slot:centent>
</template>
<p>没有template的会自上而下被放进匿名插槽</p>
</Child>效果图

作用域插槽
子组件
<!-- 子组件 -->
<template>
<div>
<h2>作用域插槽</h2>
<div>
<h1>标题:<slot name="title">我是默认标题1</slot></h1>
</div>
<slot
name="header"
:data="{ name: name, age: age }"></slot>
</div>
</template>
<script>
export default {
data() {
return {
name: '明楼',
age: 26,
};
},
};
</script>父组件
<!-- 父组件.vue -->
<template>
<div>
<h2>父组件</h2>
<!-- 作用域插槽 -->
<Scopet>
<template v-slot:default="data">
<div>
{{ data }}
</div>
</template>
<template v-slot:header="data">
<div>
{{ data.data }}
</div>
</template>
</Scopet>
</div>
</template>
<script>
import Scopet from '@/components/插槽/作用域插槽.vue';
export default {
name: 'ParentComponent',
components: {
Scopet,
},
};
</script>效果图

自定义指令
1. vue2自定义指令有五个生命周期阶段
2. bind、inserted、update、componentUpdate、unbind
3. 应用场景
- 获取焦点 v-focus
- 表单验证
- 自定义指令实现手机号码格式化生命周期
1. bind:在指令第一次绑定到元素上时生效
2. inserted:DOM渲染完成后生效,类似mounted
3. update:虚拟DOM Vnode更新时调用。可能发生在子组件还未更新时
4. ComponentUpdated:在 DOM 更新后触发,可以再这里获取更新后的DOM结构
5. unbind:指令与元素解绑时调用,可以用来进行清理工作bind
1. 执行时间在:
beforeMount -- bind -- inserted -- mounted
2. 在指令绑定到组件到元素上时生效inserted
1. 执行在bind之后,mounted之前
2. 此阶段在DOM渲染后生效update
1. 此阶段类似于beforeUpdate
2. 在组件或绑定的值更新时触发componentUpdated
1. 此阶段类似于updated
2.在DOM更新完成之后触发,可以再这里获取更新之后的DOM结构onbind
1. 指令与元素解绑时调用onbind,可以进行清理工作,
2. 可以进行清理工作,比如清理事件监听、定时器触发效果图
使用 v-model 修改值,使用 this.$destroy 触发销毁()

全局自定义指令
全局配置 Vue.directive()
// main.js
Vue.directive('myDirective', {
bind: (el, binding, vnode, oldVnode) => {
// 指令绑定时的逻辑
},
instered: () => {
//指令被插入到元素时调用
},
});组件内自定义指令
vue2 可以通过选项式 API directives:{}
// 组件内
<script>
export default {
directives: {
// 生命周期
assgin: {
// 指令第一次绑定到元素时调用,可以进行初始化工作,添加事件监听,设置初始值等
bind(el, binding, vnode, oldVnode) {
console.log("我是bind");
},
// 指令被插入到元素时调用,这里元素已经被插入到父节点中了
inserted(el, binding, vnode, oldVnode) {
console.log("我是inserted");
},
// 指令所在的绑定值,发生变化时调用,通常在这里更新元素的状态
update(el, binding, vnode, oldVnode) {
console.log("我是update");
},
// 指令所在组件的虚拟DOM全部更新完成后调用,通常在这里操作$nextTice实现延迟执行.
componentUpdated(el, binding, vnode, oldVnode) {
console.log("我是componentUpdated");
},
// 指令与元素解绑时调用,可以进行清理工作,比如移除事件监听器,删除DOmain元素
unbind() {
console.log("我是unbind");
},
},
// 获取焦点
focus:{
inserted(el,binding,vnode,oldVonde){
el.focus()
}
},
// 失去焦点时触发,创建了事件监听器,全局方法,onbind阶段进行了销毁
blur: {
inserted(el, binding) {
window.blurHandler = () => {
console.log(el.value);
}
el.addEventListener("blur", window.blurHandler)
},
unbind(el, binding) {
el.removeEventListener('blur', window.blurHandler);
delete window.blurHandler
},
},
}
}执行顺序

可能会遇到的问题
样式问题,有外边距元素不是紧贴视口
创建项目的样式问题,有外边距元素不是紧贴视口
1. 修改入口文件 App.js中的样式
body {
height: 100vh;
width: 100vw;
margin: 0px;
}简单的过度动画
隐入隐出
<template>
<transition
name="fade"
mode="out-in">
<router-view></router-view>
</transition>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>