兵哥 vue-cli

一、初始Vue-Cli

1. 安装

npm install -g @vue/cli

# OR

yarn global add @vue/cli

查看版本

vue --version

升级

npm update -g @vue/cli

# 或者

yarn global upgrade --latest @vue/cli

2. 创建几个组件

2.1. 父子组件之间传值

<Goods :goodses="goodses" :carName="carName" :carPrice="carPrice"

    @changeCarName="changeCarName" @changeCarPrice="changeCarPrice"></Goods>

// 接收属性

props:['goodses','carName','carPrice'],

    data() {

    return {

        // 备份props传递过来的参数

        myCarName:this.carName,

        myCarPrice:this.carPrice

    }

},

methods: {

        // 修改商品价格--价格每次加100

        updateGoods(id){

            this.goodses.find(g=>g.id===id).price+=100

        },

        // 删除商品

        deleteGoods(index){

            this.goodses.splice(index,1)

        },

        // 修改汽车名称

        updateCarName(){

            this.myCarName = '宝马'

            // 触发自定义事件changeCarName,将最新的汽车名称作为事件对象传回去。

            this.$emit('changeCarName',this.myCarName)

        },

        // 修改汽车价格

        updateCarPrice(){

            this.myCarPrice = '70W'

            // 触发自定义事件changeCarPrice,将最新的汽车价格作为事件对象传回去。

            this.$emit('changeCarPrice',this.myCarPrice)

        }

}

2.2. 安装Element-UI

安装

npm install element-ui

导入

// 导入element-ui组件库

import ElementUI from 'element-ui';

// 导入element-ui组件库的样式

import 'element-ui/lib/theme-chalk/index.css';

// 注意:element-ui组件库,是一个插件,所有的插件都要由Vue去use

Vue.use(ElementUI);

2.3. 安装Echarts

// 导入echarts的所有成员,并转成一个对象

import * as echarts from "echarts";

export default {

  name: "Echarts",

  data() {

      return {

          // 用户接收后台返回的数据  

          list:[]

      }

  },

  // 数据已经可以使用了  

  created() {

    // 发送ajax请求,获取数据

    this.list = [

        {

            name:'衬衫',

            count:5

        },

        {

            name:'羊毛衫',

            count:20

        },

        {

            name:'雪纺衫',

            count:36

        },

        {

            name:'裤子',

            count:10

        },

        {

            name:'鞋子',

            count:50

        }

    ]  

  },

  // 组件挂载完毕

  mounted() {

    // 基于准备好的dom,初始化echarts实例

    var myChart = echarts.init(document.querySelector(".box"));

    // 绘制图表

    myChart.setOption({

      title: {

        text: "ECharts 入门示例",

      },

      tooltip: {},

      // X轴信息  

      xAxis: {

        // 商品名称数据作为X轴信息展示

        data: this.list.map(r=>r.name),

      },

      // Y轴信息  

      yAxis: {},

      // 系列  

      series: [

        {

          name: "销量",

          type: "bar",

          // 显示每个商品的销售信息  

          data: this.list.map(r=>r.count)

        },

      ],

    });

  },

};

二、初始路由

1. 安装

npm install vue-router

2. 导入

import Vue from 'vue'

import VueRouter from 'vue-router'

Vue.use(VueRouter)

3. 创建路由器

// 导入页面组件

import Index from '../pages/Index.vue'

// 创建一个路由器对象

export default new VueRouter({

    //定义当前路由器对象管理的路由信息

    routes:[{

        //路由路径

        path:'/',

        //路由名称

        name:'Index'

        //路由组件

        component:Index

    }]

})

4. 配置路由器

// 导入当前项目中创建的路由器对象

import router from './router'

new Vue({

  render: h => h(App),

  // 在Vue的实例上,配置一个路由器对象

  router

}).$mount('#app')

5. 使用路由

5.1. 路由组件跳转

<!-- 路由链接,用于跳转路由,to属性设置路由路径 -->

<router-link to="/">首页</router-link>

<!-- 路由视图,用于显示路由组件,当浏览器的地址栏中切换到指定的路由路径时,

