09 $refs使用
作用:获取DOM元素,或者组件实例
使用1:(获取原生DOM)
1.在想要获取的dom标签上,写:ref = “”自己随便取名“” 2 this.$refs.随便取的名.XX属性=xx
使用2:(获取组件对象)
1 在<组件名>上写 ref = ‘’“自己随便取名” 2 this.$refs.自己随便取的名.举例这是个方法名 (获取了子组件里面的函数)
10 $nextTick
作用:等DOM更新后, 触发此方法里的回调函数
他是一个异步的微任务
使用场景:vue更新DOM是异步的。$nextTick可以等待DOM更新后再触发
如:点击搜索按钮, 显示聚焦的输入框, 按钮消失=》默认输入框不显示
methods: { btn() { this.count++; // 数字添加后, 异步更新DOM, 所以马上获取标签的值还是0 console.log(this.$refs.a.innerHTML); // 0 this.$nextTick(() => { console.log("DOM更新后触发$nextTick函数"); console.log(this.$refs.a.innerHTML); // 1 }) },
$nextTick返回Promise对象
上面还可以改成如下写法:
methods: { async searchFn(){ this.isShow = true await this.$nextTick() this.$refs.inp.focus() } }
11 动态组件
是什么:多个组件使用同一个挂载点,并可以动态切换,这就是动态组件
经典使用场景:点击按钮切换不同的输入框
使用方法:1 引入子组件 2 写
注意点:1 .is只能是动态属性=》:is="组件注册后的标签名字符串或data变量"
2.不能直接拿注册标签名赋值使用
总结: vue内置component组件, 配合is属性, 设置要显示的组件标签名字
<template> <div> <button @click="comName = 'UserName'">账号密码填写</button> <button @click="comName = 'UserInfo'">个人信息填写</button> <p>下面显示注册组件:</p> <div style="border: 1px solid red"> <!-- vue内置的组件component, 可以动态显示组件 --> <component :is="comName"></component> </div> </div> </template> <script> import UserName from "./UserName"; import UserInfo from "./UserInfo"; export default { data() { return { comName: "UserName", }; }, components: { UserName, UserInfo, }, }; </script>
12 组件缓存
组件切换会导致组件被频繁销毁和重新创建, 性能不高
作用:使用Vue内置的keep-alive组件, 可以让包裹的组件保存在内存中不被销毁
总结: keep-alive可以提高组件的性能, 内部包裹的标签不会被销毁和重新创建, 触发激活和非激活的生命周期方法
<keep-alive> <!-- vue内置的组件component, 可以动态显示组件 --> <component :is="comName"></component> </keep-alive>
可以使用keep-alive的include属性控制缓存范围
<keep-alive include="name1,name2"> <!-- vue内置的组件component, 可以动态显示组件 --> <component :is="comName"></component> </keep-alive>
13 插槽-
用于实现组件的内容分发, 通过 slot 标签, 可以接收到写在组件标签内的内容
vue提供组件插槽能力, 允许开发者在封装组件时,把不确定的部分定义为插槽
使用方法:
- 子组件内用占位
- 父组件中使用子组件夹着的地方, 传入标签替换slot
1.默认插槽
只能一个,多个用具名插槽
默认内容
2.具名插槽
当一个组件内有2处以上需要外部传入标签的地方
v-bind可以省略成: v-on: 可以省略成@ 那么v-slot: 可以简化成#
总结: slot的name属性起插槽名;使用组件时, template配合#插槽名传入具体html标签或组件
写法一: <div class="container" v-show="isShow"> <slot name="one"></slot> <slot name="two"></slot> </div>
写法2: <Pannel2> <!-- 简化写法 --> <template #one> <div> <p>寒雨连江夜入吴,</p> <p>平明送客楚山孤。</p> <p>洛阳亲友如相问,</p> <p>一片冰心在玉壶。</p> </div> </template> <template #two> <img src="../assets/mm.gif" alt="" /> </template> </Pannel2>
3 作用域插槽
作用: 子组件中的数据, 在给插槽赋值时在父组件环境下使用=> 子传父
总结: 组件内变量绑定在slot上, 然后使用组件v-slot:插槽名字="变量" ,变量上就会绑定slot传递的属性和值
使用方法:
- 创建子组件, 准备slot, 在slot上绑定属性和子组件值
- 使用子组件, 传入自定义标签, 用template和v-slot="自定义变量名"
- 自定义变量名会自动绑定slot上所有属性, 就可以使用子组件内值, 并替换slot位置
父组件
<Pannel3> <template v-slot:one="scope"> {{ scope.row.default2 }} </template> </Pannel3>
子组件
<template> <div> <p>这里是个Pannel3-子组件, 下面是插槽位置</p> <slot name="one" :row="slotDefault">{{ slotDefault.default1 }}</slot> </div> </template> <script> export default { data(){ return { slotDefault: { default1: "无名氏", default2: "孙红雷" } } } } </script>
14 自定义指令
作用:需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令
其实就是利用js封装一些方法
总结: 全局注册自定义指令, 哪里都能用, 局部注册, 只能在当前vue文件里用
v-xxx, 自定义指令, 获取原生DOM, 自定义操作
1.全局注册 main.js
用 Vue.directive()方法来进行注册, 以后随便哪个.vue文件里都可以直接用v-fofo指令
Vue.directive("fofo", { inserted(el){ el.focus() } })
2.局部注册
Direct.vue - 只能在当前组件.vue文件中使用
<template> <div> <input type="text" v-focus /> </div> </template> <script> export default { // 局部注册 directives: { focus: { // 自定义指令名 inserted(el){ // 固定配置项 - 当指令插入到标签自动触发此函数 el.focus() } }, }, }; </script>
3.传参
main.js 中
Vue.directive("color", { inserted(el, binding){ // 插入时触发此函数 el.style.color = binding.value; }, update(el, binding){ // 更新绑定的变量时触发此函数=》手动更新 el.style.color = binding.value; } })
15 路由
作用:专门为SPA提供页面(组件)切换功能=》.vue文件的跳转支持
原理:前端路由的本质, 对url的hash值进行改变和监听,切换对应页面组件的dom结构
是 hash 和 component 的对应关系, 一个哈希值对应一个组件页面
路由本质是就是hash值和组件的对应关系
优点:
- 整体不刷新页面,用户体验更好
- 组件化,数据传递容易, 开发效率高
缺点:
- 一定的学习成本
- 首次加载会比较慢一点
- 不利于seo搜索引擎优化
使用:1.安装 npm i vue-router
2.导入
3.使用路由插件 Vue.use(vueRouter)
4 .创建路由规则
const routes = [ {path:'/', component:XXX }]
5.创建路由对象 --传入规则
const router = new VueRouter({ routes })
6 关联到vue实例
new Vue({ router })
7 路由出口 挂载点 写在具体页面上
2 链接导航
总结: 链接导航, 用router-link配合to, 实现点击切换路由
- vue-router提供了一个全局组件 router-link: 作用用于提供路由链接
- router-link实质上最终会渲染成a链接 to属性等价于提供 href属性
- router-link提供了链接导航高亮的功能
3 链接导航 - 高亮显示
类名:router-link-active
匹配(模糊匹配)url中hash值, 包含to属性值, 链接会自动添加此类名
如果路由中有path='/',就需要使用内置的router-link-exact-active
类名控制高亮
4 跳转传参
在跳转路由时, 可以给跳转的目标组件传值
两种方式:
- query传参
- params传参(动态路由=> 详情页)
总结:
- ?key=value =》 用$route.query.key 取值
- /值-需要提前在路由规则/path/:key =》 用$route.params.key 取值
5 重定向
history模式的path路径不带#号,hash有#号
import NotFound from "@/components/NotFound"; const routes = [ { path: "/", redirect: "/home" // 重定向 }, // ...正常路由 { // 当上面路由都不匹配, 匹配这个通配符, 显示NotFound页面 path: "*", component: NotFound } ]
6编程式导航
语法: $router.push(path:string | opt:object)
通过$router.back()
返回上次访问页面
7 其他跳转方法
语法: $router.replace(path:string | opt:object)
写法1: this.$router.push({ path: "路由路径?参数名=值", })
写法2: this.$router.push({ path: "路由路径", query: { "参数名":值 } })
2 params传参 =》通过$route.params.key
接收参数
一般用在动态路由场景
this.$router.push({ path: "路由路径/参数" })
总结:
path?参数 =》普通传参
path/参数 =》动态路由传参
8 二级路由
- 一级路由path从
/
开始定义 - 二级路由path直接写名字, 无需
/
开头(在对应一级路由的children数组中配置)=》注意跳转时不要加/
- 设置默认显示某个二级路由,path和一级路由保持一致或为空
import Vue from 'vue' import VueRouter from 'vue-router' // 一级路由 import FindMusic from '@/views/FindMusic' import MyMusic from '@/views/MyMusic' // 二级路由 import Recommend from '@/views/Child/Recommend' import Ranking from '@/views/Child/Ranking' import SongList from '@/views/Child/SongList' Vue.use(VueRouter) const routes = [ { path: "/", redirect: "find" }, { path: "/find", // 一级路由 component: FindMusic, // find下的二级路由 children: [ { path: "/find", // 和父路由路径一样,默认加载这个路由 component: Recommend }, { path: "ranking", component: Ranking }, { path: "songlist", component: SongList } ] }, { path: "/my", component: MyMusic } ]; const router = new VueRouter({ routes }) export default router
9 路由守卫
全局前置守卫
路由跳转之前, 会触发一个函数
语法:router.beforeEach((to, from, next) => {})
// 路由前置守卫 router.beforeEach((to, from, next) => { // to代表要跳转到哪个路径去, to的值是个对象可以打印看到 // from代表从哪个路径跳过去 console.log(to); console.log(from); // fullPath带?后面参数的, path是完整的路径 console.log("路由要跳转了"); // 模拟判断登录了没有, 登录后才能去我的音乐 let loginFlag = false; // 假设false代表未登录 if (to.path == "/my" && loginFlag == false) { // 如果去个人中心页面, 判断未登录, 提示登录(并强制跳转回find) alert("请先登录!"); next("/find"); } else { // 如果不去/my页面就直接跳转 next(); } });
全局后置守卫
路由跳转后, 触发的函数
语法:router.afterEach((to, from) => {})