(一) 父组件修改字组件数据
- 父组件使用子组件的时候, 给子组件添加ref属性
- 父组件就可以使用 this.$refs[‘xxx’] 获取到子组件的实例, 从而去修改子组件的数据
(二) 子组件修改父组件数据
方式二:
跟普通父子组信一样, 不过父组件传给子组件的对象, 子组件修改这个对象的属性也可以实现子组件修改父组件数据的目的.
方式二:
父组件使用 :msg.sync=”msg”
子组件使用 $emit(‘update:msg’, ‘新数据’)
// 父组件 Demo.vue
<template>
<div>
<h3>父组件</h3>
<p>{{msg}}</p>
<hr>
<h5>子组件</h5>
<Son :msg.sync="msg"></Son>
</div>
</template>
<script>
import Son from './Son.vue'
export default {
components: {
Son
},
data() {
return {
msg: 'hello'
}
}
}
</script>
// 子组件 Son.vue
<template>
<div>
<input type="text" :value="msg" @input="onInput">
</div>
</template>
<script>
export default {
props: ['msg'],
methods: {
onInput() {
this.$emit('update:msg', event.target.value);
}
}
}
</script>
(三) 父子组件双向数据绑定
即父组件可以对子组件使用v-model
// 父组件Demo.vue
<template>
<div>
<h3>父组件</h3>
<p>{{msg}}</p>
<hr>
<h5>子组件</h5>
<!-- 对子组件使用v-model指令 -->
<Son v-model="msg"></Son>
</div>
</template>
<script>
import Son from './Son.vue'
export default {
components: {
Son
},
data() {
return {
msg: 'hello'
}
}
}
</script>
// 子组件 Son.vue
<template>
<div>
<input type="text" :value="msg" @input="onInput">
</div>
</template>
<script>
export default {
props: ['msg'],
model: {
// 指定对哪个属性进行使用v-model
prop: 'msg',
// 指定子组件$emit的事件名称
event: 'myevent'
},
methods: {
onInput() {
// $emit指定的事件名称
this.$emit('myevent', event.target.value);
}
}
}
</script>
(四) 路由守卫
和axios拦截器,koa中间件都有些相似的地方
- to 即将要进入的目标 路由对象
- from 当前导航正要离开的路由
- next 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
- next() 直接进入进行管道中的下一个钩子
- next({ path: ‘/xxx’ }) 跳转到/xxx 路由
// 路由白名单(不需要检查就可以直接通过进行下一步的路由)
const whitList = ['/login'];
router.beforeEach((to, from, next) => {
// 已登录,如果目标路由是/login则跳转到首页, 否则放行
if (store.state.user.token) {
if (to.path === '/login') {
next('/home');
} else {
next();
}
} else {
// 未登录
if (whitList.includes(to.path)) {
// 白名单内的路由直接放行,非白名单的跳转到登录页
next();
} else {
next('/login');
}
}
})
(五) 用户权限控制
用户权限控制的思路是:
- 前端一开始的路由只配置了一些基本的路由
- 用户登录之后, 后台会给前端返回一个角色字段, 表明用户的身份
- 前端就根据用户的身份配置不同的路由(有的公司由后台返回)
- 使用router.addRoutes方法添加权限路由。
- 在后台管理系统的侧边栏一般根据路由数组动态渲染,这样不同角色能看到的列表就不一样。 ```javascript // 基础路由,不需要权限就可以访问的路由 const baseRoutes = [{ path: ‘/login’, name: ‘login’, component: () => import(‘@/views/login/index.vue’) }]
// 创建路由 const router = new Router({ mode: ‘history’, routes: baseRoutes });
export const adminRoutes = [{…},{…},{…}]; export const superRoutes = […adminRoute,{…},{…}];
// 登录成功根据不同角色添加不同的路由
axios.post(‘/user/login’,userInfo).then(res => {
if (res.result.role == 1) {
// 动态添加超级管理员权限路由
router.addRoutes(superRoutes);
} else if (res.result.role == 2){
// 动态添加管理员权限路由
router.addRoutes(adminRoutes);
}
})
// 动态渲染侧边栏, 以下是侧边栏核心代码
``` ## (六) 自定义vue指令 ##### 01 一个简单的vue指令(是字体变红色) ```javascript// C1.vue
// C2.vue
// 后代组件
DOM 是浏览器概念,浏览器从服务器端读取 html 页面,浏览器将 html 解析成一棵元素嵌套关系的 dom 树,用对象来表示页面上的元素,并提供操作 dom 对象的 api。 2. **虚拟 DOM:** 程序员用 js 对象来模拟页面上 dom 元素的嵌套关系( 本质 ),为了实现页面元素的高效更新( 目的 ) 3. 虚拟 DOM 是真实 DOM 结构的映射,即一个数据集合 3. 虚拟DOM的核心就是一个diff算法:使用一个render()方法就可以将vNodes(虚拟dom节点)还原成真实的Html页面 ```html // 对于这个Html 文件
Hello, the world! Hello, the code!
<a name="L90hF"></a>
## (十二) vue双向数据绑定原理
**原理: **<br />vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。<br />具体步骤:<br />**第一步:**需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter 这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化
**第二步:**compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
**第三步:**Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情是:<br />在自身实例化时往属性订阅器(dep)里面添加自己 自身必须有一个 update()方法 待属性变动 dep.notice()通知时,能调用自身的 update() 方法,并触发 Compile 中绑定的回调,则功成身退。 第四步:MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过 Observer 来监听自己的 model 数据变化,通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据 model 变更的双向绑定效果。
```typescript
<script>
var obj = {};
var temp = null;
Object.defineProperty(obj, "username", {
set: function (newValue) {
console.log('给属性赋值,触发set函数')
temp = newValue;
},
get: function () {
console.log('读取属性,触发get函数');
return temp;
}
})
obj.username = '张三';
let username = obj.username;
</script>
(十三) keep-alive
- 用户在某个列表页面选择筛选条件过滤出一份数据列表,由列表页面进入数据详情页面,再返回该列表页面,我们希望:列表页面可以保留用户的筛选(或选中)状态。
- keep-alive就是用来解决这种场景。当然keep-alive不仅仅是能够保存页面/组件的状态这么简单,它还可以避免组件反复创建和渲染,有效提升系统性能。总的来说,keep-alive用于保存组件的渲染状态。
- keep-alive的生命周期
- 初次进入时:created > mounted > activated;退出后触发 deactivated
- 再次进入:会触发 activated;事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中
- 应用实例 ```javascript //1.router.js在需要缓存的路由组件添加keepAlive meta: { title: ‘demo’, keepAlive: true },
//2.路由出口配置
//3.添加列表组件和详情组件 // 列表组件
//详情组件
注意: 要把keep-alive放在父路由上, 不然不生效
javascript
// 列表进详情, 返回时滚动条回原来位置
<a name="aVPTI"></a>
## <br />
<a name="4QRPd"></a>
## (十四) 数字动画
[https://cn.vuejs.org/v2/guide/transitioning-state.html](https://cn.vuejs.org/v2/guide/transitioning-state.html)
```javascript
<template>
<p>{{ num }}</p>
</template>
<script>
import gsap from "gsap";
export default {
data() {
return {
number: 0,
};
},
computed:{
// 不显示小数点
num() {
return this.number.toFixed(0);
}
},
created() {
setTimeout(() => {
let newVal = 1000;
gsap.to(this.$data, { duration: 0.5, number: newVal });
}, 2000);
},
};
</script>