2019年底史上最全Vue框架整理从基础到实战(二)

2019年底史上最全Vue框架整理从基础到实战(二)_第1张图片

单文件组件

在很多Vue项目中,我们使用 Vue.component 来定义全局组件,紧接着用 new Vue({ el: '#app '}) 在每个页面内指定一个容器元素。

这种方式在很多中小规模的项目中运作的很好,在这些项目里 JavaScript 只被用来加强特定的视图。但当在更复杂的项目中,或者你的前端完全由 JavaScript 驱动的时候,下面这些缺点将变得非常明显:

  • 全局定义强制要求每个 component 中的命名不得重复
  • 字符串模板 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的 ``
  • 不支持 CSS 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
  • 没有构建步骤 限制只能使用 HTML 和 ES5 JavaScript, 而不能使用预处理器,如 Pug (formerly Jade) 和 Babel

文件扩展名为 .vuesingle-file components(单文件组件) 为以上所有问题提供了解决方法,并且还可以使用 webpack 或 Browserify 等构建工具。

这是一个文件名为 Hello.vue 的简单实例:

2019年底史上最全Vue框架整理从基础到实战(二)_第2张图片

现在我们获得

  • 完整语法高亮
  • CommonJS 模块
  • 组件作用域的 CSS

在看完上文之后,建议使用官方提供的 Vue CLI 3脚手架来开发工具,只要遵循提示,就能很快地运行一个带有.vue组件,ES2015,webpack和热重载的Vue项目

Vue CLI3

基本配置

  • 安装Nodejs
    • 保证Node.js8.9或更高版本
    • 终端中输入node -v,保证已安装成功
  • 安装淘宝镜像源
    • npm install -g cnpm --registry=https://registry.npm.taobao.org
    • 以后的npm可以用cnpm代替
  • 安装Vue Cli3脚手架
    • cnpm install -g @vue/cli
  • 检查其版本是否正确
    • vue --version

快速原型开发

使用 vue servevue build 命令对单个 *.vue 文件进行快速原型开发,不过这需要先额外安装一个全局的扩展:

npm install -g @vue/cli-service-global

vue serve 的缺点就是它需要安装全局依赖,这使得它在不同机器上的一致性不能得到保证。因此这只适用于快速原型开发。

需要的仅仅是一个 App.vue 文件:



然后在这个 App.vue 文件所在的目录下运行:

vue serve

启动效果:2019年底史上最全Vue框架整理从基础到实战(二)_第3张图片网页效果:2019年底史上最全Vue框架整理从基础到实战(二)_第4张图片

但这种方式仅限于快速原型开发,终归揭底还是使用vue cli3来启动项目

创建项目

vue create mysite

详细的看官网介绍

购物车

App.vue

  • {{item.title}}

    ¥{{item.price}}

cartList: [
    {
        id:1,
        title:'web全栈开发',
        price:1999
    },
    {
        id: 2,
        title: 'python全栈开发',
        price: 2999
    }
],

新建Cart.vue购物车组件



mock数据

简单的mock,使用自带的webpack-dev-server即可,新建vue.config.js扩展webpack设置

webpack官网介绍

module.exports = {
    configureWebpack:{
        devServer:{
            // mock数据模拟
            before(app,server){
                app.get('/api/cartList',(req,res)=>{
                    res.json([
                        {
                            id:1,
                            title:'web全栈开发',
                            price:1999
                        },
                        {
                            id: 2,
                            title: 'web全栈开发',
                            price: 2999
                        }
                    ])
                })
            }
        }
    }
}

访问http://localhost:8080/api/cartList 查看mock数据

使用axios获取接口数据npm install axios -S

created() {
    axios.get('/api/cartList').then(res=>{
        this.cartList = res.data
    })
}

使用ES7的async await语法

async created() {
    // try-catch解决async-awiat错误处理
    try {
        const { data } = await axios.get('/cartList')
        this.cartList = data;

    } catch (error) {
        console.log(error);
    }
},

数据持久化

localstorage vue监听器

如果组件没有明显的父子关系,使用中央事件总线进行传递

