vue
第一天
<template>
<div class="home">
<h1 class="box">{{ title }}</h1>
<p>{{ "300 *" + count + "=" + 300 * count }}</p>
<h2>{{ getRes() }}</h2>
<div :class="cc" class="aa" @click="cc = cc == 'red' ? 'blue' : 'red'">
AA
</div>
<div class="aa" :style="`background : ${cc}`">bb</div>
<button @click="title = '哈哈'">点击</button>
<button @click="ac = 0" :class="ac == 0 ? 'active' : ''">A</button>
<button @click="ac = 1" :class="ac == 1 ? 'active' : ''">B</button>
<button @click="ac = 2" :class="ac == 2 ? 'active' : ''">C</button>
<button @click="ac = 3" :class="ac == 3 ? 'active' : ''">D</button>
<div class="box">1 + 2 = {{ res }}</div>
<h1 class="">{{ obj.name }}</h1>
<h2 class="">{{ obj.money }}</h2>
<button @click="op({ name: 'aa' })">运算</button>
<!-- MustAche语法 -->
<!--
.vue文件中的模板部分 , 本质上其实是一个类似于ES6模板字符串的区域,该区域可以通过{{}}进行JS表达式的拼接
标签行间以外 : {{ JS表达式}}
{{变量 , 运算符 , 常量}}
{{ 函数调用() 返回值}} 显示出函数调用的返回值
标签行间属性值中 :
<el :attr="JS表达式"></el>
标签事件行间绑定中 :
<el @click="JS表达式"></el>
上面表达式中用到的变量和函数都需要在JS中定义
变量 :
data(){
return {
val1 : 'value1',
val2 : "value2"
}
},
methods : {
fn1(){},
fn2(){},
fn3(){},
}
-->
</div>
</template>
<script>
export default {
name: "Home",
data() {
return {
title: "vue第一个主页",
count: 200,
cc: "red",
ac: 0,
res: 0,
obj: {
name: "赵凯",
age: "0",
},
};
},
methods: {
getRes() {
return "getRes调用的是this.getRes()";
},
op(obj) {
console.log(obj);
this.res = this.getRes();
console.log(this.res);
/*
只有在data中申明过的变量 , 才具备与视图的响应特征 , 如果对一个已有的对象变量
新增一个响应式的key需要通过 this.$set(target ,key , val) 来实现
直接使用this,target,key = val 是无法更新视图的
*/
this.$set(this.obj, "money", 10000);
/*
在方法内部 , 可以通过this.attr this.method() 来访问 data中所东一的响应式属性 和 methods中定义的方法
该this永远指向 Vue组件对象 , VueComponent
*/
},
},
};
</script>
<style scoped>
.box {
color: tomato;
background: yellowgreen;
}
.red {
background: palegreen;
}
.blue {
background: skyblue;
}
.aa {
width: 100px;
height: 100px;
}
.active {
background: blue;
color: #fff;
}
</style>
第二天
<template>
<div class="event">
<!-- 事件的绑定方式 v-on:eventType -->
<button v-on:click="print('v-on绑定事件')">v-on:eventType</button>
<button v-on:mouseover="print('鼠标悬停')">鼠标悬停</button>
<!-- 事件绑定简写 -->
<button @mouseout="print('鼠标离开')">鼠标离开</button>
<!-- 事件处理函数是无参函数 -->
<button @click="alert">事件处理函数是无参函数</button>
<!-- 处理事件流 : 事件冒泡
@eventType.修饰词1 , 修饰词2=""
@event.stop = "fn"
-->
<div class="wrap" @click="print('wrap')">
<button @click.stop="print('box')">box</button>
</div>
<!-- 阻止系统默认事件 @event.prevent -->
<a href="" @click.prevent="print('a')">百度</a>
<!-- 事件只触发一次 @event.once -->
<button @click.once="print('只触发一次')">触发一次</button>
<!-- 修饰词可以互相组合 -->
<div class="wrap" @click="print('wrap')">
<a href=" " @click.prevent.stop.once="print('a')"> 百度</a>
</div>
<!-- 修饰词 .self -->
<div
@click.self="print('只有点在wrap上才能触发')"
class="wrap3"
style="width: 100px; height: 100px; border: 1px solid tomato"
>
<button>子级</button>
</div>
<!-- 键盘相关修饰词 -->
<!--
.enter 回车键
.tab Tab键
.delete 删除键
.space 空格键
.esc 退出键
.up 方向
.down .left .right
-->
<input type="text" @keydown.enter="print('enter')" />
<!-- 系统修饰键
一般情况下不能独立使用 , 必须要与其他的事件配合起来
.meta(mac:commend window : window键)
.exact : 表示系统键独一无二单独响应
-->
<!-- 代表只要按下了meta键点击就出发 , 及时同时按下了其他系统按键, 也能触发 -->
<button @click.meta="print('按着ctrl键')">
只要按这ctrl点鼠标就触发 , 及时同时按了也不触发
</button>
<button @click.meta.exact="print('只能按ctrl')">只能是ctrl+鼠标组合</button>
<!-- 事件对象 -->
<button @click="fnEvent">事件对象获取</button>
<button @click="fnEvent1('哈哈' , $event)">带参数获取事件对象</button>
<button @click="fnEvent2" data-id="x001">通过自定义行间属性传递参数</button>
</div>
</template>
<script>
export default {
name: "Event",
data() {
return {};
},
methods: {
print(item) {
alert(item);
},
alert() {
alert("哈哈哈");
},
fnEvent(e) {
console.log(e);
},
fnEvent1(argv,e){
console.log(argv , e);
},
fnEvent2(e){
// 只能获取行间通过data-属性名 定义的属性
console.log(e.currentTarget.dataset.id);
},
},
};
</script>
<style scoped>
</style>
v-modle
<template>
<div class="modle">
<!-- 默认表单事件-->
<input type="text" @input="fn" />
<p>{{ res }}</p>
<!-- v-modle -->
<input type="text" v-model="res1" />
<p>{{ res1 }}</p>
<!-- 登录注册 -->
<div class="login">
<input type="text" placeholder="用户名" v-model="loginForm.user" />
<input type="text" placeholder="密码" v-model="loginForm.pass" />
<!-- 单选 -->
<input type="radio" name="sex" value="0" v-model="loginForm.sex" />男
<input type="radio" name="sex" value="1" v-model="loginForm.sex" />女
<!-- 复选框 -->
<!-- 状态切换 -->
<input type="checkbox" v-model="loginForm.isCheck">
<!-- 多选 -->
<input type="checkbox" value="001" name="" id="" v-model="loginForm.hobby">抽烟
<input type="checkbox" value="002" name="" id="" v-model="loginForm.hobby">喝酒
<input type="checkbox" value="003" name="" id="" v-model="loginForm.hobby">烫头
<button @click="login">注册</button>
</div>
<!-- 修饰词 v-model-lazy 转为change事件触发-->
<input type="text" v-model.lazy="res3">
<p>{{res3}}</p>
<!-- 修饰词 v-model.number 将输入的值强转为数值类型 -->
<!-- 如果输入的不是数字字符串 , 会正常输出不会强转成数字 -->
<input type="text" v-model.number="res4">
<button @click="read">读取输入的数字</button>
<!-- 修饰词 v-model.trim 自动删除用户输入的空白键 -->
<input type="text" v-model.trim="res5">
<button @click="read">读取</button>
</div>
</template>
<script>
export default {
name: "Modle",
data() {
return {
res: "",
res1: "",
loginForm: {
user: "",
pass: "",
sex : "",
isCheck : "",
hobby : [] , //多选跟的是一个数组
},
res3 : '',
res4 : '',
res5 : '',
};
},
methods: {
fn(e) {
// e是原生事件对象e
console.log(this); //当前vue组件对象
console.log(e.currentTarget); //当前事件阶段的DOm对象
console.log(e.target.value); //触发事件的DOM对象
this.res = e.currentTarget.value;
},
login() {
console.log(this.loginForm.user, this.loginForm.pass , this.loginForm.sex , this.loginForm.isCheck , this.loginForm.hobby);
},
read(){
console.log(this.res4 , typeof this.res4 , this.res5);
}
},
};
</script>
<style>
</style>
第三天 计算属性和监视
计算属性
<template>
<div class="computed">
<h1>计算属性01</h1>
<!-- 软件版本号 -->
<input type="text" v-model.trim="appName" placeholder="app名称">
<input type="text" v-model.trim="appVersion" placeholder="app版本号码">
<!-- 动态的显示生成版本号 -->
<h2>{{ fullAppVerion }}</h2>
<!-- 函数 -->
<h3>{{ getFullAppVersion() }}</h3>
<!-- 计算总价 -->
<div class="caulator">
<span>{{ price }}</span>
<button>+</button>
<input type="text" v-model="count">
<button>-</button>
<p> 总价格: {{ price * count }}</p>
<!-- 第二种选择 -->
<p> 总价格: {{ getTotalPrice() }}</p>
<!-- 第三种选择 -->
<p> 总价格:{{ totalPrice }} </p>
<button @click="ca()">计算</button>
</div>
<!--
1.计算属性定义 :
计算属性是以: "函数"的形式进行定义 , 在配置选项的 computed{}中定义
2.函数名 就是计算属性名 , 函数的返回值就是计算属性的值,
3.计算属性 , 在模板中直接写 函数名
计算属性 , 在其他函数内容 , 通过this.计算属性名 , 读取
4.计算属性的值 , 一般依赖于其定义是函数内部的其他'状态量'
特征是 : 只有当其依赖的"状态量"发生变换时 , 计算属性的值才会跟这一起改
5.计算属性的值 , 一般是只读的
6.由于计算属性 , 是以函数的返回值去返回属性值的, 因此计算属性的内部的依赖传递过程必须是同步的, 不能是异步过程
7.计算属性 vs 方法的区别
1.首先都可以根据其他状态量进行复杂运算后,输出计算结果
2.计算属性会缓存运算结果 , 当状态量不变的时候 , 不会执行数据处理运算代码 , 而函数 , 只要触发就执行 , 计算属性性能更好
-->
</div>
</template>
<script>
export default {
name : 'Computed',
data(){
return{
appName:'vscode',
appVersion:'v1.0',
price : 123,
count : 0,
}
},
methods: {
getFullAppVersion(){
console.log("fnfn")
this.appName = this.appName.replace(/tmd/gi,"**")
this.appVersion = this.appVersion.replace(/tmd/gi,"**")
return this.appName + this.appVersion
},
getTotalPrice(){
return this.price * this.count
},
ca(){
console.log(this.totalPrice , this.totalPrice*100);
}
},
// 计算属性
computed:{
fullAppVerion(){
console.log('cccc')
let appName = this.appName.replace(/tmd/gi,"**")
let appVersion = this.appVersion.replace(/tmd/gi,"**")
return appName + appVersion
},
totalPrice(){
return this.price * this.count
}
},
}
</script>
<style>
</style>
计算属性2
<template>
<div class="computed">
<h1>计算属性02</h1>
<input type="text" v-model="name" placeholder="app名称">
<input type="text" v-model="version" placeholder="app版本">
<!-- 结果 -->
<input type="text" v-model="appVersion" placeholder="APP名+app版本">
<button @click="appVersion='lanou$V2.0'">修改</button>
<!-- 执念写法 -->
<h1>{{ appVersion1("AA") }}</h1>
<h1>{{ appVersion1("BB") }}</h1>
</div>
</template>
<script>
export default {
name : "Computed2",
data(){
return{
name : "",
version : "",
logo : 'logo'
}
},
computed : {
// appVersion(){
// return this.name + this.version;
// }
// 计算属性完整定义方法
appVersion : {
// 默认只有get方法 , 在appVersion被读取时调用
get(){
// 当this.name this.version变化 ,get被调用
return this.name + '$V' + this.version
},
// 可以添加set该方法 , appVersion=赋值 时被调用 形参就是等号右侧的赋值数据
set(apv){
this.name = apv.split('$V')[0];
this.version = apv.split('$V')[1];
}
},
appVersion1(){
// 计算属性使用时传递参数 , 需要返回一个函数
// 在模板中 , 将该返回的函数进行调用即可
return function(logo){
return this.name + this.version + '==' + logo
}
}
}
}
</script>
<style>
</style>
watch
<template>
<div class="watch">
<h1>wach数据监听</h1>
<input type="text" v-model.lazy="res">
<h1>{{res1}}</h1>
<!-- 计算属性写法 -->
<div>价格 <input type="text" v-model.number.lazy="price"> </div>
<input type="text" v-model.number.lazy="count" placeholder="计算属性">
<p>总价{{ cTotalPrice }}</p>
<!-- 数据监听的写法 -->
<div>价格{{ price }}</div>
<input type="text" v-model.number.lazy="count" placeholder="数据监听">
<p>总价{{ totalPrice }}</p>
<!--
在组件实例内部, 提供了一个数据监听的属性watch
1,要监听哪个状态 , 就医哪个状态为名称 , 在watch内定义函数,当该状态发生变化时, 对应watch函数就会被调用
2.watch 与计算属性的区别
2.1.watch内部监听的数据 , 对应的函数在调用时 , 只是一个普通函数调用 , 其内部可以执行 , 异步动作 , 定时器 ,ajax请求
而计算属性 , 是通过返回值进行赋值访问的 , 因此计算属性的函数内部 , 只能是同步状态
2.2 对于一个复杂的多状态参与运算的业务 , 计算属性, 只要其中任何一个状态发生变化, 都会触发运算 , 但是watch一次只能呢个监听
一个状态 , 因此对于多状态监测 , 我们采用计算属性而不是使用watch监听
3.推荐用法 : 当需要根据状态变化 , 执行异步业务时 , 我们首选采用watch方法
其他的 , 根据状态的变化 而同步变化的业务 , 使用计算属性
-->
</div>
</template>
<script>
export default {
name: "Watch",
data() {
return {
res : "",
res1 : "",
price : 123,
count : 0,
totalPrice : 0
};
},
watch : {
res(){
setTimeout(()=>{
this.res1 = this.res
},5000)
},
count(){
this.totalPrice = this.price * this.count;
},
price(){
this.totalPrice = this.price * this.count;
}
},
computed : {
cTotalPrice(){
return this.price * this.count;
}
}
}
</script>
<style>
</style>
watch2
<template>
<div class="watch">
<h1>数据监听</h1>
<input type="text" v-model="obj.val">
<button @click="obj1.name='怨种'">修改obj1</button>
<button @click="obj1.age=10">修改obj1</button>
<p> {{obj1.name}} </p>
<p> {{obj1.age }} </p>
</div>
</template>
<script>
export default {
name: "Watch2",
data() {
return {
obj : {
val : "嘿嘿"
},
obj1 : {
name:"赵凯",
age :12
},
};
},
watch : {
// val(){}
// obj1(){
// alert('xxxxx')
// },
'obj.val' : {
handler(){
alert('这是');
}
},
obj1:{
handler(){
alert("xxx")
},
deep : true //开启对象内部的深度监听
}
/*
watch默认只能监听基本数据类型的数值变化 如果需要监听对象数据 , 需要开启deep深度监听
*/
},
computed : {
}
}
</script>
<style>
</style>
vue4 组件封装
1
//组件 1
<template>
<div class="navItem" @click="fn">
<img :src="src" alt="">
<!-- 插槽 -->
<slot></slot>
<div class="title">{{ title }}</div>
</div>
</template>
<script>
export default {
// name : 'NavItem',
props : [ 'src' , 'title'],
methods : {
fn(){
this.$emit('navClick' , '数据11' , '数据22')
}
}
};
</script>
<style scoped>
.navItem {
width: 150px;
}
.navItem img {
width: 100%;
display: "block";
}
.title {
font-size: 10px;
text-align: center;
color: #ccc;
}
</style>
//调用1
<template>
<div class="com">
<h1>组件基础01</h1>
<!-- 2.页面组件调用 属性形参写在组件行间-->
<nav-item
v-for="(item, i) in in1"
:key="i"
:src="require('@/assets/logo.png')"
title="vue组件"
@navClick="fnn"
>
哈哈
</nav-item>
</div>
</template>
<script>
// 导入要使用的组件 ( 局部注册 )
import NavItem from "c/NavItem.vue";
export default {
data() {
return {
in1: [
{
src: "",
title: "",
},
],
};
},
components: {
NavItem: NavItem, //1. 组件的注册
// NavItem 注册形式二
// NavItem.name 注册形式三 是全局注册
},
methods: {
fnn(argv1, argv2) {
console.log(argv1, argv2);
},
},
};
</script>
<style>
</style>
组件二
<template>
<div class="navItem" @click="fn">
<img :src="src" alt="">
<slot></slot>
<div class="title">{{ title }}</div>
{{ count1 }}
<button @click="count1++">增加count1</button>
<h1>{{ titleFilter }}</h1>
</div>
</template>
<script>
export default {
name : 'NavItem2',
props : {
src : {
type : String , //限定props的属性类型
default : ''
},
title : {
type : String ,
default : "vue组件",
required : true
},
count : [String , Number], //表示cpount可以接受2种数据
listData : {
type : Object , //如果传入的数据是objiect类型
default : ()=>{} //对象类型默认值 , 是一个函数的返回值
},
list : {
type : Array ,
default : ()=>[] //数组类型的默认值 , 是一个函数的返回值
}
},
data(){
return {
count1 : this.count
// 如果传入的值需要在组件内部进行操作 , 最好的方式就是在组件内部的data中定义一个量进行接收,
// 以该内部状态量作为操作的数据对象
}
},
methods : {
fn(){
this.$emit('navClick' , '数据1' , '数据2')
}
},
computed : {
titleFilter(){
return this.title.replace(/TMD/,'**')
}
}
};
</script>
<style scoped>
.navItem {
width: 150px;
}
.navItem img {
width: 100%;
display: "block";
}
.title {
font-size: 10px;
text-align: center;
color: #ccc;
}
</style>
//调用2
<template>
<div class="com">
<h1>组件基础02</h1>
<!-- 2.页面组件调用 属性形参写在组件行间-->
<nav-item
:src="require('@/assets/logo.png')"
title="vue组件"
@navClick="fnn"
>
哈哈
</nav-item>
<!-- 组件对外属性 , 没有用 : 修饰时传入都是字符串 <com isCheck="false"></com>
传入的而是一个 false 字符串 , 并不是假 , 如果要传入一个JS的数据 , 并保留其原有数据类型, 需要使用属性动态传参 -->
<nav-item2
:src="require('@/assets/logo.png')"
@navClick="fnn"
:title="'123TMD'"
:count = '1'
>
哈哈
</nav-item2>
<!-- 类似于解构赋值的简写 -->
<nav-item2
@navClick="fnn"
v-bind="{
src : require('@/assets/logo.png'),
title : '123TMD',
count : 1
}"
>
哈哈
</nav-item2>
</div>
</template>
<script>
export default {
data() {
return {
};
},
methods: {
fnn(argv1, argv2) {
console.log(argv1, argv2);
},
},
};
</script>
<style>
</style>
组件3
//NavItem03
<template>
<div class="navItem" @click="fn" @mouseover="$emit('navover')">
<img :src="src" alt="">
<slot></slot>
<div class="title">{{ title }}</div>
<h1>数量{{ count1 }}</h1>
<button @click.stop="fn2"> + </button>
</div>
</template>
<script>
export default {
name : 'NavItem3',
props : [ 'src' , 'title' ,'count'],
data(){
return{
count1 : this.count
}
},
methods : {
fn(){
this.$emit('navClick' , '数据1' , '数据2')
},
fn2(){
this.count1++
this.$emit('add' , this.count1)
},
},
};
/*
组件之间的参数传递
组件在页面组件中调用
父组件: 页面组件
子组件 : 被调用组件
父组件 向子组件传参数 , 是通过子组件的 props
子组件 : 向父组件传参数 , 是通过子组件内部的事件处理函数 , 内调用this.$emit ( '自定义事件类型' , "传递参数" )
子子组件传参 :
基本方法 : 子组件1 ==> $emit ==> 父组件 => props =? 子组件2
以上方式 , 只能用于结构简单的组件传参 数 , 是通过子组件
对复杂结构组件参数传递 , 一般使用Vuex状态管理
2.在组件上扩展绑定原生事件
<nav-item v-on:event.native="fn"></nav-item>
该原生事件是绑定在组件 : "根节点" 标签上的
*/
</script>
<style scoped>
.navItem {
width: 150px;
}
.navItem img {
width: 100%;
display: "block";
}
.title {
font-size: 10px;
text-align: center;
color: #ccc;
}
</style>
//TotalPrice
<template>
<div class="totalPrice">
<h1>{{ totalPrice }}</h1>
</div>
</template>
<script>
export default {
// name : 'TotalPrice',
props : ['price' , 'count' ],
data(){
return {
// 只在组价加载是触发一次
// totalPrice : this.price * this.count
}
},
computed : {
totalPrice(){
return this.price * this.count
}
}
}
</script>
<style scoped>
h1{
background: tomato;
display: inline-block;
border-radius: 10px;
padding: 10px;
color: #ccc;
}
</style>
//InputItem
<template>
<div>
<input type="text" placeholder="输入要搜索内容" @input="fn" />
<input type="checkbox" @change="$emit('change', $event.currentTarget.checked)"/>
</div>
</template>
<script>
export default {
model: {
prop: "checked",
event: "change",
},
methods: {
fn(e) {
this.$emit("input", e.currentTarget.value);
},
},
data() {
return {};
},
};
</script>
<style scoped>
input {
border: 1px solid #333;
outline: 1px solid #007aff;
}
</style>
//调用3
<template>
<div>
<h1>组件自定义事件</h1>
<!-- @navover='fn1' -->
<nav-item3
:src="require('@/assets/logo.png')"
title="自定义事件"
@navClick="fn"
count=1
@add="fn2"
></nav-item3>
{{totalPrice}}
<total-price
:price="price"
:count="count"
v-on:click.native="fn3"
></total-price>
<!-- v-on :绑定事件监听器
native - 监听组件根元素的原生事件
-->
<!-- <input-item @input="fn4" ></input-item> -->
<input-item v-model="datastr" @change="fn5"></input-item>
{{datastr}}
</div>
<!-- @navClick="$emit('navClick' , '参数1' , '参数2')" -->
</template>
<script>
import $ from 'jquery'
export default {
data(){
return{
price : 123 ,
totalPrice : 0,
count : 0,
datastr : '啦啦'
}
},
methods:{
fn( argv1 ,argv2 ){
console.log( argv1 , argv2);
},
fn1(){
alert("监听navover")
},
fn2(count){ //Nav组件传到父级(本页面)
this.count = count
this.totalPrice = this.price * count
},
fn3(e){
console.log(e.currentTarget);
$(e.currentTarget).css('background','blue')
},
fn4(value){
this.datastr = value ;
},
fn5(arg){
alert(arg)
}
}
}
</script>
<style>
</style>