vue2基础 入门vue2

vue基础

  • vue项目搭建

  • vue单文件组件

  • mustach表达式

  • vue指令

  • methods方法

  • filters过滤器

  • computed计算属性

  • watch监听器

  • vue组件

  • vue-router 路由

  • vue生命周期

  • vue组件通信

  • slot插槽

  • vuex 状态管理

    前言

vuejs 是一个构建数据驱动的渐进式MVVM框架

数据驱动:不用操作dom(vue)

渐进式: 渐进式开发---模块的使用(在项目开发的过程之中不断的引入三方包完善项目的开发)

响应的数据绑定: 数据一旦发生改变,页面自动重新渲染(替代了 dom操作)

MVVM : model(数据) view(视图) ViewModel(数据和视图进行绑定)===双向绑定

优点

  • 体积小(33k)

  • 基于虚拟DOM 比较 不同的dom节点 直接更新的是 一部分不同的dom节点 性能高

  • 双向数据绑定 -节约渲染dom的代码

  • 生态丰富、学习成本低

    vue全家桶技术栈

    vue2.0 底层 vue-cli脚手架(vue+webpack) vue-router vuex状态管理 axios接口对接

1.vue2 项目创建

1.1直接引入

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

1.2通过vue-cli脚手架创建

npm install -g @vue/cli #vue脚手架 全局安装

或者

yarn global add @vue/cli

vue --version #检查版本是否安装成功

1.3 项目创建 vue create 项目名称

vue create 项目名称 #创建项目

手动选择配置--vue version ----babel ----css 预处理

vue 版本 配置 babel 配置 css预处理配置

项目启动

yarn serve 

1.4.vue项目目录结构

1.5.vue 代码插件

- 代码高亮  vetur 
- 代码补全   Vue VSCode Snippets

2.单文件组件 .vue SFC

一个 .vue 文件 就是一个 组件

一个页面可以是 一个vue文件组成,也可以是多个vue文件共同组成

组件特点:带有独立功能 的小模块 ,低耦合

组件的优点:可重用 可组合 易维护

<template>
  <!--   template  节点 有且只有一个 节点 div  -->
  <div>
    <div class="box">asdasdsad</div>
    <div>aaaa</div>
    asndjasbdjasbdjasda
  </div>
</template>

<script>
// 导出对象
export default {};
</script>


<style  lang="less">
.box {
  color: #f60;
  font-size: 50px;
}
</style>

3.data() 函数与mastach 语法

vue 中data函数 返回了一个数据对象给vue组件

在组件的html代码部分 可以通过 mastach 语法 {{}} 获得该数据

mastach 表达式语法:
{{ js表达式  }}
<template>
  <div>
    <!-- mustach 表达式  在vue文件中 html代码里面 获取 data的数据 -->
    <p >  姓名: {{ name }} </p>
    <p>年龄: {{ age }}</p>
    <p>爱好: {{ like[0] }} {{ like[1] }} {{ like[2] }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      name: "艾坤",
      age: 40,
      like: ["唱", "跳", "rap","篮球"],
    };
  },
};
</script>

4.vue 中的js代码配置项

<script>
export defalut {
    //数据
	data(){
		return {}
	},
    //组件   
    components:{
        
    },    
	//方法
    methods:{

	},
    //计算属性
    computed:{
        
    },
    //监听
    watch:{
        
    },
    //过滤器
    filters:{
            
    },
    //组件生命周期钩子函数-八个    

}
</script>

5.组件的创建和注册 components

  • 创建组件 .vue文件
  • 父组件导入子组件
  • 注册组件
  • 使用组件

5.1.创建组件的要求

大驼峰

5.2.父组件导入子组件

import  子组件名  from '组件路径'

5.3.父组件注册子组件

components:{
       子组件名,
 },  

5.4.组件的使用

<template>
	<div>
        <子组件名></子组件名>
    </div>
</template>

6.vue指令 14个

6.1.v-text 和 v-html 节点渲染

v-text : 给当前的dom节点 渲染 一段 静态文本 -----innerText

v-html:给当前的dom节点 渲染 一段 html代码的文本 ----innerHTML

区别:

