vue实践推荐

Posted haimengqingyuan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue实践推荐相关的知识,希望对你有一定的参考价值。

1.vue

(1)组件

每个组件单独分成文件,如A.vue文件实现A组件;
除index.vue之外文件名推荐大写开头如BaseHeader.vue或横线连接base-header.vue;
基础组件名可以共用相同的前缀,如BaseButton;
组件名应该倾向于完整单词而不是缩写;
组件名推荐多个单词,如TodoItem代替Todo;html模板中引用推荐todo-item
prop定义尽量详细,如指定其类型,必填与否;
props: {
  status: {
    type: String,
    required: true,
    validator: function (value) {
    // 校验方法
      return ***
    }
  }
}

 

 
编辑器通常按照字母顺序组织文件,可以考虑将具有相关关系的组件的命名相关,如都是搜索相关的组件可带公共前缀Search,具有父子关系的组件,可以考虑将子组件命名带上父组件命名参数SearchSidebar.vue NavigationForSearchS idebar.vue;
自闭合组件引用;
<!-- 在单文件组件、字符串模板和 JSX 中 -->
<MyComponent />
<!-- 在 DOM 模板中 -->
<my-component></my-component>
<!-- 在所有地方 -->
<my-component></my-component>
 
在声明 prop 的时候,其命名应该始终使用camelCase,而在模板和 JSX 中应该始终使用 kebab-case;
props: {
  greetingText: String
}
<WelcomeMessage greeting-text="hi"/>

 

多个特性的元素应该分多行撰写,每个特性一行,易读;
<WelcomeMessage
  greeting-text="hi"
  name="hh" />

 

(2)js文件-scss文件

文件名推荐 ‘-‘ 连接
 

(3)watch

watch 一个变量的时候,初始化并不会立即执行,需要在created手动触发一次;推荐添加immediate
watch:{
  searchText:{
    handler:‘getList‘,
    immediate:true,
    <!-- 是否深度监听,如对象 -->
    deep:true
  }
}

监听属性主要是监听某个值发生变化后,对新值去进行逻辑处理。

Watcher 初始化watch vm.$watch

Wacher充当一个中介的角色,数据发生变化的时候通知它,它再通知其他地方;

vm.$watch(‘a.b.c‘, function(new,old){
  // 当data.a.b.c发生变化时,触发该函数执行
})
 
// 只要把watcher实例添加到data.a.b.c属性的Dep中即可;当data.a.b.c的值发生变化时会通知watcher;接着watcher再执行参数中的回调函数;
 

(4)data 响应式数据

组件的 data 必须是一个函数,则每个组件实例都管理其自己的数据,数据间不会相混淆。当 data 的值是一个对象时,它会在这个组件的所有实例之间共享,当修改其中一个组件的数据,其他共享数据组件都会受影响。
data () {
  return {
    foo: ‘bar‘
  }
}
 
vm.$set( target, key, value )
Vue.set(vm.obj,‘k1‘,‘v1‘)
this.$set(this.obj,‘k1‘,‘v1‘)
this.obj = Object.assign({}, this.obj)
this.obj = Object.assign({}, this.obj,{‘k1‘,‘v1‘})
 
对象添加可以使用:
this.$set(对象名,属性,值)
 
若所需数据是响应式的,则需要一开始在data中进行定义,否则后期追加的属性是不具备响应式特征的,vue是数据劫持的方式,后期只通过赋值的方式(this.foo.a=‘a‘)没办法进行劫持(Object.defineProperty()来实现对属性的劫持);需要额外将其处理成响应式的,通过this.$set或Vue.set实现响应式;
this.$set(this.foo,‘aProperty‘,‘aavalue‘)
Vue.set(obj, ‘newProp‘, 123)
或
state.obj = {...state.obj, newProp:123}

 

(5)computed计算属性

需要对数据进行处理之后再显示 格式化输出结果 反转数组
computed:{
  newPrice:function(){
    return this.price=‘¥‘ + this.price + ‘元‘;
  }
}
 
 
computed:{
   reverseNews:function(){
    return this.newsList.reverse();
  }
}
 