Vue每个实例都有订阅/发布模式的额实现,使用$on和$emit

main.js

Vue.prototype.$bus = new Vue();

App.vue

methods: {
    addCart(index) {
        const good = this.cartList[index];
        this.$bus.$emit('addGood',good);
    }

}

Cart.vue

data() {
    return {
        cart:JSON.parse(localStorage.getItem('cart')) || []
    }
},
//数组和对象要深度监听
watch: {
    cart: {
        handler(n, o) {
            const total = n.reduce((total, c) => {
                total  = c.count
                return total;
            }, 0)
            localStorage.setItem('total', total);
            localStorage.setItem('cart', JSON.stringify(n));
            this.$bus.$emit('add', total);
        },
        deep: true
    }
},
created() {
    this.$bus.$on('addGood', good => {
        const ret = this.cart.find(v => v.id === good.id);
        if (ret) { //购物车已有数据
            ret.count  = 1;
        } else {
            //购物车无数据
            this.cart.push({
                ...good,
                count: 1,
                active: true
            })
        }
    })
},

更复杂的数据传递,可以使用vuex,后面课程会详细介绍

组件深入

组件分类

  • 通用组件
    • 基础组件,大部分UI都是这种组件,比如表单 布局 弹窗等
  • 业务组件
    • 与需求挂钩,会被复用,比如抽奖,摇一摇等
  • 页面组件
    • 每个页面都是一个组件v

使用第三方组件

比如vue最流行的element,就是典型的通用组件,执行npm install element-ui安装

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';

Vue.use(ElementUI);

new Vue({
  el: '#app',
  render: h => h(App)
});

在vue-cli中可以使用vue add element 安装

安装之前注意提前提交当前工作内容,脚手架会覆盖若干文件

2019年底史上最全Vue框架整理从基础到实战(二)_第5张图片发现项目发生了变化,打开App.vue,ctrl z撤回

2019年底史上最全Vue框架整理从基础到实战(二)_第6张图片

此时可以在任意组件中使用

官网element-ui的通用组件,基本上都是复制粘贴使用,在这里就不一一赘述,后面项目中用到该库,咱们再一一去使用

关于组件设计,最重要的还是自己去设计组件,现在我们模仿element-ui提供的表单组件,手写实现表单组件m-form

先看一下element-ui的表单

新建FormElement.vue



在App.vue组件中导入该组件,挂载,使用

组件设计

表单组件,组件分层

  1. Form负责定义校验规则
  2. FormtItem负责显示错误信息
  3. Input负责数据双向绑定
  4. 使用provide和inject内部共享数据

2019年底史上最全Vue框架整理从基础到实战(二)_第7张图片表单控件实现双向的数据绑定

Input.vue





FormElement.vue

如果不传type表示默认值,在Input.vue的props中有说明


//数据
data() {
    return {
      ruleForm: {
        name: "",
        pwd: ""
      },
      rules: {
        name: [
          { required: true, message: "请输入名称" },
          { min: 6, max: 10, message: "请输入6~10位用户名" }
        ],
        pwd: [{ require: true, message: "请输入密码" }]
      }
    };
  },

FormItem

  1. 获取当前输入框的规则
  2. 如果输入框和rule不匹配 显示错误信息
  3. Input组件中用户输入内容时,通知FormItem做校验
  4. 使用async-validator做出校验

FormItem.vue






FormElement.vue


    


    

此时网页正常显示,但没有校验规则,添加校验规则

思路:比如对用户名进行校验,用户输入的用户名必须是6~10位

npm i asycn-validator -S

Input.vue

methods: {
    handleInput(e) {
      this.inputVal = e.target.value;
      //....
       //通知父组件校验,将输入框的值实时传进去
      this.$parent.$emit("validate", this.inputVal);
    }
}

FormItem.vue