就会在router-view中显示对应的路由组件。-->

<router-view></router-view>

5.2. 编程式路由跳转

// $router就是当前项目中的路由器对象,它的push方法,用于跳转路由

// replace方法,也是用于跳转路由。

// push方法是在浏览器的历史记录中,添加一个路由信息

// replace方法是在浏览器的历史记录中,替换前一条路由信息

this.$router.push('/order')

6. swiper插件(低版本)

6.1. 安装

npm install swiper@5 vue-awesome-swiper@4

6.2. 导入

全局导入

// 导入swiper

import VueAwesomeSwiper from 'vue-awesome-swiper'

// 导入swiper的样式

import 'swiper/css/swiper.css'

// 因为swiper是插件,所以要use

Vue.use(VueAwesomeSwiper)

局部导入

// 导入swiper的组件

import { Swiper, SwiperSlide } from 'vue-awesome-swiper'

// 导入swiper的样式

import 'swiper/css/swiper.css'

export default {

    // 注册组件

    components: {

        Swiper,

        SwiperSlide

    }

}

6.3. 使用

<swiper :options="swiperOptions">

    <swiper-slide>

        <img src="http://p1.music.126.net/Y6gItVxUvkbvI2cC8KVZYA==/109951166461233203.jpg?imageView&quality=89">

    </swiper-slide>

    <swiper-slide>

        <img src="http://p1.music.126.net/ypjEcAl-BXKqb2UWdau-Tw==/109951166463199078.jpg?imageView&quality=89">

    </swiper-slide>

    <swiper-slide>

        <img src="http://p1.music.126.net/_7zX4BjboCYo4KYRvpayDg==/109951166461246383.jpg?imageView&quality=89">

    </swiper-slide>

    <swiper-slide>

        <img src="http://p1.music.126.net/3Vwphalm49ewNV-lIJUBNA==/109951166461279853.jpg?imageView&quality=89">

    </swiper-slide>

    <!-- 分页器 -->

    <div class="swiper-pagination" slot="pagination"></div>

    <!--左箭头。如果放置在swiper-container外面,需要自定义样式。-->

    <div class="swiper-button-prev" slot="button-prev"></div>

    <!--右箭头。如果放置在swiper-container外面,需要自定义样式。-->

    <div class="swiper-button-next" slot="button-next"></div>

</swiper>

data() {

    return {

        // 定义swiper的配置选项

        swiperOptions: {

            // 指定分页器

            pagination: {

                //指定分页器的容器

                el: ".swiper-pagination",

                //点击分页器的指示点分页器会控制Swiper切换

                clickable:true

            },

            // 配置衔接滑动

            loop:true,

            // 配置自动播放

            // autoplay:true

            autoplay:{

                //自动播放

                autoplay:true,

                //设置间隔时间

                delay:3000,

                // 用户操作swiper之后,是否禁止autoplay

                disableOnInteraction:false

            },

            // slide的切换效果

            effect:'coverflow',

            // 箭头

            navigation:{

                nextEl: '.swiper-button-next',

                prevEl: '.swiper-button-prev',

            }

        },

    };

},

三、路由传参

1. params 参数

路由配置

{

    path:'/index',

    // 重定向到指定的路由

    redirect:'/'

},

{

    // 注意:这里的路由需要传一个参数,路由可以传多个参数

    path:'/city/:id',

    // 设置该选项为true,组件可以通过props选项接收路由参数

    props:true,

    component:City

},

// *号,表示匹配不上的所有路由

{

    path:'*',

    component:Error404

}

页面

<li @click="$router.push(`/city/${item.id}`)" v-for="(item,index) in citys" :key="index">{{item.name}}</li>

// 使用props选项接收路由参数

props:["id"],

created() {

    // $route返回的是当前路由信息,它身上有一个params属性,该属性里面保存的是当前路由信息的参数。

    // console.log(this.$route);

    // console.log(this.$route.params.id);

    // 从路由参数中获取城市编号

    // let cityId = this.$route.params.id

    // 再根据城市编号,获取对应的城市信息

    // this.city = this.citys.find(c=>c.id==cityId)

    this.city = this.citys.find(c=>c.id==this.id)

},

