vue

107 阅读7分钟

Unit 01

一. 介绍

1.是一个构建数据驱动的==渐进式 JavaScript==框架

  • 数据驱动: 基本不用操作dom, 只要修改数据, 数据变化了, dom会自动渲染
  • 渐进式: 学一点用一点,不必学完所有的东西才使用, 只要学习其中的某一个部分,都可以集成到你的项目中
  1. vue特点
  • 体积小
  • 运行效率高
  • 双向数据绑定
  • 生态丰富 学习成本低

二. vue项目环境搭建

  • 安装脚手架
yarn global add @vue/cli
# 或
npm i -g @vue/cli

# 测试脚手架版本
vue --version    // @vue/cli 4.5.13
  • 创建项目
vue create 项目名   // 项目名:  小写加-

vue create vite

# 一顿选择 [看图形笔记]
  • 启动项目
yarn serve

三. 项目目录说明

image.png

image.png

四. 项目初始代码详解

  • main.js
import Vue from 'vue' // 引入Vue

import App from './App.vue' // 引入根组件 ***************


Vue.config.productionTip = false // 阻止生产提示

// 创建Vue的实例对象 (证明: Vue是一个类哦~~~)
new Vue({
  render: h => h(App), // 渲染哪个组件呢?
}).$mount('#app')  // 挂载渲染到哪里去


// new Vue({
//   render: function (createElement) {
//     return createElement(App)  // 把App.vue根组件 编译成浏览器认识的东西 渲染
//   }, // 渲染哪个组件呢?
// }).$mount('#app')  // 挂载渲染到哪里去
  • App.vue
<template>
  <div class="title">写html的</div>
</template>

<script>
console.log("写js的");
</script>


<style>
.title {
  color: red;
}
</style>

五. 组件

1. 组件的概念

  • 具有独立功能的ui部件, 组件的特点是: 可复用/可组合/容易维护

2. 单文件组件

  • 一个.vue文件, 就是一个单文件组件
<template>
  // 这里是写HTMl模板的, 主要就是写 - 布局
  # 注意:
     1. 只能有一个根标签
     2. 主要写 "html模板", html + vue扩展的写法
</template>

<script>
   // 这里写js交互
   // 导出一个vue的实例对象   export default new Vue({})
   // 这个实例对象 会 自动和 template 关联
   export default {
		  // 这里有很多vue "内置" 的配置
      // 数据
      data() {
        retrun {
          
        }
      },
      // 方法
      methods: {
        
      },
      // 组件
      components: {
        
      },
      // 计算属性
      computed: {
        
      }
   }
       
</script>

<style scoped lang="less">
  // 这里写css样式
  # 注意:
   1. style的样式 自动和当前组件的 template 关联
   2. scoped 可以方style中的css 只对当前组件的template有效
   3. lange="less" 那么  就可以再style中写less了.
</style>

3. 自定义组件

  • 自己写的.vue组件
  • 使用步骤 (3步骤)
  • 写一个自定义组件,然后在要使用这个组件的地方,引入组件
  • 注册组件
  • 使用组件
# 编写组件 HelloWorld.vue

# 使用步骤
1. 引入组件
import 变量名 from './xx/HelloWorld.vue'

2. 注册组件
export default {
  // 用于注册组件的
  components: {
    "键名": 变量名      
    # 注意:
      1. 键名如果使用大驼峰 在使用组件的时候 只能使用  小写+"-" 格式
  }
}

3. 使用组件
<template>
  <div>
     <键名></键名><键名 />
  </div>
</template>

六. data选项&mustach表达式

1. data选项

  • data是,vue实例对象中用于准备数据的内置选项, 这些数据,在 template 中, 可以直接使用. 且: data中的数据,具备==响应式==, 只要数据改变, template中使用到这个数据的地方 自动重新渲染, 无需dom操作

2. mustach表达式

  • 作用是用于在 template 中, 输出渲染 data选项提供的数据
{{ 表达式 }}
<template>
  <div>
    <h3>{{ str }}</h3>
    <p>我的爱好是: {{ hob[1] }}</p>
    <p>{{ num1 + num2 }}</p>
    <p>{{ flag ? "真的哦" : "假的哦" }}</p>
    <p>我的公司的地址是: {{ o.company.address }}</p>
  </div>
</template>

<script>
// export default new Vue({})
export default {
  // 数据 必须是函数 然后返回一个对象
  data() {
    return {
      str: "你好vue",
      hob: ["html", "css", "vue"],
      num1: 10,
      num2: 20,
      flag: true,
      o: {
        name: "小貂蝉",
        company: {
          address: "天府三街",
        },
      },
    };
  },
};
</script>