把复杂计算属性分割为尽可能多的更简单的属性;
computed: {
  basePrice: function () {
    return this.manufactureCost / (1 - this.profitMargin)
  },
  discount: function () {
    return this.basePrice * (this.discountPercent || 0)
  },
  finalPrice: function () {
    return this.basePrice - this.discount
  }
}

 

(6)指令

v-for v-if:
v-for循环须绑定key,在对比新旧虚拟节点时辨识虚拟节点,更新dom时效率更高;
<ul>
  <li v-for="todo in todos" :key="todo.id">
    {{ todo.text }}
  </li>
</ul>
避免v-for v-if同时作用在同一个元素上 v-for优先级高于v-if; 可以选择多加一层div;
若为了避免渲染本应该隐藏的列表,可以将v-if用于上一层容器上;
若过滤列表中数据,可以使用计算属性代替v-if;
 
指令缩写 (用 : 表示 v-bind: 、用 @ 表示 v-on: 和用 # 表示 v-slot:) 应该要么都用要么都不用;
 
如果一组 v-if + v-else 的元素类型相同,最好使用 key (比如两个 <div> 元素),防止本不相同的元素被识别为相同的元素;
<div v-if="error" key="search-status">
   {{ error }}
</div>
<div v-else key="search-results">
  {{ results }}
</div> 

 

(7)样式

为组件样式设置作用域,可以选择scoped或类名包裹,防止影响全局样式;
为了给样式设置作用域,Vue 会为元素添加一个独一无二的特性,例如 data-v-f3f3eg9。然后修改选择器,使得在匹配选择器的元素中,只有带这个特性才会真正生效;
在 scoped 样式中,类选择器比元素选择器更好,因为大量使用元素选择器是很慢的;
 

(8)渲染

组件模板{{}}内推荐简单表达式,复杂的表达式可选择计算属性或方法或过滤器;如果防止出现短暂{{}}的情况,可以选择使用v-text替换{{}} ;{{}}和v-text方式会将元素当成纯文本输出;v-html会将元素当成HTML标签解析后输出; 
 

(9)组件通信

应该优先通过 prop 和事件进行父子组件之间的通信,而不是 this.$parent 或改变 prop;
一个理想的 Vue 应用是 prop 向下传递,事件向上传递的;
子组件利用v-bind="$attrs"得到父组件的所有属性的绑定,无需在每个子组件上都绑定父组件的属性如placeholder;
<input
  :value="value"
  v-bind="$attrs"
  @input="$emit(‘input‘, $event.target.value)"
>

 

(10)路由切换组件不变的问题

当页面切换同一个路由但不同参数的地址时,组件的生命周期钩子并不会重新触发:vue-router会识别出两个路由使用同一个组件从而进行复用,而不会重新构建组件,因此组件生命周期钩子也不会被触发。想要重新触发可以选择:

a.路由导航守卫beforeRouteUpdate,可以在当前路由改变且组件被复用时调用,只需要将每次切换路由时需要处理的逻辑放在该守卫里即可如获取新数据更新状态并渲染视图。

b.观察$route对象变化,,可能会导致依赖追踪的内存消耗

watch:{
  ‘$route‘(to,from){
  // 对路由变化作出响应
  }
}

ps:如果共用组件页面有共用信息,可以只观察变化的那部分,而不用整个页面信息都重刷

watch:{
  ‘$route.query.id‘(){
    // 请求个人信息
   },
  ‘$route.query.page‘(){
    // 请求不同页面列表数据
  }
}

c.为router-view组件添加标识属性key,利用虚拟dom在渲染时通过key来对比两个节点是否相同的原理;可以使得每次切换路由时key都不一样,让虚拟dom认为router-view组件是一个新节点,从而销毁组件再重建组件。但浪费性能。

 

(11) v-model 双向绑定

使用v-model来进行双向数据绑定的时:
<input v-model="something">
仅仅是一个语法糖:
<input v-bind:value="something" v-on:input="something = $event.target.value">

https://juejin.im/post/5d70aed76fb9a06b04721ec3

 

(12)keep-alive

Vue.js内部将DOM节点抽象成了一个个的VNode节点,keep-alive组件的缓存也是基于VNode节点的而不是直接存储DOM结构;它将满足条件的组件在cache对象中缓存起来,在需要重新渲染的时候再将vnode节点从cache对象中取出并渲染,还未缓存过则进行缓存

生命周期函数

1. activated

在 keep-alive 组件激活时调用

该钩子函数在服务器端渲染期间不被调用

2. deactivated

在 keep-alive 组件停用时调用

该钩子在服务器端渲染期间不被调用

 

被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated

使用 keep-alive 会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在 activated 阶段获取数据,承担原来 created 钩子函数中获取数据的任务。

 

https://blog.csdn.net/fu983531588/article/details/90321827

 

<!-- 我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个 <keep-alive> 元素将其动态组件包裹起来。 -->
<keep-alive>
  <component v-bind:is="currentTabComponent" class="tab"></component>
</keep-alive>
<!-- keep-alive保持这个组件在内存中是常驻的,由于动态组件可能需要动态切换,可以减少组件变化时候的内存消耗,影响性能. -->
<!--<keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。--> 

https://cn.vuejs.org/v2/api/#keep-alive

<!--使用 router.meta 属性,预先定义需要缓存的组件--> 
<keep-alive>
  <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
--------------------------------------------------------
export default {
   data() {
     return {};
 },
 mounted() {},
 methods: {},
 beforeRouteLeave(to, from, next) {
   if (to.path == "/index") {
     to.meta.keepAlive = true;
   } else {
     to.meta.keepAlive = false;
   }
   next();
 }
};
 

// keepalive组件选项
var KeepAlive = {
  name: ‘keep-alive‘,
  // 抽象组件的标志
  abstract: true,
  // keep-alive允许使用的props
  props: {
    include: patternTypes,
    exclude: patternTypes,
    max: [String, Number]
  },
 
created: function created () {
  // 缓存组件vnode
  this.cache = Object.create(null);
  // 缓存组件名
  this.keys = [];
},
 
destroyed: function destroyed () {
  // destroyed钩子中销毁所有cache中的组件实例
  for (var key in this.cache) {
    pruneCacheEntry(this.cache, key, this.keys);
  }
},
 
mounted: function mounted () {
  var this$1 = this;
  // 动态include和exclude
  // 对include exclue的监听
  this.$watch(‘include‘, function (val) {
    pruneCache(this$1, function (name) { return matches(val, name); });
  });
  this.$watch(‘exclude‘, function (val) {
    pruneCache(this$1, function (name) { return !matches(val, name); });
  });
},
// keep-alive的渲染函数
render: function render () {
  // 拿到keep-alive下插槽的值
  var slot = this.$slots.default;
  // 第一个vnode节点
  var vnode = getFirstComponentChild(slot);
  // 拿到第一个组件实例
  var componentOptions = vnode && vnode.componentOptions;
  // keep-alive的第一个子组件实例存在
  if (componentOptions) {
  // check pattern
  //拿到第一个vnode节点的name
    var name = getComponentName(componentOptions);
    var ref = this;
    var include = ref.include;
    var exclude = ref.exclude;
    // 通过判断子组件是否满足缓存匹配
    if ((include && (!name || !matches(include, name))) ||(exclude && name && matches(exclude, name))) {
      return vnode
    }
 
    var ref$1 = this;
    var cache = ref$1.cache;
    var keys = ref$1.keys;
    var key = vnode.key == null ? componentOptions.Ctor.cid + (componentOptions.tag ? ("::" + (componentOptions.tag)) : ‘‘) : vnode.key;
    // 再次命中缓存
    if (cache[key]) {
      vnode.componentInstance = cache[key].componentInstance;
      // make current key freshest
      remove(keys, key);
      keys.push(key);
    } else {
      // 初次渲染时,将vnode缓存
      cache[key] = vnode;
      keys.push(key);
      // prune oldest entry
      if (this.max && keys.length > parseInt(this.max)) {
        pruneCacheEntry(cache, keys[0], keys, this._vnode);
      }
    }
    // 为缓存组件打上标志
    vnode.data.keepAlive = true;
  }
  // 将渲染的vnode返回
    return vnode || (slot && slot[0])
  }
};

 

<!-- keep-ailve组件没有用template而是使用render函数。keep-alive本质上只是存缓存和拿缓存的过程,并没有实际的节点渲染,所以使用render处理是最优的选择。 -->
<!-- render函数执行的关键一步是缓存vnode,由于是第一次执行render函数,选项中的cache和keys数据都没有值,其中cache是一个空对象,我们将用它来缓存{ name: vnode }枚举,而keys我们用来缓存组件名。 因此我们在第一次渲染keep-alive时,会将需要渲染的子组件vnode进行缓存。-->

 

https://juejin.im/post/5d8871c851882509630338c4

https://juejin.im/post/5da42574f265da5b991d6173

https://segmentfault.com/q/1010000011537852

https://segmentfault.com/a/1190000011978825

https://github.com/answershuto/learnVue/blob/master/vue-src/core/components/keep-alive.js

 

(13) vue初始化

https://cn.vuejs.org/v2/guide/instance.html#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%9B%BE%E7%A4%BA

 

vue整体生命周期分为4阶段:初始化(new Vue() 到created之前) / 模板编译(created到beforeMount之前) / 挂载(beforeMount到mounted) / 卸载(beforeDestroy到destroyed)

 

初始化目的:在vue.js实例上初始化一些属性-事件-响应式数据如props-methods-data-computed-watch-provide-inject等

https://blog.csdn.net/a419419/article/details/90764860

https://blog.csdn.net/qq_20143169/article/details/83745727

 

(14)vue 同步更新 异步更新

异步更新队列指的是当状态发生变化时,Vue异步执行DOM更新。

 

Vue的dom更新是异步的,当数据发生变化,vue并不是里面去更新dom,而是开启一个队列。

 

Vue.js实现了一个queue队列,在下一个tick的时候会统一执行queue中Watcher的run;数据变化时,根据响应式触发setter->Dep->Watcher->update->patch;

 

比如我们调用一个方法,同时涉及多个数据的操作改变,vue会把这一些列操作推入到一个队列中,相当于javascript的同步任务,在执行过程中可能会出现一些产生任务队列的异步任务,比如定时器、回调等。

 

在vue里面任务队列也叫事件循环队列。我们都知道JavaScript是循环往复的执行任务队列。Vue也一样,在一个同步任务过程中是不会去更新渲染视图,而是在同步任务(事件循环队列)执行完毕之后,在主线程的同步执行完毕,读取任务队列时更新视图。

 

需要先渲染数据然后操作dom,这时候就要使用vue提供的nextTick函数(当你需要数据先渲染,然后去操作渲染完成之后的dom,要把操作dom的逻辑写在这个函数里面):Vue.$nextTick(callback);

 

将状态改变之后想获取更新后的DOM,往往我们获取到的DOM是更新前的旧DOM,我们需要使用vm.$nextTick方法异步获取DOM;

data() {
  return {
    message: ‘数据更新前no‘
  }
},
edit(){
  this.message = ‘数据更新后have‘;
  console.log(document.getElementById(‘message‘).innerHTML);
  //数据更新前no
  this.$nextTick(() => {
    // 这个函数就是有了数据之后,渲染完成之后会执行,也就是说当你需要数据先渲染,
    // 然后去操作渲染完成之后的dom,要把操作dom的逻辑写在这个函数里面
    console.log(document.getElementById(‘message‘).innerHTML);
    // 数据更新后have1
  });
  this.message = ‘数据更新后have1‘;
}
// 多次修改了状态,但其实Vue只会渲染一次
 

Vue优先将渲染操作推迟到本轮事件循环的最后,如果执行环境不支持会降级到下一轮;Vue的变化侦测机制决定了它必然会在每次状态发生变化时都会发出渲染的信号,但Vue会在收到信号之后检查队列中是否已经存在这个任务,保证队列中不会有重复。如果队列中不存在则将渲染操作添加到队列中;之后通过异步的方式延迟执行队列中的所有渲染的操作并清空队列,当同一轮事件循环中反复修改状态时,并不会反复向队列中添加相同的渲染操作;在使用Vue时,修改状态后更新DOM都是异步的。

 

当某个响应式数据发生变化的时候,它的setter函数就会通知闭包中的Dep,Dep则会触发对应的Watcher对象的update方法

update() {
  if(this.lazy) {
    this.dirty = true
  } else if(this.sync) {
    /*同步执行则run直接渲染视图*/
    this.run()
  } else {
    /*异步则推送到观察者队列中,下一个tick时调用*/
    queueWatcher(this)
  }
}
// queueWatcher函数
// 将观察者对象push进队列,并记录观察者的id
// 如果对应的观察者已存在,则跳过,避免重复的计算
export function queueWatcher(watcher: Watcher) {
  const id = watcher.id
  if(!has[id]) {
    has[id] = true
    if(!flushing) {
      /*如果没有被flush掉,直接push到队列中即可*/
      queue.push(watcher)
    } else {
      var i = queue.length - 1;
      while (i > index && queue[i].id > watcher.id) {
        i--;
    }
    queue.splice(i + 1, 0, watcher);
  }
// queue the flush
  if(!wating) {
    wating = true
    nextTick(flushSchedulerQueue)
  }
  }
}

 

所有同步任务在主线程上执行,形成一个执行栈;

主线程之外,还有一个任务队列,这个队列用于存放异步任务, 只要异步任务有了运行结果,就在"任务队列"之中放置一个事件;

执行栈上的同步任务执行完毕后,主线程会读取任务队列中的任务执行,对应的异步任务结束等待状态,进入执行栈,开始执行;

主线程不断重复以上操作,形成事件循环.

https://www.jianshu.com/p/19efc25e2a57

 

2.vuex

> 推荐在store中初始化好所需属性
> 当在对象中添加新属性时,需要做相应处理才能将其转换为响应式的属性
> 应用层级的状态应该集中到某个store对象中
> 提交mutation是更改状态的唯一方法,且是同步的
> 异步逻辑放在action里,如接口请求

 

> 配置
{
  state:{},
  mutations:{},
  getters:{},
  actions:{}
}
 
> 使用
// 获取数据 store中的getters类似于组件中的computed作用
store.state.** {{$store.state.count}}
store.getters.xx {{$store.getters.money}}
// 修改数据
store.commit(**)
methods: {
  // increase为store中mutations
  this.$store.dispatch("increase");
}
// 提交mutation
store.dispatch(***)
methods: {
  // increaseAsync为store中actions
  this.$store.dispatch("increaseAsync");
}
 
 
> 帮助方法 快速的将组件中的数据与vuex中数据对应起来
mapState
mapGetters
mapMutations
mapActions
 
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
 
computed: {
  // ...mapState 将对象解构 ,mapState本身返回如{count:this.$store.state.count},将其解构
  ...mapState(["count"]),
  ...mapGetters(["money"])
},
 
methods: {
  ...mapMutations([‘increase‘]),
  ...mapActions([‘increaseAsync‘]),
  // 直接修改数据用commit,操作action用dispatch
  inc() {
  // this.$store.commit("increase");
  // increase为mapMutations解构出来的
    this.increase();
  },
  incAsync() {
  // this.$store.dispatch("increaseAsync");
  // increaseAsync为mapActions解构出来的
    this.increaseAsync();
  },
}
 
> 模块化 modules
根据业务功能拆分独立的store-js文件放置于store文件夹下的modules文件夹,并在store文件夹下的index.js文件中引入modules中的各个分store文件;
// store/mudules/user.js
const state = {}
const mutations = {}
const actions = {}
export default {
  state,
  mutations,
  actions
}
 
// store/index.js
import Vue from ‘vue‘;
import Vuex from ‘vuex‘;
import user from ‘./modules/user‘;
Vue.use(Vuex);
const store = new Vuex.Store({
  modules:{ user},
  // 定义全局getters
  getters:{
    roles:state => state.user.roles,
    token: state => state.user.token,
    permission_routes: state => state.permission.routes
  }
})
export default store

 

3.vue-router

(1)vue-router使用推荐

项目初始化没有添加路由功能的情况想要使用路由功能:
下载npm i vue-router -S
在main.js中引入 import VueRouter from ‘vue-router‘
安装插件Vue.use(VueRouter)
 1.配置路由
const router = new Router({
  // history模式http://localhost:8080/page2
  // hash模式http://localhost:8080/#/page2
  mode: ‘history‘,
  base: process.env.BASE_URL,
  routes: [
    // 默认路由,重定向到某个路由
    // {
      // path:‘/‘,
      // redirect:‘/home‘
    // },
     {
      path: ‘/‘,
      name: ‘home‘,
      component: Home
      },
     {
      path:‘/dashboard‘,
      name:‘dashboard‘,
      component:() => import(‘./views/Dashboard.vue‘),
      // 路由级别的路由守卫
      beforeEnter(to, from, next){
        <!-- 判断条件相应处理 -->
      },
      children:[
        // 孩子path用相对路径,去掉最前面的/
        {
          path:‘static‘,
          component:() => import(‘./views/Page1.vue‘),
          // 给组件传静态参
          props:{foo:‘bare‘}
        },
        {
          path:‘page1/:foo‘, //将route.params中参数作为属性传进去名字为foo
          name:‘page1‘,
          component:() => import(‘./views/Page1.vue‘),
          props:true
        },
        {
        // 定义name,方便$router控制路由跳转及传参
          path:‘page2/:id/:msg‘,
          name:‘page2‘,
          component:() => import(‘./views/Page2.vue‘),
        },
        // 路由中设置了prop,则页面中必须有props接收
        {
          // 定义name,方便$router控制路由跳转及传参
          path:‘page22/:id/:msg‘,
          name:‘page22‘,
          component:() => import(‘./views/Page2.vue‘),
          props:func
        },
      ]
    },
    {
      path:‘/login‘,
      name:‘login‘,
      component:() => import(‘./views/Login.vue‘),
    }
  ]
})
export default router;
 
main.js中将其路由对象传递给Vue的实例,options中加入router:router:
new Vue({
  router
})
 
2.安放路由出口
<router-view />
3.导航链接
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
4.传参
声明式的导航(<router-linkto=‘路由地址‘></router-link>)和编程式的导航 (router.push(...))都可以传参
 
ps:$router/$route
$router是路由操作对象,对要跳转的路由进行编写,而使用$route我们来从浏览器中读 取路由参数,即$router只写要跳转的路由,$route 只读(参数的获取)
 
(1)params
// params进行路由传参的时候只能由name引入
this.$router.push({ name: "about", params: { id: 11} });
this.$route.params.id
(2)query
// query传参的时候,以path,name引入都是OK的
this.$router.push({
  path: ‘/describe‘,
  query: {
    id: id
  }
})
next(‘/login?id=‘+to.path);
this.$route.query.id
 
(1)params
//*.vue params进行路由传参的时候只能由name引入
<router-link v-bind:to="{name: ‘cart‘,params: {id: 123}}">
</router-link>
 
//index.js中的路由配置
{
    path: ‘/cart/:id‘,
    name: ‘cart‘,
    component: Cart, 
}
//Cart.vue  获取路由传参
<template>
  <div>
    <span>{{ $route.params.id }}</span>
  </div>
</template>
// 页面显示路径localhost:8088/#/cart/123
 
(2)query
//query传参使用name进行引入
<router-link v-bind:to="{name: ‘cart‘, query: {id: 123}}">
</router-link>
//获取浏览器中路由的参数
<span>{{ $route.query.id }}</span>
 
//query传参使用path进行引入
<router-link v-bind:to="{path: ‘cart‘, query: {id: 123}}">
</router-link>
//获取浏览器中路由的参数
<span>{{ $route.query.id }}<
// 页面中显示路径 localhost:8088/#/cart?id=123

5.路由嵌套children 出现视图的共享即是用到嵌套的地方

6.异步路由 webpack import方法 需要时再引入

7.路由守卫 权限管理

全局级别的router.beforeEach 路由级别的beforeEnter 组件级别的beforeRouteEnter 其内的函数签名next()必须调用才能继续执行;

 

全局:

router.beforeEach((to, from, next) => {
  console.log(to, from, next, ‘to-from-next‘);
  <!-- 判断条件 -->
  next();
})

// 路由生命周期的结束

// router.afterEach((to,from)=>{})


组件级别:

组件级别的路由守卫

beforeRouterEnter(to, from, next){
  if(window.isLogin){
    // 判断是否登录,该状态暂时放在window下,如果有vuex可直接放在vuex下 是 继续
    next();
  }else{
    // 否 去登录 并带上登录之后的重定向地址
    next(‘/login?redirect=‘+to.path);
  }
}

beforeRouteUpdate(to,from,next){
  // 仅路由参数发生变化时触发,比如/page/vue /page/react
  next()
}

路由级别:
{
  path:‘/dashboard‘,
  name:‘dashboard‘,
  component:() => import(‘./views/Dashboard.vue‘),
  // 路由级别的路由守卫
  beforeEnter(to, from, next){
    <!-- 判断条件相应处理 -->
  }
  afterEnter:(next) => {
       console.log(‘enter home‘)
        next()
   }
    beforeLeave:(next) => {
        console.log(‘start leave home‘)
        next()
    }
}

 

使用query传参的时候,name,path都可以引入,但使用params传参的时候只能使用name进行引入。
接收参数的时候使用this.$route.params.name或者this.$route.query.name
进行路由跳转的时候,我们使用this.$router.push(‘路径‘)
如果index.js配置路由时,我们能看到,params的参数是URL不可或缺的一部分,但是query的参数是拼接起来的,没有也不影响;
 
?** query传参,且不需要路由配置配合,接参this.$route.query.name;/url/** params传参,且需要路由配置配合,接参this.$route.params.name。query传参时name/path都可以;params传参时只能使用name。
 
 
可以设置props,可以传静态参,也可以传变量

 

(2)vue权限控制

1. 路由定义 /src/router/index.js;包括通用路由constRoutes和权限路由asyncRoutes; =》创建布局页面layout/index.vue; 创建用户登录页面,views/Login.vue
2.路由守卫 /src/permission.js; 定义权限控制规则,异步路由生成等 =》 安装依赖模块,如elment js-cookie;添加utils/auth.js帮助方法;vuex相关模块实现:根模块,store/index.js,引入子模块,定义getters;user模块,store/modules/user.js 用户数据/用户登录;permission模块,store/modules/permission.js,路由配置信息,路由生成逻辑;
3.按钮权限 最细粒度的按钮级别权限控制通过自定义指令v-permission实现,也可ng-if-ng-show
 

(****)

vue构造的时候会在data(和一些别的字段)上建立Observer对象, getter和setter被做了拦截, getter触发依赖收集, setter触发notify.

Watcher, 注册watch的时候会调用一次watch的对象, 这样触发了watch对象的getter, 把依赖收集到当前Watcher的deps里, 当任何dep的setter被触发就会notify当前Watcher来调用Watcher的update()方法.

 

PS :感谢&参考 

以上是关于vue实践推荐的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段——.vue文件的模板

VScode插件推荐

VSCode自定义代码片段(vue主模板)

VSCode自定义代码片段11——vue路由的配置

VSCode自定义代码片段11——vue路由的配置

VSCode自定义代码片段11——vue路由的配置