mustach 更适合 零散的变量的字符拼接输出

v-text 更适合完整字符串的输出

v-html 更适合 带有html标签的字符串的输

<!-- mustach {{}} -->
    <p>
      {{ str }}
    </p>
    指令v-text
    <p v-text="str"></p>
    指令: v-html
    <p v-html="str"></p>

6.2.v-show 和 v-if 显隐切换

v-show:对dom节点 的显示和隐藏

v-if:对节点增加和删除

区别:

v-show:控制css属性 display 对dom进行显示和隐藏

v-if: 对DOM节点进行增加 删除操作

 <span v-show="flag"> 女</span>
   <span v-show="flag">男</span>
	<hr>
	 <span v-if="flag"> 女</span>
     <span v-if="flag">男</span>
<script>
export defalut{
	data(){
		flag:true
	}
}
</script>

6.3.v-if 和 v-else 和 v-else-if 判断

v-if 满足条件 新增 dom

v-else-if 不满足 v-if的条件 但是 满足了 v-else-if ="条件" 新增dom

v-else 前面的条件都不满足 新增 dom

区别:效果等同于 js 的 if else 分支语法特点

<p v-if="flag === 0">女</p>
    <p v-else-if="flag === 1">男</p>
    <p v-else-if="flag === 2">公公</p>
    <p v-else>其他</p>
<script>
  data() {
    return {
      flag: 4, //0:女  1 :男  2:公公   3:其他
    };
  },
 </script>

6.4.v-for 循环

v-for:循环数据 并渲染页面 v-for 循环必须搭配 :key="表达式" 动态属性进行使用

注意:如果同一个组件中存在多个 v-for 循环 需要特别注意 key的值

整个组件中 key 都必须保持唯一性,目的: 虚拟DOM发生更新的时候 所有的dom节点可以快速比较

 <p v-for="(item, index) in arr" :key="index">
      我是艾坤叫来的兄弟:我的名字:{{ item }}
    </p>
<script>
export default {
  data() {
    return {
      arr: ["王子", "小鬼", "大鬼"],
    };
  },
};
</script>

6.5.v-on 事件绑定 与methods 对象

给dom绑定事件

v-on:` 可以简写为 `@

函数的调用可以 传递自定义参数 与 $event 事件对象

<div v-on:事件类型="事件处理函数()"> 点击我 </div>
<div @事件类型="事件处理函数()"> 点击我 </div>
export defalut{
	methods:{
		事件执行函数(){
			console.log('点你了...')
		}toe
	}
}

6.6.v-model 输入框数据绑定

实现页面的输入框(input select check radio )与 data中的数据 进行双向绑定

双向绑定:一旦页面中的输入框发生数据的变化,会导致 data中的数据 跟着变化

<input  v-model="表达式" >
<input  v-model="number+1" >
data(){
	return{
		number:100,
        str:'你好啊'
	}
}

6.7.v-bind 属性绑定

绑定、操作dom 属性 绑定动态值 布尔值 或者数字类型时使用

v-bind:` 可简写为 `:
<标签  v-bind:属性名="表达式">
<标签 :属性名="表达式">

7.methods 方法

  • 事件处理函数
  • 页面当中的表达式 都可以使用 函数
  • 函数与函数之间 调用 this.函数名()
  • vue 声明周期 钩子函数 中调用 this.函数名()
<标签 @事件类型="事件执行函数()">
 
  <p>
        {{  函数名()  }}    //表达式 可以写成函数的调用
   <p>
       
<script>
 export default{
    methods:{
        事件执行函数(){

        },  
     }   
 }
</script>

8.filters 过滤器

将原来的数据 进行处理并返回一个新数据

语法和 methods中方法 一样,filters中的函数 必须要有返回值

filters中 获取不到data() 中的数据

<div> {{ 参数|过滤器名 }}   </div>
filters:{
		过滤器名(data){
			//处理数据
			return 新数据
		}
	}

9.computed 计算属性

作用: 将比较复杂的计算交给计算属性处理 ,而不是交给 methods处理

语法规则 和methods 一模一样 ,必须要有返回数据

调用时不能加小括号

