vue -- 初级(二)

2 篇文章 0 订阅

使用 饿了么的 MintUI 组件
    [Github 仓储地址](https://github.com/ElemeFE/mint-ui)
    [Mint-UI官方文档](http://mint-ui.github.io/#!/zh-cn)
1. 导入所有MintUI组件:
    import MintUI from 'mint-ui'
2. 导入样式表:
    import 'mint-ui/lib/style.css'
3. 在 vue 中使用 MintUI:
    Vue.use(MintUI)
4. 使用的例子:
    <mt-button type="primary" size="large">primary</mt-button>

     使用 MUI 组件
    [官网首页](http://dev.dcloud.net.cn/mui/)
    [文档地址](http://dev.dcloud.net.cn/mui/ui/)
    使用 MUI 代码片段
    > 注意: MUI 不同于 Mint-UI,MUI只是开发出来的一套好用的代码片段,里面提供了配套的样式、配套的HTML代码段,类似于 Bootstrap; 而 Mint-UI,是真正的组件库,是使用 Vue 技术封装出来的 成套的组件,可以无缝的和 VUE项目进行集成开发;
    > 因此,从体验上来说, Mint-UI体验更好,因为这是别人帮我们开发好的现成的Vue组件;
    > 从体验上来说, MUI和Bootstrap类似;
    > 理论上,任何项目都可以使用 MUI 或 Bootstrap,但是,MInt-UI只适用于Vue项目;


    注意: MUI 并不能使用  npm 去下载,需要自己手动从 github 上,下载现成的包,自己解压出来,然后手动拷贝到项目中使用;
1. 导入 MUI 的样式表:
    import '../lib/mui/css/mui.min.css'
2. 在`webpack.config.js`中添加新的loader规则:
    { test: /\.(png|jpg|gif|ttf)$/, use: 'url-loader' }
3. 根据官方提供的文档和example,尝试使用相关的组件

     将项目源码托管到oschina中
1. 点击头像 -> 修改资料 -> SSH公钥 [如何生成SSH公钥](http://git.mydoc.io/?t=154712)
2. 创建自己的空仓储,使用 `git config --global user.name "用户名"` 和 `git config --global user.email ***@**.com` 来全局配置提交时用户的名称和邮箱
3. 使用 `git init` 在本地初始化项目
4. 使用 `touch README.md` 和 `touch .gitignore` 来创建项目的说明文件和忽略文件;
5. 使用 `git add .` 将所有文件托管到 git 中
6. 使用 `git commit -m "init project"` 将项目进行本地提交
7. 使用 `git remote add origin 仓储地址`将本地项目和远程仓储连接,并使用origin最为远程仓储的别名
8. 使用 `git push -u origin master` 将本地代码push到仓储中

     App.vue 组件的基本设置
1. 头部的固定导航栏使用 `Mint-UI` 的 `Header` 组件;
2. 底部的页签使用 `mui` 的 `tabbar`;
3. 购物车的图标,使用 `icons-extra` 中的 `mui-icon-extra mui-icon-extra-cart`,同时,应该把其依赖的字体图标文件 `mui-icons-extra.ttf`,复制到 `fonts` 目录下!
4. 将底部的页签,改造成 `router-link` 来实现单页面的切换;
5. Tab Bar 路由激活时候设置高亮的两种方式:
     全局设置样式如下:
    .router-link-active{
    color:#007aff !important;
    }
或者在 `new VueRouter` 的时候,通过 `linkActiveClass` 来指定高亮的类:
    // 创建路由对象
    var router = new VueRouter({
    routes: [
    { path: '/', redirect: '/home' }
    ],
    linkActiveClass: 'mui-active'
    });

     实现 tabbar 页签不同组件页面的切换
1. 将 tabbar 改造成 `router-link` 形式,并指定每个连接的 `to` 属性;
2. 在入口文件中导入需要展示的组件,并创建路由对象:
    // 导入需要展示的组件
    import Home from './components/home/home.vue'
    import Member from './components/member/member.vue'
    import Shopcar from './components/shopcar/shopcar.vue'
    import Search from './components/search/search.vue'
    // 创建路由对象
    var router = new VueRouter({
    routes: [
    { path: '/', redirect: '/home' },
    { path: '/home', component: Home },
    { path: '/member', component: Member },
    { path: '/shopcar', component: Shopcar },
    { path: '/search', component: Search }
    ],
    linkActiveClass: 'mui-active'
    });

     使用 mt-swipe 轮播图组件
1. 假数据:
lunbo: [
    'http://www.itcast.cn/images/slidead/BEIJING/2017440109442800.jpg',
    'http://www.itcast.cn/images/slidead/BEIJING/2017511009514700.jpg',
    'http://www.itcast.cn/images/slidead/BEIJING/2017421414422600.jpg'
    ]

2. 引入轮播图组件:
<!-- Mint-UI 轮播图组件 -->
    <div class="home-swipe">
        <mt-swipe :auto="4000">
            <mt-swipe-item v-for="(item, i) in lunbo" :key="i">
                <img :src="item" alt="">
            </mt-swipe-item>
        </mt-swipe>
    </div>

     在`.vue`组件中使用`vue-resource`获取数据
1. 运行`cnpm i vue-resource -S`安装模块
2. 导入 vue-resource 组件
    import VueResource from 'vue-resource'
3. 在vue中使用 vue-resource 组件
    Vue.use(VueResource);

    Promise概念:
1. Promise 是一个 构造函数,既然是构造函数, 那么,我们就可以  new Promise() 得到一个 Promise 的实例;
2. 在 Promise 上,有两个函数,分别叫做 resolve(成功之后的回调函数) 和 reject(失败之后的回调函数)
3. 在 Promise 构造函数的 Prototype 属性上,有一个 .then() 方法,也就说,只要是 Promise 构造函数创建的实例,都可以访问到 .then() 方法
4. Promise 表示一个 异步操作;每当我们 new 一个 Promise 的实例,这个实例,就表示一个具体的异步操作;
5. 既然 Promise 创建的实例,是一个异步操作,那么,这个 异步操作的结果,只能有两种状态:
5.1 状态1: 异步执行成功了,需要在内部调用 成功的回调函数 resolve 把结果返回给调用者;
5.2 状态2: 异步执行失败了,需要在内部调用 失败的回调函数 reject 把结果返回给调用者;
5.3 由于 Promise 的实例,是一个异步操作,所以,内部拿到 操作的结果后,无法使用 return 把操作的结果返回给调用者; 这时候,只能使用回调函数的形式,来把 成功 或 失败的结果,返回给调用者;
6. 我们可以在 new 出来的 Promise 实例上,调用 .then() 方法,【预先】 为 这个 Promise 异步操作,指定 成功(resolve) 和 失败(reject) 回调函数;

    // 注意:这里 new 出来的 promise, 只是代表 【形式上】的一个异步操作;
    // 什么是形式上的异步操作:就是说,我们只知道它是一个异步操作,但是做什么具体的异步事情,目前还不清楚
    // var promise = new Promise()

    // 这是一个具体的异步操作,其中,使用 function 指定一个具体的异步操作
    /* var promise = new Promise(function(){
    // 这个 function 内部写的就是具体的异步操作!!!
    }) */

    const fs = require('fs')
    // 每当 new 一个 Promise 实例的时候,就会立即 执行这个 异步操作中的代码
    // 也就是说,new 的时候,除了能够得到 一个 promise 实例之外,还会立即调用 我们为 Promise 构造函数传递的那个 function,执行这个 function 中的 异步操作代码;
    /* var promise = new Promise(function () {
    fs.readFile('./files/2.txt', 'utf-8', (err, dataStr) => {
    if (err) throw err
    console.log(dataStr)
    })
    }) */

    // 初衷: 给路径,返回读取到的内容
    function getFileByPath(fpath) {
        var promise =  new Promise(function (resolve, reject) {
            fs.readFile(fpath, 'utf-8', (err, dataStr) => {
                if (err) return reject(err)
                    resolve(dataStr)
                  })
        })
    return promise
    }
    var p =  getFileByPath('./files/2.txt')
    p.then(function (data) {
    console.log(data + '-------')
    }, function (err) {
    console.log(err.message)
    })

    function getFileByPath(fpath) {
        return new Promise(function (resolve, reject) {
            fs.readFile(fpath, 'utf-8', (err, dataStr) => {
                if (err) return reject(err)
                resolve(dataStr)
            })
        })
    }
     getFileByPath('./files/2.txt')
    .then(function (data) {
    console.log(data + '-------')
    }, function (err) {
    console.log(err.message)
    }) */

    使用Promise 解决回调地狱:
    const fs = require('fs')
    function getFileByPath(fpath) {
        return new Promise(function (resolve, reject) {
            fs.readFile(fpath, 'utf-8', (err, dataStr) => {
            if (err) return reject(err)
            resolve(dataStr)
            })
        })
    }
// 先读取文件1,在读取2,最后读取3
// 注意: 通过 .then 指定 回调函数的时候,成功的 回调函数,必须传,但是,失败的回调,可以省略不传
    // 这是一个 错误的示范,千万不要这么用; 硬是把 法拉利,开成了 拖拉机;
    /* getFileByPath('./files/1.txt')
        .then(function (data) {
            console.log(data)
            getFileByPath('./files/2.txt')
                .then(function (data) {
                console.log(data)
            getFileByPath('./files/3.txt')
                .then(function (data) {
                console.log(data)
            })
        })
    }) */

    // 读取文件1
    // 在上一个 .then 中,返回一个新的 promise 实例,可以继续用下一个 .then 来处理
    getFileByPath('./files/11.txt')
        .then(function (data) {
            console.log(data)
            // 读取文件2
            return getFileByPath('./files/2.txt')
        })
        .then(function (data) {
            console.log(data)
                return getFileByPath('./files/3.txt')
        })
        .then(function (data) {
             console.log(data)
        })

    // 读取文件1
    // 在上一个 .then 中,返回一个新的 promise 实例,可以继续用下一个 .then 来处理
    // 如果 ,前面的 Promise 执行失败,我们不想让后续的Promise 操作被终止,可以为 每个 promise 指定 失败的回调
    getFileByPath('./files/11.txt')
        .then(function (data) {
            console.log(data)
            // 读取文件2
            return getFileByPath('./files/2.txt')
        }, function (err) {
            console.log('这是失败的结果:' + err.message)
                // return 一个 新的 Promise
                return getFileByPath('./files/2.txt')
        })
        .then(function (data) {
            console.log(data)
                return getFileByPath('./files/3.txt')
        })
        .then(function (data) {
            console.log(data)
        })
     console.log('OKOKOK')

当 我们有这样的需求: 哪怕前面的 Promise 执行失败了,但是,不要影响后续 promise 的正常执行,此时,我们可以单独为 每个 promise,通过 .then 指定一下失败的回调;
有时候,我们有这样的需求,和上面的需求刚好相反:如果 后续的Promise 执行,依赖于 前面 Promise 执行的结果,如果前面的失败了,则后面的就没有继续执行下去的意义了,此时,我们想要实现,一旦有报错,则立即终止所有 Promise的执行;
    getFileByPath('./files/1.txt')
        .then(function (data) {
        console.log(data)
        // 读取文件2
        return getFileByPath('./files/22.txt')
    })
    .then(function (data) {
    console.log(data)
        return getFileByPath('./files/3.txt')
    })
    .then(function (data) {
    console.log(data)
    })
    .catch(function (err) { // catch 的作用: 如果前面有任何的 Promise 执行失败,则立即终止所有 promise 的执行,并 马上进入 catch 去处理 Promise中 抛出的异常;
    console.log('这是自己的处理方式:' + err.message)
    })

    jQuery中ajax使用promise指定成功回调函数:
    $(function () {
        $('#btn').on('click', function () {
        $.ajax({
            url: './data.json',
            type: 'get',
            dataType: 'json'
        })
        .then(function (data) {
        console.log(data)
        })
    })
    });

加载首页轮播图数据
1. 获取数据, 如何获取呢, 使用 vue-resource
2. 使用 vue-resource 的 this.$http.get 获取数据
3. 获取到的数据,要保存到 data 身上
4. 使用 v-for 循环渲染 每个 item 项
    <mt-swipe :auto="4000">
        <!-- 在组件中,使用v-for循环的话,一定要使用 key -->
        <mt-swipe-item v-for="item in lunbotuList" :key="item.url">
            <img :src="item.img" alt="">
        </mt-swipe-item>
    </mt-swipe>

     新闻资讯 页面 制作
    1. 绘制界面, 使用 MUI 中的 media-list.html
    2. 使用 vue-resource 获取数据
    3. 渲染真实数据

    实现 新闻资讯列表 点击跳转到新闻详情
1. 把列表中的每一项改造为 router-link,同时,在跳转的时候应该提供唯一的Id标识符
2. 创建新闻详情的组件页面  NewsInfo.vue
3. 在 路由模块中,将 新闻详情的 路由地址 和 组件页面对应起来

    单独封装一个 comment.vue 评论子组件
1. 先创建一个 单独的 comment.vue 组件模板
2. 在需要使用 comment 组件的 页面中,先手动 导入 comment 组件
   `import comment from './comment.vue'`
3. 在父组件中,使用 `components` 属性,将刚才导入 comment 组件,注册为自己的 子组件
4. 将注册子组件时候的,注册名称,以 标签形式,在页面中 引用即可

    发表评论
1. 把文本框做双向数据绑定
2. 为发表按钮绑定一个事件
3. 校验评论内容是否为空,如果为空,则Toast提示用户 评论内容不能为空
4. 通过 vue-resource 发送一个请求,把评论内容提交给 服务器
5. 当发表评论OK后,重新刷新列表,以查看最新的评论
    + 如果调用 getComments 方法重新刷新评论列表的话,可能只能得到 最后一页的评论,前几页的评论获取不到
    + 换一种思路: 当评论成功后,在客户端,手动拼接出一个 最新的评论对象,然后 调用 数组的 unshift 方法, 把最新的评论,追加到  data 中 comments 的开头;这样,就能 完美实现刷新评论列表的需求;

    制作顶部滑动条的坑:    使用mui的`tab-top-webview-main`完成分类滑动栏
    1. 需要借助于 MUI 中的 tab-top-webview-main.html
2. 需要把 slider 区域的 mui-fullscreen 类去掉
3. 滑动条无法正常触发滑动,通过检查官方文档,发现这是JS组件,需要被初始化一下:
    + 导入 mui.js
    + 调用官方提供的 方式 去初始化:
mui('.mui-scroll-wrapper').scroll({
    deceleration: 0.0005 //flick 减速系数,系数越大,滚动速度越慢,滚动距离越小,默认值0.0006
    });
4. 我们在初始化 滑动条 的时候,导入的 mui.js ,但是,控制台报错: `Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode`
    + 经过我们合理的推测,觉得,可能是 mui.js 中用到了 'caller', 'callee', and 'arguments' 东西,但是, webpack 打包好的 bundle.js 中,默认是启用严格模式的,所以,这两者冲突了;
    + 解决方案: 1. 把 mui.js 中的 非严格 模式的代码改掉;但是不现实; 2. 把 webpack 打包时候的严格模式禁用掉;
    + 最终,我们选择了 plan B  移除严格模式: 使用这个插件 babel-plugin-transform-remove-strict-mode
5. 刚进入 图片分享页面的时候, 滑动条无法正常工作, 经过我们认真的分析,发现, 如果要初始化 滑动条,必须要等 DOM 元素加载完毕,所以,我们把 初始化 滑动条 的代码,搬到了 mounted 生命周期函数中;
6. 当 滑动条 调试OK后,发现, tabbar 无法正常工作了,这时候,我们需要把 每个 tabbar 按钮的 样式中  `mui-tab-item` 重新改一下名字;
7. 获取所有分类,并渲染 分类列表;

   兼容问题
1. 和 App.vue 中的 `router-link` 身上的类名 `mui-tab-item` 存在兼容性问题,导致tab栏失效,可以把`mui-tab-item`改名为`mui-tab-item1`,并复制相关的类样式,来解决这个问题;
.mui-bar-tab .mui-tab-item1.mui-active {
    color: #007aff;
    }
.mui-bar-tab .mui-tab-item1 {
    display: table-cell;
    overflow: hidden;
    width: 1%;
    height: 50px;
    text-align: center;
    vertical-align: middle;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: #929292;
    }
.mui-bar-tab .mui-tab-item1 .mui-icon {
    top: 3px;
    width: 24px;
    height: 24px;
    padding-top: 0;
    padding-bottom: 0;
    }
.mui-bar-tab .mui-tab-item1 .mui-icon~.mui-tab-label {
    font-size: 11px;
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    }
2. `tab-top-webview-main`组件第一次显示到页面中的时候,无法被滑动的解决方案:
    先导入 mui 的JS文件:
    import mui from '../../../lib/mui/js/mui.min.js'
   在 组件的 `mounted` 事件钩子中,注册 mui 的滚动事件:
    mounted() {
    // 需要在组件的 mounted 事件钩子中,注册 mui 的 scroll 滚动事件
    mui('.mui-scroll-wrapper').scroll({
    deceleration: 0.0005 //flick 减速系数,系数越大,滚动速度越慢,滚动距离越小,默认值0.0006
    });
    }
3. 滑动的时候报警告:`Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080`
    解决方法,可以加上* { touch-action: pan-y; } 这句样式去掉。
    原因:(是chrome为了提高页面的滑动流畅度而新折腾出来的一个东西) http://www.cnblogs.com/pearl07/p/6589114.html
    https://developer.mozilla.org/zh-CN/docs/Web/CSS/touch-action

    移除严格模式
    [babel-plugin-transform-remove-strict-mode](https://github.com/genify/babel-plugin-transform-remove-strict-mode)

     [vue-preview](https://github.com/LS1231/vue-preview)
    一个Vue集成PhotoSwipe图片预览插件
    实现 图片详情中 缩略图的功能
    1. 使用 插件 vue-preview 这个缩略图插件
    2. 获取到所有的图片列表,然后使用 v-for 指令渲染数据
    3. 注意: img标签上的class不能去掉
    4. 注意: 每个 图片数据对象中,必须有 w 和 h 属性

    尝试在手机上 去进行项目的预览和测试
1. 要保证 手机 和 开发项目的电脑 处于同一个 WIFI 环境中,也就是说 手机 可以 访问到 电脑的 IP
2. 打开自己的 项目中 package.json 文件,在 dev 脚本中,添加一个 --host 指令, 把 当前 电脑的 WIFI IP地址, 设置为 --host 的指令值;
+ 如何查看自己电脑所处 WIFI 的IP呢, 在 cmd 终端中运行 `ipconfig` , 查看 无线网的 ip 地址
    Total Control 软件 与手机的共屏软件(Android可用)

    <!-- 在网页中,有两种跳转方式: -->
    <!-- 方式1: 使用 a 标签 的形式叫做 标签跳转  -->
    <!-- 方式2: 使用 window.location.href 的形式,叫做 编程式导航 -->
    <div class="goods-item" v-for="item in goodslist" :key="item.id" @click="goDetail(item.id)">
    goDetail(id) {
    // 使用JS的形式进行路由导航
    // 注意: 一定要区分 this.$route 和 this.$router 这两个对象,
    // 其中: this.$route 是路由【参数对象】,所有路由中的参数, params, query 都属于它
    // 其中: this.$router 是一个路由【导航对象】,用它 可以方便的 使用 JS 代码,实现路由的 前进、后退、 跳转到新的 URL 地址
    console.log(this);
        id: this.$route.params.id, // 将路由参数对象中的 id 挂载到 data , 方便后期调用
    // 1. 最简单的
    // this.$router.push("/home/goodsinfo/" + id);
    // 2. 传递对象
    // this.$router.push({ path: "/home/goodsinfo/" + id });
    // 3. 传递命名的路由
    this.$router.push({ name: "goodsinfo", params: { id } });
    }

 小球动画优化思路:
1. 导致 动画 不准确的 本质原因: 我们把 小球 最终 位移到的 位置 横纵坐标 直接写死了, 应该 根据不同情况,动态计算这个坐标值;
2.思路: 先得到 徽标的 横纵 坐标,再得到 小球的 横纵坐标,然后 让 y 值 求差, x 值也求 差,得到 的结果,就是横纵坐标要位移的距离
3. 如何 获取 徽标和小球的 位置???   domObject.getBoundingClientRect()
    beforeEnter(el) {
        el.style.transform = "translate(0, 0)";
        },
    enter(el, done) {
        el.offsetWidth;
        // 获取小球的 在页面中的位置
        const ballPosition = this.$refs.ball.getBoundingClientRect();
        // 获取 徽标 在页面中的位置
        const badgePosition = document .getElementById("badge") .getBoundingClientRect();
        const xDist = badgePosition.left - ballPosition.left;
        const yDist = badgePosition.top - ballPosition.top;
        el.style.transform = `translate(${xDist}px, ${yDist}px)`;
        el.style.transition = "all 0.5s cubic-bezier(.4,-0.3,1,.68)";
        done();
        },
    afterEnter(el) {
        this.ballFlag = !this.ballFlag;
        },

git使用推送:
    git add .
    git commit -m "打卡了"
    git push
    git status

vuex:
    概念: vuex 是 Vue 配套的 公共数据管理工具,它可以把一些共享的数据,保存到 vuex 中,方便 整个程序中的任何组件直接获取或修改我们的公共数据;
        // 配置vuex的步骤
        // 1. 运行 cnpm i vuex -S
        // 2. 导入包
        import Vuex from 'vuex'
        // 3. 注册vuex到vue中
        Vue.use(Vuex)
        // 4. new Vuex.Store() 实例,得到一个 数据仓储对象
        var store = new Vuex.Store({
        state: {
        // 大家可以把 state 想象成 组件中的 data ,专门用来存储数据的
        // 如果在 组件中,想要访问,store 中的数据,只能通过 this.$store.state.*** 来访问
        count: 0
        },
        mutations: {
        // 注意: 如果要操作 store 中的 state 值,只能通过 调用 mutations 提供的方法,才能操作对应的数据,不推荐直接操作 state 中的数据,因为 万一导致了数据的紊乱,不能快速定位到错误的原因,因为,每个组件都可能有操作数据的方法;
        increment(state) {
        state.count++
        },
        subtract(state,obj){
        // 注意: mutations 的 函数参数列表中,最多支持两个参数,其中,参数1: 是 state 状态; 参数2: 通过 commit 提交过来的参数;
        console.log(obj)
        state.count -= (obj.c + obj.d)
        }
        },
        // 注意: 如果组件想要调用 mutations 中的方法,只能使用 this.$store.commit('方法名')
        //this.$store.commit("increment")  this.$store.commit("subtract", { c: 3, d: 1 });
        // 这种 调用 mutations 方法的格式,和 this.$emit('父组件中方法名')
        getters: {
        // 注意:这里的 getters, 只负责 对外提供数据,不负责 修改数据,如果想要修改 state 中的数据,请 去找 mutations
        optCount: function (state) {
        return '当前最新的count值是:' + state.count
        }
        }
        })
        // 总结:
        // 1. state中的数据,不能直接修改,如果想要修改,必须通过 mutations
        // 2. 如果组件想要直接 从 state 上获取数据: 需要 this.$store.state.***
        // 3. 如果 组件,想要修改数据,必须使用 mutations 提供的方法,需要通过 this.$store.commit('方法的名称', 唯一的一个参数)
        // 4. 如果 store 中 state 上的数据, 在对外提供的时候,需要做一层包装,那么 ,推荐使用 getters, 如果需要使用 getters ,则用 this.$store.getters.***

        开启Apache的gzip压缩
要让apache支持gzip功能,要用到deflate_Module和headers_Module。打开apache的配置文件httpd.conf,大约在105行左右,找到以下两行内容:(这两行不是连续在一起的)
        #LoadModule deflate_module modules/mod_deflate.so
        #LoadModule headers_module modules/mod_headers.so
然后将其前面的“#”注释删掉,表示开启gzip压缩功能。开启以后还需要进行相关配置。在httpd.conf文件的最后添加以下内容即可:
        <IfModule deflate_module>
            #必须的,就像一个开关一样,告诉apache对传输到浏览器的内容进行压缩
            SetOutputFilter DEFLATE
            DeflateCompressionLevel 9
        </IfModule>
最少需要加上以上内容,才可以生gzip功能生效。由于没有做其它的额外配置,所以其它相关的配置均使用Apache的默认设置。这里说一下参数“DeflateCompressionLevel”,它表示压缩级别,值从1到9,值越大表示压缩的越厉害。

         使用ngrok将本机映射为一个外网的Web服务器
注意:由于默认使用的美国的服务器进行中间转接,所以访问速度炒鸡慢,访问时可启用FQ软件,提高网页打开速度!
基本命令:
        1. 双击快速运行 ngrok.exe 应用程序
        2. 随机生成三级域名(自动防止重名问题),其中,80代表要向外暴露的端口号:
        ngrok http [80]
        或者人为指定三级域名(存在重名问题):
        ngrok http -subdomain=[inconshreveable] [80]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值