vue2语法

基础指令

1.v-bind

将标签属性值变成变量,动态改变标签属性

<a v-bind:href="xxx">去百度</a>
# 简写
<a :href="xxx">去百度</a>

标签属性不加v-bind时它的值"xxx"就是一个固定值,加了v-bind它的值"xxx"就变成了变量。

我们可以在data里新增一个xxx属性并为它赋值。

2.v-on

绑定事件

<button v-on:click="money++">增加余额</button>
<button v-on:click="add">增加余额</button> 
# 简写
<button @click="money++">增加余额</button> 
<button @click="add">增加余额</button>

绑定事件的值可以是简单的运算,比如累加或者三元运算符,也可以是一个方法。我们在methods这个对象中创建add(){}这个方法并执行某些操作。

3.vue中获取事件对象e

  1. 没有传参,通过形参接收
  2. 传参了,通过$event指代对象e
<a href="http://www.taobao.com" @click="goTaobao">淘宝</a>
<a href="http://www.qq.com" @click="goQQ('张老三',$event)">QQ</a>

// 利用事件对象e阻止默认行为
goTaobao(e) {
  e.preventDefault();
  console.log("我阻止了淘宝页面跳转");
},
goQQ(preson, e) {
  e.preventDefault();
  console.log("我阻止了" + preson + "去QQ页面");
}

注意:不传参的情况下add()最好去掉括号,不然很可能拿不到e

4.事件修饰符阻止默认行为

<!--
	事件修饰符 => 修饰事件
	@事件名.prevent => e.preventDefault() 阻止默认行为
	@事件名.stop => e.stopPropagation() 阻止冒泡
	prevent 和 stop 可以嵌套使用前后书写顺序没有影响
-->

<a href="http://www.taobao.com" @click.prevent.stop="goTaobao()">淘宝</a>
<a href="http://www.qq.com" @click.stop.prevent="goQQ('张三',$event)">QQ</a>

5.按键修饰符

@keyup.enter 监听回车键

@keyup.esc 监听返回键

@keyup.up 监听上键

@keyup.down 监下键

@keyup.left 监左键

@keyup.right 监听右键

除一些常规的键盘事件,其他的可以用e.key==="xxx"的形式判断。

6.v-show

语法:v-show="布尔值" true显示 false隐藏

原理:控制css display:none

适用场景:频繁切换

7.v-if

语法:v-if="布尔值" true显示 false隐藏 (控制页面有无该节点)

原理:动态删除 或 创建元素

另外:v-if 是惰性的,如果 v-if="false",那么不会创建该节点!性能更高。

适用场景:要么显示要么隐藏,不太会频繁切换,隐藏时需要移除节点的场景

8.v-model

v-model配合 表单 使用

特点:双向数据绑定

原理:v-bind="value"

注意:v-model不能绑定解构值(详解见《vue中遇到的问题》1)

v-model只能绑属性或值,不能绑函数。

class属性绑定

绑定属性常用写法,true生效,false不生效。

v-bind:class="{ '样式类名': true/false, '样式类名': true/false }"

基本对象

🥀1.computed 计算属性

特点:

  1. 依赖(多个)旧值的到新值
  2. 有缓存,如果依赖的数据未改变,则从缓存中直接拿上次计算的结果。减轻计算量
  3. 当计算属性的值是双向数据绑定(v-model)时,要用完整写法(get,set)
  4. 页面刷新时执行一次,依赖数据改变执行一次
  5. 计算属性可以实现的功能,methods里的函数也能实现。只不过methods每次调用都执行性能不高。

使用场景:分数求和,求平均值

🥀2.watch 侦听器

特点:

  1. 只有watch允许异步操作
  2. 监听 某一个 旧值的改变,然后执行某些操作
  3. 无缓存

使用场景:银行卡余额改变,向后台发送请求,后台发短信提示。

🥀3.components 组件

