1、概念
Vue 是用于构建界面的javascript 库,渐进式JavaScript框架。
对比, jquery是以dom操作为中心javascript库。
vue 是以数据驱动为主javascript库。
数据改变更新页面,页面改变更新数据,vue 是数据双向绑定的框架。
bootstrap 是响应式框架 (ui响应式)
vue 也是响应式框架(data响应式)
2、声明式编程 (注重结果)
<div id="app">
<button v-on:click="foo">点击按钮</button>
</div>
<script>
new Vue({
el:"#app",
methods: {
foo(){ console.log("触发了点击事件")}
}
})
</script>
3、命令式编程 (注重过程)
<div id="app">
<button v-on:click="foo">点击按钮</button>
</div>
<script>
let button = document.querySelector("#app button");
button.onclick = function(){
console.log("触发了点击事件")
}
</script>
4、data响应式
vue@2版本,采用defineProperty方法实现,监听数据的改变。
<div id="root">
<input type="text" class="inp">
<h3 class="title"></h3>
</div>
<script>
// 获取标签
const inp_element = document.querySelector("#root input")
const title_element = document.querySelector("#root .title")
// 数据
let data = {
text: ""
}
// 定义储存器变量 (意义就是储存数据)
// let _text = "";
// 观察data的text属性的改变
Object.defineProperty(data,"text", {
// 读
get(){
// console.log("读取text")
return this._text;
},
// 写
set(value){
// console.log("写入text")
this._text = value;
// 更新页面
title_element.innerText = inp_element.value;
}
})
// 赋值表示写入 (带等于号)
// data.text = "123";
// 读取
// console.log(data.text);
// 数据双向绑定
// 1: 数据改变更新页面
// 2: 页面更新改变数据
inp_element.oninput = () => {
// 改变数据
data.text = inp_element.value;
}
</script>
5、Vue基本语法
5.1) 创建vue实例
<!-- 设置挂载点 -->
<div id="app">
{{color}}
</div>
<!-- 引入vue框架文件 -->
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
// 创建vue实例
// 选项式开发
// const option = {}
// 不想看到控制台输出日志信息
Vue.config.productionTip = false;
// 声明常量记录vue实例
const vm = new Vue({
// 挂载容器
el: "#app",
// 在哪添加数据? 在data中添加
// data:{
// color: "red",// vue实例中
// }
// 以后经常看到的是这种写法,组件中的数据是独立的
data(){
return {
color: "red"
}
},
})
// 检查vue实例
// console.log(vm);
// MVVM: 是一种软件设计模式
// MVVM是Model-View-ViewModel的简写。它本质上就是MVC的改进版。
// MVVM模式有助于将应用程序的业务和表示逻辑与用户界面 (UI) 清晰分离。
// 保持应用程序逻辑和UI之间的清晰分离有助于解决许多开发问题,并使应用程序更易于测试、维护和演变。
5.2) 模板语法 {{}}
<!-- 插值表达式 {{ js }} -->
<div id="app" v-cloak>
<h2>{{123}}</h2>
<!-- 报错 直接填写abc, 既不是字符串,也不是变量 -->
<!-- <h2>{{abc}}</h2> -->
<h2>{{'abc'}}</h2>
<!-- 可以书写三元运算 -->
<h2>{{typeof 'abc' === 'string' ? '字符串类型':'其他类型'}}</h2>
<!-- 可以填写变量 -->
<h2>{{title}}</h2>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
// 添加属性
data: {
title: "标题2222"
}
})
</script>
5.3) 指令
设置文本
v-text
v-html
设置属性
v-bind
设置数据双向绑定
v-model
条件渲染
v-show
v-if
列表渲染
v-for
事件绑定
v-on:click="foo"
@click="foo"
自定义指令
<div id="app">
<!-- 渲染纯文本 -->
<h2 v-text="`hello title`"></h2>
<hr>
<h3 v-mytext="2024"></h3>
<!-- 设置属性 -->
<hr>
<div v-bind:class="`red`"></div>
<hr>
<div v-mybind:class="`blue`"></div>
<hr>
<!-- 定义一个改变字体颜色的指令可以吗? 肯定可以 -->
<h2 v-color="`purple`">你好,世界</h2>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
// 当文档上指令满足不了我们的需求,可以选择自定义指令
// 1) 注册全局指令
Vue.directive('color', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el,option) {
if(typeof el === 'object'){
el.style.color = option.value;
}
}
})
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
// 2)局部自定义指令
directives: {
// 名称
mytext: {
//定义指令
inserted(el, option) {
// console.log(el, option);
if (typeof el === 'object') {
el.innerHTML = option.value;
}
}
},
// 动态绑定属性(仅仅class属性)
mybind: {
inserted(el, option) {
console.log(el, option);
// 检查el是否为dom对象
if (typeof el === 'object') {
// 获取属性
let arg = option.arg;
// 判断
if (arg == "class") {
el.className = option.value;
}
}
}
}
}
})
5.4)事件
v-on:事件类型=“方法”
@事件类型=“方法”
事件修饰符
<div id="app">
<!-- 阻止事件冒泡 -->
<div @click="f1">
<ul @click.stop="f2">
<li @click.stop="f3"></li>
</ul>
</div>
<!-- 属于捕获阶段 元素事件触发顺序是从外到内 -->
<!-- .capture.stop 阻止事件捕获 -->
<!-- <div @click.capture.stop="f1"> -->
<!--
<div @click.capture="f1">
<ul @click.capture="f2">
<li @click.capture="f3"></li>
</ul>
</div>
-->
<!-- 键盘行为 -->
<input v-model="keywords" type="text" placeholder="请输入关键字" @keydown="getInputVal">
<br>
<!-- @keydown.a 按下键盘a按键触发行为 -->
<!-- @keydown.enter 按下键盘回车按键触发行为 -->
<input v-model="v1" type="text" placeholder="请输入关键字" @keydown.enter="getInputText">
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
// 实现按下回车按键获取输入框的值
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
data: {
keywords: "",
v1: "",
},
methods: {
f1(){ console.log("div")},
f2(){ console.log("ul")},
f3(){ console.log("li")},
getInputVal(event){
// console.log(event)
// 解构赋值
let { code } = event;
if(code === "Enter") {
console.log("值:",this.keywords);
}
},
getInputText(){
console.log("值:",this.v1);
}
}
})
</script>
5.5) 属性计算、属性监听、属性过滤
属性计算
<div id="app">
<div class="container mt-3">
<div class="row">
<div class="col-4">
<input v-model="firstName" type="text" class="form-control" placeholder="请输入姓">
</div>
<div class="col-4">
<input v-model="lastName" type="text" class="form-control" placeholder="请输入名">
</div>
<div class="col-4">
<span style=" font-size: 22px;text-decoration: underline;">{{fullName}}</span>
</div>
</div>
</div>
<hr>
<div class="container">
<input class="form-control" type="number" v-model="num">
<button class="btn btn-success mt-2">计算 {{num}} 乘以 2 等于 {{doubleValue}} </button>
</div>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
// 设置数据
data: {
firstName: "",// 姓
lastName: "",//名
num: 0
},
// 属性计算 (只读不写)
// 例如: fullName , doubleValue这些属性是不可以修改的
// 错误: this.fullName = "xxx"
// 此处是对象
computed: {
// 在这个对象中写方法,这个方法名称就可以作为属性,retrun的值就是计算的结果
// 全名
// fullName: {
// get(){
// return this.firstName + this.lastName
// }
// },
fullName(){
return this.firstName + this.lastName;
},
// 获取双倍的值
doubleValue(){
return this.num * 2;
}
}
})
</script>
属性监听
<div id="app">
<div class="container mt-3">
<input v-model="city" type="text" placeholder="请输入城市" class="form-control">
</div>
<div class="container mt-3">
<ul>
<li @click="play(1)">歌曲1</li>
<li @click="play(2)">歌曲2</li>
<li @click="play(3)">歌曲3</li>
<li @click="play(4)">歌曲4</li>
</ul>
</div>
<div class="container mt-3">
<button @click="addAge" class="btn btn-success">改变用户年龄</button>
</div>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
// 属性侦听
// 主要是观察数据的变化,只要数据发生改变,就执行相关的回调函数
// data、路由等数据发生改变,就可以执行对应的回调,往往用于处理一些异步的操作
// 例如: 根据城市名称查询天气信息,根据歌曲id获取歌曲信息
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
data: {
city: "广州",
music_id: "",
user: {
age: 20
}
},
// 侦听器
// 侦听器、属性侦听不是计算结果,不用写return
// 这些回调函数的名称就是属性名称,例如data: {city: music_id,user 。。。。}
watch: {
// 观察city属性的变化
// nValue(改变之后的数据),oValue(改变之前的数据) 可选参数
city(nValue,oValue){
console.log("观察city是否发生改变....")
console.log({nValue,oValue})
},
music_id: {
handler(nValue,oValue){
console.log("观察music_id是否发生改变....",nValue)
}
},
// 遇到引用数据类型的时候,考虑使用深度侦听
user:{
deep: true,// 深度侦听
immediate: true, // 立即执行
handler(nValue,oValue){
console.log("观察user.age是否发生改变....",nValue.age)
}
}
},
// 设置方法
methods: {
play(id){
this.music_id = id;
},
addAge(){
this.user.age ++;
}
}
})
</script>
属性过滤
<div id="app">
<div class="container mt-3">
<h3>{{str}}</h3>
<h3>{{str | xxx }}</h3>
<h3>{{str | yyy }}</h3>
<h3>{{str | xxx | zzz }}</h3>
</div>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
data: {
str: "abc123efg456"
},
// 过滤器
// 就是可以作为工具函数来使用哦~~~
// 通过 “|” 填写过滤器,让其执行相关的回调函数,在函数作用域中可以把处理结果返回
filters: {
// 编写xxx回调函数
xxx(value){
// console.log(this);// window
// 去掉所有数字字符
return value.replace(/\d/g,'');
},
yyy(value){
// console.log(this);// window
// 去掉所有字母字符
return value.replace(/[a-z]/ig,'');
},
zzz(value){
// 把字母转大写
return value.toUpperCase();
}
}
})
</script>
5.6)生命周期、钩子函数
程序从创建到销毁的过程,我们叫做生命周期。
主要是让我们知道,在不同阶段可以做不同事情。
人的生命周期: 少年、青年、中年、老年
Vue的生命周期: 创建阶段、挂载阶段、更新阶段、销毁阶段
在不同的阶段提供了不同的回调函数(钩子函数)
<div id="app">
<h2>数字: <span>{{num}}</span></h2>
<div ref="box">hello world</div>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
//禁止控制台输出日志信息
Vue.config.productionTip = false;
const vm = new Vue({
//挂载容器
el: "#app",
// 设置数据
data: {
num: 0,
timer: null
},
// 生命周期: 程序从创建到销毁的过程。注意回调函数先后顺序....
// 钩子函数: 指的是回调函数,生命周期的钩子函数(在vue@2中有8个生命周期的钩子函数)
// 1) 创建阶段
// 创建之前执行的钩子函数
beforeCreate(){
console.log("1:",this.num);
},
// 创建后执行的钩子函数 (初始化数据)
created(){
console.log("2:",this.num);
console.log(this.$refs.box);// undefined
// 初始化
// 问题:此处定时器函数不箭头函数,应该注意什么?
this.timer = setInterval(()=> {
if(this.num == 5) {
clearInterval(this.timer);
return ;
}
++ this.num;
},1000)
},
// 2)挂载阶段
// 挂载之前执行的钩子函数
beforeMount(){
console.log("3:",this.num);
console.log(this.$refs.box);// undefined
},
// 挂载后执行的钩子函数 (DOM操作)
mounted(){
console.log("4:",this.num);
console.log(this.$refs.box);// <div>hello world</div>
// 为了让dom操作更加稳定,可以在此处执行$nextTick回调函数
// 为了减少报错,所以调用$nextTick回调函数
this.$nextTick(()=>{
// 判断程序中是否存在这个标签
if(this.$refs.box){
// 进行dom操作
this.$refs.box.style.color = "red";
this.$refs.box.style.fontSize = "20px";
}
})
},
// 3)更新阶段
// 要数据发生改变才执行的回调函数
beforeUpdate(){
console.log("5:",this.num);
},
updated(){
console.log("6:",this.num);
},
// 4)销毁阶段
// 程序不存在了,或者以后卸载组件,(显示|隐藏 v-if="false")
beforeDestroy(){
console.log("7:",this.num);
},
destroyed(){
console.log("8:",this.num);
}
})
// 为了看得见销毁阶段的钩子函数被执行,可以调用销毁方法
// vm.$destroy();
// 通过定时器函数
// const t = setInterval(()=>{
// // 修改数据
// vm.num ++;
// },1000)
</script>
5.7)组件、组件传值
组件是可复用的 Vue 实例.
组件可以是指项目中某个功能,或者页面的某个区块。
例如:按钮,下拉菜单,轮播图,弹窗.....
<div id="app">
<el-button></el-button>
<!-- <ElSearch></ElSearch> 错误的 -->
<el-search></el-search>
</div>
<hr>
<div id="app2">
<el-button></el-button>
<!-- <el-search></el-search> 错误的 -->
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
// 组件:功能 (相当于vue实例)
// 组件是可复用的 Vue 实例
// 步骤:
// 1. 定义组件
// 2. 注册组件
// 3. 使用组件
// 一) 全局组件
// 1. 定义按钮组件 (template选项在vue2版本中必须有根节点)
const ElButton = {
// 设置数据
data() {
return {
message: "这是一个按钮123"
}
},
// 渲染模板
template: `
<div>
<div>{{message}}</div>
<button @click="foo" style="padding: 10px 20px; border: 0; background-color: skyblue; color: white;">
点击按钮
</button>
</div>
`,
// 设置方法
methods: {
// 提示
foo(){
alert("您好,触发事件。。。")
}
}
}
// 2. 注册组件(此处表示全局注册)
Vue.component("el-button",ElButton);
//禁止控制台输出日志信息
Vue.config.productionTip = false;
// 创建vue实例
new Vue({
//挂载容器
el: "#app",
// 注册组件(此处表示局部注册)
components: {
// 此处注册组件名称采用驼峰命名“ElSearch”,在使用的时候需要改成 “el-search”
// "el-search": {},
"ElSearch": {
data(){
return {
}
},
template: `
<div>
<input type="text" placeholder="请输入关键字" style="width: 90%;height: 40px;">
</div>
`
},
}
})
new Vue({
//挂载容器
el: "#app2",
})
// 注册组件注意事项:
// 1) 采用驼峰命名法注册组件名称时“”ElSearch,使用组件时需要改用短横线“el-search”
// 2) 不能使用html文档内置的标签名称作为组件名称例如: div header footer nav
// 3) 组件中的data一个函数,并且返回一个对象
// 4) template选项需要有根节点(在vue@2版本)
// 5) 组件的属性计算、侦听,过滤,生命周期的钩子和vue实例的写法一样
</script>
组件嵌套关系
<div id="app">
<element-parent></element-parent>
<!-- <element-child></element-child> 错误的 -->
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
//禁止控制台输出日志信息
Vue.config.productionTip = false;
// 定义子组件
const ElementChild = {
template: `
<div>
<h3>子组件</h3>
</div>
`
}
// 定义父组件
const ElementParent = {
template: `
<div>
<h2>父组件</h2>
<element-child></element-child>
</div>
`,
// 在父组件中注册子组件
components: {
ElementChild
}
}
// vue实例对象
new Vue({
//挂载容器
el: "#app",
// 在vue实例中注册父组件
components: {
ElementParent
}
})
父组件传值给子组件
<div id="app">
<parent></parent>
</div>
<script src="../libs/vue@2.7.16/vue.js"></script>
<script>
// 父传子
// 子组件
const child = {
// 自定义属性
props: ["num"],
template: `
<div style="border: 1px solid #ccc">
<h4>子组件</h4>
<p>{{num}}</p>
</div>
`
}
// 父组件
const parent = {
// 在父组件中注册子组件
components: {
// child: child,
child
},
template: `
<div style="border: 1px solid #000">
<h3>父组件</h3>
<child :num="100"></child>
</div>
`
}
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
// 在vue实例中注册父组件
components: {
parent
}
})
</script>
子组件传值给父组件
<div id="app">
<parent></parent>
</div>
<script src="../libs/vue@2.7.16/vue.js"></script>
<script>
// 父传子
// 子组件
// (通常需要借助事件(延迟函数、钩子函数)发送数据)
// <button @click="send">点击发送</button>
const child = {
template: `
<div style="border: 1px solid #ccc">
<h4>子组件</h4>
</div>
`,
methods: {
send(){
this.$emit("xxx",100)
}
},
// 钩子函数
created(){
this.$emit("xxx",100)
}
}
// 父组件
const parent = {
// 在父组件中注册子组件
components: {
// child: child,
child
},
template: `
<div style="border: 1px solid #000">
<h3>父组件</h3>
<p>{{num}}</p>
<child @xxx="recive"></child>
</div>
`,
methods: {
recive(cnum){
this.num = cnum;
}
},
data(){
return {
num: 0
}
}
}
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
// 在vue实例中注册父组件
components: {
parent
}
})
</script>
兄弟组件之间传值
1)
<div id="app">
<comp-a></comp-a>
<comp-b></comp-b>
</div>
<script src="../libs/vue@2.7.16/vue.js"></script>
<script>
// 创建vue实例作为通信的桥梁(这种有响应式)
const bridge = new Vue();
// 并列关系组件
const CompA = {
template: `
<div>
<h3>组件A</h3>
<button @click="senda">数字自增</button>
</div>
`,
data(){
return {
num: 100
}
},
methods: {
senda(){
this.num ++;
let value = this.num;
bridge.$emit('xxx', value)
},
},
created(){
// 发送数据
setTimeout(()=>{
this.senda();
},0)
}
}
const CompB = {
template: `
<div>
<h3>组件B</h3>
<p>{{num}}</p>
</div>
`,
data(){
return {
num: 0
}
},
created(){
// 监听组件A的事件且接收组件A的数据
bridge.$on("xxx",(value)=>{
this.num = value;
})
}
}
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
components: { CompA , CompB },
})
</script>
2)
<div id="app">
<button @click="changeNum">点击按钮</button>
<comp-header></comp-header>
<comp-footer></comp-footer>
</div>
<script src="../libs/vue@2.7.16/vue.js"></script>
<script>
// 找到Vue的原型对象
// 在原型对象上添加的属性和方法,可以给所属构造函数的实例对象使用!!!
// 在原型对象上添加的数据,是没有响应式的。
Vue.prototype.num = 100;
// 定义组件
// 头部组件
const CompHeader = {
template: `
<header>
<h3>头部组件</h3>
<p>{{num}}</p>
</header>
`
}
// 尾部组件
const CompFooter = {
template: `
<footer>
<h3>尾部组件</h3>
<p>{{num}}</p>
</footer>
`
}
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
// 注册组件
components: {
CompHeader,
CompFooter
},
// 改变num
methods: {
changeNum(){
this.num ++
console.log(this.num);
}
}
})
5.8) 混入语法
<div id="app">
<h2>Vue实例</h2>
<p>{{num}}</p>
<button @click="add">按钮</button>
<hr>
<comp-a></comp-a>
<hr>
<comp-b></comp-b>
<hr>
<comp-c></comp-c>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
// 混入: 是指代码的重复使用
// 提取重复的代码( vue实例optins选项 )
const options = {
data(){
return {
num: 100
}
},
methods: {
add(){
this.num ++;
}
},
watch: {
num(nValue){
console.log("值:",nValue);
}
},
created(){
console.log("初始化...")
}
}
// 组件A
const CompA = {
// 当data选项中的数据和mixins选项中的属性和方法相同的情况,优先使用的是组件的属性和方法等
data(){
return {
num: 1
}
},
// 混入语法
mixins: [
options
],
template: `
<div>
<h3>组件A</h3>
<p>{{num}}</p>
<button @click="add">按钮</button>
</div>
`,
// data(){
// return {
// num: 100
// }
// },
// metods: {
// add(){
// this.num ++;
// }
// }
}
// 组件B
const CompB = {
// 混入语法
mixins: [
options
],
template: `
<div>
<h3>组件B</h3>
<p>{{num}}</p>
<button @click="add">按钮</button>
</div>
`,
// data(){
// return {
// num: 100
// }
// },
// metods: {
// add(){
// this.num ++;
// }
// }
}
// 组件C(也是定义组件的意思)
const CompC = Vue.extend({
// 混入语法
mixins: [
options
],
template: `
<div>
<h3>组件C</h3>
<p>{{num}}</p>
<button @click="add">按钮</button>
</div>
`,
})
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
// 混入语法
mixins: [
options
],
//挂载容器
el: "#app",
// 注册组件
components: { CompA , CompB , CompC},
})
</script>
5.9) 组件插槽、动态组件
插槽: 是组件的拓展。让组件内容更加丰富、更加灵活渲染。
匿名插槽
<div id="app">
<comp-header><span>搜狐 </span></comp-header>
<comp-header><span>淘宝 </span></comp-header>
<comp-header><span>京东 </span></comp-header>
<comp-header><span>拼多多</span></comp-header>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
// 匿名插槽
// <slot></slot>
// 编写头部组件
const CompHeader = {
template: `
<header class="header">
<!-- 插槽 -->
<div class="left">
<slot></slot>
</div>
</header>
`
}
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
// 注册组件
components: {CompHeader}
})
</script>
具名插槽
<div id="app">
<comp-header>
<!-- 代表left插槽 -->
<template v-slot:left>
<span>LOGO</span>
</template>
<!-- 代表center插槽 -->
<template v-slot:center>
<input type="text" placeholder="请输入关键字">
</template>
<!-- 代表right插槽 -->
<template #right>
<a href="#">登录</a>
</template>
</comp-header>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
// 具名插槽
// <slot name="left"></slot>
// 编写头部组件
const CompHeader = {
template: `
<header class="header">
<!-- 插槽 -->
<div class="left">
<slot name="left"></slot>
</div>
<div class="center">
<slot name="center"></slot>
</div>
<div class="right">
<slot name="right"></slot>
</div>
</header>
`
}
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
// 注册组件
components: {CompHeader}
})
</script>
动态组件: 可以利用内置组件component的is属性,决定渲染哪一个组件。
<div id="app">
<!-- <new-song></new-song> -->
<!-- <hot-song></hot-song> -->
<!-- tab选项卡 -->
<div class="tab">
<div @click="tabFunc(0)" :class="['btn',index==0?'active':'']">最新</div>
<div @click="tabFunc(1)" :class="['btn',index==1?'active':'']">热门</div>
</div>
<!-- 内置组件 -->
<component :is="compName"></component>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
// 定义组件
// 最新音乐
const NewSong = {
template: `
<div style="height: 120px;background-color: pink;">
<h3>最新音乐</h3>
</div>
`
}
// 热门音乐
const HotSong = {
template: `
<div style="height: 120px;background-color: yellowgreen;">
<h3>热门音乐</h3>
</div>
`
}
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
// 设置数据
data(){
return {
// 记录组件名称
compName: 'new-song',
index: 0
}
},
// 设置方法
methods: {
tabFunc(i){
this.index = i;
// i === 0 ? this.compName = "new-song": this.compName = "hot-song";
if(i === 0) this.compName = "new-song";
if(i === 1) this.compName = "hot-song";
}
},
//挂载容器
el: "#app",
// 注册组件
components: {
NewSong,
HotSong
}
})
</script>
5.10) 过渡、动画
利用内置组件 transition 组件,可以实现过渡、动画这些效果。
可以看见元素/组件
从显示到隐藏或从隐藏到显示的这个过程。
显示: 入场效果
隐藏: 离场效果
过渡案例:
<style>
/* 入场类名 */
/* 入场之前的样式 */
.v-enter {
transform: translateX(-100%);
opacity: 0;
}
/* 入场过程中的样式 */
.v-enter-active {
transition: all .5s;
}
.v-enter-to {
transform: translateX(0px);
opacity: 1;
}
/* 离场类名 */
/* 离场之前的样式 */
.v-leave {
transform: translateY(0px);
opacity: 1;
}
/* 离场过程中的样式 */
.v-leave-active {
transition: all .5s;
}
/* 离场后的样式 */
.v-leave-to {
transform: translateY(-100%);
opacity: 0;
}
/* 设置transition组件的name属性为demo后 */
/* 入场类名 */
/* 入场之前的样式 */
.demo-enter {
transform: translateX(-100%) rotate(180deg);
opacity: 0;
}
/* 入场过程中的样式 */
.demo-enter-active {
transition: all .5s;
}
.demo-enter-to {
transform: translateX(0px) rotate(0deg);
opacity: 1;
}
/* 离场类名 */
/* 离场之前的样式 */
.demo-leave {
transform: translateY(0px) rotate(0deg);
opacity: 1;
}
/* 离场过程中的样式 */
.demo-leave-active {
transition: all .5s;
}
/* 离场后的样式 */
.demo-leave-to {
transform: translateY(-100%) rotate(180deg);
opacity: 0;
}
</style>
</head>
<body>
<div id="app">
<div class="container mt-2">
<div class="btn btn-success" @click="isShow=true">入场(显示)</div>
<div class="btn btn-danger" @click="isShow=false">离场(隐藏)</div>
<!-- <div v-if="isShow" class="bg-primary mt-2" style="height: 200px;"></div> -->
<transition>
<div v-if="isShow" class="bg-primary mt-2" style="height: 200px;"></div>
</transition>
<transition name="demo">
<div v-if="isShow" class="bg-primary mt-2" style="height: 200px;"></div>
</transition>
</div>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
// 数据
data(){
return {
isShow: true
}
},
})
</script>
动画案例:
<!-- 动画库 -->
<link rel="stylesheet" href="./libs/animate.min.css">
<style>
/* 入场类名 */
.enter-box {
animation: enter-ani .5s forwards;
}
/* 离场类名 */
.leave-box {
animation: leave-ani .5s forwards;
}
/* 自定义动画 */
/* 入场动画 */
@keyframes enter-ani {
0% {
transform: scale(.5) rotate(180deg);
opacity: 0;
}
100% {
transform: scale(1) rotate(0deg);
opacity: 1;
}
}
/* 离场动画 */
@keyframes leave-ani {
0% {
transform: scale(1) rotate(0deg);
opacity: 1;
}
100% {
transform: scale(.5) rotate(180deg);
opacity: 0;
}
}
</style>
</head>
<body>
<div id="app">
<div class="container mt-2">
<div class="btn btn-success" @click="isShow=true">入场(显示)</div>
<div class="btn btn-danger" @click="isShow=false">离场(隐藏)</div>
<!-- 处理动画,利用enter-active,leave-active这些属性设置 -->
<!-- 1) 自定义动画 -->
<transition
enter-active-class="enter-box"
leave-active-class="leave-box"
>
<div v-if="isShow" class="bg-primary mt-2" style="height: 200px;"></div>
</transition>
<!-- 2) 使用动画库 -->
<transition
enter-active-class="animate__animated animate__backInLeft"
leave-active-class="animate__animated animate__backOutDown"
>
<div v-if="isShow" class="bg-warning mt-2" style="height: 200px;"></div>
</transition>
</div>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
// 数据
data(){
return {
isShow: true
}
},
})
</script>
keep-alive组件缓存组件状态
<div id="app">
<div class="container mt-2">
<div class="btn btn-success" @click="isShow=true">入场(显示)</div>
<div class="btn btn-danger" @click="isShow=false">离场(隐藏)</div>
<!-- 处理动画,利用enter-active,leave-active这些属性设置 -->
<!-- 1) 自定义动画 -->
<transition
enter-active-class="enter-box"
leave-active-class="leave-box"
>
<!-- 组件 -->
<!-- vue实例和组件都有生命周期 创建 挂载 更新 销毁 -->
<!-- keep-alive 缓存数据状态的内置组件 -->
<!-- include (包括) 和 exclude (排除) 允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示: -->
<keep-alive>
<aaa v-if="isShow"></aaa>
</keep-alive>
</transition>
</div>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
// 定义组件
const aaa = {
data(){
return {
inpText: ""
}
},
methods: {
getInputText(){
console.log("输入的值:",this.inpText)
}
},
template: `
<div class="bg-info mt-2 p-3" style="height: 200px;">
<input v-model="inpText" type="text" class="form-control" placeholder="请输入关键字">
<button @click="getInputText" class="btn btn-primary mt-2">确定</button>
</div>
`,
created(){
console.log("创建了")
},
destroyed(){
console.log("销毁了")
}
}
//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
//挂载容器
el: "#app",
// 数据
data(){
return {
isShow: true
}
},
// 注册组件
components: {
aaa
}
})
</script>
组件:
1) 自定义组件(定义组件、注册组件、使用组件)
2) 内置组件 (transition 、component 、keep-alive)
5.11)脚手架(另外一博客)