vue2笔记(要换笔记本了,保存好几年的笔记)

绑定样式

<body>
    <div id="app">
        <ul class="list">
            <!-- 方式一  对象形式   根据js表达式的值添加样式 -->
            <!-- class绑定样式 对象的属性名是样式名称,属性值是布尔值 -->
            <li v-for="(item,index) in citys" :key="index" @click="dot(index)" :class="{active:index===activeIndex}">
                {{item}}</li>
        </ul>
        <!-- 方式二  三元表达式 必须在数组里面 -->
        <ul class="list">
            <li v-for="(item,index) in citys" :key="index" @click="dot(index)" :class="[index===activeIndex?'active':'']">
                {{item}}</li>
        </ul>
        <hr>

        <!-- 绑定style 行内样式的值可以被设置为变量 -->
        <div class="box" :style="{backgroundColor:bgColor,fontSize:fs}">Hello</div>
        <button @click="bgColor='tomato'">添加背景</button><button @click="fs='30px'">增大字体</button>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                // 定义高亮索引
                activeIndex: 0,
                bgColor: 'white',
                fs: '15px',
                // 定义循环列表
                citys: ["运城", "大同", "太原", "临汾"]
            },
            methods: {
                dot(index) {
                    this.activeIndex = index
                }
            },
        })
    </script>
</body>

路由

1.配置和守卫

import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
//定义路由具体信息
const routes = [
{
    path: '/',
    // 重定向到指定的路由
    redirect: '/home'
},{
    path: '/home',
    // 路由的懒加载方式一:每个都组件懒加载
    /* component: () =>
        import ('@v/Home.vue') */
    // 路由的懒加载方式二:按模块分,可将组件分成几个模块分别打包
    component: () =>
        import ( /* webpackChunkName: "home" */ '@v/Home.vue')
},]
//创建路由器对象,管理所有路由
const router = new VueRouter({
        routes
    })
    // 路由前置守卫
router.beforeEach((to, from, next) => {
        NProgress.start();
        next()
    })
    //路由后置守卫
router.afterEach((to, from) => {
    NProgress.done();
//获取元信息更改标题
    document.title = to.meta.title
})
export default router

2.在main.js中引入

import router from './router'
引入后必须在当前项目中注册router ,重要

3.路由传参

1.params

params相当于post传参

第一种:http://localhost:8080/newsPublishPC/newsDetails key和val都是隐式

跳转的是路由的name,所以路由必须有name

url不显示键值对,需要缓存 刷新会丢失

路由配置
 {
    path: '/newsDetails',
    name: 'newsDetails',
    meta: { title: '新闻详情', },
    component: () =>
      import('@/views/newsPublishPC/newsDetails'),
  },   
传递参数
    sessionStorage.setItem('newsPublishPC_id', item.id)
      this.$router.push({
        name: 'newsDetails',
        params: {
          id: item.id
        }
      })
接收参数
this.params.id = this.$route.params.id || sessionStorage.getItem('newsPublishPC_id')

第二种:http://localhost:8080/newsPublishPC/newsDetails/12345

路由后面拼接上参数传递,刷新不会丢失,url会显示val,不显示key

路由配置  props为true
  {
    path: '/newsDetails/:id',
    props: true,
    meta: { title: '新闻详情', },
    component: () =>
      import('@/views/newsPublishPC/newsDetails'),
  }

传递
this.$router.push(`/newsDetails/${item.id}`)

接收
props:['id']

2.query

类似于get参数 刷新不会丢失 无需缓存

注意:传递对象的话需要用json.stringify和json.parse

传递
      this.$router.push({
        path: '/newsDetails',
        query: {
          id: item.id
        }	
      }) 
接收
this.$router.query.id

4.多级路由跳转路径

// 第一种显示完整路径
<router-link to="/stu-manager/stu-list">查询学生</router-link> 
//   第二种短路径 没有前缀 
<router-link to="/stu-list">查询学生</router-link>
{
        // 第一种不加  ‘/’ 显示完整路径
        path: 'stu-list',
        // 第二种加‘/’ 显示单独路径
        path: '/stu-list',
        meta: {
            title: '查询学生'
        },
        component: () =>
            import ( /* webpackChunkName: "stu-manager" */ '../views/stu/StuList.vue')
    }

5.路由懒加载

// 1.每个路径都懒加载
component: () => import ('../views/stu/StuList.vue')
component: () => import ( /* webpackChunkName: "stu-manager" */ '../views/stu/StuList.vue')

6.路由缓存

//  默认是全部缓存, :include设置包裹哪些组件进行缓存,数组形式单引号,组件的name,注意大小写 ,缓存了以后vue原有的钩子就不会执行了
<keep-alive :include="['Student', 'System']">
        <router-view />
</keep-alive>

7.路由钩子

 // 路由的两个钩子   只有当路由被缓存时再用这两个钩子    否则没有意义,在缓存后需要做销毁动作可在这两个钩子里面 例如 销毁定时器等等
  activated() {
    this.start();
    console.log("student挂载了");
  },
  deactivated() {
    clearInterval(this.timer);
    console.log("student销毁了");
  }
 

8.路由钩子的使用

  // 路由被缓存后切换过来的激活钩子
    activated() {
        this.$http.get('/json/news.json').then(({ data: { result: { list } } }) => {
            // 初次给值 相当于mounted的初次渲染列表
            this.news = list

            // 后续操作列表后全部用这个列表获取到被操作后的导航列表,根据留下的列表加载新闻页面
            this.news = list.filter(r => this.$store.state.myNav.includes(r.classify))
        })
    },

vuex

1.安装

npm i vuex@3

2.配置

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
export default new Vuex.Store{
//定义全局状态
state:{}
//定义全局计算属性  
//计算属性只有一个参数就是state,用他来点出属性
 getters: {
        // 计算属性
        fullName(state) {
            return state.firstName + state.lastName
        }
    },
//定义全局方法
//方法有两个参数,state,val  
//state表示当前状态,val表示新值
  mutations: {
        setFirstName(state, val) {
            return state.firstName = val
        },
        setLastName(state, val) {
            return state.lastName = val
        },
        updateYwScore(state, val) {
            state.ywScore = val
        },
        updateStudent(state, val) {
            state.student = val
        }
    },
 // 异步必须在action里面  形参是context是上下文, val是具体的值
    actions: {
        updateYwScore(context, val) {
            // setTimeout(() => {
            //     // 通过context.commit(),再次调用mutation里面的方法实现异步方法
            //     context.commit('updateYwScore', parseInt(val - Math.random() * 10))
            // }, 1000)
            axios.get("https://www.bingjs.com:8001/Student/GetAll").then(({ data }) => {
                context.commit('updateYwScore', data.length)
                    // 调用mutations里面的赋值方法,将请求回来的值给到state里面
                context.commit('updateStudent', data)             
            });
        }
    },
//moules定义模块 定义的模块要引入到index.js中并注册
 modules: {
        car,
        plane
    }
})

