Vue 04Day Knowledge Point

一.组件进阶

一.ref 和 $refs

作用:利用 ref 和 $refs 可以用于 获取 dom 元素, 或者组件实例

1.获取原生DOM标签

添加ref属性,获取目标标签

Vue-Day 04 - 图1

Vue-Day 04 - 图2

2.通过ref属性获取组件对象

通过 this.$refs 获取组件对象, 可调用组件对象里方法等

Vue-Day 04 - 图3

二.$nextTick

1.$nextTick的学习

需求:点击改data的数据, 获取原生DOM内容

1.创建标签显示数据

  1. <p ref = "a">数字:{{count}}</p>
  2. <button @click="btn">点击加一</button>

2.点击+1, 马上获取原生DOM内容

  1. methods: {
  2. btn(){
  3. this.count++;
  4. console.log(this.$refs.a.innerHTML);
  5. }
  6. }

$nextTick:等DOM更新后, 才会触发执行此方法里的函数体

Vue-Day 04 - 图4

data改变,更新DOM是异步的,我们可以运用this.$nextTick里的函数体获取到更新后的DOM

2.$nextTick小案例

需求:点击按钮自身隐藏, 出现输入框并马上处于激活状态

注意: 一定要用v-if来写 (保证DOM异步更新前获取不到输入框, 可以体现$nextTick的价值)

  1. <template>
  2. <!-- 准备好input 和 按钮 -->
  3. <!-- 按钮点击 会显示 input (点击按钮消失,显示input,并显示focus焦点) -->
  4. <!-- 给按钮绑定一个点击事件 @click = "searchFn" 然后在methods中 调用事件函数
  5. 因为input 是进行隐藏 我们使用v-if 按钮则运用v-else 进行一个切换
  6. 在点击事件函数中 进行v-if="show" 的取反 单点击按钮 按钮隐藏 input框显示
  7. -->
  8. <!-- 获取焦点,就要找dom 给input 添加一个ref 获取dom中的focus
  9. this.$refs.inp.focus()
  10. 因为他是异步 所以需要用
  11. this.$nextTick(()=>{
  12. console.log(this.$refs.inp.focus());
  13. });
  14. -->
  15. <div>
  16. <input type="text" placeholder="输入搜索的关键字" v-if="show" ref="inp" />
  17. <button v-else @click="searchFn">点击搜索</button>
  18. </div>
  19. </template>
  20. <script>
  21. export default {
  22. data(){
  23. return{
  24. show:false,
  25. }
  26. },
  27. methods:{
  28. searchFn(){
  29. this.show = !this.show;
  30. this.$nextTick(()=>{
  31. console.log(this.$refs.inp.focus());
  32. // console.log(this.$refs.inp);
  33. });
  34. }
  35. }
  36. }
  37. </script>
  38. <style>
  39. </style>

三.dynamic 动态组件

1.基本概念

动态组件:可以改变的组件

动态组件可以解决多组件同一个位置,切换显示的需求

基本语法:

1.compontent 组件(位置) + is属性(哪个组件)

Vue-Day 04 - 图5

2.修改is属性绑定的值 => 切换组件

3.动态组件切换的时候会销毁

4.可以缓存 keep-alive

2.动态组件点击切换小案例

Vue-Day 04 - 图6

当点击指定的按钮就会切换相应内容

  1. <template>
  2. <div>
  3. <button @click="name = 'little-cat'">小猫</button>
  4. <button @click="name = 'little-dog'">小狗</button>
  5. <button @click="name = 'little-pig'">小猪</button>
  6. <component :is="name"/>
  7. </div>
  8. </template>
  9. <script>
  10. import Cat from './components/little-cat.vue';
  11. import Dog from './components/little-dog.vue';
  12. import Pig from './components/little-pig.vue';
  13. export default {
  14. data(){
  15. return{
  16. name:'little-cat'
  17. }
  18. },
  19. components:{
  20. 'little-cat':Cat,
  21. 'little-dog':Dog,
  22. 'little-pig':Pig,
  23. }
  24. }
  25. </script>
  26. <style>
  27. </style>

