文章目录

  • 一、Vue
    • 1.1 Vue介绍
    • 1.2 Vue特点
    • 1.3 Vue周边库
  • 二、初始Vue
    • 2.1 插值语法
    • 2.2 指令语法
      • 2.2.1 v:bind / 简写 : 指令 单向数据绑定
      • 2.2.2 v-model 双向数据绑定
    • 2.3 事件处理
    • 2.4 事件修饰符
    • 2.5 键盘事件
    • 2.6 计算属性
    • 2.7 监听属性
    • 2.8 计算属性与监听属性之间的区别
    • 2.9 条件渲染
    • 2.10 条件渲染
    • 2.11 收集表单数据的细节
    • 2.12 内置指令
      • 2.12.1 v-text
      • 2.12.2 v-html
      • 2.12.3 v-once
    • 2.12.4 v-pre
    • 2.13 Vue生命周期
      • 2.13.1 什么是生命周期
      • 2.13.2 声明周期总结
  • 三、Vue组件化编程
    • 3.1组件的理解
    • 3.2 非单文件组件
    • 3.3 组件的基本实用(以后基本不会使用)
    • 3.4 VueComponent
    • 3.5 模块化的三种暴露方式
  • 四、安装vue-cli
    • 4.1 步骤
    • 4.2 文件结构
    • 4.3 ref属性
    • 4.4 props属性
    • 4.5 mixin属性
    • 4.6 插件
    • 4.7 scoped样式
    • 4.8 组件自定义事件
    • 4.9 解绑自定义事件
    • 4.10 全局事件总线(开发中用的较多)
    • 4.11 Vue过度动画
      • 4.11.1 继承第三方动画库
  • 五、Axios
    • 5.1 使用axios
    • 5.2 Vue脚手架配置代理
    • 5.3 插槽
  • 六、Vuex
    • 6.1概念
    • 6.2 搭建Vuex环境
    • 6.3 基本使用
    • 6.5 getters
  • 七、路由
    • 7.1 基本使用
    • 7.2 多级路由(覆盖路由)
    • 7.3 路由的query参数
    • 7.4 命名路由
    • 7.5 路由的params参数(RestFul风格)
    • 7.7 路由的props配置
    • 7.8 编程式路由导航
    • 7.9 缓存路由组件
    • 7.10 两个新的生命周期钩子
    • 7.11 路由守卫
      • 7.11.1 全局加守卫
      • 7.11.2 独享守卫
      • 7.11.3 组件守卫
    • 7.12 路由的两种工作模式
  • 8、Element-UI组件库

提示:以下是本篇文章正文内容,下面案例可供参考

一、Vue

1.1 Vue介绍

  • Vue官网
  • 动态构建用户界面的渐进式 JavaScript 框架
  • 作者: 尤雨溪

1.2 Vue特点

  • 遵循 MVVM 模式
  • 编码简洁, 体积小, 运行效率高, 适合移动/PC 端开发
  • 它本身只关注 UI, 也可以引入其它第三方库开发项目

1.3 Vue周边库

  • vue-cli: vue 脚手架
  • vue-resource
  • axios
  • vue-router: 路由
  • vuex: 状态管理
  • element-ui: 基于 vue 的 UI 组件库(PC 端)

二、初始Vue

2.1 插值语法

  • 功能: 用于解析标签体内容
  • 语法: {{xxx}} ,xxxx 会作为 js 表达式解析
<!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>Document</title><script src="js/vue.js"></script>
</head>
<body><!-- 创建一个存放vue数据的容器 --><div id="root"><!-- {{xxx}}  可以直接获取vue实例中data里相对应的数据 -->{{name}} </div><script>// 创建一个vue实例对象let x=new Vue({//对应的容器id,也可以是类选择器el:"#root",//存放的数据  data:{name:"zhangsan",url:"www.baidu.com",}});</script>
</body>
</html>

2.2 指令语法

2.2.1 v:bind / 简写 : 指令 单向数据绑定

  • 功能: 解析标签属性、解析标签体内容、绑定事件
  • 举例:v-bind:href = ‘xxxx’ ,xxxx 会作为 js 表达式被解析 xxx为数字时,不会被当做String类型解析
  • 说明:Vue 中有有很多的指令,此处只是用 v-bind 举个例子
<!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>Document</title><script src="js/vue.js"></script>
</head>
<body><!-- 创建一个存放vue数据的容器 --><div id="root"><a v-bind:href="url">跳转页面(会获取实例中data里面的url数据)</a></div><script>// 创建一个vue实例对象let x=new Vue({//对应的容器id,也可以是类选择器el:"#root",//存放的数据  data:{name:"zhangsan",url:"www.baidu.com",}});</script>
</body>
</html>

2.2.2 v-model 双向数据绑定

  • 语法:v-mode:value=“xxx” 或简写为 v-model=“xxx”
  • 特点:数据不仅能从 data 流向页面,还能从页面流向 data
  • 备注:v-model:value可以简写为v-model,因为v-model默认收集的就是value值
  • 注意:v-model只能应用在表单类元素(输入类元素 input,select 等)
 <input type="text" v-model:value="name">

2.3 事件处理

语法:v-on:xxx 或 @xxx 绑定事件,十中xxx是事件名 例: v-on:click 单击事件