注意:

  1. 组件名用大驼峰 XxxPage(建议) 或 xxx-page 形式

  2. 局部注册(常用

    • App.vue中

      • import XxxPage from '@/components/子组件名'

      • components:

  3. 全局注册:

    • main.js中

      • import XxxPage from '@/components/子组件名'

      • Vue.components('自定义组件名',XxxPage)

    • App.vue中

      • <自定义组件名></自定义组件名>

props

特点:

  1. 单向向下 数据绑定,父组件数据改变,子组件数据更新。反之不可以。

  2. 只允许父组件修改数据

🥀父传子

思路:

  1. 父组件使用自定义属性,子组件用 props 接收

🥀子传父

思路:

  1. 子组件触发this.$emit('自定义事件名',参数1,参数2...)
  2. 父组件自定义事件,赋值一个方法
  3. 父组件给你方法写逻辑修改父组件中的数据

🥀1.v-model 组件绑定

实现子传父父传子

原理:我们将数据以 :value="数据" 的方式传给子组件,子组件通过 props:['value'] 接收数据, 子组件定义一个事件(例如@click="xxx")。

methods:{xxx(){this.$emit('input',)}}

🥀2.ref 和 refs

作用:获取表单元素,和 document.querySelector('')效果一样。

区别:querySelector是在全局搜索标签,refs是在组件中搜索,性能更高

用法:

// ref注册标签
<h1 ref="dome_h1">我是文章的标题</h1>
// refs获取标签
console.log(this.$refs.dome_h1);

特点:父组件直接获取子组件的数据和方法

$nextTick

作用:实时获取数据更新后的视图层(主要获取视图层包括DOM)

原理:视图更新是异步的微任务,$nextTick也是异步微任务。

具体分析:DOM更新的顺序是子组件先更新,之后父组件更新。因此在子组件中获取的父组件的数据总是更新之前的旧数据,所以 $nextTick 应运而生。

动态组件

作用:根据组件名判断组件是否生效

核心:<component :is="componentId"></component>

原理:component标签内的 is 属性动态绑定子组件的名字,根据子组件的名字显示组件。

<template>
  <div>
     // 点击事件改变属性 componentId 的值,这个值必须为子组件名。
    <button @click="componentId = 'UserAccount'">点我显示UserAccount</button>
    <button @click="componentId = 'UserInfo'">点我显示UserInfo</button>
     // 根据 componentId 的值显示组件
    <component :is="componentId"></component>
  </div>
</template>

<script>
import UserAccount from '@/components/07-UserAccount.vue'
import UserInfo from '@/components/07-UserInfo.vue'
export default {
    components:{
        UserAccount,
        UserInfo
    },
    data() {
        return {
            // 给  componentId 一个默认值,这个值必须是组件名
            componentId:'UserAccount'
        }
    },
};
</script>

使用场景:tap栏切换界面(不常使用),后面路由可以更好的解决。

自定义指令

https://v2.cn.vuejs.org/v2/guide/custom-directive.html

如果想注册局部指令,组件中也接受一个 directives 的选项:

directives: {
  focus: {
    //inserted DOM元素插入到页面节点触发
    inserted: function (el) {
      el.focus()
    }
  }
}

然后你可以在模板中任何元素上使用新的 v-focus property,如下:

<input v-focus>

🥀钩子函数参数

el:指令所绑定的元素,可以用来直接操作 DOM。

directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    el.style.top = binding.value + 'px'
  }
})
<input v-pin>

自定义事件

.sync(vue3中被摒弃)

实现父子数据双向联动,修改任意一个另一个也会改变。

对于 Vue.js 2.x,.sync 实际上是一种语法糖,它简化了双向绑定的模式。下面是一个简单的示例来说明 .sync 语法糖的构造:

// 父组件中
<template>
<ChildComponent :foo.sync="bar" />
</template>