三个子组件都是按照以下代码操作(代码一样,只放一份)

  1. <template>
  2. //将小猫改成其他名称 分别放入对于的子组件即可
  3. <div><h1>小猫</h1></div>
  4. </template>
  5. <script>
  6. export default {}
  7. </script>
  8. <style>
  9. </style>

二.自定义指令

1.自定义指令

自定义指令即自己定义的指令,封装dom操作,扩展额外功能

有局部注册 和 全部注册

需求:当页面加载时,让元素将获得焦点

Vue-Day 04 - 图7

局部注册

  1. <template>
  2. <!-- 当我们需要封装dom 扩展额外功能的时候我们就使用自定义指令 -->
  3. <div>
  4. <h1 v-color v-backgroundColor v-bold>你好</h1>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. // 局部注册
  10. directives:{
  11. "color":{
  12. inserted(dom){
  13. dom.style.color = 'red';
  14. }
  15. },
  16. "backgroundColor":{
  17. inserted(dom){
  18. dom.style.backgroundColor = 'yellow';
  19. }
  20. }
  21. }
  22. }
  23. </script>
  24. <style>
  25. </style>

全局注册

  1. // 全局注册
  2. // Vue.component("组件标签名",组件对象);
  3. // 全局注册 ——自定义属性
  4. Vue.directive("bold",{
  5. "inserted"(dom){
  6. dom.style.fontWeight = 'bold';
  7. }
  8. })

2.自定义指令的值

语法:在绑定指令时,可以通过“等号”的形式为指令绑定具体的参数值

通过 binding.value 可以拿到指令值,指令值修改会触发 update

  1. <template>
  2. <!-- 当我们需要封装dom 扩展额外功能的时候我们就使用自定义指令 -->
  3. <div>
  4. <!-- 给指定添加颜色 可以 但是不能直接添加 要在数据中传递颜色 然后binding binding.value-->
  5. <h1 v-color='red' v-bold>你好</h1>
  6. <h1 v-color='yellow' v-bold>你好</h1>
  7. <h1 v-color='blue' v-bold>你好</h1>
  8. <!-- 直接在点击事件赋值是不可以的 需要更新它 -->
  9. <button @click="red = 'black'">把红色变成黑色</button>
  10. </div>
  11. </template>
  12. <script>
  13. export default {
  14. data(){
  15. return{
  16. red:'red',
  17. yellow:'yellow',
  18. blue:'blue',
  19. }
  20. },
  21. // 局部注册
  22. directives:{
  23. "color":{
  24. inserted(dom,binding){
  25. console.log("指令参数",binding);
  26. dom.style.color = 'red';
  27. // 这里的dom就是我们指令所在的标签的dom 修改dom颜色
  28. dom.style.color = binding.value;
  29. },
  30. // update 会在指令的值v-指令 = "变量" 变量变化时候触发
  31. update(dom,binding){
  32. dom.style.color = binding.value;
  33. }
  34. },
  35. "backgroundColor":{
  36. inserted(dom){
  37. dom.style.backgroundColor = 'yellow';
  38. }
  39. }
  40. }
  41. }
  42. </script>
  43. <style>
  44. </style>

三.插槽

Vue-Day 04 - 图8

1.默认插槽

插槽:组件内部分内容允许外部传入

组件的内容部分,不希望写死,希望能使用的时候自定义,使用插槽。