import schema from "async-validator";
export default {
  name: "FormItem",
  data() {
    return {
      validateStatus: "",
      errorMessage: ""
    };
  },
  methods: {
    validate(value) {//value为当前输入框的值
        // 校验当前项:依赖async-validate
        let descriptor = {};
        descriptor[this.prop] = this.form.rules[this.prop];
        // const descriptor = { [this.prop]: this.form.rules[this.prop] };
        const validator = new schema(descriptor);

        let obj = {};
        obj[this.prop] = value;
        //  let obj = {[this.prop]:this.form.model[this.prop]};
        validator.validate(obj, errors => {
          if (errors) {
            this.validateStatus = "error";
            this.errorMessage = errors[0].message;
          } else {
            this.validateStatus = "";
            this.errorMessage = "";
          }
        });
      
    }
  },
  created() {
    //监听子组件Input的派发的validate事件
    this.$on("validate", this.validate);
  },
  //注入名字 获取父组件Form 此时Form我们还没创建
  inject: ["form"],
  props: {
    label: {
      type: String,
      default: ""
    },
    prop: {
      type: String
    }
  }
};

Form

  1. 声明props中获取数据模型(model)和检验规则(rules)
  2. 当FormItem组件挂载完成时,通知Form组件开始缓存需要校验的表单项
  3. 将缓存的表单项进行统一处理,如果有一个是错误,则返回false.(思路:使用promise.all()进行处理)
  4. 声明校验方法,供父级组件方法调用validate()方法

Form.vue

声明props中获取数据模型(model)和检验规则(rules)




当FormItem组件挂载完成时,通知Form组件开始缓存需要校验的表单项

FormItem.vue

mounted() {
    //挂载到form上时,派发一个添加事件
    //必须做判断,因为Form组件的子组件可能不是FormItem
    if (this.prop) {
        //通知将表单项缓存
        this.$parent.$emit("formItemAdd", this);
    }
}

Form.vue

created () {
    // 缓存需要校验的表单项
    this.fileds = []
    this.$on('formItemAdd',(item)=>{
        this.fileds.push(item);
    })
},

将缓存的表单项进行统一处理,如果有一个是错误,则返回false.(思路:使用Promise.all()进行处理).

注意:因为Promise.all方法的第一个参数是数组对象,该数组对象保存多个promise对象,所以要对FormItem的validate方法进行改造

FormItem.vue

validate() {
    // 校验当前项:依赖async-validate
    return new Promise(resolve => {
        const descriptor = { [this.prop]: this.form.rules[this.prop] };
        const validator = new schema(descriptor);
        validator.validate({[this.prop]:this.form.model[this.prop]}, errors => {
            if (errors) {
                this.validateStatus = "error";
                this.errorMessage = errors[0].message;
                resolve(false);
            } else {
                this.validateStatus = "";
                this.errorMessage = "";
                resolve(true);
            }
        });
    });
    
}

Form.vue

methods: {
    validate(callback) {
        // 获取所有的验证结果统一处理 只要有一个失败就失败,
        // 将formItem的validate方法 验证修改为promise对象,并且保存验证之后的布尔值
        // tasks保存着验证之后的多个promise对象
        const tasks = this.fileds.map(item=>item.validate());
        let ret = true;
        // 统一处理多个promise对象来验证,只要有一个错误,就返回false,
        Promise.all(tasks).then(results=>{
            results.forEach(valid=>{
                if(!valid){
                    ret = false;
                }
            })
            callback(ret);
        }) 
    }
},

测试:


    
        
    
    
        
    
    
        提交       
    

methods:{
    submitForm2(name) {
        this.$refs[name].validate(valid=>{
            console.log(valid);
            if(valid){
                alert('验证成功');
            }else{
                alert('验证失败')
            }
        });
    }
}

最后

还有2件事拜托大家

一:求赞 求收藏 求分享 求留言,让更多的人看到这篇内容

二:欢迎添加我的个人微信

备注“资料”, 300多篇原创技术文章,海量的视频资料即可获得

备注“加群”,我会拉你进技术交流群,群里大牛学霸具在,哪怕您做个潜水鱼也会学到很多东西

2019年底史上最全Vue框架整理从基础到实战(二)_第8张图片

你可能感兴趣的:(2019年底史上最全Vue框架整理从基础到实战(二))