<style lang="less" scoped>
</style>

七. 指令

1. 概念

  • 指令是指我们可以写在 template 中的标签上, 作为自定义属性, 以 v- 开头
  • 作用是: 帮助我们操作dom节点 和 操作属性节点 , 渲染数据
<template>
  <div>
    <标签名 id="box" class="xx" v-xx="表达式"></标签名>
  </div>
</template>

1.1 v-text 和 v-html

  • 往标签中渲染数据, v-text相当于 textContent , v-html 相当于 innerHTML

1.2 v-show和v-if

  • 都可以控制dom的显示和隐藏, 只是: v-show控制的是 display属性, v-if会直接删除dom和重新渲染
  • 区别: 频繁的切换显示和隐藏, 使用 v-show , 否则 使用if

1.3 v-if和v-else-if和v-else

  • 逻辑和js的if else 完全一样. 从上往下执行, 遇到==第一个满足条件的== 就渲染 , 然后就不走了

1.4 v-for

  • 循环渲染数据
<template>
  <div>
    <div>
      <!-- 循环数字 -->
      <span v-for="i in num" :key="i">{{ i }}</span>
    </div>

    <div>
      <!-- 循环字符串 -->
      <p v-for="(str, index) in strs" :key="index">{{ str }}</p>
    </div>

    <div>
      <!-- 循环数组 -->
      <h1>强哥的爱好:</h1>
      <ul>
        <li v-for="(hob, index) in hobs" :key="hob">
          {{ index }} --- {{ hob }}
        </li>
      </ul>
    </div>

    <div>
      <!-- 循环对象 -->
      <h1>强哥的对象:</h1>
      <ul>
        <li v-for="(value, key, index) in user" :key="key">
          {{ index }} --- {{ key }}--- {{ value }}
        </li>
      </ul>
    </div>

    <!-- 循环数组对象 -->
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>姓名</th>
          <th>年龄</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="user in users" :key="user.id">
          <td>{{ user.id }}</td>
          <td>{{ user.name }}</td>
          <td>{{ user.age }}</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  // 数据
  data() {
    return {
      num: 5,
      strs: "hello",
      hobs: ["钓鱼", "洗脚", "按摩", "丝袜奶茶"],
      user: {
        name: "小貂蝉",
        age: 20,
        sex: "男",
        email: "dc@qq.com",
      },
      users: [
        { id: 1, name: "张三", age: 18 },
        { id: 2, name: "李四", age: 19 },
        { id: 3, name: "王五", age: 20 },
        { id: 4, name: "赵六", age: 21 },
        { id: 5, name: "田七", age: 22 },
      ],
    };
  },
};
</script>

<style lang="less" scoped>
</style>

1.5 v-model

  • 帮我们 获取 和 设置 表单数据的, 让 template中的表单 和 data中的数据 "双向绑定". 完全保持一致,同步修改
  • 能使用的表单标签: input select textarea
<template>
  <div>
    <h1>vip信息录入</h1>
    <p>姓名: <input type="text" v-model="user.name" /></p>
    <p>
      性别: 男 <input type="radio" name="sex" value="男" v-model="user.sex" /><input type="radio" name="sex" value="女" v-model="user.sex" />
    </p>
    <p>
      爱好: 钓鱼 <input v-model="user.hobs" type="checkbox" value="钓鱼" /> 洗脚
      <input v-model="user.hobs" type="checkbox" value="洗脚" /> 按摩
      <input v-model="user.hobs" type="checkbox" value="按摩" /> 丝袜奶茶
      <input v-model="user.hobs" type="checkbox" value="丝袜奶茶" />
    </p>

    <p>
      工作:
      <select v-model="user.job">
        <option value="web开发">web开发</option>
        <option value="php开发">php开发</option>
        <option value="py开发">py开发</option>
      </select>
    </p>

    <p>
      简介:
      <textarea cols="30" rows="10" v-model="user.desc"></textarea>
    </p>

    <p><input type="checkbox" v-model="agree" /> 同意授权信息</p>

    <p><button @click="submitForm">提交</button></p>
  </div>
</template>