依赖缓存:如果参与计算的基础数据 没有发生变化,不会进行再次调用,

第一次 计算完成之后,只要参与计算的数据没有发生变化,后面的反复调用,不会执行函数体,直接用之前的数据输出

使用场景:需要反复输出的 复杂的运算

<p v-for="item in 100" :key="item">
      {{ resData }}
  </p>
data(){
    return {
        num:100,
    }
}
 computed: {
    resData() {
       //根据依赖缓存特点 只执行了一次函数体
      console.log('执行代码一次....');
      return this.num % 21;
    },
  },

10.watch 侦听器 监听器 常用

监听数据的变化,如果数据发生改变 触发对应的方法

export defalut {
	data(){
        return{
      	}
	},
	watch:{
		需要监听变量(newVal,oldVal){
				//newVal: 改变之后的数据 新数据
                //oldVal:改变之前的数据  老数据
		}
	}
}

	watch:{
		需要监听变量:{
			handler(newVal,oldVal){   },
            deep:true //是否开启深度监听
            immediate:true //立即执行一次
		}
	}

11.vue组件

11.1组件分类

  • 页面级组件

实现页面与页面之间的跳转

  • 公共组件

多个页面 组件都可使用的通用组件 放在src/components 中

  • 业务组件

在某个页面 中进行使用 的组件,更多体现为 页面的某一模块或部分

11.2页面级组件的创建步骤

创 配 占位 测 四个步骤

  • 创建.vue 文件

  • 配置路由 一 一对应 router/index.js

//导入页面级组件
import Mine from '../views/my/Mine.vue'
const routes = [
    {
        path: "/mine",  //跳转的路由
        component: Mine    //对应的组件
  	},
]
  • 父组件中需要 给子组件占位 app.vue
<router-view></router-view>
  • 测试 是否可以访问 手动切换路由地址
http://localhost:8080/#/mine

12路由的使用 vue-router

vue-router 通过a标签 封装了一个组件 :router-link

<router-link  to="页面的路径 path">  </router-link>

12.1 vue-router的配置

12.2 两个路由对象

  • this.$route
this.$route.path   #当前页面的路由
this.$route.query   #获取页面的search参数  location.search   获取的值是一个对象
this.$route.params   #获取页面参数
this.$route.matched   #当前页面匹配的所有
  • this.$router
this.$router.push('路由的地址 path ')     #在js中进行页面的跳转
this.$router.back()           #返回上一页  history.back()
this.$router.forward()        #前进一页
this.$router.go(数字)          #前进后退任意页面

13 vue的生命周期

生命周期 就是 vue组件 从诞生到消亡整个过程

vue组件生命周期分为 四大阶段 8个钩子函数

钩子函数:当达到这个阶段 自动触发的某个函数

可以在生命周期的钩子函数中处理一些业务逻辑

所有的钩子函数 都是和data() 平级

#第一大阶段  create  创建阶段
beforeCreate()  #vue组件创建之前  组件中的任何资源都获取不到  可以获取到 Vue 顶级实例
created()     #vue组件创建完成  可以获取到 data()里面的数据  

#第二大阶段  mount 挂载阶段
beforeMount()     # 挂载之前   可以获取data()   获取不到页面的dom
mounted()         # 挂载之后   可以获取所有的 dom 节点  

#第三大阶段   update  更新阶段
beforeUpdate()    #更新之前  
updated()         #更新之后   

