E-COM-NET

  • 首页
  • 在线工具
  • Layui镜像站
  • SUI文档
  • 联系我们
涔溪
涔溪

Vue学习笔记 二

  • vue
  • vue.js
  • 学习
  • 笔记

4、Vue基础扩展

4.1 插槽

  • 组件的最大特性就是复用性,而用好插槽能大大提高组件的可复用能力
  • 在Vue中插槽是很重要的存在,通过插槽,我们可以把父组件中指定的DOM作用到子组件的任意位置,后面我们坐项目用到的组件库比如element-ui,vant-ui都频繁用到的插槽,Vue的插槽主要有匿名插槽,具名插槽,作用域插槽三种,下面我们分别来认识一下他们。
4.1.1 匿名插槽★★★★

故名思义就是没有名字的插槽,只需要在子组件中使用引入即可

我们来看一下案例哈,如何引入插槽的:

<div id="app">
        
        <alert-box>有bug发生alert-box>
        <alert-box>有一个警告alert-box>
        <alert-box>alert-box>
div>
<script type="text/javascript">
        /*
          组件插槽:父组件向子组件传递内容
        */
        Vue.component('alert-box', {
            template: `
            
ERROR: # 当组件渲染的时候,这个 元素将会被替换为“组件标签中嵌套的内容”。 # 插槽内可以包含任何模板代码,包括 HTML 默认内容
`
}); var vm = new Vue({ el: '#app', data: { } });
script>
4.1.2 具名插槽★★★★
  • 具有名字的插槽就是具名插槽
  • 使用 中的 “name” 属性绑定元素,name就是插槽的名字
<div id="app">
        <base-layout>
            
            <p slot='header'>标题信息p>
            <p>主要内容1p>
            <p>主要内容2p>
            <p slot='footer'>底部信息信息p>
        base-layout>

        <base-layout>
            
            <template slot='header'>
                <p>标题信息1p>
                <p>标题信息2p>
            template>
            <p>主要内容1p>
            <p>主要内容2p>
            <template slot='footer'>
                <p>底部信息信息1p>
                <p>底部信息信息2p>
            template>
        base-layout>
div>
<script type="text/javascript">
        /*
          具名插槽
        */
        Vue.component('base-layout', {
            template: `
            
### 1、 使用 中的 "name" 属性绑定元素 指定当前插槽的名字
### 注意点: ### 具名插槽的渲染顺序,完全取决于模板,而不是取决于父组件中元素的顺序
`
}); var vm = new Vue({ el: '#app', data: { } });
script>
4.1.3 作用域插槽★★★★
  • 可以让父组件对子组件的内容进行加工处理
  • 既可以复用子组件的slot,又可以使slot内容不一致
    • 父组件中使用slot-scope绑定一个属性
    • 子组件中给标签绑定一个自定义属性,可以传递子组件的内容
    • 父组件通过slot-scope接受子组件传递过来的值即可
<div id="app">
        
        <fruit-list :list='list'>
            
            <template slot-scope='slotProps'>
                <strong v-if='slotProps.info.id==3' class="current">
                    {{slotProps.info.name}}
                strong>
                <span v-else>{{slotProps.info.name}}span>
            template>
        fruit-list>
