Vue2.x笔记

2021/8/16 vue2.x

# 实例方法-数据

this.$set(this.obj, "属性",); //添加、修改属性
this.$delete(this.obj, "属性"); //删除属性

# Vue 过滤器(搭配 el-table 使用)

<template slot-scope="scope">
  <div :style="scope.row.type">
    { {scope.row.type | licenseType} }
  </div>
</template>
//过滤器
filters: {
    licenseType: function (type) {
        switch (type) {
            case '0':
                return 'value'
                break;
            case '1':
                return 'value'
                break;
            ...
            default:
            break;
        }
    }
},

# Vue 组件注册

vue 中注册组件的方式分为全局注册局部注册两种,其中:被全局注册的组件,可以在全局任何一个组件内使用,被局部注册的组件,只能在当前注册的范围内使用。

  • 使用 app.component() 方法注册的全局组件,直接以标签的形式进行使用
import { createApp } from "vue";
import App from "./App.vue";

import Test from "./components/Test.vue";

const app = createApp(App);

app.component("Test", Test);

app.mount("#app");
  • 局部注册
<script>
import Test from './components/Test.vue'

export default {
  name: 'App',
  components: { // 通过 component 节点,为当前组件注册私有子组件
    Test
  }
}
</script>
  • 通过 name 属性注册组件
// 当前组件名称
<script>
export default {
  name: "Test",
};
</script>

// 注册时
import Test from './components/Test.vue'
app.component(Test.name,Test)

# /deep/ 样式穿透

如果给当前组件的 style 节点添加了 scoped 属性,则当前组件的样式对其子组件是不生效的。如果想让某些样式对子组件生效,可以使用 /deep/ 深度选择器。

注意:/deep/vue2.x 中实现样式穿透的方案,在 vue3.x 中推荐使用 :deep() 替代 /deep/

<style scoped>
/* 不加 /deep/ 时,生成的选择器格式为 .title[data-v-xxxx] */
.title{
    color: pink;
}

/* 不加 /deep/ 时,生成的选择器格式为 [data-v-xxxx] .title */
/* vue2.x中 */
/deep/ .title{
  color: pink;
}
/* vue3.x中 */
:deep(.title){
  color: pink;
}
</style>

# Vue 侦听器的使用

watch 侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。

watch 侦听器的基本语法

export default {
  data() {
    return {
      userName: "",
    };
  },
  watch: {
    /**
     * 监听 userName 的值的变化
     * newVal 表示变化后的新值,oldVal表示变化前的旧值
     **/
    userName(newVal, oldVal) {
      console.log(newVal, oldVal);
    },
  },
};

watch 侦听器选项

  • immediate

默认情况下,组件在初次加载完毕后不会调用 watch 侦听器。如果想让 watch 侦听器立即被调用,则需要使用 immediate 选项。

watch: {
    // 监听 userName 值的变化
    userName: {
        // handler 是固定写法:当 userName 变化时,调用 handler
        handler(newVal) {
            console.log(newVal)
        }
    },
    // immediate 为 true 表示组价加载完毕后立即调用一次当前的 watch 侦听器
    immediate: true
}
  • deep

watch 侦听的是一个对象,如果 对象中的属性值 发生了变化,则无法被监听到,此时需要使用 deep 选项。

export default {
  data() {
    return {
      userInfo1: {
        name: "",
      },
      userInfo2: {
        name: "",
        age: "",
      },
    };
  },
  watch: {
    userInfo1: {
      // 直接监听 userInfo1 对象的变化
      handler(newVal) {
        console.log(newVal);
      },
      deep: true, // 当 deep 为 true 时,可以监听到 useInfo1中 name 属性的变化
    },

    /**
     * 当监听对象中包含不止一个属性时,比如 userInfo2
     * 我们需要监听 userInfo2 中 name 属性的变化
     * 使用上面的写法会出现错误:当 userInfo2 中 age 属性变化时也会触发侦听器
     * 如果我们只想监听对象中单个属性的变化,可以按照如下方式定义侦听器
     **/

    "userInfo2.name": {
      // 只直接监听 userInfo2.name 属性值的变化
      handler(newVal) {
        console.log(newVal);
      },
    },
  },
};

# 计算属性 vs 侦听器

计算属性和侦听器侧重的 应用场景不同

  • 计算属性侧重于监听 多个值 的变化,最终计算并 返回一个新值
  • 侦听器侧重于监听 单个数据 的变化,最终执行特定的 业务处理 ,不需要有任何返回值

# Vue 删除(搭配 element-ui 使用)

async del (row) {
  const confirmResult = await this.$confirm(
    "此操作将永久删除该内容, 是否继续?",
    "提示",
     {
     confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    }
  ).catch(err => err);
  // 点击确定 返回值为:confirm
  // 点击取消 返回值为: cancel
  if (confirmResult !== "confirm") {
    return this.$message.info("已取消删除");
  }
  ...
},

# Vue 刷新页面

在项目中经常会遇到用户执行完某个操作,改变了某些状态,需要重新刷新页面,以此来重新渲染页面,例如数据的增删改查等。

在 app.vue 中添加如下代码

<template>
    <div id="app">
    	<router-view v-if="isRouterAlive"></router-view>
	</div>
</template>
<script>
    export default {
        name: 'App',
        provide () {    //父组件中通过provide来提供变量,在子组件中通过inject来注入量。
            return {
                reload: this.reload
            }
        },
        data() {
            return{
                isRouterAlive: true                    //控制视图是否显示的变量
            }
        },
        methods: {
            reload () {
                this.isRouterAlive = false;            //先关闭,
                this.$nextTick(()=> {
                    this.isRouterAlive = true;         //再打开
                })
            }
        },
    }