v-html指令

<!-- 所有由ref修饰的组件或标签,都会保存到$refs中 -->

<!-- <div ref="content"></div> -->

<!-- v-html指令,用于渲染html内容 -->

<div v-html="city.content"></div>

<!-- v-text指令,用于渲染文本内容 -->

<!-- <div v-text="city.content"></div> -->

mounted() {

    this.$refs.content.innerHTML = this.city.content

},

2. query参数

<!-- 路由地址,采用query传参方式:?参数1=XXX&参数2=XXX... -->

<li @click="$router.push(`/type?id=${item.id}`)"

    v-for="(item,index) in types" :key="index">{{item.name}}</li>

created() {

    // 通过$route.query获取路由地址?后面的参数

    // console.log(this.$route.query);

    this.type = this.types.find(t=>t.id==this.$route.query.id)

}

3. router 和router和route

// $router返回的是当前项目中的路由器对象  

// $route返回的是当前路由信息

// 判断当前路由信息,不是/news,添加到/news

if(this.$route.path != '/news'){

    this.$router.push('/news')

}

4. vue.config.js

// 引入nodejs内置模块path

let path = require('path')

// 注意:该配置文件中,只能使用commonjs模块化语法

module.exports = {

    // 关闭 eslint-loader 语法检查

    lintOnSave:false,

    // 配置devServer开发服务器

    devServer:{

        // 端口号

        port: 5566,

        // 自动打开

        open:true,

        // 静态资源路径

        // 注意:__dirname是nodejs的内置变量,返回的是的当前项目的绝对路径

        contentBase: path.join(__dirname, "static")

    },

    // 用于配置原生的Webpack配置

    configureWebpack:{

        // 解析

        resolve:{

            // 定义路径别名

            alias:{

                "@c":path.resolve(__dirname,'src/components'),

                "@p":path.resolve(__dirname,'src/pages'),

                "@a":path.resolve(__dirname,'src/apis'),

                "@u":path.resolve(__dirname,'src/utils'),

            }

        }

    }

}

四、路由进阶

1. 路由模式

// 路由模式

// 有两种模式:hash模式(默认) 和 history模式

// hash模式,使用的是锚链接的原理实现路由的跳转,这种方式兼容性非常好;缺点是路径带有#号,不够美观。

// history模式,使用的是浏览器中内置的history对象实现路由的跳转,这种方式不兼容老版本的浏览器,刷新后会丢失路由信息。

mode:'hash'

2. 路由元信息

{

    path:'/',

    name:'home',

    // meta选项,用于配置路由的元信息,里面的内容是自定义的,用于配置路由的数据

    meta:{

        title:'首页'

    },

    // 路由组件懒加载

    component:()=>import('../pages/Home.vue'),

}

3. nprogress加载进度条

安装

npm install nprogress

导入

// 导入nprogress

import NProgress from "nprogress";

// 导入nprogress的样式

import "nprogress/nprogress.css";

在导航守卫中使用

// 导航守卫

// 1.路由前置守卫--路由跳转之前

router.beforeEach((to, from, next) => {

  // to 返回去哪里的路由信息

  // from 返回从哪来的路由信息

  // next方法,用于跳转

  // 开启loading

  NProgress.start();

  // 通常:在这里会做一些权限验证操作

  next();

});

// 2.路由后置守卫--路由跳转完成

router.afterEach((to, from) => {

  // 通常:在这里会做一些页面的修改操作

  document.title = to.meta.title;

  // 结束loading

  NProgress.done();

});

4. 二级路由

//配置子路由信息

children:[

    //手机订单路由

    {

        path:'phoneOrder',

        name:'phoneOrder',

        meta:{

            title:'手机订单'

        },

        component:()=>import(/* webpackChunkName: "b" */'../pages/Order/PhoneOrder.vue')

    }

]

4. 路由懒加载

// 路由组件懒加载

component:()=>import('../pages/Home.vue')

5. 路由分组懒加载

// 路由组件分组懒加载

component:()=>import(/* webpackChunkName: "a" */'../pages/News.vue')

6. scoped