<script>
export default {
  // 准备数据
  data() {
    return {
      // 用户数据
      user: {
        name: "aa",
        sex: "",
        hobs: [],
        job: "web开发",
        desc: "",
      },

      // 是否同意
      agree: false,
    };
  },
  // 方法
  methods: {
    submitForm() {
      // console.log("提交", this.agree, this.user); // this代表当前组件的vue实例对象
      if (this.agree) {
        console.log("提交", this.user); // 发送ajax给后端
      }
    },
  },
};
</script>

<style lang="less" scoped>
</style>

1.6 v-bind

属性名: 
标准属性: 操作方式:  dom.属性  dom.属性=" "
自定义属性:  操作方式:  dom.getAttruite('属性')     dom.setAttruite('属性名','新值')
h5新增 自定义数据: data-key="值"    js操作: dom.dataset['key']   dom.dataset.key
div 
- id  className style width  height 
input 
- type  placeholder value checked    
a
- href  
img 
- src alt title 
textarea 
- row col ..
<template>
    <div>
        <div v-bind:id="num" v-bind:class="classData"  v-bind:xxx="num"  v-bind:data-id="num"></div>
        <input type="text" :placeholder="msg">
        <button @click="add">+</button>
    </div>
</template>

<script>
export default {
    data(){
        return {
            num:0,
            classData:'box',
            msg:'请输入数据'
        }
    },
    methods:{
        add(){
            this.num++;
            this.classData = this.classData=='box'?'box1':'box'
            this.msg = this.msg=='请输入数据'?'你好啊':'请输入数据'
        }
    }
}
</script>

<style lang="less" scoped>
    .box{
        width: 100px;
        height: 100px;
        background: red;
    }
    .box1{
      width: 100px;
        height: 100px;
        background: green;
    }

</style>

1.7 v-on 事件指令 和methods 执行函数

  • v-on绑定事件
  • methods 事件的执行函数
<template>
    <div>
            <div class="btn" v-on:mouseover="over"  v-on:mouseout="out">点我呀....</div>
    </div>
</template>

<script>
export default {
  data() {
    return {};
  },
  components: {},
  // 方法和函数的定义
  methods: {
    over() {
      console.log('移入了~~~~');

    },
    out() {
      console.log("移出了~~~~");
    }
  }
};
</script>

八. 事件

  • Vue绑定事件语法
<template>
  <div>
    <button v-on:事件类型="表达式">点我啊</button>
    <button v-on:事件类型="事件处理函数">点我啊</button>
    <button v-on:事件类型="事件处理函数(实参)">点我啊</button>
		
    // 简写
    <button @事件类型="表达式">点我啊</button>
    <button @事件类型="事件处理函数">点我啊</button>
    <button @事件类型="事件处理函数(实参)">点我啊</button>
  </div>  
</template>

九. 计算属性computed

  • computed写法和methods一模一样, 主要用于写复杂的计算逻辑, 然后返回结果, 在 template中, 通过函数的名字,就能直接使用结果

  • 区别

  • methods调用要写() 计算属性直接写函数名

  • methods函数不一定要有返回值 计算属性必须有返回值.

  • 计算属性有 "依赖缓存", 只要依赖的数据没有发生变化, 就会把结果缓存起来, 下一次直接使用结果, 不用重新计算, 性能极高

<template>
  <div>
  {{ 函数名 }}
  </div>  
</template>

export default {
  // 计算属性
  computed: {
    函数名() {
      /* 很多的逻辑 计算代码 */
      return 结果
    }
  }
}

十. 过滤器filters

  • 过滤数据 并返回新的数据
  • filters 语法与 methods 一样,必须跟一个返回值
  • 区别:
  • filters 函数 必须有return, filters 函数不能获取data变量的值
  • methods 的函数可以没有return
<img v-for="(item,index) in data" :key="index"  :src="item.img | 过滤器名  "> </img>


<script>
export defalut{
		data(){
            return {
                data:[
                     {img:"/xx/xx.png"},
                     {img:"/xx/xx.png"},
                     {img:"/xx/xx.png"},
                     {img:"/xx/xx.png"}
                ]
            }
        },
        filters:{
            过滤器名(形参){
                //字符拼接 并返回
                retrun '服务器地址'+形参
            }
        }
}

</script>
 <p v-for="item in arr" :key="item">
            {{item | addStr}}
 </p>

十一. 侦听器 watch

  • 当数据 发生改变时,自动触发侦听器中的函数, 监听某个数据是否发生变量,如果数据发生了变化 就执行某些功能
  • watch 语法和methods 一致, watch中的函数名 直接就是 需要监听的数据变量名
<input  v-model="num" >

