Vue学习笔记03

88 阅读3分钟

计算属性

基础

定义:一个特殊属性, 值依赖于另外一些数据动态计算出来。

注意

  1. 计算属性必须定义在 computed 节点中
  2. 计算属性必须是一个 function,计算属性必须有返回值
  3. 计算属性不能被当作方法调用,要作为属性来用
  4. 函数内使用的变量改变,重新计算结果返回
  5. 计算属性也是属性,所以不要和data里重名,用起来也和data类似

缓存特性

  1. 计算后会立刻缓存,下次直接读缓存
  2. 依赖项改变, 函数会重新执行并重新缓存
  3. 多次使用计算属性,性能会极高

计算属性的设置问题-完整写法

使用场景:给计算属性变量赋值时 计算属性默认情况下只能获取,不能修改。 要给计算属性赋值,就必须写计算属性的完整写法

<template>
  <div>
    全选:<input type="checkbox" v-model="getAll"/>
    <button @click="against">反选</button>
    <ul>
      <li v-for="i in list" :key="i.name">
        <input type="checkbox" v-model="i.checked" /> {{ i.name }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      list: [
        {
          name: "猪八戒",
          checked: false,
        },
        {
          name: "孙悟空",
          checked: false,
        },
        {
          name: "唐僧",
          checked: false,
        },
        {
          name: "沙师弟",
          checked: false,
        },
      ],
    };
  },
  computed: {
    getAll: {
      get() {
        return this.list.every(i => i.checked);
      },
      set(value) {
        this.list.forEach((v) => { v.checked = value })
        console.log(value);
      },
    },
  },
  methods: {
    against() {
      this.list.forEach((value) => {
        value.checked = !value.checked;
      });
    },
  },
};
</script>

<style>
</style>

侦听器

watch: 可以侦听到 data/computed 属性值的改变

<template>
  <div>
		<input type="text" v-model="count" />
	</div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      count: 100,
    };
  },
  watch: {
    // 在侦听器内部避免修改侦听的属性
    count(newValue, oldValue) {
			console.log("被侦听到了");
    },
};
</script>

深度侦听和立即执行

深度侦听:如果监听的是复杂数据类型,需要深度监听,需要指定deep为true, 需要用到监听的完整的写法 立即执行:页面渲染完成则立即执行

<template>
  <div>
    <input type="text" v-model="stu.age++" />
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      stu: {
        name: "小陈",
        age: 18,
      },
    };
  },
  watch: {
    stu: {
			immediate: true,  // 立即执行
      deep: true,       // 深度侦听
      handler(newValue) {
        console.log("新值是", newValue.age);
      },
    },
  },
};
</script>

生命周期

<script>
export default {
	name: "App",
	created() {},		// 创建即调执行
};
</script>

Vue组件

定义:可复用的 Vue 文件,封装,CSS和JS代码 优点:各自独立,便于复用,可维护性高 使用场景:遇到重复标签, 可复用的时候

步骤

  1. 创建组件,一个文件就是一个组件
  2. 引入组件
  3. 注册
    1. 局部注册
    2. 全局注册
  4. 使用组件

局部注册

<template>
  <div>
		<!-- 使用组件 -->
    <hm-listen></hm-listen>
  </div>
</template>

<script>
// 引入组件
import listen from "./components/组见名.vue";
export default {
	// 局部注册
	components: {
		'hm-listen': listen,
	},
};
</script>

全局注册

在main.js中注册

import Hi from "./components/全选案例.vue";
// 注册全局组件
Vue.component("hm-hi", Hi);

可以直接在任意组件中使用

<template>
  <div>
		<!-- 任意组件中使用全局注册的组件 -->
    <hm-hi></hm-hi>
  </div>
</template>

通过 name 注册组件

被引用的任意组件

<template>
  <div>被引用组件</div>
</template>

<script>
export default {
	name:"hm-quote",
};
</script>

在App.vue中引用

<template>
  <div>
    <hm-quote></hm-quote>
  </div>
</template>

<script>
import listen from "./components/组见名.vue";
export default {
	components: {
		[listen.name]: listen,		// 这里的name指向被引用文件中的export default的name
	},
};
</script>

组见名规范

命名方式

  1. 注册使用短横线命名法,例如 hm-header
    1. 使用时 <hm-button> </hm-button>
  2. 注册使用大驼峰命名法,例如 HmHeader
    1. 使用时 <HmButton> </HmButton><hm-button> </hm-button> 都可以
  3. 推荐统一使用短横线命名法

注意:组件名不能和内置html名同名

样式冲突

默认情况下,写在组件中的样式会 全局生效,因此很容易造成多个组件之间的样式冲突问题。

  1. 全局样式:默认组件中的样式会作用到全局
  2. 局部样式:可以给组件加上 scoped 属性, 可以让样式只作用于当前组件

scoped原理

  1. 当前组件内标签都被添加 data-v-hash值 的属性
  2. css选择器都被添加 [data-v-hash值] 的属性选择器
  3. 必须是当前组件的元素, 才会有这个自定义属性, 才会被这个样式作用到

组件通信

前提:每个组件有自己的数据,并且相互独立,无法相互访问 实现访问的方案:组件通信

父传子

父组件的代码

在template中,给子组件标签subject-table添加属性::事件名toSon="传给子组件的数据data"

<template>
  <div>
		<!-- 给子组件添加属性 -->
		<subject-table :toSon="data"></subject-table>
  </div>
</template>
<!-- script部分正常书写,关注template部分的子组件 -->
<script>
import subjectTable from "./components/subject-table.vue";
export default {
  components: {
    "subject-table": subjectTable,
  },
	data() {
		return {
			data: "被传入的数据",
		},
	},
</script>

子组件的代码

在script中,在export default添加:props: ["事件名toSon"],

<script>
export default {
	// 用porps接收父组件传的数据
  props: ["toSon"],
};
</script>

子传父

单向数据流

在vue中需要遵循单向数据流原则:(从父到子的单向数据流动)

  1. 父组件的数据变化了,会自动向下流动影响到子组件
  2. 子组件不能直接修改父组件传递过来的 props, props是只读的!

子组件的代码

在子组件绑定的事件中添加:this.$emit("事件名toDad", 传给父组件的数据id);

<template>
	<!-- html结构,正常写,需要注意的部分在script中 -->
	<table>
		<tr v-for="i in list" :key="i.id">
			<td>{{ i.id }}</td>
			<td>{{ i.name }}</td>
			<td>
				<button	@click="del(i.id)">删除</button>
			</td>
		</tr>
	</table>
</template>

<script>
export default {
	// 用porps接收父组件传的数据
  props: ["list"],
  methods: {
    del(id) {
			// 注意:不要直接修改父组件传来的数据
      this.$emit("toDad", id);
    },
  },
};
</script>

父组件的代码

  1. 在template中,给子组件标签name-table添加属性:@事件名toDad=“方法名delData”
  2. 在script中,添加一个函数:方法名delData(传给父组件的数据id) {...}
<template>
  <div class="container">
		<subject-table :list="nameList" @toDad="delData"></subject-table>
  </div>
</template>

<script>
import nameTable from "./components/name-table.vue";
export default {
  components: {
    "name-table": nameTable,
  },
  data() {
    return {
			// 只存全局需要的数据
      nameList: [
        {
          id: 1,
          name: "小陈",
        },
        {
          id: 2,
          name: "小黄",
        },
      ],
    };
  },
  methods: {
    delData(id) {
      const index = this.nameList.findIndex((value) => value.id === id);
      this.nameList.splice(index, 1);
    },
};
</script>