scoped属性,用于设置局部样式,当前组件中的样式只对当前组件生效

<style scoped>

    ....

</style>

7. sass

安装

npm install sass sass-loader@8 -D

使用

<style scoped lang="scss">

    // lang="scss" 就表示下面的样式采用的sass语法编写。

    // 定义变量

    $c1:darksalmon;

    $c2:cornflowerblue;

    // 定义嵌套样式

    .main{

        border: 1px solid black;

        margin-top: 10px;

        padding: 5px;

        h2{

            color: $c2;

        }

        .one{

            border: 1px dashed darkgreen;

            padding: 5px;

            h2{

                color: $c1;

                //&符号表示当前元素

                &.first{

                    font-size: 40px;

                }

            }

        }

    }

</style>

五、路由缓存

1. keep-alive组件

<!-- keep-alive用于缓存路由组件,默认情况下会缓存打开的所有组件,

如果需要指定缓存哪些组件,通过include属性指定。 -->

<keep-alive :include="['newsGn','newsGj']">

    <router-view></router-view>

</keep-alive>

2. 路由组件特有的两个生命周期

// 路由组件激活状态生命周期函数

activated() {

    // 开启定时器

    this.timer = setInterval(() => {

        this.count++

    }, 1000);

},

// 路由组件失活状态生命周期函数

deactivated() {

    clearInterval(this.timer)

},

六、组件间传值

1. 父子组件传值

父传子

// 接收父组件传值

props:['name','age']

子传父

// 触发一个自定义事件

this.$emit('updateName',this.myName)

2. 祖孙组件传值

// 添加依赖数据,它里面定义的数据,子组件可以选择性注入并直接使用。

provide(){

    return {

        carName:this.carName,

        carPrice:this.carPrice,

        updateCarName:this.updateCarName,

        updateCarPrice:this.updateCarPrice

    }

}

// 注入祖级组件中的依赖数据,注意:跟props一样,接过来的数据是只读的,不能修改。

inject:['carName','carPrice','updateCarName','updateCarPrice']

3. 兄弟组件传值

// 在Vue是原型对象上,添加一个$bus属性,该属性的的属性值是一个Vue实例。

// 将Vue的所有实例,都将共用同一个$bus。

// 这个$bus属性,我们称之为:中央事件总线

Vue.prototype.$bus = new Vue()

//触发事件

this.$bus.$emit('getAddress',this.address)

//监听事件

this.$bus.$on('getAddress',(e)=>{

    this.address = e

})

4. 全局状态管理

安装

npm install store

导入

//导入vuex插件

import Vuex from 'vuex'

//使用vuex插件

Vue.use(Vuex)

创建

//创建状态管理对象

let store = new Vuex.Store({

  //state选项,定义状态(状态就是数据)

  state:{

    planeName:'波音747',

    planePrice:'10Y'

  },

  //mutations选项,定义方法(注意:这里面只能定义同步方法)

  mutations:{

    //修改飞机的名称

    updatePlaneName(state,value){

      state.planeName = value

    },

    //修改飞机的价格

    updatePlanePrice(state,value){

      state.planePrice = value

    }

  }

})

使用

<!-- $store返回的是当前项目中的全局状态对象 -->

<h4>飞机信息:{{$store.state.planeName}},价格:{{$store.state.planePrice}}</h4>

//commit()方法,用于执行指定的mutations里面的方法

this.$store.commit('updatePlaneName','B52轰炸机')

this.$store.commit('updatePlanePrice','20Y')

七、Vuex

1. phone模块

export default {

  //namespaced:true是设置私有命名空间,默认情况下该属性是false。

  //非私有命名空间的模块,只有state是私有的,getters、mutations、actions任然提升到全局中,

  //私有命名空间的模块,所有成员都是私有的(局部的)

  namespaced: true,

  state: {

    //手机数组

    phones: [

      {

        name: "iphone13",

        price: 6999,

      },

      {

        name: "华为",

        price: 5999,

      },

      {

        name: "小米",

        price: 4999,

      },

    ],

  },

  getters: {

    // 计算手机总价

    totalPhonePrice(state) {

      return state.phones.reduce((p, c) => p + c.price, 0);

    },

  },

  mutations: {

    addPhone(state, value) {

      state.phones.push(value);

    },

  },

  actions: {

    addPhone(store, value) {

      setTimeout(() => {

        store.commit("addPhone", value);

      }, 2000);

    },

  }

};