<script>
export default{
    data(){
        return {
            num:0
        }
    },
    watch:{
        需要监听的变量名(新数据,老数据){){
        	执行的函数体
        }
    }
    
}

</script>
 watch:{
      //当num的值发生改变 触发该函数
      num(newVal,oldVal){
        console.log(newVal,oldVal);
      }     
}
  • watch 和 computed 区别

都可以: 监听一个数据的改变 然后 返回一个新数据

watch 的函数 监听一个数据的改变 然后 返回一个新数据

watch 在 data中定义一个 变量接收新数据,才可以使用

computed 监听一个数据的改变 然后 返回一个新数据

自己的函数名 就是 返回的变量 代表的是 新数据

computed  的语法 要比 watch 的语法 更加 简洁
  • methods 和computed 区别

都可以当做函数的调用

methods 可以接收 形参

computed 不能接收形参,他自己就是一个变量

computed 依赖缓存 只要参与计算的数据源 不发生改变,计算函数的函数体 不会执行,但是methods 会一直执行,computed 性能更高。

Unit 02

一. vue-router vue路由

  • 需要实现 类似于之前页面跳转的效果,达到vue组件相互切换的效果,需要引入vue路由实现
  • 路由的配置项文件: src/router/index.js
import Vue from 'vue'  // 引入vue
import VueRouter from 'vue-router'   //引入vue-router
Vue.use(VueRouter)  //vue使用 vuerouter 
// 页面路由的配置
// vue组件的路径 和  路由访问的地址  一一对应
const routes = [
   //每个页面的配置  都是一个对象,    
  {
    path:'',  // 路由访问的地址
    name:'',   //路由名称
    component:''  // vue组件路径
  },
  {
    path:'',  // 路由访问的地址
    name:'',   //路由名称
    component:''  // vue组件路径
  }
]
//实例化 vuerouter 对象
const router = new VueRouter({
  routes
})
//导出  在main.js 导入路由配置 就可以生效了
export default router
  • router的属性
this.$route.path       #vue 组件的路径 路由
this.$route.params      #获取组件上面的参数    
this.$route.query   #获取vue组件上面的查询查询   ?key=value&key1=value1

this.$router.push('组件的路由path属性')     #通过js跳转组件
this.$router.go(数字)       #根据历史记录跳转组件  -----history.go()
this.$eouter.back()       #根据历史记录 回退组件   -----history.back()
this.$router.forward()     #根据历史记录 前进一页 ----history.forward()

image.png

二. vue 组件生命周期

  • 所有的生命周期的钩子函数,当组件到达这个阶段 会进行自动的触发
  • 所有的生命周期的钩子函数都是和 data()函数同级
#组件创建阶段
# 组件创建之前
beforeCreate(){
    #组件实例被创建,但是 页面data 的数据 都是undefiend     
}
# 组件创建之后  【一般进入页面请求ajax 数据 都在created 】
created(){
    #所有的数据生效, 页面data 的数据 都可以获取到值
}

# 组件挂载阶段
#挂载前
beforeMount(){
    #页面dom节点即将进行渲染,获取dom节点===null 
}
#挂载后  【操作dom 一般是在 mounted】
mounted(){
    #所有dom节点 及数据进行了双向绑定,页面完成了数据的渲染,获取dom可以直接拿到dom节点
}


# 组件的更新阶段
# 更新前
beforeUpdate(){
    #数据一旦发生更改,自动触发,可以获取到该数据更改之前的值
}
#更新后
updated(){
    #数据发生改变触发,可以获取数据更改之后的值
}

#组件销毁阶段
#销毁前  【离开需要关闭的其他异步操作,定时器 延时器 需要在此清除】
beforeDestory(){
    #组件被销毁/关闭 跳转到下个组件(跳转前的一瞬间)进行触发
}
#销毁后
destoryed(){  
    #组件被销毁/关闭 跳转到下个组件(完成跳转的一瞬间)。进行触发
}

三. 页面级组件的创建

  • 页面路由配置的 口诀
1创 :创建一个 页面级组件 views/

2.配 : 配置 router/index.js 加入这个页面相关的配置

3.占位 : 找到这个页面的父页面 占位 < router-view> </ router-view> 【同级的配置只要占位一次】

4.测 :在浏览器的地址栏 输入 该页面的路由地址 path的值 进行访问测试
//router/index.js 配置
//导入 vue 
import Vue from 'vue';
import VueRouter from 'vue-router';
import  Discover from '@/views/discover/Discover.vue'
//顶级类 注册 子类
Vue.use(VueRouter);
//2.配置
const routes = [
    {
        path:'/discover',
        component:Discover
    }
]
//实例化 VueRouter
let router = new VueRouter({
      routes,//配置项
})