div>
<script type="text/javascript">
        /*
          作用域插槽
        */
        Vue.component('fruit-list', {
            props: ['list'],
            template: `
            
  • //3、 在子组件模板中,元素上有一个类似props传递数据给组 件的写法 msg="xxx", //插槽可以提供一个默认内容,如果如果父组件没有为这个插槽提供了内 容,会显示默认的内容。 如果父组件为这个插槽提供了内容,则默认的内容会被替换掉 {{item.name}}
  • `
    }); var vm = new Vue({ el: '#app', data: { list: [{ id: 1, name: 'apple' }, { id: 2, name: 'orange' }, { id: 3, name: 'banana' }] } });
    script>

    4.2 案例讲解-购物车

    前面我们学了组件,我们也知道Vue的核心是组件系统和数据驱动,下面我们来做一个购物车的案例,巩固深化一下我们所学的理论知识

    4.2.1 组件化布局组件拆分★★★★
    • 把静态页面转换为组件化模式
    • 把组件渲染到页面上显示效果如下所示

    代码效果如下:

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
    <style>
            #app {
                width: 600px;
                margin-top: 30px;
            }
            .header {
                width: 100%;
                height: 40px;
                line-height: 40px;
                text-align: center;
                background-color: aquamarine;
            }
    
            .footer {
                width: 100%;
                height: 50px;
                line-height: 50px;
                background-color: azure;
                text-align: right;
            }
    
            .footer>span {
                padding: 0px 15px;
                font-weight: bold;
                font-size: 15px;
                color: brown;
            }
    style>
    

    上面写了点简单的样式,效果如上图所示

    <div id="app" class="container">
        <my-cart>my-cart>
    div>
    <script>
            //1、 把静态页面转换成组件化模式
            //1.1  标题组件 
            var CartTitle = {
                template: `
                    
    我的商品
    `
    } //1.2 商品列表组件 var CartList = { template: `
    `
    } //结算组件 var CartTotal = { template: `
    总价: 100   
    `
    } //定义一个全局组件 my-cart Vue.component("my-cart", { // 引入子组件 template: `
    `
    , //注册子路由组件 components: { 'cart-title': CartTitle, 'cart-list': CartList, 'cart-total': CartTotal } }); new Vue({ el: "#app", data: { }, methods: { } })
    script>
    4.2.2完成标题和结算组件功能 组件传值★★★★
    • 标题组件事件动态渲染
      • 从父组件把标题数据传递过来 即 父向子组件传值
      • 把传递过来的数据渲染到页面上
    • 结算功能组件
      • 从父组件把商品列表list 数据传递过来 即 父向子组件传值
      • 把传递过来的数据计算最终价格渲染到页面上
    <div id="app" class="container">
            <my-cart>my-cart>
    div>
    <script>
            //1、 把静态页面转换成组件化模式
            //1.1  标题组件 
            var CartTitle = {
                props: ['title'],
                template: `
                    
    {{title}}
    `
    } //结算组件,子组件接受值即可 var CartTotal = { props: ['goods_list'], template: `
    总价: {{total}}   
    `
    , computed: { total:function(){ let amounts = 0; this.goods_list.forEach(item=>{ amounts +=item.price*item.num; }) return amounts.toFixed(2); } }, } //定义一个全局组件 my-cart Vue.component("my-cart", { data: function () { return { title: "我的商品", goods_list: [ { id: 1, name: 'TCL彩电', price: 1000, num: 1, img: 'media/day06-a.jpg' }, { id: 2, name: '机顶盒', price: 1000, num: 1, img: 'media/day06-b.jpg' }, { id: 3, name: '海尔冰箱', price: 1000, num: 1, img: 'media/day06-c.jpg' }, { id: 4, name: '小米手机', price: 1000, num: 1, img: 'media/day06-d.jpg' }, { id: 5, name: 'PPTV电视', price: 1000, num: 2, img: 'media/day06-e.jpg' } ] } }, // 引入子组件,父组件向子组件进行传值 template: `
    `
    , //注册子路由组件 components: { 'cart-title': CartTitle, 'cart-list': CartList, 'cart-total': CartTotal } });
    script>
    4.2.3 完成列表组件删除商品功能splice★★★★
    • 从父组件把商品列表list 数据传递过来 即 父向子组件传值
    • 把传递过来的数据渲染到页面上
    • 点击删除按钮的时候删除对应的数据
      • 给按钮添加点击事件把需要删除的id传递过来
        • 子组件中不推荐操作父组件的数据,有可能多个子组件使用父组件的数据,我们需要把数据 传递给父组件让父组件操作数据
        • 父组件删除对应的数据
    <div id="app" class="container">
            <my-cart>my-cart>
    div>
    <script>
            //1、 把静态页面转换成组件化模式
            //1.1  标题组件 
            var CartTitle = {
                props: ['title'],
                template: `
                    
    {{title}}
    `
    } //1.2 商品列表组件 var CartList = { props: ['goods_list'], template: `
    {{item.name}}
    `
    , methods: { del(id) { console.log(id); this.$emit("cart-del", id); } } } //结算组件,子组件接受值即可 var CartTotal = { props: ['goods_list'], template: `
    总价: {{total}}   
    `
    , computed: { total: function () { let amounts = 0; this.goods_list.forEach(item => { amounts += item.price * item.num; }) return amounts.toFixed(2); } }, } //定义一个全局组件 my-cart Vue.component("my-cart", { data: function () { return { title: "我的商品", goods_list: [ { id: 1, name: 'TCL彩电', price: 1000, num: 1, img: 'media/day06-a.jpg' }, { id: 2, name: '机顶盒', price: 1000, num: 1, img: 'media/day06-b.jpg' }, { id: 3, name: '海尔冰箱', price: 1000, num: 1, img: 'media/day06-c.jpg' }, { id: 4, name: '小米手机', price: 1000, num: 1, img: 'media/day06-d.jpg' }, { id: 5, name: 'PPTV电视', price: 1000, num: 2, img: 'media/day06-e.jpg' } ] } }, // 引入子组件,父组件向子组件进行传值 template: `
    `
    , //注册子路由组件 components: { 'cart-title': CartTitle, 'cart-list': CartList, 'cart-total': CartTotal }, methods: { removeGoods(id) { console.log(id) let index = this.goods_list.findIndex(item => { return item.id == id; }); this.goods_list.splice(index, 1); } } }); new Vue({ el: "#app", data: { }, methods: { } })
    script>
    4.2.4 完成列表组件更新商品数量computed★★★★
    • 将输入框中的默认数据动态渲染出来
    • 输入框失去焦点的时候 更改商品的数量
    • 点击按钮+和按钮-更新商品的数量,同步更新总价格
    • 子组件中不推荐操作数据 把这些数据传递给父组件 让父组件处理这些数据
    • 父组件中接收子组件传递过来的数据并处理
    <div id="app" class="container">
            <my-cart>my-cart>
    div>
    <script>
            //1、 把静态页面转换成组件化模式
            //1.1  标题组件 
            var CartTitle = {
                props: ['title'],
                template: `
                    
    {{title}}
    `
    } //1.2 商品列表组件 var CartList = { props: ['goods_list'], template: `
    {{item.name}}
    `
    , methods: { del(id) { console.log(id); this.$emit("cart-del", id); }, changeNums(id, event) { this.$emit("change-num", { id: id, type: 'change', num: event.target.value } ) }, incr(id) { this.$emit('change-num', { id: id, type: 'incr', } ); }, decr(id) { this.$emit('change-num', { id: id, type: 'decr', } ); } } } //结算组件,子组件接受值即可 var CartTotal = { props: ['goods_list'], template: `
    总价: {{total}}   
    `
    , computed: { total: function () { let amounts = 0; this.goods_list.forEach(item => { amounts += item.price * item.num; }) return amounts.toFixed(2); } }, } //定义一个全局组件 my-cart Vue.component("my-cart", { data: function () { return { title: "我的商品", goods_list: [ { id: 1, name: 'TCL彩电', price: 1000, num: 1, img: 'media/day06-a.jpg' }, { id: 2, name: '机顶盒', price: 1000, num: 1, img: 'media/day06-b.jpg' }, { id: 3, name: '海尔冰箱', price: 1000, num: 1, img: 'media/day06-c.jpg' }, { id: 4, name: '小米手机', price: 1000, num: 1, img: 'media/day06-d.jpg' }, { id: 5, name: 'PPTV电视', price: 1000, num: 2, img: 'media/day06-e.jpg' } ] } }, // 引入子组件,父组件向子组件进行传值 template: `
    `
    , //注册子路由组件 components: { 'cart-title': CartTitle, 'cart-list': CartList, 'cart-total': CartTotal }, methods: { removeGoods(id) { console.log(id) let index = this.goods_list.findIndex(item => { return item.id == id; }); this.goods_list.splice(index, 1); }, changeNums(data) { let id = data.id; let index = this.goods_list.findIndex(item => { return item.id == id; }); if (data.type == "change") { this.goods_list[index].num = data.num; } if (data.type == "incr") { this.goods_list[index].num++; } if (data.type == "decr") { this.goods_list[index].num--; } } } });
    script>

    4.3 接口调用方式

    前端要做动态数据渲染,只能通过调用接口的方式来获取服务端的数据,目前常见的方式有ajax,fetch,axios等常见的方式可以获取接口的数据,我们来分别认识一下这些操作方式…

    4.3.1 原生ajax★★★★

    ajax主要是负责是客户端和服务端异步数据通信的工具,原生的ajax对浏览器支持比较好,所以群众基础还是比较广的,我们先来看一下原生的ajax如何实现对接口数据的请求:

    原生的ajax请求数据大致分为如下几个步骤:

    <script>
            let xhr = null;
            //实例化xmlhttprequest对象
            xhr = new XMLHttpRequest();
            //配置要请求的接口地址
            xhr.open("post","url地址",true);
            //设置请求的头部信息,如果是post请求的话
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
            //设置请求后状态发生变化的回调函数
            xhr.onreadystatechange = ()=>{
    
            };
            // 发送请求
            xhr.send();
    script>
    
    4.3.2 jQuery的ajax★★★★

    但是我们大部分时候可能用上面原生的ajax的时候是很少的,我们一般都是用jQuery封装好的Api,这个前提是我们需要先引入jQuery文件,否则提示报错,jQuery的ajax使用步骤大致如下所示

    <script>
            $.ajax({
                url:"",
                data:{
    
                },
                type: "post",
                dataType: "json",
                async: true,
                success(res){
    
                },
                error(){
    
                }
            })
    script>
    
    4.3.3 fetch★★★★
    • Fetch API是新的ajax解决方案 Fetch会返回Promise
    • fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象
    • 基本结构大致如下 fetch(url, options).then()
    <script type="text/javascript">
            /*
              Fetch API 基本用法
                  fetch(url).then()
                 第一个参数请求的路径   
                 Fetch会返回Promise   
                 所以我们可以使用then 拿到请求成功的结果 
            */
            fetch('http://localhost:3000/fdata').then(function (data) {
                // text()方法属于fetchAPI的一部分,
                //它返回一个Promise实例对象,用于获取后台返回的数据
                return data.text();
            }).then(function (data) {
                //   在这个then里面我们能拿到最终的数据  
                console.log(data);
            })
    script>
    
    • fetch支持很多请求的方式如POST,GET,DELETE,UPDATE,PATCH和PUT
      • 默认的是 GET 请求
      • 需要在 options 对象中 指定对应的 method method:请求使用的方法
      • post 和 普通 请求的时候 需要在options 中 设置 请求头 headers 和 body
    <script type="text/javascript">
            /*
                  Fetch API 调用接口传递参数
            */
            //1.1 GET参数传递 - 传统URL  通过url  ? 的形式传参
            fetch('http://localhost:3000/books?id=123', {
                //get 请求可以省略不写 默认的是GET 
                method: 'get'
            }).then(function (data) {
                //它返回一个Promise实例对象,用于获取后台返回的数据
                return data.text();
            }).then(function (data) {
                //在这个then里面我们能拿到最终的数据
                console.log(data)
            });
    
            //1.2  GET参数传递  restful形式的URL  通过 / 的形式传递参数  即  id = 456 和id后台的配置有关
            fetch('http://localhost:3000/books/456', {
                //get 请求可以省略不写 默认的是GET 
                method: 'get'
            }).then(function (data) {
                return data.text();
            }).then(function (data) {
                console.log(data)
            });
    
            //2.1  DELETE请求方式参数传递      删除id  是  id = 789
            fetch('http://localhost:3000/books/789', {
                method: 'delete'
            })
                .then(function (data) {
                    return data.text();
                }).then(function (data) {
                    console.log(data)
                });
    
            //3 POST请求传参
            fetch('http://localhost:3000/books', {
                method: 'post',
                //3.1  传递数据 
                body: 'uname=lisi&pwd=123',
                //3.2  设置请求头 
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            }).then(function (data) {
                return data.text();
            }).then(function (data) {
                console.log(data)
            });
    
            //POST请求传参
            fetch('http://localhost:3000/books', {
                method: 'post',
                body: JSON.stringify({
                    uname: '张三',
                    pwd: '456'
                }),
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(function (data) {
                return data.text();
            }).then(function (data) {
                console.log(data)
            });
    
            //PUT请求传参     修改id 是 123 的
            fetch('http://localhost:3000/books/123', {
                method: 'put',
                body: JSON.stringify({
                    uname: '张三',
                    pwd: '789'
                }),
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(function (data) {
                return data.text();
            }).then(function (data) {
                console.log(data)
            });
    script>
    
    4.3.4 axios★★★★
    • 基于promise用于浏览器和node.js的http客户端
    • 支持浏览器和node.js
    • 支持promise
    • 能拦截请求和响应
    • 自动转换JSON数据
    • 能转换请求和响应数据

    axios基础用法

    • get和 delete请求传递参数
      • 通过传统的url 以 ? 的形式传递参数
      • restful 形式传递参数
      • 通过params 形式传递参数
    • post 和 put 请求传递参数
      • 通过选项传递参数
      • 通过 URLSearchParams 传递参数
    <script type="text/javascript">
            // 1. 发送get 请求
            axios.get('http://localhost:3000/adata').then(function (ret) {
                //  拿到 ret 是一个对象      所有的对象都存在 ret 的data 属性里面
                // 注意data属性是固定的用法,用于获取后台的实际数据
                // console.log(ret.data)
                console.log(ret)
            })
            // 2.  get 请求传递参数
            // 2.1  通过传统的url  以 ? 的形式传递参数
            axios.get('http://localhost:3000/axios?id=123').then(function (ret) {
                console.log(ret.data)
            })
            // 2.2  restful 形式传递参数
            axios.get('http://localhost:3000/axios/123').then(function (ret) {
                console.log(ret.data)
            })
            // 2.3  通过params  形式传递参数
            axios.get('http://localhost:3000/axios', {
                params: {
                    id: 789
                }
            }).then(function (ret) {
                console.log(ret.data)
            })
            //3 axios delete 请求传参     传参的形式和 get 请求一样
            axios.delete('http://localhost:3000/axios', {
                params: {
                    id: 111
                }
            }).then(function (ret) {
                console.log(ret.data)
            })
    
            // 4  axios 的 post 请求
            // 4.1  通过选项传递参数
            axios.post('http://localhost:3000/axios', {
                uname: 'lisi',
                pwd: 123
            }).then(function (ret) {
                console.log(ret.data)
            })
            // 4.2  通过 URLSearchParams  传递参数
            var params = new URLSearchParams();
            params.append('uname', 'zhangsan');
            params.append('pwd', '111');
            axios.post('http://localhost:3000/axios', params).then(function (ret) {
                console.log(ret.data)
            })
    
            //5  axios put 请求传参   和 post 请求一样
            axios.put('http://localhost:3000/axios/123', {
                uname: 'lisi',
                pwd: 123
            }).then(function (ret) {
                console.log(ret.data)
            })
    script>
    

    axios全局配置

    //配置公共的请求头 
    axios.defaults.baseURL = 'https://api.example.com';
    //配置 超时时间
    axios.defaults.timeout = 2500;
    //配置公共的请求头
    axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
    //配置公共的 post 的 Content-Type
    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
    

    axios拦截器
    axios的拦截器分为请求拦截器和响应拦截器:

    • 请求拦截器
      • 请求拦截器的作用是在请求发送前进行一些操作
        • 例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易
    • 响应拦截器
      • 响应拦截器的作用是在接收到响应后进行一些操作
        • 例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页
    <script>
            // 1. 请求拦截器 
            axios.interceptors.request.use(function (config) {
                console.log(config.url)
                // 1.1  任何请求都会经过这一步   在发送请求之前做些什么   
                config.headers.mytoken = 'nihao';
                // 1.2  这里一定要return   否则配置不成功  
                return config;
            }, function (err) {
                //1.3 对请求错误做点什么    
                console.log(err)
            })
            //2. 响应拦截器 
            axios.interceptors.response.use(function (res) {
                //2.1  在接收响应做些什么  
                var data = res.data;
                return data;
            }, function (err) {
                //2.2 对响应错误做点什么  
                console.log(err)
            })
    script>
    

    4.4 异步编程

    4.4.1 异步★★★

    异步和同步是相对的,同步我们一般指的是同时进行,比如张三等李四去吃饭,这个时候李四如果没有去吃饭的话,张三就会一直等着,
    就比如请求服务器数据,如果是同步的话,比如等到服务器返回数据后在执行后续的代码逻辑,但是如果是异步的话,我只需要把请求发送出去,然后继续执行我的代码,这个时候就加入了一个异步线程,当数据返回后在执行对应的逻辑,就形成了异步操作。
    所以同步是阻塞的,异步是非阻塞的。

    代码如下

    function doSomething(){
      return new Promise(function(resolve){
        setTimeout(function(){
          console.log('执行结束');
          let result = 6;
          resolve(result);
        },100);
        console.log("异步操作")
      });
    } 
    doSomething().then(result=>{
      console.log('接收到结果为:'+result);
    });
    

    执行效果如下:

    4.4.2 单线程
    • JavaScript的执行环境是「单线程」
    • 所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任务。这个任务可称为主线程
    • 异步模式可以一起执行多个任务
    4.4.3 常见异步调用★★★

    JS中常见的异步调用有

    • 定时任务
    • ajax
    • 事件函数

    定时任务
    常用到的就是超时函数setTimeout,设置后就会把要执行的代码加入异步队列,然后继续执行后面的代码,等到时间后从异步队列中执行相对应的代码,不会阻塞后面代码的执行。

    ajax
    ajax本身就是为了解决客户端和服务端异步通信而产生的,jQuery中的ajax我们可以通过设置async的属性控制同步或者异步,默认为异步,async为true为异步,否则为同步

    事件函数
    采用事件驱动模式。
    任务的执行不取决代码的顺序,而取决于某一个事件是否发生。
    监听函数有:on,bind,listen,addEventListener,observe

    也就是说只有当事件触发后才会执行对应的代码,函数才会被调用,这样的话就不会阻塞其它代码的执行,但是用的多了,可以会导致页面流程不太流畅…

    5、异步请求数据

    5.1promise

    5.1.1promise解决了什么问题★★★★★
    • 主要解决异步深层嵌套的问题
    • promise 提供了简洁的API 使得异步操作更加容易
    5.1.2基于Promise发送Ajax请求解决回调地狱★★★★★
    <script type="text/javascript">
      /*
         1. Promise基本使用
               我们使用new来构建一个Promise  Promise的构造函数接收一个参数,是函数,并且传入两个参数,resolve,reject, 分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数
        */
      var p = new Promise(function(resolve, reject){
        //2. 这里用于实现异步任务  setTimeout
        setTimeout(function(){
          var flag = false;
          if(flag) {
            //3. 正常情况
            resolve('hello');
          }else{
            //4. 异常情况
            reject('出错了');
          }
        }, 100);
      });
    //  5 Promise实例生成以后,可以用then方法指定resolved状态和reject状态的回调函数 
    //  在then方法中,你也可以直接return数据而不是Promise对象,在后面的then中就可以接收到数据了  
    p.then(function(data){
      console.log(data)
    },function(info){
      console.log(info)
    });
    </script>
    

    5.2promise基本API

    5.2.1.then()★★★★★

    得到异步任务正确的结果

    foo()
      .then(function(data){
      # 得到异步任务正确的结果
      console.log(data)
    },function(data){
      # 获取异常信息
      console.log(data)
    })
    # 成功与否都会执行(不是正式标准) 
      .finally(function(){
        console.log('finished')
      });
    
    5.2.2.catch()★★★★★

    获取异常信息

    foo()
      .then(function(data){
      # 得到异步任务正确的结果
      console.log(data)
    },function(data){
      # 获取异常信息
      console.log(data)
    })
    # 成功与否都会执行(不是正式标准) 
      .finally(function(){
        console.log('finished')
      });
    
    5.2.3.finally()★★★

    成功与否都会执行(不是正式标准)

    foo()
      .then(function(data){
      # 得到异步任务正确的结果
      console.log(data)
    },function(data){
      # 获取异常信息
      console.log(data)
    })
    # 成功与否都会执行(不是正式标准) 
      .finally(function(){
        console.log('finished')
      });
    
    5.2.4静态方法all()★★★

    Promise.all方法接受一个数组作参数,数组中的对象(p1、p2、p3)均为promise实例(如果不是一个promise,该项会被用Promise.resolve`转换为一个promise)。它的状态由这三个promise实例决定

    5.2.5静态方法race()★★★

    Promise.race方法同样接受一个数组作参数。当p1, p2, p3中有一个实例的状态发生改变(变为fulfilled或rejected`),p的状态就跟着改变。并把第一个改变状态的promise的返回值,传给p的回调函数

    /*
          Promise常用API-对象方法
        */
    // console.dir(Promise)
    function queryData(url) {
      return new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 && xhr.status == 200) {
            // 处理正常的情况
            resolve(xhr.responseText);
          }else{
            // 处理异常情况
            reject('服务器错误');
          }
        };
        xhr.open('get', url);
        xhr.send(null);
      });
    }
    
    var p1 = queryData('http://localhost:3000/a1');
    var p2 = queryData('http://localhost:3000/a2');
    var p3 = queryData('http://localhost:3000/a3');
    Promise.all([p1,p2,p3]).then(function(result){
      //   all 中的参数  [p1,p2,p3]   和 返回的结果一 一对应["HELLO TOM", "HELLO JERRY", "HELLO SPIKE"]
      console.log(result) //["HELLO TOM", "HELLO JERRY", "HELLO SPIKE"]
    })
    Promise.race([p1,p2,p3]).then(function(result){
      // 由于p1执行较快,Promise的then()将获得结果'P1'。p2,p3仍在继续执行,但执行结果将被丢弃。
      console.log(result) // "HELLO TOM"
    })
    

    5.3fetch

    5.3.1fetch API 中的HTTP请求★★★★★
    • fetch(url, options).then()
    • HTTP协议,它给我们提供了很多的方法,如POST,GET,DELETE,UPDATE,PATCH和PUT
      • 默认的是 GET 请求
      • 需要在 options 对象中 指定对应的 method method:请求使用的方法
      • post 和 普通 请求的时候 需要在options 中 设置 请求头 headers 和 body
    5.3.2参数传递★★★★★

    ​ Fetch API 调用接口传递参数

    // GET参数传递 - 传统URL  通过url  ? 的形式传参 
    fetch('http://localhost:3000/books?id=123', {
    
    // GET参数传递  restful形式的URL  通过/ 的形式传递参数  即  id = 456 和id后台的配置有关   
    fetch('http://localhost:3000/books/456', {
      // get 请求可以省略不写 默认的是GET 
      method: 'get'
    })
      .then(function(data) {
      return data.text();
    }).then(function(data) {
      console.log(data)
    });
    
    //  DELETE请求方式参数传递      删除id  是  id=789
    fetch('http://localhost:3000/books/789', {
      method: 'delete'
    })
      .then(function(data) {
      return data.text();
    }).then(function(data) {
      console.log(data)
    });
    
    // POST请求传参
    fetch('http://localhost:3000/books', {
      method: 'post',
      //  传递数据 
      body: 'uname=lisi&pwd=123',
      //  设置请求头 
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    })
      .then(function(data) {
      return data.text();
    }).then(function(data) {
      console.log(data)
    });
    
    //POST请求传参
    fetch('http://localhost:3000/books', {
      method: 'post',
      body: JSON.stringify({
        uname: '张三',
        pwd: '456'
      }),
      headers: {
        'Content-Type': 'application/json'
      }
    })
      .then(function(data) {
      return data.text();
    }).then(function(data) {
      console.log(data)
    });
    
    //PUT请求传参     修改id 是 123 的 
    fetch('http://localhost:3000/books/123', {
      method: 'put',
      body: JSON.stringify({
        uname: '张三',
        pwd: '789'
      }),
      headers: {
        'Content-Type': 'application/json'
      }
    })
      .then(function(data) {
      return data.text();
    }).then(function(data) {
      console.log(data)
    });
    
    5.3.3fetchAPI 中响应数据格式★★★★★

    用fetch来获取数据,如果响应正常返回,我们首先看到的是一个response对象,其中包括返回的一堆原始字节,这些字节需要在收到后,需要我们通过调用方法将其转换为相应格式的数据,比如JSON,BLOB或者TEXT等等

    /*
          Fetch响应结果的数据格式
        */
    fetch('http://localhost:3000/json').then(function(data){
      // return data.json();   //  将获取到的数据使用 json 转换对象
      return data.text(); //  //  将获取到的数据 转换成字符串 
    }).then(function(data){
      // console.log(data.uname)
      // console.log(typeof data)
      var obj = JSON.parse(data);
      console.log(obj.uname,obj.age,obj.gender)
    })
    

    5.4Axios

    5.4.1axios基础用法★★★★★
    • 基于promise用于浏览器和node.js的http客户端

    • 支持浏览器和node.js

    • 支持promise

    • 能拦截请求和响应

    • 自动转换JSON数据

    • 能转换请求和响应数据

    • get和 delete请求传递参数

      • 通过传统的url 以 ? 的形式传递参数
      • restful 形式传递参数
      • 通过params 形式传递参数
    • post 和 put 请求传递参数

      • 通过选项传递参数
      • 通过 URLSearchParams 传递参数
    5.4.2传参★★★★★
    1. 发送get 请求

      axios.get('http://localhost:3000/adata').then(function(ret){ 
        // 拿到 ret 是一个对象      所有的对象都存在 ret 的data 属性里面
        // 注意data属性是固定的用法,用于获取后台的实际数据
        // console.log(ret.data)
        console.log(ret)
      })
      
    2. get 请求传递参数

      // 通过传统的url  以 ? 的形式传递参数
      axios.get('http://localhost:3000/axios?id=123').then(function(ret){
        console.log(ret.data)
      })
      // restful 形式传递参数 
      axios.get('http://localhost:3000/axios/123').then(function(ret){
        console.log(ret.data)
      })
      // 通过params  形式传递参数 
      axios.get('http://localhost:3000/axios', {
        params: {
          id: 789
        }
      }).then(function(ret){
        console.log(ret.data)
      })
      
    3. axios delete 请求传参 传参的形式和 get 请求一样

      axios.delete('http://localhost:3000/axios', {
        params: {
          id: 111
        }
      }).then(function(ret){
        console.log(ret.data)
      })
      
    4. axios 的 post 请求

      // 通过选项传递参数
      axios.post('http://localhost:3000/axios', {
        uname: 'lisi',
        pwd: 123
      }).then(function(ret){
        console.log(ret.data)
      })
      // 通过 URLSearchParams  传递参数 
      var params = new URLSearchParams();
      params.append('uname', 'zhangsan');
      params.append('pwd', '111');
      axios.post('http://localhost:3000/axios', params).then(function(ret){
        console.log(ret.data)
      })
      
    5. axios put 请求传参 和 post 请求一样

      axios.put('http://localhost:3000/axios/123', {
        uname: 'lisi',
        pwd: 123
      }).then(function(ret){
        console.log(ret.data)
      })
      
    5.4.3axios 全局配置★★★★★
    配置公共的请求头 
    axios.defaults.baseURL = 'https://api.example.com';
    配置 超时时间
    axios.defaults.timeout = 2500;
    配置公共的请求头
    axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
    配置公共的 post 的 Content-Type
    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
    
    5.4.4axios 拦截器★★★★
    • 请求拦截器

      • 请求拦截器的作用是在请求发送前进行一些操作
        • 例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易
    • 响应拦截器

      • 响应拦截器的作用是在接收到响应后进行一些操作

        • 例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页

        • 请求拦截

          axios.interceptors.request.use(function(config) {
            console.log(config.url)
            // 任何请求都会经过这一步   在发送请求之前做些什么   
            config.headers.mytoken = 'nihao';
            // 这里一定要return   否则配置不成功  
            return config;
          }, function(err){
            // 对请求错误做点什么    
            console.log(err)
          })
          
        • 响应拦截

          axios.interceptors.response.use(function(res) {
            // 在接收响应做些什么  
            var data = res.data;
            return data;
          }, function(err){
            // 对响应错误做点什么  
            console.log(err)
          })
          

    5.5 async await

    5.5.1基本用法★★★★
    • async作为一个关键字放到函数前面
      • 任何一个async函数都会隐式返回一个promise
    • await关键字只能在使用async定义的函数中使用
      • ​ await后面可以直接跟一个 Promise实例对象
      • ​ await函数不能单独使用
    5.5.2处理多个异步请求★★★★
    async function queryData() {
      //  添加await之后 当前的await 返回结果之后才会执行后面的代码   
      var info = await axios.get('async1');
      // 让异步代码看起来、表现起来更像同步代码
      var ret = await axios.get('async2?info=' + info.data);
      return ret.data;
    }
    queryData().then(function(data){
      console.log(data)
    })
    

    5.6案例讲解-图书列表

    5.6.1获取图书列表 axios.get()★★★★
    • 导入axios 用来发送ajax
    • 把获取到的数据渲染到页面上
    <div id="app">
      <div class="grid">
        <table>
          <thead>
            <tr>
              <th>编号th>
              <th>名称th>
              <th>时间th>
              <th>操作th>
            tr>
          thead>
          <tbody>
            
            <tr :key='item.id' v-for='item in books'>
              <td>{{item.id}}td>
              <td>{{item.name}}td>
              <td>{{item.date }}td>
              <td>
                <a href="">修改a>
                <span>|span>
                <a href="">删除a>
              td>
            tr>
          tbody>
        table>
      div>
    div>
    <script type="text/javascript" src="js/vue.js">script>
    // 导入axios   
    <script type="text/javascript" src="js/axios.js">script>
    <script type="text/javascript">
      /*
                 图书管理-添加图书
             */
      //   配置公共的url地址  简化后面的调用方式
      axios.defaults.baseURL = 'http://localhost:3000/';
      axios.interceptors.response.use(function(res) {
        return res.data;
      }, function(error) {
        console.log(error)
      });
    
      var vm = new Vue({
        el: '#app',
        data: {
          flag: false,
          submitFlag: false,
          id: '',
          name: '',
          books: []
        },
        methods: {
          // 定义一个方法 用来发送 ajax 
          //  使用 async  来 让异步的代码  以同步的形式书写 
          queryData: async function() {
            // 调用后台接口获取图书列表数据
            // var ret = await axios.get('books');
            // this.books = ret.data;
            //  发送ajax请求  把拿到的数据放在books 里面   
            this.books = await axios.get('books');
          }
        },
    
        mounted: function() {
          // mounted  里面 DOM已经加载完毕  在这里调用函数  
          this.queryData();
        }
      });
    script>
    
    5.6.2添加图书 axios.post()★★★★
    • 获取用户输入的数据 发送到后台
    • 渲染最新的数据到页面上
    methods: {
      handle: async function(){
        if(this.flag) {
          // 编辑图书
          // 就是根据当前的ID去更新数组中对应的数据
          this.books.some((item) => {
            if(item.id == this.id) {
              item.name = this.name;
              // 完成更新操作之后,需要终止循环
              return true;
            }
          });
          this.flag = false;
        }else{
          //  在前面封装好的 handle 方法中  发送ajax请求  
          //  使用async  和 await 简化操作 需要在 function 前面添加 async   
          var ret = await axios.post('books', {
            name: this.name
          })
          //  根据后台返回的状态码判断是否加载数据 
          if(ret.status == 200) {
            //  调用 queryData 这个方法  渲染最新的数据 
            this.queryData();
          }
        }
        // 清空表单
        this.id = '';
        this.name = '';
      },        
    }         
    
    5.6.3验证图书名字是否存在 axios.post()★★★★
    • 添加图书之前发送请求验证图示是否已经存在
    • 如果不存在 往后台里面添加图书名称
      • 图书存在与否只需要修改submitFlag的值即可
    
    
    watch: {
      name: async function(val) {
        // 验证图书名称是否已经存在
        // var flag = this.books.some(function(item){
        //   return item.name == val;
        // });
        var ret = await axios.get('/books/book/' + this.name);
        if(ret.status == 1) {
          // 图书名称存在
          this.submitFlag = true;
        }else{
          // 图书名称不存在
          this.submitFlag = false;
        }
      }
    },
    
    5.6.4编辑图书 axios.post()★★★★
    • 根据当前书的id 查询需要编辑的书籍
    • 需要根据状态位判断是添加还是编辑
    methods: {
      handle: async function(){
        if(this.flag) {
          // 编辑图书   把用户输入的信息提交到后台
          var ret = await axios.put('books/' + this.id, {
            name: this.name
          });
          if(ret.status == 200){
            //  完成添加后 重新加载列表数据
            this.queryData();
          }
          this.flag = false;
        }else{
          // 添加图书
          var ret = await axios.post('books', {
            name: this.name
          })
          if(ret.status == 200) {
            // 重新加载列表数据
            this.queryData();
          }
        }
        // 清空表单
        this.id = '';
        this.name = '';
      },
        toEdit: async function(id){
          //  flag状态位用于区分编辑和添加操作
          this.flag = true;
          //  根据id查询出对应的图书信息  页面中可以加载出来最新的信息
          // 调用接口发送ajax 请求  
          var ret = await axios.get('books/' + id);
          this.id = ret.id;
          this.name = ret.name;
        },
    
    5.6.5删除图书 axios.get()★★★★

    把需要删除的id书籍 通过参数的形式传递到后台

    deleteBook: async function(id){
      // 删除图书
      var ret = await axios.delete('books/' + id);
      if(ret.status == 200) {
        // 重新加载列表数据
        this.queryData();
      }
    }
    

    6、路由

    6.1 路由概念

    6.1.1 什么是路由★★★★

    路由的本质就是一种对应关系,比如说我们在url地址中输入我们要访问的url地址之后,浏览器要去请求这个url地址对应的资源。

    那么url地址和真实的资源之间就有一种对应的关系,就是路由。

    6.1.2 前端路由和后端路由★★★★
    1. 前端路由和后端路由的实现方式

      • 后端路由是由服务器端进行实现,并完成资源的分发
      • 前端路由是依靠hash值(锚链接)的变化进行实现
    2. 后端路由性能相对前端路由来说较低,所以,我们接下来主要学习的是前端路由

    3. 前端路由基本概念

      • 根据不同的事件来显示不同的页面内容,即事件与事件处理函数之间的对应关系
      • 前端路由主要做的事情就是监听事件并分发执行事件处理函数

    6.2 路由初体验

    6.2.1 前端路由实现★★★★

    前端路由实现原理:

    前端路由是基于hash值的变化进行实现的(比如点击页面中的菜单或者按钮改变URL的hash值,根据hash值的变化来控制组件的切换)
    核心实现依靠一个事件,即监听hash值变化的事件

    核心代码:

    window.onhashchange = function(){
        //location.hash可以获取到最新的hash值
        location.hash
    }
    

    前端路由实现tab栏切换:

    点击每个超链接之后,会进行相应的内容切换,

    核心思路:

    在页面中有一个vue实例对象,vue实例对象中有四个组件,分别是tab栏切换需要显示的组件内容
    在页面中有四个超链接,如下:

    <a href="#/zhuye">主页a> 
    <a href="#/keji">科技a> 
    <a href="#/caijing">财经a>
    <a href="#/yule">娱乐a>
    

    当我们点击这些超链接的时候,就会改变url地址中的hash值,当hash值被改变时,就会触发onhashchange事件
    在触发onhashchange事件的时候,我们根据hash值来让不同的组件进行显示:

    window.onhashchange = function() {
        // 通过 location.hash 获取到最新的 hash 值
        console.log(location.hash);
        switch(location.hash.slice(1)){
            case '/zhuye':
            //通过更改数据comName来指定显示的组件
            //因为  ,组件已经绑定了comName
            vm.comName = 'zhuye'
            break
            case '/keji':
            vm.comName = 'keji'
            break
            case '/caijing':
            vm.comName = 'caijing'
            break
            case '/yule':
            vm.comName = 'yule'
            break
        }
    }
    

    代码演示:

    DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <meta http-equiv="X-UA-Compatible" content="ie=edge" />
            <title>Documenttitle>
            
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js">script>
        head>
        <body>
            
            <div id="app">
                
                <a href="#/zhuye">主页a> 
                <a href="#/keji">科技a> 
                <a href="#/caijing">财经a>
                <a href="#/yule">娱乐a>
                
                
                <component :is="comName">component>
            div>
            <script>
                // #region 定义需要被切换的 4 个组件
                // 主页组件
                const zhuye = {
                    template: '

    主页信息

    '
    } // 科技组件 const keji = { template: '

    科技信息

    '
    } // 财经组件 const caijing = { template: '

    财经信息

    '
    } // 娱乐组件 const yule = { template: '

    娱乐信息

    '
    } // #endregion // #region vue 实例对象 const vm = new Vue({ el: '#app', data: { comName: 'zhuye' }, // 注册私有组件 components: { zhuye, keji, caijing, yule } }) // #endregion // 监听 window 的 onhashchange 事件,根据获取到的最新的 hash 值,切换要显示的组件的名称 window.onhashchange = function() { // 通过 location.hash 获取到最新的 hash 值 console.log(location.hash); switch(location.hash.slice(1)){ case '/zhuye': vm.comName = 'zhuye' break case '/keji': vm.comName = 'keji' break case '/caijing': vm.comName = 'caijing' break case '/yule': vm.comName = 'yule' break } }
    script> body> html>

    6.3 Vue-Router介绍

    它是一个Vue.js官方提供的路由管理器。是一个功能更加强大的前端路由器,推荐使用。
    Vue Router和Vue.js非常契合,可以一起方便的实现SPA(single page web application,单页应用程序)应用程序的开发。
    Vue Router依赖于Vue,所以需要先引入Vue,再引入Vue Router

    6.3.1 有哪些特性★★★★★
    • 支持H5历史模式或者hash模式
    • 支持嵌套路由
    • 支持路由参数
    • 支持编程式路由
    • 支持命名路由
    • 支持路由导航守卫
    • 支持路由过渡动画特效
    • 支持路由懒加载
    • 支持路由滚动行为
    6.3.2 使用步骤★★★★★
    1. 导入js文件

      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js">script>
      <script src="https://unpkg.com/vue-router/dist/vue-router.js">script>
      
    2. 添加路由链接:是路由中提供的标签,默认会被渲染为a标签,to属性默认被渲染为href属性,
      to属性的值会被渲染为#开头的hash地址

      <router-link to="/user">Userrouter-link>
      <router-link to="/login">Loginrouter-link>
      
    3. 添加路由填充位(路由占位符)

      <router-view>router-view>
      
    4. 定义路由组件

      var User = { template:"
      This is User
      "
      } var Login = { template:"
      This is Login
      "
      }
    5. 配置路由规则并创建路由实例

      var myRouter = new VueRouter({
          //routes是路由规则数组
          routes:[
              //每一个路由规则都是一个对象,对象中至少包含path和component两个属性
              //path表示  路由匹配的hash地址,component表示路由规则对应要展示的组件对象
              {path:"/user",component:User},
              {path:"/login",component:Login}
          ]
      })
      
    6. 将路由挂载到Vue实例中

      new Vue({
          el:"#app",
          //通过router属性挂载路由对象
          router:myRouter
      })
      

    完整代码演示:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
        <!-- 导入 vue 文件 -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
    	<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
      </head>
      <body>
        <!-- 被 vm 实例所控制的区域 -->
        <div id="app">
          <router-link to="/user">User</router-link>
          <router-link to="/register">Register</router-link>
          <!-- 路由占位符 -->
          <router-view></router-view>
        </div>
        <script>
          const User = {
            template: '

    User 组件

    '
    } const Register = { template: '

    Register 组件

    '
    } // 创建路由实例对象 const router = new VueRouter({ // 所有的路由规则 routes: [ { path: '/user', component: User }, { path: '/register', component: Register } ] }) // 创建 vm 实例对象 const vm = new Vue({ // 指定控制的区域 el: '#app', data: {}, // 挂载路由实例对象 // router: router router }) </script> </body> </html>
    6.3.3 重定向★★★★

    路由重定向:可以通过路由重定向为页面设置默认展示的组件

    在路由规则中添加一条路由规则即可,如下:

    var myRouter = new VueRouter({
        //routes是路由规则数组
        routes: [
            //path设置为/表示页面最初始的地址 / ,redirect表示要被重定向的新地址,设置为一个路由即可
            { path:"/",redirect:"/user"},
            { path: "/user", component: User },
            { path: "/login", component: Login }
        ]
    })
    

    完整代码演示:

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Documenttitle>
        
        <script src="./lib/vue_2.5.22.js">script>
        <script src="./lib/vue-router_3.0.2.js">script>
      head>
      <body>
        
        <div id="app">
          <router-link to="/user">Userrouter-link>
          <router-link to="/register">Registerrouter-link>
    
          
          <router-view>router-view>
        div>
        <script>
          const User = {
            template: '

    User 组件

    '
    } const Register = { template: '

    Register 组件

    '
    } // 创建路由实例对象 const router = new VueRouter({ // 所有的路由规则 routes: [ { path: '/', redirect: '/user'}, { path: '/user', component: User }, { path: '/register', component: Register } ] }) // 创建 vm 实例对象 const vm = new Vue({ // 指定控制的区域 el: '#app', data: {}, // 挂载路由实例对象 // router: router router })
    script> body> html>

    效果和6.2.2案例效果图一样,区别在与6.2.2需要点击一下User才可以显示User组件;而重定向是打开浏览器后会直接显示User组件

    6.4 嵌套路由

    6.4.1 什么是嵌套路由★★★★
    1. 嵌套路由概念

      当我们进行路由的时候显示的组件中还有新的子级路由链接以及内容。

      嵌套路由最关键的代码在于理解子级路由的概念:

      比如我们有一个/login的路由
      那么/login下面还可以添加子级路由,如:
      /login/account
      /login/phone

    2. 嵌套路由案例

      核心代码:

      // 创建路由实例对象
      const router = new VueRouter({
          // 所有的路由规则
          routes: [
              { path: '/', redirect: '/user'},
              { path: '/user', component: User },
              // children 数组表示子路由规则
              { path: '/register', component: Register, children: [
                  { path: '/register/tab1', component: Tab1 },
                  { path: '/register/tab2', component: Tab2 }
              ] }
          ]
      })
      

      完整代码演示:

      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <meta http-equiv="X-UA-Compatible" content="ie=edge" />
          <title>Document</title>
          <!-- 导入 vue 文件 -->
          <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
      	<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
        </head>
        <body>
          <!-- 被 vm 实例所控制的区域 -->
          <div id="app">
            <router-link to="/user">User</router-link>
            <router-link to="/register">Register</router-link>
            <!-- 路由占位符 -->
            <router-view></router-view>
          </div>
          <script>
            const User = {
              template: '

      User 组件

      '
      } const Register = { template: `

      Register 组件


      tab1 tab2
      ` } const Tab1 = { template: '

      tab1 子组件

      '
      } const Tab2 = { template: '

      tab2 子组件

      '
      } // 创建路由实例对象 const router = new VueRouter({ // 所有的路由规则 routes: [ { path: '/', redirect: '/user'}, { path: '/user', component: User }, // children 数组表示子路由规则 { path: '/register', component: Register, children: [ { path: '/register/tab1', component: Tab1 }, { path: '/register/tab2', component: Tab2 } ] } ] }) // 创建 vm 实例对象 const vm = new Vue({ // 指定控制的区域 el: '#app', data: {}, // 挂载路由实例对象 // router: router router }) </script> </body> </html>

    6.5 动态路由

    6.5.1 什么是动态路由★★★★

    你可以在一个路由中设置多段“路径参数”,对应的值都会设置到$route.params中。

    核心代码演示:

    var User = { template:"
    用户:{{$route.params.id}}
    "
    } var myRouter = new VueRouter({ //routes是路由规则数组 routes: [ //通过/:参数名 的形式传递参数 { path: "/user/:id", component: User }, ] })
    6.5.2 多种实现方式★★★★
    1. 通过$route.params来获取路径参数

      var User = { template:"
      用户:{{$route.params.id}}
      "
      } var myRouter = new VueRouter({ //routes是路由规则数组 routes: [ //通过/:参数名 的形式传递参数 { path: "/user/:id", component: User }, ] })
    2. 通过props来接收参数

      var User = { 
          props:["id"],
          template:"
      用户:{{id}}
      "
      } var myRouter = new VueRouter({ //routes是路由规则数组 routes: [ //通过/:参数名 的形式传递参数 //如果props设置为true,route.params将会被设置为组件属性 { path: "/user/:id", component: User,props:true }, ] })
    3. 我们可以将props设置为对象,那么就直接将对象的数据传递给组件进行使用

      var User = { 
          props:["username","pwd"],
          template:"
      用户:{{username}}---{{pwd}}
      "
      } var myRouter = new VueRouter({ //routes是路由规则数组 routes: [ //通过/:参数名 的形式传递参数 //如果props设置为对象,则传递的是对象中的数据给组件 { path: "/user/:id", component: User,props:{username:"jack",pwd:123} }, ] })
    4. 如果想要获取传递的参数值还想要获取传递的对象数据,那么props应该设置为函数形式

      var User = { 
          props:["username","pwd","id"],
          template:"
      用户:{{id}} -> {{username}}---{{pwd}}
      "
      } var myRouter = new VueRouter({ //routes是路由规则数组 routes: [ //通过/:参数名 的形式传递参数 //如果props设置为函数,则通过函数的第一个参数获取路由对象 //并可以通过路由对象的params属性获取传递的参数 // { path: "/user/:id", component: User,props:(route)=>{ return {username:"jack",pwd:123,id:route.params.id} } }, ] })

    动态路由案例:

    代码演示:

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Documenttitle>
        
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js">script>
    	<script src="https://unpkg.com/vue-router/dist/vue-router.js">script>
      head>
      <body>
        
        <div id="app">
          <router-link to="/user/1">User1router-link>
          <router-link to="/user/2">User2router-link>
          <router-link to="/user/3">User3router-link>
          <router-link to="/register">Registerrouter-link>
          
          <router-view>router-view>
        div>
        <script>
          const User = {
            props: ['id', 'uname', 'age'],
            template: '

    User 组件 -- 用户id为: {{id}} -- 姓名为:{{uname}} -- 年龄为:{{age}}

    '
    } const Register = { template: '

    Register 组件

    '
    } // 创建路由实例对象 const router = new VueRouter({ // 所有的路由规则 routes: [ { path: '/', redirect: '/user' }, { path: '/user/:id', component: User, props: route => ({ uname: 'zs', age: 20, id: route.params.id }) }, { path: '/register', component: Register } ] }) // 创建 vm 实例对象 const vm = new Vue({ // 指定控制的区域 el: '#app', data: {}, // 挂载路由实例对象 // router: router router })
    script> body> html>

    6.6 命名路由

    6.6.1 什么是命名路由★★★

    给路由取别名

    命名路由案例:

    代码演示:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
        <!-- 导入 vue 文件 -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
    	<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
      </head>
      <body>
        <!-- 被 vm 实例所控制的区域 -->
        <div id="app">
          <router-link to="/user/1">User1</router-link>
          <router-link to="/user/2">User2</router-link>
    	  <!-- 添加了别名之后,可以使用别名进行跳转 -->
          <router-link :to="{ name: 'user', params: {id: 3} }">User3</router-link>
          <router-link to="/register">Register</router-link>
          <!-- 路由占位符 -->
          <router-view></router-view>
        </div>
        <script>
          const User = {
            props: ['id', 'uname', 'age'],
            template: '

    User 组件 -- 用户id为: {{id}} -- 姓名为:{{uname}} -- 年龄为:{{age}}

    '
    } const Register = { template: '

    Register 组件

    '
    } // 创建路由实例对象 const router = new VueRouter({ // 所有的路由规则 routes: [ { path: '/', redirect: '/user' }, { // 命名路由: 通过name属性为路由添加一个别名 name: 'user', path: '/user/:id', component: User, props: route => ({ uname: 'zs', age: 20, id: route.params.id }) }, { path: '/register', component: Register } ] }) // 创建 vm 实例对象 const vm = new Vue({ // 指定控制的区域 el: '#app', data: {}, // 挂载路由实例对象 // router: router router }) </script> </body> </html>

    6.7 编程式导航

    6.7.1 导航的方式有几种★★★★
    1. 声明式导航:通过点击链接的方式实现的导航

      <router-link to="/user">User1router-link>
      
    2. 编程式导航:调用js的api方法实现导航

      this.$router.push( { name:'user' } )
      
    6.7.2 编程式导航的实现★★★★
    this.$router.push("hash地址");
    this.$router.push("/login");
    this.$router.push({ name:'user' , params: {id:123} });
    this.$router.push({ path:"/login" });
    this.$router.push({ path:"/login",query:{username:"jack"} });
    this.$router.go( n ); //n为数字,参考history.go
    this.$router.go( -1 );
    

    编程式导航案例:

    代码演示:

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Documenttitle>
        
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js">script>
    	<script src="https://unpkg.com/vue-router/dist/vue-router.js">script>
      head>
      <body>
        
        <div id="app">
          <router-link to="/user/1">User1router-link>
          <router-link to="/user/2">User2router-link>
          <router-link :to="{ name: 'user', params: {id: 3} }">User3router-link>
          <router-link to="/register">Registerrouter-link>
          
          <router-view>router-view>
        div>
        <script>
          const User = {
            props: ['id', 'uname', 'age'],
            template: `

    User 组件 -- 用户id为: {{id}} -- 姓名为:{{uname}} -- 年龄为:{{age}}

    `
    , methods: { goRegister() { // 编程式导航 this.$router.push('/register') } }, } const Register = { template: `

    Register 组件

    `
    , methods: { goBack() { // 编程式导航 this.$router.go(-1) } } } // 创建路由实例对象 const router = new VueRouter({ // 所有的路由规则 routes: [ { path: '/', redirect: '/user' }, { // 命名路由 name: 'user', path: '/user/:id', component: User, props: route => ({ uname: 'zs', age: 20, id: route.params.id }) }, { path: '/register', component: Register } ] }) // 创建 vm 实例对象 const vm = new Vue({ // 指定控制的区域 el: '#app', data: {}, // 挂载路由实例对象 // router: router router })
    script> body> html>

    6.8 案例讲解-后台管理系统开发准备

    6.8.1 案例需求★★★
    • 点击左侧的"用户管理",“权限管理”,“商品管理”,“订单管理”,"系统设置"都会出现对应的组件并展示内容

    • 其中"用户管理"组件展示的效果如上图所示,在用户管理区域中的详情链接也是可以点击的,点击之后将会显示用户详情信息。

    6.8.2 布局方案★★★

    div+css布局实现页面的自适应

    6.8.3 技术选型★★★
    • 路由的基础用法
    • 嵌套路由
    • 路由重定向
    • 路由传参
    • 编程式导航
    6.8.4 开发流程★★★
    1. 静态布局编写
    2. 引入vue,vue-router文件
    3. 抽离组件
    4. 功能实现
    6.8.5 开发思路★★★★
    1. 根据效果图编写布局

    2. 在页面中引入vue,vue-router

      
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js">script>
      <script src="https://unpkg.com/vue-router/dist/vue-router.js">script>
      
    3. 创建Vue实例对象,准备开始编写代码实现功能

      const vm = new Vue({
          el: '#app',
          router
      })
      
    4. 抽离并渲染app根组件

      const App = {
      template: `<div>
          
          <header class="header">后台管理系统header>
          
          <div class="main">
              
              <div class="content left">
                  <ul>
                      <li><a href="#">用户管理a>li>
                      <li><a href="#">权限管理a>li>
                      <li><a href="#">商品管理a>li>
                      <li><a href="#">订单管理a>li>
                      <li><a href="#">系统设置a>li>
                  ul>
              div>
              
              <div class="content right"><div class="main-content"> div>
          div>
          
          <footer class="footer">版权信息footer>
      div>`
      }
      
    5. 将左侧菜单改为路由链接

      
      <div class="content left">
          <ul>
              <li><router-link to="/users">用户管理router-link>li>
              <li><router-link to="/rights">权限管理router-link>li>
              <li><router-link to="/goods">商品管理router-link>li>
              <li><router-link to="/orders">订单管理router-link>li>
              <li><router-link to="/settings">系统设置router-link>li>
          ul>
      div>
      
    6. 创建左侧菜单对应的路由组件

      const Users = {
          template: `

      用户管理区域

      编号姓名年龄操作
      1 张三 20 详情
      `
      } const UserInfo = { props: ['id'], template: `
      用户详情页 --- 用户Id为:{{id}}
      `
      } const Rights = { template: `

      权限管理区域

      `
      } const Goods = { template: `

      商品管理区域

      `
      } const Orders = { template: `

      订单管理区域

      `
      } const Settings = { template: `

      系统设置区域

      `
      }
    7. 在右侧主题区域添加路由占位符

      
      <div class="content right"><div class="main-content">
          <router-view />
      div>
      
    8. 添加子路由规则

      // 创建路由对象
      const router = new VueRouter({
          routes: [
              {
                  path: '/',
                  component: App,
                  children: [
                      { path: '/users', component: Users },
                      { path: '/userinfo/:id', component: UserInfo, props: true },
                      { path: '/rights', component: Rights },
                      { path: '/goods', component: Goods },
                      { path: '/orders', component: Orders },
                      { path: '/settings', component: Settings }
                  ]
              }
          ]
      })
      
    9. 通过路由重定向默认渲染用户组件

      // 创建路由对象
      const router = new VueRouter({
          routes: [
              {
                  path: '/',
                  component: App,
                  redirect: '/users',
                  children: [
                      { path: '/users', component: Users },
                      { path: '/userinfo/:id', component: UserInfo, props: true },
                      { path: '/rights', component: Rights },
                      { path: '/goods', component: Goods },
                      { path: '/orders', component: Orders },
                      { path: '/settings', component: Settings }
                  ]
              }
          ]
      })
      
    10. 渲染用户列表数据

      const Users = {
          data() {
              return {
                  userlist: [
                      { id: 1, name: '张三', age: 10 },
                      { id: 2, name: '李四', age: 20 },
                      { id: 3, name: '王五', age: 30 },
                      { id: 4, name: '赵六', age: 40 }
                  ]
              }
          },
          template: `

      用户管理区域

      编号姓名年龄操作
      {{item.id}} {{item.name}} {{item.age}} 详情
      `
      }
    11. 编程式导航实现路由详情

      const Users = {
          data() {
              return {
                  userlist: [
                      { id: 1, name: '张三', age: 10 },
                      { id: 2, name: '李四', age: 20 },
                      { id: 3, name: '王五', age: 30 },
                      { id: 4, name: '赵六', age: 40 }
                  ]
              }
          },
          methods: {
              goDetail(id) {
                  console.log(id)
                  this.$router.push('/userinfo/' + id)
              }
          },
          template: `

      用户管理区域

      编号姓名年龄操作
      {{item.id}} {{item.name}} {{item.age}} 详情
      `
      }
    12. 实现后退功能

      const UserInfo = {
          props: ['id'],
          template: `
      用户详情页 --- 用户Id为:{{id}}
      `
      , methods: { goback() { // 实现后退功能 this.$router.go(-1) } } }

    6.9 案例讲解-后台管理系统功能实现

    6.9.1 根组件创建 template★★★★★
    const app = {
    template:`<div>
        
        <header class="header">传智后台管理系统header>
        
        <div class="main">
            
            <div class="content left">
                <ul>
                    <li>用户管理li>
                    <li>权限管理li>
                    <li>商品管理li>
                    <li>订单管理li>
                    <li>系统设置li>
                ul>
            div>
            
            <div class="content right">
                <div class="main-content">添加用户表单div>
            div>
        div>
        
        <footer class="footer">版权信息footer>
    div>`
    }
    
    6.9.2 默认显示根组件 routes★★★★★
    const myRouter = new VueRouter({
        routes:[
            {path:"/",component:app}
        ]
    })
    const vm = new Vue({
        el:"#app",
        data:{},
        methods:{},
        router:myRouter
    })
    

    补充:到此为止,基本的js代码都处理完毕了,我们还需要设置一个路由占位符

    <body>
      <div id="app">
        <router-view>router-view>
      div>
    body>
    
    6.9.3 跳转配置 router-link★★★★★
    const app = {
        template:`<div>
            ........
            <div class="main">
                
                <div class="content left">
                    <ul>
                        
                        <li><router-link to="/users">用户管理router-link>li>
                        <li><router-link to="/accesses">权限管理router-link>li>
                        <li><router-link to="/goods">商品管理router-link>li>
                        <li><router-link to="/orders">订单管理router-link>li>
                        <li><router-link to="/systems">系统设置router-link>li>
                    ul>
                div>
                
                <div class="content right">
                    <div class="main-content">
                        
                        <router-view>router-view> 
                    div>
                div>
            div>
            .......
        div>`
    }
    
    6.9.4 用户信息列表 data数据模拟★★★★★

    代码演示:

    userList:[
        {id:1,name:"zs",age:18},
        {id:2,name:"ls",age:19},
        {id:3,name:"wang",age:20},
        {id:4,name:"jack",age:21},
    ]
    
    6.9.5 用户详情 传参★★★★★

    代码演示:

    const Users = {
        data(){
            return {
                userList:[
                    {id:1,name:"zs",age:18},
                    {id:2,name:"ls",age:19},
                    {id:3,name:"wang",age:20},
                    {id:4,name:"jack",age:21},
                ]
            }
        },
        template:`<div>
            <h3>用户管理h3>
            <table>
                <thead>
                    <tr>
                        <th>编号th>
                        <th>姓名th>
                        <th>年龄th>
                        <th>操作th>
                    tr>
                thead>
                <tbody>
                    <tr :key="item.id" v-for="item in userList">
                        <td>{{item.id}}td>
                        <td>{{item.name}}td>
                        <td>{{item.age}}td>
                        <td><a href="javascript:;" @click="goDetail(item.id)">详情a>td>
                    tr>
                tbody>
            table>
        div>`,
        methods:{
            goDetail(id){
                this.$router.push("/userinfo/"+id);
            }
        }
    }
    

    完整代码演示:

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <title>基于vue-router的案例title>
        <style type="text/css">
          html,
          body,
          #app {
            margin: 0;
            padding: 0px;
            height: 100%;
          }
          .header {
            height: 50px;
            background-color: #545c64;
            line-height: 50px;
            text-align: center;
            font-size: 24px;
            color: #fff;
          }
          .footer {
            height: 40px;
            line-height: 40px;
            background-color: #888;
            position: absolute;
            bottom: 0;
            width: 100%;
            text-align: center;
            color: #fff;
          }
          .main {
            display: flex;
            position: absolute;
            top: 50px;
            bottom: 40px;
            width: 100%;
          }
          .content {
            flex: 1;
            text-align: center;
            height: 100%;
          }
          .left {
            flex: 0 0 20%;
            background-color: #545c64;
          }
          .left a {
            color: white;
            text-decoration: none;
          }
          .right {
            margin: 5px;
          }
          .btns {
            width: 100%;
            height: 35px;
            line-height: 35px;
            background-color: #f5f5f5;
            text-align: left;
            padding-left: 10px;
            box-sizing: border-box;
          }
          button {
            height: 30px;
            background-color: #ecf5ff;
            border: 1px solid lightskyblue;
            font-size: 12px;
            padding: 0 20px;
          }
          .main-content {
            margin-top: 10px;
          }
          ul {
            margin: 0;
            padding: 0;
            list-style: none;
          }
          ul li {
            height: 45px;
            line-height: 45px;
            background-color: #a0a0a0;
            color: #fff;
            cursor: pointer;
            border-bottom: 1px solid #fff;
          }
          table {
            width: 100%;
            border-collapse: collapse;
          }
          td,
          th {
            border: 1px solid #eee;
            line-height: 35px;
            font-size: 12px;
          }
          th {
            background-color: #ddd;
          }
        style>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js">script>
    	<script src="https://unpkg.com/vue-router/dist/vue-router.js">script>
      head>
      <body>
        
        <div id="app">
          
          <router-view>router-view>
        div>
        <script>
          // 定义 APP 根组件
          const App = {
            template: `
    后台管理系统
    • 用户管理
    • 权限管理
    • 商品管理
    • 订单管理
    • 系统设置
    版权信息
    `
    } const Users = { data() { return { userlist: [ { id: 1, name: '张三', age: 10 }, { id: 2, name: '李四', age: 20 }, { id: 3, name: '王五', age: 30 }, { id: 4, name: '赵六', age: 40 } ] } }, methods: { goDetail(id) { console.log(id) this.$router.push('/userinfo/' + id) } }, template: `

    用户管理区域

    编号姓名年龄操作
    {{item.id}} {{item.name}} {{item.age}} 详情
    `
    } const UserInfo = { props: ['id'], template: `
    用户详情页 --- 用户Id为:{{id}}
    `
    , methods: { goback() { // 实现后退功能 this.$router.go(-1) } } } const Rights = { template: `

    权限管理区域

    `
    } const Goods = { template: `

    商品管理区域

    `
    } const Orders = { template: `

    订单管理区域

    `
    } const Settings = { template: `

    系统设置区域

    `
    } // 创建路由对象 const router = new VueRouter({ routes: [ { path: '/', component: App, redirect: '/users', children: [ { path: '/users', component: Users }, { path: '/userinfo/:id', component: UserInfo, props: true }, { path: '/rights', component: Rights }, { path: '/goods', component: Goods }, { path: '/orders', component: Orders }, { path: '/settings', component: Settings } ] } ] }) const vm = new Vue({ el: '#app', router })
    script> body> html>

    7、前端工程化

    7.1 模块化分类

    传统开发模式主要有命名冲突和文件依赖的问题。

    模块化是一个语言膨胀的必经之路,它能够帮助开发者拆分和组织代码。

    模块化就是把单独的一个功能封装到一个模块(文件)中,模块之间相互隔离,但是可以通过特定的接口公开内部成员,也可以依赖别的模块。

    模块化开发的好处:方便代码的重用,从而提升开发效率,并且方便后期的维护

    7.1.1 浏览器端的模块化★★★

    浏览器端的模块话我们主要探讨AMD和CMD两种规范

    AMD

    Asynchronous Module Definition,异步模块定义,

    // 定义AMD规范的模块
    define([function() {
      return 模块
    })
    

    AMD规范的被依赖模块是异步加载的,而定义的模块是被当作回调函数来执行的,依赖于require.js模块管理工具库,当然,AMD规范不是采用匿名函数自调用的方式来封装,我们依然可以利用闭包的原理来实现模块的私有成员和公有成员:

    define(['module1', 'module2'], function(m1, m2) {
      let x = 1;
      function add() {
        x += 1;
        return x;
      }
      return { add };
    })
    

    CMD

    CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。AMD 推崇依赖前置,CMD 推崇依赖就近。

    define(function(require, exports, module) {
      //  同步加载模块
      var a = require('./a');
      a.doSomething();
      // 异步加载一个模块,在加载完成时,执行回调
      require.async(['./b'], function(b) {
        b.doSomething();
      });
      // 对外暴露成员
      exports.doSomething = function() {};
    });
    // 使用模块
    seajs.use('path');
    

    CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的。

    因此,在CMD中require函数同步加载模块时没有HTTP请求过程。

    7.1.2 服务器端的模块化★★★
    • 服务器端的模块化规范是使用CommonJS规范:
      • 使用require引入其他模块或者包
      • 使用exports或者module.exports导出模块成员
      • 一个文件就是一个模块,都拥有独立的作用域
    // 文件名:x.js
    let x = 1;
    function add() {
      x += 1;
      return x;
    }
    module.exports.x = x;
    module.exports.add = add;
    

    CommonJS通过require()引入模块依赖,require函数可以引入Node的内置模块、自定义模块和npm等第三方模块。

    // 文件名:main.js
    let xm = require('./x.js');
    console.log(xm.x);  // 1
    console.log(xm.add());  // 2
    console.log(xm.x);   // 1
    

    require函数同步加载了x.js,并且返回了module.exports输出字面量的拷贝值

    7.1.3 ES6模块化★★★
    • ES6模块化规范中定义:
      • 每一个js文件都是独立的模块
      • 导入模块成员使用import关键字
      • 暴露模块成员使用export关键字
    //index.js
    export default {
      username: "liguanh",
      age;18
    }
    
    //导入对象
    import object from "./index"
    console.log(object);
    

    ES6的模块化已经不是规范了,而是JS语言的特性。随着ES6的推出,AMD和CMD也随之成为了历史。ES6模块与模块化规范相比,有两大特点:

    • 模块化规范输出的是一个值的拷贝,ES6 模块输出的是值的引用。
    • 模块化规范是运行时加载,ES6 模块是编译时输出接口。

    小结: 推荐使用ES6模块化,因为AMD,CMD局限使用与浏览器端,而CommonJS在服务器端使用。
    ES6模块化是浏览器端和服务器端通用的规范.

    7.2 nodeJS中安装babel体验ES6模块化

    7.2.1 安装babel★★★★
    • 打开终端或者gitbash窗口,在终端中输入如下命令:

      npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
      
    • 安装完毕之后,再次输入命令安装:

      npm install --save @babel/polyfill
      
    7.2.2 创建babel.config.js★★★★
    • 在项目目录中创建babel.config.js文件。编辑js的代码如下:

      const presets = [
                  ["@babel/env",{
                      targets:{
                          edge:"17",
                          firefox:"60",
                          chrome:"67",
                          safari:"11.1"
                      }
                  }]
              ]
      //暴露模块化的数据
      module.exports = { presets }
      
    7.2.3 创建index.js文件

    在项目目录中创建index.js文件作为入口文件
    在index.js中输入需要执行的js代码,例如:

    for(var i=0;i<10;i++){
      console.log("hello world");
    }
    
    7.2.4 使用npx执行★★★★
    • 打开终端或者gitbash执行如下的命令:

      npx babel-node ./index.js
      

    7.3 设置默认的导入导出

    在实际代码中,我们通过export关键字是能够对外暴露本模块中的变量对象,函数,类的,尽管使用如下方式export向外暴露多个变量对象,后面跟一大括号,变量名与变量名之间用逗号隔开:

    exprot {identifier1,identifier2,...}
    

    但是问题来了,如果我不想写这些变量对象呢?那么可以使用default关键字指定单个变量,函数或者类,但是要格外注意一点就是每个模块只能设置一个默认的导出值。那下面我们来看一下默认导入和导出具体怎么使用。

    7.3.1 默认导出★★★★
    export default {
            成员A,
            成员B,
            .......
        },
    //导出信息如下:
    let num = 100;
    export default{
            num
      }
    
    7.3.2 默认导入★★★★

    导入的话我们需要使用import关键字:

    import 接收名称对象 from "模块标识符",如下:
    import test from "./test.js"
    

    **注意:**在一个模块中,只允许使用export default向外默认暴露一次成员,千万不要写多个export default。
    如果在一个模块中没有向外暴露成员,其他模块引入该模块时将会得到一个空对象

    这里还要注意一点就是:若是使用export default的方式默认导出,此处的sub就不要加{}双大括号,否则就会报错。

    7.4 设置按需导入导出

    7.4.1 按需导出★★★★★
    var name = "随笔川迹";
    var age = 18;
    var weChatPublic = "itclanCoder";
    
    function sub(num1,num2){
      return num1-num2;
    }
    
    export default {
       name,
       age,
       weChatPublic,
       sub
    }
    
    7.4.2 按需导入★★★★★
    import { name,age,weChatPublic,sub} from "./test.js"
    //同时导入默认导出的成员以及按需导入的成员
    import { name,age as uname ,uage } from "./test.js"
    

    注意:一个模块中既可以按需导入也可以默认导入,一个模块中既可以按需导出也可以默认导出

    7.5 直接导入并执行代码

    7.5.1 import★★★★★

    有时候,我们只想单纯执行某个模块中的代码,并不需要得到模块中向外暴露的成员,此时,可以直接导入并执行模块代码。

    // 直接导入并执行模块代码
    import './m2.js'
    
    // 当前文件模块为 m2.js
    // 在当前模块中执行一个 for 循环操作
    for(let i = 0; i < 3; i++) {
    console.log(i)
    }
    

    7.6 webpack

    7.6.1 概念★★★★★

    webpack是一个流行的前端项目构建工具,可以解决目前web开发的困境。
    webpack提供了模块化支持,代码压缩混淆,解决js兼容问题,性能优化等特性,提高了开发效率和项目的可维护性

    7.6.2 webpack基本使用★★★★★

    创建项目目录并初始化

    创建项目,并打开项目所在目录的终端,输入命令:

    npm init -y
    

    创建首页及js文件

    在项目目录中创建index.html页面,并初始化页面结构:在页面中摆放一个ul,ul里面放置几个li
    在项目目录中创建js文件夹,并在文件夹中创建index.js文件

    安装jQuery

    打开项目目录终端,输入命令:

    npm install jQuery -S
    

    导入jQuery

    打开index.js文件,编写代码导入jQuery并实现功能:

    import $ from "jquery";
    $(function() {
      $("li:odd").css("background", "cyan");
      $("li:odd").css("background", "pink");
    });
    

    **注意:**此时项目运行会有错误,因为import $ from “jquery”;这句代码属于ES6的新语法代码,在浏览器中可能会存在兼容性问题
    所以我们需要webpack来帮助我们解决这个问题。

    安装webpack

    • 打开项目目录终端,输入命令:

      npm install webpack webpack-cli -D
      
    • 然后在项目根目录中,创建一个 webpack.config.js 的配置文件用来配置webpack
      在 webpack.config.js 文件中编写代码进行webpack配置,如下:

      module.exports = {
              mode:"development"//可以设置为development(开发模式),production(发布模式)
          }
      

      补充:mode设置的是项目的编译模式。
      如果设置为development则表示项目处于开发阶段,不会进行压缩和混淆,打包速度会快一些
      如果设置为production则表示项目处于上线发布阶段,会进行压缩和混淆,打包速度会慢一些

    • 修改项目中的package.json文件添加运行脚本dev,如下:

      "scripts":{
              "dev":"webpack"
      }
      

      注意:scripts节点下的脚本,可以通过 npm run 运行,如:
      运行终端命令:npm run dev
      将会启动webpack进行项目打包

    • 运行dev命令进行项目打包,并在页面中引入项目打包生成的js文件

      打开项目目录终端,输入命令:
      npm run dev
      等待webpack打包完毕之后,找到默认的dist路径中生成的main.js文件,将其引入到html页面中。
      浏览页面查看效果。

    • 设置webpack的打包入口/出口

      在webpack 4.x中,默认会将src/index.js 作为默认的打包入口js文件
      默认会将dist/main.js 作为默认的打包输出js文件
      如果不想使用默认的入口/出口js文件,我们可以通过改变 webpack.config.js 来设置入口/出口的js文件,如下:

      module.exports = {
              mode:"development",
              //设置入口文件路径
              entry: path.join(__dirname,"./src/xx.js"),
              //设置出口文件
              output:{
                  //设置路径
                  path:path.join(__dirname,"./dist"),
                  //设置文件名
                  filename:"res.js"
              }
      }
      
    • 设置webpack的自动打包

      默认情况下,我们更改入口js文件的代码,需要重新运行命令打包webpack,才能生成出口的js文件
      那么每次都要重新执行命令打包,这是一个非常繁琐的事情,那么,自动打包可以解决这样繁琐的操作。
      实现自动打包功能的步骤如下:

      • 安装自动打包功能的包:webpack-dev-server
        npm install webpack-dev-server -D

      • 修改package.json中的dev指令如下:

        "scripts":{
            "dev":"webpack-dev-server"
         }
        
      • 将引入的js文件路径更改为:

        <script src="/bundle.js"></script>
        
      • 运行npm run dev,进行打包

      • 打开网址查看效果:http://localhost:8080

        **注意:**webpack-dev-server自动打包的输出文件,默认放到了服务器的根目录中.

        补充:
        在自动打包完毕之后,默认打开服务器网页,实现方式就是打开package.json文件,修改dev命令:
        "dev": "webpack-dev-server --open --host 127.0.0.1 --port 9999"

    • 配置html-webpack-plugin

      使用html-webpack-plugin 可以生成一个预览页面。
      因为当我们访问默认的 http://localhost:8080/的时候,看到的是一些文件和文件夹,想要查看我们的页面
      还需要点击文件夹点击文件才能查看,那么我们希望默认就能看到一个页面,而不是看到文件夹或者目录。
      实现默认预览页面功能的步骤如下:

      • 安装默认预览功能的包:html-webpack-plugin

        npm install html-webpack-plugin -D

      • 修改webpack.config.js文件,如下:

         //导入包
         const HtmlWebpackPlugin = require("html-webpack-plugin");
         //创建对象
         const htmlPlugin = new HtmlWebpackPlugin({
         			//设置生成预览页面的模板文件
             template:"./src/index.html",
             //设置生成的预览页面名称
             filename:"index.html"
         })
        
      • 继续修改webpack.config.js文件,添加plugins信息:

        module.exports = {
                        ......
                        plugins:[ htmlPlugin ]
                    }
        
    • webpack中的加载器

      通过loader打包非js模块:默认情况下,webpack只能打包js文件,如果想要打包非js文件,需要调用loader加载器才能打包

      • loader加载器包含:
        • less-loader
        • sass-loader
        • url-loader:打包处理css中与url路径有关的文件
        • babel-loader:处理高级js语法的加载器
        • postcss-loader
        • css-loader,style-loader

      **注意:**指定多个loader时的顺序是固定的,而调用loader的顺序是从后向前进行调用

      • 安装style-loader,css-loader来处理样式文件

        • 安装包
          npm install style-loader css-loader -D

        • 配置规则:更改webpack.config.js的module中的rules数组

          module.exports = {
                  ......
                  plugins:[ htmlPlugin ],
                  module : {
                      rules:[
                          {
                              //test设置需要匹配的文件类型,支持正则
                              test:/\.css$/,
                              //use表示该文件类型需要调用的loader
                              use:['style-loader','css-loader']
                          }
                      ]
                  }
              }
          
      • 安装less,less-loader处理less文件

        • 安装包
          npm install less-loader less -D

        • 配置规则:更改webpack.config.js的module中的rules数组

          module.exports = {
                  ......
                  plugins:[ htmlPlugin ],
                  module : {
                      rules:[
                          {
                              //test设置需要匹配的文件类型,支持正则
                              test:/\.css$/,
                              //use表示该文件类型需要调用的loader
                              use:['style-loader','css-loader']
                          },
                          {
                              test:/\.less$/,
                              use:['style-loader','css-loader','less-loader']
                          }
                      ]
                  }
              }
          
      • 安装sass-loader,node-sass处理less文件

        • 安装包
          npm install sass-loader node-sass -D

        • 配置规则:更改webpack.config.js的module中的rules数组

          module.exports = {
                  ......
                  plugins:[ htmlPlugin ],
                  module : {
                      rules:[
                          {
                              //test设置需要匹配的文件类型,支持正则
                              test:/\.css$/,
                              //use表示该文件类型需要调用的loader
                              use:['style-loader','css-loader']
                          },
                          {
                              test:/\.less$/,
                              use:['style-loader','css-loader','less-loader']
                          },
                          {
                              test:/\.scss$/,
                              use:['style-loader','css-loader','sass-loader']
                          }
                      ]
                  }
              }
          

          补充:安装sass-loader失败时,大部分情况是因为网络原因,详情参考:
          https://segmentfault.com/a/1190000010984731?utm_source=tag-newest

      • 安装post-css自动添加css的兼容性前缀(-ie-,-webkit-)

        • 安装包
          npm install postcss-loader autoprefixer -D

        • 在项目根目录创建并配置postcss.config.js文件

          const autoprefixer = require("autoprefixer");
          module.exports = {
              plugins:[ autoprefixer ]
          }
          
        • 配置规则:更改webpack.config.js的module中的rules数组

          module.exports = {
              ......
              plugins:[ htmlPlugin ],
              module : {
                  rules:[
                      {
                          //test设置需要匹配的文件类型,支持正则
                          test:/\.css$/,
                          //use表示该文件类型需要调用的loader
                          use:['style-loader','css-loader','postcss-loader']
                      },
                      {
                          test:/\.less$/,
                          use:['style-loader','css-loader','less-loader']
                      },
                      {
                          test:/\.scss$/,
                          use:['style-loader','css-loader','sass-loader']
                      }
                  ]
              }
          }
          
      • 打包样式表中的图片以及字体文件
        在样式表css中有时候会设置背景图片和设置字体文件,一样需要loader进行处理
        使用url-loader和file-loader来处理打包图片文件以及字体文件

        • 安装包
          npm install url-loader file-loader -D
        • 配置规则:更改webpack.config.js的module中的rules数组
        module.exports = {
            ......
            plugins:[ htmlPlugin ],
            module : {
                rules:[
                    {
                        //test设置需要匹配的文件类型,支持正则
                        test:/\.css$/,
                        //use表示该文件类型需要调用的loader
                        use:['style-loader','css-loader']
                    },
                    {
                        test:/\.less$/,
                        use:['style-loader','css-loader','less-loader']
                    },
                    {
                        test:/\.scss$/,
                        use:['style-loader','css-loader','sass-loader']
                    },{
                        test:/\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/,
                        //limit用来设置字节数,只有小于limit值的图片,才会转换
                        //为base64图片
                        use:"url-loader?limit=16940"
                    }
                ]
            }
        }
        
      • 打包js文件中的高级语法:在编写js的时候,有时候我们会使用高版本的js语法
        有可能这些高版本的语法不被兼容,我们需要将之打包为兼容性的js代码
        我们需要安装babel系列的包

        • 安装babel转换器
          npm install babel-loader @babel/core @babel/runtime -D

        • 安装babel语法插件包

          ```shell
          

          npm install @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties -D
          ```

        • 在项目根目录创建并配置babel.config.js文件

          module.exports = {
                  presets:["@babel/preset-env"],
                  plugins:[ "@babel/plugin-transform-runtime", "@babel/plugin-proposal-class-properties" ]
              }
          
        • 配置规则:更改webpack.config.js的module中的rules数组

          module.exports = {
              ......
              plugins:[ htmlPlugin ],
              module : {
                  rules:[
                      {
                          //test设置需要匹配的文件类型,支持正则
                          test:/\.css$/,
                          //use表示该文件类型需要调用的loader
                          use:['style-loader','css-loader']
                      },
                      {
                          test:/\.less$/,
                          use:['style-loader','css-loader','less-loader']
                      },
                      {
                          test:/\.scss$/,
                          use:['style-loader','css-loader','sass-loader']
                      },{
                          test:/\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/,
                          //limit用来设置字节数,只有小于limit值的图片,才会转换
                          //为base64图片
                          use:"url-loader?limit=16940"
                      },{
                          test:/\.js$/,
                          use:"babel-loader",
                          //exclude为排除项,意思是不要处理node_modules中的js文件
                          exclude:/node_modules/
                      }
                  ]
              }
          }
          
    7.6.3 webpack中使用Vue★★★★

    上一节我们安装处理了vue单文件组件的加载器,想要让vue单文件组件能够使用,我们必须要安装vue
    并使用vue来引用vue单文件组件。

    • 安装Vue
      npm install vue -S

    • 在index.js中引入vue:import Vue from "vue"

    • 创建Vue实例对象并指定el,最后使用render函数渲染单文件组件

      const vm = new Vue({
              el:"#first",
              render:h=>h(app)
          })
      
    7.6.4 webpack打包发布★★★★

    在项目上线之前,我们需要将整个项目打包并发布。

    • 配置package.json

      "scripts":{
              "dev":"webpack-dev-server",
              "build":"webpack -p"
      }
      
    • 在项目打包之前,可以将dist目录删除,生成全新的dist目录

    7.7 Vue脚手架

    7.7.1 什么是脚手架★★★★★

    Vue脚手架可以快速生成Vue项目基础的架构。

    7.7.2 脚手架的基本使用★★★★★
    • 安装3.x版本的Vue脚手架:
      npm install -g @vue/cli
    • 基于3.x版本的脚手架创建Vue项目:
      • 使用命令创建Vue项目
        • 命令:vue create my-project
        • 选择Manually select features(选择特性以创建项目)
        • 勾选特性可以用空格进行勾选。
        • 是否选用历史模式的路由:n
        • ESLint选择:ESLint + Standard config
        • 何时进行ESLint语法校验:Lint on save
        • babel,postcss等配置文件如何放置:In dedicated config files(单独使用文件进行配置)
        • 是否保存为模板:n
        • 使用哪个工具安装包:npm
    7.7.3 图形化方式创建Vue项目★★★★
    • 命令:vue ui
      在自动打开的创建项目网页中配置项目信息。
    7.7.4 2X旧创建创建旧版Vue项目★★★★
    npm install -g @vue/cli-init
    vue init webpack my-project
    
    7.7.5 脚手架生成的项目结构分析★★★★
    • node_modules:依赖包目录
    • public:静态资源目录
    • src:源码目录
    • src/assets:资源目录
    • src/components:组件目录
    • src/views:视图组件目录
    • src/App.vue:根组件
    • src/main.js:入口js
    • src/router.js:路由js
    • babel.config.js:babel配置文件
    7.7.6 脚手架的自定义配置★★★★
    • 通过 package.json 进行配置 [不推荐使用]

      "vue":{
                  "devServer":{
                      "port":"9990",
                      "open":true
                  }
         }
      
    • 通过单独的配置文件进行配置,创建vue.config.js

      module.exports = {
                  devServer:{
                      port:8888,
                      open:true
                  }
       }
      

    7.8 ElementUI的基本使用

    Element-UI:一套基于2.0的桌面端组件库

    7.8.1 安装★★★★
    npm install element-ui -S
    
    7.8.2 全局引入★★★★
    import ElementUI from "element-ui";
    import "element-ui/lib/theme-chalk/index.css";
    Vue.use(ElementUI)
    
    7.8.3 局部引入★★★★

    借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。

    首先,安装 babel-plugin-component:

    npm install babel-plugin-component -D
    

    然后,将 .babelrc 修改为:

    {
      "presets": [["es2015", { "modules": false }]],
      "plugins": [
        [
          "component",
          {
            "libraryName": "element-ui",
            "styleLibraryName": "theme-chalk"
          }
        ]
      ]
    }
    
    7.8.4 组件使用方法演示★★★★★

    接下来,如果你只希望引入部分组件,比如 Button 和 Select,那么需要在 main.js 中写入以下内容:

    import Vue from 'vue';
    import { Button, Select } from 'element-ui';
    import App from './App.vue';
    
    Vue.component(Button.name, Button);
    Vue.component(Select.name, Select);
    /* 或写为
     * Vue.use(Button)
     * Vue.use(Select)
     */
    
    new Vue({
      el: '#app',
      render: h => h(App)
    });
    
    <el-row>
      <el-col :span="24"><div class="grid-content bg-purple-dark">div>el-col>
    el-row>
    <el-row>
      <el-col :span="12"><div class="grid-content bg-purple">div>el-col>
      <el-col :span="12"><div class="grid-content bg-purple-light">div>el-col>
    el-row>
    <el-row>
      <el-col :span="8"><div class="grid-content bg-purple">div>el-col>
      <el-col :span="8"><div class="grid-content bg-purple-light">div>el-col>
      <el-col :span="8"><div class="grid-content bg-purple">div>el-col>
    el-row>
    

    8、Vuex

    8.1Vuex概述

    8.1.1Vuex概念★★★★

    Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间的数据共享

    使用Vuex管理数据的好处:

    • 能够在vuex中集中管理共享的数据,便于开发和后期进行维护
    • 能够高效的实现组件之间的数据共享,提高开发效率
    • 存储在vuex中的数据是响应式的,当数据发生改变时,页面中的数据也会同步更新
    8.1.2Vuex和组件通信对比★★★★

    使用Vuex来管理数据共享,各组件无需关注组件间的数据通信传输,一切数据的读取和更新都是各组件与Vuex数据仓库间的操作,避免了复杂项目中数据管理混乱的情况发生

    8.1.3Vuex使用场景★★★★★

    涉及到非父子关系的组件,例如兄弟关系、祖孙关系,甚至更远的关系组件之间的联系

    中大型单页应用,考虑如何更好地在组件外部管理状态

    8.2Vuex的基本使用

    8.2.1安装★★★★★
    npm i vuex -s
    
    8.2.2语法★★★★★
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    //挂载Vuex
    Vue.use(Vuex)
    
    //创建VueX对象
    const store = new Vuex.Store({
        state:{
            //存放的键值对就是所要管理的状态
            name:'helloVueX'
        }
    })
    
    export default store
    
    8.2.3Vuex完成计数器案例★★★★★

    打开刚刚创建的vuex项目,找到src目录中的App.vue组件,将代码重新编写如下:

    
    
    
    
    
    

    在components文件夹中创建Addition.vue组件,代码如下:

    
    
    
    
    
    

    在components文件夹中创建Subtraction.vue组件,代码如下:

    
    
    
    
    
    

    最后在项目根目录(与src平级)中创建 .prettierrc 文件,编写代码如下:

    {
        "semi":false,
        "singleQuote":true
    }
    

    8.3Vuex中的核心特性

    8.3.1State★★★★★

    vuex中的数据源,我们需要保存的数据就保存在这里,可以在页面通过 this.$store.state来获取我们定义的数据;

    8.3.2Mutation★★★★★

    mutations是操作state数据的方法的集合,比如对该数据的修改、增加、删除等等。

    8.3.3Action★★★★★

    由于直接在mutation方法中进行异步操作,将会引起数据失效。所以提供了Actions来专门进行异步操作,最终提交mutation方法。

    Actions中的方法有两个默认参数

    • context 上下文(相当于箭头函数中的this)对象
    • payload 挂载参数。
    8.3.4Getter★★★★★

    可以对state中的成员加工后传递给外界

    Getters中的方法有两个默认参数

    • state 当前VueX对象中的状态对象
    • getters 当前getters对象,用于将getters下的其他getter拿来用
    8.3.5Module★★★★

    当项目庞大,状态非常多时,可以采用模块化管理模式。Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

    8.4Vuex案例

    8.4.1初始化案例State★★★★★

    首先使用vue ui初始化一个使用vuex的案例
    然后打开public文件夹,创建一个list.json文件,文件代码如下:

    [
        {
            "id": 0,
            "info": "Racing car sprays burning fuel into crowd.",
            "done": false
        },
        {
            "id": 1,
            "info": "Japanese princess to wed commoner.",
            "done": false
        },
        {
            "id": 2,
            "info": "Australian walks 100km after outback crash.",
            "done": false
        },
        {
            "id": 3,
            "info": "Man charged over missing wedding girl.",
            "done": false
        },
        {
            "id": 4,
            "info": "Los Angeles battles huge wildfires.",
            "done": false
        }
    ]
    

    再接着,打开main.js,添加store.js的引入,如下:

    import Vue from 'vue'
    import App from './App.vue'
    import store from './store.js'
    
    // 1. 导入 ant-design-vue 组件库
    import Antd from 'ant-design-vue'
    // 2. 导入组件库的样式表
    import 'ant-design-vue/dist/antd.css'
    
    Vue.config.productionTip = false
    // 3. 安装组件库
    Vue.use(Antd)
    
    new Vue({
      store,
      render: h => h(App)
    }).$mount('#app')
    

    再接着打开store.js,添加axios请求json文件获取数据的代码,如下:

    import Vue from 'vue'
    import Vuex from 'vuex'
    import axios from 'axios'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        //所有任务列表
        list: [],
        //文本输入框中的值
        inputValue: 'AAA'
      },
      mutations: {
        initList(state, list) {
          state.list = list
        },
        setInputValue(state,value){
          state.inputValue = value
        }
      },
      actions: {
        getList(context) {
          axios.get('/list.json').then(({ data }) => {
            console.log(data);
            context.commit('initList', data)
          })
        }
      }
    })
    

    最后,代开App.vue文件,将store中的数据获取并展示:

    
    
    
    
    
    
    8.4.2完成添加事项Mutation★★★★★

    首先,打开App.vue文件,给“添加事项”按钮绑定点击事件,编写处理函数

    //绑定事件
    添加事项
    
    //编写事件处理函数
    methods:{
        ......
        addItemToList(){
          //向列表中新增事项
          if(this.inputValue.trim().length <= 0){
            return this.$message.warning('文本框内容不能为空')
          }
    
          this.$store.commit('addItem')
        }
      }
    

    然后打开store.js编写addItem

    export default new Vuex.Store({
      state: {
        //所有任务列表
        list: [],
        //文本输入框中的值
        inputValue: 'AAA',
        //下一个id
        nextId:5
      },
      mutations: {
        ........
        //添加列表项
        addItem(state){
          const obj = {
            id :state.nextId,
            info: state.inputValue.trim(),
            done:false
          }
          //将创建好的事项添加到数组list中
          state.list.push(obj)
          //将nextId值自增
          state.nextId++
          state.inputValue = ''
        }
      }
      ......
    })
    
    8.4.3完成删除事项Mutation★★★★★

    首先,打开App.vue文件,给“删除”按钮绑定点击事件,编写处理函数

    //绑定事件
    删除
    
    //编写事件处理函数
    methods:{
        ......
        removeItemById(id){
          //根据id删除事项
          this.$store.commit('removeItem',id)
        }
      }
    

    然后打开store.js编写addItem

    export default new Vuex.Store({
      ......
      mutations: {
        ........
        removeItem(state,id){
          //根据id删除事项数据
          const index = state.list.findIndex( x => x.id === id )
          // console.log(index);
          if(index != -1) state.list.splice(index,1);
        }
      }
      ......
    })
    
    8.4.4完成选中状态的改变Action★★★★★

    首先,打开App.vue文件,给“复选”按钮绑定点击事件,编写处理函数

    //绑定事件
    {{item.info}}
    
    //编写事件处理函数
    methods:{
        ......
        cbStateChanged(id,e){
          //复选框状态改变时触发
          const param = {
            id:id,
            status:e.target.checked
          }
    
          //根据id更改事项状态
          this.$store.commit('changeStatus',param)
        }
      }
    

    然后打开store.js编写addItem

    export default new Vuex.Store({
      ......
      mutations: {
        ........
        changeStatus(state,param){
          //根据id改变对应事项的状态
          const index = state.list.findIndex( x => x.id === param.id )
          if(index != -1) state.list[index].done = param.status
        }
      }
      ......
    })
    
    8.4.5剩余项统计Getter★★★★★

    打开store.js,添加getters完成剩余项统计

    getters:{
      unDoneLength(state){
        const temp = state.list.filter( x => x.done === false )
        console.log(temp)
        return temp.length
      }
    }
    

    打开App.vue,使用getters展示剩余项

    //使用映射好的计算属性展示剩余项

    {{unDoneLength}}条剩余
    
    //导入getters
    import { mapState,mapGetters } from 'vuex'
    //映射
    computed:{
      ...mapState(['list','inputValue']),
      ...mapGetters(['unDoneLength'])
    }
    
    8.4.6清除完成事项Mutation★★★★★

    首先,打开App.vue文件,给“清除已完成”按钮绑定点击事件,编写处理函数

    
    清除已完成
    
    //编写事件处理函数
    methods:{
      ......
      clean(){
        //清除已经完成的事项
        this.$store.commit('cleanDone')
      }
    }
    

    然后打开store.js编写addItem

    export default new Vuex.Store({
      ......
      mutations: {
        ........
        cleanDone(state){
          state.list = state.list.filter( x => x.done === false )
        }
      }
      ......
    })
    
    8.4.7点击选项卡切换事项Getter★★★★★

    打开App.vue,给“全部”,“未完成”,“已完成”三个选项卡绑定点击事件,编写处理函数
    并将列表数据来源更改为一个getters。

    
      ......
      
      
        全部
        未完成
        已完成
      
      ......
    
    
    //编写事件处理函数以及映射计算属性
    methods:{
      ......
      changeList( key ){
        //点击“全部”,“已完成”,“未完成”时触发
        this.$store.commit('changeKey',key)
      }
    },
    computed:{
      ...mapState(['list','inputValue','viewKey']),
      ...mapGetters(['unDoneLength','infoList'])
    }
    

    打开store.js,添加getters,mutations,state

    export default new Vuex.Store({
      state: {
        ......
        //保存默认的选项卡值
        viewKey:'all'
      },
      mutations: {
        ......
        changeKey(state,key){
          //当用户点击“全部”,“已完成”,“未完成”选项卡时触发
          state.viewKey = key
        }
      },
      ......
      getters:{
        .......
        infoList(state){
          if(state.viewKey === 'all'){
            return state.list
          }
          if(state.viewKey === 'undone'){
            return state.list.filter( x => x.done === false )
          }
          if(state.viewKey === 'done'){
            return state.list.filter( x => x.done === true )
          }
        }
      }
    })
    

    你可能感兴趣的:(vue,vue.js,学习,笔记)

    • 系统学习Python——并发模型和异步编程:进程、线程和GIL
      分类目录:《系统学习Python》总目录在文章《并发模型和异步编程:基础知识》我们简单介绍了Python中的进程、线程和协程。本文就着重介绍Python中的进程、线程和GIL的关系。Python解释器的每个实例都是一个进程。使用multiprocessing或concurrent.futures库可以启动额外的Python进程。Python的subprocess库用于启动运行外部程序(不管使用何种
    • C++ 11 Lambda表达式和min_element()与max_element()的使用_c++ lamda函数 min_element((1) 2401_84976182 程序员c语言c++学习
      既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上CC++开发知识点,真正体系化!由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新如果你需要这些资料,可以戳这里获取#include#include#includeusingnamespacestd;boolcmp(int
    • C++ 11 Lambda表达式和min_element()与max_element()的使用_c++ lamda函数 min_element(
      网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。需要这份系统化的资料的朋友,可以添加戳这里获取一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!intmain(){vectormyvec{3,
    • 冒泡、选择、插入排序:三大基础排序算法深度解析(C语言实现) xienda 算法排序算法数据结构
      在算法学习道路上,排序算法是每位程序员必须掌握的基石。本文将深入解析冒泡排序、选择排序和插入排序这三种基础排序算法,通过C语言代码实现和对比分析,帮助读者彻底理解它们的差异与应用场景。算法原理与代码实现1.冒泡排序(BubbleSort)工作原理:通过重复比较相邻元素,将较大元素逐步"冒泡"到数组末尾。voidbubbleSort(intarr[],intn){  for(inti=0;iarr[
    • 精通Canvas:15款时钟特效代码实现指南 烟幕缭绕
      本文还有配套的精品资源,点击获取简介:HTML5的Canvas是一个用于绘制矢量图形的API,通过JavaScript实现动态效果。本项目集合了15种不同的时钟特效代码,帮助开发者通过学习绘制圆形、线条、时间更新、旋转、颜色样式设置及动画效果等概念,深化对Canvas的理解和应用。项目中的CSS文件负责时钟的样式设定,而JS文件则包含实现各种特效的逻辑,通过不同的函数或类处理时间更新和动画绘制,提
    • 高效批量单词翻译工具的设计与应用
      本文还有配套的精品资源,点击获取简介:在信息技术飞速发展的今天,批量单词翻译工具通过计算机的数据处理能力,大大提高了语言学习和文字处理的效率。用户通过简单输入单词列表到一个文本文件,并运行翻译程序,即可获得翻译结果并保存至指定文件。该工具集成了内置或外部翻译引擎,利用自然语言处理技术实现快速准确的翻译,并可能提供词性识别等附加功能。尽管机器翻译无法完全取代人工校对,但它为用户提供了一种高效的翻译解
    • FPGA小白到项目实战:Verilog+Vivado全流程通关指南(附光学类岗位技能映射) 阿牛的药铺 算法移植部署fpga开发verilog
      FPGA小白到项目实战:Verilog+Vivado全流程通关指南(附光学类岗位技能映射)引言:为什么这个FPGA入门路线能帮你快速上岗?本文设计了一条**"Verilog语法→工具链操作→光学项目实战→岗位技能对标"的阶梯式学习路径。不同于泛泛而谈的FPGA教程,我们聚焦光学类产品开发**核心能力(时序接口设计、图像处理算法移植、高速接口应用),通过3个递进式项目(从LED闪烁到图像边缘检测),
    • PyTorch & TensorFlow速成复习:从基础语法到模型部署实战(附FPGA移植衔接) 阿牛的药铺 算法移植部署pytorchtensorflowfpga开发
      PyTorch&TensorFlow速成复习:从基础语法到模型部署实战(附FPGA移植衔接)引言:为什么算法移植工程师必须掌握框架基础?针对光学类产品算法FPGA移植岗位需求(如可见光/红外图像处理),深度学习框架是算法落地的"桥梁"——既要用PyTorch/TensorFlow验证算法可行性,又要将训练好的模型(如CNN、目标检测)转换为FPGA可部署的格式(ONNX、TFLite)。本文采用"
    • 基于链家网的二手房数据采集清洗与可视化分析 Mint_Datazzh 项目selenium网络爬虫
      个人学习内容笔记,仅供参考。项目链接:https://gitee.com/rongwu651/lianjia原文链接:基于链家网的二手房数据采集清洗与可视化分析–笔墨云烟研究内容该课题的主要目的是通过将二手房网站上的存量与已销售房源,构建一个二手房市场行情情况与房源特点的可视化平台。该平台通过HTML架构和Echarts完成可视化的搭建。因此,该课题的主要研究内容就是如何利用相关技术设计并实现这样
    • 算法学习笔记:17.蒙特卡洛算法 ——从原理到实战,涵盖 LeetCode 与考研 408 例题
      在计算机科学和数学领域,蒙特卡洛算法(MonteCarloAlgorithm)以其独特的随机抽样思想,成为解决复杂问题的有力工具。从圆周率的计算到金融风险评估,从物理模拟到人工智能,蒙特卡洛算法都发挥着不可替代的作用。本文将深入剖析蒙特卡洛算法的思想、解题思路,结合实际应用场景与Java代码实现,并融入考研408的相关考点,穿插图片辅助理解,帮助你全面掌握这一重要算法。蒙特卡洛算法的基本概念蒙特卡
    • 分布式学习笔记_04_复制模型 NzuCRAS 分布式学习笔记架构后端
      常见复制模型使用复制的目的在分布式系统中,数据通常需要被分布在多台机器上,主要为了达到:拓展性:数据量因读写负载巨大,一台机器无法承载,数据分散在多台机器上仍然可以有效地进行负载均衡,达到灵活的横向拓展高容错&高可用:在分布式系统中单机故障是常态,在单机故障的情况下希望整体系统仍然能够正常工作,这时候就需要数据在多台机器上做冗余,在遇到单机故障时能够让其他机器接管统一的用户体验:如果系统客户端分布
    • 算法学习笔记:15.二分查找 ——从原理到实战,涵盖 LeetCode 与考研 408 例题 呆呆企鹅仔 算法学习算法学习笔记考研二分查找
      在计算机科学的查找算法中,二分查找以其高效性占据着重要地位。它利用数据的有序性,通过不断缩小查找范围,将原本需要线性时间的查找过程优化为对数时间,成为处理大规模有序数据查找问题的首选算法。二分查找的基本概念二分查找(BinarySearch),又称折半查找,是一种在有序数据集合中查找特定元素的高效算法。其核心原理是:通过不断将查找范围减半,快速定位目标元素。与线性查找逐个遍历元素不同,二分查找依赖
    • vue keep-alive标签的运用
      keep-alive,想必大家都不会很陌生,在一些选项卡中会使用到。其实,它的作用大概就是把组件的数据给缓存起来。比如果我有一个选项卡,标签一,标签二,标签三。现在,我需要实现,当我在标签一的表单中输入内容后,点击标签二,再回到标签一,表单的内容依然存在。如果按以往的做法,不使用keep-alive,那是不能实现的。然而,我们只需要在选项卡的内容最外层包一个keep-alive标签即可。但这儿有一
    • Vue3+Vite+TS+Axios整合详细教程 老马聊技术 VueViteTSvue.js
      1.Vite简介Vite是新一代的前端构建工具,在尤雨溪开发Vue3.0的时候诞生。类似于Webpack+Webpack-dev-server。其主要利用浏览器ESM特性导入组织代码,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用。生产中利用Rollup作为打包工具,号称下一代的前端构建工具。vite是一种新型的前端构建工具,能够显著的提升前端开发者的体验。它主要有俩部分组成:一个
    • 本地包解决npm error code E404 雅痞yuppie npm前端node.js
      这个错误提示表明npm找不到名为create-vue-admin-cli的包。这是因为你开发的CLI工具还没有发布到npm官方注册表。要解决这个问题,有两种方法:方法一:使用本地开发模式测试1.确保你的CLI已正确链接到全局在你的vue-admin-cli项目根目录下执行:npmlink这会在全局环境中创建一个符号链接,指向你本地的CLI项目。2.使用本地链接的CLI创建项目直接使用命令:vue-
    • OpenWebUI(12)源码学习-后端constants.py常量定义文件 青苔猿猿 AI大模型openwebuiconstants常量定义
      目录文件名:`constants.py`功能概述:主要功能点详解1.**MESSAGES枚举类**2.**WEBHOOK_MESSAGES枚举类**3.**ERROR_MESSAGES枚举类**✅默认错误模板✅认证与用户相关错误✅资源冲突与重复错误✅验证失败类错误✅权限限制类错误✅文件上传与格式错误✅模型与API错误✅请求频率与安全限制✅数据库与配置错误4.**TASKS枚举类**✅总结实际应用场
    • RocketMQ 基础教程-应用篇-死信队列 码炫课堂-码哥 rocketmq专题rocketmqjava
      作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬学习必须往深处挖,挖的越深,基础越扎实!阶段1、深入多线程阶段2、深入多线程设计模式阶段3、深入juc源码解析阶段4、深入jdk其余源码解析
    • 入门html这篇文章就够了 ξ流ぁ星ぷ132 html前端
      HTML笔记文章目录HTML笔记html介绍什么是htmlhtml的作用HTML标签介绍常用标签标签and标签and标签u标签del删除线br标签用于换行pre标签,预处理标签span标签div标签sub标签andsup标签hr标签h1,h2...h6标签:HTML5中的语义标签:特殊字符img标签a标签第一种用法:超链接第二种用法:锚点video标签表格标签:form标签input标签selec
    • OKHttp3源码分析——学习笔记 Sincerity_ 源码相关Okhttp源码解析读书笔记httpclientcache
      文章目录1.HttpClient与HttpUrlConnection的区别2.OKHttp源码分析使用步骤:dispatcher任务调度器,(后面有详细说明)Request请求RealCallAsyncCall3.OKHttp架构分析1.异步请求线程池,Dispather2.连接池清理线程池-ConnectionPool3.缓存整理线程池DisLruCache4.Http2异步事务线程池,http
    • JavaScript 基础09:Web APIs——日期对象、DOM节点 梦想当全栈 JavaScriptjavascript前端开发语言
      JavaScript基础09:WebAPIs——日期对象、DOM节点进一步学习DOM相关知识,实现可交互的网页特效能够插入、删除和替换元素节点。能够依据元素节点关系查找节点。一、日期对象掌握Date日期对象的使用,动态获取当前计算机的时间。ECMAScript中内置了获取系统时间的对象Date,使用Date时与之前学习的内置对象console和Math不同,它需要借助new关键字才能使用。1.实例
    • 【AI大模型学习路线】第三阶段之RAG与LangChain——第十六章(Advanced RAG[1])基于历史对话重新生成Query? 985小水博一枚呀 AI大模型学习路线人工智能学习langchainRAG
      【AI大模型学习路线】第三阶段之RAG与LangChain——第十六章(AdvancedRAG[1])基于历史对话重新生成Query?【AI大模型学习路线】第三阶段之RAG与LangChain——第十六章(AdvancedRAG[1])基于历史对话重新生成Query?文章目录【AI大模型学习路线】第三阶段之RAG与LangChain——第十六章(AdvancedRAG[1])基于历史对话重新生成Q
    • 【AI大模型学习路线】第三阶段之RAG与LangChain——第十六章(Advanced RAG[1])其他Query优化相关策略? 985小水博一枚呀 AI大模型学习路线人工智能学习langchain
      【AI大模型学习路线】第三阶段之RAG与LangChain——第十六章(AdvancedRAG[1])其他Query优化相关策略?【AI大模型学习路线】第三阶段之RAG与LangChain——第十六章(AdvancedRAG[1])其他Query优化相关策略?文章目录【AI大模型学习路线】第三阶段之RAG与LangChain——第十六章(AdvancedRAG[1])其他Query优化相关策略?一
    • 传奇修改map地图教程_传奇技能第三祭:NPC的增加、隐藏和脚本修改 垃圾箱博物馆 传奇修改map地图教程
      技能献祭,Get新技能:传奇技能——NPC功能与实现跟航家学技能,用干货带你飞,现学现用,底部有配套学习资源本篇内容简介:通过对游戏内NPC的控制,可以让NPC出现在地图中的任意位置,还可以控制外观显示、自定义命名,新增与隐藏以及脚本功能的实现。一、NPC总控制文本所在路径:D:MirServerMir200EnvirEnvir目录下,找到NPC总控制文本:Merchant,游戏内的所有NPC都在
    • LangChain中的向量数据库接口-Weaviate 洪城叮当 langchain数据库经验分享笔记交互人工智能知识图谱
      文章目录前言一、原型定义二、代码解析1、add_texts方法1.1、应用样例2、from_texts方法2.1、应用样例3、similarity_search方法3.1、应用样例三、项目应用1、安装依赖2、引入依赖3、创建对象4、添加数据5、查询数据总结前言  Weaviate是一个开源的向量数据库,支持存储来自各类机器学习模型的数据对象和向量嵌入,并能无缝扩展至数十亿数据对象。它提供存储文档嵌
    • [Vue warn]: onUnmounted is called when there is no active component instance to be associated with 扬帆起航&d vue.jsjavascript前端ecmascript前端框架
      [Vuewarn]:onUnmountediscalledwhenthereisnoactivecomponentinstancetobeassociatedwith.LifecycleinjectionAPIscanonlybeusedduringexecutionofsetup().Ifyouareusingasyncsetup(),makesuretoregisterlifecyclehoo
    • 深度学习模型表征提取全解析 ZhangJiQun&MXP 教学2024大模型以及算力2021AIpython深度学习人工智能pythonembedding语言模型
      模型内部进行表征提取的方法在自然语言处理(NLP)中,“表征(Representation)”指将文本(词、短语、句子、文档等)转化为计算机可理解的数值形式(如向量、矩阵),核心目标是捕捉语言的语义、语法、上下文依赖等信息。自然语言表征技术可按“静态/动态”“有无上下文”“是否融入知识”等维度划分一、传统静态表征(无上下文,词级为主)这类方法为每个词分配固定向量,不考虑其在具体语境中的含义(无法解
    • Vue3组件库实战: 打造高复用UI系统 武昌库里写JAVA 面试题汇总与解析课程设计springbootvue.jslayui毕业设计
      Vue3组件库实战:打造高复用UI系统介绍什么是Vue3组件库在前端开发中,UI组件库是非常重要的一部分。Vue3组件库是基于Vue.js3.x版本开发的一套可用于构建Web应用的UI组件集合,可以帮助开发者快速搭建页面并保证页面的一致性和美观性。目标关键词:Vue3组件库设计与构建设计原则组件库的设计需要遵循一定的原则,比如易用性、可维护性、扩展性等。在设计阶段需要考虑到不同场景的使用,并且保证
    • Ubuntu基础(Python虚拟环境和Vue) aaiier ubuntupythonlinux
      Python虚拟环境sudoaptinstallpython3python3-venv进入项目目录cdXXX创建虚拟环境python3-mvenvvenv激活虚拟环境sourcevenv/bin/activate退出虚拟环境deactivateVue安装Node.js和npm#安装Node.js和npm(Ubuntu默认仓库可能版本较旧,适合入门)sudoaptinstallnodejsnpm#验
    • AI Agent开发学习系列 - langchain之Chains的使用(7):用四种处理文档的预制链轻松实现文档对话 alex100 AIAgent学习人工智能langchainprompt语言模型python
      在LangChain中,四种文档处理预制链(stuff、refine、mapreduce、mapre-rank)是实现文档问答、摘要等任务的常用高阶工具。它们的核心作用是:将长文档切分为块,分步处理,再整合结果,极大提升大模型处理长文档的能力。stuff直接拼接所有文档内容到prompt,一次性交给大模型处理。适合文档较短、token不超限的场景。refine递进式摘要。先对第一块文档生成初步答案
    • .NET 一款基于BGInfo的红队内网渗透工具 dot.Net安全矩阵 网络.net安全.netcoreweb安全矩阵
      01阅读须知此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。本文所提供的工具仅用于学习,禁止用于其他方面02基本介绍在内网渗透过程中,白名单绕过是红队常见的技术需求。Sharp4Bginfo.exe是一款基于微软签名工具
    • 遍历dom 并且存储(将每一层的DOM元素存在数组中) 换个号韩国红果果 JavaScripthtml
      数组从0开始!! var a=[],i=0; for(var j=0;j<30;j++){ a[j]=[];//数组里套数组,且第i层存储在第a[i]中 } function walkDOM(n){ do{ if(n.nodeType!==3)//筛选去除#text类型 a[i].push(n); //con
    • Android+Jquery Mobile学习系列(9)-总结和代码分享 白糖_ JQuery Mobile
      目录导航   经过一个多月的边学习边练手,学会了Android基于Web开发的毛皮,其实开发过程中用Android原生API不是很多,更多的是HTML/Javascript/Css。   个人觉得基于WebView的Jquery Mobile开发有以下优点: 1、对于刚从Java Web转型过来的同学非常适合,只要懂得HTML开发就可以上手做事。 2、jquerym
    • impala参考资料 dayutianfei impala
      记录一些有用的Impala资料   1. 入门资料 >>官网翻译:     http://my.oschina.net/weiqingbin/blog?catalog=423691   2. 实用进阶 >>代码&架构分析:     Impala/Hive现状分析与前景展望:http
    • JAVA 静态变量与非静态变量初始化顺序之新解 周凡杨 java静态非静态顺序
      今天和同事争论一问题,关于静态变量与非静态变量的初始化顺序,谁先谁后,最终想整理出来!测试代码: import java.util.Map; public class T { public static T t = new T(); private Map map = new HashMap(); public T(){ System.out.println(&quo
    • 跳出iframe返回外层页面 g21121 iframe
      在web开发过程中难免要用到iframe,但当连接超时或跳转到公共页面时就会出现超时页面显示在iframe中,这时我们就需要跳出这个iframe到达一个公共页面去。 首先跳转到一个中间页,这个页面用于判断是否在iframe中,在页面加载的过程中调用如下代码: <script type="text/javascript"> //<!-- function
    • JAVA多线程监听JMS、MQ队列 510888780 java多线程
      背景:消息队列中有非常多的消息需要处理,并且监听器onMessage()方法中的业务逻辑也相对比较复杂,为了加快队列消息的读取、处理速度。可以通过加快读取速度和加快处理速度来考虑。因此从这两个方面都使用多线程来处理。对于消息处理的业务处理逻辑用线程池来做。对于加快消息监听读取速度可以使用1.使用多个监听器监听一个队列;2.使用一个监听器开启多线程监听。 对于上面提到的方法2使用一个监听器开启多线
    • 第一个SpringMvc例子 布衣凌宇 spring mvc
      第一步:导入需要的包; 第二步:配置web.xml文件 <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi=
    • 我的spring学习笔记15-容器扩展点之PropertyOverrideConfigurer aijuans Spring3
      PropertyOverrideConfigurer类似于PropertyPlaceholderConfigurer,但是与后者相比,前者对于bean属性可以有缺省值或者根本没有值。也就是说如果properties文件中没有某个bean属性的内容,那么将使用上下文(配置的xml文件)中相应定义的值。如果properties文件中有bean属性的内容,那么就用properties文件中的值来代替上下
    • 通过XSD验证XML antlove xmlschemaxsdvalidationSchemaFactory
      1. XmlValidation.java package xml.validation; import java.io.InputStream; import javax.xml.XMLConstants; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schem
    • 文本流与字符集 百合不是茶 PrintWrite()的使用字符集名字 别名获取
      文本数据的输入输出;           输入;数据流,缓冲流         输出;介绍向文本打印格式化的输出PrintWrite();   package 文本流; import java.io.FileNotFound
    • ibatis模糊查询sqlmap-mapping-**.xml配置 bijian1013 ibatis
              正常我们写ibatis的sqlmap-mapping-*.xml文件时,传入的参数都用##标识,如下所示: <resultMap id="personInfo" class="com.bijian.study.dto.PersonDTO"> <res
    • java jvm常用命令工具——jdb命令(The Java Debugger) bijian1013 javajvmjdb
              用来对core文件和正在运行的Java进程进行实时地调试,里面包含了丰富的命令帮助您进行调试,它的功能和Sun studio里面所带的dbx非常相似,但 jdb是专门用来针对Java应用程序的。         现在应该说日常的开发中很少用到JDB了,因为现在的IDE已经帮我们封装好了,如使用ECLI
    • 【Spring框架二】Spring常用注解之Component、Repository、Service和Controller注解 bit1129 controller
      在Spring常用注解第一步部分【Spring框架一】Spring常用注解之Autowired和Resource注解(http://bit1129.iteye.com/blog/2114084)中介绍了Autowired和Resource两个注解的功能,它们用于将依赖根据名称或者类型进行自动的注入,这简化了在XML中,依赖注入部分的XML的编写,但是UserDao和UserService两个bea
    • cxf wsdl2java生成代码super出错,构造函数不匹配 bitray super
          由于过去对于soap协议的cxf接触的不是很多,所以遇到了也是迷糊了一会.后来经过查找资料才得以解决. 初始原因一般是由于jaxws2.2规范和jdk6及以上不兼容导致的.所以要强制降为jaxws2.1进行编译生成.我们需要少量的修改: 我们原来的代码 wsdl2java com.test.xxx -client http://..... 修改后的代
    • 动态页面正文部分中文乱码排障一例 ronin47
      公司网站一部分动态页面,早先使用apache+resin的架构运行,考虑到高并发访问下的响应性能问题,在前不久逐步开始用nginx替换掉了apache。 不过随后发现了一个问题,随意进入某一有分页的网页,第一页是正常的(因为静态化过了);点“下一页”,出来的页面两边正常,中间部分的标题、关键字等也正常,唯独每个标题下的正文无法正常显示。 因为有做过系统调整,所以第一反应就是新上
    • java-54- 调整数组顺序使奇数位于偶数前面 bylijinnan java
      import java.util.Arrays; import java.util.Random; import ljn.help.Helper; public class OddBeforeEven { /** * Q 54 调整数组顺序使奇数位于偶数前面 * 输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半
    • 从100PV到1亿级PV网站架构演变 cfyme 网站架构
      一个网站就像一个人,存在一个从小到大的过程。养一个网站和养一个人一样,不同时期需要不同的方法,不同的方法下有共同的原则。本文结合我自已14年网站人的经历记录一些架构演变中的体会。 1:积累是必不可少的 架构师不是一天练成的。 1999年,我作了一个个人主页,在学校内的虚拟空间,参加了一次主页大赛,几个DREAMWEAVER的页面,几个TABLE作布局,一个DB连接,几行PHP的代码嵌入在HTM
    • [宇宙时代]宇宙时代的GIS是什么? comsci Gis
             我们都知道一个事实,在行星内部的时候,因为地理信息的坐标都是相对固定的,所以我们获取一组GIS数据之后,就可以存储到硬盘中,长久使用。。。但是,请注意,这种经验在宇宙时代是不能够被继续使用的          宇宙是一个高维时空
    • 详解create database命令 czmmiao database
      完整命令 CREATE DATABASE mynewdb   USER SYS IDENTIFIED BY sys_password   USER SYSTEM IDENTIFIED BY system_password   LOGFILE GROUP 1 ('/u01/logs/my/redo01a.log','/u02/logs/m
    • 几句不中听却不得不认可的话 datageek
      1、人丑就该多读书。 2、你不快乐是因为:你可以像猪一样懒,却无法像只猪一样懒得心安理得。 3、如果你太在意别人的看法,那么你的生活将变成一件裤衩,别人放什么屁,你都得接着。 4、你的问题主要在于:读书不多而买书太多,读书太少又特爱思考,还他妈话痨。 5、与禽兽搏斗的三种结局:(1)、赢了,比禽兽还禽兽。(2)、输了,禽兽不如。(3)、平了,跟禽兽没两样。结论:选择正确的对手很重要。 6
    • 1 14:00 PHP中的“syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM”错误 dcj3sjt126com PHP
      原文地址:http://www.kafka0102.com/2010/08/281.html   因为需要,今天晚些在本机使用PHP做些测试,PHP脚本依赖了一堆我也不清楚做什么用的库。结果一跑起来,就报出类似下面的错误:“Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM in /home/kafka/test/
    • xcode6 Auto layout and size classes dcj3sjt126com ios
      官方GUI   https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/Introduction/Introduction.html   iOS中使用自动布局(一)   http://www.cocoachina.com/ind
    • 通过PreparedStatement批量执行sql语句【sql语句相同,值不同】 梦见x光 sql事务批量执行
      比如说:我有一个List需要添加到数据库中,那么我该如何通过PreparedStatement来操作呢? public void addCustomerByCommit(Connection conn , List<Customer> customerList) {    String sql = "inseret into customer(id
    • 程序员必知必会----linux常用命令之十【系统相关】 hanqunfeng Linux常用命令
      一.linux快捷键 Ctrl+C : 终止当前命令 Ctrl+S : 暂停屏幕输出 Ctrl+Q : 恢复屏幕输出 Ctrl+U : 删除当前行光标前的所有字符 Ctrl+Z : 挂起当前正在执行的进程 Ctrl+L : 清除终端屏幕,相当于clear   二.终端命令 clear : 清除终端屏幕 reset : 重置视窗,当屏幕编码混乱时使用 time com
    • NGINX IXHONG nginx
      pcre 编译安装 nginx conf/vhost/test.conf   upstream admin { server 127.0.0.1:8080; }   server {                 listen       80; &
    • 设计模式--工厂模式 kerryg 设计模式
      工厂方式模式分为三种:   1、普通工厂模式:建立一个工厂类,对实现了同一个接口的一些类进行实例的创建。   2、多个工厂方法的模式:就是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式就是提供多个工厂方法,分别创建对象。   3、静态工厂方法模式:就是将上面的多个工厂方法模式里的方法置为静态,
    • Spring InitializingBean/init-method和DisposableBean/destroy-method mx_xiehd javaspringbeanxml
      1.initializingBean/init-method 实现org.springframework.beans.factory.InitializingBean接口允许一个bean在它的所有必须属性被BeanFactory设置后,来执行初始化的工作,InitialzingBean仅仅指定了一个方法。 通常InitializingBean接口的使用是能够被避免的,(不鼓励使用,因为没有必要
    • 解决Centos下vim粘贴内容格式混乱问题 qindongliang1922 centosvim
      有时候,我们在向vim打开的一个xml,或者任意文件中,拷贝粘贴的代码时,格式莫名其毛的就混乱了,然后自己一个个再重新,把格式排列好,非常耗时,而且很不爽,那么有没有办法避免呢? 答案是肯定的,设置下缩进格式就可以了,非常简单: 在用户的根目录下 直接vi  ~/.vimrc文件 然后将set pastetoggle=<F9> 写入这个文件中,保存退出,重新登录,
    • netty大并发请求问题 tianzhihehe netty
      多线程并发使用同一个channel java.nio.BufferOverflowException: null at java.nio.HeapByteBuffer.put(HeapByteBuffer.java:183) ~[na:1.7.0_60-ea] at java.nio.ByteBuffer.put(ByteBuffer.java:832) ~[na:1.7.0_60-ea]
    • Hadoop NameNode单点问题解决方案之一 AvatarNode wyz2009107220 NameNode
      我们遇到的情况 Hadoop NameNode存在单点问题。这个问题会影响分布式平台24*7运行。先说说我们的情况吧。 我们的团队负责管理一个1200节点的集群(总大小12PB),目前是运行版本为Hadoop 0.20,transaction logs写入一个共享的NFS filer(注:NetApp NFS Filer)。 经常遇到需要中断服务的问题是给hadoop打补丁。 DataNod
    按字母分类: ABCDEFGHIJKLMNOPQRSTUVWXYZ其他
    首页 - 关于我们 - 站内搜索 - Sitemap - 侵权投诉
    版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved.