01-vue介绍与小胡子语法
- 配置代码段,网址:snippet-generator.app/
- 搜索:elementui,是一个组件库,可以选择别人封装好的组件用
01-vue初识
官网
-
中文官网: cn.vuejs.org/ 默认是vue3
-
文档读一下:cn.vuejs.org/v2/guide/in… vue2
-
Vue
Vue (读音 /vjuː/,类似于 view),作者: 尤雨溪 构建用户界面渐进式JavaScript框架 是基于HTML,CSS,JS构建的,它提供了一套声明式的,组件化的编程模型。 我们通常所说的Vue是指Vue全家桶(Vue核心+Vue生态)
-
Vue特点:
1)声明式编程,组件化编程,提高开发效率 2)不需要操作DOM,只需要操作数据,数据变了,界面会自动刷新 3)Vue采用了虚拟DOM + 优秀Diff算法
Vue快速入门:
1)先把Vue当成别人封装好的JS库,在项目中直接引用并使用它
快速体验
-
引入Vue的方式:
1)在页面中通过CDN方式引入 2)下载Vue源码,引入我们下载好的源码 3)通过NPM工具,下载引入 4)使用Vue脚手架去引入Vue
-
体验vue
<!-- 引入Vue.js,人家向外暴露一个Vue类 new Vue --> <script src="../lib/vue2.7.8.js"></script> </head> <body> <!-- 定义的容器 --> <!-- 容器也叫模板,也叫视图 --> <div id="app"> <h2>你好, {{ name }} === {{ age }} === {{ sex }}</h2> </div> <script> let vm = new Vue({ // el表示vm实例要与哪个容器进行关联,el对应的值是一个CSS选择器 el:"#app", // data是用来给模板或视图提供数据的 data(){ return { // return中的对象中的写的数据,就是用来给模板提供的数据 // name,age,sex,叫响应式数据,写在data中的数据叫响应式数据 // 所谓的响应式数据,是指数据变了,模板会自动刷新 // 写在data中的所有的数据,都会挂载到vm对象上,成为vm的属性 name:"wc", age:18, sex:"man" } } }); console.log(vm); // 看看是否vm上有name.age.sex // 总结: // 1)vm叫Vue实例 通过new Vue构造器new出来的 对象是属性的无序集合 // 2)new Vue时,传递一个配置对象 el data:给模板提供数据 // 3)响应式数据:数据变了,视图要重新渲染(自动刷新) // 4)data中的数据,都要挂载到vm实例上,作为vm实例的属性 // 5)在vue中,不需要操作DOM,操作的是响应式数据。数据变了,模板自动刷新 </script>
02-vue语法注意事项
MVVM模型
- MVVM是Model-View-ViewModel的简称,是目前非常流行的架构模式;
- 通常情况下,我们也经常称Vue是一个MVVM的框架
小胡子语法注意事项一:
- {{}} Mustache,插值语法,也叫小胡子语法
- 一个vm实例只能指定一个模板,一个容器
- 小胡子语法只能在容器内部使用,容器外是不能使用
- 只能写在文本节点处,不能写在属性节点。错误示范:
小胡子语法注意事项二:
- 小胡子中可以放表达式(任何有值的内容都是表达式)
- 小胡子中可以书写实例的属性
- 小胡子中可以书写JS表达式
- 不可以写语句 if.swich.for
03-$mount的使用
配置代码片段
-
具体的步骤如下
第一步,复制自己需要生成代码片段的代码; 第二步,https://snippet-generator.app/ 在该网站中生成代码片段; 第三步,在VSCode中配置代码片段;
-
命名为:v2
-
输入v2就会出现配置好的代码:
通过$mount关联容器
-
$mount需要传递一个容器的CSS选择器(字符串类型)
-
$mount是Vue构造器的原型对象上的方法,所以通过VM实例也可以调用
let vm = new Vue({ // el:"#app", // 作用:让vm实例与容器进行关联 data(){ return { name:"wc", age:18, sex:"man" } } }); console.log(vm); vm.$mount("#app")
02-响应式原理与事件绑定
01-初识响应式原理
// 问:下面的代码中有几个对象?
// 答: 3个 vm叫实例对象 new一个{}配置对象 data中返回一个对象
let vm = new Vue({
el:"#app",
data(){
return {
msg:"hello vue"
}
}
});
console.log(vm);
// 在vm实例上,还有一个叫_data属性,它里面也包含了data中的数据
// 之所以以_打头,表示不希望别人使用 私有属性
console.log(vm._data);
// vm这个对象 与 data函数调用返回的对象 是两个不同的对象
-
vue2的响应式原理,靠之前的JS高级中的 Object.defineProperty
// 精细化设置属性 就是给data对象添加msg属性 Object.defineProperty(data,"msg",{ // 当获取属性时,自动走get,得到的值是,return后面的值 get(){ return vm.msg; // 获取也要在vm }, // 当给msg属性设置一个属性时,会走set,设置的新值会作为set的参数 set(val){ vm.msg = val; // 设置在vm上 // 更新视图..... } }) // 数据变了,我要更新视图,也就是说,数据变了,我肯定要知道 // 当数据发生了变化,会走set,在set中可以更新视图... data.msg = "i love vue" console.log(data.msg);
02-事件绑定
-
在vue中,通过指令来绑定事件。指令:说白了,就是标签的自定义属性 是以v-打头
-
v-on基本上不用,一般都使用简写 @
-
一个元素可以同时绑定多个事件,但是一般情况下只是绑定一个
-
methods中的方法,不要写成箭头函数的形式
-
如果是箭头函数,内部的this表示window
-
监听器能不能挂载到vm实例上? 能
let vm = new Vue({ el:"#app", data(){ return { msg:"hello vue" } }, // methods中放模板中绑定的监听器 // methods 加了s 可以放很多很多方法 methods:{ // handle(){ // // console.log("handle..."); // // this表示vm实例 vm上有个msg 获取 // // console.log(this.msg); // // msg是响应式数据,数据变了,界面要更新 设置 // this.msg = "hi vue" // } handle:function(){ console.log(this); this.msg = "hi vue" }, handle2(){ console.log("点击了按钮~"); }, over(){ console.log("鼠标移入了~"); } } }); // 写在methos中的方法,也会挂载到vm实例上的 vm.handle2()
03-传参问题
-
在绑定一个监听器时,()可以加也可以不加,加()的目的是为了传参
-
月
<div id="app"> <button @click=" getMsg(123) ">传递一个参数</button> <!-- @click=后面是跟了一个"" 千万不要当成字符串,它仅仅是vue中的语法 --> <!-- "" 仅仅是vue的语法,在""里放JS表达式 --> <button @click=" getMsg2(123,'i love you') ">传递两个参数</button> <!-- 没有加() 在监听器中,默认第一个参数,就是事件对象 --> <button @click=" getMsg3 ">获取事件对象方式一</button> <!-- 加()的目的是为了传参 --> <!-- 如果添加了(),监听器中的第1个参数,就不是事件对象了 --> <!-- 如果还想获取事件对象,那么需要手动的传递事件对象 $event --> <button @click=" getMsg4($event) ">获取事件对象方式二</button> </div> <script> let vm = new Vue({ el: "#app", // data中放响应式数据 data() { return { } }, // methods中放方法(监听器) methods: { getMsg(a) { console.log(a); // console.log("getMsg..."); }, getMsg2(a, b) { console.log(a, b); }, getMsg3(e) { console.log(e); }, getMsg4(e){ console.log(e); } } }); </script>
04-事件修饰符
-
.stop - 调用 event.stopPropagation()。
-
.prevent - 调用 event.preventDefault()。
-
.capture - 添加事件侦听器时使用 capture 模式。
-
.once - 只触发一次回调。
引入Vue.js,人家向外暴露一个Vue类 new Vue --> <script src="../lib/vue2.7.8.js"></script> <style> .box{ width: 200px; height: 200px; background-color: skyblue; } </style> </head> <body> <!-- 定义的容器 --> <div id="app"> <!-- form表单有默认的提交事件 --> <!-- a标签也有默认事件 --> <form action="http://www.baidu.com"> <!-- 一点登录跳到百度 --> <!-- <input type="submit" value="登录"> --> <!-- 打印showMsg... 并且跳百度 --> <!-- <button @click="showMsg">点我</button> --> <!-- @click.prevent 阻止默认事件 --> <!-- 方法2 --> <button @click.prevent="showMsg">点我</button> </form> <hr> <!-- 先触发里边再触发外边 --> <div class="box" @click="showMsg2"> <!-- 方法2 --> <button @click.stop="showMsg3">阻止冒泡</button> </div> <!-- 捕获 从外向内 --> <hr> <!-- once表示只处罚一次,用的不多 --> <button @click.once="showMsg4">只触发一次</button> <!-- 事件的修饰符可以链式来写,谁先谁后无所谓,了解: @click.stop.prevent.once @click.once.stop.prevent --> </div> <script> let vm = new Vue({ el:"#app", data(){ return { } }, methods:{ showMsg(e){ console.log("showMsg...."); // e拿到事件对象 // e.preventDefault(); // 阻止默认事件 法1 }, showMsg2(e){ console.log("showMsg2..."); }, showMsg3(e){ console.log("showMsg3..."); // e.stopPropagation(); // 阻止冒泡 法1 }, showMsg4(){ console.log("showMsg4..."); } } }); </script>
05-按键修饰符
-
按键修饰符:
.enter 回车键 .left 左键 .right 右键 .up 上键 .down 下键 .esc .a .b .c
-
代码如下:
<div id="app"> 请输入你喜欢的人的名字,按回车打印出来:<input type="text" v-model="people" @keyup.enter="handle"> </div> <script> let vm = new Vue({ el:"#app", data(){ return { people:"wc" } }, methods:{ handle(e){ // console.log(e); // 未使用按键修饰符 // if(e.keyCode === 13){ // console.log("你喜欢的人的名字是:", this.people); // this表示people // } // 使用按键修饰符后,直接打印 console.log("你喜欢的人的名字是:", this.people); } } }); </script>
03-指令
01 v-bind指令
-
v-bind作用是用于把数据绑定到属性节点处
<div id="app"> <img v-bind:src="url" alt=""> <!-- v-bind可以简写成: --> <img :src="url" alt=""> <!-- "haha是字符串" --> <p title="haha"></p> <!-- vm身上的动态属性 --> <p :title="haha">我是一个P标签</p> <!-- 不加:表示输入框中有个ok --> <input type="text" :value="ok"> <!-- 冒号删了href的属性是name,加上:href的属性是wangcai --> <a :href="name">{{name}}</a> </div> <script> let vm = new Vue({ el:"#app", data(){ return { url:"https://cn.vuejs.org/images/logo.svg", haha:"lala", ok:"ok666", name:"wangcai" } } }); </script>
02 v-once指令 (了解)
-
v-once表示只会第一次渲染数据到模板中,后面数据变了,模板也不会刷新了
<script src="../lib/vue2.7.8.js"></script> </head> <body> <!-- 定义的容器 --> <div id="app" v-once> <!-- v-once表示只会第一次渲染数据到模板中,后面数据变了,模板也不会刷新了 --> <!-- <h2 v-once>计数器:{{number}}</h2> --> <h2>计数器:{{number}}</h2> <button @click="increment">加1</button> </div> <script> let vm = new Vue({ el:"#app", data(){ return { number:0 } }, methods:{ increment(){ this.number++ } } }); </script>
03 v-text (了解)
-
v-text用于更新元素的 textContent:
-
v-text不会解析标签
<div id="app"> <h2>{{msg}}</h2> <!-- "msg" 不是字符串,不是字符中,不是字符串,不是字符串 --> <!-- {{}}是v-text的语法糖,说白了,就是简写形式 --> <!-- 基本上不用,一般使用{{}} --> <h2 v-text="msg"></h2> <hr> <!-- v-text并不会解析标签 --> <div v-text="msg2"></div> </div> <script> let vm = new Vue({ el:"#app", data(){ return { msg:"hello vue", msg2:"<p style='color:red;'>我是一个P标签</p>" } } }); </script>
04 v-html指令 (了解)
- v-html能解析字符串
05 v-pre指令 (了解)
- v-pre是一个指令,了解,作用:跳过模板编译
- 之前是小胡子打印出来还是
- 如果模板中有些标签,不需要编译,可以使用v-pre,跳过模板编译
06 v-cloak指令 (了解)
- v-cloak 表示vm和模板没有关联好,不去编译{{}}
07 v-if
-
v-if后面如果是真,就渲染DOM元素或组件
-
v-if可以控制一个DOM元素创建或销毁
-
如果一个DOM元素,需要频繁地显示或隐藏,建议不要使用v-if
-
v-if是惰性的 如果判断值本身就是false,压根就不会创建
-
每一次显示,都是创建出一个新的DOM元素,每一隐藏都是移除,销毁掉这个DOM元素
<div id="app"> <!-- v-if后面也是写表达式 --> <!-- " true " 不是字符串,不是字符串,不是字符串 --> <!-- v-if后面如果是真,就渲染DOM元素或组件 --> <!-- <h1 v-if=" true ">今天是08月08号,再过一段时间就9月份了</h1> --> <!-- v-if后面如果转化成假,这个DOM元素或组件压根不会渲染 --> <!-- <h1 v-if=" 1-1 ">今天是08月08号,再过一段时间就9月份了</h1> --> <button @click="handle">让盒子显示或隐藏</button> <!-- v-if可以控制一个DOM元素创建或销毁 --> <!-- 频繁地创建或销毁一个DOM元素,性能也很低 --> div class="box" v-if="show"></div> </div> <script> let vm = new Vue({ el:"#app", data(){ return { // 响应式数据 // 默认是true show:true } }, methods:{ handle(){ this.show = !this.show } } }); </script>
08 v-else-if
-
show是什么就显示哪个div
-
v-if|v-eles-if|v-else中间不要出现其它的标签,否则就失效了,报警告了
<div id="app"> <!-- 需求: show是什么就显示哪个div --> <div class="pink" v-if=" show==='pink' "></div> <div class="skyblue" v-else-if=" show=='skyblue' "></div> <!-- v-if|v-eles-if|v-else中间不要出现其它的标签,否则就失效了,报警告了 --> <!-- <p>我是一个孤独的P标签</p> --> <div class="gold" v-else></div> </div> <script> let vm = new Vue({ el: "#app", data() { return { show:"gold" } } }); </script>
09 template标签
-
template标签,也叫幽灵标签; 看上去是标签,但是渲染不出来
-
template可以当做不可见的包裹元素
-
template 控制一片div的显示或隐藏
<div id="app"> <template v-if="number==1"> <div>haha</div> <div>haha</div> <div>haha</div> </template> <template v-else-if="number==2"> <div>xixi</div> <div>xixi</div> <div>xixi</div> </template> <template v-else> <div>hehe</div> <div>hehe</div> <div>hehe</div> </template> </div> <script> let vm = new Vue({ el: "#app", data() { return { number: 1 // number是1显示第一片div } } }); </script>
10 v-show
-
通过v-show控制元素的显示与隐藏
<div id="app"> <button @click="handle">通过v-show控制元素的显示与隐藏</button> <!-- v-show后面不是字符串 --> <div class="box" v-show="show"></div> </div> <script> let vm = new Vue({ el:"#app", data(){ return { // 响应式数据 show:true // 如果为false div标签还在,只是加上了style="display:none;" } }, methods:{ handle(){ this.show = !this.show } } });
v-if和v-show的区别?
v-if
- v-if是控制元素的创建或销毁,每次创建出来的都是新的,创建或销毁DOM元素,很耗性能。
- v-if后面的条件是false,它是惰性的,DOM元素压根不会创建
- v-if支持template标签
- v-if会导致浏览器的重排(重排一定会引起重绘)
v-show
- v-show后面的条件不管是true或false,DOM元素都会创建,它是通过display来控制元素的显示或隐藏
- v-show不支持template标签
- v-show导致浏览器的重绘(重绘不一定引起重排)。
- 如果需要频繁控制元素的显示或隐藏,那么使用v-show,不频繁,也可以使用v-if,尽可能使用v-show
11 v-modle指令
表单提交是开发中非常常见的功能,也是和用户交互的重要手段
- 比如用户在登录、注册时需要提交账号密码
- 比如用户在检索、创建、更新信息时,需要提交一些数据
v-model可以用来收集表单中的数据
-
v-model一般用在表单元素
-
v-model指令可以在表单 input、textarea以及select元素上创建双向数据绑定
-
双向数据绑定:data变input内容变,输入框内容变data也变
<div id="app"> <!-- 不使用v-model,实现双向绑定 --> <!-- 希望:输入框内容变了,data也变 触发input事件 --> <!-- 不加小括号第一个参数表示事件对象 --> <input type="text" :value="msg" @input="inputChange"> </div> <script> let vm = new Vue({ el:"#app", data(){ return { msg:"i love vue" } }, methods:{ inputChange(e){ // 通过事件对象拿输入框内容 拿到之后要改变msg,给msg赋值就行 this.msg = e.target.value } } }); </script>
-
使用v-model
<div id="app"> // v-model就是一个语法糖: :value + @input // 实现双向数据绑定 <input type="text" v-model="msg"> </div> <script> let vm = new Vue({ el:"#app", data(){ return { msg:"i love vue" } }, methods:{ inputChange(e){ // 通过事件对象拿输入框内容 拿到之后要改变msg,给msg赋值就行 this.msg = e.target.value } } }); </script>
-
在vue中,如果监听器中的代码就一行,可以写在模板中,不建议使用
01 v-model绑定textarea
如何收集textarea中的数据
02 v-model绑定checkbox
-
checkbox可以作为一个单选框
-
checkbox多选框:v-model绑定的就是一个数组了
-
每一个input上,必须有一个value
<div id="app"> <!-- checkbox可以作为一个是否同意的单选框 --> <label for="agree"> <!-- 单个选框(是否同意按钮) v-model的值是布尔值 --> <input type="checkbox" id="agree" v-model="isAgree"> 同意xxx协议 </label> <h2>单选框:{{isAgree}}</h2> <hr> <!-- checkbox多选框:v-model绑定的就是一个数组了 --> <!-- 每一个input上,必须有一个value --> <div class="hobbies"> <h2>请选择你的爱好:</h2> <label for="sing"> <input type="checkbox" id="sing" v-model="hobbies" value="sing"> 唱歌 </label> <label for="coding"> <input type="checkbox" id="coding" v-model="hobbies" value="coding"> 打代码 </label> <label for="basketball"> <input type="checkbox" id="basketball" v-model="hobbies" value="basketball"> 打篮球 </label> </div> <h2>爱好:{{hobbies}}</h2> </div> <script> let vm = new Vue({ el:"#app", data(){ return { isAgree:false, hobbies:[] } } }); </script>
03 v-model绑定radio
-
收集radio输入框的内容
-
v-model收集的也是value值
-
name选项保证二选一
-
value不写可能收集不到数据
<div id="app"> <div class="gender"> <label for="male"> <!-- v-model收集的也是value值 --> <input id="male" name="sex" type="radio" v-model="gender" value="male"> 男 </label> <label for="female"> <input id="female" name="sex" type="radio" v-model="gender" value="female"> 女 </label> <h2>性别: {{gender}}</h2> </div> </div> <script> let vm = new Vue({ el:"#app", data(){ return { gender:"female" } } }); </script>
04 v-model绑定select
- select下拉菜单
- 需要加上value,因为最终收集的是value中的数据
- v-model需要写在select身上
select的单选
<select v-model="fruit">
<option value="apple">苹果</option>
<option value="orange">橘子</option>
<option value="banana">香蕉</option>
</select>
<h2>单选:{{fruit}}</h2>
select的多选
-
加上multiple 多选
-
size=3 表示可视区中显示几个选项
<select multiple size="3" v-model="fruit2"> <option value="apple">苹果</option> <option value="orange">橘子</option> <option value="banana">香蕉</option> </select> <h2>多选:{{fruit2}}</h2> <script> let vm = new Vue({ el:"#app", data(){ return { // 默认情况下选中 fruit:"banana", fruit2:["apple"] } } }); </script>
05 v-model的修饰符
-
lazy 把input事件切换成change事件
-
input事件:输入框内容变,data也变
-
change事件:失去焦点后data中的数据才变
input type="text" v-model.lazy="msg"> <h2>msg:{{msg}}</h2>
-
number将绑定的字符串内容,转化为数字类型
<input type="text" v-model.number="number"> <!-- typeof number 判断number的类型 是否是字符串 --> <h2>number:{{number}} --- {{ typeof number }}</h2>
-
trim去掉首尾空格
<input type="text" v-model.trim="str"> <h2>str:{{str}}</h2>
-
多个修改符可以连用
<input type="text" v-model.lazy.number.trim="str">
12 v-for指令
01 v-for遍历数组
-
v-for 遍历,把一片数据渲染到页面上
-
v-for写谁身上 最终生成谁
-
v-for="(item,index) in data(data中的数据)
<div id="app"> <!-- v-for 遍历,把一片数据渲染到页面上 --> <!-- 遍历数组 --> <ul> <!-- v-for写在谁的身上,最终就遍历出多少个谁 --> <!-- v-for="(item,index) in data" --> <!-- item数组中的每一项,index数组中的索引 --> <li v-for="(item,index) in students"> {{ item.name }} --- {{ index }} </li> </ul> </div> <script> let vm = new Vue({ el: "#app", data() { return { students: [{ id: 1, name: "貂蝉" }, { id: 2, name: '妲己' }, { id: 3, name: '大桥' }, { id: 4, name: '小乔' }, { id: 5, name: '周瑜' }, { id: 1, name: "貂蝉" }, { id: 2, name: '妲己' }, { id: 3, name: '大桥' }, { id: 4, name: '小乔' }, { id: 5, name: '周瑜' } ], } } }); </script>
02 v-for遍历对象
<div id="app">
<h2>遍历对象</h2>
<!-- 最终生成p标签,v-for写谁身上 最终生成谁 -->
<!-- value是值 wangcai 18 男 -->
<p v-for="value in obj">
{{value}}
</p>
<hr>
<!-- 可以写两个参数: key是键 键是指name、age、sex -->
<p v-for="(value,key) in obj">
{{value}} --- {{key}}
</p>
<hr>
<!-- 也可以写三个参数 加上索引 索引一般不用 -->
<p v-for="(value,key,index) in obj">
{{value}} --- {{key}} --- {{index}}
</p>
</div>
<script>
let vm = new Vue({
el: "#app",
data() {
return {
obj: {
name: "wangcai",
age: 18,
sex: '男'
}
}
}
});
</script>
03 v-for遍历数字和字符串
<div id="app">
<h2>遍历数字</h2>
<!-- 遍历从1-5 索引0-4 -->
<p v-for="(num,index) in 5">
{{num}} --- {{index}}
</p>
<hr>
<h2>遍历字符串</h2>
<!-- str是字符串中的每一个字母 -->
<p v-for="(str,index) in 'ILoveVue'">
{{str}} --- {{index}}
</p>
</div>
04 计算属性、侦听器
01-计算属性的基本使用
- 小胡子中的运算尽可能放在计算属性中
- 计算属性:根据已有的状态,计算出一个新的状态
- 计算属性写成函数的形式,实际上是一个属性值
- 不能调用 即加()
- 计算属性的值,取决于函数的返回值
计算属性不能写异步代码。如:定时器,ajax,事件绑定...
-
在计算属性中,this表示vm
-
计算属性会缓存
<div id="app"> 请输入你的姓:<input type="text" v-model="firstName"> <br> 请输入你的名:<input type="text" v-model="lastName"> <br> <!-- vue官方不推荐在{{}}语法中做运算 --> <!-- 拼出全名 --> <!-- <p>全名:{{ firstName + lastName }}</p> --> <p>全名:{{ allName() }}</p> <p>全名:{{ allName() }}</p> <p>全名:{{ allName() }}</p> <p>全名:{{ allName() }}</p> <hr> <!-- 在模板中,第1次使用计算属性时,会执行计算属性对应的函数 --> <!-- 后面如果计算属性依赖的数据没有发生变化,计算属性会缓存起来 --> <p>全名:{{ allName2 }}</p> <!-- 下面使用计算属性,都是从缓存中取出来的属性,性能高 --> <p>全名:{{ allName2 }}</p> <p>全名:{{ allName2 }}</p> <p>全名:{{ allName2 }}</p> <script> let vm = new Vue({ el:"#app", data(){ return { firstName:"wang", lastName:"Cai" } }, methods:{ // 把复杂运算放到方法中,也是OK的 allName(){ // 走了四次 console.log("我是方法...."); return this.firstName + this.lastName } }, // 计算属性 computed:{ // 状态 ==> 数据 allName2(){ // 走一次,因为数据没变化 后面三次都是走的缓存 console.log("我是计算属性...."); // 计算属性的值,取决于函数的返回值 // return 123; // 当计算属性依赖的数据变化了,计算属性会重新计算 // console.log(this); this表示vm return this.firstName + this.lastName; } } }); console.log(vm); </script>
02-计算属性的完整写法
-
写成对象的形式
<script> let vm = new Vue({ el:"#app", data(){ return { firstName:"Wang", lastName:"Cai" } }, methods:{ updateName(){ // 计算属性allName也会挂载到vm上的 this.allName = "李-四" } }, computed:{ // 计算属性的另一种写法(用的不多) 对象的形式 allName:{ // 当在模板中使用计算属性时,会自动走get get(){ return this.firstName + "-" + this.lastName; }, // 当修改计算属性时,会走set,但是一般情况下,不会修改计算属性 set(val){ // val是计算属性的新值 // console.log("set..."); // 验证修改后有没有走set // console.log(val); // 李-四 let arr = val.split("-") // 切成数组 this.firstName = arr[0] // 拿到李 this.lastName = arr[1] // 拿到四 } } } }); </script>
03 计算属性与方法的区别
-
计算属性computed:属性
-
methods:方法
-
使用时methods加(),computed不加()
-
computed有缓存
<div id="app"> <h2>{{ showMsg() }}</h2> <h2>{{ showMsg() }}</h2> <h2>{{ showMsg() }}</h2> <h2>{{ showMsg() }}</h2> <h2>{{ showMsg() }}</h2> <hr> <h2>{{ showTotal }}</h2> <h2>{{ showTotal }}</h2> <h2>{{ showTotal }}</h2> <h2>{{ showTotal }}</h2> <h2>{{ showTotal }}</h2> </div> <script> let vm = new Vue({ el:"#app", data(){ return { } }, methods:{ showMsg(){ console.log("我是方法"); return "method" } }, computed:{ // 有缓存 showTotal(){ console.log("我是计算属性"); // 返回什么就是什么 return "computed" } } }); console.log(vm); </script>
04-侦听器watch的使用
数据变了做一些其他事情,watch去监听这个数据
-
函数的写法
watch:{ keyword(){ console.log("我侦听到了keyword的变化"); } }
-
对象的写法
watch:{ // 对象的写法,需要在对象中写一个handler // 当keyword发生了变化,会自动执行handler // handler名字不能随便写 handler(){ console.log("我侦听到了keyword的变化"); } }
05-侦听器的配置选项
- 如果想侦听到对象中所有的属性,需要写成对象的形式
在侦听器中可以写异步代码
let vm = new Vue({
el: "#app",
data() {
return {
a: {
b: {
count: 1,
msg: '我爱你'
}
}
}
},
watch:{
a:{
deep:true, // 深度侦听 一上来没执行
immediate:true, // 一上来,先执行一次侦听器
handler(){
// console.log("i love u"); // 不能监听到,需要配置deep
// 在侦听器中可以写异步代码
setTimeout(()=>{
this.a.b.msg = "lalala"
},3000)
}
}
}
});
05 动态类名与行内样式
01-绑定class
01-动态类名之单个状态写法
-
在一个标签上,既可以写动态类型(前面加:),也可以写非动态类型(前面不加:)
<div id="app"> <!-- 动态类名的写法 box2是一个状态 --> <!-- 在一个标签上,既可以写动态类型,也可以写非动态类型 --> <div :class="box2" class="box3">动态类名-单个状态的写法</div> </div> <script> let vm = new Vue({ el:"#app", data(){ return { box2:"bad" } } }); </script>
02-动态类名之对象写法
-
:class后面跟一个对象 { K:V } key是键,value是值
<div id="app"> <div :class="obj"> 千里之行,始于足下。——老子 </div> </div> <script> let vm = new Vue({ el:"#app", data(){ return { obj:{ // 键表示类名 值表示是否有这个类 one:true, two:true, three:false, four:0 } } } }); </script>
03-动态类名之数组写法
- 直接写 数组的形式
- 定义在状态里(响应数据)
02-绑定style
01-动态行内样式之对象的写法
-
写在标签里
-
当成状态
<div id="app"> <p :style="obj"> 任何人都应当有自尊心,自信心,独立性,不然就是奴才 </p> </div> <script> let vm = new Vue({ el:"#app", data(){ return { // vm.obj.color = "red" 通过这种形式添加的数据并不是响应式数据 // 不是响应式数据,就意味着页面不会更新,但数据加上去了 obj:{ // obj本身就是响应式数据 // 响应式数据可以修改 width:"200px", height:"200px", // vm.obj.background = "gold" 修改响应式数据,模板会更新 background:"skyblue" } // 需求:后期想给obj上添加响应式数据,如何添加? // 去官网查 // 答:$set } } }); vm.$set(vm.obj,"color","red") </script>
-
删除一个响应式数据,使用$delete
02-动态行内样式之数组的写法
-
第一种写法:
<!-- 数组中写对象 可以写多个对象 --> <p :style="[{color:'red',background:'skyblue'},{height:'300px'}]"> 任何人都应当有自尊心,自信心,独立性,不然就是奴才 </p>
-
第二种写法:
<p :style="[obj1,obj2]"> 任何人都应当有自尊心,自信心,独立性,不然就是奴才 </p> <script> let vm = new Vue({ el:"#app", data(){ return { obj1:{color:'red',background:'skyblue'}, obj2:{height:'300px'}, } } });
-
第三种写法:
<p :style="arr"> 任何人都应当有自尊心,自信心,独立性,不然就是奴才 </p> <script> let vm = new Vue({ el:"#app", data(){ return { arr:[ {color:'red',background:'skyblue'}, {height:'300px'}, ] } } });
06-数组更新检测与Vue生命周期
01-数组更新检测
数组更新检测
-
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
-
下面的7个方法,会引起界面更新
<div id="app"> <ul> <li>{{name}}</li> <li>{{age}}</li> <li>{{sex}}</li> <li>{{hobby}}</li> </ul> <button @click="updateHobby">修改睡觉为打代码</button> </div> <script> let vm = new Vue({ el:"#app", data(){ return { name:"wc", age:18, sex:"man", hobby:["睡觉","吃饭","打豆豆"] } }, methods:{ updateHobby(){ // 这样修改,数据已经变了,但是模板没有刷新 // 这个修改数据,并非是响应式的 // 如果数组中的数据是基本数据类型,通过索引去修改它,界面并不会更新 // this.hobby[0] = "打代码"; // 数据变了,界面也没有刷新 // 通过数组的length修改数据,并排是响应式的 // this.hobby.length = 2; // 调用数组的push,pop方法,也是响应式的 // this.hobby.push("写代码") // this.hobby.pop() // this.hobby.splice(0,1,"打代码") // map返回一个加工后的新数组 // console.log(this.hobby.map(item=>item=="睡觉" ? "打代码" : item)); this.hobby = this.hobby.map(item=>item=="睡觉" ? "打代码" : item); } } }); </script>
-
数组中的元素是一个对象,通过索引修改对象中的属性,也会引起界面的更新
-
在data中,一个对象不管嵌套多深,所有数据都是响应式数据
<div id="app"> <p>{{arr}}</p> <button @click="handle">修改data中的数据</button> </div> <script> let vm = new Vue({ el: "#app", data() { return { arr: ["xq", 123, { name: 'wangcai' }, true] } }, methods:{ handle(){ // 数据变了,但是界面没有更新, // 通过索引调用 不是响应式数据 // this.arr[0] = "666"; // 调用数据的7个方法,是响应式的 // 如果数组中的元素是一个对象的话,通过索引去修改对象中的属性,也会引起界面的更新 this.arr[2].name = "xiaoqiang"; } } }); // 总结数据更新检测: // 在data中定义的数据都是响应式数据,有特殊情况: // 数组中的元素有可能是响应式的【数组中的元素是对象】,也有可能不是响应式的【基本类型】 // 调用数组上的7个方法,也会引起界面更新 </script>
02-Vue生命周期
-
生命周期函数,也叫钩子函数,会在合适的时机自动调用
-
函数的名字,不能随便,都是vue定死的
<div id="app"> <p :style="{opacity:tmd}">Vue是一个很NB的框架!!!</p> </div> <script> let vm = new Vue({ el:"#app", data(){ return { tmd:1 } }, // 生命周期函数,也叫钩子函数 // 这个函数会在合适的时机自动调用 // 函数的名字,不能随便,都是vue定死的 // 每一个钩子函数,都有特定的含义 mounted(){ setInterval(()=>{ this.tmd -= .1; if(this.tmd<=0) this.tmd = 1; },500) } }); </script>
02-Vue生命周期的8个钩子函数
-
beforeCreate,created
-
beforeMount,mounted
-
beforeUpdate,updated
-
beforeDestroy,destroyed
<div id="app"> <button @click="add">加1</button> <span ref="cur">{{count}}</span> <button @click="minus">减1</button> <br> <button @click="handle">销毁vm</button> </div> <script> let vm = new Vue({ el:"#app", data(){ return { count:1 } }, methods:{ add(){ this.count++ }, minus(){ this.count-- }, handle(){ // 销毁vm this.$destroy(); } }, // 生成周期函数,最先执行执行的是beforeCreate, // 说明:vm还没有初始化完成 不能通过vm使用data中的方法和methods中的方法 // 项目中没有什么用,了解就OK了 beforeCreate(){ // vm还没有初始化配置完毕,在这里不能获取vm的属性或方法 console.log("初始化阶段:beforeCreate","vm没有初始化完毕",this.count); // this.count拿不到 }, // vm实例已经初始化完成了 // 有用,在项目中,通常可以在这里发送ajax请求 created(){ // 此处,就可以获取vm的属性或方法了 console.log("初始化阶段:created","vm初始化完毕", this.count); }, // vm挂载之前调用 // 项目中用的也不多 beforeMount(){ // 可以获取vm实例,可以得到vm实例上的属性或方法,但是不能获取真实DOM console.log("挂载阶段:beforeMount","vm挂载之前执行一次",this.count,this.$refs.cur); }, // vm已经挂载完毕了 mounted(){ // 挂载完毕,就可以获取DOM元素 // 在这里,也可以发生ajax请求 个人一般在mounted中发请求 console.log("挂载阶段:mounted","vm挂载完毕",this.$refs.cur); }, // 更新阶段,当响应式数据发生了变化,就会触发一次 beforeUpdate(){ console.log("更新阶段:beforeUpdate",this.count); }, // 更新阶段:当vm的响应式数据发生变化,更新界面会触发一次 updated(){ // 能不能在updated中更新状态? // 答:不能,会导致死循环 console.log("更新阶段:updated",this.count); }, // vm销毁之前调用 beforeDestroy(){ console.log("销毁阶段:beforeDestroy",this.count); }, // vm销毁完毕:处理后事,如关闭之前开的一些定时器,或其它的收尾工作 destroyed(){ console.log("销毁阶段:destroyed",this.count); } }); // 总结: // 初始化阶段:beforeCreate created 只会执行一次 // 挂载阶段:beforeMount mounted 只会执行一次 // 更新阶段:beforeUpdate updated 只响应式数据发生变化,都会调用,调用N次 // 销毁阶段:beforeDestroy destroyed // 销毁后,并不是说界面看不见了,vm实例还可以访问,但是它不工作了!!!! </script>
07-非单文件组件
01-认识组件
- 组件:代码+资源,集合
非单文组件使用分为三步骤
-
第一步:定义
-
第二步:注册
-
第三步:使用
<div id="app"> <!-- 第三步:使用 --> <!-- 配置好之后,当成标签来使用 --> <Hello></Hello> <Hello></Hello> <Hello></Hello> <Hello></Hello> <Hello></Hello> </div> <script> // 第一步:定义 // 在extend中传组件的配置项 // 之前new Vue时,传递的配置项,在Vuex.extend中基本上都可以配置 let Hello = Vue.extend({ // el 只有在根组件中才可以配置el,在普通组件中不能配置el template:"<h2>我是Hello组件</h2>", // 配置当前组件对应的模板 }) let vm = new Vue({ el:"#app", data(){ return { } }, // 第二步:注册 components:{ // Hello:Hello 注册名、组件名 一样可以写一个 Hello } }); </script>
02-组件嵌套
<div id="app">
<!-- 使用组件就相当于使用标签 -->
<Count></Count> <br>
<Count></Count> <br>
<Count></Count> <br>
<Count></Count> <br>
<Count></Count> <br>
<Box></Box> <br>
<Box></Box> <br>
<Box></Box> <br>
<Box></Box> <br>
</div>
<script>
// 定义
let Hello = Vue.extend({
template: "<h1>我是Hello组件</h1>"
})
// Count组件
let Count = Vue.extend({
// 注册 Count里注册一个Hello
components:{
Hello
},
data(){
return{
count:0
}
},
methods:{
add(){ this.count++ },
minus(){ this.count-- }
},
// 之前是el 现在是template
template: `
<div class="box">
// 使用
<Hello></Hello>
<button @click="minus">-</button>
<span>{{count}}</span>
<button @click="add">+</button>
</div>
`
})
// 定义Box组件
let Box = Vue.extend({
data(){
return{
f:16
}
},
// 配置
template:`
<div class="box1">
<p :style="{fontSize:f+'px'}" @click="f++">我是一个孤独的P标签</p>
</div>
`
})
let vm = new Vue({
el: "#app",
// 注册 vm里注册一个Count
components:{
Count,
Box
},
data() {
return {
}
}
});
</script>
03-根组件的template
对于根组件来说,可以在两个地方,指定模板
-
1)el对应容器内部的html代码段
-
2)配置template,用来指定模板
-
template的优先级更高
<div id="app"> <div>我是一个DIV</div> </div> <script> // 对于根组件来说,可以在两个地方,指定模板 // 1)el对应容器内部的html代码段 // 2)配置template,用来指定模板 // 如果指定了template,它的优先级更高 打印出haha 而不是:我是一个DIV let vm = new Vue({ el: "#app", template:` <div>haha</div> `, data() { return { } } }); // template指定模板 用$mount vm.$mount("#app") </script>
04-引出App组件
<div id="app">
</div>
<script>
// 定义App组件
const App = Vue.extend({
// App组件中还可以有其他组件 Count Box
// 注册
components:{
Count,
Box
},
// 定义
template:`
<div> App组件 </div>
`
})
let vm = new Vue({
// 跟组件中注册,根目录下就有一个App组件
components:{
App
},
// 使用
template:`
<div>
<App></App>
</div>
`,
data() {
return {
}
}
});
vm.$mount("#app")
</script>
05-全局注册组件
注册组件分两种:
-
1)局部注册 在哪里注册,在对应的模板中使用
-
2)全局注册 只需要注册一次,可以在任何地方使用
<div id="app1"> <div> 我是DIV1 <hr> <Count></Count> </div> </div> <div id="app2"> <div> 我是DIV2 <hr> <Count></Count> </div> </div> <script> // 定义Count组件 const Count = Vue.extend({ data() { return { count: 1 }; }, template: ` <div> <button @click="count++">加</button> <span>{{count}}</span> <button @click="count--">减</button> </div> ` }); // 全局注册 在项目中,有些组件为了使用方法,都会使用全局注册 组件名:Count,组件:Count Vue.component("Count",Count) let vm1 = new Vue({ el:"#app1", data(){ return { } } }); let vm2 = new Vue({ el:"#app2", data(){ return { } } }); </script>
06-vm、vc与组件的关系
-
根组件实例叫vm 普通组件实例叫vc
-
vm看得见 vc看不见
-
VueComponent是一个类,Vue底层会帮我们new
<div id="app"> </div> <script> // 定义Count组件 // extend返回一个构造函数,叫VueComponent const Count = Vue.extend({ data() { return { count: 1 }; }, template: ` <div> <button @click="count++">加</button> <span>{{count}}</span> <button @click="count--">减</button> </div> ` }); console.log(Count); // c叫组件对象 这是我们new出来的 // 之前vue底层帮我们new出来 let c = new Count(); // 也可以使用Vue原型对象上的属性或方法 console.log(c.$data); let vm = new Vue({ el: "#app", data() { return { a:1 } } }); // console.log(vm.$data); </script>
-
Student构造器对应的是VueComponent类的实例:vc,底层帮我们new出来
<div id="app"> <Student></Student> </div> <script> Vue.prototype.coding = function(){ console.log("开始打代码了..."); } // 当我们使用Vue.extend 得到一个VueComponent构造器 // 不需要我们new Vue底层会帮我们new let Student = Vue.extend({ data() { return { info: 'I love Vue!!!' }; }, template: ` <h1 @click="changeInfo">{{info}}</h1> `, methods: { changeInfo() { // this.info = "I love React!!!" // 问:this是谁? // 答:vc Student构造器对应的实例vc,底层帮我们new出来的 // 组件内的this,不是vm,不是vm,不是vm,是VueComponent类的实例 // 看上去和vm很像,但实际上,两者是不同东西 // 组件内的this,就是VueComponet类的实例,可以叫它VC // this.coding(); console.log(this.__proto__.__proto__ === Vue.prototype); } } }); let vm = new Vue({ el: "#app", components:{ Student }, data() { return { a: 1 } }, methods:{ ok(){ // this表示vm console.log(this); } } }); </script>
07-Vue.extend创建组件简写方式
<script>
// 下面是Vue.extend的简写形式
// 定义组件
let App = {
// 为了在调试工具中显示正确的组件名,通常会配置name选项
name:"App",
data(){
return{
name:"wc"
}
},
template:`
<div>
<h1 @click="handler">{{name}}</h1>
</div>
`,
methods:{
handler(){
this.name = "xq";
// this表示vc
console.log(this);
}
}
}
let vm = new Vue({
el:"#app",
components:{
// Abc表示注册名 App表示组件名
// "Abc":App // 上面不配置name选项 组件名就是Abc
App
},
data(){
return {
}
}
});
</script>
08-脚手架
安装插件
- 插件一:Vetur,从Vue2开发就一直在使用的VSCode支持Vue的插件
- 插件二:Volar,官方推荐的插件
Vue CLI 安装和使用
-
全局安装: npm install @vue/cli -g
-
升级Vue CLI(如果是比较旧的版本,可以通过下面的命令来升级): npm update @vue/cli -g
-
通过Vue的命令来创建项目: vue create 项目的名称
每次修改js都需要重新跑一下 npm run serve
scoped表示该样式只在当前组件显示 < HelloWorld/>组件
vue.config.js中使用lintOnSave关闭exlint
根组件下的 < App/>组件
export default 向外暴露出一个对象
09-父传子与todolist案例
01-父传子
01-props的第一种写法
- props代表子组件接收父组件的数据
- props有多种写法,第一种写法,props后面写一个数组
- props中写自定义属性的名字
- 自定义属性,加 :
02-props的第二种写法
- 对象的写法
02-子传父
01-在组件上绑定自定义事件
-
父组件 App
<template> <div class="app"> <h1>我是父组件 王健林</h1> <hr> <MySon @wc="handler"></MySon> </div> </template> <script> import MySon from "./components/MySon.vue" export default { name: 'App', components: { MySon }, methods:{ handler(val){ // val是子传递给父的数据 console.log("val:",val); } } } </script>
-
子组件 MySon
<template> <div class="son"> <h1>我是子组件 王思聪</h1> <!-- @click="clickHandler" 不叫自定义事件,是封装好的事件 --> <button @click="clickHandler">触发自定义事件</button> </div> </template> <script> export default { name: "MySon", props:[], data() { return { money:500, }; }, methods: { clickHandler(){ // console.log("clickHandler..."); // 在这里,触发自定义事件 // 为什么找两次 // 因为在vc身上没有是$emit,沿着原型链可以去Vue的原型对象上找到$emit // console.log(this); // this.money给父亲 // this.$emit("wc",this.money) this.$emit("xq",this.car) } }, }; </script>
02-$on绑定自定义事件
通过ref拿DOM元素
<template>
<MySon @wc="handler" ref="cur"></MySon>
</template>
<script>
// 当组件挂载完毕执行一次mounted
mounted(){
// 当代码走到这里,说明,组件都挂载,渲染完毕
// 问:能不能获取组件实例? 答:可以
// console.log(this.$refs.cur); // 得到VC实例,才能实现绑定
// 可以通过$on绑定自定义事件
// 当xq事件发生了,处罚监听器
this.$refs.cur.$on("xq",(val)=>{
// 谁触发了xq事件,就可以传递数据
console.log("val:",val);
})
},
</script>
10-自定义指令 directives
指令:对DOM元素进行底层操作时,可以使用自定义指令
01-自定义局部指令
- 自定义局部指令:只能在当前组件中使用
- 在MyCommont1组件中定义的自定义指令,在其它组件中是不能使用的
- 想要在其他组件中使用,需要封装全局指令 在main.js中配置
02-自定义全局指令
-
自定义全局指令:在任意组件中使用
-
第二个参数是函数形式
-
第二个参数是对象形式
11-过滤器 filter
01-局部过滤器
使用过滤器
对time时间进行格式化,进行过滤
<h1>{{ time | timeFormat }}</h1>
- myapp文件夹下安装 npm i moment
- 安装出现以下问题,在npm i moment后加上 --legacy-peer-deps
- 安装成功过后进行以下操作
02-全局过滤器
12-插件
- 在main.js中使用插件
- 自定义插件
- vue规定插件身上要有一个install方法
13-事件总线
-
配置全局事件总线,就是在Vue原型对象身上配置$bus属性
在$bus身上有,$on和$emit $on注册自定义事件 订阅 可以用来接收数据 $emit触发自定义事件 发布 可以用来发送数据
-
在mian.js中配置
孙子传给爷爷
- 孙子中,发布数据
- 爷爷中,订阅(接收)数据
老大传给老二,兄弟间
- 老大发布
- 老二订阅
14-github案例
- 分成两个组件,是兄弟关系
- 方法一:在上面组件发送请求,响应请求就返回到上面组件,拿到数据后然后再把数据传到下面组件
- 方法二:把搜索框的内容拿到传到下面组件,然后在第二个组件中发送请求,响应请求返回到第二个组件中
- 在vue.config.js配置代理
- 不需要记,用的时候去vue官网抄
01-对axios二次封装
-
安装:npm i nprogress
-
导出封装后的axios
export default axios;
-
使用axios
15-前端路由
01-前端路由的两种
- 路由器router:维护一个映射表,映射表可以决定的数据的流向
- 前端路由核心:url发生了变化,监听到url变化了,需要切换页面(组件)
01-hash路由
02-h5中的history路由
API
- pushState( ):打开一个指定的地址;
- popstate( ):前进或后退可以被监听到
02-vue-router的基本使用
-
安装Vue Router:npm install vue-router@3.5.3
-
若安装不上后面加上 --legacy-peer-deps
-
一个路由器中可以配置N个路由,一个路由就是一个对象
-
这个对象中,配置一个路径对应一个组件
总结一个路由的基本使用: 1)创建router文件夹,里面创建index.js 2)在index.js中引入路由,并安装插件(npm install vue-router@3.5.3) Vue.use 3)创建路由器对象 new VueRouter() 并导出 4)在路由对象中配置路由规则 routes 5)在main.js中 导入路由器对象 并挂载到根组件上 6)配置路由的出口,就是当路径匹配到的话,对应的组件放在哪里
-
router-view是vue-router这个插件中内置好的组件
-
代表路由的出口,路径匹配到的组件,就需要放到出口中
-
redirect表示重定向
03-router-link实现跳转
-
router-link,类似于a标签
总结: 1)vue-router帮我们封装了两个组件 <router-view></router-view> 路由的出口 <router-link></router-link> 类似于a标签,点击实现跳转 2)使用vue开发的项目,都是单页面 SPA url改变了,监听到,需要在路由出口中放不同的组件,页面只有一张,变化的是路由出口中的组件
04-路由懒加载
- 懒加载:切换到这个路由时再去加载
- 第一步在硬盘打包 npm run build
- 第二步使用import进行懒加载,在硬盘再次打包npm run build
- 第三步 npm run serve
- 第四部利用魔法注释起名字,再次打包npm run build
- npm run serve
05-嵌套路由和404组件
嵌套路由步骤
- 第一步:创建组件,pages文件夹下
- 第二步:配置规则,router文件夹下的index文件里
- 第三步:配置出口并使用,组件里
404组件
- 创建NotFound组件
06-动态路由
-
配置
vue-router帮我们提供了两个组件: <router-view> <router-link> 除上上面的两个组件之外,还有两个对象,就是vc实例身上 $route 路由对象 身上有N个属性 params属性 $router 路由器对象 隐式原形对象上有N个方法 back forward go(-1) go(1) 一个路由器有n个路由
params传参
- 也可以在组件实现跳转,相当于a标签
query传参
07-编程式路由
声明式路由
编程式路由
- 后退
08-路由导航守卫
- 没有登录进去也可以访问
- 配置路由的全局守卫
16-CRM案例
- npm i 安装依赖
- 路由组件:在router文件夹下index.js里配置的组件,可以放在pages文件夹也可以放在views文件夹里
- components里放的是非路由组件
17-vuex状态管理(集中状态管理)
store:仓库
State:状态
Mutations:修改状态唯一属性
Devtool:追踪状态
01-vuex介绍与非脚手架中使用
Vuex:集中状态管理 状态理解成数据
引入Vuex.js
<script src="./libs/vuex.js"></script>
<div id="app">
<h1>根组件</h1>
<hr>
<add-counter></add-counter>
<hr>
<sub-counter></sub-counter>
</div>
<script>
// 创建一个仓库 需要传入一个配置对象
let store = new Vuex.Store({
// state是状态 是集中管理的状态
// 状态是响应式的
// 组件中的data中的状态也是状态式
state: {
counter: 0
},
// 修改状态的唯一途径
mutations: {
},
// 放异步代码,如果有异步操作,代码需要写在actions中
actions: {
},
// 类似于组件中的计算属性
// 根据已有状态计算出一个新的状态
getters: {
}
});
// 定义组件
let AddCounter = Vue.extend({
template: `
<div>
<p>我是addcounter组件</p>
<p>在addcounter组件中使用仓库中的数据:{{$store.state.counter}}</p>
<button @click="add">加1</button>
</div>
`,
methods:{
add(){
// 这样是粗暴地修改状态 极力不推荐
// 如果其它组件也这样修改状态,状态不好追踪了
// this.$store.state.counter++;
// 这时需要commit一个mutation,通过mutation去修改状态
}
}
})
let SubCounter = Vue.extend({
template: `
<div>
<p>我是subcounter组件</p>
<p>在subcounter组件中使用仓库中的数据:{{$store.state.counter}}</p>
<button @click="sub">减1</button>
</div>
`,
methods:{
sub(){
// this.$store.state.counter--;
// 利用commit一个mutation
this.$store.commit("sub")
}
}
})
// this.$store.state.counter
let vm = new Vue({
el: "#app",
store, // vuex也是一个插件,需要挂载到根组件上,就意味着,它的子子孙孙,都可以使用这个仓库了
components:{
AddCounter,
SubCounter
},
data() {
return {
}
}
});
</script>
-
mutations修改状态
mutations: { // 每一个mutations就是一个函数 // 第1个参数是仓库中的state // payload 是commit mutation时,传递的参数 // 下面的100传给了playload add(state,payload){ // state.counter++; state.counter += payload }, sub(state){ state.counter--; } } 在组件中使用: mutations: { // 需要commit一个mutation,通过mutation去修改状态 // 组件中调用 this.$store.commit("add",100) }
02-脚手架中使用vuex
- 在src(源码)文件夹下创建一个store文件夹(仓库)
- 创建脚手架 vue create myapp
- 不选Linter,否则安装vuex时报错
- 安装vuex npm i vuex@3.6.2
- store下创建index.js,导入vuex、导出store仓库
- main.js中导入store仓库,并把仓库挂载到根目录上
- 在components文件夹下创建组件、定义组件
- App中使用组件
03-mapState的使用
- mapState将仓库中的状态映射成组件的计算属性
04-mapGetters的使用
- mapGetters也可以把仓库中的计算属性映射成组件的计算属性
- 使用getter的方式一
- 使用getter的方式二
05-mapMutations的使用
- mapMutations可以把仓库中的mutation映射成组件的方法
- 传参
06-mapActions的使用
- mapActions可以action映射成组件的方法
18-过渡动画
-
vue中的过渡动画
-
Vue外向暴露了一些类,利用这些class就可以完成过渡动画。
v-enter-from:进入过渡开始的状态 v-enter-active:进入过渡生效时状态 v-enter-to:进入过渡结束的状态 v-leave-from: 离开过渡的开始状态 v-leave-active: 离开过渡生效时状态 v-leave-to: 离开过渡结束的状态
-
div需要用transition包住,如果没有起名就用v-打头
rotate是旋转 0deg是0度 scale是缩放
19-vant组件库
-
封装好的组件库,网站:vant-contrib.gitee.io/vant/v2/#/z…
(1)全部安装 # Vue 2 项目,安装 Vant 2: npm i vant@latest-v2 -S (2)自动按需引入 # 安装插件: npm i babel-plugin-import -D babel.config.js 中配置 (3)组件中使用——引入 全局注册 局部注册
20-网易云音乐
-
创建项目时,选择router 、vuex直接就可以安装
-
项目运行后,安装 axios、vant(npm i vant@latest-v2 -S)
-
按需引入,安装插件 npm i babel-plugin-import -D
网易云本地接口文件夹下:运行入口,node app.js 若报错,安装:npm install express
适配
-
安装: npm i postcss
-
安装:npm i postcss-pxtorem
-
创建:postcss.config.js文件
配置 module.exports = { plugins: { 'postcss-pxtorem': { rootValue: 37.5, propList: ['*'], }, }, };
21-新蜂商城
项目部署
-
第一步:npm run biuld打包
-
第二步:去Gitee上创建一个仓库,网址:gitee.com/
登录后,点击创建仓库,如下: (1)左上角点击仓库 (2)右上角点击+ (3)写名字 (4)点击创建
(1)
(2)
(3)
(4)
-
第三步:创建完复制链接
右键点,Git Bash Here 必须先安装Gei
git clone克隆+链接,paste粘贴
效果如下,点回车
-
第四部:复制打包后的文件
打开桌面上生成的文件夹
复制打包后生成的dist文件夹中的文件,复制到xfshop文件夹里
clear清除
-
第五步:把项目扔到原仓库
cd xfshop进到xfshop里
git add .
git commit -m "项目over"
git push origin master
-
第六步:查看效果,代码已放入仓库
-
第七步:点击右上方“服务”——>Gitee Pages
启动
-
第八步:出错
-
打包后的index.html中,直接是/js,需要在前面加上/xfshop
搜索,在vue.confi中配置
配置代码:publicPath:"/xfshop",
- 第九步:配置好,重新打包:npm run build
打包后效果(前面加上了/xfshop)
- 第十步:重新把dist文件夹中的代码复制到xfshop文件夹中
- 第十一步:传到git服务器上,git add .重复上述步骤:git commit -m "项目over"、git push origin master
- 第十二步:点击服务,更新
- 第十三步:若报错,重新更新不勾选强制使用HTTPS
不要走https,后端有的不支持https