不积跬步无以至千里003

2020.11.16 工作笔记

  • huishua_web_agent 汇刷后台管理系统代码理解

  • attribute和property的区别 两个都是属性

第一个问题: 什么是 attribute & 什么是 property ?
attribute 是我们在 html 代码中经常看到的键值对, 例如:
<input id="the-input" type="text" value="Name:" />
复制代码上面代码中的 input 节点有三个 attribute:

id : the-input
type : text
value : Name:

property 是 attribute 对应的 DOM 节点的 对象属性 (Object field), 例如:
HTMLInputElement.id === 'the-input'
HTMLInputElement.type === 'text'
HTMLInputElement.value === 'Name:'
复制代码第二个问题:
从上面的例子来看, 似乎 attribute 和 property 是相同的, 那么他们有什么区别呢?
让我们来看另一段代码:
<input id="the-input" type="typo" value="Name:" /> // 在页面加载后,
我们在这个input中输入 "Jack"
复制代码注意这段代码中的 type 属性, 我们给的值是 typo, 这并不属于 input 支持的 type 种类.
让我们来看看上面这个 input 节点的 attribute 和 property:
// attribute still remains the original value
input.getAttribute('id') // the-input
input.getAttribute('type') // typo
input.getAttribute('value') // Name:

// property is a different story
input.id // the-input
input.type //  text
input.value // Jack
复制代码可以看到, 在 attribute 中, 值仍然是 html 代码中的值. 而在 property 中, type 被自动修正为了 text, 而 value 随着用户改变 input 的输入, 也变更为了 Jack
这就是 attribute 和 Property 间的区别:
attribute 会始终保持 html 代码中的初始值, 而 Property 是有可能变化的.
其实, 我们从这两个单词的名称也能看出些端倪:
attribute 从语义上, 更倾向于不可变更的
而 property 从语义上更倾向于在其生命周期中是可变的
Attribute or Property 可以自定义吗?
先说结论: attribute 可以 property 不行
我们可以尝试在 html 中自定义 attribute:
<input value="customInput" customeAttr="custome attribute value" />
复制代码然后我们尝试获取自定义的属性:
input.getAttribute('customAttr') // custome attribute value
input.customAttr // undefined
复制代码可以看到, 我们能够成功的获取自定义的 attribute, 但是无法获取 property.
其实不难理解, DOM 节点在初始化的时候会将html 规范中定义的 attribute 赋值到 property 上, 而自定义的 attribute 并不属于这个氛围内, 自然生成的 DOM 节点就没有这个 property.
一些补充
需要注意, 有一些特殊的 attribute, 它们对应的 Property 名称会发生改变, 比如:

for (attr) => htmlFor (prop)
class (attr) => className (prop)

(如果我们追到 DOM 的源码中, 应该是能列出一份清单的: 哪些 attribute 的名称会对应到哪些 Property, 感兴趣不妨试试)
关于 attribute 和 property 两者之间的差别, stackoverflow 上有一些很有意思的讨论:
stackoverflow.com/a/6377829/5…
其中有些人认为 attribute 的值表示的是 defaultValue,DOM 节点的 Property 则是另一回事. 比如: check (attr) 对应的是 defaultChecked (prop), value(attr) 对应的应该是 defaultValue (prop)
关于我们在 attribute 中 value 的限制 (如 input 的 type 有那些有效值), 可以参考这个链接:
www.w3.org/TR/html5/in…

作者:ssthouse
链接:https://juejin.im/post/6844903712721387534
DOM property 和 attribute 的区别详解
引言
之前在阅读vue 的api的时候,在解释指令v-bind时,其中关于修饰符 .prop 的解释是- 作为一个 DOM property 绑定而不是作为 attribute 绑定。 令我挺好奇的,虽然干了这么久前端还未详细探究过两者之前的具体区别。于是就跟着链接进入了Stack Overflow中,看与这相关的一个问题与讨论。讨论的内容也经多位牛人编辑,总结得很详细,就想着把这里面的内容在博客中分享记录一下。奈何时间关系,一直在博客的草稿箱里,年底了不怎么忙,趁有时间就总结翻译一下。

明确概念
首先因为两个单词在中文中都翻译成属性,所以会造成较多混淆。在此也先明确一下其它一些基础概念。 身为前端人员我们经常会用标签,元素,DOM来形容HTML 内容,对此其实有明确划分的。如下HTML code(能明确区分的可以跳过)

