赞
踩
目录
8.1.1 传给v-bind:class一个对象,以动态切换class
8.2.1 把一个数组传给 v-bind:class,以应用一个 class 列表
13.4.2 vuex中 this.$store.dispatch() 与 this.$store.commit()方法的区别
(部分图例引用黑马教程及其他文章来源)
数据的变化会驱动视图自动更新。
在网页中,form负责采集数据,Ajax负责提交数据。数据源的变化,会被自动渲染到页面上;页面上表单采集的数据发生变化的时候,会被 vue 自动获取到,并更新到数据源中。
MVVM 是 vue 实现数据驱动视图和双向数据绑定的核心原理。MVVM 指的是 Model、View 和 ViewModel,它把每个 HTML 页面都拆分成了这三个部分,如图所示:
注:
1、当数据源发生变化时,会被 ViewModel 监听到,VM会根据最新的数据源自动更新页面的结构。
2、当表单元素的值发生变化时,也会被VM监听到,VM会把变化过后最新的数据自动同步到Model数据源中。
内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有如下 3 个:
(注意:插值表达式只能用在元素的内容节点中,不能用在元素的属性节点中!)
v-bind:为元素的属性动态绑定属性值,则需要用到 v-bind 属性绑定指令。
- <!--html-->
- <a :href="'https://www.runoob.com/vue2/'+url">点击跳转vue菜鸟教程</a>
-
- <!--script-->
- const vm2=new Vue({
- el:'#box2',
- data:{
- url:'vue-tutorial.html'
- }
- })
vue提供了v-on事件绑定指令,用于为DOM元素绑定事件监听。
- <button @click="add">自增</botton>
- <button @click="changeColor">变色</botton>
- data(){
- return{
- count:'',
- }
- }
- methods:{
- add(){
- this.count++;
- },
- changeColor(e){
- e.target.style.backgroundColor='red';
- }
- }
- v-if、v-else、v-else-if条件性的渲染某元素,判定为true时渲染,否则不渲染
- 两者区别:v-if条件不满足不渲染,v-show条件不满足令其display为none
- <div v-if="score<60">不及格</div>
- <div v-else-if="60<=score&&score<90">中等</div>
- <div v-else="score>=90">优秀</div>
-
- <div v-show="true">display:block显示</div>
- <div v-show="false">display:none隐藏</div>
注意:不推荐在同一元素上使用 v-if 和 v-for (详情请查看官网)
生命周期概念:生命周期是指一个组件从创建 > 运行 > 销毁的整个过程,强调的是一个时间段。
生命周期函数概念:是由 vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行。
(注意:生命周期强调的是时间段,生命周期函数强调的是时间点 。)
- <template>
- <div class="test-container">
- <h3 id="myh3">Test.vue 组件 --- {{ books.length }} 本图书</h3>
- <p id="pppp">message 的值是:{{ message }}</p>
- <button @click="message += '~'">修改 message 的值</button>
- </div>
- </template>
-
- <script>
- export default {
- props: ['info'],
- data() {
- return {
- message: 'hello vue.js',
- books: []
- }
- },
- watch: {
- message(newVal) {
- console.log('监视到了 message 的变化:' + newVal)
- }
- },
- methods: {
- },
-
- beforeCreate() {
- // 创建阶段的第1个生命周期函数。在这个函数无法访问data、prors、methods
- //很少有
- },
- created() {
- // 组件只是在内存中被创建好,但还未被渲染到页面
- // 经常在它里面,调用 methods 中的方法,利用Ajax请求服务器的数据。并且,把请求到的数据,转存到 data 中,供 template 模板渲染的时候使用!
- //可以访问data、prors、methods
- this.initBookList()
- },
- beforeMount() {
- //只是在内存上编译好HTML
- //将在渲染组件时执行的操作
- //很少用
- },
-
- mounted() {
- //在此之前DOM还没被渲染,但此时在mounted()时DOM已经被渲染
- // 如果要操作当前组件的 DOM,最早只能在 mounted 阶段执行
- //组件创建阶段到此结束
- },
- beforeUpdate() {
- //已经根据拿到最新数据,还没完成组件DOM结构的渲染
- },
- // 当数据变化之后,为了能够操作到最新的 DOM 结构,必须把代码写到 updated 生命周期函数中
- updated() {
- //已经根据最新数据,完成组件DOM结构的渲染。可以被执行多次(因为数据会变化多次)
- //组件运行阶段到此结束
- },
- beforeDestroy() {
- this.message = 'aaa'
- },
- destroyed() {
- //组件销毁阶段到此结束
- }
- }
- </script>
当组件第一次被创建,会执行created生命周期函数,也会执行activated生命周期函数。之后组件再被激活,只会触发activated而不会触发created。
使用:
- <keep-alive>
- <组件名></组件名>
- <keep-alive>
- // 只缓存组件name为a和b的组件
- <keep-alive include="a,b">
- <component />
- </keep-alive>
-
- // 组件name为c的组件不缓存(可以保留它的状态或避免重新渲染)
- <keep-alive exclude="c">
- <component />
- </keep-alive>
-
- // 如果同时使用include,exclude,那么exclude优先于include, 下面的例子只缓存a组件
- <keep-alive include="a,b" exclude="b">
- <component />
- </keep-alive>
-
- // 如果缓存的组件超过了max设定的值5,那么将删除第一个缓存的组件
- <keep-alive exclude="c" max="5">
- <component />
- </keep-alive>
注意:若组件没有定义自己的name,则默认以注册组件时的名称作为匹配条件。如果定义了name,会以name作为匹配条件。
watch侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。
1、方法格式的侦听器(watch:{……}):
2、对象格式的侦听器 (watch(){……}):
如果要侦听对象里属性的变化,可以如以下操作:
1、定义计算属性:
- new Vue({
- el:"#app",
- data:{ ... },
- methods:{ ... },
- watch:{ ... },
- computed:{
- 计算属性名(){
- 计算过程
- return 属性值
- }
- }
- })
2、在页面上使用计算属性:
<p>{{计算属性名}}</p>
1、computed 和 data同级,计算属性写在computed中;
2、写起来像方法,用起来像属性;
3、计算属性虽然称为属性,但其本质是一个函数;
4、虽然计算属性本质是一个函数,但是在页面中使用计算属性时,不要加();
5、一定要有返回值;
6、可以使用data中的已知值;
7、只要跟计算属性相关的数据发生了变化,计算属性就会重新计算,不相关的属性无论如何变化,都不会导致计算属性变化;
8、计算属性名不能和data中的数据重名(因为要使用data中的数据)。
- 【页面上使用】{{reversedMessage}}
-
- 【data中定义】msg:'New York'
-
- 【计算属性】computed:{
- reversedMsg (){
- return this.msg.split('').reverse().join('')
- }
- }
1、computed计算属性:
作用:
(1)解决模板中放入过多的逻辑会让模板过重且难以维护的问题。例如两个数据的拼接或字体颜色的判断。
(2)它支持缓存,只有依赖的数据发生了变化,才会重新计算。例如模板中多次用到数据拼接可以用计算属性,只执行一次计算,除非数据发生变化。
(3)不支持异步,如果有异步操作,无法监听数据的变化。
(4)如果属性值是函数,默认使用get方法,函数的返回值就是属性的属性值。还有一个set方法,当数据变化时就会调用set方法。
(5)computed的值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data声明过,或者父组件传递过来的props中的数据进行计算的。
2、watch侦听器:
作用:
(1)它不支持缓存,数据变化时,它就会触发相应的操作。
(2)支持异步监听。
(3)接受两个参数,第一个是最新的值,第二个是变化之前的值。
(4)监听data或者props传来的数据,发生变化时会触发相应操作。有两个参数:
immediate:立即触发回调函数。
deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注意的是,deep无法监听到数组和对象内部的变化。
3、总结:
(1)computed 计算属性 : 依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。
(2)watch 侦听器 : 更多的是观察的作用,无缓存性,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作。
4、computed与watch的使用场景:
computed:是多对一,多个数据影响一个。当需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时都要重新计算。
watch:是一对多,一个数据发生变化,执行相应操作会影响多个数据。当需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许执行异步操作 ( 访问一个 API ),限制执行该操作的频率,并在得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
————————————————
版权声明:本板块为CSDN博主「前端路啊」的原创文章,原文链接:原文网址
ref用来辅助开发者在不依赖于jQuery的情况下,获取DOM元素或组件的引用。
- <p ref="mytext">我会被refs获取到</p>
- <button @click="refTest">获取mytext,改变其文本</button>
- refTest(){
- console.log(this.$refs.mytext);
- this.$refs.mytext.innerHTML='我被获取到啦'
- },
【子组件 child.vue】
- showTitle(){
- alert('aaa');
- }
【父组件 parent.vue】
- <child ref="A">流程环节配置</child>
- <button @click="B">点我弹出</button>
- B(){
- this.$refs.A.showTitle();
- },
- <template>
- <div>
- <!-- class和style -->
- <div v-bind:class="{ 'active': isActive, 'text-danger': hasError }">aa</div>
- </div>
- </template>
- <script>
- export default {
- data() {
- return {
- isActive:true,
- hasError:false
- }
- },
- }
- </script>
- <style>
- .active{
- color:#e5c
- }
- .text-danger{
- color: rgb(16, 212, 65);
- }
- </style>
上面的语法表示 active 这个 class 存在与否将取决于数据isActive为true还是false。
此外,v-bind:class 指令也可以与普通的 class attribute 共存。当有如下模板:
- <div
- class="static"
- v-bind:class="{ active: isActive, 'text-danger': hasError }"
- ></div>
-
- data: {
- isActive: true,
- hasError: false
- }
以上渲染的结果是:<div class="static active"></div>
当 isActive 或者 hasError 变化时,class 列表将相应地更新。例如,如果hasError=true,则渲染结果为:<div class="static active hasError"></div>
- <div v-bind:class="classObject"></div>
-
- data: {
- classObject: {
- active: true,
- 'text-danger': false
- }
- }
- <div v-bind:class="[class1,class2]"></div>
- data: {
- class1:'active',
- class2:'box'
- }
以上结果渲染为:<div class="active box"></div>
在数组语法中也可以使用对象语法:
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
这样写将始终添加 errorClass,但是只有在 isActive:true 时才添加 activeClass。
对于带数据绑定 class的组件也同样适用:
<my-component v-bind:class="{ active: isActive }"></my-component>
当 isActive 为 true 时,class="组件原来的样式 active"
方式一:v-bind:class="{ '类名1': data1, '类名2': data2,…… }" data(){ return{ data1:false/true, data2 : false/true …… } } 方式二:v-bind:class="对象名" data(){ return{ 对象名:{ "类名1":false/true, "类名2":true/true, …… } } } 方式三:v-bind:class="[class1,class2,class3,……]" data(){ return{ class1:'类名1', class2:'类名2', …… } }
v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名:
- <div v-bind:style="{color:textColor,fontSize:textSize+ 'px'}">aa</div>
-
- data() {
- return {
- textColor:'#aa8',
- textSize:30
- }
- },
直接绑定到一个样式对象通常更好,这会让模板更清晰:
- <div v-bind:style="styleObject"></div>
-
- data: {
- styleObject:{
- color:'#fff',
- fontSize:25+'px',
- }
- }
v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上:
- <div v-bind:style="[styleObject1,styleObject2]"></div>
- data: {
- styleObject1: {
- color: 'red',
- fontSize:13+'px'
- },
- styleObject2: {
- width: 100+'px',
- height:130+'px'
- }
- }
【父组件】
- <template>
- <div>
- <h2>parent</h2>
- <!--3、传入parentMsg-->
- <child :visible="visible"></child>
- </div>
- </template>
- <script>
- //1、引入子组件
- import child from './child.vue'
- export default {
- data() {
- return {
- //2、定义要传入子组件的数据parentMsg
- visible:'true'
- }
- },
- components:{
- child
- }
- }
- </script>
【子组件】
- <template>
- <div>
- {{visible}}
- </div>
- </template>
- <script>
- export default {
- name:'child',
- //使用prors对象可以设置配置项,使用prors数组不可以。
- // props:{
- // parentMsg:{
- // type:String,
- // default:'i am child'
- // }
- // }
- props:['visible']//接收
- }
- </script>
emit使用方法:this.$emit(‘自定义事件名’,所需要传的值)
【子组件】发送值
- <template>
- <div>
- <button @click="childmsg">点我试试</button>
- </div>
- </template>
- <script>
- export default {
- name:'child',
- data() {
- return {
- msg:"This is the first word from child"
- }
- },
- methods:{
- //点击按钮则向父组件传自定义事件sendmsg,childmsg
- childmsg(){
- this.$emit('sendmsg',this.msg)
- }
- }
- }
- </script>
【父组件】接收值
- <template>
- <div>
- <child @sendmsg="getmsg"></child>
- </div>
- </template>
- <script>
- import child from './child.vue'
- export default {
- data() {
- return {
- }
- },
- components:{
- child
- },
- methods:{
- getmsg(val){
- console.log(val)
- }
- }
- }
- </script>
总结:
- 父传子【父中定义要传的值A,通过:B="A"传给子,子用props:["B"]接收,但props只读,要C:this.B,在子组件中就可以对C进行操作(可以理解为B只是C的初始值)】
- 子传父【在子中的某个事件 this.$emit('传给父组件的事件E',要传的值G),父用@E="F"接收并使用,在F中可以如下定义:F(val){……},此处会把G作为实参传给val】
- import Vue from 'vue'
- export default new Vue()
第二步:在【兄弟组件A】中,引入eventBus.js > 定义数据msg > 编写方法用于发送msg:
- import bus from './eventBus.js'
- <button @click="sendMsg">
- export default{
- data(){
- return{
- msg:'hello'
- }
- },
- methods:{
- sendMsg(){
- bus.$emit('share',this.msg);
- }
- }
- }
- import bus from './eventBus.js'
- <button @click="sendMsg">
- export default{
- data(){
- return{
- newMsg:[]
- }
- },
- created:{
- bus.$on('share',val=>{
- this.newMsg=val;
- })
- }
- }
总体思想:父组件指定内容,子组件渲染内容。
- 【父组件】
- <Left>
- <p>这是在 Left 组件声明的p标签</p>
- </Left>
-
- 【子组件】
- <div class="left-box">
- <span>Left 组件</span>
- <!-- 在 Left 组件内声明一个插槽区 -->
- <slot></slot>
- </div>
【将内容放在指定的插槽内】:
- 【父组件】
- <Left>
- <template v-slot:mySlot>
- <p>这是在 Left 组件声明的p标签</p>
- </template>
- </Left>
-
- 【子组件】
- <div style="color:#33e;background:#ee2">
- <slot name="mySlot"></slot>
- </div>
当需要将内容置入不同组件时,要用带有name属性的插槽:
- <HeaderVue #header>我是来自header的插槽</HeaderVue>
- <Main>
- <template v-slot:box1>我是来自child的插槽box1</template>
- <template v-slot:box2>我是来自child的插槽box2</template>
- </Main>
条件:在封装组件时,为预留的 <slot> 提供属性对应的值
格式:
子组件:<slot v-bind:username='username' name='box1'></slot>
父组件:<template v-slot:box1='username_prors'>
在封装组件时,为预留的 <slot> 提供属性对应的值,叫做作用域插槽。这些属性对应的值可以在父组件中访问到,默认为空对象。
【子组件中】
- <div>
- <slot v-bind:user="user" name="box3"></slot>
- <slot v-bind:msg="hello world" name="box4"></slot>
- </div>
-
- data(){
- return:{
- user:{
- firstname:'lan',
- lastname:'chun'
- }
- }
- }
【父组件中】
- <子组件名>
- <template v-slot:box3="slotProps1">
- {{slotProps1.user.firstname}}
- {{slotProps1.user.lastname}}
- </template>
- <template v-slot:box4="slotProps2">
- {{slotProps2.msg}}
- </template>
- </子组件名>
条件:被提供的内容只有默认插槽时
格式:直接写在组件里
当被提供的内容只有默认插槽时,组件的标签可以被当作插槽的模板来使用,可以把 v-slot 直接用在组件上:
- <子组件名 v-slot:default="slotProps">
- {{ slotProps.user.firstName }}
- </子组件名>
- <current-user>
- <template v-slot:default="slotProps">
- {{ slotProps.user.firstName }}
- </template>
-
- <template v-slot:other="otherSlotProps">
- ...
- </template>
-
- </current-user>
动态指令参数也可以用在 v-slot 上,来定义动态的插槽名:
- <base-layout>
- <template v-slot:[dynamicSlotName]>
- ...
- </template>
- </base-layout>
直接把 slot attribute 用在一个普通元素上:
- <base-layout>
- <h1 slot="header">Here might be a page title</h1>
-
- <p>A paragraph for the main content.</p>
- <p>And another one.</p>
-
- <p slot="footer">Here's some contact info</p>
- </base-layout>
url地址里,‘#’及以后的部分称为哈希地址,可以在控制台用location.hash打印哈希地址
1)用户点击页面上的路由链接
2)导致url地址的Hash值变化
3)前端路由监听到Hash地址的变化
4)前端路由把当前Hash地址对应的组件渲染到浏览器中
- //1、导入Vue和VueRouter的包,定义 (路由) 组件
- import Vue from 'vue'
- import VueRouter from 'vue-router'
- import Prize from '@/components/Prize.vue'
- import Home from "@/components/Main.vue";
- import parent from '@/components/parent'
-
- //2、调用Vue.use()函数,把VueRouter安装为vue插件
- Vue.use(VueRouter);
-
- //3、创建路由的实例对象
- const router =new VueRouter({
- routes:[
- {
- path:'/home',
- component:Home
- },
- {
- path:'/prize',
- component:Prize,
- },
- {
- path:'/parent',
- component:parent
- }
- ]
- })
-
- //4、向外共享路由的实例
- export default router
(在new Vue中的router是“router:router”的简写,若import routerVue from 'xxxx',则应写为router:routerVue)
( "el"等价于$mount)
- import Vue from 'vue'
- import VueRouter from 'vue-router'
- import Prize from '@/components/Prize.vue'
- import Home from "@/components/Main.vue";
- import parent from '@/components/parent'
-
- Vue.use(VueRouter);
-
- const router =new VueRouter({
- routes:[
- {
- path:'/',
- redirect:'/home'
- },
- {
- path:'/home',
- component:Home
- },
- {
- path:'/prize',
- component:Prize,
- },
- {
- path:'/parent',
- component:parent
- }
- ]
- })
-
- export default router
- <!--可以实现路由跳转,如下:-->
- <div id="app">
- <h1>Hello App!</h1>
- <p>
- <!-- 使用 router-link 组件来导航. -->
- <!-- 通过传入 `to` 属性指定链接. -->
- <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
- <router-link to="/home">首页</router-link>
- <router-link to="/prize">奖品</router-link>
- </p>
- <!-- 路由出口 -->
- <!-- 路由匹配到的组件将渲染在这里 -->
- <router-view></router-view>
- </div>
- //也可以在methods中使用,如下:
- methods: {
- goBack() {
- window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/')
- }
- }
- 在进行模块化导入的时候,如果给定的是文件夹,则默认导入这个文件夹下,名字叫做 index.js 的文件
- 当对应的路由匹配成功,将自动设置 class 属性值 。查看API文档学习更多相关内容。
需求:在apptest.vue下路由到about,在about组件下路由到tab1、tab2
- {
- path: '/about',
- component: About,
- // redirect: '/about/tab1',
- children: [
- // 子路由规则
- // 默认子路由:如果 children 数组中,某个路由规则的 path 值为空字符串,则这条路由规则,叫做“默认子路由”
- { path: '', component: Tab1 },
- { path: 'tab2', component: Tab2 }
- ]
- },
- <router-link to="/about">关于</router-link>
- <!-- 作用很单纯:占位符,给要显示的组件预留位置的 -->
- <router-view></router-view>
- <router-link to="/about">关于</router-link>
- <router-link to="/about/tab2">关于</router-link>
-
- <router-view></router-view>
需求:有一个组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。
- const User = {
- template: '<div>User</div>'
- }
-
- const router = new VueRouter({
- routes: [
- // 动态路径参数 以冒号开头
- { path: '/user/:id', component: User }
- //相当于/user?id=xxx
- ]
- })
①可以通过const User = {template: '{{ $route.params.动态路径参数 }}'来查看当前用户的动态路径参数。
打印this时是对象
this.$route 是路由的“参数对象”
this.$router 是路由的“导航对象”
②可以为路由规则开启 props 传参,从而方便的拿到动态参数的值
【index.js】
{ path: '/movie/:mid', component: Movie, props: true },
【movie.vue】
props: ['mid'],
- 在 hash 地址中, / 后面的参数项,叫做“路径参数”
- 在路由“参数对象”中,需要使用 this.$route.params 来访问路径参数
- 在 hash 地址中,? 后面的参数项,叫做“查询参数”
- 在路由“参数对象”中,需要使用 this.$route.query 来访问查询参数
- 在 this.$route 中,path 只是路径部分;fullPath 是完整的地址
【 例如】:
/movie/2?name=zs&age=20 是 fullPath 的值
/movie/2 是 path 的值
- {
- // 会匹配所有路径
- path: '*'
- }
- {
- // 会匹配以 `/user-` 开头的任意路径
- path: '/user-*'
- }
注:当使用通配符路由时,请确保路由的顺序是正确的,也就是说含有通配符的路由应该放在最后。路由 { path: '*' } 通常用于客户端 404 错误。
vue-router中的编程式导航API,常用的导航API有:
①this.$router.push('hash地址')
跳转到指定hash地址,并增加一条历史记录
②this.$router.replace('hash地址')
跳转到指定的hash地址,并替换掉当前的历史记录
③this.$router.go(数值n)
跳回第n条历史记录
- <template>
- <div class="movie-container">
- <button @click="gotoLk">通过 push 跳转到“洛基”页面</button>
- <button @click="gotoLk2">通过 replace 跳转到“洛基”页面</button>
-
- <button @click="goback">后退</button>
- <!-- 在行内使用编程式导航跳转的时候,this 必须要省略,否则会报错! -->
- <button @click="$router.back()">back 后退</button>
- <button @click="$router.forward()">forward 前进</button>
- </div>
- </template>
-
- <script>
- export default {
- name: 'Movie',
- methods: {
- gotoLk() {
- // 通过编程式导航 API,导航跳转到指定的页面
- this.$router.push('/movie/1')
- },
- gotoLk2() {
- this.$router.replace('/movie/1')
- },
- goback() {
- // go(-1) 表示后退一层
- // 如果后退的层数超过上限,则原地不动
- this.$router.go(-1)
- }
- }
- }
- </script>
路由守卫可以控制路由的访问权限。
【index.js】中
- // 为 router 实例对象,声明全局前置导航守卫
- // 只要发生了路由的跳转,必然会触发 beforeEach 指定的 function 回调函数
- router.beforeEach(function(to, from, next) {
- // to 表示将要访问的路由的信息对象
- // from 表示将要离开的路由的信息对象
- // next() 函数表示放行的意思
- // 分析:
- // 1. 要拿到用户将要访问的 hash 地址
- // 2. 判断 hash 地址是否等于 /main。
- // 2.1 如果等于 /main,证明需要登录之后,才能访问成功
- // 2.2 如果不等于 /main,则不需要登录,直接放行 next()
- // 3. 如果访问的地址是 /main。则需要读取 localStorage 中的 token 值
- // 3.1 如果有 token,则放行
- // 3.2 如果没有 token,则强制跳转到 /login 登录页
- if (to.path === '/main') {
- // 要访问后台主页,需要判断是否有 token
- const token = localStorage.getItem('token')
- if (token) {
- next()//如果有token(登录)就放行
- } else {
- // 没有登录,强制跳转到登录页
- next('/login')
- }
- } else {
- next()
- }
- })
如:http://localhost:8080/index?page=1
fullPath:路由全地址,fullPath为/index?page=1
path:路径,不带参数,path为/index
- 1. 路由跳转并携带query参数,to的字符串写法 messageData是一个变量
- <router-link :to="`/home/news?id=001&message=${messageData}`" ></router-link>
-
- 2. 路由跳转并携带query参数,to的对象
- <router-link :to="{
- path:"/home/news",
- query:{
- id:001,
- message:messageData
- }
- }" >
- </router-link>
获取参数:this.$route.query.id 、 this.$route.query.message
方式一:路由跳转并携带param参数,to的字符串写法 ,首先我们要在路由文件中定义我们要传递的参数
- // 1. 路由跳转并携带params参数,to的字符串写法 messageData是一个变量
- <router-link :to="`/home/news/001/${messageData}`" ></router-link> //即{id:001,message:xxx}
跳转时直接斜杠/后面拼接参数
- // 1. 路由跳转并携带params参数,to的字符串写法 messageData是一个变量
- <router-link :to="`/home/news/001/${messageData}`" ></router-link> //即{id:001,message:xxx}
方式二:路由跳转并携带params参数,to的对象写法,不需要在路由文件中定义参数
- <router-link :to="{
- name:"HomeNews", //使用params传参时,必须使用name属性进行路由跳转,不能使用path配置项跳转
- params:{
- id:001,
- message:messageData
- }
- }" ></router-link>
获取参数:this.$route.params.id 、 this.$route.params.message
传参配置: src/router/index.js
- {
- name:'HomeNews'
- path:'news/:id/:message',//二级路由,定义参数,表示第一个参数是id,第二个是message
- component:News,
- // 第一种写法:props值为对象,该对象中所有的key-value最终都会通过props传递给组件news
- // props:{a:1},
- // 第二种写法(只能params):props值为Boolean,为true时把路由收到的`params`参数通过props传递给组件news
- // props:true,
- // 第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传递给组件news
- props:function(route){
- return {
- id:route.query.id,
- message:route.query.message
- }
- },
- },
使用: New.vue
- export default{
- prors:['id','message']
- }
vuex是专为vue.js应用程序开发的状态管理模式。它采用集中存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。vuex也集成刀vue的官方调试工具devtools extension,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能。
当我们在页面上点击一个按钮,它会触发(dispatch)一个action, action 随后会执行(commit)一个mutation, mutation 立即会改变state, state 改变以后,我们的页面会state 获取数据,页面发生了变化。
通俗理解是存储在store里的都是全局变量,可以通过方法提交更新,其他页面和组件也会同步更新,拿到最新的值。状态管理核心状态管理有5个核心,分别是state、getter、mutation、action以及module。
驱动应用的数据源。state为单一状态树,可以使用一个对象包含全部的应用层级状态,state就是数据源。
getter有点类似vue的计算属性computed,当我们需要对数据进行处理,那么我们就需要使用getter,getter会接收state作为第一个参数,而且getter的返回值会根据它的依赖被缓存起来,只有getter中的依赖值(state中的某个需要派生状态的值)发生改变的时候才会被重新计算。
- const getters = {
- getUserState (state) {
- let data;
- if(state.userState==0){
- data='无效'
- }else if(state.userState==1){
- data = '1级'
- }else{
- data = '2级'
- }
- return data;
- }
- }
-
- export default new Vuex.Store({
- state,
- mutations,
- getters
- })
页面上使用这个getters:
计算数据状态:{{$store.getters.getUserState}}
更改store中state状态的唯一方法就是提交mutation,类似vue中的methods。每个mutation都有一个字符串类型的事件类型和一个回调函数,我们需要改变state的值就要在回调函数中改变。我们要执行这个回调函数,那么我们需要执行一个相应的调用方法:store.commit。
响应在 view 上的用户输入导致的状态变化。action可以提交mutation,在action中可以执行store.commit,而且action中可以有任何的异步操作。action处理异步操作,由于mutation都是同步事务,在 mutation 中混合异步调用会导致你的程序很难调试。action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态。
- mutations: {
- addAge: (state, payload) => {
- state.informations.forEach(info => {
- info.age += payload;
- })
- }
- },
- actions: {
- addAge: (context, payload) => {
- setTimeout(function () {
- context.commit("addAge", payload);
- }, 2000);
- }
- }
在组件的methods中能够通过【this.$store.dispatch("addAge", 2);】分发action。
(或者使用mapActions辅助函数将组件的 methods 映射为 store.dispatch 调用)
- methods: {
- addAge() {
- this.$store.dispatch("addAge", 2);
- }
- },
注意:
1、所有 store 中 state 的变更,都放置在 store 自身的 action 中去管理。
2、Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到更新。
3、不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交(commit)mutation。
这两个的区别是存取的方式不同,两个都是传值给vuex的mutation改变state.
- 【存储】this.$store.dispatch("action的方法名",value)
- 【取值】this.$store.getters.action的方法名
- 【存储】this.$store.commit("mutation的方法名",value)
- 【取值】this.$store.state.mutation的方法名
在app.vue里先import store from “./store” 并且在new vue实例的时候加上store,这样就可以全局调用了。
【src/store/index.js】引入Vuex文组件:
- //第一步:使用import引入vue和vuex
- import Vue from 'vue';
- import Vuex from 'vuex';
-
- //第二步:把vuex作为组件引入
- Vue.use(Vuex);
-
- //第三步:实例化vuex.store对象
- //store变量是实例化一个vuex.store
- export const store =new Vuex.Store({
- //第四步:定义state
- //state专门用于保存共享的状态值
- state:{
- //保存登陆状态
- login:false
- },
-
- //第五步:编写方法改变state中的值
- //专门书写方法,用于更新state中的值
- mutations:{
- doLogin(state){
- state.login=true;
- },
- doLoginout(state){
- state.login=false;
- }
- }
- });
【 src/components/Header.vue】组件JS部分:
- <script>
- //使用vuex的mapState需要引入
- import {mapState} form "vuex";
-
- export default{
- name:"Header",
- //引入vuex>store>state中的值,必须在计算属性中书写
- computed:{
- //mapState辅助函数,可以快速引入store中的值
- ...mapState(["login"])
- },
- methods:{
- loginout(){
- //调用store里登出的方法
- this.$store.commit(" doLoginout");
- }
- }
- }
- </script>
【src/components/Login.vue】组件JS部分 :
- <script>
- export default {
- name: "Login",
- data() {
- return {
- };
- },
- methods: {
- doLogin() {
- ……
- // 路由跳转指定页面
- this.$router.push({ path: "/" });
-
- //更新 vuex 的 state的值, 必须通过 mutations 提供的方法才可以
- //通过 commit('方法名') 就可以触发mutations 中的指定方法
- this.$store.commit("doLogin");
- }
- });
- }
- }
- };
- </script>
使用$router.push转到首页url,并且调用store里的登录方法把共享登录状态变成true。
【声明】src/store/index.js:
- import Vuex from 'vuex';
- import Vue from 'vue';
- ……;
- import test from '@/store/modules/test'
-
- Vue.use(Vuex);
- export default new Vuex.Store({
- modules: {
- ……,
- test
- },
- });
【定义】src/store/models/test.js:
- const state={
- username:'lanchun',
- userState:0
- }
- const mutations={
- SetUserName(state,name){
- state.username=name;
- },
- SetUserState(state,num){
- state.userState+=num;
- }
- }
-
- export default{
- state,
- mutations
- }
【使用】src/views/page.vue:
- <template>
- <div>
- <h1>{{$store.state.test.username}}</h1>
- <h1>{{$store.state.test.userState}}</h1>
- 数据状态:
- <a-button @click="addState">状态+1</a-button>
- </div>
- </template>
-
- methods: {
- addState(){
- console.log(this.$store.state.test);
- console.log(this.$store);
- this.$store.commit('SetUserName','张三');
- this.$store.commit('SetUserState',1);
- },
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。