#第四大阶段   destroy  销毁阶段
beforeDestroy(){
     #销毁之前触发
destroyed()        #销毁之后触发

14 vue组件通信

组件与组件之间的数据传递

  • 父传 子

  • 子传 父

  • 状态管理vuex

  • 中央事件总线 $bus (不使用)

  • 相关 本地存储 和页面带参传值

    14.1 组件 父传子 动态属性+props

    在父组件中将数据传递给子组件

    子组件需要父组件的数据 做页面的渲染

    子组件props 接收到的数据 用法和 data中的数据用法完全一致

    父组件

    <子组件名  title="你好啊"  :age="20"></子组件名>
    

子组件

通过props 接收后, 直接用 this.变量使用

props:{
    title:{
        type:String,
        default:'标题'
    },
    age:{
        type:Number,
        default:0
    },   
}

14.2组件 子传父 $emit+自定义事件

父组件

<子组件 @自定义的事件类型名="执行函数名" >  </子组件> 

export default{
    methods:{
        执行函数名(获取到的子组件的回传参数){
            //业务逻辑
        }
    }  
}

子组件

  methods:{
        自定义的事件类型名(){
            this.$emit("自定义的事件类型名",需要传递的数据)
        }
    }

14.3 中央事件总线 $bus

所有组件需要传递数据 都直接存到 $bus

其他的所有的组件 都可以直接找 $bus 获取 数据

优点:无视层级传数据

缺点:必须在同一个 页面组件中,切换页面后 $bus 就无法触发事件

//main.js  整个程序的入口
Vue.prototype.$bus = new Vue() ;  //中介 新的vue实例对象,专门存取数据  $emit 

//向$bus写入数据--存数据的组件
this.$bus.$emit('自定义的事件类型',数据)

//在组件中获取值 --取数据的组件
//找到当前组件的 created()
created(){
 this.$bus.$on('自定义的事件类型',data=>{
     console.log(data) //获取的数据
 })   
}

14.4 祖宗孙子传值: provide+ inject

优:祖宗节点定义好数据,所有的孙子组件 都可以使用该数据 非常方便

缺:只能传递一个 固定值下去,没有响应式(子组件修改了该数据,祖宗节点的数据并不会发生变化)

祖宗组件

 //   祖宗注入依赖
  provide: {
    name: '你好呀',
  },
 //   祖宗注入依赖
  provide() {
    return {
      name: "你好呀",
    };
  },

孙子组件

  export default {
        inject:['name'],
        mounted(){
            //可以获取和使用
            console.log(this.name);
            //不能修改---报错
            this.name = '我是孙子组件'
        }
    }

14.5 中间商:父亲组件带动态属性 $attrs $listeners

通过属性传值:可以快速实现 祖宗>孙子 孙子>祖宗【父亲组件只是一个中间商 负责 转发数据和转发事件】

爷爷组件

<template>
  <div>
      我是爷爷组件
         <button @click="title='我是爷爷组件的新数据'">点击修改数据</button>
          <hr />
         <father :title="title" @change="getData"></father>
  </div>
</template>

<script>
import Father from './components/AppFather.vue'
export default {
  data() {
    return {
      title: "我是爷爷组件的数据",
    };
  },
  methods:{
      //根据自定义数据 获取孙子组件的传递数据
      getData(data){
        console.log(data);
      }
  },
  components: {
    Father,
  },
};
</script>

父亲组件

父亲组件 通过$attrs 将获取到的上一层的数据 传递给 下一级

父亲组件 通过 $listeners 将获取到的自定义事件 传递给上一级 触发

<template>
    <div>
        父亲组件:
        <hr>
        <grand-son v-bind="$attrs" v-on="$listeners" ></grand-son>
    </div>
</template>

<script>
  import GrandSon from './GrandSon.vue'
    export default {
        components:{
            GrandSon
        }
    }
</script>

孙子组件

<template>
  <div>
    我是孙子组件:
    <p>{{ title }}</p>
    <button @click="changeData">回传数据给祖宗</button>
  </div>
</template>

<script>
export default {
  props: {
      // 在爷爷组件中传递过来的属性
    title: { 
        type:String,
        default:'标题'
     },
  },
  methods:{
      changeData(){
          let data ={msg:"我是孙子组件回传的数据"}
          this.$emit('change',data)
      }
  },

15 vue插槽使用 slot

父组件把 html 代码 传给子组件

子组件预留 html代码的位置 给父组件

15.1匿名插槽

子组件的slot标签就是 预留给 父组件 传html代码的位置

#父组件
<子组件>
    #写入替换 slot插槽的html代码
	<html代码>
</子组件>
    
 #子组件
</div>
	#子组件提前给父组件预留的位置 插槽
	<slot></slot>
</div>   
    

15.2具名插槽

如果同一个子组件中出现多个 插槽 必须使用具名插槽

如果是同一个子组件中出现两个 插槽 可以一个匿名 一个具名

#父组件
<子组件>
    <div slot="插槽名1">
    </div>	  		
     <div slot="插槽名2">
</子组件>

#子组件
<div>
    <slot name="插槽名1"></slot>    、
    <slot name="插槽名2"> </slot>
<div>

15.3 作用域插槽

将子组件的数据 回传给 父组件的插槽 部分的代码进行使用

一般情况下:作用域插槽 都是基于 具名插槽进行操作

#父组件
<子组件>
    <div slot="插槽名1" slot-socpe="scope">
        {{scope.变量}}
    </div>	  		
     <div slot="插槽名2">
    </div>
</子组件>
#子组件
<div>
    <slot name="插槽名1" :变量=“str”></slot>    、
    <slot name="插槽名2"> </slot>
<div>
data(){
    return {
    	str:'啦啦啦'
    	}
 }

15.4 简化语法 vue3 适用

#父组件
<子组件>
    <div v-slot="插槽名1">
    </div>	  		
     <div v-slot="插槽名2">
    </div>
</子组件>
#父组件
<子组件>
    <template #插槽名1>
			<div> </div>
	</template>
     <div v-slot="插槽名2">
    </div>
</子组件>
#父组件
<子组件>
    <template  #插槽名1="scope">
			<div >
                {{scope.变量}}
            </div>	
	</template>	
     <div slot="插槽名2">
    </div>
</子组件>

16 vuex状态管理

vuex是一个程序里面的状态管理模式,它是集中式存储所有组件的状态的小仓库,并且保持我们存储的状态以一种可以预测的方式发生变化

官网地址https://vuex.vuejs.org/zh/

vuex周期图

16.1 安装 vuex

  • 安装vuex

进入项目,在命令行中输入安装指令,回车

yarn add [email protected] --save  
//或
npm i [email protected] --save   
  • 创建vuex 的仓库文件

src/store/index.js

在src路径下创建store文件夹,然后创建index.js文件,文件内容如下:

import Vue from 'vue'
import Vuex from 'vuex'

//注册插件 
Vue.use(Vuex);
//根据vuex的store 生成实例对象 
const store = new Vuex.Store({
    //存数据的仓库
    state:{
        name:'comentang'
    },
    //修改仓库中数据的同步方法
    mutations:{
    },
    //调用 同步方法 实现异步修改仓库中的数据
    actions:{
    }
})
//暴露生成的vuex实例
export default store;
  • main.js 进行导入和挂载
import store from './store' //引入前面导出的store对象
Vue.config.productionTip = false;

new Vue({  
  router,
  store,  //将store 实例挂载到vue顶级实例对象上
  render: h => h(App)
}).$mount('#app')

16.2 获取 state 中的数据

state:{
 	name:"babybearcq"     
 }
  • 直接通过实例对象层级查找

缺点:每次改变都需要使用该语句进行重新获取,代码太冗长

this.name = this.$store.state.name  // babybearcq
  • 通过 计算属性 获取值

优点:如果仓库中的数据发生了变化,computed 会自动触发,重新更新值

computed:{
    nameData(){
        return this.$store.state.name;
    }
}
  • 通过计算属性 + 对象解构获取

将mapState 对象解构出来直接放到 computed中

优点:使用简便,推荐此方法

import {mapState} from 'vuex'

computed:{
    ...mapState(['name'])
}

16.3 mutations 修改数据的方法

  • 在组件中直接修改

直接通过实例对象层级赋值

缺点:任何组件任何时候都可以修改这个数据,给数据维护带来了不稳定性。

vuex官网页非常明确的指出,修改vuex仓库中的数据必须使用 vuex中定义的方法。

低版本的vuex 数据会修改成功 但是控制台会有报错提示

this.$store.state.name = '新数据'
  • 定义mutations的方法 修改数据
const store = new Vuex.Store({
    //存数据的仓库
    state:{
        name:'babybearcq'
    },
    //修改仓库中数据的同步方法
    mutations:{
        changeName(state,newData){
            state.name = newData
        }
    },
})

在组件中 调用该方法 实现修改数据

this.$store.commit('changeName',新数据)

methods+解构的方式 【推荐】

import { mapMutations } from 'vuex';
methods:{
     // 注意,mapMutations是解构到methods里面的,而不是计算属性了
    ...mapMutations(['changeName']),
     //使用方法和methods中的函数 一致。    
     // this.changeName(新数据) 修改数据 
}

16.4 actions 异步修改数据

定义actions 异步操作中 通过上下文 调用同步方法 修改数据

 //调用 同步方法 实现异步修改仓库中的数据
    actions:{
        //1s之后 通过上下文 调用同步方法修改数据
        setAsyncData(context,newData){
            return new Promise(resolve=>{
                setTimeout(()=>{
                    context.commit('changeName',newData);
                    resolve();
                },1000)
            })
        }
    }
  • 在组件中 调用该方法 实现修改数据
let res = await  this.$store.dispatch('setAsyncData',this.title)
  • methods+解构的方式 【推荐】
import { mapActions } from 'vuex';
methods:{
     // 注意,mapActions是解构到methods里面的,而不是计算属性了
        ...mapActions(['setAsyncData']),
   	    let res= await this.setAsyncData(this.title)
}

16.5 修饰器:Getters

获取数据时 统一对该数据进行处理之后 再返回新数据

特点:必须要有return 返回新数据 ,调用时不需要传参数

定义修饰器

 getters:{
        updateName(state){
            return '你好呀'+state.name;    
        }
    }
  • 组件中直接使用 获取数据
 this.$store.getters.updateName
  • 通过computed 解构函数使用
import {mapGetters} from 'vuex'
 computed:{
    ...mapGetters(['updateName'])
  },
  created() {
    //取值
    this.updateName1 = this.updateName
  }

16.6 模块 Module

假设一个项目功能比较复杂,在vuex中存储的数据非常多,设置出现了同名的情况,这种时候就不能直接写到一个store 文件中了,应该根据不同的功能模块 对 该store文件进行拆分。

思路:写独立的js文件 将 5个核心配置写入一个对象 并 暴露出去,导入到总的store里面的modules里面

现有模块: 用户模块users 商品模块

src/store/index.js  #总的vuex主模块
src/store/users.js   #用户模块
src/store/goods.js  #商品模块

主模块 index

//index.js
import Vue from 'vue'
import Vuex from 'vuex'

// 导入子模块  
import users from './users'
import goods from './goods'

//注册插件 
Vue.use(Vuex);
//根据vue的store 生成实例对象 
const store = new Vuex.Store({
    state: {
        name: '我是主模块的cometang'
    },
    mutations: {
    },
    actions: {
    },
    getters: {
    },
    //模块
    modules: {
        users, goods
    }
})
//暴露生成的vuex实例
export default store;

用户模块

const users = {
    namespaced: true,
    state: {
        userName: '我是userjs的name'
    },
    mutations: {

    },
    actions: {

    },
    getters: {

    }
}
export default users

商品模块

const goods = {
    namespaced: true,
    state:{
        goodsName:'我是goods的name'
    },
    mutations:{

    },
    actions:{

    },
    getters:{

    }
}
export default goods

注意:使用了模块化和命名空间之后对于子模块中的数据,方法的调用 不再建议使用 解构赋值快速复制的方式进行.

原因:本来命名空间打开就是为了区分各个不同的模块,如果用解构的方式,可能会造成数据变量名 方法名重名使用的风险。

  • 使用方式
//获取数据
this.$store.state.users.userName;
//获取Getters 修饰器的数据
this.$store.getters.users.userName;
//调用同步方法
this.$store.commit('模块名/mutations的方法名',传递的数据)
// 调用异步方法
this.$store.dispatch('模块名/actions的方法名',传递的数据)
  • 解构使用

特点:一个组件中 只能解构一个模块的数据 和方法

import { mapState,mapMutations,mapActions,mapGetters } from 'vuex';
  computed:{
    ...mapState('users',['userName']),     //this.userName
    ...mapGetters('users',['newUserName'])  //this.newUserName
  },
  methods:{
    ...mapMutations('users',['updateName']), //this.updateName(数据)
    ...mapActions('users',['asyncUpdateName'])//this.asyncUpdateName(数据)
  },

16.7 vuex 持久化

  • **插件 ** 数据持久化的插件
npm install vuex-persistedstate   
或
yarn add vuex-persistedstate 
//数据持久化插件导入
import persistedState from 'vuex-persistedstate'

//根据vue的store 生成实例对象 
const store = new Vuex.Store({
    state: {
    },
    mutations: {
    },
    actions: {
    },
    getters: {
    },
    //模块
    modules: {
    },
    plugins: [persistedState()] //添加插件
    
})
//暴露生成的vuex实例
export default store;
  • 本地存储

  • 创建公共函数 utils/store.js

import { validatenull } from 'utils/validate';
import website from '@/config/website'; // 
/**
 * 存储localStorage
 */
export const setStore = (params = {}) => {
  let { name, content, type } = params;
  name = keyName + name;
  let obj = {
    dataType: typeof content,
    content: content,
    type: type,
    datetime: new Date().getTime(),
  };
  if (type) window.sessionStorage.setItem(name, JSON.stringify(obj));
  else window.localStorage.setItem(name, JSON.stringify(obj));
};

/**
 * 获取localStorage
 */
export const getStore = (params = {}) => {
  let { name, debug } = params;
  name = keyName + name;
  let obj = {},
    content;
  obj = window.sessionStorage.getItem(name);
  if (validatenull(obj)) obj = window.localStorage.getItem(name);
  if (validatenull(obj)) return;
  try {
    obj = JSON.parse(obj);
  } catch {
    return obj;
  }
  if (debug) {
    return obj;
  }
  if (obj.dataType == 'string') {
    content = obj.content;
  } else if (obj.dataType == 'number') {
    content = Number(obj.content);
  } else if (obj.dataType == 'boolean') {
    content = eval(obj.content);
  } else if (obj.dataType == 'object') {
    content = obj.content;
  }
  return content;
};

/**
 * 删除localStorage
 */
export const removeStore = (params = {}) => {
  let { name, type } = params;
  name = keyName + name;
  if (type) {
    window.sessionStorage.removeItem(name);
  } else {
    window.localStorage.removeItem(name);
  }
};

/**
 * 获取全部localStorage
 */
export const getAllStore = (params = {}) => {
  let list = [];
  let { type } = params;
  if (type) {
    for (let i = 0; i <= window.sessionStorage.length; i++) {
      list.push({
        name: window.sessionStorage.key(i),
        content: getStore({
          name: window.sessionStorage.key(i),
          type: 'session',
        }),
      });
    }
  } else {
    for (let i = 0; i <= window.localStorage.length; i++) {
      list.push({
        name: window.localStorage.key(i),
        content: getStore({
          name: window.localStorage.key(i),
        }),
      });
    }
  }
  return list;
};

/**
 * 清空全部localStorage
 */
export const clearStore = (params = {}) => {
  let { type } = params;
  if (type) {
    window.sessionStorage.clear();
  } else {
    window.localStorage.clear();
  }
};

vuex 文件 store/index.js

import { setStore, getStore, removeStore } from 'utils/store';
const store = createStore({
  state: {
   //从本地获取数据 
    language: getStore({ name: 'language' }) || 'zh-cn',
    isLock: getStore({ name: 'isLock' }),
    lockPasswd: getStore({ name: 'lockPasswd' }) || '',
  },
      
 mutations: {
    setLanguage: (state, language) => {
      state.language = language;
    //改变后将数据存储到本地
      setStore({
        name: 'language',
        content: state.language,
      });
    },
        
   setLockPasswd: (state, lockPasswd) => {
      state.lockPasswd = lockPasswd;
      setStore({
        name: 'lockPasswd',
        content: state.lockPasswd,
        type: 'session',
      });
    },
        
     clearLock: (state, data) => {
      state.isLock = false;
      state.lockPasswd = '';
       //将使用过的数据 从本地清除
      removeStore({
        name: 'lockPasswd',
        type: 'session',
      });
    },
  },
});

export default store;

参考:https://www.gotang.cn/pages/658702/#%E5%89%8D%E8%A8%80

热门相关:流鱼无恙   裙上之臣   神算大小姐   戏精老公今天作死没   修真界败类