<div id="" class=""></div>
复制代码
标签指的是 div,也有其他标签如:a,p,input等等。 多数标签分为<div> 开始标签(opening tag),以及</div>结束标签(closing tag)。 当然有的也不区分如: <input><hr><br>等。 标签上有附加信息我们称之为 HTML 属性,如 id,class 以上合起来,我们统称为HTML 元素,而一个HTML文档就是多个HTML元素构成的。

而HTML DOMHTML 的标准对象模型,DOM(Document Object Model),直译就是文档对象模型 HTML DOM 定义了所有 HTML 元素的对象和属性,以及访问它们的方法。 而DOM对象上的属性我们称之为property。

讨论原因
引发此次讨论的主要原因就是因为jQuery v1.6.1的发布,此版本之前直接用attr()方法处理了property和attribute,为了消除property和attribute的歧义,以及一些attr()的bug和维护困难的问题,于是新添加了prop()方法,jQuery v1.6.1发布日志可以在这里看。

详细解释
编写HTML源代码时,可以在HTML元素上定义属性(attribute) 。 然后,一旦浏览器解析了您的代码,就会创建一个对应的DOM节点。 该节点是一个对象,因此具有属性 (property)。 例如:

<input type="text" value="name">
复制代码
input元素有两个属性(attribute),type和value。 浏览器解析这段代码后,将创建一个HTMLInputElement对象,该对象将包含许多属性。 例如:accept,accessKey,align,alt,attributes,autofocus,baseURI,checked,childElementCount,childNodes,childNodes,classList,className,clientHeight等

解析创建后的这个DOM节点对象,property是这个对象的属性,而attribute是这个对象的attributes这个对象的属性 (简单讲就是这样 domObj.attibutes.attribute )。

因为是根据HTML 元素创建的DOM节点对象,所以会有许多属性(property)都与具有相同或相似名称的属性(attribute)相关,但这不并是一对一的关系。 比如:

<input id="inputId" type="text" value="name">
复制代码
此元素创建的DOM节点对象有,id,type,value 等属性(property) DOM节点对象上的id 属性(property)是映射的id属性(attribute)。获取id的property就是获取attribute值,设置也是一样。

var inputDom = document.querySelector('#inputId')
console.log(inputDom.getAttribute('id'))
console.log(inputDom.id)
// "inputId"
// "inputId"

inputDom.setAttribute('id','inputId2')
console.log(inputDom.getAttribute('id'))
console.log(inputDom.id)
// "inputId2"
// "inputId2"

inputDom.id = 'inputId'
console.log(inputDom.getAttribute('id'))
console.log(inputDom.id)
// "inputId"
// "inputId"
复制代码
DOM节点对象上的type属性(property)是映射 type的属性(attribute),获取property读取的是attribute值,并且设置property写入的是attribute值。type不是纯粹的映射属性,因为它的值只能为 已知值 (例如:text,submit,button,checkbox等等)。以下可以看到,设置type为未知值 时 property始终为text。

var inputDom = document.querySelector('#inputId')
console.log(inputDom.getAttribute('type'))
console.log(inputDom.type)
// text
// text

inputDom.setAttribute('type','007')
console.log(inputDom.getAttribute('type'))
console.log(inputDom.type)
// 007
// text

inputDom.type = '008'
console.log(inputDom.getAttribute('type'))
console.log(inputDom.type)
// 008
// text
复制代码
value属性(property)不是完全映射value属性(attribute)初始状态value属性(property)映射的value属性(attribute), 当用户手动更改输入框的内容时 , value属性(property)将更改为用户输入的信息。

<input id="inputId" type="text" value="name">
复制代码
var inputDom = document.querySelector('#inputId')
console.log(inputDom.getAttribute('value'))
console.log(inputDom.value)
// name
// name

inputDom.setAttribute('value','007')
console.log(inputDom.getAttribute('value'))
console.log(inputDom.value)
// 007
// 007

inputDom.value = '008'
console.log(inputDom.getAttribute('value'))
console.log(inputDom.value)
// 007
// 008
复制代码
由以上可以得知,input的value属性(property)在用户未输入数据,或设置property的值时,取的值是attribute的值。当用户输入值或者设置了property的值后,property的值就不受attribute影响了,property的值就是页面输入框内展示的内容(如下图)

