乐趣区

关于vue.js:Vue-脚手架编程

1.1 初始化脚手架

1.1.1 阐明

  1. Vue 脚手架是 Vue 官网提供的标准化开发工具(开发平台)
  2. 最新的版本是 4.x
  3. 文档

1.1.2 具体步骤

  1. 第一步(仅第一次执行):全局装置 @vue/cli

    npm install -g @vue/cli
  2. 第二步:切换到要创立我的项目的目录,而后应用命令创立我的项目

    vue create xxxx

    xxxx: 我的项目名

  3. 第三步:启动我的项目

    npm run serve
  4. 备注:

    1. 如呈现:下载迟缓请配置淘宝镜像:

      npm config set registry https://registry.npm.taobao.org
    2. Vue 脚手架暗藏了所有 webpack 相干的配置,若想查看具体的 webpack配置,请执行:

      vue inspect > output.js

1.1.3 模板我的项目的构造

├──node_modules
├──public
│ ├──favicon.ico: 页签图标
│ └──index.html: 主页面
├──src
│ ├──assets: 寄存动态资源
│ │ └──logo.png
│ │──component: 寄存组件
│ │ └──HelloWorld.vue
│ │──App.vue: 汇总所有组件
│ │──main.js: 入口文件
├──.gitignore:git 版本管制疏忽的配置
├──babel.config.js:babel 的配置文件
├──package.json: 利用包配置文件
├──README.md: 利用形容文件
├──package-lock.json:包版本控制文件

1.1.4 不同版本的 Vue

  1. vue.jsvue.runtime.xxx.js 的区别:

    1. vue.js 是完整版的 Vue,蕴含:外围性能 + 模板解析器。
    2. vue.runtime.xxx.js 是运行版的 Vue,只蕴含:外围性能;没有模板解析器
  2. 因为 vue.runtime.xxx.js 没有模板解析器,所以不能应用 template 这个配置项,须要应用 render 函数接管到的 createElement 函数去指定具体内容

1.1.5 vue.config.js 配置文件

  1. 应用 vue inspect > output.js 能够查看到 Vue 脚手架的默认配置。
  2. 应用 vue.config.js 能够对脚手架进行个性化定制,详情

1.2 ref

