Vue 笔记 04

本文详细介绍了Vue项目的构建过程,包括安装启动、项目目录结构、主要配置文件的说明。同时深入讲解了Vue中的ref、props、mixins、插件、scoped样式、WebStorage以及组件间的通信,如自定义事件、全局事件总线和消息订阅发布。重点讨论了如何在子组件向父组件传递数据,并给出了实际示例。
摘要由CSDN通过智能技术生成

Vue项目构建

1. 安装启动
  1. 安装包:npm i -g @vue/cli
  2. 创建项目:vue create xxxx
  3. 启动项目:切换到项目目录后,运行npm run serve
2. 项目目录
|-- public
    |-- favicon.ico:页签图标
    |-- index.html:主页面
|-- src
	|-- App.vue:汇总所有组件
	|-- main.js:入口文件
	|-- assets:存放静态资源
	    |-- logo.png
	|-- components:存放组件
		|-- HelloWorld.vue
|-- .gitignore:git版本控制忽略的配置
|-- babel.config.js:babel的配置文件
|-- package-lock.json:包版本控制文件
|-- package.json:应用包配置文件
|-- README.md:应用描述文件
3. public/index.html 文件相关说明
<head>
  <meta charset="utf-8">
  <!-- 针对IE浏览器的配置:让IE浏览器以最高的渲染级别渲染页面 -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <!-- 开启移动端的理想视口 -->
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <!-- 配置页签图标 <%= BASE_URL %> 指的是public文件夹的路径 -->
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <!-- 配置网页标题:指的是package.json中配置的name属性 -->
  <title>
    <%= htmlWebpackPlugin.options.title %>
  </title>
</head>

<body>
  <!-- 当浏览器不支持js时,noscript标签中的元素就会被渲染 -->
  <noscript>
    <strong>文字</strong>
  </noscript>
  <!-- 容器 -->
  <div id="app"></div>
</body>
4. 单文件组件的写法
<template>
  <div class="demo">
    <h2>姓名:{{ studentName }}</h2>
    <h2>年龄:{{ age }}</h2>
    <button @click="showName">点我显示姓名</button>
  </div>
</template>

<script>
export default {
  name: "School",
  data() {
    return {
      studentName: "LMY",
      age: 22,
    };
  },
  methods: {
    showName() {
      alert(this.studentName);
    },
  },
};
</script>

<style>
.demo {
  color: tomato;
}
</style>
5. src/main.js 文件相关说明
// 该文件是整个项目的入口文件
import Vue from "vue";
// 引入App组件,该组件是其他所有组件的父组件
import App from "./App.vue";

Vue.config.productionTip = false;

new Vue({
  // 将app组件放入容器中
  render: (h) => h(App),
  // render: (h) => h("h1", "你好啊"),
}).$mount("#app");
/*
	当前引入的Vue是vue.runtime.xxx.js,只包含核心功能,没有模板解析器
	所以无法在new Vue的时候指定template配置项来指定页面内容
	需要使用render函数接收到的createElement即h去指定具体内容
*/
6. vue.config.js

该文件可以对脚手架的webpack配置进行一些修改,文件中的配置项会覆盖默认配置

module.exports = {
	// 配置项不能为空,覆盖后会导致配置错误,项目无法启动
  pages: {
    index: {
      // 重新指定入口
      entry: "src/main.js",
    },
  },
  // 关闭语法检查
  lintOnSave: false,
};

详情参考 https://cli.vuejs.org/zh/config/#vue-config-js

ref 标签属性

被用来给元素或子组件注册引用信息

<!-- 注册引用 -->
<h1 v-text="msg" ref="title"></h1>
<school ref="sch"/>
// 给标签加ref属性,获取到DOM元素
console.log("@", this.$refs.title);
// 给组件加ref属性,获取到组件实例对象vc
console.log("@", this.$refs.sch);

props配置项

作用:让组件接收外部传进来的数据

接收数据

<student name="feidu" :age="22" gender=""/>

传递数据

// 简单接收
props: ["name", "gender", "age"],
// 限制类型
props: {
  name: String,
  age: Number,
  gender: String,
},
// 其他限制
props: {
  name: {
    type: String,
    required: true, // 必须传
  },
  age: {
    type: Number,
    default: 18, // 指定默认值
  },
  gender: {
    type: String,
    required: true,
  },
},
// 在模板中可以直接使用,和data用法一致