2. store对象

//导入vue

import Vue from "vue";

//导入vuex插件

import Vuex from "vuex";

//使用vuex插件

Vue.use(Vuex);

//导入手机模块

import phone from './modules/phone.js'

//创建状态管理对象,并导出

export default new Vuex.Store({

  //定义状态

  state: {

    //姓

    firstName: "张",

    //名

    lastName: "三",

    //汽车数组

    cars: [

      {

        name: "奔驰",

        price: 50,

      },

      {

        name: "宝马",

        price: 40,

      },

      {

        name: "奥迪",

        price: 30,

      },

    ],

  },

  //定义计算属性

  getters: {

    //姓名--方法的参数是状态对象

    fullName(state) {

      //通过状态对象,可以获取到所有的状态信息

      return state.firstName + "." + state.lastName;

    },

    //汽车的总价

    totalCarPrice(state) {

      return state.cars.reduce((p, c) => p + c.price, 0);

    },

  },

  //定义操作状态的方法(这里的方法一般都是同步方法)

  mutations: {

    //修改姓--第一个参数是状态,第二个参数是新值

    updateFirstName(state, value) {

      state.firstName = value;

    },

    //修改名

    updateLastName(state, value) {

      state.lastName = value;

    },

    //添加汽车

    addCar(state, value) {

      state.cars.push(value);

    },

  },

  //定义操作状态的方法(这里的方法可以定义异步方法)

  actions: {

    // 修改名--第一个参数是上下文对象(就是当前store对象),第二个参数是新值

    updateLastName(store, value) {

      //注意:actions最好不要直接操作state,通过mutations操作state

      //所以,actions直接操作是mutations

      //为什么要这么设计,因为我们可能要跟value值发送请求,获取对应的值

      // 这里我们使用定时器,默认异步过程。

      setTimeout(() => {

        store.commit("updateLastName", value);

      }, 2000);

    },

    //添加汽车

    addCar(store, value) {

      store.commit("addCar", value);

    },

  },

  //模块

  modules: {

    //手机模块

    phone

  },

});

3. 注册给Vue

// 导入当前项目的路由器对象

import router from './router'

// 导入当前项目的全局状态管理对象

import store from './store'

new Vue({

  //使用路由

  router,

  //使用全局状态管理

  store,

  //渲染App组件

  render: h => h(App)

}).$mount('#app')

4. 使用

计算属性中转

computed:{

    //返回汽车数组

    cars(){

        return this.$store.state.cars

    },

    //返回汽车总价

    totalCarPrice(){

        return this.$store.getters.totalCarPrice

    },

    //返回手机数组信息

    phones() {

      // 注意:手机数组数据在phone模块中

      // $store.state返回的是全局状态,根据全局状态获取指定模块,再获取该模块中具体的状态。

      return this.$store.state.phone.phones;

    },

    //返回手机总价

    totalPhonePrice(){

        // 注意:总价在phone模块中

        // 获取模块中的计算机属性的方式是['模块名/计算属性名']

        return this.$store.getters['phone/totalPhonePrice']

    }

}

调用方法

methods: {

        //修改姓名

        updateFirstName(){

            this.$store.commit('updateFirstName','王')

        },

        //同步方法修改名

        syncUpdateLastName(){

            //commit()方法,调用的是mutations里面的方法

            this.$store.commit('updateLastName','明')

        },

        //异步方法修改名

        asyncUpdateLastName(){

            //dispatch()方法,调用的是actions里面的方法

            this.$store.dispatch('updateLastName','天')

        },

        //添加汽车

        addCar(){

            this.$store.dispatch('addCar',this.car)

        },

        //同步方法添加手机

        syncAddPhone(){

            // 注意:addPhone方法在phone模块中

            this.$store.commit('phone/addPhone',this.phone)

        },

        //异步方法添加手机

        asyncAddPhone(){

            // 注意:addPhone方法在phone模块中

            this.$store.dispatch('phone/addPhone',this.phone)

        }

}