定义modules模块   定义后要引入到index.js中
export default {
    // namespaced模块私有化属性,  默认是false不私有化
    //  非私有化的模块在合并模块里面的成员时,state会包一层对象,必须点出来,其他的不会包
    // 私有化的getters,mutations,actios里面的方法在合并时会变成:模块名称/方法名 重新命名
    namespaced: true,
    state: {
        name: '保时捷',
        price: 150
    },
    getters: {
        carInfo(state) {
            return `汽车名称:${state.name},汽车价格:${state.price}`
        }
    },
    mutations: {
        updateCarName(state, val) {
            state.name = val
        },
        updateCarPrice(state, val) {
            state.price = val
        }

    },
    actions: {
        updateCarPrice(context, val) {
            setTimeout(() => {
                context.commit('updateCarPrice', val)
            }, 1000)
        }
    }
}

3.组件调用store

调用属性

模板中:{{ $store.state.firstName }}
如果调用私有化的模块 {{this.$store.state.plane.list}}

// 或者在计算属性中调用,使模板简洁,前提是在store的index文件中已经计算好了
computed: {
    fullName() {
      return this.$store.getters.fullName;
    },
    sumScore() {
      return this.$store.getters.sumScore;
    },
  }

调用方法

// 调用mutations方法用commit 调用actions方法用dispatch
 updateYwScore() {
      // 通过commit调用mutation里面的方法  同步
      this.$store.commit("updateYwScore", 100);
      // 通过dispatch调用actions里面的方法  异步
      this.$store.dispatch("updateYwScore", 100);
    },
// 调用私有化模块的话要加私有化的前缀
 methods: {
    add() {
      // 不私有化不用 加前缀
      this.$store.commit("addPlane", this.feiji);
      //   私有化要加前缀
      //   this.$store.commit("plan/addPlane", this.feiji);
    },
  },

加载数据

// 在组件中通过 mounted钩子调用本函数的方法
 methods: {
    updateYwScore() {
      this.$store.dispatch("updateYwScore", 100);
      this.student = $store.state.student;
    },
  },
  mounted() {
    this.updateYwScore();
  },

4.映射函数

// 导入映射函数
import { mapState, mapGetters, mapMutations, mapActions } from "vuex"
// 映射数据和计算属性
computed: {
    // 映射函数会将state中的数据映射到组件
    ...mapState(["firstName", "lastName", "age"]),
    // 映射vuex中的getters
    ...mapGetters(["fullName", "shMoney"])
    //  映射modules里面的要加前缀
    ...mapState("car", ["name", "color", "price"]),
    // ...mapState(["name", "color", "price"]),
    ...mapGetters("car", ["carInfo"]),
  },
  //映射函数
methods: {
    // 映射vuex中的方法,只能行内传参  方法名必须和vuex一样,且必须传参
    ...mapMutations(["updateFirstName", "updateLastName"]),
    // 映射vuex中的mapActions   用法同映射mapMutations一样
    ...mapActions(["updateAge", "updateMoney"]),
  ------映射modules里面的要加前缀-----
...mapMutations("car", ["updateName", "updateColor"]),
    ...mapActions("car", ["updatePrice"]),
  },

5.上下互换位置方法 (对象)

up(index) {
      // index获取当前对象
      let obj1 = this.list[index];
      //   index获取当前对象的上一个对象
      let obj2 = this.list[index - 1];
      //   通过$set互换属性
      this.$set(this.list, index, obj2);
      this.$set(this.list, index - 1, obj1);
    },
    down(index) {
      // index获取当前对象
      let obj1 = this.list[index];
      //   index获取当前对象的上一个对象
      let obj2 = this.list[index + 1];
      //   通过$set互换属性
      this.$set(this.list, index, obj2);
      this.$set(this.list, index + 1, obj1);
    },

事件修饰符

1.prevent:阻止默认事件(常用);
2.stop:阻止事件冒泡(常用);
3.once:事件只触发一次(常用);
4.capture:使用事件的捕获模式;
5.self:只有event.target是当前操作的元素时才触发事件;
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;

按钮修饰符

enter .tab .delete (捕获“删除”和“退格”键) .esc .space .up .down .left .right 
<input type="text" @keyup.enter="search">
<button>搜索</button>

指令

