TypeScript与Vue组合开发记录点(三)

pinia

pinia与vuex相似,是Vue的存储库,允许跨组件/页面共享状态,适用于单页面应用。

安装脚手架vite

 // 安装vite
 npm init vite@latest

安装状态管理库pinia

npm install pinia

配置pinia

因为vue单页面应用,那么整个应用使用状态管理,就需要在main.js文件里配置。

 // main.js
 import { createApp } from 'vue'
 import App from './App.vue'
 // 导入构造函数
 import { createPinia } from 'pinia'
 // 实例化 Pinia
 const pinia = createPinia()
 // 创建Vue应用实例app
 const app = createApp(App)
 // 应用以插件形式挂载Pinia实例
 app.use(pinia)
 app.mount('#app')

定义状态仓库

在工程文件夹下新建store文件夹,内部有index.js文件用来定义状态

 // src/store/index.js
 // 引入仓库定义函数
 import { defineStore } from 'pinia'
 // 传入2个参数,定义仓库并导出
 // 第一个参数唯一不可重复,字符串类型,作为仓库ID以区分仓库
 // 第二个参数,以对象形式配置仓库的state,getters,actions
 // 配置 state getters actions
 export const mainStore = defineStore('main', {
   // state 类似组件的data选项,函数形式返回对象
   state: () => {
     return {
       msg: 'hello world!',
       counter: 0
     }
   },
   getters: {},
   actions: {}
 })

使用pinia状态变化

通过$path方法,批量修改数据的变更。$path传入一个对象,对象的属性就是各种状态。

 <template>
   <button @click="handleClick">修改状态数据</button>
      <p>{{msg}}</p>
     <!-- 或者使用解构之后的 -->
     <p>{{counter}}</p>
 </template><script setup>
 // 导入状态仓库
 import { mainStore } from "../store/index.js";
 // 使普通数据变响应式的函数  
 import { storeToRefs } from "pinia";
 // 实例化仓库
 const store = mainStore();
 // 解构并使数据具有响应式
 const { msg,counter } = storeToRefs(store);// 点击 + 1;修改字符串
 function handleClick() {
   store.$patch({
      msg: "pinia good!",
     counter: counter.value + 1,
   });
 }
 </script>

数据持久化

pinia支持扩展插件实现数据持久化,该插件为pinia-plugin-persist。使用Pinia持久化插件,在开发的过程中,像用户信息(名字,头像,token)需要pinia中存储且需要本地存储

export const useUserStore = defineStore({
  state () {
    return {
      count: 0,
      num: 100,
      list: [1, 2, 3, 4 ]
    }
  },
  persist: {
    enabled: true, // 开启缓存  默认会存储在本地localstorage
    storage: sessionStorage, // 缓存使用方式
    paths:[] // 需要缓存键 
  }
})

缓存结果
在这里插入图片描述

SCSS样式

样式Scss就是Sass的升级版,其语法完全兼容 CSS3,css有一个特别不常用的特性,即@import规则,它允许在一个css文件中导入其他css文件。并且@import规则引入时,该行引入代码一定要先于其他任何css规则,除了@charset。

// import.css文件
  .hd{
    color: blue;
  }
// index.html文件
<style type="text/css">
  @import "import.css";
  .hd{
    color: orange;
  }
</style>
...
<p class="hd">我是什么颜色</p>

这时,文本p内的字体就变成了import.css内定义的蓝色。

Props传递组件数据方法

举例,在App.vue中使用了school自定义的组件,同时,需要传递参数。

// App.vue代码
<template>
  <div>
    <!-- 在school标签内加参数,表示该参数需要传递 -->
    <School name="李四" address="女"></School>
    <hr>
  </div>
</template>

<script>
//引入School组件
import School from "./components/School.vue";
//注册组件
export default {
  name: "App",
  components: { School },
};
</script>

<style>
</style>

然后在自定义组件school内要对需传递的参数进行确认

// School.vue代码
<template>
  <div>
    <h2>学校的名称:{{ name }}</h2>
    <h2>学校的地址:{{ address }}</h2>
    <h2>个人简介:{{msg}}</h2>

  </div>
</template>

<script>
export default {
  School: "School",
  data() {
    return {
      msg:'我是一个程序员'
    };
  },
  //使用props确认传过来的参数,第一种写法,数组的形式
  props:['name','address']

};
</script>

在子组件中确认参数的形式仅以数组的形式进行确认有时会出现bug,所以还有第二种写法,规定传递的参数的数据类型。写法如下:

//school.vue的代码
<template>
  <div>
    <h2>学校的名称:{{ name }}</h2>
    <h2>学校的地址:{{ address }}</h2>
    <h2>个人简介:{{ msg }}</h2>
    <h2>成立的年份:{{ year + 1 }}</h2>
  </div>
</template>

<script>
export default {
  School: "School",
  data() {
    return {
      msg: "我是一个程序员",
    };
  },
  //使用props确认传过来的参数,第一种写法,数组的形式
  //   props: ["name", "address","year"],
  //使用props确认传过来的参数,第二种写法,确认了参数,然后对其参数的类型进行限制
  props: {
    name: String,
    address: String,
    year: Number,
  },
};
</script>

样式的Scoped属性

样式深度选择器

样式深度选择器::v-deep/deep/,可以用来修改组件中子组件的样式,对于某些组件的样式使用了scoped属性后,又想去修改嵌套的子组件的样式,就可以用到样式穿透,即深度选择器。

// 在某个组件的样式代码中修改子组件<el-button>样式
<style lang="scss" scoped>
//  ::v-deep写法
    .el-button::v-deep{
         span{
                color: '#f00'
         }
    }
    // /deep/写法
    /deep/.el-button{
         span{
                color: '#f00'
         }
    }