在这里插入图片描述
attribute的值是HTML源代码属性(如下图)
attribute 的值
从这个例子中就能很明显看出来property和attribute的区别了,当然还有很多属性property与attribute之间的映射关系并不相同,比如class attribute 和 className property、classList property 之间的关系等等。

总结
最后总的来讲就是 HTML属性 (attribute)和 DOM属性(property),是相互关联的。多数情况attribute值仅用作初始DOM节点对象使用,而property更多用于页面交互,很多框架都是在与元素和指令的 property和事件打交道。

  • 高阶组件 provide inject 爷孙传参

    定义在export default对象中 与methods同级

    父组件 main.vue 引入MainContent 作为组件

<main-content v-if="!$store.state.common.contentIsNeedRefresh" />

provide () {
      return {
        // 刷新
        refresh () {
          this.$store.commit('common/updateContentIsNeedRefresh', true)
          this.$nextTick(() => {
            this.$store.commit('common/updateContentIsNeedRefresh', false)
          })
        }
      }
    },

main-content.vue

<el-dropdown-item @click.native="refresh()">刷新当前标签页</el-dropdown-item>

inject: ['refresh'],

provide和inject就相当于 升级版的props和emit 用于爷孙传参,但是官方不推荐这个方法,还是使用vuex比较合适,因为这样组件之间的耦合度会很高,就脱离组件化的思想了,滥用跨多级组件进行传参的时候,代码的稳定性和可维护性会大大降低的干活

在vue中不同组件通信方式如下

1.父子组件,通过prop

2.非父子组件,通过vuex或根vue转载器

 通常是以上两种情况,然而还有一种比较特殊的情况,即孙子组件或更深层次的组件通信

1.下面是a.vue

<template>
	<div class="test">
		<son prop="data"></son>
	</div>
</template>
2.下面是son.vue

<template>
	<div>
		<grandson prop="data"></grandson>
	</div>
</template>
 
<script>
export default {
	name: 'Son',
	props: ['data'],
}
</script>
很容易看出,如果父组件需要与grandson通信,除了vuex,必须先与son组件通信,再由son与grandson通信,在层级比较少的情况下也无可厚非,但是层级一旦多起来是很可怕的

有人会问为什么不用vuex,简单省事,有很多为了这个引入vuex会导致代码性价比比较低,项目本身没有使用vuex的必要

那么这种情况下provide / inject就登场了

1.provide就相当于加强版父组件prop

2.inject就相当于加强版子组件的props 

因为以上两者可以在父组件与子组件、孙子组件、曾孙子...组件数据交互,也就是说不仅限于prop的父子组件数据交互,只要在上一层级的声明的provide,那么下一层级无论多深都能够通过inject来访问到provide的数据

1.父级组件如下

<template>
	<div class="test">
		<son prop="data"></son>
	</div>
</template>
 
<script>
export default {
	name: 'Test',
	provide: {
		name: 'Garrett'
	}
}
 2.孙子组件,注意这里是孙子组件,父级 -> 子组件 -> 孙子组件三个层级关系

<template>
	<div>
		{{name}}
	</div>
</template>
 
<script>
export default {
	name: 'Grandson',
	inject: [name]
}
</script>
这里可以通过inject直接访问其两个层级上的数据,其用法与props完全相同,同样可以参数校验等