Vue-Day 04 - 图9

  1. <template>
  2. <div class="container">
  3. <category-category title="美食" :list="foods">
  4. <img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
  5. </category-category>
  6. <category-category title="游戏" :list="games">
  7. <ul>
  8. <li v-for="(g,index) in games" :key="index">{{g}}</li>
  9. </ul>
  10. </category-category>
  11. <category-category title="电影" :list="films">
  12. <video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
  13. </category-category>
  14. </div>
  15. </template>
  16. <script>
  17. import category from './components/category.-cate.vue'
  18. export default {
  19. components:{
  20. 'category-category':category
  21. },
  22. data(){
  23. return{
  24. foods:['火锅','烧烤','汉堡','牛排'],
  25. games:['lol','穿越火线','QQ飞车','红色警戒'],
  26. films:['《蜡笔小新》','《名侦探柯南》','《赌侠》','《赌圣》']
  27. }
  28. }
  29. }
  30. </script>
  31. <style scoped>
  32. .container{
  33. display: flex;
  34. justify-content: space-around;
  35. }
  36. img{
  37. width: 100%;
  38. }
  39. video{
  40. width: 100%;
  41. }
  42. </style>
  1. <template>
  2. <div class="category">
  3. <h3>{{title}}分类</h3>
  4. <!-- 定义个插槽 (挖个坑 等着组件的使用者进行填充) -->
  5. <slot>默认值,当使用者没有传递具体结构,我就出现</slot>
  6. <!-- <ul>
  7. <li v-for="(item,index) in list" :key="index">{{item}}</li>
  8. </ul> -->
  9. <!-- http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 -->
  10. </div>
  11. </template>
  12. <script>
  13. export default {
  14. // props:['list','title']
  15. props:['title']
  16. }
  17. </script>
  18. <style>
  19. .category{
  20. background-color: skyblue;
  21. width: 200px;
  22. height: 300px;
  23. }
  24. h3{
  25. text-align: center;
  26. background-color: orange;
  27. }
  28. </style>

2.具名插槽

Vue-Day 04 - 图10

  1. <template>
  2. <div class="container">
  3. <category-category title="美食" :list="foods">
  4. <img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
  5. <a slot="footer" href="http://baidu.com">更多美食</a>
  6. </category-category>
  7. <category-category title="游戏" :list="games">
  8. <ul slot="center">
  9. <li v-for="(g,index) in games" :key="index">{{g}}</li>
  10. </ul>
  11. <div class="foot" slot="footer">
  12. <a href="http://baidu.com">单机游戏</a>
  13. <a href="http://baidu.com">网络游戏</a>
  14. </div>
  15. </category-category>
  16. <category-category title="电影" :list="films">
  17. <video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
  18. <!-- <template slot="footer"> -->
  19. <template v-slot:footer>
  20. <div class="foot">
  21. <a href="http://baidu.com">经典</a>
  22. <a href="http://baidu.com">热门</a>
  23. <a href="http://baidu.com">推荐</a>
  24. </div>
  25. <h4>欢迎前来观看</h4>
  26. </template>
  27. </category-category>
  28. </div>
  29. </template>
  30. <script>
  31. import category from './components/category.-cate.vue'
  32. export default {
  33. components:{
  34. 'category-category':category
  35. },
  36. data(){
  37. return{
  38. foods:['火锅','烧烤','汉堡','牛排'],
  39. games:['lol','穿越火线','QQ飞车','红色警戒'],
  40. films:['《蜡笔小新》','《名侦探柯南》','《赌侠》','《赌圣》']
  41. }
  42. }
  43. }
  44. </script>
  45. <style scoped>
  46. .container,.foot{
  47. display: flex;
  48. justify-content: space-around;
  49. }
  50. img{
  51. width: 100%;
  52. }
  53. video{
  54. width: 100%;
  55. }
  56. h4{
  57. text-align: center;
  58. }
  59. </style>
  1. <template>
  2. <div class="category">
  3. <h3>{{title}}分类</h3>
  4. <!-- 定义个插槽 (挖个坑 等着组件的使用者进行填充) -->
  5. <slot name="center">默认值,当使用者没有传递具体结构,我就出现1</slot>
  6. <slot name="footer">默认值,当使用者没有传递具体结构,我就出现2</slot>
  7. <!-- <ul>
  8. <li v-for="(item,index) in list" :key="index">{{item}}</li>
  9. </ul> -->
  10. <!-- http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 -->
  11. </div>
  12. </template>
  13. <script>
  14. export default {
  15. // props:['list','title']
  16. props:['title']
  17. }
  18. </script>
  19. <style>
  20. .category{
  21. background-color: skyblue;
  22. width: 200px;
  23. height: 300px;
  24. }
  25. h3{
  26. text-align: center;
  27. background-color: orange;
  28. }
  29. </style>

3.作用域插槽

