v
- 创建一个vue实例
- 插值表达式{{}}
- vue响应式特性
- vue指令
- v-if vs. v-show 指令
- v-else-if 指令
- v-on指令 注册监听
- 内联语句
- methods中的函数名![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/8b9d81539ba74e6691b27694813e0f65.png)
- v-on 调用传参
- v-bind 动态的设置html标签
- v-for指令 基于数据循环
- v-for中的key
- v-model 表单绑定
- 指令修饰符
- v-bind对于样式控制的增强
- v-model应用于其他表单元素
- 计算属性
- computed 计算属性 VS methods方法
- 计算属性的完整写法
- watch 监听器
- watch完整写法
- VUE的生命周期和生命周期的四个阶段
- created应用新闻迭代
- 输入框获取焦点
- 工程化开发&脚手架vue CLI
- 组件化开发&根组件
- 局部注册
- 全局注册组件
- 组件样式冲突scoped
- data是一个函数
- 组件通信
- 父传子用props方式
- 子传父
- prop校验
- 类型校验
- 非父子通信-事件总线
- 非父子通宵扩展-provide-inject
- v-model原理
- 表单类组件封装&v-model简化代码
- sync修饰符
- ref和refs获取dom和组件
- vue异步更新 nextTick
- Vue 自定义指令-基础语法
- 自定义指令-封装v-loading
- 插槽-默认插槽
- 插槽-后备内容
- 具名插槽
- 作用域插槽
- 组件标签封装-my-tag
- 单页应用&路由
- 路由的使用
- 组件存放
- 路由封装抽离
创建一个vue实例
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><!--创建vue容器初始化渲染1.准备容器2.引包(vue的js包) 3.创建实例4.添加配置项 完成渲染--><div id="app"><!--这将来会编写一些用于渲染的代码逻辑-->{{msg}}</div><!-- 创建实例 --><script>//引入了vuejs的核心包,在全局环境下,就有了vue构造函数const app =new Vue(//通过el配置选择器指定了vue管理的是那个盒子//#app就指定管理了上面app的那个盒子{el:'#app',//通过data提供数据进行渲染data:{msg:"hello vue"}})</script>
</body>
</html>
插值表达式{{}}
插值是用来展示渲染的
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><!--创建vue容器初始化渲染1.准备容器2.引包(vue的js包) 3.创建实例4.添加配置项 完成渲染--><div id="app"><!--这将来会编写一些用于渲染的代码逻辑-->{{msg.toUpperCase()}}{{msg.toUpperCase()+"你好啊"}}<h1>{{msg}}</h1></div><!-- 创建实例 --><script>//引入了vuejs的核心包,在全局环境下,就有了vue构造函数const app =new Vue(//通过el配置选择器指定了vue管理的是那个盒子//#app就指定管理了上面app的那个盒子{el:'#app',//通过data提供数据进行渲染data:{msg:"hello word"}})</script>
</body>
</html>
vue响应式特性
//引入了vuejs的核心包,在全局环境下,就有了vue构造函数const app =new Vue(//通过el配置选择器指定了vue管理的是那个盒子//#app就指定管理了上面app的那个盒子{el:'#app',//通过data提供数据进行渲染data:{//响应式数据》数据变化后视图会自动更新msg:"你好,响应式"}//data中的数据是会被添加到实例上。//1.实例.属性名//2.实例.属性名=新值})
一旦数据变化数据也会变化。
vue指令
具体指令查看:https://cn.vuejs.org/api/built-in-directives.html#built-in-directives
例如v-html这个指令。
v-html 的内容直接作为普通 HTML 插入
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><!--创建vue容器初始化渲染1.准备容器2.引包(vue的js包) 3.创建实例4.添加配置项 完成渲染--><div id="app"><div v-html="msg"></div></div><!-- 创建实例 --><script>//引入了vuejs的核心包,在全局环境下,就有了vue构造函数const app =new Vue(//通过el配置选择器指定了vue管理的是那个盒子//#app就指定管理了上面app的那个盒子{el:'#app',//通过data提供数据进行渲染data:{//响应式数据》数据变化后视图会自动更新msg:"<a href='http://ww.baidu.com'>百度</a>"}//data中的数据是会被添加到实例上。//1.实例.属性名//2.实例.属性名=新值})</script>
</body>
</html>
v-if vs. v-show 指令
v-if 是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。
v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。
相比之下,v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。
总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show
较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。
show是通过css来控制隐藏,if是通过判断条件控制元素的创建和移除
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><div id="app"><h1 v-show="msg">Hello!</h1><h1 v-if="msg">v-if</h1></div><!-- 创建实例 --><script>const app =new Vue({el:'#app',data:{msg: true}})</script>
</body>
</html>
v-else-if 指令
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><div id="app"><p v-if="gender===1">男</p><p v-else>女</p><hr><p v-if="score>=90">A</p><p v-else-if="score>=70">B</p><p v-else>C</p></div><!-- 创建实例 --><script>const app =new Vue({el:'#app',data:{gender: 2,score:80}})</script>
</body>
</html>
v-on指令 注册监听
内联语句
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><div id="app"><button v-on:click="count--">-</button><span>{{count}}</span><!-- 给+号注册点击事件 --><button v-on:click="count++">+</button></div><!-- 创建实例 --><script>const app =new Vue({el:'#app',data:{count:100}})</script>
</body>
</html>
或者用@click注册
<button @click="count++">+</button>
methods中的函数名
methods中用来提供方法。
实现隐藏方法
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><div id="app"><button @click="fun">显示隐藏</button><h1 v-show="isshow">测试</h1></div><!-- 创建实例 --><script>const app =new Vue({el:'#app',data:{isshow:true},methods:{fun(){app.isshow=!app.isshow; }}})</script>
</body>
</html>
v-on 调用传参
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><div id="app"><button @click="fun(5)">减5 </button><button @click="fun(10)">减10 </button><p>当前数值:{{number}}</p></div><!-- 创建实例 --><script>const app =new Vue({el:'#app',data:{number: 100},methods:{fun(number){this.number-=number;}}})</script>
</body>
</html>
v-bind 动态的设置html标签
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><div id="app"><img v-bind:src="imgUrl"></div><!-- 创建实例 --><script>const app =new Vue({el:'#app',data:{imgUrl: "./omg/10.png "}})</script>
</body>
</html>
简写
<div id="app"><img :src="imgUrl">
</div>
v-for指令 基于数据循环
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><div id="app"><ul><li v-for="(item,index) in list">{{item}} - {{index}}</li></ul></div><!-- 创建实例 --><script>const app =new Vue({el:'#app',data:{list: ['1','2','3']}})</script>
</body>
</html>
v-for中的key
v-model 表单绑定
数据变化:视图自动你更新 视图变化:数据自动更新
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><div id="app">账户:<input v-model="username"><br>密码:<input v-model="password"><br><button @click="login">登陆</button></div><!-- 创建实例 --><script>const app =new Vue({el:'#app',data:{username:'',password:''},methods:{login(){console.log(this.username,this.password)}}})</script>
</body>
</html>
指令修饰符
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><div id="app"><!-- 绑定键盘回车事件 --><input @keyup.enter="fn" v-model="username" type="text"></div><!-- 创建实例 --><script>const app =new Vue({el:'#app',data:{username:''},methods:{fn(){console.log(this.username)}}})</script>
</body>
</html>
v-bind对于样式控制的增强
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 实例</title><!-- 引入 Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script><style>.active{color: red;}</style>
</head><body><div id="app"><ul><li v-for="(item,index) in list" :key="item.id" @click="activeIndex = index">//通过{active: index === activeIndex}"实现动态控制<a :class="{active: index === activeIndex}" href="#">{{item.name}}</a></li></ul></div><!-- 创建实例 --><script>const app =new Vue({el:'#app',data:{activeIndex:0,//记录高亮list:[{id:1,name:'京东秒杀'},{id:2,name:'每日特价'},{id:3,name:'品类秒杀'},]}})</script>
</body>
</html>
:STYLE单独控制某个属性变化
v-model应用于其他表单元素
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>textarea {display: block;width: 240px;height: 100px;margin: 10px 0;}</style>
</head>
<body><div id="app"><h3>小黑学习网</h3>姓名:<input type="text" v-model="username"> <br><br>是否单身:<input type="checkbox" v-model="isSingle"> <br><br><!-- 前置理解:1. name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥2. value: 给单选框加上 value 属性,用于提交给后台的数据结合 Vue 使用 → v-model-->性别: <input v-model="gender" type="radio" name="gender" value="1">男<input v-model="gender" type="radio" name="gender" value="2">女<br><br><!-- 前置理解:1. option 需要设置 value 值,提交给后台2. select 的 value 值,关联了选中的 option 的 value 值结合 Vue 使用 → v-model-->所在城市:<select v-model="cityId"><option value="101">北京</option><option value="102">上海</option><option value="103">成都</option><option value="104">南京</option></select><br><br>自我描述:<textarea v-model="desc"></textarea> <button>立即注册</button></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {username: '',isSingle: false,gender: "2",cityId: '102',desc: ""}})</script>
</body>
</html>
计算属性
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>table {border: 1px solid #000;text-align: center;width: 240px;}th,td {border: 1px solid #000;}h3 {position: relative;}</style>
</head>
<body><div id="app"><h3>小黑的礼物清单</h3><table><tr><th>名字</th><th>数量</th></tr><tr v-for="(item, index) in list" :key="item.id"><td>{{ item.name }}</td><td>{{ item.num }}个</td></tr></table><!-- 目标:统计求和,求得礼物总数 --><p>礼物总数:{{ totalCount }} 个</p></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {// 现有的数据list: [{ id: 1, name: '篮球', num: 1 },{ id: 2, name: '玩具', num: 2 },{ id: 3, name: '铅笔', num: 5 },]},computed: {totalCount () {// 基于现有的数据,编写求值逻辑// 计算属性函数内部,可以直接通过 this 访问到 app 实例// console.log(this.list)// 需求:对 this.list 数组里面的 num 进行求和 → reducelet total = this.list.reduce((sum, item) => sum + item.num, 0)return total}}})</script>
</body>
</html>
computed 计算属性 VS methods方法
计算属性是有缓存的,一旦算出来结果就会立刻缓存
下一次读取》直接读缓存就行》性能特别高
计算属性的完整写法
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body><div id="app">姓:<input type="text"><br>名:<input type="text"><br><p>姓名:{{ fullName }}</p><button>修改姓名</button></div><script>const app = new Vue({el: '#app',data: {firsName:"刘",lastName:"备",},computed: {fullName: {get() {return this.firstName + this.lastName;}}
},methods: {changeName(){}}})</script>
</body>
</html>
watch 监听器
作用:监视数据变化,执行一些逻辑或异步操作
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style>* {margin: 0;padding: 0;box-sizing: border-box;font-size: 18px;}#app {padding: 10px 20px;}.query {margin: 10px 0;}.box {display: flex;}textarea {width: 300px;height: 160px;font-size: 18px;border: 1px solid #dedede;outline: none;resize: none;padding: 10px;}textarea:hover {border: 1px solid #1589f5;}.transbox {width: 300px;height: 160px;background-color: #f0f0f0;padding: 10px;border: none;}.tip-box {width: 300px;height: 25px;line-height: 25px;display: flex;}.tip-box span {flex: 1;text-align: center;}.query span {font-size: 18px;}.input-wrap {position: relative;}.input-wrap span {position: absolute;right: 15px;bottom: 15px;font-size: 12px;}.input-wrap i {font-size: 20px;font-style: normal;}</style><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script></head><body><div id="app"><!-- 条件选择框 --><div class="query"><span>翻译成的语言:</span><select><option value="italy">意大利</option><option value="english">英语</option><option value="german">德语</option></select></div><!-- 翻译框 --><div class="box"><div class="input-wrap"><textarea v-model="obj.words"></textarea><span><i>⌨️</i>文档翻译</span></div><div class="output-wrap"><div class="transbox">mela</div></div></div></div><script>// 接口地址:https://applet-base-api-t.itheima.net/api/translate// 请求方式:get// 请求参数:// (1)words:需要被翻译的文本(必传)// (2)lang: 需要被翻译成的语言(可选)默认值-意大利// -----------------------------------------------const app = new Vue({el: '#app',data: {words: '',},// 具体讲解:(1) watch语法 (2) 具体业务实现watch:{//该方法会在数据变化的时候执行'obj.words'(newValue,oldValue){console.log("变化了",newValue,oldValue)}}})</script></body>
</html>
watch完整写法
VUE的生命周期和生命周期的四个阶段
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div id="app"><h3>{{ title }}</h3><div><button @click="count--">-</button><span>{{ count }}</span><button @click="count++">+</button></div></div><script src="./vue.js"></script><script>const app = new Vue({el: '#app',data: {count: 100,title: '计数器'},//1.创建阶段beforeCreate(){console.log("响应数据准备好之前")},created(){console.log("响应数据准备好之后")},//2.挂载阶段beforeMount(){console.log("模板渲染之前")},mounted(){console.log("模板渲染之后")},//3.更新阶段(修改数据》更新视图beforeUpdatre(){console.log("数据修改了视图还没有更新");},updated(){console.log('update数据修改,视图已经更新了')},//4.卸载阶段beforeDestroy(){console.log('卸载前')},destroyed(){console.log("卸载后")}})</script>
</body></html>
created应用新闻迭代
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;list-style: none;}.news {display: flex;height: 120px;width: 600px;margin: 0 auto;padding: 20px 0;cursor: pointer;}.news .left {flex: 1;display: flex;flex-direction: column;justify-content: space-between;padding-right: 10px;}.news .left .title {font-size: 20px;}.news .left .info {color: #999999;}.news .left .info span {margin-right: 20px;}.news .right {width: 160px;height: 120px;}.news .right img {width: 100%;height: 100%;object-fit: cover;}</style>
</head>
<body><div id="app"><ul><li v-for="(item,index) in list" :key="item.id" class="news"><div class="left"><div class="title">{{item.title}}</div><div class="info"><span>{{item.source}}</span><span>{{item.time}}</span></div></div><div class="right"><img :src="item.img" alt=""></div></li></ul></div><script src="./vue.js"></script><script src="./axios.js"></script><script>// 接口地址:http://hmajax.itheima.net/api/news// 请求方式:getconst app = new Vue({el: '#app',data: {list:[]},async created(){//进入页面立即发送请求const res = await axios.get('http://hmajax.itheima.net/api/news');console.log(res)//将数据更新到data中的listthis.list=res.data.data}})</script>
</body>
</html>
输入框获取焦点
<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>示例-获取焦点</title><!-- 初始化样式 --><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reset.css@2.0.2/reset.min.css"><!-- 核心样式 --><style>html,body {height: 100%;}.search-container {position: absolute;top: 30%;left: 50%;transform: translate(-50%, -50%);text-align: center;}.search-container .search-box {display: flex;}.search-container img {margin-bottom: 30px;}.search-container .search-box input {width: 512px;height: 16px;padding: 12px 16px;font-size: 16px;margin: 0;vertical-align: top;outline: 0;box-shadow: none;border-radius: 10px 0 0 10px;border: 2px solid #c4c7ce;background: #fff;color: #222;overflow: hidden;box-sizing: content-box;-webkit-tap-highlight-color: transparent;}.search-container .search-box button {cursor: pointer;width: 112px;height: 44px;line-height: 41px;line-height: 42px;background-color: #ad2a27;border-radius: 0 10px 10px 0;font-size: 17px;box-shadow: none;font-weight: 400;border: 0;outline: 0;letter-spacing: normal;color: white;}body {background: no-repeat center /cover;background-color: #edf0f5;}</style>
</head><body>
<div class="container" id="app"><div class="search-container"><img src="https://www.itheima.com/images/logo.png" alt=""><div class="search-box"><input type="text" v-model="words" id="inp"><button>搜索一下</button></div></div>
</div><script src="./vue.js"></script>
<script>const app = new Vue({el: '#app',data: {words: ''},//等输入框渲染完成,输入框获取焦点mounted(){document.querySelector("#inp").focus()}})
</script></body></html>
工程化开发&脚手架vue CLI
组件化开发&根组件
局部注册
新建components局部文件夹,在里面编写局部组件
编写一个头部局部组件
<template><div class="hm-header">我是header</div>
</template><script>
export default {}
</script><style>.hm-header{height: 100px;line-height: 100px;text-align:center;font-size: 30px;}
</style>
然后引入局部组件使用
<template><div class="App"><!-- 头部组件 --><HmHeader></HmHeader><!-- 主体组件 --><!-- 底部组件 --></div>
</template><script>
import HmHeader from './components/HmHeader.vue';
export default {// 使用变量components:{// 组件名:组件对象HmHeader:HmHeader}
}
</script><style>.App{width: 600px;height: 700px;background-color: aqua;margin:0 auto;padding:1 ;}
</style>
全局注册组件
在main.JS进行全局注册
// 导入全局组件
import HmButton from './components/HmButton.vue';
Vue.config.productionTip = false
// 进行全局注册
Vue.component('HmButton',HmButton)
直接引入
<template><div class="hm-header">我是header<HmButton></HmButton></div></template>
组件样式冲突scoped
默认的style样式会作用到全局,如果不想影响全局加上scoped属性,这样只会作用于当前组件。
data是一个函数
组件通信
父传子用props方式
<template><div class="app" style="border: 3px solid #000; margin: 10px">我是APP组件<!-- 1.给组件标签,添加属性方式 赋值 --><Son :title="myTitle"></Son></div>
</template><script>
import Son from "./components/Son.vue"
export default {name: "App",components: {Son,},data() {return {myTitle: "学前端,就来黑马程序员",}},
}
</script><style>
</style>
<template><div class="son" style="border:3px solid #000;margin:10px"><!-- 3.直接使用props的值 -->我是Son组件 </div>
</template><script>
export default {name: 'Son-Child',// 2.通过props来接受props:['title']}
</script><style></style>
子传父
<template><div class="app" style="border: 3px solid #000; margin: 10px">我是APP组件<!-- 1.给组件标签,添加属性方式 赋值 --><Son :title="myTitle" @changeTitle="handleChange"></Son></div>
</template><script>
import Son from "./components/Son.vue"
export default {name: "App",components: {Son,},data() {return {myTitle: "学前端,就来黑马程序员",}},methods:{//3.提供处理函数handleChange(newTitle){console.log(newTitle)}}
}
</script><style>
</style>
<template><div class="son" style="border:3px solid #000;margin:10px"><!-- 3.直接使用props的值 -->我是Son组件 </div>
</template><script>
export default {name: 'Son-Child',// 2.通过props来接受props:['title'],methods:{changeFn(){//1.通过$emit像父组件传递消息this.$emit('changeTitle',"船只教育")}}}
</script><style></style>
prop校验
<template><div class="base-progress"><div class="inner" :style="{ width: w + '%' }"><span>{{ w }}%</span></div></div>
</template><script>
export default {props: {//设置校验类型w:Number}// 1.基础写法(类型校验)// 2.完整写法(类型、是否必填、默认值、自定义校验)
}
</script><style scoped>
.base-progress {height: 26px;width: 400px;border-radius: 15px;background-color: #272425;border: 3px solid #272425;box-sizing: border-box;margin-bottom: 30px;
}
.inner {position: relative;background: #379bff;border-radius: 15px;height: 25px;box-sizing: border-box;left: -3px;top: -2px;
}
.inner span {position: absolute;right: 0;top: 26px;
}
</style>
<template><div class="app"><BaseProgress :w="width"></BaseProgress></div>
</template><script>
import BaseProgress from './components/BaseProgress.vue'
export default {data() {return {width: 30,}},components: {BaseProgress,},
}
</script><style>
</style>
类型校验
非父子通信-事件总线
创建一个空的总线
A组件监听事件
B组件监听事件
非父子通宵扩展-provide-inject
v-model原理
表单类组件封装&v-model简化代码
sync修饰符
ref和refs获取dom和组件
<template><div class="app"><div class="base-chart-box">这是一个捣乱的盒子</div><BaseChart></BaseChart></div>
</template><script>
import BaseChart from './components/BaseChart.vue'
export default {components:{BaseChart}
}
</script><style>
.base-chart-box {width: 300px;height: 200px;
}
</style>
<template><div ref="mychart" class="base-chart-box">子组件</div>
</template><script>
import * as echarts from 'echarts'export default {mounted() {// 基于准备好的dom,初始化echarts实例// document.querySelector 会查找项目中所有的元素// $refs只会在当前组件查找盒子// var myChart = echarts.init(document.querySelector('.base-chart-box'))var myChart = echarts.init(this.$refs.mychart)// 绘制图表myChart.setOption({title: {text: 'ECharts 入门示例',},tooltip: {},xAxis: {data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],},yAxis: {},series: [{name: '销量',type: 'bar',data: [5, 20, 36, 10, 10, 20],},],})},
}
</script><style scoped>
.base-chart-box {width: 400px;height: 300px;border: 3px solid #000;border-radius: 6px;
}
</style>
vue异步更新 nextTick
<template><div class="app"><div v-if="isShowEdit"><input type="text" v-model="editValue" ref="inp" /><button>确认</button></div><div v-else><span>{{ title }}</span><button>编辑</button></div></div>
</template><script>
export default {data() {return {title: '大标题',isShowEdit: false,editValue: '',}},methods: {handleEdit(){//1.显示输入框this.isShowEdit =true//2.让输入框获取焦点this.$nextTick(()=>{this.$refs.inp.focus()})}},
}
</script><style>
</style>
Vue 自定义指令-基础语法
自定义指令-封装v-loading
插槽-默认插槽
插槽-后备内容
具名插槽
一旦起了名字就是具名插槽,需要添加template包裹起来
作用域插槽
<template><div><MyTable :data="list"><template #default="obj"><button @click="del(obj.row.id)">删除</button></template></MyTable><MyTable :data="list2"></MyTable></div>
</template><script>
import MyTable from './components/MyTable.vue'
export default {data () {return {list: [{ id: 1, name: '张小花', age: 18 },{ id: 2, name: '孙大明', age: 19 },{ id: 3, name: '刘德忠', age: 17 },],list2: [{ id: 1, name: '赵小云', age: 18 },{ id: 2, name: '刘蓓蓓', age: 19 },{ id: 3, name: '姜肖泰', age: 17 },]}},components: {MyTable}
}
</script>
<template><table class="my-table"><thead><tr><th>序号</th><th>姓名</th><th>年纪</th><th>操作</th></tr></thead><tbody v-for="(item,index) in data" :key="item.id"><tr><td>1</td><td>小张</td><td>8</td><td><!-- 给slot标签传值 --><slot :row="item"> </slot></td></tr></tbody></table>
</template><script>
export default {props: {data: Array,},
}
</script><style scoped>
.my-table {width: 450px;text-align: center;border: 1px solid #ccc;font-size: 24px;margin: 30px auto;
}
.my-table thead {background-color: #1f74ff;color: #fff;
}
.my-table thead th {font-weight: normal;
}
.my-table thead tr {line-height: 40px;
}
.my-table th,
.my-table td {border-bottom: 1px solid #ccc;border-right: 1px solid #ccc;
}
.my-table td:last-child {border-right: none;
}
.my-table tr:last-child td {border-bottom: none;
}
.my-table button {width: 65px;height: 35px;font-size: 18px;border: 1px solid #ccc;outline: none;border-radius: 3px;cursor: pointer;background-color: #ffffff;margin-left: 5px;
}
</style>
组件标签封装-my-tag
单页应用&路由
路由的使用
组件存放
路由封装抽离
wwwwwwwwwww