//暴露实例对象
export default router;
//main.js  
import router from '@/router/index.js'

//挂载到当前项目的实例上
new Vue({
    router:router,
})
  • 占位 app.vue
 <div class="app">
  
     <AppHeader></AppHeader>
       <!-- 占位 -->
     <router-view></router-view>
  </div>
  • 测试
http://localhost:8080/#/discover

四. 组件传值

1. 父传子

  • 父组件使用了子组件,子组件没有参数需要父组件将参数传递过来
  • 父组件使用子组件时,直接以自定义属性的方式 写入参数
#父组件
# 参数1="值1"   只能传递字符串
<子组件  参数1="值1" 参数2=“值2”  :参数3="表达式">    </子组件>


#子组件
props:{
	参数1:{
		type:Number,  //限制传递数据类型
        default:0,    // 默认值
	}
}
# 子组件通过props 获取的数据 都可以像data中的数据一样进行使用
  props:{
            val:{
                type:Number,
                default:0,
            },
            arr:{
                type:Array,
                default:()=>{   //如果接受的数据引用数据类型,默认值需要写一个函数返回空对象
                    return [];
                }
            }
        },

2.子传父

  • 将子组件的值 传递给父组件
#父组件
事件执行函数名 后面不需要加 ()
<子组件 @自定义事件类型名="事件执行函数名" >   </子组件>

methods:{
	事件执行函数(data){
		//data  ===子组件回传的数据
		
	}
}


#子组件
this.$emit('自定义事件类型名',回传的参数)

3. 中央事件总线 $bus

  • 将跨层级 的传值 放到中央事件总线中
  • 同一个页面中 跨域层级的组件相互之间值的传递
// 在 main.js 中 创建中介
// 重新实例化一个 空的 vue对象(中介)  挂载到 现在正在使用的这个vue对象的 原型链上
Vue.prototype.$bus = new Vue();

//组件中使用 $bus 存值
this.$bus.$emit('自定义事件类型名',传入的参数)

// 组件中使用 $on 取值
this.$bus.$on('自定义事件类型名',(data)=>{
    //data 就是传入的参数
   
})

五. vue 插槽- slot

  • 子组件预留位置(插槽),等待将来父组件可以写入自己代码 替代插槽

1. 匿名插槽

#父组件
<子组件>
    #写入替换 slot插槽的html代码
</子组件>


#子组件
</div>
	#子组件提前给父组件预留的位置 插槽
	<slot></slot>
</div>

2. 具名插槽

  • 如果同一个子组件中 出现了 两个或两个以上的插槽,必须使用具名插槽
  • 父组件中的 标签属性 slot 找到子组件中 slot name相同的 进行一 一对应替换
#父组件
<子组件>
    <div slot="插槽名1">
    </div>	  		
     <div slot="插槽名2">
    </div>
</子组件>

#子组件
<div>
    <slot name="插槽名1"></slot>    、
    <slot name="插槽名2"> </slot>
<div>

3. 作用域插槽

  • 子组件自己有数据需要渲染到 slot 里面去 ,必须使用作用域插槽
  • 作用域插槽必须是 基于具名插槽进行操作
#父组件
<子组件>
    <div slot="插槽名1" slot-socpe="scope">
        {{scope.属性名}}
    </div>	  		
     <div slot="插槽名2">
    </div>
</子组件>

#子组件
<div>
    <slot name="插槽名1" :属性名="数据"></slot>    、
    <slot name="插槽名2"> </slot>
<div>

4. v-slot指令

  • v-slot 插槽指令,vue2.6.0 版本更新的一个指令,主要是 用来替代之前的 插槽的语法
  • 匿名插槽
#父组件
<子组件>
    <template v-slot>
			#写入替换 slot插槽的html代码、
    </template>
</子组件>
  • 具名插槽 v-slot:插槽名
 <template v-slot:title>
		<div >  女装  </div>
  </template>

#简化语法   v-slot:   ===>  #
 <template #msg>
 		<div > 查看 <i class="iconfont icon-wode"></i></div>
</template>
  • 作用域插槽
<template v-slot:title="scope"  >
                 儿童服装{{scope.shopName}}
</template>

<template #title="scope"  >
              儿童服装1{{scope.shopName}}
</template>