Vue学习笔记
作者 黄姚的黄和姚
目录
- 修改vue中data的值 页面变化 状态变化=> 视图变化 数据响应式
- 再也不会关心DOM的更新 只关心数据
- 1. 首先要在头部导入Vue的js文件
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
- 2. 在body里面写一个模板div,id为app,或者其它的名字
<body>
<div id="app">
<!-- vue的代码就写这里面 -->
{{message}} // 插值表达式 app里变量写这里面
</div>
<script>
// Vue是构造函数
console.log(Vue);
- 3. 照下面的模板写
// 定义一个Vue实例
var app = new Vue({
el: "#app", // el 元素 vue需要接管的元素
data: { // data vue实例对象的数据(状态)[对象]
message: "hello world",
t: Date.now(),
link: "http://www.baidu.com",
name: "百度",
show: true,
},
// --------------方法----------------
methods: { // methods 专门用于定义组件方法的地方 [对象]
// 普通函数 不要乱用箭头函数 箭头函数没有this
clickHandler: function () {
},
fanfa(): {
},
},
// --------------计算属性------------
computed: { // computed 计算属性 里面的值 不是方法
// Vue 知道 val 依赖于 data中的某个值,
// 因此当 data中的某个值 发生改变时,所有依赖 val 的绑定也会更新
val: function(){
// <!-- 事件处理代码 -->
return 值; // 需要返回一个值
},
// 不同的是计算属性是基于它们的响应式依赖进行缓存的。
// 只在相关响应式依赖发生改变时它们才会重新求值
},
// --------------监听----------------
watch: { // watch 变量监听 监听某个变量的变化 一旦变量发生变化立刻对应的触发方法
val: function(newVal, oldVal){
// <!-- 事件处理代码 -->
},
// 当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的
},
// --------------组件----------------
component: {
},
// ------------生命周期--------------
// (创建前、创建后、挂载前、挂载后、更新前、更新后、销毁前、销毁后)
// 这里只看三个
// 创建后 最早能读到 this
created: function () {
// console.log("创建之后", this, document.querySelector(".test"));
},
// 挂载后 最早能获取到 DOM
mounted: function () {
// console.log("挂载之后", this, document.querySelector(".test"));
},
// 销毁后
destroyed: function () {
console.log("销毁之后");
},
});
</body>
- 只能有根组件,可以有多个子组件
// 组件要用 component 定义
Vue.component("todo-item", {
// todo-item 组件现在接受一个
// "prop",类似于一个自定义 attribute。
// 这个 prop 名为 todo。
// 子组件里面的props属性,用来接收根组件传来的值
props: ["todo"],
// data 组件里data一定要用函数包着并返回
data: function(){
return {
val: "",
number: 0,
}
}
template: "<li>{{todo.text}}</li>",
// 根组件有的子组件也有
methods、computed 等
});
<div v-bind:src="link"></div>
<div :src="link"></div>
<!-- -----------------------------
data: { // data vue实例对象的数据(状态)[对象]
link: "http://www.baidu.com",
},
-->
<ul>
<li v-for="arr in arrs">{{arr}}</li>
<li v-for="arr of arrs">{{arr}}</li>
<li v-for="obj in objs">{{arr}}</li>
<li v-for="obj of objs">{{arr}}</li>
<!-- in 和 of 是一样的 of比较接近js语法 建议用of -->
<!-- 多参数用逗号隔开 还要用小括号括起来 -->
<li v-for="(obj, index) of objs">{{index}} - {{obj}}</li>
<!-- -----------------------------
data: { // data vue实例对象的数据(状态)[对象]
arrs: [],
objs: {},
},
-->
</ul>
<template v-if="show"> <!-- template 空标签 不渲染在页面中 -->
show = true
</template>
<template v-if="show1">
show1 = false
</template>
<template v-if="show1">
show1 = false
</template>
<template v-else-if="show2">
show2 = true
</template>
<template v-else="show1">
show1 = false
</template>
<!-- v-if 和 v-else-if 还有 v-else 连用时,要紧挨着,中间不能隔着其他标签 -->
<!-- -----------------------------
data: { // data vue实例对象的数据(状态)[对象]
show: true,
show1: false,
show2: true,
},
-->
<button v-on:click="方法名"></button>
<button v-on:click="reverseMessage"></button>
<button @click="reverseMessage"></button>
<!--
methods: {
reverseMessage: function () {
console.log(111);
},
},
-->
<input v-model="val">
{{val}}
<!-- -----------------------------
data: { // data vue实例对象的数据(状态)[对象]
val: "",
},
-->
<style>
.active {
background-color: green;
}
.text-danger {
color: red;
}
</style>
<body>
<div id="app">
<!-- class -->
<!-- 对象语法 -->
<div v-bind:class="{ active: isActive }">{ active: isActive }</div>
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
>
{ active: isActive, 'text-danger': hasError }
</div>
<!-- 你可以在对象中传入更多字段来动态切换多个 class。
此外,v-bind:class 指令也可以与普通的 class attribute 共存 -->
<div class="static" v-bind:class="classObject">classObject</div>
<!-- 数组语法 -->
<div v-bind:class="[activeClass, errorClass]">
[activeClass, errorClass]
</div>
<div v-bind:class="[isActive ? activeClass : '', errorClass]">
[isActive ? activeClass : '', errorClass]
</div>
<div v-bind:class="[{active: isActive}, errorClass]">
[{active: isActive}, errorClass]
</div>
<!-- style -->
<!-- 对象语法 -->
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">
{ color: activeColor, fontSize: fontSize + 'px' }
</div>
</div>
<script>
new Vue({
el: "#app",
data: {
isActive: true,
hasError: true,
// classObject: {
// active: true,
// "text-danger": true,
// },
activeClass: "active",
errorClass: "text-danger",
activeColor: "red",
fontSize: "12",
},
computed: {
classObject: function () {
return {
active: this.isActive,
"text-danger": this.hasError,
};
},
},
});
</script>
<!--
chrome WebKit->Blink
firefox Gecko
ie Trident
Opera chrome Blink WebKit
sifar WebKit
edge chrome Blink
排版引擎
WebCore
KHTML
-->
</body>
<style type="text/css">
p.active {
text-decoration: line-through;
}
</style>
<body>
<div id="app">
<input type="text" v-model.trim.lazy="value" /><br>
<!-- 输入时不变,失去焦点改变value -->
<input type="text" v-model.trim.number="num" /><br>
<!-- 读取数字 -->
<!-- <textarea cols="30" rows="10">{{value}}</textarea> -->
<textarea cols="30" rows="10" v-model="value"></textarea>
<br />
<hr>
<!-- 单个复选 布尔 -->
<input type="checkbox" checked v-model="checked" />
<p :class="{active:checked}">{{msg}}</p>
<br />
<hr>
<!-- 单个复选 布尔 -->
<input type="checkbox" checked v-model="checked2" true-value="yes" false-value="no" />
<br />
<hr>
<!-- 多个复选 绑定到数组 -->
<label>
<input type="checkbox" value="A" v-model="fav" />
<span>苹果</span>
</label>
<label>
<input type="checkbox" value="B" v-model="fav" />
<span>葡萄</span>
</label>
<label>
<input type="checkbox" value="O" v-model="fav" />
<span>橘子</span>
</label>
<br />
<hr>
<!-- 单选 -->
<label>
<input type="radio" value="male" v-model="gender" />
<span>男</span>
</label>
<label>
<input type="radio" value="female" v-model="gender" />
<span>女</span>
</label>
<br />
<!-- 下拉选择 -->
<select v-model="selected">
<option value="bmw">bmw</option>
<option value="volvo">volvo</option>
<option value="benz">benz</option>
</select>
<select v-model="multipleSeleted" multiple>
<option value="bmw">bmw</option>
<option value="volvo">volvo</option>
<option value="benz">benz</option>
</select>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
num: "",
value: "hello",
checked: true,
checked2: "yes",
fav: ["A"],
gender: "female",
selected: "benz",
multipleSeleted: ["volvo"],
msg: "today mission",
},
});
</script>
</body>s
-
v-enter
-
v-enter-active
-
v-enter-to
-
v-leave
-
v-leave-active
-
v-leave-to
<style type="text/css">
.active {
color: #FFA500;
}
.slideH1 {
transition: all .5s;
}
.slide-enter {
transform: translateX(200px);
opacity: 0;
}
/* .slide-enter {
transform: translateX(300px);
opacity: 0;
} */
.slide-enter-active {
transition: all 4s;
}
.slide-enter-to {
transform: translateX(-100px);
}
.slide-leave {
/* transform: translateY(0px); */
/* opacity: 0.1; */
}
.slide-leave-active {
transition: all 1s;
}
.slide-leave-to {
transform: translateY(100px);
opacity: 0;
}
</style>
<body>
<div id="app">
<button type="button" @click="toggle">toggle</button>
<h1 :class="{active: awesome}"> VUE VUE VUE VUE</h1>
<!-- <transition name="move"> -->
<!-- <h1 v-if="awesome"> VUE comming2222 </h1> -->
<!-- <h1 v-show="awesome"> VUE comming111 </h1> -->
<!-- 放两个第二个没显示 -->
<!-- </transition> -->
<!-- <transition-group name="moves">
<h1 v-if="awesome" :key="1"> VUElsit comming2222 </h1>
<h1 v-show="!awesome" :key="2"> VUElist comming111 </h1>
</transition-group> -->
<transition name="slide">
<h1 v-if="awesome" class="slideH1">
<----vue slide vue silde vue slide</h1>
</transition>
<!-- 在<transition标签里面插入或者删除标签时>,
vue会自动自动嗅探目标元素是否应用了 CSS 过渡或动画,
如果是,在恰当的时机添加/删除 CSS 类名。-->
</div>
<script type="text/javascript">
let vm = new Vue({
el: "#app",
data: {
awesome: true,
},
methods: {
toggle: function() {
this.awesome = !this.awesome;
console.log(this.awesome);
}
}
});
</script>
</body>
<style>
.big {
width: 150px;
height: 150px;
background-color: red;
}
.box {
width: 100px;
height: 100px;
background-color: lightblue;
}
.small {
width: 50px;
height: 50px;
background-color: lightcoral;
}
</style>
</head>
<body>
<div id="app">
<p @click="count++">
{{count}} 行内 count ++
</p>
<p @click="count += 1">
{{count}} 行内 count += 1
</p>
<p @click="increment">
{{count}} 调用函数不带参
</p>
<p @click="incrementN(2)">
{{count}} 调用函数带参 (2)
</p>
<p @click="incrementN(10, $event)">
<!-- $event 这里代表 DOM事件对象 -->
可以通过参数 $event 来访问DOM事件对象
</p>
<hr />
<!-- 事件修饰符 stop capture prevent self once passive scroll事件 移动端 -->
<!-- .prevent 阻止默认事件 -->
prevent 是拦截默认事件,passive是不拦截默认事件。
<br>
通俗点说就是每次事件产生,浏览器都会去查询一下是否有preventDefault阻止该次事件的默认动作。我们加上passive就是为了告诉浏览器,不用查询了,我们没用preventDefault阻止默认动作。
<br>
这里一般用在滚动监听,@scoll,@touchmove。因为滚动监听过程中,移动每个像素都会产生一次事件,每次都使用内核线程查询prevent会使滑动卡顿。我们通过passive将内核线程查询跳过,可以大大提升滑动的流畅度。
<br>
注:passive和prevent冲突,不能同时绑定在一个监听器上。
<a @click.prevent="increment" href="http://ww.baidu.com">baidu</a>
<a @click.prevent href="http://ww.baidu.com">baidu</a>
<!-- 空的也可以 即不调用函数-->
<!-- .self -->
<div class="big" @click.self="big">
big
<div class="box">box</div>
</div>
<hr />
<!-- stop 阻止冒泡事件 -->
<!-- capture 事件捕获 -->
<!-- 会先 执行带有事件捕获修饰符的事件,
再执行冒泡事件,
遇到.stop修饰符会停下来,
所有事件执行并只执行一次
-->
<div class="big" @click.capture="big">
big
<div class="box" @click.self="box">
box
<div class="small" @click.capture="small">
small
<div @click="btn">btn</div>
</div>
</div>
</div>
<!-- once -->
<p @click.once="count ++ ">
{{count}} 使用.once后事件只能触发一次
</p>
<!-- self -->
<p @click.prevent.self="btn">
btn .self设置后,自身事件只能由自身去触发
不能通过冒泡触发
<p @click="btn2">
btn2
</p>
</p>
<!-- 按键修饰符 up down left right enter space esc tap delete -->
<!-- 系统修饰键 ctrl alt shift 要按下之后才能按下一个键 -->
<input type="text" placeholder="@keyup.up.down.left.right" @keyup.up.down.left.right="keyupHandler"
v-model.trim="value" />
<input type="text" placeholder="@keyup.ctrl.alt.up" @keyup.ctrl.alt.up="keyupHandler"
v-model.trim="value" />
<input type="text" placeholder="@keyup.ctrl.up" @keyup.ctrl.up="keyupHandler" v-model.trim="value" />
<input type="text" placeholder="@keyup.ctrl.up.exact" @keyup.ctrl.up.exact="keyupHandler"
v-model.trim="value" />
<input type="text" placeholder="@keyup.Backspace" @keyup.Backspace="keyupHandler" v-model.trim="value" />
<!-- .exact允许你控制由精确的 系统修饰符 (ctrl alt shift) 组合触发的事件 -->
<!-- 只能同时出现组合的按键才触发,多一个其他按键都不行 -->
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button v-on:click.ctrl="keyupHandler">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button v-on:click.ctrl.exact="keyupHandler">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button v-on:click.exact="keyupHandler">A</button>
<!-- 鼠标按钮修饰符 left right middle -->
<button v-on:mousedown.left="keyupHandler">B</button>
<button v-on:mousedown.right="keyupHandler">B</button>
<button v-on:mousedown.middle="keyupHandler">B</button>
</div>
<script type="text/javascript">
let vm = new Vue({
el: "#app",
data: {
count: 10,
value: "",
},
methods: {
increment: function(event) {
this.count += 1;
console.log(this.event);
},
incrementN: function(n, e) {
this.count += n;
console.log(n, e);
},
clickHandler(event) {
cconsole.log("click", event);
},
big() {
console.log("big");
},
box() {
console.log("box");
},
small() {
console.log("small");
},
btn() {
console.log("btn");
},
btn2() {
console.log("btn2")
},
keyupHandler($event) {
console.log($event);
},
},
});
</script>
</body>
-
第一种
-
子组件 : template(<标签名 @事件名="$emit(‘自定义事件名’, 参数1, 参数2…)"></标签名>)
-
根组件 : <子组件 @自定义事件名=“根组件方法”></子组件> 传多少个参数过来,就在方法里面定义多少个参数接收
-
第二种
-
子组件 : template(<标签名 @事件名=“子组件方法(参数…)”></标签名>)
在子组件的方法里面用 this.$emit(“自定义事件名”, 参数1, 参数2…); -
根组件 : <子组件 @自定义事件名=“根组件方法”></子组件> 传多少个参数过来,就在方法里面定义多少个参数接收
-
第三种
-
子组件 : 直接在子组件的方法里面用 this.$emit(“自定义事件名”, 参数1, 参数2…);
-
根组件 : <子组件 @自定义事件名=“根组件方法”></子组件> 传多少个参数过来,就在方法里面定义多少个参数接收
<body>
<div id="app">
<!-- 自定义事件 -->
<!-- 父级组件可以像处理 native DOM 事件一样通过 v-on 监听子组件实例的任意事件 -->
<counter :n="n" @decrement="zengjia"></counter>
<counter :n="n" v-on:decrement-n="zengjiaN"></counter>
<!-- <counter :n="n" v-on:decrement-n="n-=$event"></counter> -->
<!-- $event 自定义事件抛出的值 -->
</div>
<script>
Vue.component("counter", {
props: ["n"],
data: function () {
return {
count: 5,
};
},
template: `
<div>
<p>parent n is {{n}}, you clicked {{count}} times </p>
<button @click='count++'>count++</button>
<button @click='$emit("decrement")'>--</button>
<button @click='$emit("decrement-n", 5)'>-n</button>
</div>`,
});
// 同时子组件可以通过调用内建的 $emit 方法并传入事件名称来触发一个事件
// 子组件methods内部 用this.$emit
var vm = new Vue({
el: "#app",
data: {
n: 10,
},
methods: {
zengjia() {
// console.log(123);
this.n--;
},
// 自定义事件触发的方法 默认参数就是 子组件抛出的值
zengjiaN(num) {
// console.log(456, a);
this.n -= num;
},
},
});
</script>
</body>
- 根传子
- 直接在标签中绑定 子用props接收
- 子传根
- 要使用$emit()方法 根要在标签中接收
- 子传子
- 子先传给根,根再传给另一个子
<body>
<div id="app">
<h1>根组件内容: {{msg}}</h1>
<test :xxx="msg"></test>
<counter :n="n"></counter>
<counter :n="n"></counter>
<counter :n="n"></counter>
<ul>
<post-item
v-for="item in posts"
:post="item"
:title="item.title"
></post-item>
</ul>
</div>
<script>
Vue.component("post-item", {
props: ["post", "title"],
template: `
<div>
<h3>title:{{post.title}}</h3>
<p>content:{{post.content}}</p>
</div>
`,
});
// 每个组件必须只有一个根元素
Vue.component("test", {
props: ["xxx"],
template: "<p>test组件 {{xxx}}</p>",
});
Vue.component("counter", {
props: ["n"],
// data: {
// count: 5,
// },
data: function () {
return {
count: 5,
};
},
// 组件内的data 必须是一个 函数 返回一个对象
// 因此每个实例可以维护一份被返回对象的独立的拷贝
template:
"<p @click='count++'>parent n is {{n}}, you clicked {{count}} times </p>",
// template:
// "<p @click='n++'>parent n is {{n}}, you clicked {{count}} times </p>",
// 不能直接修改props的值 只能修改自己的data
// 所有的组件都只能修改自身的data
});
var vm = new Vue({
el: "#app",
data: {
msg: "hello vue",
n: 10,
posts: [
{ title: "123", content: "123content" },
{ title: "456", content: "456content" },
{ title: "789", content: "789content" },
],
},
});
</script>
</body>
-
事件修饰符
- .stop
- .prevent
- .capture
- .self
- .once
- .passive
-
按键修饰符
- .enter
- .tab
- .delete (捕获“删除”和“退格”键)
- .esc
- .space
- .up
- .down
- .left
- .right
-
系统修饰符
- .ctrl
- .alt
- .shift
- .meta
- .exact
- .left
- .right
- .middle
安装
npm install -g @vue/cli
查看版本
vue --version
创建项目
vue create hello-world
一路回车
运行服务器
npm run serve