v-model: 双向数据绑定
v-for: 遍历数组/对象/字符串
v-on: 绑定事件监听, 可简写为@
v-if: 条件渲染(动态控制节点是否存存在)
v-else: 条件渲染(动态控制节点是否存存在)
v-show: 条件渲染 (动态控制节点是否展示)
v-text:
1.作用:向其所在的节点中渲染文本内容。
2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
v-html:
1.作用:向指定节点中渲染包含html结构的内容
2.与插值语法的区别:(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。(2).v-html可以识别html结构。
3.严重注意:v-html有安全性问题!(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
v-cloak :
1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
2.使用css,display:none配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题
v-once:
1.v-once所在节点在初次动态渲染后,就视为静态内容了。
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
v-pre:
1.跳过其所在节点的编译过程。
2.可利用它跳过没有使用指令语法、没有使用插值语法的节点,会加快编译。

动画

动画语法:
默认是v-开头  如果给transtion加了name属性就要用name开头
给循环的标签加动画必须-grop 且必须有k值
定义动画
@keyframes 名字{
from{}
to{}
}
动画进入
 .v-enter-active{
animation: 名字 时间 匀速
}
动画离开
.v-enter-active{
animation: 名字 时间 匀速
}

定义过渡(谁用过渡给谁身上加过渡)
进入的起点 和离开的终点一样
.v-enter{}
进入的终点  和离开的起点一样
.v-enter-to{}
离开的起点
.v-leave{}
离开的终点
.v-leave-to{}

动画库
npm install animate.css --save

哪个组件用就在哪个组件引入
import 'animate.css'

使用:
name="animate__animated animate__bounce"
enter-active-class="动画名"
leave-active-class="动画名"

例子:循环要放到transition-group上面 里面嵌套盒子
<transition-group
          v-for="(item, index) in channel"
          :key="index"
          name="animate__animated animate__bounce"
          enter-active-class="animate__lightSpeedInLeft"
          leave-active-class="animate__lightSpeedOutRight"
          appear
        >
          <div class="item" @click="decrement(index)" key="index">
            {{ item }}
          </div>
        </transition-group>

组件传值

1.props 和$emit

父传子

父组件在子组件标签中通过 :name=“name”的方式
子组件用props接收数据,注意是只读的,如果要修改数据必须使用中转变量来备份

子传父
1.子组件中定义事件通过this.$emit(‘自定义事件’,数据)
<view class="item" @click="updateIndex(index)"  :class="{active:myActive===index}"   v-for="(item,index) in list">{{item}}</view>


methods: {
				updateIndex(index){
					this.myActive=index
					this.$emit('updateIndex',index)
				}
			}

2.父组件中在子组件的标签上通过 @自定义事件=“父组件的事件”

// 简单的直接通过$event赋值
<tabMenu label="配料" :list="pl" :active="plActive" @updateIndex="plActive=$event"></tabMenu>
// 复杂的定义自定义事件
<tabMenu label="温度" :list="wd" :active="wdActive" @updateIndex="getIndex"></tabMenu>
methods: {
			getIndex(e){
				console.log(e)
				this.wdActive=e
			}
		}
  1. 还可以将事件合并成v-model
子组件接收传过去的值必须是'value',自定义事件必须'input'
export default {
			props:['label','list','value'], //这里必须是value
			data() {
				return {
			   myActive:this.value
				}
			},
			methods: {
				updateIndex(index){
					this.myActive=index
					this.$emit('input',index)  //这里必须是input
				}
			}
		}

父组件合并事件为v-model
<tabMenu label="糖分" :list="tf"  v-model="tfActive"></tabMenu>
<tabMenu label="配料" :list="pl" v-model="plActive"></tabMenu>
<tabMenu label="温度" :list="wd" v-model="wdActive"></tabMenu>

2.依赖注入 provide 和inject

父可以给任意后代传递数据
用法等同于props,区别是可以传函数
父组件中定义provide(){return{数据或者函数}}
子组件用inject接收 ,注意,也是只读,修改需要备份
子组件通过接收到的函数可以向父级通信
父组件
 provide() {
    return {
      address: this.address,
      // 注入方法,这个方法可以让后代修改自己的值 方法定义在methods
      setAddress: this.setAddress, 
    };
  },
setAddress(val) {
      this.address = val;
    },
子组件
inject: ["address", "setAddress"]
methods: {
    undateAddress() {
      this.myAddress = "南京";
      this.setAddress(this.myAddress);
    },
  },

3.$bus

1.在main.js创建中央事件总线$bus
Vue.prototype.$bus = new Vue()
      
2.A组件发布消息      
 methods: {
    getData() {
      this.$bus.$emit("hello", this.car);
    },
  },
3.B组件接收消息,注意:这里必须用箭头函数,否则this指向的是$bus,是获取不到数据的
 mounted() {
    this.$bus.$on("hello", (e) => {  //e是形参
      this.car = e;
    });
  },
4.B组件销毁事件
 beforeDestroy() {
    this.$bus.$off("hello");
  },

4.$children $parent

<body>
  <!-- 父组件修改子组件
     1.$children[index],通过index获取到对应的子组件来修改某个值,但是这种方法不好,因为DOM变化了索引就会变
     2.给组件添加ref属性,然后用$refs获取到子组件,来修改子组件的值, ref可以给组件加,也可以加在div上面-->
  <!-- 子组件修改父组件
  1. $parent父级  2.$root根级 -->
  <div id="app" v-cloak>
      <div class="box">
          <div>
              <p>姓名:{{name}}</p>
              <p>年龄:{{age}}</p>
              <button @click="update1">修改1</button>
              <button @click="update2">修改2</button>
              <button @click="update3">修改3</button>
          </div>
          <child1 ref="a"></child1>
          <child2 ref="b"></child2>
          <child3 ref="c"></child3>
      </div>
  </div>
  <!-- 引入vue -->
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
  <script>
      Vue.component('child1', {
          template: `
              <div class="child">
                  <p>姓名:{{name}}</p>
                  <p>姓名:{{age}}</p>
              </div>
          `,
          data() {
              return {
                  name: '周星驰',
                  age: 55
              }
          },
      })
      Vue.component('child2', {
          template: `
              <div class="child">
                  <p>姓名:{{name}}</p>
                  <p>姓名:{{age}}</p>
                  <child2-1></child2-1>
              </div>
          `,
          data() {
              return {
                  name: '周比利',
                  age: 50
              }
          },
      })
      Vue.component('child2-1', {
          template: `
              <div class="child">
                  <p>姓名:{{name}}</p>
                  <p>姓名:{{age}}</p>
                  <button @click="updateParent">修改父级</button>
                  <button @click="updateRoot">修改根级</button>
              </div>
          `,
          data() {
              return {
                  name: '儿子',
                  age: 15
              }
          },
          methods: {
              updateParent() {
                  this.$parent.name = '爸爸'
                  this.$parent.age = 52
              },
              updateRoot() {
                  this.$root.name = '爷爷'
                  this.$root.age = 90
              }
          },
      })
      Vue.component('child3', {
              template: `
              <div class="child">
                  <p>姓名:{{name}}</p>
                  <p>姓名:{{age}}</p>
              </div>
          `,
              data() {
                  return {
                      name: '周润发',
                      age: 65
                  }
              },
          })
          // 关闭生产提示
      Vue.config.productionTip = false
      new Vue({
          el: '#app',
          data() {
              return {
                  name: '李欢',
                  age: 22
              }
          },
          methods: {
              update1() {
                  // this.$refs.a.name = '朱茵'
                  this.$children[0].name = '朱茵'
              },
              update2() {
                  // this.$refs.b.name = '关晓彤'
                  this.$children[1].name = '关晓彤'
              },
              update3() {
                  // this.$refs.c.name = '赵丽颖'
                  this.$children[2].name = '赵丽颖'
              }
          },

      })
  </script>
</body>

5. v-model

只能绑一个v-model

<body>
  <!-- 组件中使用v-model就是将v-bind:value 和 v-on:input事件给集合起来
   用法: 1.组件中传递的属性值必须是 value,
         2.组件中要备份value值,
         3.组件中自定义回传事件必须写成input ,回传的值是备份的值
         updateTitle() {
                  this.$emit('input', this.myTitle)
              }
         4.在组件中使用时直接用v-model绑定父组件中传过去的值
  -->
  <div id="app" v-cloak>
      {{title}}
      <hr>
      <div>严格按照v-model的写法</div>
      <b-box :value="title" @input="title=$event"></b-box>
      <div>简写</div>
      <b-box v-model="title"></b-box>
  </div>

  <!-- 引入vue -->
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>

  <script>
      // 关闭生产提示
      Vue.config.productionTip = false
      Vue.component('b-box', {
          // 1.定义组件
          template: `
          <div class="box">
              <span>标题:</span>
              <input type="text" v-model="myTitle">
              <button @click="updateTitle">提交</button>
          </div>
          `,
          props: ['value'], //2.接收父组件传过来的属性
          // 3.备份父组件传过来的属性
          data() {
              return {
                  myTitle: this.value
              }
          },
          methods: {
              // 4.自定义事件回传组件内部title改变后的值
              updateTitle() {
                  this.$emit('input', this.myTitle)
              }
          }
      })
      new Vue({
          el: '#app',
          data() {
              return {
                  title: '你好啊小宝贝'
              }
          },

          /* methods: {
              updateTitle(e) {
                  this.title = e
              }
          }, */

      })
  </script>
</body>

6.sync

<body>
  <div id="app" v-cloak>
      <div>{{title}}</div>
      <div>{{msg}}</div>
      <div>{{time}}</div>
      <b-box v-model="title" :time.sync="time" :msg.sync="msg"></b-box>
  </div>
  <!-- 引入vue -->
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>

  <script>
      // 关闭生产提示
      Vue.config.productionTip = false
      Vue.component('b-box', {
          // 1.定义组件
          template: `
          <div class="box">
              <div>
              <span>标题:</span>
              <input type="text" v-model="myTitle">
              <button @click="updateTitle">提交</button>
              </div>
              <div>
                  <span>时间:</span>
              <input type="text" v-model="myTime">
              <button @click="updateTime">提交</button>
              </div>
              <div>
              <span>信息:</span>
              <input type="text" v-model="myMsg">
              <button @click="updateMsg">提交</button>
              </div> 
          </div>
          `,
          props: ['value', 'msg', 'time'],

          data() {
              return {
                  myTitle: this.value,
                  myTime: this.time,
                  myMsg: this.msg

              }
          },
          methods: {
              updateTitle() {
                  this.$emit('input', this.myTitle)
              },
              updateTime() {
                  // sync修饰符必须用 update:属性名  固定写法
                  //  然后在组件中用 :time.sync="time" :msg.sync="msg" 双向绑定
                  this.$emit('update:time', this.myTime)
              },
              updateMsg() {
                  this.$emit('update:msg', this.myMsg)
              }
          }
      })
      new Vue({
          el: '#app',
          data() {
              return {
                  title: '你好啊小宝贝',
                  msg: '宝马7系yyds',
                  time: '2022-2-22'

              }
          },

          /* methods: {
              updateTitle(e) {
                  this.title = e
              }
          }, */

      })
  </script>
</body>

自定义指令和插件

1.main.js导入自定义插件

import myplugins from './plugins'
Vue.use(myplugins)

2.创建插件和指令

plugins文件夹
export default {
    install(Vue, options) {
        // console.log('------------自定义全局指令-------------------');
        // 定义一个v - red指令
        Vue.directive('red', function(el, bind) {
                el.style.color = 'red'
            })
            // 定义一个v - color=""指令
        Vue.directive('color', function(el, { value }) {
                el.style.color = value
            })
            // 定义一个点击事件
        Vue.directive('myclick', function(el, bind) {
                el.onclick = function() {
                    alert('你好啊')
                    this.style.color = 'pink'
                }
            })
            // 定义一个鼠标进入事件
        Vue.directive('active', function(el, bind) {
            el.onmouseenter = function() {
                this.style.color = 'pink'
            }
        })
        Vue.directive('unactive', function(el, bind) {
                el.onmouseleave = function() {
                    this.style.color = 'black'
                }
            })
            // console.log('------------自定义全局混入-------------------');
        Vue.mixin({
            data() {
                return {
                    base_url: "https://bingjs.com:8001",
                };
            },
            methods: {
                sayHi() {
                    alert("你好!我是一个组件!");
                },
            },
            mounted() {
                console.log("当前组件挂载完毕....");
            },
        });
        // console.log('------------自定义全局过滤器-------------------');
        Vue.filter("filterUS", function(val) {
            return "$" + val.toFixed(2);
        });

        // console.log('------------自定义组件-------------------');
        Vue.prototype.$http = { name: "axios" };
        // 使用Vue,注册全局组件
        Vue.component("b-box", {
            render: (h) => {
                return h("div", "b-box");
            },
        });
    }
}

钩子

普通8个钩子

 <script>
        Vue.config.productionTip = false
        let vm = new Vue({
            el: '#app',
            data: {
                name: "张三",
                age: 18
            },
            beforeCreate() {
                // 此阶段还未获取到数据
                console.log('代理之前');
            },
            created() {
                // 此阶段已经获取到了数据
                console.log('代理完成');
                
                // debugger  // 打断点可以看到DOM没有被渲染
            },
            beforeMount() {
                // 此阶段已经获取到了数据但还未开始渲染页面
                console.log('挂载渲染页面之前');
               

            },
            mounted() {
                // mounted阶段获取到了数据并渲染页面完成
                console.log('挂载完成');
               
                // debugger
            },
            beforeUpdate() {
                // 更新之前数据已经变化了但是还未更新页面
                console.log('更新之前');
        

            },
            updated() {
                //此时数据变化了  页面被被重新渲染
                console.log('更新完成');
            
            },
            beforeDestroy() {
                // 在销毁之前进行收尾:关闭定时器,关闭消息订阅,解绑自定义事件等
                console.log('销毁之前');
               
            },
            destroyed() {
                // vm被销毁了,失去了响应式
                console.log('销毁完成');
               
            },
        })
        setTimeout(() => {
            // 销毁vm,但是钩子还可以获取到vm的东西
            vm.$destroy()
        }, 5000)
    </script>

路由的两个钩子

 // 路由的两个钩子   只有当路由被缓存时再用这两个钩子    否则没有意义,在缓存后需要做销毁动作可在这两个钩子里面 例如 销毁定时器等等
  activated() {
    this.start();
    console.log("student挂载了");
  },
  deactivated() {
    clearInterval(this.timer);
    console.log("student销毁了");
  }

第十一个钩子$nextTick

watch: {
    isShow(val) {
      if (val) {
        //   $nextTick 第十一个钩子,在等DOM渲染出来以后再执行对应的方法,类似于定时器,但是如果DOM不渲染他不会执行
        this.$nextTick(() => {
          this.$refs.inp.focus();
          // console.log(val);
        });
      }
    },
  },

配置代理服务器跨域

module.exports = defineConfig({
    transpileDependencies: true,
    lintOnSave: false,
    //开启代理服务器(方式一) 只写端口号跨域 和服务器地址一样
    // devServer: {
    //     // proxy: 'http://localhost:8848',
    //     // proxy: 'http://localhost:8888'
    // },
    //开启代理服务器(方式二)  添加多个代理
    devServer: {
        proxy: {
            //请求前缀  配置多个代理服务器要加前缀
            '/car': {
                // 代理地址
                target: 'http://localhost:8848',
                //忽略前缀   替换成空   必须加
                pathRewrite: { '^/car': '' },
                ws: true, //用于支持websocket
                // secure: false,  // 如果是https接口,需要配置这个参数
                // changeOrigin: true // 用于控制请求头中额host值   为真 骗取真实服务器请求来自于那里?  默认就是true
            },
            '/phone': { //请求前缀
                target: 'http://localhost:8888',
                pathRewrite: { '^/phone': '' }, //忽略前缀 必须加
                ws: true, //用于支持websocket
                // changeOrigin: true // 用于控制请求头中额host值   为真 骗取真实服务器请求来自于那里?
            }
        }
    }
})

单个代理用法: 直接写路由
 // axios.get("/list").then(({ data }) => {
      //   this.cars = data;
      // });
多个代理用法:必须加前缀
 axios.get("/car/list").then(({ data }) => {
        this.cars = data;
      });

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">
    <link rel="stylesheet" href="//at.alicdn.com/t/font_3177501_1q8vo20s883.css">
    <title>Document</title>
    <script src="../js/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.24.0/axios.min.js"></script>
    <style>
        #app {
            position: relative;
            width: 800px;
            margin: 0 auto;
        }
        
        img {
            width: 100%;
        }
        
        .left,
        .right {
            width: 60px;
            height: 80px;
            background-color: rgba(227, 245, 168, 0.212);
            font-size: 30px;
            color: aqua;
            text-align: center;
            line-height: 80px;
            position: absolute;
            top: 30%;
            cursor: pointer;
        }
        
        .left {
            top: 0;
            bottom: 0;
            margin: auto;
            left: 0px;
            user-select: none;
        }
        
        .right {
            top: 0;
            bottom: 0;
            margin: auto;
            right: 0px;
            user-select: none;
        }
        
        .dot ul {
            width: 100%;
            display: flex;
            justify-content: center;
            position: absolute;
            bottom: 10px;
        }
        
        .dot ul li {
            list-style: none;
            width: 10px;
            height: 10px;
            background-color: #ccc;
            border-radius: 50%;
            margin: 0 5px;
            cursor: pointer;
        }
        
        .dot ul li.active {
            background-color: tomato;
        }
    </style>
</head>
<div id="app">
    <!-- 图片  -->
    <img :src="imgs[index1]" @mouseenter="stop" @mouseleave="start">
    <!-- 左右切换按钮 -->
    <div class="left" @click="prev">&lt;</div>
    <div class="right" @click="next">&gt;</div>
    <!---->
    <div class="dot">
        <ul>
            <!-- 点的长度取决于图片的数量   高亮跟随 -->
            <li v-for="(item,index) in imgs" :class="{active:index===index1}"></li>
            <li v-for="(item,index) in imgs" :class="[index===index1?'active':'']" @click="dotClick(index)"></li>
        </ul>
    </div>
</div>

<body>
    <script>
        new Vue({
            el: '#app',
            data: {
                // 定义图片的索引
                index1: 0,
                // 定时器开关
                timer: null,
                // 图片数据 axios请求
                imgs: [

                ]
            },
            methods: {
                // 向左方法
                prev() {
                    if (--this.index1 <= 0) {
                        // 向左到第一张后返回第五张循环播放
                        this.index1 = this.imgs.length - 1
                    }
                },
                // 向右
                next() {
                    if (++this.index1 >= this.imgs.length) {
                        // 向右到最后一张后返回第1张循环播放
                        this.index1 = 0
                    }
                },
                // 点点高亮的点击事件
                dotClick(index) {
                    this.index1 = index
                },
                // 鼠标悬停方法
                stop() {
                    clearInterval(this.timer)
                },
                // 鼠标离开开始播放
                start() {
                    this.timer = setInterval(() => {
                        if (++this.index1 >= this.imgs.length) {
                            this.index1 = 0
                        }
                    }, 1000);
                }
            },
            // 数据代理完成  在代理完成后发送axios请求
            created() {
                axios.get('./img.json').then(r => {
                    console.log(r);
                    let {
                        data
                    } = r
                    console.log(data);
                    this.imgs = data
                })
            },
            // 挂载完成
            mounted() {
                this.timer = setInterval(() => {
                    if (++this.index1 >= this.imgs.length) {
                        this.index1 = 0
                    }
                }, 3000);

            },
            /*   // 销毁之前
              beforeDestroy() {
                  clearInterval(this.timer)
              }, */
        })
    </script>
</body>

</html>

#计算属性

  computed: {
                // 简写
                /*  fullName1() {
                     console.log('计算属性被调用了!');
                     return this.firstName + '.' + this.lastName
                 } */

                // 完整写法 计算属性一般是只读的,如果要可写得用完整写法,采用对象的形式
                fullName1: {
                    // 用于返回计算属性的值
                    get() {
                        return this.firstName + '.' + this.lastName
                    },
                    // 用于重新计算属性的值
                    set(val) {
                        let arr = val.split('.')
                        this.firstName = arr[0]
                        this.lastName = arr[1]
                    }
                }

            }

侦听器

<body>
    <!-- 
            computed和watch之间的区别:
    1.computed:将数据经过计算后返回对应的结果,因为计算属性用到的数据发生改变后会重新执行,所以computed具备一定的侦听能力。它能完成的功能,watch都可以完成。
    2.watch:要侦听哪个属性就以该属性key定义方法  两个参数,新值和旧值,该方法只是纯粹的监听指定的属性是否发生变化,如果变化了就执行对应的侦听方法。watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
    总结:  如果一个数据发生变化,需要重新返回一个结果,用computed  而需要重新执行某些程序,用watch                       
              
    两个重要的原则
	1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
	2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,
	这样this的指向才是vm 或 组件实例对象。
     -->
    <div id="app">
        <p>姓名:{{name}} <button @click="name+='@'">修改姓名</button></p>
        <p>年龄:{{age}} <button @click="setAge">修改年龄</button></p>
        <div v-if="isShow">22岁显示(methods)</div>
        <div v-if="isShow2">25岁显示(computed)</div>
        <div v-if="isShow3">30岁显示(watch)</div>
        <hr> {{emp}} <br>
        <button @clocl="emp = {}">替换整个对象</button>
        <button @click="emp.name+='@'">修改姓名</button>
        <button @click="emp.age--">修改年龄</button>
        <button @click="emp.car.carPrice++">修改汽车价格</button>
    </div>
    <script>
        Vue.config.productionTip = false
        new Vue({
            el: '#app',
            data() {
                return {
                    name: '李欢',
                    age: 19,
                    isShow: false,
                    isShow3: false,
                    emp: {
                        name: '秦玉姣',
                        age: 30,
                        car: {
                            carName: '大众',
                            carPrice: 25
                        }
                    }
                }
            },
            methods: {
                setAge() {
                    if (++this.age >= 22) this.isShow = true
                }
            },
            // computed: 将数据经过计算后返回对应的结果, 因为计算属性用到的数据发生改变后会重新执行,所以computed具备一定的侦听能力
            computed: {
                isShow2() {
                    return this.age >= 25
                }
            },
            // watch:要侦听哪个属性就以该属性key定义方法  两个参数,新值和旧值,该方法只是纯粹的监听指定的属性是否发生变化,如果变化了就执行对应的侦听方法
            watch: {
                // 轻度监视
                age(newVal, oldVal) {
                    if (newVal >= 30) {
                        this.isShow3 = true
                    }
                },
                // 深度监视   以配置对象的形式 
                emp: {
                    // immediate: true 渲染完成立即执行一次
                    immediate: true,
                    // 监视对象的某个属性发生变化要开启deep: true
                    // deep: true,
                    handler(n, o) {
                        // 监视对象只传一参
                        console.log(n, o);
                    }

                }
            }

        })
    </script>
</body>

过滤器

局部过滤器

<body>
    <div id="app">
        <!-- 同时使用全局和局部过滤器,以局部过滤器为准 -->
        <h2>{{price1 | toFixed2}} </h2>
        <h2>{{price2 | toFixed | ceil}} </h2>
        <h2>{{price3 | toFixed | ceil}} </h2>
        <h2>{{price4 | toFixed | ceil}}</h2>
        <!-- 输入框动态绑定值不需要加括号 -->
        <span><input type="text" :value="price1 | toFixed2 "></span>
        <hr>
        <p>{{msg}}</p>
        <p>{{msg | reverse}}</p>
        <p>{{birthday}}</p>
        <p>{{birthday | formatDate}}</p>
    </div>
    <script src="../js/vue.js"></script>
    <script src="./全局过滤器.js"></script>
    <script>
        // 关闭生产提示
        Vue.config.productionTip = false

        /* // 全局过滤器 第一个参数是名字  后面是回调函数
        Vue.filter('toFixed2', function(val) {
            return val.toFixed(3)
        })
        Vue.filter('reverse', function(val) {
            return val.split('').reverse().join('')
        })
        Vue.filter('formatDate', function(val) {
            let year = val.getFullYear()
            let month = val.getMonth() + 1
            let day = val.getDate()
            return [year, month, day].join('---')
        }) */
        new Vue({
            el: '#app',
            data() {
                return {
                    price1: 1.11111,
                    price2: 2.222,
                    price3: 3.5555555,
                    price4: 4.9899,
                    msg: 'HelloWrold',
                    // new Date 要加单引号
                    birthday: new Date('1992-05-28')
                }
            },
            // 局部过滤器
            filters: {
                toFixed(val) {
                    return val.toFixed(2)
                },
                ceil(val) {
                    return Math.ceil(val)
                },

            }
        })
    </script>
</body>

全局过滤器

要在组件中引入

// 全局过滤器 第一个参数是名字  后面是回调函数
Vue.filter('toFixed2', function (val) {
    return val.toFixed(3)
})
Vue.filter('reverse', function (val) {
    return val.split('').reverse().join('')
})
Vue.filter('formatDate', function (val) {
    let year = val.getFullYear()
    let month = val.getMonth() + 1
    let day = val.getDate()
    console.log([year, month, day].join('-'));
    return [year, month, day].join('-')
    
})

v-model

用法

<body>
    <div id="app">
        <!-- 
        lazy - 取代 input 监听 change 事件
        number - 输入字符串转为有效的数字
        trim - 输入首尾空格过滤 -->

        <!--1. v-model直接给输入框赋值 -->
        <h1><input type="text" v-model.lazy="msg">{{msg}}</h1>
        <hr>
        <!-- 2.复选框v-model获取checkbox的布尔值 -->
        <input type="checkbox" v-model="isAgree">是否同意? {{isAgree}}
        <hr>
        <!-- 3.单选框  v-model可以根据data中的数据默认勾选 ,然后获取value值-->
        <input type="radio" value="男" v-model="sex"><input type="radio" value="女" v-model="sex">{{sex}}
        <hr>
        <!-- 4. 多选框  v-model获取值生成到数组  写了value获取到是value的值-->
        <input type="checkbox" value="抽烟" v-model="hobby">北京
        <input type="checkbox" value="喝酒" v-model="hobby">上海
        <input type="checkbox" value="烫头" v-model="hobby">运城
        <input type="checkbox" value="洗澡" v-model="hobby">临汾 <br> {{hobby}}
        <hr>
        <!-- 5. 单选下拉框 v-model可以获取下拉框的值 不写value获取到是文本的值-->
        <select v-model="address">
            <option>北京</option>
            <option>上海</option>
            <option>运城</option>
            <option>临汾</option>
        </select>
        <br>{{address}}
        <br>
        <!-- 6. 多选下拉框 v-model可以获取下拉框的值 不写value获取到是文本的值-->
        <select v-model="address1" multiple>
            <option>北京</option>
            <option>上海</option>
            <option>运城</option>
            <option>临汾</option>
        </select>
        <br>{{address}}
    </div>
    <script>
        new Vue({
            el: '#app',
            data() {
                return {
                    msg: '你好啊',
                    isAgree: true,
                    sex: '男',
                    hobby: ['喝酒', '烫头'],
                    address: '北京',
                    address1: ['北京', '上海']
                }
            },
        })
    </script>
</body>

案例

<body>
    <div id="app">
        <h1>口碑信息统计表</h1>
        <table>
            <tr>
                <td>姓名:</td>
                <td> <input type="text" v-model.lazy="kb.name" placeholder="请输入姓名"></td>
            </tr>
            <tr>
                <td>年龄:</td>
                <td> <input type="text" v-model.number.lazy="kb.age" placeholder="请输入年龄"></td>
            </tr>
            <tr>
                <td>性别:</td>
                <td>
                    <input type="radio" v-model="kb.sex" value="男"><input type="radio" v-model="kb.sex" value="女"></td>
            </tr>
            <tr>
                <td>手机号:</td>
                <td> <input type="tel" v-model.lazy.trim.number="kb.tel" placeholder="请输入手机号"></td>
            </tr>
            <tr>
                <td>学历:</td>
                <td>
                    <select v-model="kb.educationBackground">
                        <option value="小学">小学</option>
                        <option value="初中">初中</option>
                        <option value="高中">高中</option>
                        <option value="大专">大专</option>
                        <option value="本科">本科</option>

                    </select>
                </td>
            </tr>
            <tr>
                <td>意向:</td>
                <td>
                    <input type="checkbox" v-model="kb.purpose" value="UI">UI
                    <input type="checkbox" v-model="kb.purpose" value="软件测试">软件测试
                    <input type="checkbox" v-model="kb.purpose" value="web前端">web前端
                    <input type="checkbox" v-model="kb.purpose" value="JAVA后端">JAVA后端
                    <input type="checkbox" v-model="kb.purpose" value="云计算">云计算
                    <input type="checkbox" v-model="kb.purpose" value="大数据">大数据
                </td>
            </tr>
            <tr>
                <td>给谁:</td>
                <td>
                    <input v-model="kb.toWho" type="radio" value="秦老师">秦老师
                    <input v-model="kb.toWho" type="radio" value="顾老师">顾老师
                    <input v-model="kb.toWho" type="radio" value="班主任">班主任
                    <input v-model="kb.toWho" type="radio" value="就业老师">就业老师
                </td>
            </tr>
            <tr>
                <td colspan="3">
                    <div style="color: pink; font-size: 20px;" v-if="kb.toWho==='秦老师'">爱你呦亲爱的!</div>
                    <div style="color: black; font-size: 20px;" v-if="kb.toWho==='顾老师'">教员提供终生技术指导</div>
                    <div style="color: red; font-size: 20px;" v-if="kb.toWho==='班主任'">谢谢宝子们!</div>
                    <div style="color: green; font-size: 20px;" v-if="kb.toWho==='就业老师'">包你高薪就业!</div>
                </td>
            </tr>
            <tr>
                <td></td>
                <td> <input type="checkbox" v-model="kb.isOk">是否同意
                    <button :disabled="!kb.isOk">提交</button>
                </td>
            </tr>
        </table>
        {{kb}}
    </div>
    <!-- 引入vue -->
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.24.0/axios.min.js"></script>
    <!-- 引入axios -->
    <script src='https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.js'></script>
    <script>
        // 关闭生产提示
        Vue.config.productionTip = false
        new Vue({
            el: '#app',
            data() {
                return {
                    kb: {
                        name: '',
                        age: '',
                        sex: '男',
                        tel: '',
                        educationBackground: '大专',
                        purpose: [],
                        toWho: '',
                        isOk: false
                    }
                }
            }
        })
    </script>
</body>

v2购物车

<body>
    <div id="app">
        <table v-cloak>
            <!-- 表头 -->
            <thead>
                <tr>
                    <th> <input type="checkbox" v-model="isCkAll">全选</th>
                    <th style="width: 60px; height: 50px;">名称</th>
                    <th>图片</th>
                    <th style="width: 60px;">单价</th>
                    <th style="width: 100px;">数量</th>
                    <th style="width: 60px;">小计</th>
                    <th style="width: 60px;">操作</th>
                </tr>
            </thead>
            <!-- 主体 -->
            <tbody v-if="this.goods.length>0">
                <tr v-for="(g, index) in goods" :key="g.id">
                    <td> <input type="checkbox" v-model="g.isCk"></td>
                    <td>{{g.name}}</td>
                    <td>
                        <img :src="g.pic">
                    </td>
                    <td>{{g.price | toRMB}}</td>
                    <td>
                        <button @click="g.count--" :disabled="g.count===1">-</button>
                        <input type="text" class="count" v-model.number="g.count" readonly>
                        <button @click=" jiaPrice(index)">+</button>
                    </td>
                    <td>{{g.price*g.count | toRMB}}</td>
                    <td>
                        <a href="javascript:;" @click="del">删除</a>
                    </td>
                </tr>
            </tbody>
            <tbody v-else>
                <tr>
                    <td colspan="7">
                        <img class="del" src="http://www.ykyao.com/postsystem/docroot/images/kindeditor/image/20160406/2016040615404366627.png">
                    </td>
                </tr>
            </tbody>
            <!-- 尾部 -->
            <tfoot>
                <td colspan="7" style="text-align: right;">
                    <span>总价:{{totalPrice | toRMB}}</span>
                    <span></span>
                </td>
            </tfoot>
        </table>
    </div>
    <!-- 引入vue -->
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.24.0/axios.min.js"></script>
    <!-- 引入axios -->
    <script src='https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.js'></script>
    <script>
        // 关闭生产提示
        Vue.config.productionTip = false
        new Vue({
            el: '#app',
            data() {
                return {
                    goods: [{
                        id: 1,
                        name: '手表',
                        pic: 'https://img13.360buyimg.com/n7/jfs/t1/90088/17/20462/75026/61d1b2e7Efd207486/4723905806de1f2c.jpg',
                        price: 2199,
                        count: 1,
                        isCk: false
                    }, {
                        id: 2,
                        name: '手机',
                        pic: 'https://img13.360buyimg.com/n7/jfs/t1/155183/24/7208/46178/5fbe0446E88417894/63cd6bffac98185d.jpg',
                        price: 3999,
                        count: 1,
                        isCk: true
                    }, {
                        id: 3,
                        name: '电视',
                        pic: 'https://img10.360buyimg.com/n7/jfs/t1/200000/38/15689/51980/6182619eE5044433f/22a173da97a3d92e.jpg',
                        price: 3499,
                        count: 1,
                        isCk: true
                    }, {
                        id: 4,
                        name: '冰箱',
                        pic: 'https://img10.360buyimg.com/n7/jfs/t1/149908/15/2773/53205/5f0ad38bEeeedb207/aefa4ba990cbf08d.jpg',
                        price: 2999,
                        count: 1,
                        isCk: false
                    }, ]
                }
            },
            methods: {
                // 加
                jiaPrice(index) {
                    if (this.goods[index].count >= 9) {
                        alert('最多购买9件')
                    } else {
                        this.goods[index].count++
                    }
                },
                // 删除
                del(index) {
                    // if (!confirm('确定删除吗?')) return
                    this.goods.splice(index, 1)
                }

            },
            filters: {
                toRMB(val) {
                    return '¥' + val.toFixed(2)
                }
            },
            computed: {
                // 判断是否全选
                isCkAll: {
                    get() {
                        // 每一项被选就全选
                        return this.goods.length > 0 && this.goods.every(r => r.isCk)

                    },
                    set(val) {
                        // val是isCkAll的值 
                        this.goods.forEach(r => r.isCk = val)
                    }
                },
                totalPrice() {
                    // let sum = 0
                    // this.goods.filter(r => r.isCk).map(r => {
                    //     sum += r.price * r.count
                    // })
                    // return sum
                    return this.goods.filter(r => r.isCk).map(r => r.price * r.count).reduce((a, b) => {
                        return a + b
                    }, 0)
                }
            }
        })
    </script>
</body>

深度响应式

Vue监视数据的原理:
			1. vue会监视data中所有层次的数据。

			2. 如何监测对象中的数据?
							通过setter实现监视,且要在new Vue时就传入要监测的数据。
								(1).对象中后追加的属性,Vue默认不做响应式处理
								(2).如需给后添加的属性做响应式,请使用如下API:
												Vue.set(target,propertyName/index,value) 或 
												vm.$set(target,propertyName/index,value)

			3. 如何监测数组中的数据?
								通过包裹数组更新元素的方法实现,本质就是做了两件事:
									(1).调用原生对应的方法对数组进行更新。
									(2).重新解析模板,进而更新页面。

			4.在Vue修改数组中的某个元素一定要用如下方法:
						1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
						2.Vue.set() 或 vm.$set()
			
			特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!

插槽

普通插槽

<body>
    <div id="app" v-cloak>
        <c-car :title="bsj.title" :content="bsj.content">
        </c-car>
    </div>

    <!-- 引入vue -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>

    <script>
        Vue.component('c-car', {
                template: `
                            <div class="box">
                                <h2>{{title}}</h2>
                                <slot></slot>
                                <div>{{content}}</div>
                            </div>
                            `,
                props: ['title', 'content']
            })
            // 关闭生产提示
        Vue.config.productionTip = false
        new Vue({
            el: '#app',
            data() {
                return {
                    bsj: {
                        title: '保时捷',
                        content: '必须买一辆'
                    }
                }
            },
        })
    </script>
</body>

具名插槽

<body>
    <div id="app" v-cloak>

        <a-box>
            <!-- 在组件内部写 <template></template>标签,在标签内部写上要放到哪个插槽 v-slot  简写为# -->
            <template #header>
                <h2>保时捷</h2>
            </template>
            <template #content>
            </template>
            <template #footer>
                <div>100</div>
            </template>
        </a-box>
    </div>

    <!-- 引入vue -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>

    <script>
        Vue.component('a-box', {
                template: `
          <div class="box">
              <div class="header"><slot name="header"></slot></div>
              <div class="content"><slot name="content"></slot></div>
              <div class="footer"><slot name="footer"></slot></div>
          </div>
                            `,
            })
    </script>
</body>

作用域插槽

<body>
    <div id="app" v-cloak>
        <b-box>
            <!-- 2.具名插槽接收到组件传出来的数据scope,通过scope对数据进行增删改查 -->
            <template #btn="scope">
                <button @click="scope.list[scope.index].price++">修改价格</button>
                <button @click="scope.list.splice(scope.index,1)">行内删除</button>
                <!-- 3.如果要实现更复杂的业务,需要单独定义方法,在vue实例中定义,将整个scope传出去 -->
                <button @click="del(scope)">方法删除</button>
            </template>
        </b-box>
    </div>
    <!-- 引入vue -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
    <script>
        Vue.component('b-box', {
                // 1.作用域插槽必须是具名插槽   slot定义插槽名字。 将索引和列表传出去
                template: `
                <div class="box">
                    <ul>
                        <li v-for="(item, index) in list" :key="index">
                            <span>{{item.id}}--{{item.name}}--{{item.price}} </span>
                            <slot name="btn" :index="index" :list="list"></slot>
                        </li>
                    </ul>
                </div>
            `,
                data() {
                    return {
                        list: [{
                            id: 1,
                            name: '奔驰',
                            price: 100
                        }, {
                            id: 2,
                            name: '宝马',
                            price: 120
                        }, {
                            id: 3,
                            name: '奥迪',
                            price: 150
                        }]
                    }
                },
            })
            // 关闭生产提示
        Vue.config.productionTip = false
        new Vue({
            el: '#app',
            data() {
                return {}
            },
            mounted() {},
            methods: {
                del(scope) {
                    if (confirm('确定删除吗?'))
                        scope.list.splice(scope.index, 1)
                }
            },
            computed: {},
            watch: {}
        })
    </script>
</body>

自定义轮播组件

<!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">
   <link rel="stylesheet" href="//at.alicdn.com/t/font_3177501_1q8vo20s883.css">
   <title>Document</title>

   <style>
       #app {
           position: relative;
           width: 800px;
           margin: 0 auto;
       }
       
       .lunbo {
           position: relative;
       }
       
       img {
           width: 100%;
       }
       
       .left,
       .right {
           width: 60px;
           height: 80px;
           background-color: rgba(227, 245, 168, 0.212);
           font-size: 30px;
           color: aqua;
           text-align: center;
           line-height: 80px;
           position: absolute;
           top: 30%;
           cursor: pointer;
       }
       
       .lunbo .left {
           top: 0;
           bottom: 0;
           margin: auto;
           left: 0px;
           user-select: none;
       }
       
       .lunbo .right {
           top: 0;
           bottom: 0;
           margin: auto;
           right: 0px;
           user-select: none;
       }
       
       .dot ul {
           width: 100%;
           display: flex;
           justify-content: center;
           position: absolute;
           bottom: 10px;
       }
       
       .dot ul li {
           list-style: none;
           width: 10px;
           height: 10px;
           background-color: #ccc;
           border-radius: 50%;
           margin: 0 5px;
           cursor: pointer;
       }
       
       .dot ul li.active {
           background-color: tomato;
       }
   </style>