<!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>Document</title><script src="js/vue.js"></script>
</head>
<body><!-- 创建一个存放vue数据的容器 --><!-- 事件绑定的两种方法 --><span id="cli" v-on:click="showInfo">点我</span><span @click="showInfo($event,66)">点我</span></div><script>// 创建一个vue实例对象let x=new Vue({//对应的容器id,也可以是类选择器el:"#root",//存放的数据  data:{name:"zhangsan",url:"www.baidu.com",},methods: {showInfo(){alert(1);},showInfo(event,number){console.log(event,number);}},});</script>
</body>
</html>

2.4 事件修饰符

  • 加在事件处理的后面 以 . 开始 加
 1. prevent:阻止默认事件(常用)<a href="www.baidu.com" @click.prevent="showInfo($event,66)">点我阻止默认事件</a>2. stop:阻止事件冒泡(常用)3. once:事件只触发一次(常用)

2.5 键盘事件

  • Vue中常用的按键别名 @keyup.xxx=“方法名”/@keydown.xxx=“方法名” xxx代表下面的按键别名
 1. 回车=> enter2. 删除=> delete(捕获“删除”和“退格”键)3. 退出=> esc4. 空格=> space5. 换行=> tab(特殊,必须配合@keydown使用)6. 上=> up7. 下=> down8. 左=> left9. 右=>right
  • 使用按键别名
<!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>Document</title><script src="js/vue.js"></script>
</head>
<body><!-- 创建一个存放vue数据的容器 --><div id="root" v-bind:href="url">键盘事件:<input type="text" @keyup.enter="keycode"></div><script>// 创建一个vue实例对象let x=new Vue({//对应的容器id,也可以是类选择器el:"#root",//存放的数据  data:{name:"zhangsan",url:"www.baidu.com",},methods: {keycode(e){//打印文本的值console.log(e.target.value);}},});</script>
</body>
</html>

2.6 计算属性

 计算属性:1. 定义:要用的属性不存在,要通过已有属性计算得来2. 原理:底层借助了Object.defineproperty方法提供的getter和setter3. get函数什么时候执行?(1). 初次读取时会执行一次(2). 当依赖的数据发生改变时会被再次调用。4. 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。5. 备注:(1). 计算属性最终会出现在vm上,直接读取使用即可。(2). 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