缺点
这么做也是有明显的缺点的,在任意层级都能访问导致数据追踪比较困难,不知道是哪一个层级声明了这个或者不知道哪一层级或若干个层级使用了,因此这个属性通常并不建议使用能用vuex的使用vuex,不能用的多传参几层,但是在做组件库开发时,不对vuex进行依赖,且不知道用户使用环境的情况下可以很好的使用
  • native 修饰符 作用:侦听组件根元素上的原生事件

    • 1,给vue组件绑定事件时候,必须加上native ,不然不会生效

      2,等同于在子组件中:

      子组件内部处理click事件然后向外发送click事件:$emit("click".fn)

    像这样的自己封装的组件要用点击事件就需要加上native
    <el-dropdown-item @click.native="refresh()">刷新当前标签页</el-dropdown-item> 
    @ == v-on
    
    普通的html元素就没有这个必要 可以直接触发
    <button @click="refresh()">click</button>
    

    拓展:如果使用router-link标签,加上@click事件,绑定的事件会无效,因为router-link的作用是单纯的路由跳转,会阻止click事件,如果不加 .native, 事件是不会触发的,因此需要加上 .native 才会触发事件

  • el-dropdown-item 是element-ui 中的下拉框组件的内容标签

    这就相当与自己封装的组件 所以接上条 要想在这里使用点击事件,是要加修饰符的,用修饰符native来触发原生的点击事件,这样才能实现点击的效果

  • vuex的使用

    1,在store文件夹中新建一个modules文件夹,这个modules文件夹的作用就是因为有时候项目会比较复杂,需要这样操作把状态管理的操作进行分组,按组进行编写
    2,创建common.js文件用es6语法抛出一个对象,state和mutations,这里有个namespaced:true即命名空间的意思,*vuex中的store分模块管理,需要在store的index.js中引入各个模块,为了解决不同模块命名冲突的问题,将不同模块的namespaced:true,之后在不同页面中引入getter、actions、mutations时,需要加上所属的模块名*

    3,在index.js中

    import Vue from 'vue'
    import Vuex from 'vuex'
    import common from './modules/common'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
    	modules:{
    		common
    	}
    })
    

    4,mian.vue中使用

     provide () {
          return {
            // 刷新
            refresh () {//这里commit是调用mutations执行 common就是store模块名,/后面的就是mutations中的方法名
              this.$store.commit('common/updateContentIsNeedRefresh', true)
              this.$nextTick(() => {
                this.$store.commit('common/updateContentIsNeedRefresh', false)
              })
            }
          }
        },
    

    vuex中加了命名空间后的使用方式 粘贴自blog内容

    1、声明分模块的store时加上namespaced:true
    
    // initial state
    const state = {
      userId:'',//用户id
      userName:'',//用户名称
      token:'',//token
      permission:''//权限
    }
     
    // getters
    const  getters = {
      // 获取用户信息
      getUserInfo(){
        return state;
      }
    }
     
    // actions
    const actions = {}
     
    // mutations
    const mutations = {
      setUserInfo(state,payload) {
        console.log("payload:"+payload);
        console.info(payload);
        state.userId = payload.userId;
        state.userName = payload.userName;
        state.token = payload.token;
        state.permission = payload.permission;
      }
    }
     
    export default {
      namespaced: true,
      state,
      getters,
      actions,
      mutations
    }
    2、使用模块中的mutations、getters、actions时候,要加上模块名,例如使用commint执行mutations时
    
    格式:模块名/模块中的mutations
    
    xxx/setUserInfo
    
    this.$store.commit("userInfo/setUserInfo",userInfo)
    3、获取属性时同样加上模块名
    
    格式:store.state.模块名.模块属性
    
    $store.state.userInfo.userName
    
  • $nextTick vue组件上的方法

    使用的时候都是this.$nextTick()直接调用

    • this.$nextTick()方法主要是用在数据改变,dom改变应用场景中。vue中数据和dom渲染由于是异步的,所以,要让dom结构随数据改变这样的操作都应该放进this.$nextTick()的回调函数中。created()中使用的方法时,dom还没有渲染,如果此时在该钩子函数中进行dom赋值数据(或者其它dom操作)时无异于徒劳,所以,此时this.$nextTick()就会被大量使用,而与created()对应的是mounted()的钩子函数则是在dom完全渲染后才开始渲染数据,所以在mounted()中操作dom基本不会存在渲染问题。

    • this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。

      假设我们更改了某个dom元素内部的文本,而这时候我们想直接打印出这个被改变后的文本是需要dom更新之后才会实现的,也就好比我们将打印输出的代码放在setTimeout(fn, 0)中;

    • 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

      所以就衍生出了这个获取更新后的DOM的Vue方法。所以放在Vue.nextTick()回调函数中的执行的应该是会对DOM进行操作的 js代码;

      **理解:**nextTick(),是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数,

什么是$nextTick()
简单的回答:
因为Vue的异步更新队列,$nextTick是用来知道什么时候DOM更新完成的。

实例介绍:
有一个div,默认用v-if隐藏,点击按钮之后,改变v-if的值让它显示出来,并且读取到div中的值。

<div id=app>
  <div id="div" v-if="showDiv">我是显示文本</div>
  <button @click="showAndGetText">获取内容</button >