八、映射函数

1. 导入映射函数

// 从vuex中,导入映射函数

import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'

2. 使用映射函数生成计算属性

computed:{

    //如果vuex里面state的数据名称 跟 页面中的计算属性名称相同,

    //就可以使用mapState映射函数,自动生成页面中的计算属性。

    ...mapState(['cars']),

    //注意:如果要映射模块里面的state,函数的第一个参数设置为模块的名称

    ...mapState('phone',['phones']),

    //如果vuex里面getters的数据名称 跟 页面中的计算属性名称相同,

    //就可以使用mapGetters映射函数,自动生成页面中的计算属性。

    ...mapGetters(['totalCarPrice']),

    //注意:如果要映射模块里面的getters,函数的第一个参数设置为模块的名称

    ...mapGetters('phone',['totalPhonePrice'])

}

3. 使用映射函数生成方法

// 注意1:生成的方法名跟mutations里面的方法名相同。

// 注意2:生成的方法会带有一个参数,通过参数传递数据。

...mapMutations(['deleteCar']),

// 注意:如果要映射模块里面的方法,第一个参数传递模块的名称

...mapMutations('phone',['deletePhone'])

...mapActions(['addCar'])

...mapActions('phone',['addPhone'])

九、自定义插件、自定义指令

1. key

<ul>

    <!-- 注意:如果只是展示列表数据,这里的可以可以是索引,

    如果列表中的数据会经常发生变化,特别是列表的数据的位置会发生变化,

    这个是key一定要设置为对象身上的唯一属性,比如:学号,工号,车牌号等等,

    这样做会大大提高列表重新渲染的性能损耗。 -->

    <li v-for="(item) in list" :key="item.id">

        {{item.id}}--{{item.name}}--{{item.sex}}--{{item.age}}

        <button @click="item.age++">添加年龄</button>

    </li>

</ul>

<div>

    <p>学号:<input type="text" v-model="obj.id"></p>

    <p>姓名:<input type="text" v-model="obj.name"></p>

    <p>性别:<input type="text" v-model="obj.sex"></p>

    <p>年龄:<input type="text" v-model.number="obj.age"></p>

    <p><button @click="add">添加</button></p>

</div>

add(){

    //验证学号和姓名不能为空

    if(!this.obj.id || !this.obj.name) return alert('学号和姓名不能为空')

    //验证学号不能重复

    if(this.list.map(r=>r.id).includes(this.obj.id)) return alert('学号不能重复')

    //添加到数组中

    this.list.unshift(this.obj)

    //清空当前对象

    this.obj = {

        id:'',

        name:'',

        sex:'',

        age:''

    }

}

2. $nextTick()

// $nextTick()回调函数里面的代码,回在DOM渲染完毕后执行

// 在Vue中,如果我们需要手动操作DOM,经常会用到这个方法。  

this.$nextTick(()=>{

    this.$refs.car.focus()

})

3. 自定义指令

directives:{

      //自定义一个指令,指令名称是myhtml,

      //自定义指令就是一个方法,该方法有两个参数:返回指令所在的dom元素,绑定的一份数据  

      myhtml:function(el,binding){

          el.innerHTML = binding.value

      },

      red:function(el){

          el.style.color = 'red'

      },

      color:function(el,binding){

          el.style.color = binding.value

      }

}

4. 自定义插件

// 定义一个插件,插件就是将给Vue添加的全局成员,归类到一起去,这样做利于后期维护。