<script>
    export default {
        data(){
            return {
                bar:'你好啊'
            }
        };
</script>
// 子组件中
<template>
<input :value="foo" @input="$emit('update:foo', $event.target.value)" />
</template>

<script>
    export default {
        props: ['foo']
    };
</script>

在父组件中,通过 :foo.sync="bar"bar 传递给子组件的 foo 属性,并实现双向绑定。注意,.sync 修饰符实际上是通过 :value@input 的组合来实现的。

在子组件中,使用 :value="foo" 将父组件传递的值绑定到输入框的 value 属性上。然后,在输入框的 input 事件中,通过 $emit 方法触发一个名为 update:foo 的自定义事件,并传递当前输入框的值。父组件监听到该事件后,将更新其绑定的属性 bar

总结一下,.sync 语法糖的构造实际上是通过使用 :value@input 的组合,结合自定义事件和 $emit 方法来实现父子组件之间的双向绑定。

v-model(在vue3中构造发生改变)

通过v-mode语法糖实现单纯子传父功能

// 父组件
<template>
  <div>
    <ChildComponent v-model="childData" />
    <p>Received data from child: {{ childData }}</p>
  </div>
</template>

<script>
    export default {
        data(){
            return {
               childData:'你好啊'
            }
        };
</script>
// 子组件
<template>
  <div>
    <input v-model="internalData" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      internalData: ''
    };
  },
  watch: {
    internalData(newValue) {
      this.$emit('input', newValue);
    }
  }
};
</script>

在父组件中,我们使用 v-model="childData" 的语法糖将 childData 数据属性传递给子组件。子组件使用 v-model 中绑定的 input 事件来监听输入框的值变化,并将新值通过 $emit('input', newValue) 发送给父组件。

在子组件中,我们使用 v-model 绑定了输入框的值到子组件的 internalData 数据属性上。然后,我们使用 watch 监听 internalData 的变化,并在变化时触发 input 事件,将新值传递给父组件。

父组件通过 v-model 绑定的 childData 数据属性会自动接收子组件传递的值,并在父组件中更新。

通过这种方式,使用 v-model 语法糖可以更简洁地在子组件中向父组件传递数据,并实现双向绑定的效果。

事件&按键修饰符

.native修饰符

作用 : 对于组件,用于监听原生事件,而不是组件内部使用 vm.$emit 触发的事件

原理:在封装好的组件事件上加 事件.native 事件会加在组件内部的根元素上,和scss样式的 ::v-deep 相似

总结: 给组件绑定原生事件后, 如果没触发就加 .native

注意事项: 只有原生事件 (click mouseenter mouseleave...) 才需要加 .native

父组件:

<template>
  <div>  
   <!-- <el-button></el-button> 内部触发了 click 事件 -->
   <!-- <el-dropdown-item></el-dropdown-item> 内部没有触发 click 事件 -->
   <son @click.native="sonClick" />   
  </div>
</template>

<script>
import son from './son.vue'
export default {
  components: {
    son
  },
  methods: {
    sonClick() {
      console.log('son 被点了')
    }
  }
}
</script>

子组件

<template>
  <!-- 如果没有使用 native , 子组件内部使用 `vm.$emit`  才能触发事件 --> 
  <!-- <div @click="$emit('click')"> --> 
  <div>
    我是 SON 组件
  </div>
</template>

API

$attrs

在 Vue 中,$attrs 是一个特殊的属性,用于在子组件中接收父组件传递的非props属性。它是一个对象,包含了父组件中传递的所有非props属性

注意:获取所有非props组件属性(classstyle 除外)

非props属性:没有在子组件中被props接收的属性

vueCopy code<template>
  <div>
    <p>子组件</p>
    <p>属性A: {{ $attrs.attrA }}</p>
    <p>属性B: {{ $attrs.attrB }}</p>
  </div>
</template>

<script>
export default {
  name: 'ChildComponent',
  mounted() {
    console.log(this.$attrs);
  }
}
</script>

在上面的示例中,父组件可以像这样传递属性给子组件:

vueCopy code<template>
  <div>
    <p>父组件</p>
    <ChildComponent attrA="Value A" attrB="Value B" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  }
}
</script>

在子组件中,$attrs 将包含父组件传递的 attrAattrB 属性。

$listeners

在 Vue 中,$listeners 是一个特殊的属性,用于在子组件中接收父组件传递的事件监听器。它是一个对象,包含了父组件中传递的所有事件监听器。

注意:包含了父作用域中的 v-on / @ 事件监听器 (不含 .native 修饰器的)