</div>
<script>
var app = new Vue({
  el: '#app',
  data () {
    return {
      showDiv : false
    },
    methods: {
      showAndGetText () {
        this.showDiv  = true
        let text = document.getElementById('div').innerHTML
        console.log(text)
      }
    }
  }
})
</script>

这段代码并不难理解,但是控制台回抛出一个innerHTML of null的错误,因为此时页面并未完成渲染,它并没有获取到div元素,这里涉及到一个Vue的重要概念:异步更新队列。

Vue在观察到数据变化时并不是直接更新DOM,而是开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。

在缓冲时会去除重复的数据,这样避免了不必要的计算和DOM操作。然后,在下一个时间循环Tick中,Vue刷新队列并执行已去重的工作。

所以,如果你用一个for循环来动态改变数据100次,其实它只会应用最后一次改变,如果没有这种机制,DOM就要重绘100次,这是我们不愿意看到的。

知道了Vue异步更新DOM的原理之后,上面的现象就不难理解了,事实上在this.showDiv = true时,div仍然是没有被创建出来的,下面的

let text =document.getElementById('div').innerHTML console.log(text)
1
仍然读取的是这一次事件循环的DOM,而实际上在这一次事件循环中,DOM并没有更新,所以是读取不到的。
我们需要等下一个Vue事件循环,DOM更新完成后再读取,就可以读取到了。
那么这时就是$nextTick闪亮登场的时候:

<div id=app>
  <div id="div" v-if="showDiv">我是显示文本</div>
  <button @click="showAndGetText">获取内容</button >
</div>
<script>
var app = new Vue({
  el: '#app',
  data () {
    return {
      showDiv : false
    },
    methods: {
      showAndGetText () {
        this.showDiv  = true
        this.$nextTick(function () {
        let text = document.getElementById('div').innerHTML
        console.log(text)
        })
      }
    }
  }
})
</script>

这样就取到我们想要的文本数据了。
理论上,我们不应主动去操作DOM,因为Vue的核心思想就是数据驱动DOM,但在很多业务里,我们避免不了会操做一些DOM,这时我们就有可能用到$nextTick。