export default {

  //插件中必须包含一个install方法,方法的第一个参数不是Vue,后面的参数是可选的

  install: function(Vue) {

    // 注册全局指令

    Vue.directive("myhtml", function(el, binding) {

      el.innerHTML = binding.value;

    });

    Vue.directive("red", function(el) {

      el.style.color = "red";

    });

    Vue.directive("color", function(el, binding) {

      el.style.color = binding.value;

    });

    //全局混入,之后所有的Vue实例,都将拥有里面定义的成员

    Vue.mixin({

      data() {

        return {

          myName: "组件",

          myAge: 20,

        };

      },

      methods: {

        sayHi() {

          alert("大家好!");

        },

      },

    });

    //给Vue的原型对象添加成员,之后所有的Vue实例,都将共享这些成员

    Vue.prototype.address = "北京市朝阳区1001号";

    //全局过滤器

    Vue.filter("toFixed2", function(val) {

      return val.toFixed(2);

    });

    //注册全局组件

    Vue.component("b-button", {

      render: (h) => h("button", { style: { color: "red" } }, "按钮"),

    });

  },

};

// 导入自定义插件

import myPlugin from './plugin'

//use方法,就是去调用插件中的install方法。

Vue.use(myPlugin)

十、代理服务器

1. 过渡

页面

<!-- 将需要做动画或过渡效果的内容,用transition包起来 -->

<transition name="box">

    <div class="box" v-show="isShow">

        <h2>最后一个月,一定好好学习</h2>

    </div>

</transition>

<hr />

<!-- 给列表添加动画或过渡效果,用transition-group -->

<button @click="addGoods">添加</button>

<transition-group name="box" tag="ul">

    <li v-for="(item, index) in goodses" :key="item.id">

        {{ item.id }}--{{ item.name }}

        <button @click="delGoods(index)">删除</button>

    </li>

</transition-group>

样式

//进入时样式 和 离开时样式

.box-enter-active,

.box-leave-active {

  transition: all 1s;

}

// 进入之前样式 和 离开之后样式

.box-enter,

.box-leave-to {

  transform: translateX(10px);

  opacity: 0;

}

2. nanoid

安装

npm install nanoid

导入

import { nanoid } from 'nanoid'

使用

this.goodses.push({

    id:nanoid(),

    name:'丰田'

})

3. 服务器

1号服务器

// 导入express

let express = require("express");

// 创建一个服务器对象

let app = express();

// 开启一个端口号

app.listen(5566, () => {

  console.log("服务器成功开启!端口号5566");

});

//配置中间件,拦截所有的请求

app.use((req, res, next) => {

  //允许跨域

  // res.setHeader("Access-Control-Allow-Origin", "*");

  next();

});

//学生数组

let stus = [

  {

    no: "1001",

    name: "张三",

    age: 20,

    sex: "男",

  },

  {

    no: "1002",

    name: "李四",

    age: 22,

    sex: "女",

  },

  {

    no: "1003",

    name: "王五",

    age: 24,

    sex: "男",

  },

]

// 定义一个get请求接口

app.get("/list", (req, res) => {

  res.send(stus);

});

2号服务器

// 导入express

let express = require("express");

// 创建一个服务器对象

let app = express();

// 开启一个端口号

app.listen(7788, () => {

  console.log("服务器成功开启!端口号7788");

});

//配置中间件,拦截所有的请求

app.use((req, res, next) => {

  //允许跨域

  // res.setHeader("Access-Control-Allow-Origin", "*");

  next();

});

//汽车数组

let cars = [

    {

      id: "1001",

      name: "奔驰"

    },

    {

      id: "1002",

      name: "宝马"

    },

    {

      id: "1003",

      name: "奥迪"

    },

  ]

// 定义一个get请求接口

app.get("/list", (req, res) => {

  res.send(cars);

});

4. 配置代理

module.exports = {

    //取消eslint语法检查

    lintOnSave:false,

    //devServer是脚手架中的开发服务器

    devServer:{

        //配置主机名

        host:'localhost',

        //配置端口号

        port:'8080',

        //在开发服务器中,配置一个代理服务器地址。

        //注意:在开发阶段,通过向当前开发服务器发送ajax请求,当前服务器会将请求转发给配置的代理服务器地址。

        // proxy:'http://localhost:5566'

        // 配置多个代理服务器地址

        proxy:{

            // /stu是前缀

            '/stu':{

                //代理的地址

                target:'http://localhost:5566',

                //路径重写,因为向真实的后台发送请求时,不需要加前缀

                pathRewrite:{

                    //将地址中,/stu替换成空

                    '^/stu':''

                }

            },

            '/car':{

                target:'http://localhost:7788',

                pathRewrite:{

                    '^/car':''

                }

            }

        }

    },

}