<template>
  <div>
    <p>子组件</p>
    <button @click="$listeners.click">点击我</button>
	<button @click="$listeners.changePage">点击我切换页面</button> 
  </div>
</template>

<script>
export default {
  name: 'ChildComponent',
  mounted() {
    console.log(this.$listeners);
  }
}
</script>

在上面的示例中,父组件可以像这样传递事件监听器给子组件:

<template>
  <div>
    <p>父组件</p>
    <ChildComponent @click="handleClick" @changePage="changePage"/>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleClick() {
      console.log('点击事件触发');
    },
    // 自定义的方法,传给子组件使用
    changePage(){
      console.log('页面改变了')
    }
  }
}
</script>

在子组件中,$listeners 将包含父组件传递的 click 事件监听器。子组件可以通过 @click="$listeners.click" 将该事件监听器绑定到按钮的点击事件上,使得点击按钮时触发父组件中定义的 handleClick 方法。

需要注意的是,$listeners 对象中的事件监听器只能通过 v-on@ 语法绑定到子组件的具体元素上。它不会自动应用到子组件根元素上。如果要将父组件的事件监听器应用到子组件的根元素上,可以使用 v-on="$listeners"v-bind="$listeners" 来手动绑定。

插槽

🥀默认插槽

使用场景:一个子组件中一个或多个插槽插入相同内容的标签。

🥀具名插槽

使用场景:一个子组件中要用到多个插槽来插入不同的标签

🥀作用域插槽

在Vue.js中,"作用域插槽"(Scoped Slots)是一种特殊类型的插槽,允许组件在插槽中传递数据给父组件,使得父组件可以使用这些数据进行更复杂的处理或渲染。

使用作用域插槽时,您可以在组件中定义带有特殊属性的插槽,并将数据作为该属性的值传递给插槽内容。

下面是一个使用作用域插槽的示例:

<template>
  <div>
    <h1>组件标题</h1>
    <slot :user="user" :list="list" :age="age">
      <p>默认插槽的内容</p> //当父组件中未修改插槽时显示,否则被替换
    </slot>
  </div>
</template>

在上面的例子中,我们在<slot>元素上使用v-bind指令来绑定一系列的属性,他们被集合成一个对象{user:"user",list="list",age="age"}

在父组件中,可以使用带有特殊语法的<template>元素来接收这个对象:

<template>
  <div>
    <my-component>
      <template v-slot:obj="obj"> //v-slot可简写为#
        <p>年龄,{{ obj.age }}!</p>
      </template>
    </my-component>
  </div>
</template>

在这个例子中,我们使用v-slot指令来接收名为user的作用域插槽。通过特殊的语法"{ user }",我们将插槽中传递的数据解构为一个名为user的变量,然后可以在插槽内容中使用这个变量进行渲染。

最终渲染的结果将是:

<div>
  <h1>组件标题</h1>
  <p>欢迎,John Doe!</p>
</div>

通过使用作用域插槽,您可以在组件中传递数据给父组件,并在父组件中使用这些数据进行更高级的渲染或处理操作。这使得组件的灵活性和可重用性更进一步提升。

生命周期钩子

八大生命周期钩子函数:

  • 第一阶段,声明阶段 只能创建组件才触发

​ 1.beforeCreate:data数据初始化之前,组件还没有数据

​ 2.created: data数据初始化之后,可以获取到组件的数据和方法

​ 3.beforeMount:DOM渲染之前,DOM还没渲染

​ 4.mounted:DOM渲染之后,可以操作DOM了

  • 第二阶段,运行阶段 数据更新->视图更新

​ 5.beforeUpdate: 数据更新,DOM更新前

​ 6.updated : 数据更新,DOM更新后

  • 第三阶段,销毁阶段 组件销毁(v-if,动态组件,路由跳转)

​ 7.beforeDestroy: 组件销毁前 //关闭定时器,全局事件(resize,scroll)

​ 8.destroyed : 组件销毁后

  • 用于处理组件被缓存时的激活和停用事件。

​ 9.activated:组件激活时被调用

​ 10.deactivated:组件失活时被调用(页面跳转、组件消失)

注意:

我们通常在created钩子执行时发送ajax请求,这样就避免了一次页面渲染,提高性能。

如果在mounted执行时发送ajax请求,它会先DOM渲染,由于没有发ajax所以渲染的是空数据。此时我们发送ajax获得数据,数据更新DOM又渲染一次造成不必要的性能浪费。

router路由

作用:以单页面实现页面跳转的效果,网页不会刷新。主要提高用户体验。

缺点:首次加载较慢

本质:路径与组件的映射关系,改变url地址后缀的hash值,不同的页面组件生效。

路由原生语法(了解)

两种:hash 模式和 history 模式

https://blog.csdn.net/qq_53061847/article/details/125018494

hash模式

vue2中最高版本的router是5.3.1,更高版本是给vue3使用的。

npm i vue-router@5.3.1

vue中默认的hash模式路由

#/xxx/ 的模式就是hash模式,url地址的hash值改变不会刷新页面
https://music.163.com/#/my/

原理:

①点a

②url地址改变 http://localhost:8080/#/xxx

③路由会检测到url地址改变,hashChange事件触发

④去路由表routes查复合path路径的对象

⑤去router-view去渲染 对象.component 保存的组件

用法:

1.在src下创建一个views文件夹,专门用来存储页面组件,配合路径使用

|__src

​ |__views 页面组件,配合路径使用

​ |__FindPage.vue

​ |__MyPage.vue

​ |__PartPage.vue

​ |__compontents 复用组件,展示数据,常用于复用

​ |__HeadPage.vue

​ |__BodyPage.vue

​ |__FootPage.vue

2.在src下创建一个router文件,在文件下生成一个index.js文件,专门用来统一管理所有路由。

App.vue文件

<template>
<div>
    <div class="footer_wrap">
       <!-- <a href="#/find">发现音乐</a>
        <a href="#/my">我的音乐</a>
        <a href="#/part">朋友</a>
		-->
        <!-- <router-link to="find"> 是路由自带的标签用于代替a标签,to相当于href可省略#。同时自带/-->
        <router-link to="find">发现音乐</router-link>
        <router-link to="my">我的音乐</router-link>
        <router-link to="part">朋友</router-link>
    </div>
    <div class="top">
        <!-- 将来我们需要指定路由出口的地方 -->
    </div>
    </div>
</template>

index.js文件

// ①引入路由
import VueRouter from 'vue-router'
import Vue from 'vue'
// ②注册路由组件
Vue.use(VueRouter)
// ③创建路由实例对象,配置路由规则
const router = new VueRouter({
    routes: [
        { path: '/', redirect: '/find' },
        { path: '/find', component:  ()=>import('@/view/FindPage.vue')},
        { path: '/my', component:  ()=>import('@/view/MayPage.vue')},
        { path: '/part', component: ()=>import('@/view/PartPage.vue')},
        {path: '/*', component: ()=>import('@/view/NoFindPage.vue')}
    ] //路由规则,url和组件的对应关系
})
// ④将配置好的路由对象暴露出去
export default router

3.在main.js中引入路由,可全局使用

// ⑤引入路由对象
import router from '@/router/index'

new Vue({
  router, // ⑥注入router
  render: h => h(App),
}).$mount('#app')

4.指定路由出口,通常写在App.vue文件中

<template>
<div>
    <div class="footer_wrap">
        <router-link to="find">发现音乐</router-link>
        <router-link to="my">我的音乐</router-link>
        <router-link to="part">朋友</router-link>
    </div>
    <div class="top">
        <!-- ⑦指定路由出口,类似插槽的占位 -->
        <router-view></router-view>
    </div>
    </div>
</template>

history 模式

特点:好看,没有#

核心:history.pushState() 给浏览器增加一条历史记录,用户切换历史记录不会刷新页面。

配置:new VueRouter({mode:'history'}),和路由表平级。

const router = new VueRouter({
  mode:'history', //开启history模式
  routes: [
     { path: '/', redirect: '/find' },
    { path: '/find', component:  ()=>import('@/view/FindPage.vue')},
    { path: '/my', component:  ()=>import('@/view/MayPage.vue')},
    { path: '/part/:name/:name1', component: ()=>import('@/view/PartPage.vue')},
    {path: '/*', component: ()=>import('@/view/NoFindPage.vue')}
  ] //路由规则,url和组件的对应关系
})
image-20230520113852954

