计算属性
基础
定义:一个特殊属性, 值依赖于另外一些数据动态计算出来。
注意
- 计算属性必须定义在 computed 节点中
- 计算属性必须是一个 function,计算属性必须有返回值
- 计算属性不能被当作方法调用,要作为属性来用
- 函数内使用的变量改变,重新计算结果返回
- 计算属性也是属性,所以不要和data里重名,用起来也和data类似
缓存特性
- 计算后会立刻缓存,下次直接读缓存
- 依赖项改变, 函数会重新执行并重新缓存
- 多次使用计算属性,性能会极高
计算属性的设置问题-完整写法
使用场景:给计算属性变量赋值时 计算属性默认情况下只能获取,不能修改。 要给计算属性赋值,就必须写计算属性的完整写法
<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代码 优点:各自独立,便于复用,可维护性高 使用场景:遇到重复标签, 可复用的时候
步骤
- 创建组件,一个文件就是一个组件
- 引入组件
- 注册
- 局部注册
- 全局注册
- 使用组件
局部注册
<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>
组见名规范
命名方式
- 注册使用短横线命名法,例如 hm-header
- 使用时
<hm-button> </hm-button>
- 使用时
- 注册使用大驼峰命名法,例如 HmHeader
- 使用时
<HmButton> </HmButton>和<hm-button> </hm-button>都可以
- 使用时
- 推荐统一使用短横线命名法
注意:组件名不能和内置html名同名
样式冲突
默认情况下,写在组件中的样式会 全局生效,因此很容易造成多个组件之间的样式冲突问题。
- 全局样式:默认组件中的样式会作用到全局
- 局部样式:可以给组件加上 scoped 属性, 可以让样式只作用于当前组件
scoped原理
- 当前组件内标签都被添加 data-v-hash值 的属性
- css选择器都被添加 [data-v-hash值] 的属性选择器
- 必须是当前组件的元素, 才会有这个自定义属性, 才会被这个样式作用到
组件通信
前提:每个组件有自己的数据,并且相互独立,无法相互访问 实现访问的方案:组件通信
父传子
父组件的代码
在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中需要遵循单向数据流原则:(从父到子的单向数据流动)
- 父组件的数据变化了,会自动向下流动影响到子组件
- 子组件不能直接修改父组件传递过来的 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>
父组件的代码
- 在template中,给子组件标签name-table添加属性:@事件名toDad=“方法名delData”
- 在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>