zoukankan      html  css  js  c++  java
  • 06:vuejs项目实战

    1.1 项目说明

      1、技术架构

          vue.js, 模块化,工程化, 移动端

      2、目录部署  

          Css:所有样式文件

          Data:所有异步接口

          Img:所有图片文件

          Js:所有js文件(2.0)

          index.html

      3、结构说明

          1. 一个页面看成是一个组件,所以要创建三个组件

          2. 页面中只能同时显示一个组件,那么如果只有一个容器元素,就可以实现渲染一个了

          3. Vue中定义了一个叫component自定义元素,跟transition一样,有特殊的功能,用来渲染组件

              component是一个万能的组件容器的元素

              Is属性的属性值是谁,就渲染谁

              为了让属性值是动态变量,我们可以使用v-bind指令

          4. 使用component指定当前显示的组件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, width=device-width">
        <title>爱创课堂团购网</title>
    </head>
    <body>
        <div id="app">
            <!-- 定义组件容器:定义一个万能的组件元素 view是谁就会渲染谁-->
            <component v-bind:is="view"></component>
        </div>
    
        <script src="vue.js"></script>
        <script src="index.js"></script>
    </body>
    </html>
    index.html
    // 第一步:使用Vue.extend方法,定义三个组件、每个组件实质就是一个页面
    var Home = Vue.extend({            // home组件:模拟显示home页面
       template:'<h1>Home</h1>'
    });
    var List = Vue.extend({            // list组件:模拟显示list页面
        template:'<h1>List</h1>'
    });
    var Detail = Vue.extend({          // detail组件:模拟显示detail页面
        template:'<h1>Detail</h1>'
    });
    
    // 第二步:将组件注册到页面中 Vue.component
    Vue.component('Home',Home);
    Vue.component('list',List);
    Vue.component('detail',Detail);
    
    // 创建vue实例化对象
    var app = new Vue({
        el:'#app',
        data:{
            view:'home'        // 定义默认渲染视图的名称
        }
    });
    
    
    // route路由执行的函数,来控制页面显示的组件(home、list、detail)
    var route = function () {
        var hash = location.hash;         // 获取到url后面传入的参数
        hash = hash.replace(/#/?/,'');    //  url中 '#' 和 '#/'  是无意义的,因此要过滤掉
        hash = hash.split('/');
        var map = {               // 定义了组件的名称才能够渲染
            home:true,
            list:true,
            detail:true
        };
        if (map[hash[0]]){             // hash[0]在map表中存在才能渲染 hash[0]= home、list、detail
            app.view = hash[0]         // 将页面设置成url传入的那个组件
        }else {
            app.view = 'home'         // 否则进入默认路由(home这个组件)
        }
        app.query = hash.slice(1);    // 从第二个成员开始表示路由参数了
        // http://localhost:63342/vuejsPro/bbb/demo/index.html?_ijt=p7pgchp7pvfueq4e4tem6c0n0r#home/type/2
        // app.query = ["type", "2"]
    };
    
    // 实现路由:hashchange 当页面hash改变就会触发此事件
    window.addEventListener('hashchange',route);    // 每次url给不就会触发
    route();   // 当页面加载文成也要执行route路由函数   // window.addEventListener('load',route);
    index.js

     1.2 定义路由

       1、路由原理

          1. 我们定义三套组件:home、list、detail,每个组件实际对应了一个页面

          2. 并且每个组件对应一个自定义路由,前端的路由是根据hash实现的,所以我们要监听hash的改变

          3. Hash的改变会触发hashchange事件,所以我们订阅该事件,然后解析路由,切换组件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, width=device-width">
        <link rel="stylesheet" type="text/css" href="css/index.css">
        <title>爱创课堂团购网</title>
    </head>
    <body>
        <div id="app">
            <!-- 定义组件容器:定义一个万能的组件元素 view是谁就会渲染谁-->
            <component v-bind:is="view"></component>
        </div>
    
        <script src="js/vue.js"></script>
        <script src="js/index.js"></script>
    
    </body>
    </html>
    index.html
    // 第一步:使用Vue.extend方法,定义三个组件、每个组件实质就是一个页面
    var Home = Vue.extend({            // home组件:模拟显示home页面
       template:'<h1>Home</h1>'
    });
    var List = Vue.extend({            // list组件:模拟显示list页面
        template:'<h1>List</h1>'
    });
    var Detail = Vue.extend({          // detail组件:模拟显示detail页面
        template:'<h1>Detail</h1>'
    });
    
    // 第二步:将组件注册到页面中 Vue.component
    Vue.component('Home',Home);
    Vue.component('list',List);
    Vue.component('detail',Detail);
    
    // 创建vue实例化对象
    var app = new Vue({
        el:'#app',
        data:{
            view:'home'        // 定义默认渲染视图的名称
        }
    });
    
    
    // route路由执行的函数,来控制页面显示的组件(home、list、detail)
    var route = function () {
        var hash = location.hash;         // 获取到url后面传入的参数
        hash = hash.replace(/#/?/,'');    //  url中 '#' 和 '#/'  是无意义的,因此要过滤掉
        hash = hash.split('/');
        var map = {               // 定义了组件的名称才能够渲染
            home:true,
            list:true,
            detail:true
        };
        if (map[hash[0]]){             // hash[0]在map表中存在才能渲染 hash[0]= home、list、detail
            app.view = hash[0]         // 将页面设置成url传入的那个组件
        }else {
            app.view = 'home'         // 否则进入默认路由(home这个组件)
        }
        app.query = hash.slice(1);    // 从第二个成员开始表示路由参数了
        // http://localhost:63342/vuejsPro/bbb/demo/index.html?_ijt=p7pgchp7pvfueq4e4tem6c0n0r#home/type/2
        // app.query = ["type", "2"]
    };
    
    // 实现路由:hashchange 当页面hash改变就会触发此事件
    window.addEventListener('hashchange',route);    // 每次url给不就会触发
    route();   // 当页面加载文成也要执行route路由函数   // window.addEventListener('load',route);
    js/index.js

     1.3 异步请求

      1、运行node后端服务

          C:Users om>cd C:Users omPycharmProjectsvuejsProbbdemo         # 进入app.js文件夹下
          C:Users omPycharmProjectsvuejsProbbdemo> node app.js               # 运行
              server running at port 3001

    /**
     * 服务器
     */
    
    var MINE_TYPES = {
        'html':     'text/html',
        'xml':         'text/xml',
        'txt':         'text/plain',
        'css':         'text/css',
        'js':         'text/javascript',
        'json':     'application/json',
        'pdf':         'application/pdf',
        'swf':         'application/x-shockwave-flash',
        'svg':         'image/svg+xml',
        'tiff':     'image/tiff',
        'png':         'image/png',
        'gif':         'image/gif',
        'ico':         'image/x-icon',
        'jpg':         'image/jpeg',
        'jpeg':     'image/jpeg',
        'wav':         'audio/x-wav',
        'wma':         'audio/x-ms-wma',
        'wmv':         'video/x-ms-wmv',
        'woff2':     'application/font-woff2'
    };
    var PORT = 3001;
    var http = require('http');
    var url = require('url');
    var fs = require('fs');
    var path = require('path');
    var root = process.cwd();
    
    var server = http.createServer(function(request, response) {
        var pathname = decodeURIComponent(url.parse(request.url).pathname);
        var realPath = path.join(root, pathname);
        var ext = path.extname(realPath);
        if (!ext) {
            realPath = path.join(realPath, '/home.html');
            ext = '.html'
        }
        fs.exists(realPath, function(exists) {
            if (exists) {
                fs.readFile(realPath, 'binary', function(err, file) {
                    if (!err) {
                        response.writeHead(200, {
                            'Content-Type': MINE_TYPES[ext.slice(1)] || 'text/plain'
                        });
                        response.write(file, 'binary');
                        response.end();
                    } else {
                        response.writeHead(500, {
                            'Content-Type': 'text/plain'
                        });
                        response.write('ERROR, the reason of error is ' + err.code + '; Error number is ' + err.errno + '.');
                        response.end();
                    }
                })
            } else {
                response.writeHead(404, {
                    'Content-Type': 'text/plain'
                });
                response.write('This request URL ' + pathname + ' was not found on this server.');
                response.end();
            }
        });
    
    });
    server.listen(PORT);
    console.log("server running at port " + PORT);
    app.js 服务端
    {
        "errno": 0,
        "name":"zhangsan",
        "age":100
    }
    home.json 模拟请求数据
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Title</title>
    </head>
    <body>
        <h1>home</h1>
        <script src="vue.js"></script>
        <script>
            // 实现异步请求
             var Util = {
                 ajax:function (url, fn) {                       // url:请求地址;fn:请求回调函数
                     var xhr = new XMLHttpRequest();             // 初始化xhr
                     xhr.onreadystatechange = function () {    // 监听事件
                         if (xhr.readyState === 4){             // 判断状态
                             if (xhr.status === 200 ){          // 判断状态码
                                 fn && fn(JSON.parse( xhr.responseText) )       // 执行函数fn: xhr.responseText 是从服务端获取到的数据
                             }
                         }
                     };
                     xhr.open('GET', url, true);    // 打开链接
                     xhr.send(null)                 // null代替发送数据内容
                 }
             };
             // 测试
             Util.ajax('home.json',function (res) {
                 console.log(res,3333333333333333333)
             });
        </script>
    </body>
    </html>
    home.html 发送异步请求

     1.4 头部样式

       说明:公用的部分,不要写在组件中,尽量写在父组件(vue实例化对象中),这样组件可以复用。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, width=device-width">
        <link rel="stylesheet" type="text/css" href="css/index.css">
        <title>爱创课堂团购网</title>
    </head>
    <body>
        <!-- 定义容器元素 -->
        <div id="app">
            <header class="header">
                <div class="title">
                    <div class="go-back" v-on:click="goBack"><span class="arrow"><span class="arrow green"></span></span></div>
                    <div class="login">登录</div>
                    <h1>爱创课堂团购网</h1>
                </div>
                <div class="search" v-show="showSearch">
                    <input type="text" placeholder="请输入搜索关键字" v-on:keyup.enter="gotoSearch">
                </div>
            </header>
        </div>
        <script type="text/javascript" src="js/vue2.js"></script>
        <script type="text/javascript" src="js/index.js"></script>
    </body>
    </html>
    index.html
    // 实例化vue
    var app = new Vue({
        el: '#app',             // 绑定数据
        data: {
            view: 'home',      // 存储路由参数
            query: [],
            search: '',        // 是否显示搜索框
            showSearch: true
        },
        methods: {             // 定义方法
            gotoSearch: function (e) {                 // 点击enter进行搜索
                this.search = e.target.value            // 第一种方式,通过组件间通信
            },
            goBack: function () {                        // 返回逻辑
                history.go(-1)
            }
        }
    });
    js/index.js

       

     1.5 分类按钮: home页面中的不变数据

       1、说明

          1. 分类按钮的数据是不变的,因此不变的数据,通常直接写在js中,变的通过异步请求获取

           2. 直接写在页面中的数据,通常称之为同步的数据,通过异步请求获取的数据,通常称之为异步数据

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, width=device-width">
        <link rel="stylesheet" type="text/css" href="css/index.css">
        <title>爱创课堂团购网</title>
    </head>
    <body>
        <!-- 定义容器元素 -->
        <div id="app">
            <component v-bind:searchquery="search" v-bind:is="view"></component>
        </div>
        <!-- 定义首页模板 -->
        <script type="text/template" id="tpl_home">
            <!-- 定义首页组件容器 -->
            <section class="home">
                <ul class="types clearfix">
                    <li v-for="item in types">
                        <a v-bind:href="'#list/type/' + item.id">
                            <img v-bind:src="'img/icon/' + item.url" alt="">
                            <p>{{item.title}}</p>
                        </a>
                    </li>
                </ul>
            </section>
        </script>
        <script type="text/javascript" src="js/vue2.js"></script>
        <script type="text/javascript" src="js/index.js"></script>
    </body>
    </html>
    index.html
    // 拓展工具方法
    var Util =  {
        /***
         * 获取模板的方法
         * @id         模板标签元素id
         * return     模板内容
         **/
        tpl: function (id) {
            return document.getElementById(id).innerHTML;
        },
        /**
         * 我们要实现异步请求的方法
         * @url        请求地址
         * @fn         执行的方法
         ***/
        ajax: function (url, fn) {                            // 创建xhr对象
            var xhr = new XMLHttpRequest();                    // 订阅事件
            xhr.onreadystatechange = function () {        // 监听状态
                if (xhr.readyState === 4) {                // 判断状态
                    if (xhr.status === 200) {              // 执行回调函数
                        // console.log(xhr)
                        fn(JSON.parse(xhr.responseText))
                    }
                }
            };
            xhr.open('GET', url, true);            // 打开链接
            xhr.send(null)                        // 发送数据
        }
    };
    
    // 定义三个组件
    var Home = Vue.extend({
        template: Util.tpl('tpl_home'),
        data: function () {          // 定义数据
            return {                // 返回值才是真正的数据
                types: [
                    {id: 1, title: '美食', url: '01.png'},
                    {id: 2, title: '电影', url: '02.png'},
                    {id: 3, title: '酒店', url: '03.png'},
                    {id: 4, title: '休闲娱乐', url: '04.png'},
                    {id: 5, title: '外卖', url: '05.png'},
                    {id: 6, title: 'KTV', url: '06.png'},
                    {id: 7, title: '周边游', url: '07.png'},
                    {id: 8, title: '丽人', url: '08.png'},
                    {id: 9, title: '小吃快餐', url: '09.png'},
                    {id: 10, title: '火车票', url: '10.png'}
                ],
            }
        },
    });
    
    // 注册三个组件
    Vue.component('home', Home);
    
    // 实例化vue
    var app = new Vue({
        el: '#app',             // 绑定数据
        data: {
            view: 'home',      // 存储路由参数
            search: '',        // 是否显示搜索框
        },
    });
    
    // 定义路由
    function router () {
        var hash = location.hash;
        hash = hash.replace(/^#/?/, '');
        hash = hash.split('/');
        // 定义规则
        var map = {
            home: true,
        };
        if (map[hash[0]]) {
            app.view = hash[0]
        } else {
            app.view = 'home'
        }
        app.query = hash.slice(1);
    }
    window.addEventListener('hashchange', router);
    window.addEventListener('load', router);
    index.js

         

    1.6 广告模块:home页面中通过异步请求获取数据

       1、说明

          1. 这里的数据是可变的,所以要写在异步请求中,

          2. 什么时候请求数据?看组件什么时候创建完成。所以要看组件生命周期,组件的生命周期

          3. Vue将组件看成是一个有生命的个体,跟人一样,定义了各个阶段,组件的生命周期:组件的创建过程

          4. 组件生命周期钩子函数:当组件处在某个阶段,要执行某个方法,来通知我们,组件进入某个阶段,这个方法就是组件生命周期的钩子函数

          5. 这些方法在组件中直接定义,会按照顺序执行,没有参数,作用域都是组件实例化对象

          6. 注:为了让数据属性具有特性,我们一定要将该数据在绑定的数据(data)中定义出来

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta charset="UTF-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, width=device-width">
        <link rel="stylesheet" type="text/css" href="css/index.css">
        <title>爱创课堂团购网</title>
    </head>
    <body>
        <!-- 定义容器元素 -->
        <div id="app">
            <component v-bind:searchquery="search" v-bind:is="view"></component>
        </div>
        <!-- 定义首页模板 -->
        <script type="text/template" id="tpl_home">
            <!-- 定义首页组件容器 -->
            <section class="home">
                <!-- 定义ad广告 -->
                <ul class="ad clearfix">
                    <li v-for="(item, index) in ad">
                        <a v-bind:href="'#/detail/' + item.id">
                            <h3>{{item.title}}</h3>
                            <p>{{item.description}}</p>
                            <img v-bind:src="'img/ad/' + item.url" alt="">
                        </a>
                    </li>
                </ul>
            </section>
        </script>
        <script type="text/javascript" src="js/vue2.js"></script>
        <script type="text/javascript" src="js/index.js"></script>
    </body>
    </html>
    index.html
    // 拓展工具方法
    var Util =  {
        /***
         * 获取模板的方法
         * @id         模板标签元素id
         * return     模板内容
         **/
        tpl: function (id) {
            return document.getElementById(id).innerHTML;
        },
        /**
         * 我们要实现异步请求的方法
         * @url        请求地址
         * @fn         执行的方法
         ***/
        ajax: function (url, fn) {                            // 创建xhr对象
            var xhr = new XMLHttpRequest();                    // 订阅事件
            xhr.onreadystatechange = function () {        // 监听状态
                if (xhr.readyState === 4) {                // 判断状态
                    if (xhr.status === 200) {              // 执行回调函数
                        // console.log(xhr)
                        fn(JSON.parse(xhr.responseText))
                    }
                }
            };
            xhr.open('GET', url, true);            // 打开链接
            xhr.send(null)                        // 发送数据
        }
    };
    
    // 定义三个组件
    var Home = Vue.extend({
        template: Util.tpl('tpl_home'),
        data: function () {          // 定义数据
            return {                // 返回值才是真正的数据
                ad: [],            // 将数据定义出来,否则没有特性
            }
        },
        created: function () {
            this.$parent.showSearch = true;
            var me = this;
            Util.ajax('data/home.json', function (res) {        // 请求数据
                if (res && res.errno === 0) {
                    me.ad = res.data.ad;                        // 存储数据
                    me.list = res.data.list;
                    // 2.0版本不建议使用$set更新数据
                    // me.$set('ad', res.data.ad)
                }
            })
        }
    });
    
    // 注册三个组件
    Vue.component('home', Home);
    
    // 实例化vue
    var app = new Vue({
        el: '#app',             // 绑定数据
        data: {
            view: 'home',      // 存储路由参数
            search: '',        // 是否显示搜索框
        },
    });
    
    // 定义路由
    function router () {
        var hash = location.hash;
        hash = hash.replace(/^#/?/, '');
        hash = hash.split('/');
        // 定义规则
        var map = {
            home: true,
        };
        if (map[hash[0]]) {
            app.view = hash[0]
        } else {
            app.view = 'home'
        }
        app.query = hash.slice(1);
    }
    window.addEventListener('hashchange', router);
    window.addEventListener('load', router);
    index.js

    1.7 效果图 

       

         

    1.8 项目模块化

       1、项目模块化目录结构

    Lib: 库文件
    Util:工具方法
    Filter:定义过滤器
    Router: 定义路由
    Vm:存储所有组件
        Home:home组件以及样式
        List:list组件以及样式
        Detail:detail组件以及样式
        App.js:vue实例化对象
        App.css: app样式
    Bootstrap.js 启动的文件
    Reset.js 默认样式
    目录结构说明

          

       2、个文件代码展示

        1. index.html和app.js

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, width=device-width">
        <!--<link rel="stylesheet" type="text/css" href="css/index.css">-->
        <title>爱创课堂团购网</title>
    </head>
    <body>
        <!-- 定义容器元素 -->
        <div id="app">
            <header class="header">
                <div class="title">
                    <div class="go-back" v-on:click="goBack"><span class="arrow"><span class="arrow green"></span></span></div>
                    <div class="login">登录</div>
                    <h1>爱创课堂团购网</h1>
                </div>
                <div class="search" v-show="showSearch">
                    <input type="text" placeholder="请输入搜索关键字" v-on:keyup.enter="gotoSearch">
                </div>
            </header>
            <!-- 定义组件容器元素 -->
            <!-- <home></home>
            <list></list>
            <detail></detail> -->
            <!-- 同时只能渲染一个组件 -->
            <component v-bind:searchquery="search" v-bind:is="view"></component>
        </div>
        <!-- 定义首页模板 -->
        <script type="text/template" id="tpl_home">
            <!-- 定义首页组件容器 -->
            <section class="home">
                <ul class="types clearfix">
                    <li v-for="item in types">
                        <a v-bind:href="'#list/type/' + item.id">
                            <img v-bind:src="'img/icon/' + item.url" alt="">
                            <p>{{item.title}}</p>
                        </a>
                    </li>
                </ul>
                <!-- 定义ad广告 -->
                <ul class="ad clearfix">
                    <li v-for="(item, index) in ad">
                        <a v-bind:href="'#/detail/' + item.id">
                            <h3>{{item.title}}</h3>
                            <p>{{item.description}}</p>
                            <img v-bind:src="'img/ad/' + item.url" alt="">
                        </a>
                    </li>
                </ul>
                <!-- 定义商品列表 -->
                <ul class="list-container">
                    <li v-for="item in list">
                        <a v-bind:href="'#detail/' + item.id">
                            <img v-bind:src="'img/list/' + item.img" alt="">
                            <div class="content">
                                <h3>{{item.title}}</h3>
                                <p>
                                    <span class="price">{{item.price | price}}</span>
                                    <span class="origin-price">{{item.orignPrice | orignPrice}}</span>
                                    <span class="sales">{{item.sales | sales}}</span>
                                </p>
                            </div>
                        </a>
                    </li>
                </ul>
            </section>
        </script>
        <!-- 定义list模板 -->
        <script type="text/template" id="tpl_list">
            <section class="list">
                <ul class="types clearfix">
                    <li v-for="ickt in types" v-on:click="sortBy(ickt.key)">
                        <span>{{ickt.value}}</span>
                        <span class="arrow"></span>
                    </li>
                </ul>
                <ul class="list-container">
                    <!-- <li v-for="item in list | filterBy query"> -->
                    <!-- <li v-for="item in list | filterBy searchquery"> -->
                    <li v-for="item in dealList">
                        <a v-bind:href="'#detail/' + item.id">
                            <img v-bind:src="'img/list/' + item.img" alt="">
                            <div class="content">
                                <h3>{{item.title}}</h3>
                                <p>
                                    <span class="price">{{item.price | price}}</span>
                                    <span class="origin-price">{{item.orignPrice | orignPrice}}</span>
                                    <span class="sales">{{item.sales | sales}}</span>
                                </p>
                            </div>
                        </a>
                    </li>
                </ul>
                <div class="load-more" v-show="others.length" v-on:click="loadMore">
                    <span>查看剩余{{others.length}}条团购</span>
                    <span class="arrow">
                        <span class="arrow white"></span>
                    </span>
                </div>
            </section>
        </script>
        <!-- 定义详情页模板 -->
        <script type="text/template" id="tpl_detail">
            <section class="product">
                <div class="image-part">
                    <img v-if="data.src" v-bind:src="'img/item/' + data.src" alt="">
                    <h1>{{data.title}}</h1>
                    <p>{{data.description}}</p>
                </div>
                <div class="price-part">
                    <span class="price">{{data.price}}</span>
                    <span class="sign"></span>
                    <span class="origin">{{data.orignPrice | orignPrice}}</span>
                    <span class="buy">立即购买</span>
                </div>
                <ul class="sale-part clearfix">
                    <li>支持自动退货</li>
                    <li>支持随时退货</li>
                    <li>{{data.sales | sales}}</li>
                </ul>
                <div class="store-part part">
                    <div class="header">店家信息</div>
                    <div class="body">
                        <p>{{data.storeName}}</p>
                        <p>{{data.storeAddress}}</p>
                    </div>
                    <div class="footer">查看{{data.storeNum}}家分店</div>
                </div>
                <div class="buy-part part">
                    <div class="header">购买须知</div>
                    <div class="body">
                        <ul>
                            <li>
                                <h3>有效期</h3>
                                <p>{{data.validateTime}}</p>
                            </li>
                            <li>
                                <h3>使用时间</h3>
                                <p>{{data.useTime}}</p>
                            </li>
                            <li>
                                <h3>使用规则</h3>
                                <p v-for="item in data.rules">{{item}}</p>
                            </li>
                        </ul>
                    </div>
                </div>
            </section>
        </script>
        <!-- 引入脚本文件 -->
        <!--<script type="text/javascript" src="static/lib/vue2.js"></script>-->
    
        <script type="text/javascript" src="static/lib/sea.js"></script>
        <script type="text/javascript" src="static/lib/seajs-css.js"></script>
        <script type="text/javascript" src="static/lib/seajs-preload.js"></script>
        <script>
            // 定义配置引入入口文件
            seajs.config({
                // 配置根目录
                base:'/static',
                // 预加载
                preload:['lib/vue']
            });
            // 引入入口文件
            seajs.use('bootstrap')
        </script>
    </body>
    </html>
    demo/index.heml
    /**
     * 服务器
     */
    
    var MINE_TYPES = {
        'html':     'text/html',
        'xml':         'text/xml',
        'txt':         'text/plain',
        'css':         'text/css',
        'js':         'text/javascript',
        'json':     'application/json',
        'pdf':         'application/pdf',
        'swf':         'application/x-shockwave-flash',
        'svg':         'image/svg+xml',
        'tiff':     'image/tiff',
        'png':         'image/png',
        'gif':         'image/gif',
        'ico':         'image/x-icon',
        'jpg':         'image/jpeg',
        'jpeg':     'image/jpeg',
        'wav':         'audio/x-wav',
        'wma':         'audio/x-ms-wma',
        'wmv':         'video/x-ms-wmv',
        'woff2':     'application/font-woff2'
    };
    var PORT = 3001;
    var http = require('http');
    var url = require('url');
    var fs = require('fs');
    var path = require('path');
    var root = process.cwd();
    
    var server = http.createServer(function(request, response) {
        var pathname = decodeURIComponent(url.parse(request.url).pathname);
        var realPath = path.join(root, pathname);
        var ext = path.extname(realPath);
        if (!ext) {
            realPath = path.join(realPath, '/index.html');
            ext = '.html'
        }
        fs.exists(realPath, function(exists) {
            if (exists) {
                fs.readFile(realPath, 'binary', function(err, file) {
                    if (!err) {
                        response.writeHead(200, {
                            'Content-Type': MINE_TYPES[ext.slice(1)] || 'text/plain'
                        });
                        response.write(file, 'binary');
                        response.end();
                    } else {
                        response.writeHead(500, {
                            'Content-Type': 'text/plain'
                        });
                        response.write('ERROR, the reason of error is ' + err.code + '; Error number is ' + err.errno + '.');
                        response.end();
                    }
                })
            } else {
                response.writeHead(404, {
                    'Content-Type': 'text/plain'
                });
                response.write('This request URL ' + pathname + ' was not found on this server.');
                response.end();
            }
        });
    
    });
    server.listen(PORT);
    console.log("server running at port " + PORT);
    demo/app.js

        2. static文件夹下文件

    define(function (require, exports, module) {
        // 定义过滤器
        Vue.filter('price', function (value) {
            return value + '元';
        })
        // 定义门市价过滤器
        Vue.filter('orignPrice', function (value) {
            return '门市价:' + value + '元'
        })
        // 定义销量过滤器
        Vue.filter('sales', function (value) {
            return '销量' + value
        })
    
        // 过滤器无需暴露接口,可以直接使用
    });
    1.1 demo/static/filter/filter.js
    define(function (require, exports, module) {
        // 引入vue实例化对象
        var app = require('vm/app');
        // 定义路由
        function router () {
            // 解析hash就要获取hash
            var hash = location.hash;
            // 删除#
            // hash = hash.slice(1);
            // 删除起始的/
            // hash = hash.replace(/^//, '')
            hash = hash.replace(/^#/?/, '');
            // 对/进行切割,保留第一部分,就是组件名称,后面的成员就是参数
            hash = hash.split('/');
            // 定义规则
            var map = {
                home: true,
                list: true,
                detail: true
            };
            // 只有在map中存在的组件,才能渲染
            if (map[hash[0]]) {
                // 切换组件
                app.view = hash[0]
            } else {
                // 进入默认路由
                app.view = 'home'
            }
            // 我们还可以将参数存储
            app.query = hash.slice(1);
        }
        // 监听路由改变
        window.addEventListener('hashchange', router);
        // 页面加载没有触发hashchange事件,我们可以手动触发hashchange事件,或者监听load事件
        window.addEventListener('load', router)
    
        // 暴露接口
        module.exports = router;
    });
    2.1 demo/static/filter/router.js
    define(function (require, exports, module) {
        // 拓展工具方法
        var Util = {
            /***
             * 获取模板的方法
             * @id         模板标签元素id
             * return     模板内容
             **/
            tpl: function (id) {
                return document.getElementById(id).innerHTML;
            },
            /**
             * 我们要实现异步请求的方法
             * @url        请求地址
             * @fn         执行的方法
             ***/
            ajax: function (url, fn) {
                // 创建xhr对象
                var xhr = new XMLHttpRequest();
                // 订阅事件
                xhr.onreadystatechange = function () {
                    // 监听状态
                    if (xhr.readyState === 4) {
                        // 判断状态
                        if (xhr.status === 200) {
                            // 执行回调函数
                            // console.log(xhr)
                            fn(JSON.parse(xhr.responseText))
                        }
                    }
                }
                // 打开链接
                xhr.open('GET', url, true);
                // 发送数据
                xhr.send(null)
            }
        }
        // 暴露接口
        module.exports = Util;
    });
    3.1 demo/static/util/util.js
    define(function (require, exports, module) {
        // 引入组件
        var home = require('vm/home/home');
        var list = require('vm/list/list');
        var detail = require('vm/detail/detail');
        // 引入样式
        require('vm/app.css');
    
        // 实例化vue
        var app = new Vue({
            el: '#app',
            // 绑定数据
            data: {
                view: 'home',
                // 存储路由参数
                query: [],
                search: '',
                // 是否显示搜索框
                showSearch: true
            },
            // 定义方法
            methods: {
                // 点击enter进行搜索
                gotoSearch: function (e) {
                    // 第一种方式,通过组件间通信
                    this.search = e.target.value
                    // 第二种方式存储在路由中
                    // location.hash = '#/list/search/' + e.target.value
                    // console.log(e.target.value)
                },
                // 返回逻辑
                goBack: function () {
                    history.go(-1)
                }
            }
        });
        // 暴露接口
        module.exports = app;
    });
    4.1 demo/static/vm/app.js
    define(function (require, exports, module) {
        // 引入样式
        require('./detail.css');
        // 使用过滤器
        require('filter/filter');
        // 使用工具
        var Util = require('util/util');
    
        // 详情页
        var Detail = Vue.extend({
            template: Util.tpl('tpl_detail'),
            // 定义数据
            data: function () {
                return {
                    data: {}
                }
            },
            // 请求数据
            created: function () {
                // 隐藏搜索框
                this.$parent.showSearch = false;
                var me = this;
                // 获取商品id
                var id = me.$parent.query[0];
                // console.log(id)
                // 请求数据
                Util.ajax('data/product.json', function (res) {
                    if (res && res.errno === 0) {
                        // 存储数据
                        me.data = res.data
                    }
                })
            }
        });
        // 注册组件
        Vue.component('detail', Detail)
    
        module.exports = Detail;
    
    });
    4.2 demo/static/vm/detail/detail.js
    define(function (require, exports, module) {
        // 引入样式
        require('vm/home/home.css');
        // 引入过滤器
        require('filter/filter');
        // 引入Util模块
        var Util = require('util/util');
    
        var Home = Vue.extend({
            template: Util.tpl('tpl_home'),
            // 定义数据
            data: function () {
                // 返回值才是真正的数据
                return {
                    types: [
                        {id: 1, title: '美食', url: '01.png'},
                        {id: 2, title: '电影', url: '02.png'},
                        {id: 3, title: '酒店', url: '03.png'},
                        {id: 4, title: '休闲娱乐', url: '04.png'},
                        {id: 5, title: '外卖', url: '05.png'},
                        {id: 6, title: 'KTV', url: '06.png'},
                        {id: 7, title: '周边游', url: '07.png'},
                        {id: 8, title: '丽人', url: '08.png'},
                        {id: 9, title: '小吃快餐', url: '09.png'},
                        {id: 10, title: '火车票', url: '10.png'}
                    ],
                    // num: 111
                    // 将数据定义出来,否则没有特性
                    ad: [],
                    list: []
                }
            },
            created: function () {
                this.$parent.showSearch = true;
                var me = this;
                Util.ajax('data/home.json', function (res) {
                        if (res && res.errno === 0) {
                            // 存储数据
                            me.ad = res.data.ad;
                            console.log(me.ad,111111111111222222222)
                            me.list = res.data.list;
                            // 2.0版本不建议使用$set更新数据
                            // me.$set('ad', res.data.ad)
                        }
                    })
                }
        });
        Vue.component('home',Home);
    
        // 暴露接口
        module.exports = Home;
    
    });
    4.3 demo/static/vm/home/home.js
    define(function (require, exports, module) {
        // 引入样式
        require('./list.css');
        // 引入过滤器
        require('filter/filter');
    
        // 引入工具
        var Util = require('util/util');
    
        // 列表页
        var List = Vue.extend({
            template: Util.tpl('tpl_list'),
            // 获取属性数据
            props: ['searchquery'],
            data: function () {
                // 返回值才是绑定的数据
                return {
                    types: [
                        {value: '价格排序', key: 'price'},
                        {value: '销量排序', key: 'sales'},
                        {value: '好评排序', key: 'evaluate'},
                        {value: '优惠排序', key: 'discount'}
                    ],
                    // 定义存储数据的变量
                    list: [],
                    // 剩余的产品
                    others: [],
                    // 搜索字段
                    query: ''
                }
            },
            // 动态数据
            computed: {
                dealList: function () {
                    var me = this;
                    return this.list.filter(function (obj) {
                        // console.log(arguments)
                        return obj.title.indexOf(me.searchquery) >= 0;
                    })
                }
            },
            // 定义方法
            methods: {
                // 点击加载更多按钮
                loadMore: function () {
                    // 将other中数据传递给list
                    this.list = this.list.concat(this.others);
                    // 此时others中应该没有数据了
                    this.others = [];
                },
                // 点击排序按钮
                sortBy: function (type) {
                    // 如果字段是优惠,我们要单独处理
                    if (type === 'discount') {
                        this.list.sort(function (a, b) {
                            // 比较原价-现价的插值
                            // 升序
                            // return (a.orignPrice - a.price) - (b.orignPrice - b.price)
                            // 降序
                            return (b.orignPrice - b.price) - (a.orignPrice - a.price)
                        })
                    } else {
                        // 数组排序
                        this.list.sort(function (a, b) {
                            // 升序
                            // return a[type] - b[type]
                            // 降序
                            return b[type] - a[type]
                        })
                    }
                    // console.log(22, type)
    
                }
            },
            // 视图渲染完成执行的方法
            created: function () {
                this.$parent.showSearch = true;
                // console.log(this)
                // 用$parent的数据更新query
                this.query = this.$parent.query[1]
                var me = this;
                var url = 'data/list.json?' + this.$parent.query[0] + '=' + this.$parent.query[1]
                // 请求数据
                Util.ajax(url, function (res) {
                    // console.log(res)
                    // 请求成功,存储数据
                    if (res && res.errno === 0) {
                        // 默认显示三条
                        me.list = res.data.slice(0, 3);
                        me.others = res.data.slice(3)
                    }
                })
            }
        });
        // 注册
        Vue.component('list', List);
        // 可以暴露接口,也可以不暴露接口
        module.exports = List;
    });
    4.4 demo/static/vm/list/list.js
  • 相关阅读:
    weblogic 正常启动页面还是404
    oracle awr 生成
    jre 修改timezone 夏令时冬令时问题
    apache 2.4 配置loadbalance
    plsq 调试存储过程
    Windows怎么命令行修改文件权限
    Windows上面挂载NFS共享
    linux sar命令详解
    Tomcat Connector connectionTimeout含义和验证
    c++STL系列之Set
  • 原文地址:https://www.cnblogs.com/xiaonq/p/9238803.html
Copyright © 2011-2022 走看看