1.2.1 应用阐明

  1. 被用来给元素或子组件注册援用信息(id 的替代者)
  2. 利用在 html 标签上获取的是实在 DOM 元素,利用在组件标签上是组件实例对象(vc
  3. 应用形式:

    1. 打标识:<h1 ref="xxx">.....</h1><School ref="xxx"></School>
    2. 获取:this.$refs.xxx

1.3 props

1.3.1 应用阐明

  1. 性能:让组件接管内部传过来的数据
  2. 传递数据:<Demo name="xxx"/>
  3. 接收数据:

    1. 第一种形式(只接管):props:['name']
    2. 第二种形式(限度类型):props:{name:String}
    3. 第三种形式(限度类型、限度必要性、指定默认值):

      props:{
          name:{
          type:String, // 类型
          required:true, // 必要性
          default:'老王' // 默认值
          }
      }

      备注:props 是只读的,Vue 底层会监测你对 props 的批改,如果进行了批改,就会收回正告,若业务需要的确须要批改,那么请复制 props 的内容到 data 中一份,而后去批改 data 中的数据。

1.3.2 代码示例

父组件 App 中应用子组件 Student,并传参数

<template>
<div id="app">
    <!-- 留神:属性后面有没有加 : 的区别,没加就是示意传的参数是字符串,加了就是示意具体的类型值 -->
    <!-- <Student studentName="张三" studentSex="男" studentAge="18"/> -->
    <hr />
    <Student studentName="张三" studentSex="男" :studentAge="18"/>
    <hr />
    <Student  studentSex="男" :studentAge="20"/>

    </div>
</template>
<script>
    import Student from "./components/Student.vue";

    export default {components: { Student}
    };
</script>

Student 组件接管父组件传来的参数

<template>
  <div>
    <h2>{{msg}}</h2>
    <h2> 学生姓名: {{studentName}}</h2>
    <h2> 学生性别: {{studentSex}}</h2>
    <!-- <h2> 学生年龄: {{studentAge + 1}}</h2> -->
    <h2> 学生年龄: {{age + 1}}</h2>
    <button @click="addAge"> 点我年龄 +10 </button>
  </div>
</template>

<script>
export default {
  name: "Student",
  // 接管参数的简要写法
  // props: ['studentName', 'studentSex', 'studentAge'],

  // 承受参数 + 指定类型的写法
  // props: {
  //   studentName: String,
  //   studentSex: String,
  //   // 指令类型为数值类型,当传入的类型不是数值类型时就会报错
  //   // Expected Number with value 18, got String with value "18".
  //   studentAge: Number, 
  // },

  // 接管参数 + 指定类型 + 指定是否必传 + 指定默认值
  props: {
    studentName: {
      // 指定类型是字符串
      type: String,
      // 指定默认值
      default: "李四"
    },
    studentSex: {
      type: String,
      // 指定必传
      required: true
    },
    studentAge: {type: Number}
  },
  
  data() {
    return {
      msg: "我是一名学生",
      age: this.studentAge
    };
  },

  methods: {addAge() {
      // props 是只读的,Vue 底层会监测你对 props 的批改,如果进行了批改,就会收回正告,若业务需要的确须要批改,那么请复制 props 的内容到 data 中一份,而后去批改 data 中的数据。// 正告 
      // Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders.
      // this.studentAge += 10;
      this.age += 10
    }
  }
};
</script>

1.4 混入

1.4.1 应用阐明

  1. 性能:能够把多个组件共用的配置提取成一个混入对象
  2. 应用形式:

    第一步定义混入:

    {data(){....},
        methods:{....}
        ....
    }

    第二步应用混入:
    ​ – 全局混入:Vue.mixin(xxx)
    ​ – 部分混入:mixins:['xxx']

1.4.2 代码示例

定义混入 mixin.js

// 定义一个混入配置信息
// 阐明:如果混入中配置的数据、办法,在组件中有同样的数据定义、办法名称,会加载组件中的数据和办法,混入中的数据和办法就不起作用
const mixin1 = {data() {
        return {
            x: 200,
            y: 100
        }
    },
    methods: {showName() {alert(this.name)
        }
    },
}
// 阐明:生命周期中的函数,如果混入、组件中都有配置的话,二者都会执行
const mixin2 = {mounted() {console.log("mixin 中的 mounted...")
    },
}

export {
    mixin1,
    mixin2
}

在组件中应用混入:

<template>
  <div>
    <h2> 学校名称:{{name}}</h2>
    <h2> 学校地址:{{address}}</h2>
    <button @click="showName"> 点我提示信息 </button>
  </div>
</template>

<script>
// 引入混入
import {mixin1} from "@/mixin";

export default {
  name: "School",
  // 混入配置项
  mixins: [mixin1],
  data() {
    return {
      name: "北京大学",
      address: "北京",
    };
  },
  methods: {// showName() {//   alert(this.name);
    // },
  },
};
</script>
<template>
  <div>
    <h2> 学生姓名: {{name}}</h2>
    <h2> 学生性别: {{sex}}</h2>
    <h2> 学生年龄: {{age}}</h2>
    <button @click="showName"> 点我提示信息 </button>
  </div>
</template>

<script>
// 引入混入
import {mixin1, mixin2} from "../mixin";
export default {
  name: "Student",
  mixins: [mixin1, mixin2],

  data() {
    return {
      name: "张三",
      sex: "男",
      age: 20,
      x: 1000,
    };
  },
  methods: {showName() {console.log("student...");
      alert(this.name + "hello world");
    },
  },
  mounted() {console.log("student 中的 mounted...");
  },
};
</script>

1.5 插件

1.5.1 应用阐明

  1. 性能:用于加强 Vue
  2. 实质:蕴含 install 办法的一个对象,install 的第一个参数是 Vue,第二个当前的参数是插件使用者传递的数据。
  3. 定义插件:

    对象.install = function (Vue, options) {
        // 1. 增加全局过滤器
        Vue.filter(....)
    
        // 2. 增加全局指令
        Vue.directive(....)
    
        // 3. 配置全局混入(合)
        Vue.mixin(....)
    
        // 4. 增加实例办法
        Vue.prototype.$myMethod = function () {...}
        Vue.prototype.$myProperty = xxxx
    }
  4. 应用插件:Vue.use()

1.5.2 代码示例

定义插件 plugins.js

export default {install(Vue) {console.log(Vue, "@@@@@");

        // 全局定义过滤器
        Vue.filter("strSlice", function (value) {return value.slice(0, 4)
        })

        // 全局定义指令
        Vue.directive("fbind", {
            // 指令与元素胜利绑定时 一上来
            bind(element, binding) {element.value = binding.value},
            // 指令所在元素插入页面时
            inserted(element, binding) {element.focus()
            },
            // 指令所在模板被从新解析时
            updated(element, binding) {element.value = binding.value},
        })
        // 给 Vue 原型上增加一个办法 vm、vc 都能应用
        Vue.prototype.hello = () => {console.log("hello world");
        }
    },

}

main.js 中应用插件

// 引入插件
import plugins from './plugins'

// 应用插件
Vue.use(plugins)

1.6 scoped 款式

  1. 作用:让款式在部分失效,避免抵触。
  2. 写法:

    <style scoped>
      .demo {
        background-color: orange;
        // less 与 css 的一个区别就是 less 能够叠加写,css 不能够
        .title {font-size: 40px;}
      }
    </style>

1.7 组件化编码流程

  1. 组件化编码流程:

    1. 拆分动态组件:组件要依照性能点拆分,命名不要与 html 元素抵触。
    2. 实现动静组件:思考好数据的寄存地位,数据是一个组件在用,还是一些组件在用:

      1. 一个组件在用:放在组件本身即可。
      2. 一些组件在用:放在他们独特的父组件上(<span style=”color:red”> 状态晋升 </span>)。
      3. 实现交互:从绑定事件开始。
  2. props 实用于:

    1. 父组件 ==> 子组件 通信
    2. 子组件 ==> 父组件 通信(要求父先给子一个函数)
  3. 应用 v-model 时要切记:v-model 绑定的值不能是 props 传过来的值,因为 props 是不能够批改的!
  4. props 传过来的若是对象类型的值,批改对象中的属性时 Vue 不会报错,但不举荐这样做。

1.8 webStorage

1.8.1 应用阐明

  1. 存储内容大小个别反对 5MB 左右(不同浏览器可能还不一样)
  2. 浏览器端通过 Window.sessionStorageWindow.localStorage 属性来实现本地存储机制
  3. 相干 API:

    1. xxxxxStorage.setItem('key', 'value');
      该办法承受一个键和值作为参数,会把键值对增加到存储中,如果键名存在,则更新其对应的值
    2. xxxxxStorage.getItem('person');
      ​该办法承受一个键名作为参数,返回键名对应的值
    3. xxxxxStorage.removeItem('key');
      ​该办法承受一个键名作为参数,并把该键名从存储中删除
    4. xxxxxStorage.clear()

      该办法会清空存储中的所有数据

  4. 备注:

    1. SessionStorage 存储的内容会随着浏览器窗口敞开而隐没
    2. LocalStorage 存储的内容,须要手动革除才会隐没
    3. xxxxxStorage.getItem(xxx) 如果 xxx 对应的 value 获取不到,那么 getItem 的返回值是 null
    4. JSON.parse(null) 的后果仍然是 null

1.8.2 代码示例

LocalStorage

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>localStorage 浏览器本地存储 </title>
</head>
<body>
    <div>
        <h2>localStorage 浏览器本地存储 </h2>
        <button onclick="save()"> 点我保留一个数据 </button>
        <button onclick="read()"> 点我读取一个数据 </button>
        <button onclick="remove()"> 点我删除一个数据 </button>
        <button onclick="clearAll()"> 点我清空数据 </button>
    </div>

    <script type="text/javascript">
        let person = {name: "张三", age: 19}

        // localStorage 保留数据时最终都是 字符串
        function save() {
            // 保留字符串
            localStorage.setItem("name", "张三")
            // 保留数字
            localStorage.setItem("age", 18)
            // 保留对象数据
            // localStorage.setItem("person", person)
            localStorage.setItem("person", JSON.stringify(person))
        }

        function read() {
            // 读取字符串
            console.log(localStorage.getItem("name"))
            // 读取数字
            console.log(localStorage.getItem("age"))
            // 读取对象
            console.log(localStorage.getItem("person"))
            console.log(JSON.parse(localStorage.getItem("person")))
        }

        function remove() {
            // 删除字符串
            localStorage.removeItem("name")
            // 移除数字
            localStorage.removeItem("age")
            // 移除对象
            localStorage.removeItem("person")
        }

        function clearAll() {console.log("clear...");
            localStorage.clear()}
    </script>
</body>
</html>

SessionStorage

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>sessionStorage 浏览器本地存储 </title>
</head>
<body>
    <div>
        <h2>sessionStorage 浏览器本地存储 </h2>
        <button onclick="save()"> 点我保留一个数据 </button>
        <button onclick="read()"> 点我读取一个数据 </button>
        <button onclick="remove()"> 点我删除一个数据 </button>
        <button onclick="clearAll()"> 点我清空数据 </button>
    </div>

    <script type="text/javascript">
        let person = {name: "张三", age: 19}

        // sessionStorage 保留数据时最终都是 字符串
        function save() {
            // 保留字符串
            sessionStorage.setItem("name", "张三")
            // 保留数字
            sessionStorage.setItem("age", 18)
            // 保留对象数据
            // sessionStorage.setItem("person", person)
            sessionStorage.setItem("person", JSON.stringify(person))
        }

        function read() {
            // 读取字符串
            console.log(sessionStorage.getItem("name"))
            // 读取数字
            console.log(sessionStorage.getItem("age"))
            // 读取对象
            console.log(sessionStorage.getItem("person"))
            console.log(JSON.parse(sessionStorage.getItem("person")))
        }

        function remove() {
            // 删除字符串
            sessionStorage.removeItem("name")
            // 移除数字
            sessionStorage.removeItem("age")
            // 移除对象
            sessionStorage.removeItem("person")
        }

        function clearAll() {console.log("clear...");
            sessionStorage.clear()}
    </script>
</body>
</html>

1.9 组件的自定义事件

1.9.1 应用阐明

  1. 一种组件间通信的形式,实用于:子组件 ===> 父组件
  2. 应用场景:A 是父组件,B 是子组件,B 想给 A 传数据,那么就要在 A 中给 B 绑定自定义事件(<span style=”color:red”> 事件的回调在 A 中 </span>)。
  3. 绑定自定义事件:

    1. 第一种形式,在父组件中:<Demo @helloWorld="test"/><Demo v-on:helloWorld="test"/>
    2. 第二种形式,在父组件中:

      <Demo ref="demo"/>
      ......
      mounted(){this.$refs.xxx.$on('helloWorld', this.test)
      }
    3. 若想让自定义事件只能触发一次,能够应用 once 修饰符,或 $once 办法。
  4. 触发自定义事件:this.$emit('helloWorld', 数据)
  5. 解绑自定义事件this.$off('helloWorld')
  6. 组件上也能够绑定原生 DOM 事件,须要应用 native 修饰符。
  7. 留神:通过 this.$refs.xxx.$on('helloWorld', 回调) 绑定自定义事件时,回调 <span style=”color:red”> 要么配置在 methods 中 </span>,<span style=”color:red”> 要么用箭头函数 </span>,否则 this 指向会出问题!

1.9.2 代码示例

父组件 App

<template>
  <div id="app" class="app">
    <h1> 学校名称是:{{schoolName}}</h1>
    <h1> 学生姓名是:{{studentName}}</h1>

    <!-- 通过 props 来实现子组件给父组件传递数据 -->
    <School :getSchoolName="getSchoolName" />

    <!-- 第一种写法:通过父组件给子组件绑定一个自定义事件来实现子组件给父组件传递数据 应用 @ 或者 v-on -->
    <!-- <Student @getStudentName="getStudentName" /> -->
    
    <!-- 第二种写法:通过父组件给子组件绑定一个自定义事件来实现子组件给父组件传递数据 应用 ref-->
    <Student ref="student" />
    
    <!-- 通过父组件给子组件绑定一个自定义事件来实现子组件给父组件传递数据,只触发一次 -->
    <!-- <Student @getStudentName.once="getStudentName"/> -->
    <!-- <Student ref="student" /> -->
    
    <!-- 应用组件原生的办法 -->
    <!-- <Student @click.native="show" /> -->
    
    <!-- <Student @getStudentName="getStudentName" @getDemo="getDemo" /> -->
  </div>
</template>

<script>
import School from "./components/School.vue";
import Student from "./components/Student.vue";
export default {components: { School, Student},
  data() {
    return {
      schoolName: "",
      studentName: "",
    };
  },

  methods: {
    // 接管 School 子组件传递来的数据
    getSchoolName(name) {console.log("App 组件收到了学校名称", name);
      this.schoolName = name;
    },

    // 接管 Student 子组件传递来的数据
    getStudentName(name) {console.log("App 组件收到了学生姓名", name);
      this.studentName = name;
    },

    // 接管多个数据
    getDemo(...params) {console.log(...params);
    },

    show() {alert(123)
    }
  },

  mounted() {
    // 写法一
    this.$refs.student.$on("getStudentName", (name) => {
      // 一般函数写法 此时 this 是 VueComponent 实例 Student
      // 箭头函数写法 此时 this 是 vm 
      console.log(this,"@@@", name);
       this.studentName = name
    })
    // 写法二
    // this.$refs.student.$on("getStudentName", this.getStudentName)
    // this.$refs.student.$once("getStudentName", this.getStudentName)
  },
};
</script>

<style>
.app {
  background-color: gray;
  padding: 5px;
}
</style>

子组件 School

<template>
  <div class="school">
    <h2> 学校名称:{{name}}</h2>
    <h2> 学校地址:{{address}}</h2>
    <button @click="sendSchoolName"> 把学校名称给 App 组件 </button>
  </div>
</template>

<script>
export default {
  name: "School",
  props: ["getSchoolName"],
  data() {
    return {
      name: "北京大学",
      address: "北京",
    };
  },
  methods: {sendSchoolName() {this.getSchoolName(this.name);
    },
  },
};
</script>

<style>
.school {
  background-color: skyblue;
  padding: 5px;
}
</style>

子组件 Student

<template>
  <div class="student">
    <h2> 学生姓名: {{name}}</h2>
    <h2> 学生性别: {{sex}}</h2>
    <h2> 学生年龄: {{age}}</h2>
    <button @click="sendStudentName"> 把学生姓名给 App 组件 </button>
    <button @click="unbind"> 解绑自定义事件 </button>
    <button @click="death"> 销毁以后组件实例 </button>
  </div>
</template>

<script>
// 引入混入
export default {
  name: "Student",

  data() {
    return {
      name: "张三",
      sex: "男",
      age: 20,
    };
  },
  methods: {sendStudentName() {
      // 触发 student 组件实例的 getStudentName 事件
      this.$emit("getStudentName", this.name);
      this.$emit("getDemo", 1, 2, 3, 4);
    },
    // 解绑自定义事件
    unbind() {
      // 解绑一个自定义事件
      // this.$off("getStudentName");

      // 解绑多个自定义事件
      this.$off(["getStudentName", "getDemo"]);
    },
    // 销毁以后组件实例
    death() {
      // 销毁了以后 Student 组件的实例,销毁后所有 Student 实例的自定义事件全都不见效。this.$destroy()}
  },
};
</script>

<style lang="less" scoped>
.student {
  background-color: orange;
  padding: 5px;
  margin-top: 30px;
}
</style>

1.10 全局事件总线

1.10.1 应用阐明

  1. 一种组件间通信的形式,实用于 <span style=”color:red”> 任意组件间通信 </span>。
  2. 装置全局事件总线:

    new Vue({
        ......
        beforeCreate() {Vue.prototype.$bus = this // 装置全局事件总线,$bus 就是以后利用的 vm},
        ......
    }) 
  3. 应用事件总线:

    1. 接收数据:A 组件想接收数据,则在 A 组件中给 $bus 绑定自定义事件,事件的 <span style=”color:red”> 回调留在 A 组件本身。</span>

      methods(){demo(data){......}
      }
      ......
      mounted() {this.$bus.$on('xxxx',this.demo)
      }
    2. 提供数据:this.$bus.$emit('xxxx', 数据)
  4. 最好在 beforeDestroy 钩子中,用 $off 去解绑 <span style=”color:red”> 以后组件所用到的 </span> 事件。

1.10.2 代码示例

main.js 中装置全局事件总线

import Vue from 'vue'

import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  el: "#app",
  render: h => h(App),
  beforeCreate() {
    // 装置全局事件总线
    Vue.prototype.$bus = this
  }
})

在组件 School 中挂载全局事件

<template>
  <div class="demo">
    <h2> 学校名称:{{name}}</h2>
    <h2> 学校地址:{{address}}</h2>
  </div>
</template>

<script>
export default {
  name: "School",
  data() {
    return {
      name: "北大大学",
      address: "北京",
    };
  },
  methods: {},
  // 在组件挂载时绑定一个事件
  mounted() {this.$bus.$on("getStudentName", (data) => {
      // 此时 this 是 VueComponent 的实例 School
      console.log(this);
      console.log("School 组件收到了数据:", data);
    });
  },
  // 在组件销毁前解绑事件
  beforeDestroy() {this.$bus.$off("getStudentName")
  }
};
</script>

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

Student 组件中触发全局事件

<template>
  <div class="demo">
    <h2 class="title"> 学生姓名: {{name}}</h2>
    <h2> 学生性别: {{sex}}</h2>
    <h2> 学生年龄: {{age}}</h2>
    <button @click="sendStudentName"> 把学生名字给 School 组件 </button>
  </div>
</template>

<script>
// 引入混入
export default {
  name: "Student",

  data() {
    return {
      name: "张三",
      sex: "男",
      age: 20,
    };
  },
  methods: {sendStudentName() {
      // 触发事件
      this.$bus.$emit("getStudentName", this.name)
    }
  },
};
</script>

<!-- <style>
  .demo {background-color: orange;}
</style> -->
<!-- 不指定,默认应用 css -->
<!--  scoped: 示意款式只对指定的组件起作用 -->
<!-- <style scoped>
  .demo {background-color: orange;}
</style> -->

<!-- lang: 指定用什么款式  -->
<!-- less 须要引入 less-loader:npm install less-loader 指定版本:npm install [email protected] -->
<!-- npm view webpack versions 查看 webpack 版本命令,同理:-->
<style lang="less" scoped>
  .demo {
    background-color: orange;
    // less 与 css 的一个区别就是 less 能够叠加写,css 不能够
    .title {font-size: 40px;}
  }
</style>

1.11 音讯订阅与公布

1.11.1 阐明应用

  1. 一种组件间通信的形式,实用于 <span style=”color:red”> 任意组件间通信 </span>
  2. 它蕴含以下操作:

    1. 订阅音讯 – 对应绑定事件监听
    2. 公布音讯 – 散发事件
    3. 勾销音讯订阅 – 解绑事件监听
  3. PubSub.js

    1. 在线文档
    2. 装置:
    3. 相干语法:

      • import PubSub from 'pubsub-js' : 引入
      • PubSub.subscribe(‘msgName’, functon(msgName, data){}): 订阅
      • PubSub.publish(‘msgName’,data): 公布音讯,触发订阅的回调函数调用
      • PubSub.unsubscribe(token): 勾销音讯的订阅
  4. 应用步骤:

    1. 装置 pubsubnpm i pubsub-js
    2. 引入: import pubsub from 'pubsub-js'
    3. 接收数据:A 组件想接收数据,则在 A 组件中订阅音讯,订阅的 <span style=”color:red”> 回调留在 A 组件本身。</span>

      methods(){demo(data){......}
      }
      ......
      mounted() {this.pid = pubsub.subscribe('xxx',this.demo) // 订阅音讯
      }
    4. 提供数据:pubsub.publish('xxx', 数据)
    5. 最好在 beforeDestroy 钩子中,用 PubSub.unsubscribe(pid) 去 <span style=”color:red”> 勾销订阅。</span>

1.11.2 代码示例

School 组件订阅音讯

<template>
  <div class="demo">
    <h2> 学校名称:{{name}}</h2>
    <h2> 学校地址:{{address}}</h2>
  </div>
</template>

<script>
import pubsub from "pubsub-js";
export default {
  name: "School",
  data() {
    return {
      name: "北大大学",
      address: "北京",
    };
  },
  methods: {},
  mounted() {
    // 订阅音讯
    const pubId = pubsub.subscribe("sendStudentName", (messageName, data) => {
      // 箭头函数写法 此时 this 是 VueComponent 实例 School
      console.log(this);
      console.log(messageName, data);
    })
    // pubsub.subscribe("sendStudentName", function (messageName, data) {
    //   // 一般函数写法,此时 this undefined
    //   console.log(this);
    //   console.log(messageName, data);
    // });
  },
  beforeDestroy() {
    // 勾销订阅音讯
    // 勾销订阅音讯时要用 pubId 去勾销订阅
    pubsub.unsubscribe(this.pubId);
  },
};
</script>

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

Student 组件生产音讯

<template>
  <div class="demo">
    <h2 class="title"> 学生姓名: {{name}}</h2>
    <h2> 学生性别: {{sex}}</h2>
    <h2> 学生年龄: {{age}}</h2>
    <button @click="sendStudentName"> 把学生姓名给 School 组件 </button>
  </div>
</template>

<script>
// 引入音讯订阅
import pubsub from "pubsub-js";
export default {
  name: "Student",
  data() {
    return {
      name: "张三",
      sex: "男",
      age: 20,
    };
  },
  methods: {sendStudentName() {
      // 公布音讯
      // 第一个参数是音讯名
      pubsub.publish("sendStudentName", this.name);
    },
  },
};
</script>

<!-- <style>
  .demo {background-color: orange;}
</style> -->
<!-- 不指定,默认应用 css -->
<!--  scoped: 示意款式只对指定的组件起作用 -->
<!-- <style scoped>
  .demo {background-color: orange;}
</style> -->

<!-- lang: 指定用什么款式  -->
<!-- less 须要引入 less-loader:npm install less-loader 指定版本:npm install [email protected] -->
<!-- npm view webpack versions 查看 webpack 版本命令,同理:-->
<style lang="less" scoped>
.demo {
  background-color: orange;
  // less 与 css 的一个区别就是 less 能够叠加写,css 不能够
  .title {font-size: 40px;}
}
</style>

1.12 nextTick

  1. 语法:this.$nextTick(回调函数)
  2. 作用:在下一次 DOM 更新完结后执行其指定的回调
  3. 什么时候用:当扭转数据后,要基于更新后的新 DOM 进行某些操作时,要在 nextTick 所指定的回调函数中执行

    1.13 适度与动画

1.13.1 应用阐明

  1. 作用:在插入、更新或移除 DOM 元素时,在适合的时候给元素增加款式类名
  2. 写法:

    1. 筹备好款式:

      • 元素进入的款式:

        1. v-enter:进入的终点
        2. v-enter-active:进入过程中
        3. v-enter-to:进入的起点
      • 元素来到的款式:

        1. v-leave:来到的终点
        2. v-leave-active:来到过程中
        3. v-leave-to:来到的起点
    2. 应用 <transition> 包裹要适度的元素,并配置 name 属性:

      <transition name="hello">
          <h1 v-show="isShow"> 你好啊!</h1>
      </transition>
    3. 备注:若有多个元素须要适度,则须要应用:<transition-group>,且每个元素都要指定 key

1.13.2 代码示例

transition

<template>
  <div>
    <button @click="isShow = !isShow"> 显示 / 暗藏 </button>
    <!-- appear 示意页面一进来就进行动画成果 -->
    <transition name="hello" appear>
      <h1 v-show="isShow">Hello World</h1>
    </transition>
  </div>
</template>

<script>
export default {
  name: "Test1",
  data() {
    return {isShow: true,};
  },
};
</script>

<style scoped>
h1 {background-color: orange;}

.hello-enter-active {animation: helloWorld 0.5s linear;}

.hello-leave-active {animation: helloWorld 0.5s linear reverse;}

@keyframes helloWorld {
  from {transform: translateX(-100%);
  }
  to {transform: translateX(0px);
  }
}
</style>

transition-group

<template>
  <div>
    <button @click="isShow = !isShow"> 显示 / 暗藏 </button>
    <!-- appear 示意页面一进来就进行动画成果 -->
    <!-- transition-group 包裹一组标签,须要指定 key -->
    <transition-group name="hello" appear="">
      <h1 v-show="isShow" key="1">Hello</h1>
      <h1 v-show="isShow" key="2">World</h1>
    </transition-group>
  </div>
</template>

<script>
export default {
  name: "Test2",
  data() {
    return {isShow: true,};
  },
};
</script>

<style scoped>
h1 {background-color: skyblue;}

/* 进入的终点,来到的起点 */
.hello-enter,
.hello-leave-to {transform: translateX(-100%);
}

.hello-enter-active,
.hello-leave-active {transition: 0.5s linear;}

/* 来到的终点,进入的重点 */
.hello-leave,
.hello-enter-to {transform: translateX(0);
}
</style>

应用第三方动画库 Animate.css

<template>
  <div>
    <button @click="isShow = !isShow"> 显示 / 暗藏 </button>
    <!-- 应用第三方动画库 -->
    <transition-group
      appear
      name="animate__animated animate__bounce"
      enter-active-class="animate__swing"
      leave-active-class="animate__backOutUp"
    >
      <h1 v-show="isShow" key="1">Hello</h1>
      <h1 v-show="isShow" key="2">World</h1>
    </transition-group>
  </div>
</template>

<script>
// Animate.css 应用步骤
// 0. 官网地址:https://animate.style/
// 1. 装置:npm install animate.css --save
// 2. 引入:import "animate.css";

import "animate.css";
export default {
  name: "Test3",
  data() {
    return {isShow: true,};
  },
};
</script>

<style scoped>
h1 {background-color: orange;}
</style>

1.14 插槽

1.14.1 应用阐明

  1. 作用:让父组件能够向子组件指定地位插入 html 构造,也是一种组件间通信的形式,实用于 父组件 ===> 子组件
  2. 分类:默认插槽、具名插槽、作用域插槽

    1.14.2 默认插槽

    父组件

<Category>
    <div>html 构造 1 </div>
</Category>

子组件

<template>
    <div>
        <!-- 定义插槽 -->
        <slot> 插槽默认内容...</slot>
    </div>
</template>

1.14.3 具名插槽

父组件中

<Category>
    <template slot="center">
        <div>html 构造 1 </div>
    </template>

    <template v-slot:footer>
        <div>html 构造 2 </div>
    </template>
</Category>

子组件中

<template>
    <div>
        <!-- 定义插槽 -->
        <slot name="center"> 插槽默认内容...</slot>
        <slot name="footer"> 插槽默认内容...</slot>
    </div>
</template>

1.14.4 作用域插槽

  1. 了解:<span style=”color:red”> 数据在组件的本身,但依据数据生成的构造须要组件的使用者来决定。</span>(games 数据在 Category 组件中,但应用数据所遍历进去的构造由 App 组件决定)
  2. 具体编码:

    父组件中

    <Category>
        <template scope="scopeData">
            <!-- 生成的是 ul 列表 -->
            <ul>
                <li v-for="g in scopeData.games" :key="g">{{g}}</li>
            </ul>
        </template>
    </Category>
    
    <Category>
        <template slot-scope="scopeData">
            <!-- 生成的是 h4 题目 -->
            <h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
        </template>
    </Category>

    子组件

    <template>
        <div>
            <slot :games="games"></slot>
        </div>
    </template>
    
    <script>
        export default {
            name:'Category',
            props:['title'],
            // 数据在子组件本身
            data() {
                return {games:['红色警戒','穿梭前线','劲舞团','超级玛丽']
                }
            },
        }
    </script>
退出移动版