<!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>Document</title><script src="js/vue.js"></script>
</head>
<body><div id="root">firstName:<input type="text" v-model="firstName"><br>lastName:<input type="text" v-model="lastName"><br>全名:<span> {{fullName}} </span></div><script>new Vue({el:"#root",data:{firstName:"张",lastName:"三",},computed: {// 直接当做普通属性调用不加括号// 任何data中数据变化立即重新计算// 计算属性会缓存fullName:{//get有什么用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值//get什么时候用? 1.初次读取fullName时候。 2.所依赖的数据发生变化时。get(){return this.firstName+"-"+this.lastName;}set(value){console.log(属性被修改);const arr=value.split["-"];this.firstName=arr[0];this.lastName=arr[1];}}},})</script>
</body>
</html>
  • 计算属性简写:只考虑展示数据,不考虑修改数据时,可以使用
<body><div id="root">firstName:<input type="text" v-model="firstName"><br>lastName:<input type="text" v-model="lastName"><br>全名:<span> {{fullName}} </span></div><script>new Vue({el:"#root",data:{firstName:"张",lastName:"三",},computed: {// 直接当做普通属性调用不加括号// 任何data中数据变化立即重新计算// 计算属性会缓存// fullName:{//     //get有什么用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值//     //get什么时候用? 1.初次读取fullName时候。 2.所依赖的数据发生变化时。//     get(){//         return this.firstName+"-"+this.lastName;//     },//     set(value){//         console.log(属性被修改);//         const arr=value.split["-"];//         this.firstName=arr[0];//         this.lastName=arr[1];//     }// },//上面fullName的简写 可以直接写要展示的方法即可fullName(){return this.firstName+"-"+this.lastName;}},})</script>
</body>

2.7 监听属性

<script>new Vue({el: "#root",data: {firstName: "张",lastName: "三",},watch: {//语法/** 1.*  要监视的对象:{*      handler(newVal,oldVal){*          *      }*  }*  2.*  要监视的对象:(newVal,oldVal)->{*      业务*  }**/firstName: (newVal, oldVal) => {console.log(newVal, oldVal);},lastName: {immediate:true, //初始化时让handler调用一下handler(newVal, oldVal) {console.log(newVal, oldVal);}},//监测属性 简写firstName(newVal, oldVal){console.log(newVal, oldVal);}},})</script>

2.8 计算属性与监听属性之间的区别

  • computed和watch的区别
 1. computed能完成的功能,watch都可以完成。2. watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
  • 两个重要的小原则:
 1. 所被Vue管理的函数,最好写成普通函数,这样this的指向才是 vm 或 组件实例对象2. 所有不被Vue管理的函数(定时器回调函数,ajax的回调函数,Promise的回调函数),最好写成箭头函数,这样this的指向才是 vm 或 组件实例对象

2.9 条件渲染

<!-- v-show做条件渲染:true显示标签,false给标签加上display:none隐藏标签 --><a href="#" v-show="true">超链接</a><a href="#" v-show="false">超链接</a><!-- v-if做条件渲染:true显示标签,false给标签删除 --><a href="#" v-if="true">超链接</a><a href="#" v-if="false">超链接</a>

2.10 条件渲染

<body><div id="root"><ul><!-- 需要遍历哪个标签,v-for遍历就加在哪个标签身上  --><!-- key放在虚拟DOM中进行diff算法运行时用到,key最好使用数据中的唯一表示,防止出现意想不到的BUG)--><!-- 若不写key,默认是采用index索引值当做key--><li v-for="(person,index) in persons" :key="person.id">{{person.name}}--{{person.age}}-{{index}}--{{person.id}}</li></ul></div><script>new Vue({el:"#root",data:{persons:[{id:"001",name:"张三",age:16},{id:"002",name:"李四",age:17},{id:"003",name:"王五",age:18},]}})</script>
</body>

2.11 收集表单数据的细节

<!-- 收集表单数据:若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。若:<input type="checkbox"/>1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)2.配置input的value属性:(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)(2)v-model的初始值是数组,那么收集的的就是value组成的数组备注:v-model的三个修饰符:lazy:失去焦点再收集数据number:输入字符串转为有效的数字trim:输入首尾空格过滤-->
 <body><!-- 收集表单数据:若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。若:<input type="checkbox"/>1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)2.配置input的value属性:(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)(2)v-model的初始值是数组,那么收集的的就是value组成的数组备注:v-model的三个修饰符:lazy:失去焦点再收集数据number:输入字符串转为有效的数字trim:输入首尾空格过滤--><!-- 准备好一个容器--><div id="root"><form @submit.prevent="demo">账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/>密码:<input type="password" v-model="userInfo.password"> <br/><br/>年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/>性别:男<input type="radio" name="sex" v-model="userInfo.sex" value="male">女<input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br/><br/>爱好:学习<input type="checkbox" v-model="userInfo.hobby" value="study">打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat"><br/><br/>所属校区<select v-model="userInfo.city"><option value="">请选择校区</option><option value="beijing">北京</option><option value="shanghai">上海</option><option value="shenzhen">深圳</option><option value="wuhan">武汉</option></select><br/><br/>其他信息:<textarea v-model.lazy="userInfo.other"></textarea> <br/><br/><input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.baidu.com">《用户协议》</a><button>提交</button></form></div></body><script type="text/javascript">Vue.config.productionTip = falsenew Vue({el:'#root',data:{userInfo:{account:'',password:'',age:18,sex:'female',hobby:[],city:'beijing',other:'',agree:''}},methods: {demo(){console.log(JSON.stringify(this.userInfo))}}})</script>

2.12 内置指令

2.12.1 v-text

  • 向其所在的标签插入文本
v-text指令:1.作用:向其所在的节点中渲染文本内容。2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
<!-- 准备好一个容器--><div id="root"><div>你好,{{name}}</div><div v-text="name"></div><div v-text="str"></div></div>

2.12.2 v-html

<!-- v-html指令:1.作用:向指定节点中渲染包含html结构的内容。2.与插值语法的区别:(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。(2).v-html可以识别html结构。3.严重注意:v-html有安全性问题!!!!(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!--><!-- 准备好一个容器--><div id="root"><div>你好,{{name}}</div><div v-html="str"></div><div v-html="str2"></div></div>

2.12.3 v-once

<body><!-- v-once指令:1.v-once所在节点在初次动态渲染后,就视为静态内容了。2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。--><!-- 准备好一个容器--><div id="root"><h2 v-once>初始化的n值是:{{n}}</h2><h2>当前的n值是:{{n}}</h2><button @click="n++">点我n+1</button></div></body><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。new Vue({el:'#root',data:{n:1}})</script>

2.12.4 v-pre

<body><!-- v-pre指令:1.跳过其所在节点的编译过程。2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。--><!-- 准备好一个容器--><div id="root"><h2 v-pre>Vue其实很简单</h2><h2 >当前的n值是:{{n}}</h2><button @click="n++">点我n+1</button></div></body><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。new Vue({el:'#root',data:{n:1}})</script>

2.13 Vue生命周期

2.13.1 什么是生命周期

             生命周期:1.又名:生命周期回调函数、生命周期函数、生命周期钩子。2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。4.生命周期函数中的this指向是vm 或 组件实例对象。
  • 演示
 <body><!-- 生命周期:1.又名:生命周期回调函数、生命周期函数、生命周期钩子。2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。4.生命周期函数中的this指向是vm 或 组件实例对象。--><!-- 准备好一个容器--><div id="root"><h2 v-if="a">你好啊</h2><h2 :style="{opacity}">欢迎学习Vue</h2></div></body><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。new Vue({el:'#root',data:{a:false,opacity:1},methods: {},//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mountedmounted(){console.log('mounted',this)setInterval(() => {this.opacity -= 0.01if(this.opacity <= 0) this.opacity = 1},16)},})//通过外部的定时器实现(不推荐)/* setInterval(() => {vm.opacity -= 0.01if(vm.opacity <= 0) vm.opacity = 1},16) */</script>
</html>
  • 借鉴声明周期图

2.13.2 声明周期总结

常用的生命周期钩子:1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。关于销毁Vue实例1.销毁后借助Vue开发者工具看不到任何信息。2.销毁后自定义事件会失效,但原生DOM事件依然有效。3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。

三、Vue组件化编程

3.1组件的理解

  • 组件的定义:实现应用中局部功能代码和资源的集合

3.2 非单文件组件

  • 一个文件中包含n个组件

3.3 组件的基本实用(以后基本不会使用)

Vue中使用组件的三大步骤:一、定义组件(创建组件)二、注册组件三、使用组件(写组件标签)一、如何定义一个组件?使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;区别如下:1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。备注:使用template可以配置组件结构。二、如何注册组件?1.局部注册:靠new Vue的时候传入components选项2.全局注册:靠Vue.component('组件名',组件)三、编写组件标签:<school></school>
  • 演示
<body><div id="root"><!-- 第三步:编写组件标签 --><student></student><hr></div><script>//第一步:创建school组件const student=Vue.extend({template:`<div><h2>{{student}}</h2>    <h2>{{major}}</h2>    </div>`,// el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。data(){return {student:"安阳工学院",major:"计算机",}},})//第二步:全局注册组件Vue.component('student',student)new Vue({el:"#root",//第二步:注册组件(局部注册)components:{student:student,}})</script>
</body>

3.4 VueComponent

关于VueComponent:1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。2.我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)。3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!4.关于this指向:(1).组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。(2).new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。

3.5 模块化的三种暴露方式

  • 模块化三种暴露方式
  1. 分别暴露
<script>
// 组件交换相关的代码(数据、方法等)export const student=Vue.extend({data(){return {student:"安阳工学院",major:"计算机",}},})
</script>
  1. 同意暴露
<script>
// 组件交换相关的代码(数据、方法等)const student=Vue.extend({data(){return {student:"安阳工学院",major:"计算机",}},})export {school}
</script>
  1. 默认暴露(用的较多)
<script>
// 组件交换相关的代码(数据、方法等)export default {name:"和当前vue组件的文件名同步"data(){return {student:"安阳工学院",major:"计算机",}},}export default school
</script>

四、安装vue-cli

  • 安装 vue-cli之前先安装node

4.1 步骤

  • 使用cmd 管理员
 1. 配置npm淘宝镜像 防止下载过慢npm config set registry https://registry.npm.taobao.org2.  全局安装@Vue/clinpm install -g @vue/cli3. 创建项目vue create 项目名创建vue2项目要使用 npm 4. 启动项目npm run serve

4.2 文件结构

4.3 ref属性

 1. 被用来给元素或子组件注册引用信息(id的替代者)2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(VueComponent)3. 使用方式打标识: <h1 ref="xxx"></h1> 或 <School ref="xxx"></School>获取:this.$refs.xxx

4.4 props属性

  • 当别人要用我们的组件,数据不一样时,我们就不能把当前组件的数据写死,我们需要让调用者给我们这个组件的标签 传入参数
  • 传入参数
<template><div>//动态传入参数<Student name="张三" :age="16"></Student><div v-text="msg"></div><button>点我输出</button></div>
</template><script>
import Student from "./components/Student.vue";
export default {data() {return {msg: "欢迎学习Vue",}},components: {Student,},};
</script>
  • 定义props 接收参数
<template><div><h2>姓名:{{name}}</h2><h2>年龄:{{age}}</h2></div>
</template><script>
export default {name:"Student",data() {return {// name:"法外狂徒-张三",// age:16,}},//简单声明接收props:["name","age"],//接收的同时对数据进行类型的限制props:{name:String,age:Number,},//接收的同时对数据:进行类型限制+默认值指定+必要性的限制props:{name:{type:String,//name的类型required:true,//name是必须要传的},age:{type:Number,//age的类型default:22,//age如果不传,默认值是22}}
}
</script>
  • 备注:
 props是只读的,Vue底层会检测你对props的修改,如果进行了修改,就会发出警告。若业务需要确实需要修改,那么请赋值props的内容到data中一份,然后去修改data中的数据。

4.5 mixin属性

  • mixin(混入)
 功能:可以把多个组件共用的配置提取成一个混入对象使用方式:第一步定义混合,例如:export default {data(){...},methods:{...},...}第二步使用混入,例如:1. 全局混入:Vue.mixin(xxx)2. 局部混入:mixins:[xxx]

4.6 插件

  • 功能:用于增强Vue
  • 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
 定义插件:export default{install(Vue){插件,插件,...}}使用插件:引入插件:import plugins from "插件的js文件"应用插件:Vue.use(plugins)

4.7 scoped样式

  • 作用:让样式在局部(每个组件中)生效,防止冲突
  • 写法:

4.8 组件自定义事件

  1. 一种组件之间的通信方式,适用于 子组件===>父组件
  • 写法1:
  1. 组件Student.vue
<template><div><h2>姓名:{{name}}</h2><h2>年龄:{{age}}</h2><button @click="sendStudentName">触发mk事件</button></div>
</template><script>
export default {name:"Student",data() {return {name:"法外狂徒-张三",age:16,}},methods:{sendStudentName(){//触发Student组件实例对象身上的mk事件this.$emit("mk",this.name);}}
}
</script><style>
</style>
  1. App.vue
<template><div>//自定义组件 名称 mk 当触发了mk事件 调用 demo方法<Student v-on:mk="demo"></Student><div v-text="msg"></div></div>
</template><script>
import Student from "./components/Student.vue";
export default {data() {return {msg: "欢迎学习Vue",}},methods:{demo(name){console.log("demo方法被调用了",name);}},components: {Student,},};
</script>
  • 写法2:
  1. 组件Student.vue
<template><div><h2>姓名:{{name}}</h2><h2>年龄:{{age}}</h2><button @click="sendStudentName">触发t1事件</button></div>
</template><script>
export default {name:"Student",data() {return {name:"法外狂徒-张三",age:16,}},methods:{sendStudentName(){//触发Student组件实例对象身上的mk事件this.$emit("t1",this.name);}}
}
</script>
  1. App.vue
<template><div><Student ref="t1"></Student><div v-text="msg"></div></div>
</template><script>
import Student from "./components/Student.vue";
export default {data() {return {msg: "欢迎学习Vue",}},methods:{demo(name){console.log("demo方法被调用了");}},//当App.vue中的数据创建好后,会触发mounted方法执行mounted() {//this.$refs.mk会拿到mk的这个组件实例对象//给mk这个组件实例对象绑定 自定义事件t1,当t1这个自定义事件被触发调用 demo方法this.$refs.mk.$on("t1",this.demo);},components: {Student,},};
</script>

4.9 解绑自定义事件

  • 组件Student.vue 解绑自定义事件
<script>
export default {name:"Student",data() {return {name:"法外狂徒-张三",age:16,}},methods:{sendStudentName(){//触发Student组件实例对象身上的mk事件this.$emit("t1",this.name);this.$emit("t2",this.age);},unbind(){this.$off("t1");//解绑一个自定义事件this.$off(["t1","t2"]);//解绑多个自定义事件this.$off();//解绑所有自定义事件}}
}
</script>
  • App.vue
<script>
import Student from "./components/Student.vue";
export default {data() {return {msg: "欢迎学习Vue",}},methods:{demo(name){console.log("demo方法被调用了");},t2(age){console.log(age);}},//当App.vue中的数据创建好后,会触发mounted方法执行mounted() {//this.$refs.mk会拿到mk的这个组件实例对象//给mk这个组件实例对象绑定 自定义事件t1,当t1这个自定义事件被触发调用 demo方法this.$refs.mk.$on("t1",this.demo);this.$refs.mk.$on("t2",this.t2);},components: {Student,},};
</script>

4.10 全局事件总线(开发中用的较多)

  • 全局时间总线:任意组件之间的通信
  1. 安装全局事件总线 main.js
//引入Vue
import Vue from "vue"
import App from './App.vue'
//关闭生产提示
Vue.config.productionTip=false
new Vue({//将App组件放入到容器中render:h=>h(App),beforeCreate() {Vue.prototype.$bus=this;//安装全局事件总线,this指的是当前应用的vm},
}).$mount("#app")
  1. 使用全局事件总线:A想接受数据
export default {data() {return {msg: "欢迎学习Vue",}},methods:{demo(name){console.log("demo方法被调用了");},t2(age){console.log(age);},t3(data){console.log("全局事件总线===>",data);}},//当App.vue中的数据创建好后,会触发mounted方法执行mounted() {//给$bus这个全局事件总线绑定 自定义事件hello,当hello这个自定义事件被触发调用 this.t3方法this.$bus.$on("hello",this.t3);},components: {Student,},};
  1. 使用全局事件总线:
export default {name:"Student",data() {return {name:"法外狂徒-张三",age:16,}},methods:{sendStudentName(){//触发全局事件总线身上的hello事件,给hello的回调方法传参this.$bus.$emit("hello",this.name);},beforeDestroy(){//最好用beforeDestory钩子中,用$off("事件名")去解绑当前组件所用到的事件this.$bus.$off("hello");}}
}

4.11 Vue过度动画

<template><div><button @click="isShow = !isShow">显示/隐藏</button><!-- Vue内置动画标签,把动画放入即可appear:打开浏览器动画从无到有name:若给name赋予了名字,那么Vue定义的动画类名 必须写为: xxx-enter/leave-active--><transition name="xxx" appear>   <h1 v-show="isShow" >你好啊</h1></transition></div>
</template><script>
export default {name:"Test",data() {return {isShow:true,}},
}
</script><style>h1{background-color: orange;}/* Vue定义的动画起始类名 */.v-enter-active{animation: ani 1s;}/* Vue定义的动画反转类名 */.v-leave-active{animation: ani 1s reverse;}/* 定义一个动画 */@keyframes ani {from{transform: translateX(-100%);}to{transform: translateX(0px);}}
</style>

4.11.1 继承第三方动画库

animate第三方动画库官网

  • 使用
 0. 下载animate.cssnpm install animate.css --save1. 引入animate.css文件import 'animate.css'2. 在Vue动画标签上的name属性写入动画库指定的名称name="animate__animated animate__bounce"3. 在Vue动画标签上写入进场动画类名和退场动画类名enter-active-class="进场效果" leave-active-class="退场效果"4. 效果去官方获取想要的写入类名即可
  • 测试
<template><div><button @click="isShow = !isShow">显示/隐藏</button><!-- Vue内置动画标签,把动画放入即可appear:打开浏览器动画从无到有name:若给name赋予了名字,那么Vue定义的动画类名 必须写为: xxx-enter/leave-active--><transition name="animate__animated animate__bounce" enter-active-class="animate__bounce" leave-active-class="animate__backOutUp" appear>   <h1 v-show="isShow"  >你好啊</h1></transition></div>
</template><script>
import 'animate.css'
export default {name:"Test",data() {return {isShow:true,}},
}
</script><style>h1{background-color: orange;}
</style>

五、Axios

5.1 使用axios

  1. 下载axios
 npm i axios
  1. 引用axios
 import axios from 'axios'

5.2 Vue脚手架配置代理

  • 解决跨域问题
  1. 方法一: 在vue.config.js中添加如下配置
//配置代理对象
devServer: {proxy: 'http://localhost:后端端口号'}
  • 说明:

    1. 优点:配置简单,请求资源时直接发给前端(8080)即可
    2. 缺点:不能配置多个代理,不能灵活控制请求是否走代理
    3. 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器(有限匹配前端资源)
  1. 方法二
module.exports = {devServer: {proxy: {'/api1': {// 匹配所有以 '/api1'开头的请求路径target: 'http://localhost:5000',// 代理目标的基础路径changeOrigin: true,pathRewrite: {'^/api1': ''}//把以api1开头的路径去掉发送给target路径},'/api2': {// 匹配所有以 '/api2'开头的请求路径target: 'http://localhost:5001',// 代理目标的基础路径changeOrigin: true,pathRewrite: {'^/api2': ''}}}}
}
/*changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080changeOrigin默认值为true
*/
  • 前台发送请求
export default {methods: {getStu(){axios.get("http://localhost:8080/api1/students").then(response=>{console.log("请求成功了",response,response.data);},error=>{console.log("请求失败了",error,error.message);})}},};

说明:

  1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
  2. 缺点:配置略微繁琐,请求资源时必须加前缀。

5.3 插槽

  • 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件 。
  • 分类:默认插槽、具名插槽、作用域插槽
  1. 默认插槽
父组件中:<Student><div>html结构1</div></Student>
子组件中:<template><div><!-- 定义插槽 --><slot>插槽默认内容...</slot></div></template>
  1. 具名插槽
父组件中:<Student><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. 作用域插槽
  • 理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(数据在Stu组件中,但使用数据遍历出来的解构由App主组件决定)
父组件中:<Stu>//scope中定义的变量名就是子组件中定义的games所有数据(名字不强制要求可以随意)<template scope="scopeData"><!-- 生成的是ul列表 --><ul><li v-for="g in scopeData.games" :key="g">{{g}}</li></ul></template></Stu><Stu><template slot-scope="scopeData"><!-- 生成的是h4标题 --><h4 v-for="g in scopeData.games" :key="g">{{g}}</h4></template></Stu>
子组件中:<template><div><slot :games="games"></slot></div></template><script>export default {name:'Stu',props:['title'],//数据在子组件自身data() {return {games:['红色警戒','穿越火线','劲舞团','超级玛丽']}},}</script>

六、Vuex

6.1概念

  • 在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
  • 何时使用? 多个组件需要共享数据时

6.2 搭建Vuex环境

  1. 创建文件:src/store/index.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)//准备actions对象——响应组件中用户的动作
const actions = {}
//准备mutations对象——修改state中的数据
const mutations = {}
//准备state对象——保存具体的数据
const state = {}//创建并暴露store
export default new Vuex.Store({actions,mutations,state
})
  1. main.js中创建vm时传入store配置项
......
//引入store
import store from './store/index.js'
......//创建vm
new Vue({el:'#app',render: h => h(App),store
})

6.3 基本使用

  1. 初始化数据、配置actions、配置mutations,操作文件store.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//引用Vuex
Vue.use(Vuex)const actions = {//响应组件中加的动作jia(context,value){// console.log('actions中的jia被调用了',miniStore,value)context.commit('JIA',value)},
}const mutations = {//执行加JIA(state,value){// console.log('mutations中的JIA被调用了',state,value)state.sum += value}
}//初始化数据
const state = {sum:0
}//创建并暴露store
export default new Vuex.Store({actions,mutations,state,
})
  1. 组件中读取vuex中的数据:$store.state.sum
  2. 组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)$store.commit('mutations中的方法名',数据)
  3. 备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

6.5 getters

  • 概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。
  • store/index.js中追加getters配置
const getters = {bigSum(state){return state.sum * 10}
}//创建并暴露store
export default new Vuex.Store({......getters
})

七、路由

  • 理解: 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。
  • 前端路由:key是路径,value是组件。 当访问key路径时,指定的位置会展示指定的组件
    注意点

    1. 路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。
    2. 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
    3. 每个组件都有自己的$route属性,里面存储着自己的路由信息。
    4. 整个应用只有一个router,可以通过组件的$router属性获取到。

7.1 基本使用

  1. 安装vue-router路由命令: npm i vue-router
  2. 应用插件:Vue.use(引入路由的自定义名称)
  3. 编写route配置:在src下创建index.js配置路由 src/index.js
//该文件专门用于创建整个应用的路由器
//引入VueRouter
import VueRouter from 'vue-router'
//引入Luyou 组件
import About from '../components/About'
import Home from '../components/Home'//创建router实例对象,去管理一组一组的路由规则
export default new VueRouter({routes:[{path:'/about',component:About},{path:'/home',component:Home}]
})
  1. 实现切换(active-class可配置高亮样式)
<router-link active-class="active" to="/home(路由中配置的路径)">About</router-link>
  1. 指定展示位置
 <router-view></router-view>

7.2 多级路由(覆盖路由)

  • 在一个路由规则中再定义路由
  1. 配置路由规则,使用children配置项:
//创建一个路由器
export default new VueRouter({//路由routes:[{path:'/about',component:About,},{path:'/home',component:Home,       //配置子级路由children:[{//此处不要加 /path:"news",component:News,},{path:"message",component:Message,}]},]
})
  1. 跳转(要写完整路径):
<router-link to="/home/news">News</router-link>

7.3 路由的query参数

  • 当我们利用router路由发送请求时,可以携带一些参数进行传递
  1. 传递参数
<template><div><ul><!-- 跳转并携带query参数,to的字符串写法 --><li v-for="data in DataList" :key="data.id"><router-link :to="`/home/message/detail?id=${data.id}&title=${data.title}`">{{data.title}}</router-link></li><li v-for="data in DataList" :key="data.id"><router-link :to="{path:'/home/message/detail',query:{id:data.id,title:data.title,}}">{{data.title}}</router-link></li></ul><hr><router-view></router-view></div></template><script>
export default {name:"Message",data() {return {DataList:[{id:"001",title:"message001"},{id:'002',title:"message002"},{id:'003',title:"message003"},]}},
};
</script>
  1. 接收参数
<template><ul><li>消息编号:{{$route.query.id}}</li><li>消息详情:{{$route.query.title}}</li></ul>
</template>
$route.query.id
$route.query.title

7.4 命名路由

  1. 作用可以简化路由的跳转。
  2. 如何使用?
    2.1 给路由命名
//创建一个路由器
export default new VueRouter({//路由routes:[{path:'/about',component:About,},{path:'/home',component:Home,       //配置子级路由children:[{//此处不要加 /path:"news",component:News,},{path:"message",component:Message,children:[{name:"detail",//给当前路由命名path:"detail",component:Detail,}]}]},]
})

2.2 简化跳转:

<!--简化前,需要写完整的路径 -->
<router-link to="/demo/test/detail">跳转</router-link><!--简化后,直接通过名字跳转 -->
<router-link :to="{name:'detail'}">跳转</router-link><!--简化写法配合传递参数 -->
<router-link :to="{name:'detail',query:{id:666,title:'你好'}}"
>跳转</router-link>

7.5 路由的params参数(RestFul风格)

  1. router/index.js配置路由,声明接收params参数 使用 :参数名来当占位符
{path:'/home',component:Home,children:[{path:'news',component:News},{component:Message,children:[{name:'xiangqing',path:'detail/:id/:title', //使用占位符声明接收params参数component:Detail}]}]
}
  1. 传递参数
<!-- 跳转并携带params参数,to的字符串写法 -->
<router-link :to="/home/message/detail/666/你好">跳转</router-link><!-- 跳转并携带params参数,to的对象写法 -->
<router-link :to="{name:'xiangqing',params:{id:666,title:'你好'}}"
>跳转</router-link>

特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!

7.7 路由的props配置

  • router/index.js中配置 作用:让路由组件更方便的收到参数
{name:'xiangqing',path:'detail/:id',component:Detail,//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件// props:{a:900}//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数(RestFul风格传参)通过props传给Detail组件// props:true//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件props(route){return {id:route.query.id,title:route.query.title}}
}
  • 接收props
<template><ul><li>消息编号:{{$route.query.id}}</li><li>消息详情:{{$route.query.title}}</li><li>消息详情:{{id}}</li><li>消息详情:{{title}}</li></ul>
</template><script>
export default {name:"Detail",props:['id','title'],mounted(){console.log(this);}
}
</script>

7.8 编程式路由导航

  • 作用:不借助<router-link>实现路由跳转,让路由跳转更加灵活
//$router的两个API
this.$router.push({name:'detail',params:{id:xxx,msg:xxx,}
})
//会覆盖上一次点击的记录
this.$router.replace({name:'detail',params:{id:xxx,msg:xxx,}
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退(正数代表向前走几次路径,负数代表向后退几次路径)

7.9 缓存路由组件

  • 作用:让不展示的路由组件保持挂载,不被销毁。
  • 编写:若include不写 默认router-view中所有呈现的组件都会保持挂载
<keep-alive include="组件名"> <router-view></router-view>
</keep-alive>

7.10 两个新的生命周期钩子

  • 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
  • 两个路由名字:
    1. activated路由组件被激活时触发。
    2. deactivated路由组件失活时触发。
<template><ul><li>news001 <input type="text"></li><li>news002 <input type="text"></li><li>news003 <input type="text"></li></ul>
</template><script>
export default {name: "News",activated() {console.log("News组件被激活了");},deactivated(){console.log("News组件没有被激活");}
};
</script>

7.11 路由守卫

  • 作用:对路由进行权限控制
  • 分类:全局守卫、独享守卫、组件内守卫

7.11.1 全局加守卫

//创建一个路由器
const router= new VueRouter({//路由routes:[{path:'/about',component:About,},{path:'/home',component:Home,       //配置子级路由children:[{//此处不要加 /path:"news",component:News,},{path:"message",component:Message,children:[{name:"detail",//给当前路由命名//自定义属性必须放在meta中meta:{a:true},path:"detail",component:Detail,}]}]},]
})
//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{// 参数1:to 当前路由要去哪儿//参数2:from 当前路由从哪儿来//参数3:放行if(判断条件 或者 to.meta.a(自定义参数进行判断)){ //判断当前路由是否需要进行权限控制next() //放行}else{//不放行}
})//全局后置守卫:初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{console.log('afterEach',to,from)
})
export default router

7.11.2 独享守卫

//创建一个路由器
const router= new VueRouter({//路由routes:[{path:'/about',component:About,},{path:'/home',component:Home,       //配置子级路由children:[{//此处不要加 /path:"news",component:News,},{path:"message",meta:{a:true},component:Message,children:[{name:"detail",//给当前路由命名path:"detail",component:Detail,}],//独享路由守卫beforeEnter(to,from,next){console.log('beforeEnter',to,from)if(to.meta.a){ //判断当前路由是否需要进行权限控制next()}}}]},]
})export default router

7.11.3 组件守卫

<template><ul><li>news001 <input type="text"></li><li>news002 <input type="text"></li><li>news003 <input type="text"></li></ul>
</template><script>
export default {name: "News",activated() {console.log("News组件被激活了");},deactivated(){console.log("News组件没有被激活");},//进入守卫:通过路由规则,进入该组件时被调用beforeRouteEnter (to, from, next) {},//离开守卫:通过路由规则,离开该组件时被调用beforeRouteLeave (to, from, next) {}
};
</script>

7.12 路由的两种工作模式

  1. 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。

  2. hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。

  3. hash模式:

    1. 地址中永远带着#号,不美观 。
    2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
    3. 兼容性较好。
  4. history模式:

    1. 地址干净,美观 。
    2. 兼容性和hash模式相比略差。
    3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。

8、Element-UI组件库

官网


# 总结 提示:这里对文章进行总结: 例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

Vue保姆级入门教程相关推荐

  1. 深度学习保姆级入门教程 -- 论文+代码+常用工具

    导读 该篇文章可以看作是我研一如何入门深度学习的一个大总结,本人本科专业为软件工程,硕士期间研究方向为基于深度学习的图像分割,跨度相对而言不算太大.如果你对如何入门深度学习还很迷茫的话,那么请看下去吧 ...

  2. 微服务网关:SpringCloud Gateway保姆级入门教程

    什么是微服务网关 SpringCloud Gateway是Spring全家桶中一个比较新的项目,Spring社区是这么介绍它的: 该项目借助Spring WebFlux的能力,打造了一个API网关.旨 ...

  3. 什么是微服务网关?SpringCloud Gateway保姆级入门教程

    什么是微服务网关 SpringCloud Gateway是Spring全家桶中一个比较新的项目,Spring社区是这么介绍它的: 该项目借助Spring WebFlux的能力,打造了一个API网关.旨 ...

  4. 【机器学习】机器学习神器Scikit-Learn保姆级入门教程

    公众号:尤而小屋 作者:Peter 编辑:Peter Scikit-learn是一个非常知名的Python机器学习库,它广泛地用于统计分析和机器学习建模等数据科学领域. 建模无敌:用户通过scikit ...

  5. ElasticSearch保姆级入门教程

    文章目录 一.初识ElasticSearch 二.安装Elasticsearch 2.1 创建网络 2.2 下载资源/加载镜像 2.3 运行 2.4 部署kibana 2.4.1 部署 2.5 安装I ...

  6. PyTorch 分布式框架 Ray :保姆级入门教程

    来源:官方博客 翻译:PyTorch 开发者社区(微信公众号) 今天的机器学习需要分布式计算.无论是训练网络.调整超参数.服务模型还是处理数据,机器学习都是计算密集型的,如果没有访问集群,速度会非常慢 ...

  7. Containerd 的前世今生和保姆级入门教程

    1. Containerd 的前世今生 很久以前,Docker 强势崛起,以"镜像"这个大招席卷全球,对其他容器技术进行致命的降维打击,使其毫无招架之力,就连 Google 也不例 ...

  8. 机器学习神器Scikit-Learn保姆级入门教程

    Scikit-learn是一个非常知名的Python机器学习库,它广泛地用于统计分析和机器学习建模等数据科学领域. 建模无敌:用户通过scikit-learn能够实现各种监督和非监督学习的模型 功能多 ...

  9. 管理订单状态,该上状态机吗?轻量级状态机COLA StateMachine保姆级入门教程

    前言 在平常的后端项目开发中,状态机模式的使用其实没有大家想象中那么常见,笔者之前由于不在电商领域工作,很少在业务代码中用状态机来管理各种状态,一般都是手动get/set状态值.去年笔者进入了电商领域 ...

最新文章

  1. 74ls390设计任意进制计数器_异步FIFO:设计原理及Verliog源码
  2. 关于知识蒸馏,这三篇论文详解不可错过
  3. ASP.NET 2.0 正式版中无刷新页面的开发
  4. sqlserver导出带数据的脚本文件
  5. 使用直接内存时可以更快
  6. java excutorthread_JAVA 线程池ThreadPoolExcutor原理探究
  7. 基于asp.net338医院体检信息管理系统
  8. python round函数
  9. 为什么用CDN给你网站加速?
  10. 2022年~全网最真实的软件测试面试题合集
  11. 体系结构实验(4)—— Tomasulo算法
  12. 大数据-机器学习导论-1
  13. 工作组和域的概念及辨析
  14. ​你在淘宝剁手,钱却可能进入黑客的口袋
  15. 人工智能一大技术:强化学习(RL)
  16. 解决PC微信版本过低 1.0.7.33版本及以上版本方法
  17. Android 军刀级神器:Magisk
  18. IMPERVA-WAF 系统制作和安装-USB
  19. 如何构建电商用户画像
  20. G1 GC详解及设置

热门文章

  1. vpp源码框架的rpm打包、安装、启动1
  2. 计算机机房分区,2021年高校计算机新建机房硬盘分区及软件安装计划硬盘分区教程win10.docx...
  3. Nordic如何将服务特征的UUID设置为128位?
  4. 算法创作|“石头剪刀布”问题解决方法
  5. 从美术设计角度回溯与展望CODM出海之路
  6. 今年的5G手机,必须具备这些功能!
  7. 【Houdini】Houdini实现Realflow大脑袋案例
  8. 各种主流游戏引擎盘点 【端游 、页游 、手游】(使用游戏引擎的好处是什么)...
  9. HTML5课堂入门笔记(完)
  10. 显示器屏幕的最佳分辨率和高宽比