总结 : n e x t T i c k 大 致 意 思 就 是 在 v u e 中 数 据 响 应 的 过 程 不 是 数 据 一 改 变 d o m 立 即 改 变 , 视 图 也 跟 着 改 了 , v u e 的 异 步 更 新 队 列 原 理 , ∗ ∗ V u e 在 观 察 到 数 据 变 化 时 并 不 是 直 接 更 新 D O M , 而 是 开 启 一 个 队 列 , 并 缓 冲 在 同 一 事 件 循 环 中 发 生 的 所 有 数 据 改 变 ∗ ∗ 有 时 候 页 面 的 d o m 还 没 有 渲 染 出 来 , 我 们 想 拿 到 d o m 上 的 数 据 , 直 接 获 取 是 获 取 不 到 的 , 要 用 nextTick大致意思就是在vue中数据响应的过程不是数据一改变dom立即改变,视图也跟着改了,vue的异步更新队列原理,**Vue在观察到数据变化时并不是直接更新DOM,而是开启一个队列,并缓冲在同一事件循环中发生的所有数据改变** 有时候页面的dom还没有渲染出来,我们想拿到dom上的数据,直接获取是获取不到的,要用 nextTickvuedomvueVueDOMdomdomnextTick的方法

  • vue的数据响应过程

    :数据更改->通知Watcher->更新DOM 不是数据发生变化之后 DOM 立即变化

  • Object.assign 浅拷贝 复制

  • lodash插件

    ​ js工具库

    npm i --save lodash
    

    lodash.assign和merge

    _.assign(object, [sources])
    分配来源对象的可枚举属性到目标对象上。 来源对象的应用规则是从左到右,随后的下一个对象的属性会覆盖上一个对象的属性。
    
     console.log(
          _.assign(
            {},
            { a: 1, b: { c: 1, d: null }, c: [1, 2, 3], d: 2 },
            { a: 2, b: { c: 2, d: undefined }, c: [2] }
          )
        );
        // a: 2
        // b: {c: 2, d: undefined}
        // c: [2]
        // d: 2
    
    _.merge(object, [sources])
    该方法类似 _.assign, 除了它递归合并 sources 来源对象自身和继承的可枚举属性到 object 目标对象。如果目标值存在,被解析为undefined的sources 来源对象属性将被跳过。数组和普通对象会递归合并,其他对象和值会被直接分配覆盖。源对象从从左到右分配。后续的来源对象属性会覆盖之前分配的属性。
    
    console.log(
          _.merge(
            {},
            { a: 1, b: { c: 1, d: null }, c: [1, 2, 3], d: 2 },
            { a: 2, b: { c: 2, d: undefined }, c: [2] }
          )
        );
        // a: 2
        // b: {c: 2, d: null}
        // c: (3) [2, 2, 3]
        // d: 2
    

    该项目中引用了

    isArray 用于判断是不是数组,如果是数组则输出true,反之输出 false

    cloneDeep 深拷贝

    merge 后面的会覆盖前面的对象属性,会递归遍历

    isEqual 判断是否相等

    import isArray from 'lodash/isArray' //引入
    //使用
    hasChild (row) {
            return (isArray(row[this.childKey]) && row[this.childKey].length >= 1) || false
          },
    
    • cloneDeep(val) val是要深拷贝的值 粘贴自blog

      Lodash
      是一个一致性、模块化、高性能的 JavaScript 实用工具库。
      _.cloneDeep(value)
      这个方法类似_.clone,除了它会递归拷贝 value。(注:也叫深拷贝)。
      
      
      var objects = [{ 'a': 1 }, { 'b': 2 }];
       
      var deep = _.cloneDeep(objects);
      console.log(deep[0] === objects[0]);
      // => false
       
      
      _.clone(value)   
      创建一个 value 的浅拷贝。
      
      var objects = [{ 'a': 1 }, { 'b': 2 }];
       
      var shallow = _.clone(objects);
      console.log(shallow[0] === objects[0]);
      // => true
      1、什么是浅拷贝
      
      创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
      
      2、什么是深拷贝
      
      深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。
      
          var obj = [{'a':1},{'b':2}]
          var deep = _.cloneDeep(obj)
          console.log(deep[0] === obj[0]);//false 深拷贝拷贝的是值 在堆内存中重新开辟了一个新的地方 所以这两者是不绝对相等的 一个变了另一个不受任何影响
      
          var obj2 = [{'a':1},{'b':2}]
          var deep2 = _.clone(obj2)
          console.log(deep2[0] === obj2[0]);//true 浅拷贝拷贝的是地址 栈内存中的地址被拷贝走 所以这两者就是一个东西 故绝对想等 一个变了另一个也跟着被改变
      

      该项目中用到cloneDeep的地方如下

      store/index.js
      
        mutations: {
          // 重置vuex本地储存状态
          resetStore (state) {
            Object.keys(state).forEach((key) => {
              state[key] = cloneDeep(window.SITE_CONFIG['storeState'][key])
            })
          }
        },
      
      utils/index.js
      这里封装了一个清楚登录的方法 在这里调用resetStore重置了vuex的本地存储状态 
      
      /* 清除登录信息 */
      export function clearLoginInfo() {
          Vue.cookie.delete('token')
          store.commit('resetStore')
          sessionStorage.clear()
          router.options.isAddDynamicMenuRoutes = false
      }
      
  • 引申一下 export的用法

    按名称导出再使用时,导入的变量名必须和导出的名称一致

    定义:

    export function nameExport (x, y) {
      return x * y
    }123
    

    引用:

    import { nameExport } from './fetch/learnExport'1
    

    使用

    nameExport()
    
  • window.SITE_CONFIG

    这个变量的含义就是==》

    • window.SITE_CONFIG['storeState'] = {};// vuex本地储存初始化状态(用于不刷新页面的情况下,也能重置初始化项目中所有状态)
      
    • // 保存整站vuex本地储存初始状态
      window.SITE_CONFIG['storeState'] = cloneDeep(store.state)
      
      • 全局配置 粘贴自blog

      项目做得太少了,尤其还不会java,对网站的全局配置这一块的理解还停留在初级认知阶段。一般来说,在网页开发中往往一些版本控制、CDN静态资源、api接口地址、常用的公共变量等都会写到window下面并提升至首页方便管理,如网易一些爆款的H5中这种手法非常常见。在我之前使用开源的renren-fast-vue中这种手法更是大量运用,这次学习d2-admin也借鉴一下这种全局变量的使用(挂载变量一时爽,一直挂载一直爽,小心别翻车了)。先不管了,一顿Copy操作猛如虎,定睛一看,注释占了百分之九十五!当然,代码了瞬间有了后端的痕迹,不过在本项目 public/index.html中使用的模板语法来源于 lodash 模板插入,和public文件夹相关的内容可以去翻翻d2-admin文档关于cli 和 webpack 配置部分,这里就不再赘述,总之,万丈高楼平地起,基础建设很重要!

      全局配置window.SITE_CONFIG

        window.SITE_CONFIG = {};
        window.SITE_CONFIG['version'] = '<%= process.env.VUE_APP_VERSION %>';     // 版本
        window.SITE_CONFIG['nodeEnv'] = '<%= process.env.VUE_APP_NODE_ENV %>';    // node env
        window.SITE_CONFIG['apiURL'] = '<%= process.env.VUE_APP_API %>';          // api请求地址
        window.SITE_CONFIG['storeState'] = {};                                    // vuex本地储存初始化状态(用于不刷新页面的情况下,也能重置初始化项目中所有状态)
        window.SITE_CONFIG['contentTabDefault'] = {                               // 内容标签页默认属性对象
          'name': '',                                                             // 名称, 由 this.$route.name 自动赋值(默认,名称 === 路由名称 === 路由路径)
          'params': {},                                                           // 参数, 由 this.$route.params 自动赋值 
          'query': {},                                                            // 查询参数, 由 this.$route.query 自动赋值 
          'menuId': '',                                                           // 菜单id(用于选中侧边栏菜单,与this.$store.state.sidebarMenuActiveName进行匹配)
          'title': '',                                                            // 标题
          'isTab': true,                                                          // 是否通过tab展示内容?
          'iframeURL': ''                                                         // 是否通过iframe嵌套展示内容? (以http[s]://开头, 自动匹配)
        };
        window.SITE_CONFIG['menuList'] = [];                                      // 左侧菜单列表(后台返回,未做处理)
        window.SITE_CONFIG['permissions'] = [];                                   // 页面按钮操作权限(后台返回,未做处理)
        window.SITE_CONFIG['dynamicRoutes'] = [];                                 // 动态路由列表
        window.SITE_CONFIG['dynamicMenuRoutes'] = [];                             // 动态(菜单)路由列表
        window.SITE_CONFIG['dynamicMenuRoutesHasAdded'] = false;                  // 动态(菜单)路由是否已经添加的状态标示(用于判断是否需要重新拉取数据并进行动态添加操作)
      复制代码
      

      大厂某H5案例中全局配置挂载

  • strict: process.env.NODE_ENV !== ‘production’

    process.envNode.js 中的一个环境对象。其中保存着系统的环境的变量信息 NODE_ENV 就是其中的一个环境变量。这个变量主要用于标识当前的环境(生产环境,开发环境

    • store/index.js中定义的方法 process.env.NODE_ENV是在判断运行的环境
      
      mutations: {
        // 重置vuex本地储存状态
        resetStore (state) {
          Object.keys(state).forEach((key) => {
            state[key] = cloneDeep(window.SITE_CONFIG['storeState'][key])
          })
        }
      },
      strict: process.env.NODE_ENV !== 'production'
      })
      
    • 默认的环境就是production 生产环境

    • strict 严格模式

      • import Vue from 'vue'
        import Vuex from 'vuex'
        import cart from './modules/cart'
        import products from './modules/products'
        import createLogger from '../../../src/plugins/logger'
        
        Vue.use(Vuex)
        
        const debug = process.env.NODE_ENV !== 'production'
        
        export default new Vuex.Store({
          modules: {
            cart,
            products
          },
          strict: debug,
          plugins: debug ? [createLogger()] : []
        
  • 浏览器 network中查看请求头状态

  • 在项目中安装lodash依赖包

    但是在vue文件里直接import lodash from ‘lodash’ 后 就可以直接使用

  • qs插件

    • qs 是一个增加了一些安全性的查询字符串解析和序列化字符串的库

    • 在项目中使用命令行工具输入

      cnpm install qs

      安装完成后在需要用到的组件中

      import qs from 'qs’
      Vue.prototype.$qs = qs

      两个常用的方法:

      • qs.parse():将URL解析成对象的形式
      • qs.stringify():将对象 序列化成URL的形式,以&进行拼接
  • mockjs假数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值