- 微信小程序UI组件库合集
UI组件库合集,大家有遇到好的组件库,欢迎留言评论然后加入到文档里。 第一款: 官方WeUI组件库,地址 https://developers.weixin.qq.com/miniprogram/dev/extended/weui/ 预览码: [图片] 第二款: ColorUI:地址 https://github.com/weilanwl/ColorUI 预览码: [图片] 第三款: vantUI(又名:ZanUI):地址 https://youzan.github.io/vant-weapp/#/intro 预览码: [图片] 第四款: MinUI: 地址 https://meili.github.io/min/docs/minui/index.html 预览码: [图片] 第五款: iview-weapp:地址 https://weapp.iviewui.com/docs/guide/start 预览码: [图片] 第六款: WXRUI:暂无地址 预览码: [图片] 第七款: WuxUI:地址https://www.wuxui.com/#/introduce 预览码: [图片] 第八款: WussUI:地址 https://phonycode.github.io/wuss-weapp/quickstart.html 预览码: [图片] 第九款: TouchUI:地址 https://github.com/uileader/touchwx 预览码: [图片] 第十款: Hello UniApp: 地址 https://m3w.cn/uniapp 预览码: [图片] 第十一款: TaroUI:地址 https://taro-ui.jd.com/#/docs/introduction 预览码: [图片] 第十二款: Thor UI: 地址 https://thorui.cn/doc/ 预览码: [图片] 第十三款: GUI:https://github.com/Gensp/GUI 预览码: [图片] 第十四款: QyUI:暂无地址 预览码: [图片] 第十五款: WxaUI:暂无地址 预览码: [图片] 第十六款: kaiUI: github地址 https://github.com/Chaunjie/kai-ui 组件库文档:https://chaunjie.github.io/kui/dist/#/start 预览码: [图片] 第十七款: YsUI:暂无地址 预览码: [图片] 第十八款: BeeUI:git地址 http://ued.local.17173.com/gitlab/wxc/beeui.git 预览码: [图片] 第十九款: AntUI: 暂无地址 预览码: [图片] 第二十款: BleuUI:暂无地址 预览码: [图片] 第二十一款: uniydUI:暂无地址 预览码: [图片] 第二十二款: RovingUI:暂无地址 预览码: [图片] 第二十三款: DojayUI:暂无地址 预览码: [图片] 第二十四款: SkyUI:暂无地址 预览码: [图片] 第二十五款: YuUI:暂无地址 预览码: [图片] 第二十六款: wePyUI:暂无地址 预览码: [图片] 第二十七款: WXDUI:暂无地址 预览码: [图片] 第二十八款: XviewUI:暂无地址 预览码: [图片] 第二十九款: MinaUI:暂无地址 预览码: [图片] 第三十款: InyUI:暂无地址 预览码: [图片] 第三十一款: easyUI:地址 https://github.com/qq865738120/easyUI 预览码: [图片] 第三十二款 Kbone-UI: 地址 https://wechat-miniprogram.github.io/kboneui/ui/#/ 暂无预览码 第三十三款 VtuUi: 地址 https://github.com/jisida/VtuWeapp 预览码: [图片] 第三十四款 Lin-UI 地址:http://doc.mini.talelin.com/ 预览码: [图片] 第三十五款 GraceUI 地址: http://grace.hcoder.net/ 这个是收费的哦~ 预览码: [图片] 第三十六款 anna-remax-ui npm:https://www.npmjs.com/package/anna-remax-ui/v/1.0.12 anna-remax-ui 地址: https://annasearl.github.io/anna-remax-ui/components/general/button 预览码 [图片] 第三十七款 Olympus UI 地址:暂无 网易严选出品。 预览码 [图片] 第三十八款 AiYunXiaoUI 地址暂无 预览码 [图片] 第三十九款 visionUI npm:https://www.npmjs.com/package/vision-ui 预览码: [图片] 第四十款 AnimaUI(灵动UI) 地址:https://github.com/AnimaUI/wechat-miniprogram 预览码: [图片] 第四十一款 uView 地址:http://uviewui.com/components/quickstart.html 预览码: [图片] 第四十二款 firstUI 地址:https://www.firstui.cn/ 预览码: [图片]
2023-01-10 - vue的基础知识点总结
vue的基础知识点总结 小程序的前端框架可以选用uniapp,是一款集成了vue的小程序前端开发框架,同时一套代码可以适配h5,安卓和小程序。对vue感兴趣的同学可以上手玩玩 vue的基础指令 基本模板(不使用脚手架) [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>02-Vue基本模板</title> <!--1.下载导入Vue.js--> <script src="js/vue.js"></script> </head> <body> <div id="app"> <p>{{ name }}</p> </div> <script> // 2.创建一个Vue的实例对象 let vue = new Vue({ // 3.告诉Vue的实例对象, 将来需要控制界面上的哪个区域 el: '#app', // 4.告诉Vue的实例对象, 被控制区域的数据是什么 data: { name: "李南江" } }); </script> </body> </html> <!-- 1.Vue框架使用方式 1.1传统下载导入使用 1.2vue-cli安装导入使用 2.Vue框架使用步骤 2.1下载Vue框架 2.2导入Vue框架 2.3创建Vue实例对象 2.4指定Vue实例对象控制的区域 2.5指定Vue实例对象控制区域的数据 --> [代码] vue数据的单项绑定 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>03-Vue数据单向传递</title> <!--1.下载导入Vue.js--> <script src="js/vue.js"></script> </head> <body> <!-- 1.MVVM设计模式 在MVVM设计模式中由3个部分组成 M : Model 数据模型(保存数据, 处理数据业务逻辑) V : View 视图(展示数据, 与用户交互) VM: View Model 数据模型和视图的桥梁(M是中国人, V是美国人, VM就是翻译) MVVM设计模式最大的特点就是支持数据的双向传递 数据可以从 M -> VM -> V 也可以从 V -> VM -> M 2.Vue中MVVM的划分 Vue其实是基于MVVM设计模式的 被控制的区域: View Vue实例对象 : View Model 实例对象中的data: Model 3.Vue中数据的单向传递 我们把"数据"交给"Vue实例对象", "Vue实例对象"将数据交给"界面" Model -> View Model -> View --> <!--这里就是MVVM中的View--> <div id="app"> <p>{{ name }}</p> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { name: "李南江" } }); </script> </body> </html> [代码] v-model数据的双向传递 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>04-Vue数据双向传递</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.Vue调试工具安装 如果你能打开谷歌插件商店, 直接在线安装即可 https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd?hl=zh-CN 由于国内无法打开谷歌国外插件商店, 所以可以离线安装 https://www.chromefor.com/vue-js-devtools_v5-3-0/ 2.安装步骤: 2.1下载离线安装包 2.2打开谷歌插件界面 2.3直接将插件拖入 2.4报错 程序包无效: "CRX_HEADER_INVALID" 可以将安装包修改为rar后缀, 解压之后再安装 2.5重启浏览器 --> <!-- 2.数据双向绑定 默认情况下Vue只支持数据单向传递 M -> VM -> V 但是由于Vue是基于MVVM设计模式的, 所以也提供了双向传递的能力 在<input>、<textarea> 及 <select> 元素上可以用 v-model 指令创建双向数据绑定 注意点: v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值 而总是将 Vue 实例的数据作为数据来源 --> <!--这里就是MVVM中的View--> <div id="app"> <p>{{ name }}</p> <input type="text" v-model="msg"> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { name: "李南江", msg: "知播渔" } }); </script> </body> </html> [代码] v-once只渲染一次 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>05-常用指令-v-once</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.什么是指令? 指令就是Vue内部提供的一些自定义属性, 这些属性中封装好了Vue内部实现的一些功能 只要使用这些指令就可以使用Vue中实现的这些功能 2.Vue数据绑定的特点 只要数据发生变化, 界面就会跟着变化 3.v-once指令: 让界面不要跟着数据变化, 只渲染一次 --> <!--这里就是MVVM中的View--> <div id="app"> <p v-once>原始数据: {{ name }}</p> <p>当前数据: {{ name }}</p> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { name: "李南江", } }); </script> </body> </html> [代码] v-cloak数据渲染完之后才显示 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>06-常用指令-v-cloak</title> <style> [v-cloak] { display: none } </style> </head> <body> <!-- 1.Vue数据绑定过程 1.1会先将未绑定数据的界面展示给用户 1.2然后再根据模型中的数据和控制的区域生成绑定数据之后的HTML代码 1.3最后再将绑定数据之后的HTML渲染到界面上 正是在最终的HTML被生成渲染之前会先显示模板内容 所以如果用户网络比较慢或者网页性能比较差, 那么用户会看到模板内容 2.如何解决这个问题 利用v-cloak配合 [v-cloak]:{display: none}默认先隐藏未渲染的界面 等到生成HTML渲染之后再重新显示 3.v-cloak指令作用: 数据渲染之后自动显示元素 --> <!--这里就是MVVM中的View--> <div id="app"> <p v-cloak>{{ name }}</p> </div> <!-- <div id="app"> <p> 李南江 </p> </div> --> <script src="js/vue.js"></script> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { name: "李南江", } }); </script> </body> </html> [代码] v-text和v-html [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>07-常用指令v-text和v-html</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.什么是v-text指令 v-text就相当于过去学习的innerText 2.什么是v-html指令 v-html就相当于过去学习的innerHTML --> <!--这里就是MVVM中的View--> <div id="app"> <!--插值的方式: 可以将指定的数据插入到指定的位置--> <!-- <p>++++{{ name }}++++</p>--> <!--插值的方式: 不会解析HTML--> <!-- <p>++++{{ msg }}++++</p>--> <!--v-text的方式: 会覆盖原有的内容--> <!-- <p v-text="name">++++++++</p>--> <!--v-text的方式: 也不会解析HTML--> <!-- <p v-text="msg">++++++++</p>--> <!--v-html的方式: 会覆盖原有的内容--> <p v-html="name">++++++++</p> <!--v-html的方式:会解析HTML--> <p v-html="msg">++++++++</p> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { name: "李南江", msg: "<span>我是span</span>" } }); </script> </body> </html> [代码] v-if [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>08-常用指令v-if</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.什么是v-if指令 条件渲染: 如果v-if取值是true就渲染元素, 如果不是就不渲染元素 2.v-if特点: 如果条件不满足根本就不会创建这个元素(重点) 3.v-if注意点 v-if可以从模型中获取数据 v-if也可以直接赋值一个表达式 --> <!-- 4.v-else指令 v-else指令可以和v-if指令配合使用, 当v-if不满足条件时就执行v-else就显示v-else中的内容 5.v-else注意点 v-else不能单独出现 v-if和v-else中间不能出现其它内容 --> <!-- 6.v-else-if指令 v-else-if可以和v-if指令配合使用, 当v-if不满足条件时就依次执行后续v-else-if, 哪个满足就显示哪个 7.v-else-if注意点 和v-else一样 --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <p v-if="show">我是true</p>--> <!-- <p v-if="hidden">我是false</p>--> <!-- <p v-if="true">我是true</p>--> <!-- <p v-if="false">我是false</p>--> <!-- <p v-if="age >= 18">我是true</p>--> <!-- <p v-if="age < 18">我是false</p>--> <!-- <p v-if="age >= 18">成年人</p>--> <!-- <p>中间的内容</p>--> <!-- <p v-else>未成年人</p>--> <p v-if="score >= 80">优秀</p> <p v-else-if="score >= 60">良好</p> <p v-else>差</p> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { show: true, hidden: false, age: 17, score: 50 } }); </script> </body> </html> [代码] v-show [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>09-常用指令v-show</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.什么是v-show指令 v-show和v-if的能够一样都是条件渲染, 取值为true就显示, 取值为false就不显示 2.v-if和v-show区别 v-if: 只要取值为false就不会创建元素 v-show: 哪怕取值为false也会创建元素, 只是如果取值是false会设置元素的display为none 3.v-if和v-show应用场景 由于取值为false时v-if不会创建元素, 所以如果需要切换元素的显示和隐藏, 每次v-if都会创建和删除元素 由于取值为false时v-show会创建元素并设置display为none, 所有如果需要切换元素的显示和隐藏, 不会反复创建和删除, 只是修改display的值 所以: 如果企业开发中需要频繁切换元素显示隐藏, 那么推荐使用v-show, 否则使用v-if --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <p v-show="show">我是true</p>--> <!-- <p v-show="hidden">我是false</p>--> <!-- <p v-show="true">我是true</p>--> <!-- <p v-show="false">我是false</p>--> <!-- <p v-show="age >= 18">我是true</p>--> <!-- <p v-show="age < 18">我是false</p>--> <p v-show="show">我是段落1</p> <p v-show="hidden">我是段落2</p> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { show: true, hidden: false, age: 18 } }); </script> </body> </html> [代码] v-for [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>10-常用指令v-for</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.什么是v-for指令 相当于JS中的for in循环, 可以根据数据多次渲染元素 2.v-for特点 可以遍历 数组, 字符, 数字, 对象 --> <!--这里就是MVVM中的View--> <div id="app"> <ul> <!-- <li v-for="(value, index) in list">{{index}}---{{value}}</li> --> <!-- <li v-for="(value, index) in 'abcdefg'"> {{index}}---{{value}} </li> --> <!-- <li v-for="(value, index) in 6">{{index}}---{{value}}</li> --> <!-- <li v-for="(value, key) in obj">{{key}}---{{value}}</li> --> </ul> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: "#app", // 这里就是MVVM中的Model data: { list: ["张三", "李四", "王五", "赵六"], obj: { name: "lnj", age: 33, gender: "man", class: "知播渔", }, }, }); </script> </body> </html> [代码] v-bind(语法糖: 😃 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>10-常用指令v-bind</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.什么是v-bind指令 在企业开发中想要给"元素"绑定数据, 我们可以使用{{}}, v-text, v-html 但是如果想给"元素的属性"绑定数据, 就必须使用v-bind 所以v-bind的作用是专门用于给"元素的属性"绑定数据的 2.v-bind格式 v-bind:属性名称="绑定的数据" :属性名称="绑定的数据" 3.v-bind特点 赋值的数据可以是任意一个合法的JS表达式 例如: :属性名称="age + 1" --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <p>{{name}}</p>--> <!-- <p v-text="name"></p>--> <!-- <p v-html="name"></p>--> <!--注意点: 如果要给元素的属性绑定数据, 那么是不能够使用插值语法的--> <!-- <input type="text" value="{{name}}" /> --> <!--注意点: 虽然通过v-model可以将数据绑定到input标签的value属性上 但是v-model是有局限性的, v-model只能用于input/textarea/select 但是在企业开发中我们还可能需要给其它标签的属性绑定数据--> <!-- <input type="text" v-model="name">--> <!-- <input type="text" v-bind:value="name">--> <!-- <input type="text" :value="name">--> <input type="text" :value="age + 1" /> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: "#app", // 这里就是MVVM中的Model data: { name: "知播渔666", age: 18, }, }); </script> </body> </html> [代码] 绑定类名:class [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>12-常用指令-绑定类名</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .size{ font-size: 100px; } .color{ color: red; } .active{ background: skyblue; } </style> </head> <body> <!-- 1.v-bind指令的作用 v-bind指令给"任意标签"的"任意属性"绑定数据 对于大部分的属性而言我们只需要直接赋值即可, 例如:value="name" 但是对于class和style属性而言, 它的格式比较特殊 2.通过v-bind绑定类名格式 :class="['需要绑定类名', ...]" 3.注意点: 3.1直接赋值一个类名(没有放到数组中)默认回去Model中查找 :class="需要绑定类名" 2.2数组中的类名没有用引号括起来也会去Model中查找 :class="[需要绑定类名]" 2.3数组的每一个元素都可以是一个三目运算符按需导入 :class="[flag?'active':'']" 2.4可以使用对象来替代数组中的三目运算符按需导入 :class="[{'active': true}]" 2.5绑定的类名太多可以将类名封装到Model中 obj: { 'color': true, 'size': true, 'active': false, } 4.绑定类名企业应用场景 从服务器动态获取样式后通过v-bind动态绑定类名 这样就可以让服务端来控制前端样式 常见场景: 618 双11等 --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <p class="size color active">我是段落</p>--> <!-- 注意点: 如果需要通过v-bind给class绑定类名, 那么不能直接赋值 默认情况下v-bind会去Model中查找数据, 但是Model中没有对应的类名, 所以无效, 所以不能直接赋值 --> <!-- <p :class="size">我是段落</p>--> <!-- 注意点: 如果想让v-bind去style中查找类名, 那么就必须把类名放到数组中 但是放到数组中之后默认还是回去Model中查找 --> <!-- <p :class="[size]">我是段落</p>--> <!-- 注意点: 将类名放到数组中之后, 还需要利用引号将类名括起来才会去style中查找 --> <!-- <p :class="['size', 'color', 'active']">我是段落</p>--> <!-- 注意点: 如果是通过v-bind类绑定类名, 那么在绑定的时候可以编写一个三目运算符来实现按需绑定 格式: 条件表达式 ? '需要绑定的类名' : '' --> <!-- <p :class="['size', 'color', flag ? 'active' : '']">我是段落</p>--> <!-- 注意点: 如果是通过v-bind类绑定类名, 那么在绑定的时候可以通过对象来决定是否需要绑定 格式: {'需要绑定的类名' : 是否绑定} --> <!-- <p :class="['size', 'color',{'active' : false}]">我是段落</p>--> <!-- 注意点: 如果是通过v-bind类绑定类名, 那么还可以使用Model中的对象来替换数组 --> <p :class="obj">我是段落</p> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { flag: false, obj:{ 'size': false, 'color': false, 'active': true, } } }); </script> </body> </html> [代码] 绑定样式:style [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>13-常用指令-绑定样式</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.如何通过v-bind给style属性绑定数据 1.1将数据放到对象中 :style="{color:'red','font-size':'50px'}" 1.2将数据放到Model对象中 obj: { color: 'red', 'font-size': '80px', } 2.注意点 2.1如果属性名称包含-, 那么必须用引号括起来 2.2如果需要绑定Model中的多个对象, 可以放到一个数组中赋值 --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <p style="color: red">我是段落</p>--> <!-- 注意点: 和绑定类名一样, 默认情况下v-bind回去Model中查找, 找不到所以没有效果 --> <!-- <p :style="color: red">我是段落</p>--> <!-- 注意点: 我们只需要将样式代码放到对象中赋值给style即可 但是取值必须用引号括起来 --> <!-- <p :style="{color: 'red'}">我是段落</p>--> <!-- 注意点: 如果样式的名称带-, 那么也必须用引号括起来才可以 --> <!-- <p :style="{color: 'red', 'font-size': '100px'}">我是段落</p>--> <!-- <p :style="obj">我是段落</p>--> <!-- 注意点: 如果Model中保存了多个样式的对象 ,想将多个对象都绑定给style, 那么可以将多个对象放到数组中赋值给style即可 --> <p :style="[obj1, obj2]">我是段落</p> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { obj1:{ "color": "blue", "font-size": "100px" }, obj2: { "background-color": "red" } } }); </script> </body> </html> [代码] v-on(语法糖: @) [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>14-常用指令-v-on</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.什么是v-on指令? v-on指令专门用于给元素绑定监听事件 2.v-on指令格式 v-on:事件名称="回调函数名称" @事件名称="回调函数名称" 3.v-on注意点: v-on绑定的事件被触发之后, 会去Vue实例对象的methods中查找对应的回调函数 --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <button onclick="alert('lnj')">我是按钮</button>--> <!-- 注意点: 1.如果是通过v-on来绑定监听事件, 那么在指定事件名称的时候不需要写on 2.如果是通过v-on来绑定监听事件, 那么在赋值的时候必须赋值一个回调函数的名称 --> <!-- <button v-on:click="alert('lnj')">我是按钮</button>--> <!-- 注意点: 当绑定的事件被触发后, 会调用Vue实例的methods对象中对应的回调函数 --> <!-- <button v-on:click="myFn">我是按钮</button>--> <button @click="myFn">我是按钮</button> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, methods: { myFn(){ alert('lnj') } } }); </script> </body> </html> [代码] v-on的修饰符 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>15-常用指令-v-on修饰符</title> <script src="js/vue.js"></script> <style> * { margin: 0; padding: 0; } .a { width: 300px; height: 300px; background: red; } .b { width: 200px; height: 200px; background: blue; } .c { width: 100px; height: 100px; background: green; } </style> </head> <body> <!-- 1.v-on修饰符 在事件中有很多东西需要我们处理, 例如事件冒泡,事件捕获, 阻止默认行为等 那么在Vue中如何处理以上内容呢, 我们可以通过v-on修饰符来处理 2.常见修饰符 .once - 只触发一次回调。 .prevent - 调用 event.preventDefault()。 .stop - 调用 event.stopPropagation()。 .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。 .capture - 添加事件侦听器时使用 capture 模式。 --> <!--这里就是MVVM中的View--> <div id="app"> <!--注意点: 默认情况下事件的回调函数可以反复的执行, 只要事件被触发就会执行--> <!-- <button v-on:click="myFn">我是按钮</button>--> <!--如果想让事件监听的回调函数只执行一次, 那么就可以使用.once修饰符--> <!-- <button v-on:click.once ="myFn">我是按钮</button>--> <!--如果想阻止元素的默认行为, 那么可以使用.prevent修饰符--> <!-- <a href="http://www.it666.com" v-on:click.prevent="myFn">我是A标签</a>--> <!-- 默认情况下载嵌套的元素中, 如果都监听了相同的事件, 那么会触发事件冒泡 如果想阻止事件冒泡, 那么可以使用.stop修饰符 --> <!--<div class="a" @click="myFn1"> <div class="b" @click.stop="myFn2"> <div class="c" @click="myFn3"></div> </div> </div>--> <!-- 如果想让回调只有当前元素触发事件的时候才执行, 那么就可以使用.self修饰符 --> <!-- <div class="a" @click="myFn1"> <div class="b" @click.self="myFn2"> <div class="c" @click="myFn3"></div> </div> </div> --> <!-- 默认情况下是事件冒泡, 如果想变成事件捕获, 那么就需要使用.capture修饰符 --> <!-- <div class="a" @click.capture="myFn1"> <div class="b" @click.capture="myFn2"> <div class="c" @click.capture="myFn3"></div> </div> </div> --> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: "#app", // 这里就是MVVM中的Model data: {}, // 专门用于存储监听事件回调函数 methods: { myFn() { alert("lnj"); }, myFn1() { console.log("爷爷"); }, myFn2() { console.log("爸爸"); }, myFn3() { console.log("儿子"); }, }, }); </script> </body> </html> [代码] v-on的注意点 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>16-常用指令-v-on注意点</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.v-on注意点 1.1绑定回调函数名称的时候, 后面可以写()也可以不写 v-on:click="myFn" v-on:click="myFn()" 1.2可以给绑定的回调函数传递参数 v-on:click="myFn('lnj', 33)" 1.3如果在绑定的函数中需要用到data中的数据必须加上this --> <!--这里就是MVVM中的View--> <div id="app"> <button @click="myFn('lnj', 33, $event)">我是按钮</button> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { gender: "man" }, // 专门用于存储监听事件回调函数 methods: { myFn(name, age, e){ // alert('lnj'); // console.log(name, age, e); console.log(this.gender); } } }); </script> </body> </html> [代码] v-on按键修饰符 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>17-常用指令-v-on按键修饰符</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.什么是按键修饰符 我们可以通过按键修饰符监听特定按键触发的事件 例如: 可以监听当前事件是否是回车触发的, 可以监听当前事件是否是ESC触发的等 2.按键修饰符分类 2.1系统预定义修饰符 2.2自定义修饰符 --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <input type="text" @keyup.enter="myFn">--> <input type="text" @keyup.f2="myFn"> </div> <script> Vue.config.keyCodes.f2 = 113; // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { myFn(){ alert("lnj"); } } }); </script> </body> </html> [代码] vue自定义全局指令 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>18-常用指令-自定义指令</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.自定义全局指令 在Vue中除了可以使用Vue内置的一些指令以外, 我们还可以自定义指令 2.自定义全局指令语法 vue.directive('自定义指令名称', { 生命周期名称: function (el) { 指令业务逻辑代码 } }); 3.指令生命周期方法 自定义指令时一定要明确指令的业务逻辑代码更适合在哪个阶段执行 例如: 指令业务逻辑代码中没有用到元素事件, 那么可以在bind阶段执行 例如: 指令业务逻辑代码中用到了元素事件, 那么就需要在inserted阶段执行 4.自定义指令注意点 使用时需要加上v-, 而在自定义时不需要加上v- --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <p v-color>我是段落</p>--> <input type="text" v-focus /> </div> <script> /* directive方法接收两个参数 第一个参数: 指令的名称 第二个参数: 对象 注意点: 在自定义指令的时候, 在指定指令名称的时候, 不需要写v- 注意点: 指令可以在不同的生命周期阶段执行 bind: 指令被绑定到元素上的时候执行 inserted: 绑定指令的元素被添加到父元素上的时候执行 * */ Vue.directive("color", { // 这里的el就是被绑定指令的那个元素 bind: function (el) { el.style.color = "red"; }, }); Vue.directive("focus", { // 这里的el就是被绑定指令的那个元素 inserted: function (el) { el.focus(); }, }); // 这里就是MVVM中的View Model let vue = new Vue({ el: "#app", // 这里就是MVVM中的Model data: {}, // 专门用于存储监听事件回调函数 methods: {}, }); </script> </body> </html> [代码] 自定义指令传参 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>19-常用指令-自定义指令参数</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.自定义指令参数 在使用官方指令的时候我们可以给指令传参 例如: v-model="name" 在我们自定义的指令中我们也可以传递传递 2.获取自定义指令传递的参数 在执行自定义指令对应的方法的时候, 除了会传递el给我们, 还会传递一个对象给我们 这个对象中就保存了指令传递过来的参数 --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <p v-color="'blue'">我是段落</p>--> <p v-color="curColor">我是段落</p> </div> <script> Vue.directive("color", { // 这里的el就是被绑定指令的那个元素 bind: function (el, obj) { // el.style.color = "red"; el.style.color = obj.value; } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { curColor: 'green' }, // 专门用于存储监听事件回调函数 methods: { } }); </script> </body> </html> [代码] directives自定义局部指令 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>21-常用指令-自定义局部指令</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.自定义全局指令的特点 在任何一个Vue实例控制的区域中都可以使用 2.自定义局部指令的特点 只能在自定义的那个Vue实例中使用 3.如何自定义一个局部指令 给创建Vue实例时传递的对象添加 directives: { // key: 指令名称 // value: 对象 'color': { bind: function (el, obj) { el.style.color = obj.value; } } } --> <!--这里就是MVVM中的View--> <div id="app1"> <p v-color="'blue'">我是段落</p> </div> <div id="app2"> <p v-color="'red'">我是段落</p> </div> <script> /* Vue.directive("color", { // 这里的el就是被绑定指令的那个元素 bind: function (el, obj) { el.style.color = obj.value; } }); */ // 这里就是MVVM中的View Model let vue1 = new Vue({ el: '#app1', // 这里就是MVVM中的Model data: {}, // 专门用于存储监听事件回调函数 methods: {} }); // 这里就是MVVM中的View Model let vue2 = new Vue({ el: '#app2', // 这里就是MVVM中的Model data: {}, // 专门用于存储监听事件回调函数 methods: {}, // 专门用于定义局部指令的 directives: { "color": { // 这里的el就是被绑定指令的那个元素 bind: function (el, obj) { el.style.color = obj.value; } } } }); </script> </body> </html> [代码] computed计算属性 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>22-Vue-计算属性</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.插值语法特点 可以在{{}}中编写合法的JavaScript表达式 2.在插值语法中编写JavaScript表达式缺点 2.1没有代码提示 2.2语句过于复杂不利于我们维护 3.如何解决? 对于任何复杂逻辑,你都应当使用计算属性 --> <!--这里就是MVVM中的View--> <div id="app"> <p>{{name}}</p> <p>{{age + 1}}</p> <p>{{msg.split("").reverse().join("")}}</p> <!-- 注意点: 虽然在定义计算属性的时候是通过一个函数返回的数据 但是在使用计算属性的时候不能在计算属性名称后面加上() 因为它是一个属性不是一个函数(方法) --> <p>{{msg2}}</p> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { name: "lnj", age: 18, msg: "abcdef" }, // 专门用于存储监听事件回调函数 methods: {}, // 专门用于定义计算属性的 computed: { msg2: function () { let res = "abcdef".split("").reverse().join(""); return res; } } }); </script> </body> </html> [代码] 计算属性和函数的区别 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>23-Vue-计算属性和函数</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.计算属性和函数 通过计算属性我们能拿到处理后的数据, 但是通过函数我们也能拿到处理后的数据 那么计算属性和函数有什么区别呢? 2.1函数"不会"将计算的结果缓存起来, 每一次访问都会重新求值 2.2计算属性"会"将计算的结果缓存起来, 只要数据没有发生变化, 就不会重新求值 2.计算属性应用场景 计算属性:比较适合用于计算不会频繁发生变化的的数据 --> <!--这里就是MVVM中的View--> <div id="app"> <!--<p>{{msg1()}}</p> <p>{{msg1()}}</p> <p>{{msg1()}}</p>--> <p>{{msg2}}</p> <p>{{msg2}}</p> <p>{{msg2}}</p> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { /* 函数的特点: 每次调用都会执行 * */ msg1(){ console.log("msg1函数被执行了"); let res = "abcdef".split("").reverse().join(""); return res; } }, // 专门用于定义计算属性的 computed: { /* 计算属性的特点: 只要返回的结果没有发生变化, 那么计算属性就只会被执行一次 计算属性的应用场景: 由于计算属性会将返回的结果缓存起来 所以如果返回的数据不经常发生变化, 那么使用计算属性的性能会比使用函数的性能高 * */ msg2: function () { console.log("msg2计算属性被执行了"); let res = "abcdef".split("").reverse().join(""); return res; } } }); </script> </body> </html> [代码] 自定义全局的过滤器 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>24-Vue-自定义全局过滤器</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.什么是过滤器? 过滤器和函数和计算属性一样都是用来处理数据的 但是过滤器一般用于格式化插入的文本数据 2.如何自定义全局过滤器 Vue.filter("过滤器名称", 过滤器处理函数): 3.如何使用全局过滤器 {{msg | 过滤器名称}} :value="msg | 过滤器名称" 4.过滤器注意点 4.1只能在插值语法和v-bind中使用 4.2过滤器可以连续使用 --> <!--这里就是MVVM中的View--> <div id="app"> <!--Vue会把name交给指定的过滤器处理之后, 再把处理之后的结果插入到指定的元素中--> <p>{{name | formartStr1 | formartStr2}}</p> </div> <script> /* 如何自定义一个全局过滤器 通过Vue.filter(); filter方法接收两个参数 第一个参数: 过滤器名称 第二个参数: 处理数据的函数 注意点: 默认情况下处理数据的函数接收一个参数, 就是当前要被处理的数据 * */ Vue.filter("formartStr1", function (value) { // console.log(value); value = value.replace(/学院/g, "大学"); console.log(value); return value; }); Vue.filter("formartStr2", function (value) { // console.log(value); value = value.replace(/大学/g, "幼儿园"); console.log(value); return value; }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { name: "知播渔学院, 指趣学院, 前端学院, 区块链学院" }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] filters自定义局部过滤器 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>24-Vue-自定义全局过滤器</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.自定义全局过滤器的特点 在任何一个Vue实例控制的区域中都可以使用 2.自定义局部过滤器的特点 只能在自定义的那个Vue实例中使用 3.如何自定义一个局部指令 给创建Vue实例时传递的对象添加 filters: { // key: 过滤器名称 // value: 过滤器处理函数 'formartStr': function (value) {} } --> <!--这里就是MVVM中的View--> <div id="app1"> <p>{{name | formartStr}}</p> </div> <div id="app2"> <p>{{name | formartStr}}</p> </div> <script> /* Vue.filter("formartStr", function (value) { // console.log(value); value = value.replace(/学院/g, "大学"); // console.log(value); return value; }); */ // 这里就是MVVM中的View Model let vue1 = new Vue({ el: '#app1', // 这里就是MVVM中的Model data: { name: "知播渔学院, 指趣学院, 前端学院, 区块链学院" }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { } }); // 这里就是MVVM中的View Model let vue2 = new Vue({ el: '#app2', // 这里就是MVVM中的Model data: { name: "知播渔学院, 指趣学院, 前端学院, 区块链学院" }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部过滤器的 filters: { "formartStr": function (value) { // console.log(value); value = value.replace(/学院/g, "大学"); // console.log(value); return value; } } }); </script> </body> </html> [代码] 过滤器传参和String的原型方法padStart [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>24-Vue-自定义全局过滤器</title> <script src="js/vue.js"></script> </head> <body> <!-- 需求: 利用过滤器对时间进行格式化 --> <!--这里就是MVVM中的View--> <div id="app"> <p>{{time | dateFormart("yyyy-MM-dd")}}</p> </div> <script> /* 注意点: 在使用过滤器的时候, 可以在过滤器名称后面加上() 如果给过滤器的名称后面加上了(), 那么就可以给过滤器的函数传递参数 * */ Vue.filter("dateFormart", function (value, fmStr) { // console.log(fmStr); let date = new Date(value); let year = date.getFullYear(); let month = date.getMonth() + 1 + ""; let day = date.getDate() + ""; let hour = date.getHours() + ""; let minute = date.getMinutes() + ""; let second = date.getSeconds() + ""; if(fmStr && fmStr === "yyyy-MM-dd"){ return `${year}-${month.padStart(2, "0")}-${day.padStart(2, "0")}`; } return `${year}-${month.padStart(2, "0")}-${day.padStart(2, "0")} ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}:${second.padStart(2, "0")}`; }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { time: Date.now() }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] vue过渡动画 trainsition [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>28-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .box{ width: 200px; height: 200px; background: red; } .v-enter{ opacity: 0; } .v-enter-to{ opacity: 1; } .v-enter-active{ transition: all 3s; } .v-leave{ opacity: 1; } .v-leave-to{ opacity: 0; } .v-leave-active{ transition: all 3s; } </style> </head> <body> <!-- 1.如何给Vue控制的元素添加过渡动画 1.1将需要执行动画的元素放到transition组件中 1.2当transition组件中的元素显示时会自动查找.v-enter/.v-enter-active/.v-enter-to类名 当transition组件中的元素隐藏时会自动查找.v-leave/ .v-leave-active/.v-leave-to类名 1.3我们只需要在.v-enter和.v-leave-to中指定动画动画开始的状态 在.v-enter-active和.v-leave-active中指定动画执行的状态 即可完成过渡动画 --> <!--这里就是MVVM中的View--> <div id="app"> <button @click="toggle">我是按钮</button> <transition> <div class="box" v-show="isShow"></div> </transition> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { isShow: false }, // 专门用于存储监听事件回调函数 methods: { toggle(){ this.isShow = !this.isShow; } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] 给多个组件添加不同的动画 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>29-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .box{ width: 200px; height: 200px; background: red; } .one-enter{ opacity: 0; } .one-enter-to{ opacity: 1; margin-left: 500px; } .one-enter-active{ transition: all 3s; } .two-enter{ opacity: 0; } .two-enter-to{ opacity: 1; margin-top: 500px; } .two-enter-active{ transition: all 3s; } </style> </head> <body> <!-- 1.transition注意点: transition中只能放一个元素, 多个元素无效 如果想给多个元素添加过渡动画, 那么就必须创建多个transition组件 2.初始动画设置 默认情况下第一次进入的时候没没有动画的 如果想一进来就有动画, 我们可以通过给transition添加appear属性的方式 告诉Vue第一次进入就需要显示动画 3.如何给多个不同的元素指定不同的动画 如果有多个不同的元素需要执行不同的过渡动画,那么我们可以通过给transition指定name的方式 来指定"进入之前/进入之后/进入过程中, 离开之前/离开之后/离开过程中"对应的类名 来实现不同的元素执行不同的过渡动画 --> <!--这里就是MVVM中的View--> <div id="app"> <button @click="toggle">我是按钮</button> <transition appear name="one"> <div class="box" v-show="isShow"></div> <!-- <div class="box" v-show="isShow"></div>--> </transition> <transition appear name="two"> <div class="box" v-show="isShow"></div> </transition> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { isShow: true }, // 专门用于存储监听事件回调函数 methods: { toggle(){ this.isShow = !this.isShow; } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] 通过js钩子执行动画 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>30-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .box{ width: 200px; height: 200px; background: red; } .v-enter{ opacity: 0; } .v-enter-to{ opacity: 1; margin-left: 500px; } .v-enter-active{ transition: all 3s; } </style> </head> <body> <!-- 1.当前过渡存在的问题 通过transition+类名的方式确实能够实现过渡效果 但是实现的过渡效果并不能保存动画之后的状态 因为Vue内部的实现是在过程中动态绑定类名, 过程完成之后删除类名 正式因为删除了类名, 所以不能保存最终的效果 2.在Vue中如何保存过渡最终的效果 通过Vue提供的JS钩子来实现过渡动画 v-on:before-enter="beforeEnter" 进入动画之前 v-on:enter="enter" 进入动画执行过程中 v-on:after-enter="afterEnter" 进入动画完成之后 v-on:enter-cancelled="enterCancelled" 进入动画被取消 v-on:before-leave="beforeLeave" 离开动画之前 v-on:leave="leave" 离开动画执行过程中 v-on:after-leave="afterLeave" 离开动画完成之后 v-on:leave-cancelled="leaveCancelled" 离开动画被取消 3.JS钩子实现过渡注意点 3.1在动画过程中必须写上el.offsetWidth或者el.offsetHeight 3.2在enter和leave方法中必须调用done方法, 否则after-enter和after-leave不会执行 3.3需要需要添加初始动画, 那么需要把done方法包裹到setTimeout方法中调用 --> <!--这里就是MVVM中的View--> <div id="app"> <button @click="toggle">我是按钮</button> <!-- 注意点: 虽然我们是通过JS钩子函数来实现过渡动画 但是默认Vue还是回去查找类名, 所以为了不让Vue去查找类名 可以给transition添加v-bind:css="false" --> <transition appear v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter"> <div class="box" v-show="isShow"></div> </transition> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { isShow: true }, // 专门用于存储监听事件回调函数 methods: { toggle(){ this.isShow = !this.isShow; }, beforeEnter(el){ // 进入动画开始之前 console.log("beforeEnter"); el.style.opacity = "0"; }, enter(el, done){ // 进入动画执行过程中 console.log("enter"); /* 注意点: 如果是通过JS钩子来实现过渡动画 那么必须在动画执行过程中的回调函数中写上 el.offsetWidth / el.offsetHeight * */ // el.offsetWidth; el.offsetHeight; el.style.transition = "all 3s"; /* 注意点: 动画执行完毕之后一定要调用done回调函数 否则后续的afterEnter钩子函数不会被执行 * */ // done(); /* 注意点: 如果想让元素一进来就有动画, 那么最好延迟以下再调用done方法 * */ setTimeout(function () { done(); }, 0); }, afterEnter(el){ // 进入动画执行完毕之后 console.log("afterEnter"); el.style.opacity = "1"; el.style.marginLeft = "500px"; } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] 自定义类名动画 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>32-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .box{ width: 200px; height: 200px; background: red; } .a{ opacity: 0; } .b{ opacity: 1; margin-left: 500px; } .c{ transition: all 3s; } </style> </head> <body> <!-- 1.自定义类名动画 在Vue中除了可以使用 默认类名(v-xxx)来指定过渡动画 除了可以使用 自定义类名前缀(yyy-xx)来指定过渡动画(transition name="yyy") 除了可以使用 JS钩子函数来指定过渡动画以外 还可以使用自定义类名的方式来指定过渡动画 enter-class // 进入动画开始之前 enter-active-class // 进入动画执行过程中 enter-to-class // 进入动画执行完毕之后 leave-class // 离开动画开始之前 leave-active-class // 离开动画执行过程中 leave-to-class // 离开动画执行完毕之后 --> <!--这里就是MVVM中的View--> <div id="app"> <button @click="toggle">我是按钮</button> <transition appear enter-class="a" enter-active-class="c" enter-to-class="b"> <div class="box" v-show="isShow"></div> </transition> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { isShow: true }, // 专门用于存储监听事件回调函数 methods: { toggle(){ this.isShow = !this.isShow; } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] Animate动画库的使用 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>33-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .box{ width: 200px; height: 200px; background: red; } </style> <link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css"> </head> <body> <!-- 1.配合Animate.css实现过渡动画 1.1导入Animate.css库 1.2在执行过程中的属性上绑定需要的类名 --> <!--这里就是MVVM中的View--> <div id="app"> <button @click="toggle">我是按钮</button> <transition appear enter-class="" enter-active-class="animated bounceInRight" enter-to-class=""> <div class="box" v-show="isShow"></div> </transition> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { isShow: true }, // 专门用于存储监听事件回调函数 methods: { toggle(){ this.isShow = !this.isShow; } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] v-for中的key作用 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>35-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .v-enter{ opacity: 0; } .v-enter-to{ opacity: 1; } .v-enter-active{ transition: all 3s; } .v-leave{ opacity: 1; } .v-leave-to{ opacity: 0; } .v-leave-active{ transition: all 3s; } </style> </head> <body> <!-- 1.如何同时给多个元素添加过渡动画 通过transition可以给单个元素添加过渡动画 如果想给多个元素添加过渡动画, 那么就必须通过transition-group来添加 transition-group和transition的用法一致, 只是一个是给单个元素添加动画, 一个是给多个元素添加动画而已 --> <!--这里就是MVVM中的View--> <div id="app"> <form> <input type="text" v-model="name"> <input type="submit" value="添加" @click.prevent="add"> </form> <ul> <transition-group appear> <li v-for="(person,index) in persons" :key="person.id" @click="del(index)"> <input type="checkbox"> <span>{{index}} --- {{person.name}}</span> </li> </transition-group> </ul> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { persons: [ {name: "zs", id: 1}, {name: "ls", id: 2}, {name: "ww", id: 3} ], name: "" }, // 专门用于存储监听事件回调函数 methods: { add(){ let lastPerson = this.persons[this.persons.length - 1]; let newPerson = {name: this.name, id: lastPerson.id + 1}; // this.persons.push(newPerson); this.persons.unshift(newPerson); this.name = ""; }, del(index){ this.persons.splice(index, 1); } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] transition-group的使用 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>35-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .v-enter{ opacity: 0; } .v-enter-to{ opacity: 1; } .v-enter-active{ transition: all 3s; } .v-leave{ opacity: 1; } .v-leave-to{ opacity: 0; } .v-leave-active{ transition: all 3s; } </style> </head> <body> <!-- 1.如何同时给多个元素添加过渡动画 通过transition可以给单个元素添加过渡动画 如果想给多个元素添加过渡动画, 那么就必须通过transition-group来添加 transition-group和transition的用法一致, 只是一个是给单个元素添加动画, 一个是给多个元素添加动画而已 --> <!--这里就是MVVM中的View--> <div id="app"> <form> <input type="text" v-model="name"> <input type="submit" value="添加" @click.prevent="add"> </form> <ul> <transition-group appear> <li v-for="(person,index) in persons" :key="person.id" @click="del(index)"> <input type="checkbox"> <span>{{index}} --- {{person.name}}</span> </li> </transition-group> </ul> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { persons: [ {name: "zs", id: 1}, {name: "ls", id: 2}, {name: "ww", id: 3} ], name: "" }, // 专门用于存储监听事件回调函数 methods: { add(){ let lastPerson = this.persons[this.persons.length - 1]; let newPerson = {name: this.name, id: lastPerson.id + 1}; // this.persons.push(newPerson); this.persons.unshift(newPerson); this.name = ""; }, del(index){ this.persons.splice(index, 1); } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] transition-group的注意点 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>36-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .v-enter{ opacity: 0; } .v-enter-to{ opacity: 1; } .v-enter-active{ transition: all 3s; } .v-leave{ opacity: 1; } .v-leave-to{ opacity: 0; } .v-leave-active{ transition: all 3s; } </style> </head> <body> <!-- 1.transition-group注意点: 默认情况下transition-group会将动画的元素放到span标签中 我们可以通过tag属性来指定将动画元素放到什么标签中 2.transition-group动画混乱问题 一般情况下组动画出现动画混乱都是因为v-for就地复用导致的 我们只需要保证所有数据key永远是唯一的即可 --> <!--这里就是MVVM中的View--> <div id="app"> <form> <input type="text" v-model="name"> <input type="submit" value="添加" @click.prevent="add"> </form> <!-- <ul>--> <transition-group appear tag="ul"> <li v-for="(person,index) in persons" :key="person.id" @click="del(index)"> <input type="checkbox"> <span>{{index}} --- {{person.name}}</span> </li> </transition-group> <!-- </ul>--> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { persons: [ {name: "zs", id: 1}, {name: "ls", id: 2}, {name: "ww", id: 3} ], name: "", id: 3 }, // 专门用于存储监听事件回调函数 methods: { add(){ this.id++; // let lastPerson = this.persons[this.persons.length - 1]; let newPerson = {name: this.name, id: this.id}; // this.persons.push(newPerson); this.persons.unshift(newPerson); this.name = ""; }, del(index){ this.persons.splice(index, 1); } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] 组件化开发 自定义全局组件 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>37-Vue组件-自定义全局组件</title> <script src="js/vue.js"></script> </head> <body> <!-- Vue两大核心: 1.数据驱动界面改变 2.组件化 1.什么是组件? 什么是组件化? 1.1在前端开发中组件就是把一个很大的界面拆分为多个小的界面, 每一个小的界面就是一个组件 1.2将大界面拆分成小界面就是组件化 2.组件化的好处 2.1可以简化Vue实例的代码 2.2可以提高复用性 3.Vue中如何创建组件? 3.1创建组件构造器 3.2注册已经创建好的组件 3.3使用注册好的组件 --> <!--这里就是MVVM中的View--> <div id="app"> <!--// 3.3使用注册好的组件--> <abc></abc> </div> <script> // 3.1创建组件构造器 let Profile = Vue.extend({ // 注意点: 在创建组件指定组件的模板的时候, 模板只能有一个根元素 template: ` <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> ` }); // 3.2注册已经创建好的组件 // 第一个参数: 指定注册的组件的名称 // 第二个参数: 传入已经创建好的组件构造器 Vue.component("abc", Profile ); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] 自定义全局组件的注意点 首先vue.component(组件名,组件对象)可以代替vue.extend script标签中可以定义组件,加上id属性 template标签加上id属性才是vue官方的方式 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>38-Vue组件-自定义全局组件</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.创建组件的其它方式 1.1在注册组件的时候, 除了传入一个组件构造器以外, 还可以直接传入一个对象 1.2在编写组件模板的时候, 除了可以在字符串模板中编写以外, 还可以像过去的art-template一样在script中编写 1.3在编写组件模板的时候, 除了可以在script中编写以外, vue还专门提供了一个编写模板的标签template --> <!--这里就是MVVM中的View--> <div id="app"> <!--// 3.3使用注册好的组件--> <abc></abc> </div> <!-- <script id="info" type="text/html"> <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> </script> --> <template id="info"> <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> </template> <script> // 3.1创建组件构造器 /* let Profile = Vue.extend({ // 注意点: 在创建组件指定组件的模板的时候, 模板只能有一个根元素 template: ` <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> ` }); */ /* let obj = { // 注意点: 在创建组件指定组件的模板的时候, 模板只能有一个根元素 template: ` <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> ` }; */ // 3.2注册已经创建好的组件 // 第一个参数: 指定注册的组件的名称 // 第二个参数: 传入已经创建好的组件构造器 // Vue.component("abc", Profile ); // Vue.component("abc", obj ); /* Vue.component("abc", { // 注意点: 在创建组件指定组件的模板的时候, 模板只能有一个根元素 template: ` <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> ` }); */ Vue.component("abc", { // 注意点: 在创建组件指定组件的模板的时候, 模板只能有一个根元素 template: "#info" }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html> [代码] 自定义局部组件 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>39-Vue组件-自定义局部组件</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.自定义全局组件特点 在任何一个Vue实例控制的区域中都可以使用 2.自定义局部组件特点 只能在自定义的那个Vue实例控制的区域中可以使用 3.如何自定义一个局部组件 在vue实例中新增components: {} 在{}中通过key/vue形式注册组件 components:{ abc: {} } --> <!--这里就是MVVM中的View--> <div id="app1"> <abc></abc> </div> <div id="app2"> <abc></abc> </div> <template id="info"> <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> </template> <script> /* // 自定义全局组件 Vue.component("abc", { // 注意点: 在创建组件指定组件的模板的时候, 模板只能有一个根元素 template: "#info" }); */ // 这里就是MVVM中的View Model let vue1 = new Vue({ el: '#app1', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { } }); // 这里就是MVVM中的View Model let vue2 = new Vue({ el: '#app2', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { "abc": { // 注意点: 在创建组件指定组件的模板的时候, 模板只能有一个根元素 template: "#info" } } }); </script> </body> </html> [代码]
2021-11-16 - mongodb知识点总结
mongodb知识总结 微信云开发使用的云数据库集成了简化版的mongodb,因此学习两者之一就可以很快掌握另一个 mongoDB 开篇 [代码]<!-- 1.什么是MongoDB? MongoDB和MySQL一样都是数据库, 都是存储数据的仓库, 不同的是MySQL是关系型数据库, 而MongoDB是非关系型数据库 2.什么是非关系型数据库? - 在'关系型数据库'中, 数据都是存储在表中的, 对存储的内容有严格的要求 因为在创建表的时候我们就已经规定了表中有多少个字段, 已经规定了每个字段将来要存储什么类型数据, 已经规定了每个字段将来是否可以为空,是否必须唯一等等 - 在'非关系型数据库'中, 没有表概念, 所以存储数据更加灵活 因为不需要创建表,所以也没有规定有哪些字段, 也没有规定每个字段数据类型, 也没有规定每个字段将来是否可以为空,是否必须唯一等等 - '关系型数据库'由于操作的都是结构化的数据, 所以我们需要使用结构化语言SQL来操作 - '非关系型数据库'由于数据没有严格的结构要求, 所以无需使用SQL来操作 3.什么是MongoDB? 存储文档(BSON)的非关系型数据库 --> <!-- 例如在MySQL中: |--------------------------------------------------------| | name(varchar(255) not null) | age(int unique) | |--------------------------------------------------------| 我们可以把 'zs', 33 保存到表中 但是我们不能将 33, 'zs' 保存到表中 但我们不能能将 null, 33 保存到表中 但是我们不能将 'zs', 33, '男' 保存到表中 但是我们不能再次将 'zs', 33 保存到表中 --> <!-- 例如在MongoDB中: 我们可以把 {name: 'zs', age: 33}; 保存到集合中 我们也可以把 {name: 33, age: 'zs'}; 保存到集合中 我们也可以把 {name: null, age: 33}; 保存到集合中 我们也可以把 {name: 'zs', age: 33, gender:'男'}; 保存到集合中 但是我们可以再次将 {name: 'zs', age: 33}; 保存到集合中 - '非关系型数据库'可以看做是'关系型数据库'的功能阉割版本, 通过减少用不到或很少用的功能,从而提升数据库的性能 --> <!-- 4.MongoDB是如何存储文档的? MySQL中所有的数据都是存储在表中的, 而MongoDB中所有的数据都是存储在集合中的 4.1MySQL |--行1 |--表1--|--行2 数据库--| |--行3 |--表2 |--... ... 4.2MongoDB |--文档1 |--集合1--|--文档2 数据库--| |--文档3 |--集合2 |--... ... --> <!-- 5.企业开发如何选择? - 关系型数据库和非关系型数据库之间并不是替代关系, 而是互补关系 所以在企业开发中大部分情况是结合在一起使用. - 对于数据模型比较简单、数据性能要求较高、数据灵活性较强的数据, 我们存储到非关系型数据库中 相反则存储到关系型数据库中 - 具体使用: 会在项目中实现 --> [代码] 快速上手 [代码]<!-- https://docs.mongodb.com/manual/ https://www.mongodb.org.cn/tutorial/ 1.连接MongoDB服务器 通过mongo连接MongoDB服务器 2.查看数据库 show dbs #和MySQL中的 show databases; 指令一样 3.创建数据库 use 数据库名称 #和MySQL中的 use 指令一样, 只不过MongoDB中的use数据库不存在会自动创建 4.查看数据库中有哪些集合 show collections #和MySQL中的 show tables; 指令一样 5.创建集合 db.createCollection('集合名称'); #和MySQL中的 create table xxx(); 指令一样 6.插入数据 db.集合名称.insert(文档对象); #和MySQL中的 insert into xxx values () 指令一样 7.查询数据 db.集合名称.find(); #和MySQL中的 select * from xxx; 指令一样 8.删除集合 db.集合名称.drop() #和MySQL中的 drop table xxx; 指令一样 9.删除数据库 db.dropDatabase() #在哪个数据库中就会删除哪个数据库 #和MySQL中的 drop database xxx; 指令一样 10.和MySQL的不同 - 没有MySQL中表的概念, 取而代之的是集合 - 创建集合时不用指定集合中有哪些字段 - 只要是一个合法的文档对象都可以往里面存储 - ... ... --> [代码] 主键 [代码]<!-- 1.主键 - MongoDB的主键和MySQL一样, 也是用于保证每一条数据唯一性的 - 和MySQL不同的是, MongoDB中的主键无需明确指定 + 每一个文档被添加到集合之后, MongoDB都会自动添加主键 + MongoDB中文档主键的名称叫做 _id - 默认情况下文档主键是一个ObjectId类型的数据 + ObjectId类型是一个12个字节字符串(5e8c5ae9-c9d35e-759b-d6847d) + 4字节是存储这条数据的时间戳 + 3字节的存储这条数据的那台电脑的标识符 + 2字节的存储这条数据的MongoDB进程id + 3字节是计数器 2.为什么要使用ObjectId类型数据作为主键? 因为MongoDB是支持'横向扩展'的数据库 - 横向扩展是指'增加数据库服务器的台数' - 纵向扩展是指'增加数据库库服务器的配置' - 过去一个数据库只能安装在一台电脑上, 但是每台电脑的性能是有峰值的 一旦达到峰值就会导致服务器卡顿、宕机、重启等问题. 所以过去为了防止如上问题的出现,我们只能不断的'纵向扩展' 也就是不断的提升服务器的配置, 让服务器能处理更多的请求 但是纵向扩展也是有峰值的, 一台电脑的配置不可能无限提升 所以为了解决这个问题就有了分布式数据库 - 分布式数据库是指可以在多台电脑上安装数据库, 然后把多台电脑组合成一个完整的数据库, 在分布式数据库中,我们可以通过不断同步的方式, 让多台电脑都保存相同的内容 当用户请求数据时, 我们可以把请求派发给不同的数据库服务器处理 当某一台服务器宕机后, 我们还可以继续使用其它服务器处理请求 从而有效的解决了单台电脑性能峰值和单台电脑宕机后服务器不能使用的问题 2.2为什么要使用ObjectId类型数据作为主键? 正是因为MongoDB是一个分布式数据库, 正是因为分布式数据库可以把请求派发给不同的服务器 所以第一次插入数据时, 我们可能派发给了A服务器, 插入到了A服务器的数据库中 但是第二次插入数据时, 我们又可能派发给了B服务器, 插入到了B服务器的数据库中 但是B服务器此时并不知道A服务器当前的主键值是多少, 如果通过MySQL中简单的递增来保证数据的唯一性 那么将来在多台服务器同步数据的时候就会出现重复的情况, 所以MongoDB的主键并没有使用简单的递增 而是使用了ObjectId类型数据作为主键 3.是否支持其它类型数据作为主键? 3.1在MongoDB中支持除了'数组类型'以外的其它类型数据作为主键 3.2在MongoDB中甚至还支持将一个文档作为另一个文档的主键(复合主键) db.person.insert({name: 'lnj', age: 33}); db.person.insert({_id: 1, name: 'lnj', age: 33}); #db.person.insert({_id: 1, name: 'lnj', age: 33}); #报错 db.person.insert({_id: '1', name: 'lnj', age: 33}); db.person.insert({_id: {name:'it66', gender: '男'}, name: 'lnj', age: 33}); #db.person.insert({_id: {name:'it66', gender: '男'}, name: 'lnj', age: 33}); #报错 db.person.insert({_id: {gender: '男', name:'it66'}, name: 'lnj', age: 33}); --> [代码] 创建文档 [代码]<!-- 1.主键 - MongoDB的主键和MySQL一样, 也是用于保证每一条数据唯一性的 - 和MySQL不同的是, MongoDB中的主键无需明确指定 + 每一个文档被添加到集合之后, MongoDB都会自动添加主键 + MongoDB中文档主键的名称叫做 _id - 默认情况下文档主键是一个ObjectId类型的数据 + ObjectId类型是一个12个字节字符串(5e8c5ae9-c9d35e-759b-d6847d) + 4字节是存储这条数据的时间戳 + 3字节的存储这条数据的那台电脑的标识符 + 2字节的存储这条数据的MongoDB进程id + 3字节是计数器 2.为什么要使用ObjectId类型数据作为主键? 因为MongoDB是支持'横向扩展'的数据库 - 横向扩展是指'增加数据库服务器的台数' - 纵向扩展是指'增加数据库库服务器的配置' - 过去一个数据库只能安装在一台电脑上, 但是每台电脑的性能是有峰值的 一旦达到峰值就会导致服务器卡顿、宕机、重启等问题. 所以过去为了防止如上问题的出现,我们只能不断的'纵向扩展' 也就是不断的提升服务器的配置, 让服务器能处理更多的请求 但是纵向扩展也是有峰值的, 一台电脑的配置不可能无限提升 所以为了解决这个问题就有了分布式数据库 - 分布式数据库是指可以在多台电脑上安装数据库, 然后把多台电脑组合成一个完整的数据库, 在分布式数据库中,我们可以通过不断同步的方式, 让多台电脑都保存相同的内容 当用户请求数据时, 我们可以把请求派发给不同的数据库服务器处理 当某一台服务器宕机后, 我们还可以继续使用其它服务器处理请求 从而有效的解决了单台电脑性能峰值和单台电脑宕机后服务器不能使用的问题 2.2为什么要使用ObjectId类型数据作为主键? 正是因为MongoDB是一个分布式数据库, 正是因为分布式数据库可以把请求派发给不同的服务器 所以第一次插入数据时, 我们可能派发给了A服务器, 插入到了A服务器的数据库中 但是第二次插入数据时, 我们又可能派发给了B服务器, 插入到了B服务器的数据库中 但是B服务器此时并不知道A服务器当前的主键值是多少, 如果通过MySQL中简单的递增来保证数据的唯一性 那么将来在多台服务器同步数据的时候就会出现重复的情况, 所以MongoDB的主键并没有使用简单的递增 而是使用了ObjectId类型数据作为主键 3.是否支持其它类型数据作为主键? 3.1在MongoDB中支持除了'数组类型'以外的其它类型数据作为主键 3.2在MongoDB中甚至还支持将一个文档作为另一个文档的主键(复合主键) db.person.insert({name: 'lnj', age: 33}); db.person.insert({_id: 1, name: 'lnj', age: 33}); #db.person.insert({_id: 1, name: 'lnj', age: 33}); #报错 db.person.insert({_id: '1', name: 'lnj', age: 33}); db.person.insert({_id: {name:'it66', gender: '男'}, name: 'lnj', age: 33}); #db.person.insert({_id: {name:'it66', gender: '男'}, name: 'lnj', age: 33}); #报错 db.person.insert({_id: {gender: '男', name:'it66'}, name: 'lnj', age: 33}); --> <!-- 1.写入一个文档 db.<collection>.insertOne( <document>, { writeConcern: <document> } ); document: 需要写入的文档 writeConcern: 写入安全级别 2.安全级别 用于判断数据是否写入成功, 安全级别越高, 丢失数据风险越小, 但是性能消耗(操作延迟)也就越大 默认情况下MongoDB会开启默认的安全些级别,先不用关心 3.注意点 在使用insertXXX写入文档时, 如果调用insertOne的集合不存在会自动创建 db.person.insertOne({name:'zs', age:18}) db.person.find() db.student.insertOne({name:'zs', age:18}) #集合不存在会自动创建 db.student.find() 4.其它方式 db.<collection>.save( <document>, { writeConcern: <document> } ); db.person.save({name:'ls', age:19}) db.person.find() db.teacher.save({name:'ls', age:19}) #集合不存在会自动创建 db.teacher.find() 5.insertOne和save不同 主键冲突时insertOne会报错,而save会直接用新值覆盖久值 db.person.insertOne({_id:1, name:'ww', age:22}) db.person.find() db.person.insertOne({_id:1, name:'ww', age:22}) #报错 db.person.save({_id:1, name:'it666', age:66}) #用新数据替换久数据 db.person.find() --> <!-- 1.写入多个文档 db.<collection>.insertMany( [<document>, ...], { writeConcern: <document>, ordered: <boolean> } ); ordered: 是否按顺序写入 ordered默认取值是true, 也就是会严格按照顺序写入 如果ordered是false, 则不会按照顺序写入, 但写入效率更高(系统会自动优化) db.person.insertMany( [{name:'zs', age:18},{name:'ls', age:19},{name:'ww', age:20}], {} ) db.person.find() 2.注意点: 如果ordered是true, 前面的文档出错, 后面的所有文档都不会被写入 如果ordered是false, 前面的文档出错, 后面的所有文档也会被写入 db.person.insertMany( [{_id:1, name:'zs', age:18},{_id:1, name:'ls', age:19},{_id:2, name:'ww', age:20}], { ordered: true } ) db.person.find() db.person.remove({}) db.person.insertMany( [{_id:1, name:'zs', age:18},{_id:1, name:'ls', age:19},{_id:2, name:'ww', age:20}], { ordered: false } ) db.person.find() --> <!-- 1.写入一个或多个文档 db.<collection>.insert( <document> or ,[<document>, ...] { writeConcern: <document>, ordered: <boolean> } ); insertOne和insertMany结合体 2.注意点: 和insertOne/insertMany一样, 集合不存在会自动创建 和insertOne/insertMany一样, 主键冲突会报错 和insertMany一样, 默认都是按顺序插入, 前面的文档出错, 后续所有文档不会被插入 --> [代码] 读取文档 查询文档 [代码]<!-- 1.查询文档 db.<collection>.find( <query>, <projection> ) query: 查询条件, 相当于MySQL中的where projection: 投影条件, 规定了结果集中显示那些字段, 相当于MySQL中的 select 字段1, 字段2, .. from 表名; 2.查询所有文档 db.<collection>.find(); 不传入条件, 默认就是查询所有 3.查询满足条件文档 db.person.insert([{name:'zs', age:17},{name:'ls', age:18},{name:'ww', age:19}]) 3.1单个字段条件 db.person.find() // 默认会返回指定集合中所有的数据和所以的字段 db.person.find({name:'zs'}) // 我们可以通过第一个参数指定查询条件, find方法会把所有满足条件的数据返回给我们 3.2多个字段条件 db.person.find({name:'zs', age:17}) // 默认是And关系, 也就是默认要求同时满足所有指定的条件, 才会返回对应的数据 db.person.find({age:17, name:'zs'}) // 注意点: 没有顺序要求, 只要是同时满足多个条件即可 3.3文档中又是文档情况 db.person.insert( [{name:'zs', age:17, book:{name:'HTML', price:66}}, {name:'ls', age:18, book:{name:'JavaScript', price:88}}, {name:'ww', age:19, book:{name:'Vue', price:199}}] ) db.person.find({'book.name':'JavaScript'}) // 如果某一个文档的某一个字段的取值又是一个文档, 那么在判断的时候我们可以通过'字段.文档属性名称'的方式来判断 4.查询指定字段 0表示不显示, 1表示显示 除主键以外, 其它字段不能同时出现0和1(要么不写,写了就必须全是1或者全是0) db.person.find({},{_id:0}) // 如果不想查询某一个字段, 那么就可以指定这个字段的投影取值为0 db.person.find({},{_id:0, name:1, age:1, book:1}) // 如果想查询某一个字段, 那么就可以指定这个字段的投影取值为1 // 默认情况下如果不指定, 那么所有字段的投影取值都是1 db.person.find({},{_id:0, name:1, age:1, book:0}) // 除了_id字段以外, 其它的字段不能同时出现0和1 db.person.find({},{_id:0, book:0}) --> [代码] 比较运算符 [代码]<!-- 1.比较操作符 和MySQL一样, MongodDB中也支持很多比较操作符 $eq: 等于 / $ne: 不等于 $gt: 大于 / $gte: 大于等于 $lt: 小于 / $lte: 小于等于 2.使用格式 db.<collection>.find( {<field>: {$<operator>: <value>}}, <projection> ) 3.示例 db.person.insert([{name:'zs', age:17, gender:'男'},{name:'ls', age:18},{name:'ww', age:19}]) 查询名称叫做zs的人 查询所有成年人 查询所有未成年人 查询所有不是18岁的人 db.person.find({name:'zs'}) //默认情况下就是按照相等来判断 db.person.find({name:{$eq:'zs'}}) //这里就是明确的告诉MongoDB需要按照相等来查询 db.person.find({age:{$gte: 18}}) db.person.find({age:{$lt: 18}}) db.person.find({age:{$ne: 18}}) 注意点: 没有指定字段也算作不等于 db.person.find({gender:{$ne: '女'}}) // 注意点: 在做不等于判断的时候, 没有需要判断的字段, 也算作是不等于 --> <!-- 1.其它比较操作符 $in: 匹配和任意指定值相等的文档 $nin:匹配和任意指定值都不相等的文档 2.使用格式 db.<collection>.find( {<field>: {$<operator>: [<value1>, <value2>, ...]}}, <projection> ) 3.实例 查询名称叫做zs或者ls的人 查询名称不叫zs或者ls的人 查询性别不是男或女的人 db.person.find({name:{$in:['zs', 'ls']}}) // 匹配和任意指定值相等的文档 db.person.find({name:{$nin:['zs', 'ls']}}) // 匹配和任意指定值都不相等的文档 db.person.find({gender:{$nin:['男', '女']}}) // 注意点: 和$ne一样, 如果没有需要判断的字段, 也算作满足条件 注意点: 没有指定字段也算作不包含 --> [代码] 逻辑操作符 [代码]<!-- 1.逻辑操作符 $not: 匹配条件不成立的文档 {<field>: {$not: {<expression>}}} $and: 匹配条件全部成立的文档 {<field>: {$and: [{<expression1>}, {<expression2>}, ...}]} $or : 匹配至少一个条件成立的文档 {<field>: {$or: [{<expression1>}, {<expression2>}, ...}]} $nor: 匹配多个条件全部不成立的文档 {<field>: {$nor: [{<expression1>}, {<expression2>}, ...}]} 2.示例: //2.1$not //查询所有年龄不等于18岁的人 db.person.find({age:{$ne:18}}) db.person.find({age:{$not:{$eq:18}}}) //查询不是男人的人 db.person.find({gender:{$eq:'男'}}) // 注意点: $not运算符和$ne/$nin一样, 如果需要查询的字段不存在, 也会算作条件成立 db.person.find({gender:{$not:{$eq:'男'}}}) //2.2$and //查询所有名称叫做zs的未成年人 db.person.find({$and:[{name:{$eq:'zs'}},{age:{$lt:18}}]}) db.person.find({$and:[{name:'zs'},{age:{$lt:18}}]}) db.person.find({name:'zs', age:{$lt:18}}) //2.3$or //查询所有名称叫做zs或者ls的人 db.person.find({name:{$in:['zs','ls']}}) db.person.find({$or:[{name:{$eq:'zs'}},{name:{$eq:'ls'}}]}) db.person.find({$or:[{name:'zs'},{name:'ls'}]}) //2.4$nor //查询所有名称不叫zs或者ls的人 db.person.find({name:{$nin:['zs','ls']}}) db.person.find({$nor:[{name:'zs'},{name:'ls'}]}) //查询所有名称不叫zs或者性别不是男的人 // 注意点: $nor运算符和$ne/$nin/$not一样, 如果需要查询的字段不存在, 也会算作条件成立 db.person.find({$nor:[{gender:'男'}]}) --> [代码] 字段操作符 [代码]<!-- 1.字段操作符 $exists: 查询包含某个字段的文档 {<field>: {$exists: <boolean>}} $type: 查询指定字段包含指定类型的文档 {<field>: {$type: <BSON> or [<BSON1>, <BSON2>]}} 2.查询包含字段gender的人 db.person.insert([ {name:'zs', age:17, gender:'男'}, {name:'ls', age:18}, {name:'ww', age:19}, {name:'it666', age:20, gender:'女'} ]) // 需求: 要求查询出所有拥有gender属性的文档 db.person.find({gender:{$exists: true}}) 3.应用场景: // 应用场景: 配合$ne/$nin/$nor/$not来清理数据 db.person.find({gender:{$ne:'男'}}) db.person.find({gender:{$ne:'男', $exists:true}}) 4.查询所有年龄是字符串类型的文档 db.person.insert([ {name:'itzb', age:'666'}, {name:'lnj', age:'888'}, ]) // 需求: 要求查询出所有age属性的取值是字符串类型的文档 db.person.find({age:{$type:'string'}}) --> [代码] 数组操作符 [代码]<!-- 1.数组操作符 $all : 匹配数组中包含所有指定查询值的文档 {<field>: {$all: [<value1>, <value2>, ...]}} $elemMatch: 匹配数组中至少有一个能完全匹配所有的查询条件的文档 {<field>: {$elemMatch: {<query1>, <query2>, ...}}} 2.示例 查询tags中同时拥有html和js的文档 db.person.insert([ {name: 'zs', tags:['html', 'js', 'vue']}, {name: 'ls', tags:['html', 'react', 'vue']}, {name: 'ww', tags:['html', 'node', 'js']}, ]) db.person.find({tags:{$all:['html', 'js']}}) 查询所有名称叫做zs,年龄是18岁的文档 db.school.insert([ {class: 'one', students: [ {name:'zs', age: 18}, {name:'ls', age: 19}, {name:'ww', age: 20}, ]}, {class: 'two', students: [ {name:'zs', age: 20}, {name:'ls', age: 19}, {name:'ww', age: 18}, ]}, ]) db.school.find({'studnets.name':'ww', 'studnets.age':18}) db.school.find({studnets:{$elemMatch:{name:'ww',age:18}}}) --> [代码] 运算操作符:正则表达式 [代码]<!-- 1.运算操作符 { <field>: { $regex: /pattern/, $options: '<options>' } } { <field>: { $regex: /pattern/<options> } } 查询满足正则的文档 2.示例 db.person.insert([ {name:'zs', age:18}, {name:'ls', age:19}, {name:'ww', age:17}, {name:'Zsf', age:18}, {name:'Lnj', age:19}, {name:'Wz', age:17} ]) // 需求: 要求查询出所有姓z的人(文档) db.person.find({name:{$regex:/^z/, $options: 'i'}}) // 需求: 要求查询出所有姓是z或者l的人(文档) db.person.find({name:{$in:[/^z/i, /^l/i]}}) --> [代码] 文档游标 [代码]<!-- 1.文档游标 1.1为什么学习前端都要学习MongoDB? 因为MongoDB原生就支持JavaScript, 也就是我们可以直接在MongoDB中混入JS代码 1.2什么是文档游标 我们执行find方法后, find方法其实是有返回值的, find方法会返回一个文档游标(相当于C语言指针) 1.3文档游标常用方法 hasNext(): 是否还有下一个文档 next(): 取出下一个文档 forEach(): 依次取出所有文档 1.4文档游标注意点 默认情况下通过文档游标遍历完所有文档后, 系统会在10分钟后自动关闭当前游标 如果不想自动关闭, 我们可以通过noCursorTimeout函数来保持游标一直有效 let cursor = db.person.find().noCursorTimeout() 如果想手动关闭游标, 我们也可以通过close函数来手动关闭游标 cursor.close() 2.示例 // 需求: 往person集合中插入100个文档 var arr =[]; for(var i = 0; i < 100; i++){ arr.push({name:'it'+i, age:18+i}); } db.person.insertMany(arr) var cursor = db.person.find().noCursorTimeout() //cursor[0] //cursor[1] while(cursor.hasNext()){ printjson(cursor.next()) } cursor.forEach(printjson) cursor.close() --> [代码] 分页方法 [代码]<!-- 1.分页方法 cursor.limit(<number>): 取多少个文档 cursor.skip(<offset>) : 跳过多少个文档 2.示例 //var cursor = db.person.find() // 需求: 要求取出前5个文档 //cursor.limit(5) // 需求: 要求跳过前面的5个文档, 取出剩余的所有 //cursor.skip(5) // 注意点: 我们可以直接在find方法后面调用limit方法或者skip方法 //db.person.find().limit(5) //db.person.find().skip(5) 3.分页函数注意点 // 注意点: MongoDB是支持链式调用的 // 需求: 跳过前面5个文档, 取出后面的5个文档 //db.person.find().skip(5).limit(5) // 注意点:在链式调用的时候, 无论skip写在前面还是后面, 都会在limit之前执行 db.person.find().limit(5).skip(10) --> [代码] 排序函数 [代码]<!-- 1.排序函数 cursor.sort({field: ordering, ...}): 按照指定规则排序 ordering为1表示升序排序 ordering为-1表示降序排序 2.示例 // 注意点: 默认情况下find方法只会返回100个文档 db.person.find() db.person.insert({name:'itzb', age:15}) db.person.find().limit(101) db.person.find().sort({age:1}) db.person.find().sort({age:-1}) 3.注意点 3.1find方法默认只会取出100个文档 3.2sort函数永远在分页函数之前执行 db.person.find().skip(5).limit(5) db.person.find().skip(5).limit(5).sort({age:-1}) --> [代码] 统计函数 [代码]<!-- 1.统计函数 cursor.count(<applySkipLimit>): 统计集合中文档的个数 applySkipLimit默认为false, 表示忽略skip和limit 2.示例 db.person.find().count() // 注意点: count函数可以接收一个applySkipLimit参数, 通过这个参数可以告诉MongoDB在统计的时候是否需要忽略Skip和Limit // 默认情况下applySkipLimit的取值是false, 表示忽略Skip和Limit db.person.find().skip(6).count() db.person.find().limit(5).count() db.person.find().skip(6).count({applySkipLimit:true}) db.person.find().limit(5).count({applySkipLimit:true}) 2.统计函数注意点 在find函数不提供筛选条件时, count函数会从集合的元数据中取得结果 在单台电脑上是这个结果是准确的, 但是如果数据库为分布式结构(多台电脑)时, 如果不给find函数提供筛选条件, 那么count函数返回的结果并不一定准确 --> [代码] 更新文档 save方法 [代码]<!-- 1.更新文档 MongoDB中有三个常用的更新方法: save()/update()/findAndmodify() 2.save方法 save用于往集合里添加一个新文档或者覆盖文档 当没有指定文档_id的时候就是新增 当指定了集合中已经存在的_id的时候就是覆盖 3.示例 db.person.insert([ {name:'zs', age:18}, {name:'ls', age:19}, {name:'ww', age:20}, {name:'zs', age:21}, ]) --> [代码] update方法 [代码]<!-- 1.update方法 db.collection.update(<filter>, <update>, <options>) <filter>: 筛选条件 <update>: 新的内容 <options>: 额外配置 2.通过update覆盖满足条件数据 默认情况下如果<update>没有使用更新操作符, 那么就会使用指定的内容覆盖符合条件的内容 3.示例: db.person.update({name:'lnj'}, {name:'zs'}) 4.注意点: // 注意点: update方法默认情况下就是覆盖 // 如果不想覆盖, 而是想单纯的更新, 那么就必须在第二个参数中使用'更新操作符' db.person.update({name:'ww'},{score: 99.9},{}) // 注意点: update方法默认只会更新满足条件的第一个文档 // 如果想更新所有满足条件的文档, 那么就必须指定第三个参数 db.person.update({name:'zs'}, {name:'zs', age:55}, {}) // 注意点: 如果在使用update方法的时候, 在第二个参数中指定了_id, 那么就必须保证指定的_id和被更新的文档的_id的取值一致 // 否则就无法更新, 否则就会报错 // 开发技巧: 在企业开发中如果需要使用update方法, 那么就不要指定_id db.person.update({name:'zs'}, {_id:1, name:'zs', age:55}, {}) db.person.update({name:'zs'}, {_id:ObjectId("5e9007350718cb6e37ab4515"), name:'zs', age:88}, {}) // 注意点: 如果想更新所有满足条件的文档, 我们可以指定第三个参数的取值multi:true // 注意点: 如果指定了multi:true, 那么就必须在第二个参数中使用'更新操作符' db.person.update({name:'zs'}, {name:'zs', age:55}, {multi:true}) --> [代码] $set更新操作符 [代码]<!-- 1.更新操作符 默认情况下update会使用新文档覆盖旧文档 如果不想覆盖而是仅仅想更新其中的某些字段 那么我们就需要使用update的更新操作符 2.$set更新操作符 $set: 更新或者新增字段, 字段存在就是更新, 字段不存在就是新增 格式: {$set:<value1>, ...} 3.示例: db.person.update({name:'zs'}, {$set:{name:'itzb'}}) db.person.update({name:'itzb'}, {$set:{age:'888'}}) 4.更新内嵌文档和数组 db.person.insert([ {name:'zs', age:18}, {name:'ls', age:19}, {name:'ww', age:20}, {name:'zs', age:21}, ]) db.person.update({name:'ww'}, {age:55}) // 更新普通字段 db.person.update({name:'ls'}, {$set:{age:55}}) db.person.update({name:'zs'}, {$set:{age:88}}, {multi:true}) db.person.insert( { name:'ww', age:18, book:{name:'跟着江哥学编程', price:2888}, tags:['html', 'JavaScript']} ) // 更新文档字段 db.person.update({name:'ww'}, {$set:{'book.name': 'it666.com'}}) // 更新数组字段 db.person.update({name:'ww'}, {$set: {'tags.0': 'vue'}}) 5.注意点: // 注意点: 如果操作的字段存在, 那么就是更新, 如果操作的字段不存在, 那么就是新增 db.person.update({name:'ls'}, {$set:{score: 59.5}}) // 注意点: 如果操作的是数组字段, 如果操作索引不存在, 那么也会自动新增 // 如果被操作的索引前面没有数据, 那么会自动用null来填充 db.person.update({name:'ww'}, {$set: {'tags.2': 'react'}}) db.person.update({name:'ww'}, {$set: {'tags.5': 'node'}}) --> [代码] $unset更新操作符 [代码]<!-- 1.$unset更新操作符 $unset: 删除字段 格式 :{$unset:{<field>:'', ...}} 2.示例: // 删除普通字段 db.person.update({name:'ls'}, {$unset:{score:''}}) // 注意点: 如果使用$unset删除某一个字段, 那么后面赋值为任何的内容都不重要 db.person.update({name:'ls'}, {$unset:{age:'www.it666.com'}}) // 删除文档字段中的字段 db.person.update({name:'ww'}, {$unset:{'book.price': ''}}) // 删除数组字段中的元素 // 注意点: 如果删除的是数组字段中的元素, 那么并不会修改数组的长度, 而是用null来填充删除的内容 db.person.update({name:'ww'}, {$unset:{'tags.1': ''}}) 3.注意点: 3.1删除数组元素并不会影响数组的长度, 而是设置为Null 3.2如果删除的字段不存在, 不会做任何操作 --> [代码] $rename重命名操作 [代码]<!-- 1.$rename更新操作符 $rename: 重命名字段 格式 :{$rename:{<field>:<newName>, ...}} 2.示例 db.person.update({name:'zs'}, {$rename:{name:'MyName'}}) // 注意点: 如果修改的是文档字段中的字段, 那么取值必须写上层级关系 db.person.update({name:'ww'}, {$rename:{'book.name':'book.BookName'}}) // 注意点: 如果要操作的字段不存在, 那么不会做任何的操作 db.person.update({name:'ls'}, {$rename:{age:'MyAge'}}) // 注意点: 如果重命名之后的名称已经存在了, 那么已经存在的字段就会被删除 // 底层的本质: 先调用了$unset删除了原有的book字段, 然后再调用$set修改字段的名称 db.person.update({name:'ww'}, {$rename:{name:'book'}}) // 注意点: 不能通过$rename更新操作符来操作数组 db.person.insert( { name:'it666', age:666, book:{name:'知播渔', price:999}, tags:[{name:'html', price:'123'}, {name:'js', price:456}] } ) db.person.update({name:'it666'}, {$rename:{'tags.0.name':'tags.0.TagName'}}) 4.乾坤大挪移 // 可以将外层的字段转移到内层的文档中 db.person.update({name:'it666'}, {$rename:{age:'book.age'}}) db.person.find() // 可以将内存文档中的字段, 转移到外层文档中 db.person.update({name:'it666'}, {$rename:{'book.age':'age'}}) --> [代码] $inc$mul更新操作符 [代码]<!-- 1.$inc和$mul更新操作符 $inc:更新字段值(增加或者减少字段保存的值) 格式: {$inc:{<field>: <number>}} $mul:更新字段值(乘以或者除以字段保存的值) 格式: {$mul:{<field>: <number>}} 2.示例 db.person.update({name:'lnj'}, {$inc:{age:2}}) db.person.update({name:'lnj'}, {$inc:{age:-5}}) db.person.update({name:'lnj'}, {$mul:{age:0.5}}) db.person.update({name:'lnj'}, {$mul:{age:2}}) 3.注意点: 3.1只能操作数字类型字段 3.2如果操作的字段不存在, 会自动新增这个字段 不同的是$inc会把操作的值赋值给新增的字段, 而$mul会自动赋值为0 db.person.update({name:'lnj'}, {$inc:{weight:2}}) db.person.update({name:'lnj'}, {$mul:{height:2}}) --> [代码] $max$min更新操作符 [代码]<!-- 1.$min和$max更新操作符 $min:比较保留更小字段值 格式: {$min:{<field>: <value>}} $max:比较保留更大字段值 格式: {$max:{<field>: <value>}} 2.示例 db.person.insert({name:'lnj', age:33}) db.person.update({name:'lnj'}, {$min:{age:50}}) db.person.update({name:'lnj'}, {$min:{age:18}}) db.person.update({name:'lnj'}, {$max:{age:5}}) db.person.update({name:'lnj'}, {$max:{age:55}}) 3.注意点: // 注意点: 如果操作的字段不存在, 那么会自动增加, 并且会将操作的值赋值给新增的字段 db.person.update({name:'lnj'}, {$min:{weight:120}}) db.person.update({name:'lnj'}, {$max:{height:175}}) // 注意点: 和$inc/$mul不同, $min/$max不仅仅能操作数值类型的字段, 只要是可以比较的字段都可以操作 db.person.insert({name:'def', age:666}) db.person.update({name:'def'}, {$min:{name:'efg'}}) db.person.update({name:'def'}, {$min:{name:'cde'}}) // 注意点: 不是相同的数据类型也可以进行比较 db.person.update({name:'lnj'}, {$min:{age:null}}) MongoDB对BSON的数据类型有一个潜在的排序规则 Null Numbers(ints, longs, doubles, decimals) Symbol, String Object Array BinData ObjectId Boolean Date Timestamp Regular Expression --> [代码] $addToSet数组更新操作符 [代码]<!-- 1.$addToSet数组更新操作符 $addToSet: 向数组字段中添加元素 格式 : {$addToSet: {<field>:<values>, ...}} 2.示例 db.person.insert([ {name:'zs', books:[{name:'html', price:66}, {name:'js', price:88}], tags:['html', 'js']}, {name:'ls', books:[{name:'vue', price:99}, {name:'node', price:199}], tags:['vue', 'node']} ]) db.person.update({name:'zs'}, {$addToSet:{tags:'react'}}) 3.注意点 // 注意点:如果操作的元素不存在, 那么会自动新增, 并且将操作的值赋值给新增的数组字段 db.person.update({name:'zs'}, {$addToSet:{other:'123'}}) // 注意点: $addToSet会自动去重, 如果添加的元素已经存在了, 那么就不会添加了 db.person.update({name:'zs'}, {$addToSet:{other:'123'}}) // 注意点: 如果往数组字段中添加的是文档类型, 那么必须一模一样才会去重 db.person.update({name:'zs'}, {$addToSet:{books:{name:'html', price:66}}}) db.person.update({name:'zs'}, {$addToSet:{books:{price:66, name:'html'}}}) // 注意点: 如果往数组字段中添加的是数组, 那么也必须一模一样才会去重 db.person.update({name:'ls'}, {$addToSet:{tags:['1', '2']}}) db.person.update({name:'ls'}, {$addToSet:{tags:['1', '2']}}) db.person.update({name:'ls'}, {$addToSet:{tags:['2', '1']}}) // 注意点: 如果往往数组字段中添加的是数组, 那么默认情况下会将整个数组作为一个元素添加进去 // 如果不想诶一个整体添加进去,那么必须使用$each来添加 db.person.update({name:'ls'}, {$addToSet:{tags:{$each: ['1', '2', '3']}}}) --> [代码] $push更新操作符 [代码]<!-- 1.$push数组更新操作符 $push: 向数组字段中添加元素(不去重) 格式 : {$push: {<field>:<value1>, ...}} --> <!-- 1.$pop数组更新操作符 $pop: 从数组字段中删除元素 格式: {$pop: {<field>:<1|-1>, ...}} 2.示例 db.person.update({name:'zs'}, {$pop:{tags:1}}) #删除最后一个 db.person.update({name:'zs'}, {$pop:{tags:-1}})#删除第一个 3.注意点 数组中的元素都被删除以后, 仍然会保留空的数组 --> [代码] $pull更新操作符 [代码]<!-- 1.$pull数组更新操作符 $pull: 从数组字段中删除特定元素 格式: {$pull: {<field>:<value|condition>, ...}} 2.示例 db.person.insert([ {name:'zs', books:[{name:'html', price:66}, {name:'js', price:88}], tags:['html', 'js', ['1', '2']]}, {name:'ls', books:[{name:'vue', price:99}, {name:'node', price:199}], tags:['a', 'b', 'ab', 'c', 'ac']} ]) 删除特定元素 根据条件删除元素 db.person.update({name:'zs'}, {$pull:{tags:'js'}}) db.person.update({name:'ls'}, {$pull:{tags:/^a/}}) 3.注意点 // 注意点: 如果要删除的元素是一个数组, 那么必须一模一样才能删除 db.person.update({name:'zs'}, {$pull:{tags:['2', '1']}}) db.person.update({name:'zs'}, {$pull:{tags:['1', '2']}}) // 注意点: 如果要删除的元素是一个文档, 那么不用一模一样也可以删除 db.person.update({name:'zs'}, {$pull:{books:{price:66, name:'html'}}}) db.person.update({name:'zs'}, {$pull:{books:{name:'js'}}}) --> [代码] $pullAll更新操作符 [代码]<!-- 1.$pullAll数组更新操作符 $pullAll: 从数组字段中批量删除特定元素 格式: {$pullAll: {<field>: [<value1>, <value2>, ...], ...}} 2.示例 db.person.insert([ {name:'zs', books:[{name:'html', price:66}, {name:'js', price:88}], tags:['html', 'js', ['1', '2']]}, {name:'ls', books:[{name:'vue', price:99}, {name:'node', price:199}], tags:['a', 'b', 'ab', 'c', 'ac']} ]) db.person.update({name:'zs'}, {$pullAll:{tags:['html', 'js']}}) 3.注意点 // 注意点: 和$pull一样, 如果删除的是数字字段中的数组元素, 那么必须一模一样才能删除 db.person.update({name:'zs'}, {$pullAll:{tags:[['2','1']]}}) db.person.update({name:'zs'}, {$pullAll:{tags:[['1','2']]}}) // 注意点: 和$pull不一样, 如果删除的是数组字段中的文档元素, 那么也必须一模一样才能删除 db.person.update({name:'zs'}, {$pullAll:{books:[{price:66,name:'html'}]}}) db.person.update({name:'zs'}, {$pullAll:{books:[{name:'html',price:66}]}}) --> [代码] $和$[]更新操作符 [代码]<!-- 1.$和$[]数组更新操作符 $ : 更新数组中满足条件的特定元素 格式: db.<collection>.update( { <array field>:<query selector> } { <update operator>: {'<array field>.$':value}} ) $[]: 更新数组中所有元素 db.<collection>.update( { <update operator>: {'<array field>.$[]':value}} ) 2.示例 db.person.insert([ {name:'zs', books:[{name:'html', price:66}, {name:'js', price:88}], tags:['html', 'js', ['1', '2']]}, {name:'ls', books:[{name:'vue', price:99}, {name:'node', price:199}], tags:['a', 'b', 'ab', 'c', 'ac']} ]) db.person.find() db.person.update( {name:'zs', tags:'js'}, {$set:{'tags.$':'JavaScript'}} ) db.person.update( {name:'zs'}, {$set:{'tags.$[]': 'it666'}} ) --> [代码] 删除文档 [代码]<!-- 1.删除文档 db.<collection>.remove(<query>, <options>) <query>: 删除筛选条件 <options>: 删除额外配置 2.示例 db.person.insert([ {name:'zs', age:18}, {name:'zs', age:19}, {name:'ls', age:20}, {name:'ls', age:21}, {name:'ww', age:22}, {name:'zl', age:23}, ]) 2.示例 //2.1删除所有满足条件 // 注意点: 和update方法不同, remove方法默认就会删除所有满足条件的数据 db.person.remove({name:'zs'}) //2.2删除第一个满足条件 db.person.remove({name:'ls'},{justOne:true}) //2.3删除所有文档 db.person.remove({}) --> [代码] 聚合操作 $project [代码]<!-- 1.什么是聚合操作? - 聚合操作就是通过一个方法完成一系列的操作 - 在聚合操作中, 每一个操作我们称之为一个阶段, 聚合操作会将上一个阶段处理结果传给下一个阶段继续处理, 所有阶段都处理完毕会返回一个新的结果集给我们 2.聚合操作格式 db.<collection>.aggregate(<pipeline>, <options>) <pipeline>: 定义每个阶段操作 <options> : 聚合操作额外配置 3.聚合管道阶段 $project: 对输入文档进行再次投影 作用 : 按照我们需要的格式生成结果集 格式 : {$project:{<field>:<value>}} 4.示例 db.person.insert([ {name:{firstName:'Jonathan', lastName:'Lee'}, age:18, book:{name:'玩转HTML', price: 88}}, {name:{firstName:'Amelie', lastName:'Jiang'}, age:17, book:{name:'玩转JavaScript', price: 99}} ]) db.person.aggregate([ { $project:{ _id:0, clientName: '$name.firstName', clientAge: '$age' } } ]) 5.聚合表达式 5.1字段路径表达式 $<filed>: 使用$来指示字段路径 $<filed>.<sub-field>: 使用$和.来指示内嵌文档字段路径 5.2字段路径表达式示例 $name $book.name 6.注意点: // 注意点: $project修改的是结果集而不是原有的集合 db.person.find() // 注意点: 如果字段表达式使用了不存在的字段, 那么会自动用Null填充 db.person.aggregate([ { $project:{ _id:0, fullName: ['$name.firstName', '$name.middleName','$name.lastName'], clientAge: '$age' } } ]) --> [代码] $match [代码]<!-- 1.聚合管道阶段 $match: 和find方法中的第一个参数一样, 用于筛选符合条件的文档 格式 : {$match:{<query>}} 2.示例 db.person.aggregate([ { $match:{ 'name.firstName':'Jonathan' } } ]) db.person.aggregate([ { $match:{ 'name.firstName':'Jonathan' } }, { $project:{ _id:0, clientName: '$name.firstName', clientAge: '$age' } } ]) 3.使用技巧: 应该在聚合操作的最前面使用$match, 这样可以有效减少处理文档的数量, 大大提升处理的效率 --> [代码] $limit和$skip [代码]<!-- 1.聚合管道阶段 $limit: 和游标的limit方法一样, 用于指定获取几个文档 格式 : {$limit:<number>} $skip : 和游标的skip方法一样, 用于指定跳过几个文档 格式 : {$skip:<number>} 2.示例 db.person.aggregate([ { $skip:1 }, { $limit:1 }, { $project:{ _id:0, clientName: '$name.firstName', clientAge: '$age' } } ]) --> [代码] $unwind [代码]<!-- 1.聚合管道阶段 $unwind: 展开数组字段 格式 : {$unwind:{path:<field>}} 2.示例: db.person.update({'name.firstName':'Jonathan'}, {$set:{tags:['html', 'js']}}) db.person.update({'name.firstName':'Amelie'}, {$set:{tags:'vue'}}) db.person.aggregate([ { $unwind:{ path:'$tags' } } ]) 3.注意点: 3.1$unwind会为数组中的每个元素创建一个新的文档 3.2可以通过includeArrayIndex属性添加展开之后的元素在原数组中的位置 db.person.aggregate([ { $unwind:{ path:'$tags', includeArrayIndex: 'index' } } ]) 3.3如果需要展开的字段不存在, 或者数组中没有元素, 或者为null, 会被unwind剔除 db.person.insert([ {name:{firstName:'san', lastName:'zhang'}, age:20}, {name:{firstName:'si', lastName:'li'}, age:21, tags:[]}, {name:{firstName:'wu', lastName:'wang'}, age:22, tags:null} ]) 3.4如果想让unwind不剔除不存在/没有元素/为Null的文档, 那么可以添加preserveNullAndEmptyArrays属性 db.person.aggregate([ { $unwind:{ path:'$tags', includeArrayIndex: 'index', preserveNullAndEmptyArrays: true } } ]) --> [代码] $sort [代码]<!-- 1.聚合管道阶段 $sort: 和文档游标sort方法一样, 对文档进行排序 格式 : {$sort:{<field>>:1|-1}} 2.示例 db.person.aggregate([ { $sort:{ age: 1 } } ]) --> [代码] $lookup [代码]<!-- 1.聚合管道阶段 $lookup: 用来做关联查询 格式 : {$lookup:{ from: 关联集合名称, localField: 当前集合中的字段名称, foreignField:关联集合中的字段名称, as: 输出字段的名称 }} 2.示例: db.person.insert([ {name:{firstName:'Jonathan', lastName:'Lee'}, age:18, books:['html', 'js']}, {name:{firstName:'Amelie', lastName:'Jiang'}, age:19, books:['vue']}, {name:{firstName:'si', lastName:'Li'}, age:20, books:[]} ]) db.books.insert([ {name:'html', price:88}, {name:'js', price:99}, {name:'vue', price:110}, ]) db.person.aggregate([ { $lookup:{ from: 'books', localField: 'books', foreignField: 'name', as: 'booksData' } } ]) 3.和unwind阶段结合使用 可以有效的过滤掉无效数据 可以给每个匹配的结果生成一个新的文档 db.person.aggregate([ { $unwind:{ path:'$books' } }, { $lookup:{ from: 'books', localField: 'books', foreignField: 'name', as: 'booksData' } } ]) --> [代码] $lookup相关查询 [代码]<!-- 1.聚合管道阶段 $lookup: 用来做关联查询 格式 : {$lookup:{ from: 关联集合名称, let: {定义给关联集合的聚合操作使用的当前集合的常量}, pipeline: [关联集合的聚合操作] as: 输出字段的名称 }} 2.示例: 不相关查询 db.person.aggregate([ { $lookup:{ from: 'books', pipeline: [ { $match:{ price:{$gte:100} } } ], as: 'booksData' } } ]) 相关查询 db.person.aggregate([ { $lookup:{ from: 'books', let: { bks: '$books'}, pipeline: [ { $match:{ $expr:{ $and:[ {$gte: ['$price', 100]}, {$in: ['$name', '$$bks']} ] } //price:{$gte:100} } } ], as: 'booksData' } } ]) 3系统变量表达式 $$<variable>: 使用$$来指示系统变量 --> [代码] $group [代码]<!-- 1.聚合管道阶段 $group: 对文档进行分组 格式 : {$group:{ _id:<expression>, <field1>: {<accumulator1>: <expression1>} ... ... }} _id: 定义分组规则 <field>: 定义新字段 2.示例 db.person.insert([ {name:'zs', age:10, city:'北京'}, {name:'ls', age:20, city:'上海'}, {name:'ww', age:30, city:'北京'}, {name:'zl', age:40, city:'上海'}, {name:'lnj', age:50, city:'北京'}, {name:'jjj', age:60, city:'广州'}, ]) db.person.aggregate([ {$group:{ _id:'$city', totalAge:{$sum:'$age'}, avgAge:{$avg:'$age'}, minAge:{$min:'$age'}, maxAge:{$max:'$age'}, totalName:{$push:'$name'} }} ]) --> [代码] $out [代码]<!-- 1.聚合管道阶段 $out: 前面阶段处理完的文档写入一个新的集合 格式: {$out: <new collection name>} 2.示例: db.person.aggregate([ { $group:{ _id: '$city', totalAge: {$sum:'$age'}, avgAge: {$avg: '$age'}, minAge: {$min: '$age'}, maxAge: {$max: '$age'}, totalAges: {$push: '$age'} } }, { $out:'newPerson' } ]) db.newPerson.find() 3.注意点: 如果利用$out写入一个已经存在的集合, 那么集合中的原有数据会被覆盖 --> [代码] 配置 [代码]<!-- 1.聚合操作额外配置 db.<collection>.aggregate(<pipeline>, <options>) 格式: {allowDiskUse: <boolean>} allowDiskUse默认取值是false, 默认情况下管道阶段占用的内存不能超过100M,如果超出100M就会报错 如果需要处理的数据比较多, 聚合操作使用的内存可能超过100M, 那么我们可以将allowDiskUse设置为true 如果allowDiskUse设置为true, 那么一旦超出100M就会将操作的数据写入到临时文件中, 然后再继续操作 --> <!-- 1.字段路径表达式 $<filed>: 使用$来指示字段路径 $<filed>.<sub-field>: 使用$和.来指示内嵌文档字段路径 2.示例 $name $book.name 3.系统变量表达式 $$CURRENT: 表示当前操作的文档 4.示例 $$CURRENT.name 等价于 $name 5.常量表达式 $literal:<value> : 表示常量<value> 6.示例 $literal:'$name' : 表示常量字符串$name db.person.insert([ {name:{firstName:'Jonathan', lastName:'Lee'}, age:18}, {name:{firstName:'Amelie', lastName:'Jiang'}, age:19} ]) db.person.find() db.person.aggregate([ {$project:{ _id:0, //myName:'$name.firstName', // 字段路径表达式 //myAge:'$age' // 字段路径表达式 //myName:'$$CURRENT.name.firstName', //系统变量表达式 //myAge:'$$CURRENT.age' // 系统变量表达式 myName:'$name.firstName', myAge:{$literal:'$age'} // 常量表达式 }} ]) --> [代码] 数据类型转换 [代码]<!-- 1.数据类型转换操作符 - MongoDB对于文档的格式并没有强制性的要求, 同一个集合中存储的文档, 字段的个数和数据类型都可以不同 对与文档的格式没有强制性的要求是MongoDB的一大优势, 但是同时也增加了数据消费端的使用难度 因为我们在使用数据的时候, 有可能同一个字段取出来的数据类型是不同的, 这样非常不利于我们后续操作 所以也正是因为如此, MongoDB在4.0中推出了$convert数据类型转换操作符 - 通过$convert数据类型转换操作符, 我们可以将不同的数据类型转换成相同的数据类型, 以便于后续我们在使用数据的过程中能够统一对数据进行处理 2.$convert格式 {$convert:{ input: '需要转换的字段', to: '转换之后的数据类型', onError: '不支持的转换类型', onNull: '没有需要转换的数据' }} 3.示例 db.person.insert([ {name:'zs', timestamp:ISODate('2020-08-09T11:23:34.733Z')}, {name:'ls', timestamp:'2021-02-14 12:00:06 +0800 '}, {name:'ww', timestamp:' 2023-04-01T12:00:00Z'}, {name:'zl', timestamp:'1587009270000'}, {name:'it666', timestamp:'Sunday'}, {name:'itzb'}, ]) db.person.aggregate([ {$project:{ _id:0, timestamp:{ $convert:{ input:'$timestamp', to:'date', onError: '不支持的转换类型', onNull: '没有需要转换的数据' } } }} ]) --> [代码]
2021-11-17