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 进行求和 → reduce
let 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
// 请求方式:get
const app = new Vue({
el: '#app',
data: {
list:[]
},
async created(){
//进入页面立即发送请求
const res = await axios.get('http://hmajax.itheima.net/api/news');
console.log(res)
//将数据更新到data中的list
this.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