如果采用history模式,用户在某个路由下刷新页面,浏览器会以这个路由地址请求数据。服务器没有路由对应的资源,返回404错误。

注意:需要后端配合,如果用户访问的是一个后端不存在的资源路径(在某个路由地址下刷新页面),后端返回index.html

路由懒加载

将组件的加载封装在匿名函数中,当哪个路由被使用时触发对应的函数加载对应的组件。

好处:相对于一次性加载所有组件,懒加载减轻了服务器压力,提高了用户体验。

const Home = () => import('./components/Home.vue');
const About = () => import('./components/About.vue');
const Contact = () => import('./components/Contact.vue');

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  { path: '/contact', component: Contact },
];

const router = new VueRouter({
  routes,
});

$route和$router区别

$route$router是Vue Router提供的两个不同的对象,用于在Vue.js应用程序中处理路由相关的信息和导航。

  1. $route对象:

    • $route是一个表示当前活动路由的对象,包含了当前路由的信息,例如路径、参数、查询参数、哈希等。
    • 它是一个只读属性,用于访问当前路由的信息。
    • 您可以通过this.$route在Vue组件中访问到当前路由对象。
  2. $router对象:

    • $router是Vue Router的实例,它提供了一些方法来进行编程式的路由导航,例如pushreplacego等。
    • 它是用于在Vue组件中进行路由导航的工具,允许您在代码中动态地进行路由跳转。
    • $router对象具有一些方法来处理路由导航,例如this.$router.push用于导航到新的路由。

总结:

  • $route是一个对象,用于访问当前活动路由的信息。
  • $router是Vue Router的实例,提供了方法用于进行编程式的路由导航。

因此,您可以使用$route来访问当前路由的信息,而使用$router来执行编程式路由导航操作。

路由传参跳转

1.声明式导航

1.声明式导航进行路由传参

​ 有两种:一种叫查询参数,一种叫动态参数

2.声明式导航进行路由传参的实现

​ 查询参数方式:①

​ ②目标组件 {{$route.query.属性名}} 方法中 $route 前加this

​ 动态参数方式:①

​ ②路由表中对应路由规则path中添加 path:'/路径/:属性名/:属性名'

​ ③目标组件 {{$route.params.属性名}} 方法中 $route 前加this

2.编程式导航(重点)

第一种 this.$router.push({path:'/路径'})(跳转到路由表中对应路径的路由)