</>

在需要刷新页面的组件调用 reload 方法

export default {
    inject:['reload'],                                 //注入App里的reload方法
    data () {
        return {}
    },
    methods:{
      方法:{
        this.reload()
      }
    }

# Vue 路由跳转传参

//path:跳转路径
//query:请求参数
this.$router.push({
  path: "/路径名称",
  query: { 参数名: JSON.stringify("参数值") },
});
//跳转后页面获取参数
this.赋值对象 = JSON.parse(this.$route.query.参数名);

# 解决 Vue 重复点击路由报错

//在router文件夹下的index.js中加入以下代码
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
  return originalPush.call(this, location).catch((err) => err);
};

# Vue 路由跳转缓存

实现需求

1.页面跳转后,回到此页面时,页面不刷新

2.详情页返回至列表页时,数据不刷新,同时浏览位置不改变

实现原理

keep-alivevue-router配合使用

//1.在整个页面框架中需要进行是否缓存的设置
  <keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
  </keep-alive>
  <router-view v-if="!$route.meta.keepAlive"></router-view>

//2.在路由配置中设置页面是否缓存
  path: '/xxxx',
  component: xxxx,
  meta: {
    keepAlive: true,
    scollTopPosition: 0
  }

//3.记录滚动条
  //第一步:定义初始滚动高度
  scroll:0
  //第二步:mounted中的方法代表dom已经加载完毕
  mounted:function(){
    window.addEventListener('scroll', this.handleScroll);
  },
  //第三步:用于存放页面函数
  methods:{
    handleScroll () {
      this.scroll  = $(window).height()+ $(document).scrollTop()
    }
  },
  //第四步:当再次进入(前进或者后退)时,只触发activated(注:只有在keep-alive加载时调用)
  activated(){
    if(this.scroll > 0){
        window.scrollTo(0, this.scroll);
        window.addEventListener('scroll', this.handleScroll);
    }
  },
  //第五步:deactivated 页面退出时关闭事件 防止其他页面出现问题
  deactivated(){
    window.removeEventListener('scroll', this.handleScroll);
  },

//4.跳转同一页面获取不同数据
  //实现方法:watch监听路由
  watch: {
    "$route": function (n, o) {
      console.log('watch', n, o);
    }
  },

# 深拷贝

问题:

Vue开发过程中数组新push一个对象,其他对象也同时被修改

原因:

对象是引用类型,传递的是引用地址,所以两个数组引用的是同一个对象,只要其中一个数组改变,就会导致对象改变,进而另一个引用的数组也会改。

解决方法:

将需要放入数组的对象先深拷贝一份,用拷贝的对象,这样就不存在引用关系了。

1.拷贝:

new_obj = JSON.parse(JSON.stringify(obj));

2.重新申请一个内存空间,然后赋值给他,再push,实现深拷贝

# Vue 解析 XLSX 文件

vue 框架中上传 xlsx 文件,使用 js-xlsx 解析文件内容

//1.首先执行(安装)
npm install xlsx

//2.在当前页面.vue文件中引入
import XLSX from 'xlsx'

//3.在main.js中引入
import XLSX from '路径'

//4.vue+element:使用element-ui组件(el-upload),在onChange方法中调用读取数据函数(readExcel)

readExcel (e) {
  let that = this;
  const files = that.fileData;
  console.log('files', files);
  if (!files) {
    //如果没有文件
    return false;
  } else if (!/\.(xls|xlsx)$/.test(files.name.toLowerCase())) {
    this.$message.error("上传格式不正确,请上传xls或者xlsx格式");
    return false;
  }
  const fileReader = new FileReader();
  fileReader.onload = ev => {
    try {
      const data = ev.target.result;
      // console.log('data', data)
      const workbook = XLSX.read(data, {
        type: "binary"
      });
      console.log('workbook', workbook.SheetNames)
      const wsname = workbook.SheetNames[0]; //取第一张表
      const ws = XLSX.utils.sheet_to_json(workbook.Sheets[wsname]); //生成json表格内容
      console.log('ws', ws);//ws中即为获取到的数据
      this.outputs = ws
    } catch (e) {
      return false;
    }
  };
  // 如果为原生 input 则应是 files[0]
  fileReader.readAsBinaryString(files.raw);
},

# Vue 自定义校验

//data中
var checkName = (rule, value, callback) => {
  if (!value) {
    return callback(new Error("请输入姓名"));
  }
  setTimeout(() => {
    let reg = /^[\u0391-\uFFE5A-Za-z]+$/;
    if (!reg.test(value) && value !== "") {
      callback(new Error("请输入中文姓名"));
    } else {
      callback();
    }
  }, 100);
};

//rules中-validator: + 自定义规则名
name: [{ required: true, validator: checkName, trigger: "blur" }],

# 常用表单校验规则

链接地址 (opens new window)

# Vue 自定义过滤器

# -- 格式化数字三位加一逗号

Vue.filter("NumFormat", function(value) {
  if (!value) return "0.00";
  var intPart = Number(value) - (Number(value) % 1); //获取整数部(这里是windy93的方法)
  var intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, "$1,"); //将整数部分逢三一断
  var floatPart = ".00"; //预定义小数部分
  var value2Array = value.toString().split(".");
  //=2表示数据有小数位
  if (value2Array.length == 2) {
    floatPart = value2Array[1].toString(); //拿到小数部分
    if (floatPart.length == 1) {
      //补0,实际上用不着
      return intPartFormat + "." + floatPart + "0";
    } else {
      return intPartFormat + "." + floatPart;
    }
  } else {
    return intPartFormat + floatPart;
  }
});
更新时间 : 2021年11月1日星期一下午5点58分