</head>
<div id="app">
   <!-- :index1="index1" 控制图片索引 非必传
        :imgs="imgs"     控制图片数据  必传
        :lunbotime="lunbotime"  控制轮播间隔时间  非必传   -->
   <b-lunbo :imgs="imgs"></b-lunbo>
</div>

<body>
   <!-- 引入axios -->
   <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
   <!-- 引入vue -->
   <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
   <script>
       Vue.config.productionTip = false
       Vue.component('b-lunbo', {
           template: `
                       <div class="lunbo">
                                    <!-- 图片  -->
                           <img :src="imgs[myIndex1]" @mouseenter="stop" @mouseleave="start">
                                    <!-- 左右切换按钮 -->
                           <div class="left" @click="prev">&lt;</div>
                           <div class="right" @click="next">&gt;</div>
                                     <!-- 点点 -->
                           <div class="dot">
                               <ul>
                                   <li v-for="(item,index) in imgs" :class="[index===myIndex1?'active':'']" @click="dotClick(index)"></li>
                               </ul>
                           </div>
                       </div>
                `,

           props: {
               index1: {
                   type: Number,
                   default: 0
               },
               imgs: {
                   type: Array,
               },
               // 轮播时间默认3000
               lunbotime: {
                   type: Number,
                   default: 3000
               }
           },
           data() {
               return {
                   // 定时器开关
                   timer: null,
                   // 备份
                   myIndex1: this.index1,
                   myLunboTime: this.lunbotime
               }
           },
           methods: {
               // 向左方法
               prev() {
                   if (--this.myIndex1 <= 0) {
                       // 向左到第一张后返回第五张循环播放
                       this.myIndex1 = this.imgs.length - 1
                   }
               },
               // 向右
               next() {
                   if (++this.myIndex1 >= this.imgs.length) {
                       // 向右到最后一张后返回第1张循环播放
                       this.myIndex1 = 0
                   }
               },
               // 鼠标悬停方法
               stop() {
                   // 清除定时器停止播放
                   clearInterval(this.timer)
               },
               // 圆点的点击事件
               dotClick(index) {
                   this.myIndex1 = index
               },
               // 定时器
               start() {
                   this.timer = setInterval(() => {
                       if (++this.myIndex1 >= this.imgs.length) {
                           this.myIndex1 = 0
                       }
                   }, this.myLunboTime);
               }
           },
           // 挂载完成后开始播放
           mounted() {
               this.start()
           },
       })

       new Vue({
           el: '#app',
           data: {
               // 控制轮播时间
               lunboTime: 1000,
               // 图片数据 axios请求
               imgs: []
           },
           methods: {
               // 请求数据方法 赋值给imgs
               async getImg() {
                   let {
                       data
                   } = await axios.get('./img.json')
                   this.imgs = data
               }
           },
           // 挂载完成
           mounted() {
               // 请求数据
               this.getImg()
           },

       })
   </script>
</body>

render函数

new Vue({
   //在工程化开发的环境中,引入的模板是不完整的,不带解析模板的
   //原因是为了减少文件体积,不带解析模板200kb,带模板300kb
   // 直接导入vue会报错,要求使用render函数,可以在vue的package里面找到入口和出口文件,改成完整版的vue
   el: "#app2",
   // 如果手动添加了render函数,vue会以render函数为主,而不去使用el选项
   //reder函数会替换掉html容器里面的内容
   // 给vue换个容器 改成app2
   render: function(h) {
       return h('h1', this.name + '-----' + this.age)
   },
   data() {
       return {
           name: '李欢',
           age: 18

       }
   },
})
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值