5. 组件

//数据初始化完成

created(){

    //ajax请求数据,必须要遵循同源策略,什么是同源策略?

    //请求地址的协议名,主机名(域名或ip地址),端口号,必须跟当前地址相同,否则就是跨域请求。

    //解决跨域有两种途径:1.后端允许跨域,2.前端想办法骗过后端实现跨域(jsonp技术,代理服务器技术)

    /* axios.get('http://localhost:5566/list').then(({data})=>{

          this.stuList = data

    }) */

    axios.get('http://localhost:8080/stu/list').then(({data})=>{

        this.stuList = data

    })

    axios.get('http://localhost:8080/car/list').then(({data})=>{

        this.carList = data

    })

}

十一、mockjs

1. 子组件接收父组件传值

//通过props接收父组件传过来的值

props:['name','age','updateHomeAddress'],

mounted() {

    // 父级传过来的数据,子级如果没有用props去接,这些属性会保存到$attrs对象中

    console.log(this.$attrs);

},

data() {

    return {

        myName:this.name,

        myAge:this.age,

        mySex:this.$attrs.sex,

        myAddress:this.$attrs.address

    }

},

methods: {

    //修改地址

    updateAddress(){

        //修改当前组件的地址

        this.myAddress = '北京'

        //调用父级传过来的方法,修改父级的地址

        this.updateHomeAddress('北京')

    }

}

2. mockjs拦截请求

//  mockjs提供了两个功能:1.生成随机数据 2.拦截 Ajax 请求

// 导入mockjs

import Mock from "mockjs";

// 设置请求延迟时间

Mock.setup({

    timeout: 400,

});

// 生成一个数组数据

const { list } = Mock.mock({

  //随机生成一个10到20条的数组

  "list|10-20": [{

    'SubjectId|+1':1,

    'SubjectName':'@ctitle(10,15)',

    'ClassHour':'@integer(33,66)',

    'Grade':{

        'GradeId':'@integer(1,3)',

        'GradeName':'@ctitle(2,4)'

    }

  }],

});

// 拦截查询请求

Mock.mock('http://bingjs.com:81/Subject/GetAll', "get", (options) => {

    console.log(options);

  return list;

});

// 拦截添加请求

Mock.mock('http://bingjs.com:81/Subject/Add', "post", (options) => {

    //获取参数数据

    let obj = JSON.parse(options.body)

    let subject = {

        SubjectId:list.length+1,

        SubjectName:obj.subjectName,

        ClassHour:obj.classHour,

        GradeId:obj.gradeId

    }

    subject.Grade = Mock.mock({

        'GradeId':'@integer(1,3)',

        'GradeName':'@ctitle(2,4)'

    })

    list.push(subject)

    return true

});

Mock.mock('http://bingjs.com:81/Subject/Delete','post',(options)=>{

    //获取参数数据

    let {subjectId} = JSON.parse(options.body)

    let index = list.findIndex(r=>r.SubjectId==subjectId)

    list.splice(index,1)

    return true

})

// 导入mockjs

import './mock/index.js'

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • 1.组件的组成 <temmplata> 2.组件的样式隔离 3.dom元素的获取 定义: 使用:this.$r...
    char1阅读 681评论 0 1
  • 一、概念介绍 Vue.js和React.js分别是目前国内和国外最火的前端框架,框架跟类库/插件不同,框架是一套完...
    刘远舟阅读 1,024评论 0 0
  • 一、Vue3启程 1. 初始Vue3 姓名:{{name}} 年龄:{{age}} 修改数据 /...
    野鸽儿阅读 490评论 0 0
  • vue去哪网跟学笔记 记录学习点滴 1. 初始化项目 1.1 手机显示配适 minimum-scale=1.0,m...
    noobakong阅读 2,221评论 0 16
  • Vue Vue是一个前端js框架,由尤雨溪开发,是个人项目 Vue近几年来特别的受关注,三年前的时候angular...
    hcySam阅读 275评论 0 0