注意:props是只读的,Vue底层会监测你对props的修改,如果进行了修改就会报错。想要修改可以将prop的值复制到data中然后修改data中的数据

mixins配置项

作用:可以把多个组件共用的配置提取成一个混合对象

定义混合 mixin.js

export const mixin = {
  methods: {
    showName() {
      alert(this.name);
    },
  },
};

局部使用混合

import { mixin } from "../mixin";
// 配置项
mixins: [mixin],

全局使用混合:在main.js中修改

import { mixin } from "../mixin";
Vue.mixin(mixin);

注意:

  1. 如果混合中配置项是methods和data,那么会将原有的和混合中的放在一起使用,如果存在冲突,以组件中原来定义的为准
  2. 如果像生命周期钩子函数这种配置,会将函数中的代码进行合并,此时混合中的代码在前

插件

  • 作用:用于增强Vue
  • 本质:包含install方法的一个对象,install 的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据

定义插件 plugins.js

export default {
  install(Vue, x) {
    console.log("@install", Vue, x);
    // 可以定义全局过滤器、全局指令、混合
    // 添加全局方法
    Vue.prototype.hello = () => { alert("hello"); }
  },
};

使用插件:在main.js中修改

// 引入插件
import plugins from "./plugins";
// 应用插件:应用插件后install方法就会调用进行一些增强的操作
Vue.use(plugins, 1);

scoped样式

在组件中定义样式

<style scoped> 
.demo {
  background-color: rosybrown;
}
</style>

此时样式只在当前组件中生效

WebStorage

  • 存储内容大小一般支持5MB左右(不同的浏览器可能不同)
  • 浏览器端通过 window.localStoragewindow.sessionStorage 属性来实现本地存储机制

相关API

<div id="root">
  <h2>LocalStorage</h2>
  <button onclick="saveData()">点我保存数据</button>
  <button onclick="readData()">点我读取数据</button>
  <button onclick="deleteData()">点我删除数据</button>
  <button onclick="deleteAllData()">点我清空数据</button>
</div>
<script>
  // F12 在Application选项卡中查看
  function saveData() {
    localStorage.setItem("msg", "dudu");
    // 两个参数都是字符串类型,如果数据不是字符串可以使用JSON来进行转换
    localStorage.setItem("book", JSON.stringify({ name: 'modu', author: "Priest" }));
  }
  function readData() {
    console.log(localStorage.getItem("msg"));
    // 如果读取的值不存在,返回值为null,JSON.parse(null)的结果还是null
    console.log(JSON.parse(localStorage.getItem("book")));
  }
  function deleteData() {
    localStorage.removeItem("msg");
  }
  function deleteAllData() {
    localStorage.clear();
  }
  // localStorage中的数据在浏览器关闭后也不会消失,需要手动调用API或者清除浏览器缓存
  // sessionStorage 与 localStorage使用的API完全相同,区别在于浏览器关闭后sessionStorage中的数据就会消失
</script>

注意:sessionStorage 与 localStorage使用的API完全相同,区别在于浏览器关闭后sessionStorage中的数据就会消失,而localStorage中的数据需要手动调用API或者清除浏览器缓存才可以删除

组件自定义事件

子组件给父组件传递数据方式一:通过父组件给子组件传递函数类型的props来实现

父组件 App.vue

<template>
  <div class="app">
    <school :getSchoolName="getSchoolName" />
  </div>
</template>