​ 传参:①--->this.$router.push({path:'/路径',query{属性:值})

​ ---> 目标组件 $route.query.属性

​ ②--->this.$router.push({path:'/路径/')

​ --->路由表{path: '/路径/:属性名', component:''}

​ --->目标组件 $route.query.属性

第二种 this.$router.push({name:'路由名'})(跳转到路由表中对应路由名的路由)

​ 传参:①--->this.$router.push({name:'路由名',query)

​ ---> 目标组件 $route.query.属性

​ ②--->this.$router.push({name:'路由名',params)

​ ---> 目标组件 $route.params.属性

3.前进或后退导航

使用$router.go方法进行前进或后退导航:

// 前进一步
this.$router.go(1);
@click("$router.go(1)")
// 后退一步
this.$router.go(-1);
@click("$router.go(-1)")
// 前进两步
this.$router.go(2);
@click("$router.go(2)")

路由重定向

作用:输入网址时让其强制转到某个路由界面。

用法:

// 在路由表第一个写
{ path: '/', redirect: ()=>import('@/view/首页组件.vue')},

vue路由 - 404

404:找不到路径匹配时,给个提示页面

路由最后,path匹配*(任意路径) - 前面路径都不匹配就匹配这个。

为什么要写在最后呢?应为路由表匹配规则从上到下,匹配成功下面将不再执行。

const router = new VueRouter({
  routes: [
    { path: '/', redirect: '/find' },
    { path: '/find', component:  ()=>import('@/view/FindPage.vue')},
    { path: '/my', component:  ()=>import('@/view/MayPage.vue')},
    { path: '/part/:name/:name1', component: ()=>import('@/view/PartPage.vue')},
    {path: '/*', component: ()=>import('@/view/NoFindPage.vue')}
  ] //路由规则,url和组件的对应关系
})

组件缓存

使用场景:路由切换, 保证组件不被销毁

语法

  • include - 字符串或正则表达式。指定哪些组件会被缓存。
  • exclude - 字符串或正则表达式。指定哪些组件不会被缓存。
  • max - 数字。最多可以缓存多少组件实例。
<keep-alive include="组件名"> //
    <router-view></router-view>
</keep-alive>

两个钩子函数

activateddeactivated 是 Vue 组件的生命周期钩子函数,用于处理组件被缓存时的激活和停用事件。

当一个组件被 <keep-alive> 缓存时,它可能会经历以下生命周期阶段:

  1. 创建和挂载阶段:
    • created: 组件实例被创建后调用。
    • mounted: 组件挂载到 DOM 后调用。
  2. 激活和停用阶段:
    • activated: 当组件被缓存并激活时调用。在组件第一次被缓存后,每次激活时都会调用该钩子函数。
    • deactivated: 当组件被缓存并停用时调用。在组件从活动状态转为非活动状态时,每次停用时都会调用该钩子函数。
  3. 销毁阶段:
    • beforeDestroy: 组件实例销毁之前调用。
    • destroyed: 组件实例销毁后调用。

通过使用 activateddeactivated 钩子函数,你可以在组件被缓存时执行特定的操作,例如重新加载数据或执行清理操作。

利用activated钩子函数,手动让组件每次激活都会发送新的axios请求

App.vue文件

<!-- 一级目录 -->
<keep-alive>
<router-view></router-view>
</keep-alive>

面经详情页.vue组件中

export default {
  name: 'ArticleDetailPage',
 //组件激活时
  activated() {
    //发送axios请求
  },

vuex

本质:一个公共仓库,用来存储公共数据和方法。

使用场景:大型项目,需要较复杂的数据处理(父传子,子传父解决不了的情况,比如一棵树两层三层之间兄弟互传数据)。

结构

export default new Vuex.Store({
    //公共数据,类似于data,不同于data的函数体,他是一个唯一对象(vuex是一个公共库)不用担心变量名污染问题。
    state: {},
    //公共数据的计算属性,数据只读,不允许修改。利用旧数据得到新数据
    getters: {},
    //唯一修改数据的方法存放处(只能写同步代码,作者要求)
    mutations: {},
    //写异步操作的地方,不可以直接修改state的数据,要通知mutation去修改
    actions: {},
    //创建小仓库,里面包含大仓库中所有方法。注意一定要写namespaced:true,不然里面定义的属性或方法会被当成公共的。
    modules: {
        子仓库名:{
        	namespaced:true, //使其成为带命名空间的独立模块。
        	state: {},  
    		getters: {},
    		mutations: {},
   		 	actions: {},
    		modules:{}
		}
     }
})

使用vuex

在创建项目时,选择自定义模式,勾选Vuex,在src下自动生成一个store文件和一个index.js文件。

|___src

​ |___store

​ |___index.js //vuex仓库所在文件

state单一状态树

它作为一个“唯一数据源”而存在。这也意味着,每个应用将仅仅包含一个 store 实例

它和vue实例中的data最寻同样的规则。

获取state中数据的方法:

在vue文件中(原生)

​ ---this.$store.state.小仓库名.属性名 (只在函数方法中可用)

​ ---{{$store.state.小仓库名.属性名}}

在vue文件中(辅助函数)

​ import {mapState} from 'vuex'

​ computed:{...mapState('小仓库',['属性名1','属性名2'])}

​ ---{{属性名}}

​ ---this.属性名

在js文件按中

​ import store from 'vuex'

​ ---store.state.小仓库名.属性名 (只在函数方法中可用)

getters

他和vue实例中的计算属性具有相同规则

特点:数据只读,不允许修改。

应用:可以利用一些数组或字符串方法获得一些新数据。

获取getter中数据的方法:

在vue文件中(原生)

​ ---this.$store.getters.小仓库名.属性名 (只在函数方法中可用)

​ ---{{$store.getters.小仓库名.属性名}}

在vue文件中(辅助函数)

​ import {mapGetters} from 'vuex'

​ computed:{...mapGetters('小仓库名',['属性名1','属性名2'])}

​ ---{{属性名}}

​ ---this.属性名

在js文件按中

​ import store from 'vuex'

​ ---store.getters.小仓库名.属性名 (只在函数方法中可用)

mutations

唯一修改数据的方法存放处(只能写同步代码,作者要求)

特点:mutations中自带两个属性,statepaylode

  • state: 就是数据对象
  • paylode: 提交载荷,大多情况下载荷应该是一个对象,这样我们就可以一次传递多个数据。
mutations: {
  increment (state, payload) { //这里我们只能有一个payload载荷(形参),只能接收一条数据。state是回调。
    state.count += payload.amount
  }
}

获取mutations中方法的方法:

vue文件中的方法

this.$store.commit('小仓库名/increment', 10) //一条数据
this.$store.commit('小仓库名/increment', {}) //多条数据
this.$store.commit('小仓库名/increment', [10,11,12])//多条数据

js文件中的方法

import store from '@/store'
store.commit('小仓库名/increment', 10) //一条数据
store.commit('小仓库名/increment', {}) //多条数据
store.commit('小仓库名/increment', [10,11,12])//多条数据

Actions

写异步操作的地方,不可以直接修改state的数据,要通知mutation去修改

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,

因此你可以调用 context.commit 提交一个 mutation,

或者通过 context.statecontext.getters 来获取 state 和 getters。

特点:mutations中自带两个属性,contextpaylode

  • context: 与 store 实例具有相同方法和属性的对象(但不是store)
  • paylode: 提交载荷,大多情况下载荷应该是一个对象,这样我们就可以一次传递多个数据。
actions: {
  _increment (state, payload) { //这里我们只能有一个payload载荷(形参),只能接收一条数据。state是回调。
    context.commit('小仓库名/方法名',参数) //调用mutations中的方法,可传参
  }
}

获取actions中方法的方法:

vue文件中的方法

// 这种方法只能在函数体中使用,不能直接暴露在外使用
this.$store.dispatch('小仓库名/_increment', 10) //一条数据
this.$store.dispatch('小仓库名/_increment', {}) //多条数据
this.$store.dispatch('小仓库名/_increment', [10,11,12])//多条数据

辅助函数写法

import { mapActions } from 'vuex'
methods: {
  ...mapActions('小仓库名',['方法名']) //这样小仓库中Actions对象中的方法就被映射过来了,可直接使用。
}

js文件中的方法

import store from '@/store'
// 这种方法只能在函数体中使用,不能直接暴露在外使用
store.dispatch('小仓库名/_increment', 10) //一条数据
store.dispatch('小仓库名/_increment', {}) //多条数据
store.dispatch('小仓库名/_increment', [10,11,12])//多条数据

module

Vuex 允许我们将 store 分割成模块(module)

每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

注意: 子模块中一定要加 namespaced: true,主要作用让子模块成为独立模块拥有独立作用域。

抽离写法

store/cart.js 小仓库模块

import axios from 'axios'
export default {
  namespaced: true, //开启独立作用域
  state: {},
  getters: {},
  mutations: {},
  actions: {}
}

store/index.js 大仓库(唯一公共仓库)

import Vue from 'vue'
import Vuex from 'vuex'
import cart from './cart' //引入子仓库
//注册Vuex
Vue.use(Vuex)
//创建并暴露出store仓库
export default new Vuex.Store({
  state: {},
  getters: {},
  mutations: {},
  actions: {},
  modules: {
    cart //嵌入子仓库
  }
})

修改组件内样式

scss使用 ::v-deep

sass和less的样式穿透 使用 /deep/

stylus的样式穿透 使用 >>>

posted @ 2023-07-13 14:28  莫扎特03  阅读(111)  评论(0编辑  收藏  举报