Vue-Day 04 - 图11

  1. <template>
  2. <div class="container">
  3. <category-category title="游戏" >
  4. <template scope="obj">
  5. <ul>
  6. <li v-for="(g,index) in obj.games" :key="index">{{g}}</li>
  7. </ul>
  8. </template>
  9. </category-category>
  10. <category-category title="游戏" >
  11. <template scope="obj">
  12. <ol>
  13. <li style="color:red" v-for="(g,index) in obj.games" :key="index">{{g}}</li>
  14. </ol>
  15. </template>
  16. </category-category>
  17. <category-category title="游戏">
  18. <template scope="obj">
  19. <h4 v-for="(g,index) in obj.games" :key="index">{{g}}</h4>
  20. </template>
  21. </category-category>
  22. </div>
  23. </template>
  24. <script>
  25. import category from './components/category.-cate.vue'
  26. export default {
  27. components:{
  28. 'category-category':category
  29. },
  30. }
  31. </script>
  32. <style scoped>
  33. .container,.foot{
  34. display: flex;
  35. justify-content: space-around;
  36. }
  37. img{
  38. width: 100%;
  39. }
  40. video{
  41. width: 100%;
  42. }
  43. h4{
  44. text-align: center;
  45. }
  46. </style>
  1. <template>
  2. <div class="category">
  3. <h3>{{title}}分类</h3>
  4. <!-- <slot >默认值,当使用者没有传递具体结构,我就出现1</slot> -->
  5. <slot :games="games">我是默认的一些内容</slot>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. props:['title'],
  11. data(){
  12. return{
  13. games:['lol','穿越火线','QQ飞车','红色警戒'],
  14. }
  15. }
  16. }
  17. </script>
  18. <style>
  19. .category{
  20. background-color: skyblue;
  21. width: 200px;
  22. height: 300px;
  23. }
  24. h3{
  25. text-align: center;
  26. background-color: orange;
  27. }
  28. </style>

4.插槽传参

匿名插槽传参

  1. <template>
  2. <div>
  3. <niming-slot v-slot="obj">
  4. <img :src="obj.zidingyi.url" alt="">
  5. <h1>{{obj.zidingyi.name}}</h1>
  6. <h1>{{obj.zidingyi.age}}</h1>
  7. </niming-slot>
  8. </div>
  9. </template>
  10. <script>
  11. import NingMing from "./components/niming-slot.vue";
  12. export default {
  13. components:{
  14. "niming-slot":NingMing,
  15. }
  16. }
  17. </script>
  18. <style>
  19. </style>
  1. <template>
  2. <div>
  3. <slot :zidingyi="user"></slot>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. data(){
  9. return{
  10. user:{
  11. name:'小明',
  12. age:18, url:"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1113%2F041620104229%2F200416104229-8-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659665716&t=a7f983f36e9540d91b49a362a93540f3",
  13. }
  14. }
  15. }
  16. }
  17. </script>
  18. <style>
  19. </style>

具名插槽传参(需要多个插槽)

  1. <template>
  2. <div>
  3. <personal-info>
  4. <template #header="obj">
  5. <h1>{{obj.headerheader}}</h1>
  6. </template>
  7. <template #tbody="obj">
  8. <h1>{{obj.tbodytbody}}</h1>
  9. </template>
  10. <template #footer="obj">
  11. <img :src="obj.tupian" alt="">
  12. </template>
  13. </personal-info>
  14. </div>
  15. </template>
  16. <script>
  17. import PersonnalInfo from "./components/personal-info.vue"
  18. export default {
  19. components:{
  20. "personal-info":PersonnalInfo,
  21. }
  22. }
  23. </script>
  24. <style>
  25. </style>
  1. <template>
  2. <div>
  3. <slot name="header" :headerheader="user.name"></slot>
  4. <slot name="tbody" :tbodytbody="user.age"></slot>
  5. <slot name="footer" :tupian="user.url"></slot>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. data(){
  11. return{
  12. user:{
  13. name:'小明',
  14. age:18,
  15. url:"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1113%2F041620104229%2F200416104229-8-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659665716&t=a7f983f36e9540d91b49a362a93540f3",
  16. }
  17. }
  18. }
  19. }
  20. </script>
  21. <style>
  22. </style>