<script>
export default {
  methods: {
    getSchoolName(name) {
      console.log(`APP组件收到了学校名:${name}`);
    },
  }
</script>

子组件 School.vue

<template>
  <div class="school">
    <h2>学校名称:{{ name }}</h2>
    <button @click="sendSchoolName">点我发送学校名</button>
  </div>
</template>

<script>
export default {
  props: ["getSchoolName"],
  methods: {
    sendSchoolName() {
      this.getSchoolName(this.name);
    },
  },
</script>
子组件给父组件传递数据方式二:通过父组件给子组件绑定一个自定义事件实现

父组件 App.vue

<template>
  <div class="app">
    <!-- 绑定一个名字为dudu的自定义事件 -->
    <student @dudu="getStudentName" />
  </div>
</template>

<script>
export default {
  methods: {
    // 定义事件触发后的回调函数,可以使用ES6中的 ...params 来接收参数
    getStudentName(name) {
      console.log(`APP组件收到了学生名:${name}`);
    },
  }
</script>

子组件 Student.vue

<template>
  <div class="student">
    <h2>姓名:{{ name }}</h2>
    <button @click="sendStudentName">点我发送学生名</button>
  </div>
</template>

<script>
export default {
  methods: {
    sendStudentName() {
      // 触发自定义事件:第一个参数为事件名,后面的参数可以有很多,用来传递需要的数据
      this.$emit("dudu", this.name);
    },
  },
</script>

在父组件中也可以在JS代码中绑定事件

<template>
  <div class="app">
    <student ref="student" />
  </div>
</template>

<script>
export default {
  mounted() {
    // 绑定自定义事件的另一种方式
    this.$refs.student.$on("dudu", this.getStudentName);
  },
  methods: {
    getStudentName(name) {
      console.log(`APP组件收到了学生名:${name}`);
    },
  }
</script>

如果事件只触发一次那么两种绑定方式分别为:

  1. <student @dudu.once="getStudentName" />
  2. this.$refs.student.$once("dudu", this.getStudentName);

解除绑定自定义事件

// 解绑一个自定义事件
this.$off("dudu");
// 解绑多个自定义事件
this.$off(["dudu", "demo"]);
// 解绑所有的自定义事件
this.$off();

注意:组件实例被销毁(可以调用this.$destroy()或者路由的方式)后,组件实例上的所有自定义事件都会自动解绑

一些注意事项

在JS代码中绑定事件时,可以将第二个参数直接写回调函数的内容,但回调函数一定要使用箭头函数的形式

this.$refs.student.$on("dudu", (name) => {
  console.log(`APP组件收到了学生名:${name}`);
  console.log(this);
});

因为事件回调函数中的this默认是触发事件的对象,也就是Student组件实例对象,此时就无法使用this来操作App组件实例对象中的数据

this.$refs.student.$on("dudu", function (name) {
  console.log(`APP组件收到了学生名:${name}`);
  console.log(this);
});

不可以使用@click="show"直接给组件绑定原生DOM事件,Vue会将该click事件当做自定义事件处理,如果要绑定,需要使用@click.native="show"

全局事件总线

  • 一种组件间通信的方式,适用于任意组件间通信

安装全局事件总线:main.js

new Vue({
  render: (h) => h(App),
  // 安装全局事件总线
  beforeCreate() {
    // 将当前应用的vm保存到原型对象中,使之后的每个组件都可以操作它
    Vue.prototype.$bus = this;
  },
}).$mount("#app");

使用全局事件总线:

// 在组件上绑定事件
mounted() {
  this.$bus.$on("dudu", (data) => {
    console.log("我是School组件", data);
  });
},
// 在组件销毁之前解绑自己在总线上绑定的事件
beforeDestroy() {
  this.$bus.$off("dudu");
},
// 在另一个组件上触发该事件,并传递数据
methods: {
  sendStudentName() {
    this.$bus.$emit("dudu", 666);
  },
},

消息订阅与发布

  • 一种组件间通信的方式,适用于任意组件间通信
  • 一种实现:pubsub-js

安装: npm i pubsub-js

引入:import pubsub from "pubsub-js";

使用:

mounted() {
  // 订阅消息:msgName是事件名,data是参数
  this.pubId = pubsub.subscribe("dudu", (msgName, data) => {
    console.log("有人发布了dudu消息,dudu消息的回调执行了...", msgName, data);
    console.log(this); // this的规则和自定义事件相同
  });
},
beforeDestroy() {
  // 取消订阅:类似定时器的取消方式
  pubsub.unsubscribe(this.pubId);
},
sendStudentName() {
  pubsub.publish("dudu", this.name);
},

$nextTick

  • 语法:this.$nextTick(回调函数)
  • 作用:在下一次DOM更新结束后执行其指定的回调
  • 用法:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值