</style>

超出内容滚动条

Overflow:auto给div盒子内容超出盒子高度时加滚动条,需要指定div盒子高度

空数据显示内容

ElementUI当表格Table组件内无数据时,使用empty-text="暂无数据"显示

路由守卫中的next()

next()可以通俗的理解为放行的意思。括号内参数为空。

beforeEach((to, from, next) => {
	to // 要去的路由
	from // 当前路由
	next() // 放行的意思
}

next() 是放行,但是如果next()里有参数的话,next()就像被重载一样,就有了不同的功能,比如next(’/login’) 、 next(to)等等,表示中断当前导航,并执行新的导航。

// 这里的意义并不是执行去login的路由页面,而是中断当前导航,开始执行login导航
beforeEach((to, from, next) => {
  next('/login')
}

因为没有next()进行放行,上述代码会陷入循环嵌套

// 陷入循环嵌套
beforeEach((to, from, next) => {
  beforeEach(('/logon', from, next) => {
  	 beforeEach(('/logon', from, next) => {
  	 	 beforeEach(('/logon', from, next) => {
  	 	 	beforeEac...  // 一直循环下去...... , 因为我们没有使用 next() 放行
 		}
 	 }
  }
}

所以next(’/login’)不是说直接去/login路由,而是中断这一次路由守卫的操作,又进入一次路由守卫。加入一些判断条件后,就会改变这个死循环了。

// 第一次如果导航访问home,会执行next('/login'),然后就会进入新的路由守卫,
// 此时路径改变了,没有了home,那么就执行else中的next()放行。
beforeEach((to, from, next) => {
   if(to.path === '/home') {
   	next('/logon')
   } else {
    // 如果要去的地方不是 /home , 就放行
   	next()
   }
}

js中的next()

Js多个异步请求,使用next()按顺序执行,next()表示继续下一步

全局前置守卫

router.beforeEach 注册一个全局前置守卫:当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。

calc()函数

css用来动态计算宽度的函数。需要注意的是,运算符前后都需要保留一个空格,例如:width: calc(100% - 10px);

#div1 {
    position: absolute;
    left: 50px;
    width: calc(100% - 100px);
    border: 1px solid black;
    background-color: yellow;
    padding: 5px;
    text-align: center;
}

作用域插槽

作用域插槽,父组件决定了插槽处的样式,子组件决定插槽处的数据,slot-scope是vue旧版本写法,新写法是v-slot。

nextTick()

nextTick()等待下一次 DOM 更新刷新的工具方法。Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存到“next tick”以确保每个组件无论发生多少状态改变,都仅执行一次更新。$nextTick()是绑定在实例上的nextTick()函数,组件传递给 this.$nextTick() 的回调函数会带上 this 上下文,其绑定了当前组件实例。

// 某组件内使用ref绑定名称,使用了v-if=showComp设定是否显示
<MyComp ref="mycomp" v-if="showComp"></MyComp>

我们假定showComp默认值是false,在另一个函数里尝试获取当前的showComp值

// 一个函数里给showComp填了true
this.showComp=true;
// 直接使用this.$refs.mycomp,会获取到false
// 因为刚才showComp还是false,刚刚才设置成true,dom还没来得及加载。
// 这个时候我们就需要使用nextTick函数。
// 使用nextTick会获取到true
this.$nextTick(()=>{
	this.$refs.mycomp.refresh();
});

横线 hr /标签

<hr />是网页编辑里的一个标签,其表现形式为一条横线。

Popup组件

Popup是组件库mand-mobile(滴滴金融组件库)的一个点击弹出层

This.$emit()

This.$emit()是子组件向父组件传值,子组件this.$emit(‘title’,data),父组件@title=”title”,就接收到了子组件中的data值。
注意:@titlev-on:title的简写。

CSS样式注意点

  • justify-content: left; /* 一个挨一个在对齐容器得左边缘 */

  • font-weight: bold /将字体设置为粗体/

v-bind和v-on

在父子组件传递数据时有用处:
1.父组件给子组件传递值

// 父组件给子组件v-bind绑定一个属性,作为传参的依据
<div>
    <child :aaa="aa" :bbb="bb" @ccc="cc" />
</div>
data() {
    return {
        aa: 666,
        bb: "999",
    }
}
methods() {
    cc: function() {
        console.log("cc")
    }
}
// 子组件使用props接收确认参数,并规定参数类型
props: {
    aaa: [String, Number],
    bbb: {
          type: String,
          default: 'qwe'
          required: true
    },
    ccc: {
          type: Function
    }
}

2.子组件给父组件传递值

//子组件:使用$emit向父组件传递一个事件名和所带的数据
<button @click="toReturn">返回</button>
methods: {
    toReturn() {
          this.$emit("childValue", "子组件向父组件传值", true);
    }
}

//父组件:通过v-on事件名接收子组件传递过来的参数
<div v-on:childValue="getChildValue"></div>
methods: {
     getChildValue: function(data, data2) {
         console.log(data, data2);
     }
}

v-bind

v-bind指令用于设置HTML属性:v-bind:href 缩写为 :href

// v-bind完整语法
<a v-bind:href="url"></a>
// 简写
<a :href="url"></a>

// v-bind完整语法
<child v-bind:data="data" />
// 简写
<child  :data="data" />

v-on

v-on 指令用于绑定HTML事件 :v-on:click 缩写为 @click

// v-on完整语法
<div v-on:click="clickFunc">按钮</div >
// 缩写
<div @click="clickFunc">按钮</div>

// v-on完整语法
<child v-on:returnFunc="toReturnFunc" / >
// 缩写
<child @returnFunc="toReturnFunc" />
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值