Vue2(路由)

2023-11-02

一,路由原理(hash)

单页应用的路由模式有两种

1、哈希模式(利用hashchange 事件监听 url的hash 的改变)
2、history模式(使用此模式需要后台配合把接口都打到我们打包后的index.html上)

hash模式的原理:

核心是锚点值的改变,我们监听到锚点值改变了就去局部改变页面数据,不做跳转。跟传统开发模式url改变
后立刻发起请求,响应整个页面,渲染整个页面比路由的跳转用户体验更好

演示1

二,路由安装和使用(vue2)

导入路由插件

<script src="../js/vue-router.js"></script>

安装路由插件到Vue中

Vue.use(VueRouter);

创建VueRouter对象

    // 路由的安装 前提是要导入路由js
    Vue.use(VueRouter)

    // 创建一个登录子组件
    var login = {
        template:`
            <div>
                登录页面    
            </div>
        `,
    }

    // 创建路由配置实例,主要实现,路劲和子组件之间的映射
    var myrouter = new VueRouter({
        routes:[
            {path:'/login/id',name:'login',component:login},
        ]
    })

使用路由

<body>
    <div id="app">
        头部
        <!-- 下面是路由出口 -->
        <router-view></router-view>
        尾部
    </div>
</body>
<script src="../Vue2/js/vue2.7.js"></script>
<script src="../Vue2/js/vue-router.js"></script>
<script>
    // 路由的安装 前提是要导入路由js
    Vue.use(VueRouter)

    // 创建一个登录子组件
    var login = {
        template:`
            <div>
                个人页面    
            </div>
        `,
    }

    // 创建路由配置实例,主要实现,路劲和子组件之间的映射
    var myrouter = new VueRouter({
        routes:[
            {path:'/login',name:'login',component:login},
        ]
    })

    var app = new Vue({
        el:'#app',
        data(){
            return{
                
            }
        },
        router:myrouter,
        
    })


</script>

示例2

三,路由跳转

路由的跳转有两种方式:

使用标签

<router-link to="/login">登录</router-link>

编程式路由,使用js

this.$router.push({path:'/login'});
this.$router.replace({path:'/login'});

说明:

1.this.$router.push(); 会向history中添加记录
2.this.$router.replace();不会向history中添加记录。
3.this.$router.go(-1)常用来做返回上一个地址。

路由中的对象:

1.this.$route 路由信息对象,只读。
2.this.$router 路由操作对象,只写。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        头部
        <router-link to="/login">登录</router-link>
        <router-link to="/person">个人</router-link>
        <button @click="toxiaohao">api 王导</button>
        <!-- 下面是路由出口 -->
        <router-view></router-view>
        尾部
    </div>
</body>
<script src="../Vue2/js/vue2.7.js"></script>
<script src="../Vue2/js/vue-router.js"></script>
<script>
    // 路由的安装 前提是要导入路由js
    Vue.use(VueRouter)

    // 创建一个登录子组件
    var login = {
        template:`
            <div>
                登录页面     
            </div>
        `,
       
    }

     // 创建一个登录子组件
     var person = {
        template:`
            <div> 
                个人页面 
            </div>
        `,
       
    }

    // 创建一个个人页面子组件
    var xiaohao = {
        template:`
            <div>
                王导页面    
            </div>
        `,
    

    }

    // 创建路由配置实例,主要实现,路劲和子组件之间的映射
    var myrouter = new VueRouter({
        routes:[
            {path:'/login',name:'login',component:login},
            {path:'/person',name:'person',component:person},
            {path:'/xiaohao',name:'xiaohao',component:xiaohao}
        ]
    })

    var app = new Vue({
        el:'#app',
        data(){
            return{
                
            }
        },
        router:myrouter,
        methods:{
            toxiaohao(){
                this.$router.replace({
                    path:'/xiaohao'
                })
            },
        }
    })


</script>
</html>

示例3

四,路由的传参和取值

查询参

配置。查询参可以和path属性匹配,也可以和name属性匹配。

<router-link :to="{path:'/login',query:{id:queryid}}"></router-link>

或者

<router-link :to="{name:'login',query:{id:queryid}}"></router-link>

或者

this.$router.push({path:'/login',query:{id:queryid}});

取参

// 此代码可以写到组件的钩子函数中
this.$route.query.id
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        头部
        <router-link :to="{path:'login',query:{id:loginId}}">带参数登录</router-link>
        <router-link :to="{name:'person',query:{id:personId}}">带参数个人</router-link>
        <button @click="clxiaodao">带参数王导</button>
        <!-- 下面是路由出口 -->
        <router-view></router-view>
        尾部
    </div>
</body>
<script src="../Vue2/js/vue2.7.js"></script>
<script src="../Vue2/js/vue-router.js"></script>
<script>
    // 路由的安装 前提是要导入路由js
    Vue.use(VueRouter)

    // 创建一个登录子组件
    var login = {
        template:`
            <div>
                登录页面     
            </div>
        `, 
        mounted(){
            console.log(this.$route.query.id);
        },
    }

     // 创建一个登录子组件
     var person = {
        template:`
            <div> 
                个人页面 
            </div>
        `,
        mounted(){
            console.log(this.$route.query.id);
        },  
    }

    // 创建一个个人页面子组件
    var xiaodao = {
        template:`
            <div>
                王导页面    
            </div>
        `,
        mounted(){
            console.log(this.$route.query.id);
        },
    }

    // 创建路由配置实例,主要实现,路劲和子组件之间的映射
    var myrouter = new VueRouter({
        routes:[
            {path:'/login',name:'login',component:login},
            {path:'/person',name:'person',component:person},
            {path:'/xiaodao',name:'xiaodao',component:xiaodao}
        ]
    })

    var app = new Vue({
        el:'#app',
        data(){
            return{
                loginId:1,
                personId:2,
                xiaodaoId:3
            }
        },
        router:myrouter,
        methods:{
            clxiaodao(){
                this.$router.push({
                    path:'/xiaodao',query:{id:this.xiaodaoId}
                })
            },
        }
    })


</script>
</html>

示例4

路由参

配置路由规则

var router = new VueRouter({
   routers:[
       // 需要在配置路由规则时,使用冒号指定参数
       {name:'login',path:'/login/:id',component:LoginVue}
   ]
});

配置。意:在这里path和params两个参数不能同时使用

<router-link :to="{name:'login',params:{id:paramId}}"></router-link>

或者

this.$router.push({name:'login',params:{id:this.paramId}});

取参

this.$route.params.id;

注意:相同路由,但参数不同。造成页面不刷新的问题。

<router-view :key="$route.fullPath"></router-view>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        头部
        <router-link :to="{name:'login',params:{id:loginId}}">路由登录</router-link>
        <router-link :to="{name:'person',params:{id:personId}}">路由个人</router-link>
        <button @click="apixiaodao">api路由 王导</button>
        <!-- 下面是路由出口 -->
        <router-view></router-view>
        尾部
    </div>
</body>
<script src="../Vue2/js/vue2.7.js"></script>
<script src="../Vue2/js/vue-router.js"></script>
<script>
    // 路由的安装 前提是要导入路由js
    Vue.use(VueRouter)

    // 创建一个登录子组件
    var login = {
        template:`
            <div>
                登录页面     
            </div>
        `, 
        mounted(){
            console.log(this.$route.params.id);
        }
    }

     // 创建一个登录子组件
     var person = {
        template:`
            <div> 
                个人页面 
            </div>
        `,
        mounted(){
            console.log(this.$route.params.id);
        }
    }

    // 创建一个个人页面子组件
    var xiaodao = {
        template:`
            <div>
                王导页面    
            </div>
        `,
        mounted(){
            console.log(this.$route.params.id);
        }
    }

    // 创建路由配置实例,主要实现,路劲和子组件之间的映射
    var myrouter = new VueRouter({
        routes:[
            {path:'/login/id',name:'login',component:login},
            {path:'/person/id',name:'person',component:person},
            {path:'/xiaodao/id',name:'xiaodao',component:xiaodao}
        ]
    })

    var app = new Vue({
        el:'#app',
        data(){
            return{
                loginId:1,
                personId:2,
                xiaodaoId:3
            }
        },
        router:myrouter,
        methods:{
            apixiaodao(){
                this.$router.push({
                    name:'xiaodao',params:{id:this.xiaodaoId}
                })
            }
        }
    })


</script>
</html>

示例5

五,嵌套路由

1.路由间有层级关系。他们在模板中也有嵌套关系。
2.可以一次性配置多个路由。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <router-view :key="$route.fullPath"></router-view>
    </div>
</body>
<script src="../Vue2/js/vue2.7.js"></script>
<script src="../Vue2/js/vue-router.js"></script>
<script>
     // 路由的安装 前提是要导入路由js
     Vue.use(VueRouter)

    //  导航子组件,一级路由
     var nav = {
        template:`
            <div>
                <router-link :to="{name:'nav.index'}">首页</router-link>    
                <router-link :to="{name:'nav.person'}">个人中心</router-link>    
                <router-link :to="{name:'nav.message'}">消息</router-link> 
                <router-view></router-view>    
            </div>
        `
     }


     //  首页子组件,二级路由
     var index = {
        template:`
            <div>
                首页    
            </div>
        `
     }
     //  个人中心子组件,二级路由
     var person = {
        template:`
            <div>
                个人中心    
            </div>
        `
     }
     //  消息子组件,二级路由
     var message = {
        template:`
            <div>
                消息  
            </div>
        `
     }

     var router = new VueRouter({
        routes:[
            {
                path:'/nav/',
                name:'nav',
                component:nav,
                children:[
                    {path:'',redirect:'/nav/index'}, 
                    {path:'index',name:'nav.index',component:index},
                    {path:'person',name:'nav.person',component:person},
                    {path:'message',name:'nav.message',component:message},
                ]
            },
            {
                path:'',
                redirect:'/nav'
            }
        ]
     })

     var app = new Vue({
        el:'#app',
        router,
        
     })


</script>
</html>

示例六

六,路由守卫

可以做验证判断
使用路由的钩子函数beforeEach实现

mounted(){
            this.$router.beforeEach((to,from,next)=>{
                console.log(to);
                if(to.path=='/index'){
                    next();
                }else{
                    setTimeout(()=>{
                        next()
                    },2000)
                }
            })
        }

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <router-view :key="$route.fullPath"></router-view>
    </div>
</body>
<script src="../Vue2/js/vue2.7.js"></script>
<script src="../Vue2/js/vue-router.js"></script>
<script>
     // 路由的安装 前提是要导入路由js
     Vue.use(VueRouter)

    //  导航子组件,一级路由
     var nav = {
        template:`
            <div>
                <router-link :to="{name:'nav.index'}">首页</router-link>    
                <router-link :to="{name:'nav.person'}">个人中心</router-link>    
                <router-link :to="{name:'nav.message'}">消息</router-link> 
                <router-view></router-view>    
            </div>
        `
     }


     //  首页子组件,二级路由
     var index = {
        template:`
            <div>
                首页    
            </div>
        `
     }
     //  个人中心子组件,二级路由
     var person = {
        template:`
            <div>
                个人中心    
            </div>
        `
     }
     //  消息子组件,二级路由
     var message = {
        template:`
            <div>
                消息  
            </div>
        `
     }

     var router = new VueRouter({
        routes:[
            {
                path:'/nav/',
                name:'nav',
                component:nav,
                children:[
                    {path:'',redirect:'/nav/index'}, 
                    {path:'index',name:'nav.index',component:index},
                    {path:'person',name:'nav.person',component:person},
                    {path:'message',name:'nav.message',component:message},
                ]
            },
            {
                path:'',
                redirect:'/nav'
            }
        ]
     })

     var app = new Vue({
        el:'#app',
        router,
        mounted(){
            this.$router.beforeEach((to,from,next)=>{
                console.log(to);
                if(to.path=='/index'){
                    next();
                }else{
                    setTimeout(()=>{
                        next()
                    },2000)
                }
            })
        }
     })


</script>
</html>

最后

送大家一句话:半山腰总是挤的你要去山顶看看!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Vue2(路由) 的相关文章

  • 使用 AJAX 来回发送信息

    使用 post 你可以向服务器发送信息 但是当你需要从服务器接收信息时怎么办呢 信息如何从可以由 php 变量保存的方式变为可以由 javascript 变量保存的方式 反之亦然 这与您的问题更相关 http docs jquery com
  • Jest 中从未调用图像 onLoad 处理程序

    我正在尝试使用 Jest 测试将 dataUrl 加载到图像中 我正在使用 JSDOM 并按照说明添加resources usable 作为一个选项 如果我直接从 Node 运行该代码 则该代码可以工作 但是当我尝试在 Jest 中运行它时
  • 从 HTML 表单发送数据到 Node.js 服务器

    我正在学习 Node js 我的服务器中有这个 var http require http var url require url http createServer function request response response w
  • Jqplot 中两个系列数据的不同颜色条

    我想知道如何在 Jqplot 中为两个系列制作不同的颜色条 如果我只有一个系列数据 它的工作原理如下图所示 红色和绿色基于其值 但是 如果我有两个系列数据 我无法为每个系列数据配置两个系列颜色 目前我只能做这个图 我希望两个系列图可以根据其
  • 如何监控浏览器中发出的所有自定义事件?

    我想监视网络浏览器中触发的所有自定义事件 任何标准浏览器都可以 需要明确的是 我知道您可以附加事件处理程序来查看何时触发 通常 事件 但如何可靠地检测嵌入对象或 jQuery 脚本是否触发自定义事件 我可以重构浏览器源代码来挂钩事件循环 但
  • JS如何获取多维数组的最大深度?

    我有一个多维数组 我想知道它的最大深度 我发现了这个灵魂 但它不适用于对象数组 const getArrayDepth arr gt return Array isArray arr 1 Math max arr map getArrayD
  • 使用shinyjs通过javascript在闪亮的应用程序中操作现有的Leaflet地图

    我有一个闪亮的应用程序 其中包含现有的传单地图 我希望能够在渲染后使用自定义 javascript 通过shinyjs包裹 一个最小的例子如下 app R packages library dplyr library leaflet lib
  • 使用 JavaScript 填写 PDF 表单

    这就是我所拥有的 用户填写很长的 html 表单 用户获取下载不同 pdf 的链接 这是可填写的表格 链接是使用 javascript 生成的 用户单击链接 生成 url 使用用户之前提交的数据 在表单中处理数据并完成字段 这是在表单内使用
  • 将 FBX 文件转换为 .gltf 后,模型非常小,为什么?

    问题 将 FBX 文件转换为 gltf 后 模型非常小 为什么 我尝试用以下方法缩放模型frontObject scale set 1000 1000 1000 但我收到以下错误 TypeError Cannot read property
  • TypeScript 中类和命名空间的区别

    到底有什么区别classes and namespaces在打字稿中 我知道 如果您创建一个带有静态方法的类 您可以在不实例化该类的情况下访问它们 这正是我猜想的命名空间的要点之一 我还知道你可以创建多个同名的命名空间 并且它们的方法在编译
  • 向下滚动时如何使图像移动?

    这是我想要实现的目标的示例 https www flambette com en https www flambette com en 我尝试过更改图像的 css 属性 但效果不能满足我的需求 我尝试过以下代码 mydocument on
  • AttachEvent 或 addEventListener - 存储在哪里?

    在 jQuery 中 如果我这样做 a click function Do something 点击事件存储在 a data events 我可以像这样获取它 jQuery each a data events function i eve
  • Angular UI.Bootstrap 单选按钮在 ng-repeat 中表现得很奇怪[重复]

    这个问题在这里已经有答案了 我在 Angular 的 ui bootstrap 中动态生成无线电模型的选项时遇到问题 我想我可以简单地对数组进行 ng repeat 使用 btn radio 属性的内容 如下所示 in the contro
  • 为什么在 vue 组件上输入另一个输入时,输入文件的值丢失了?

    我有两个组件 我的第一个组件 父组件 如下所示
  • 如何混淆或使 JavaScript 文件不可读?

    我的应用程序中有 JavaScript 脚本 其中包含 JavaScript 和 jQuery 函数 所有用户与我的应用程序的交互都是动态的 并且通过 jQuery 传递到应用程序 我意识到 当我在客户端运行我的应用程序时 客户端可以通过查
  • 传单 - 导入 Geojson - Angular 6

    我尝试将 GeoJson 文件导入到 Angular 的应用程序 6 中的传单中 通过这个解决方案 我的 geojson 是在 leafletmap 中绘制的 但我有这个错误 我无法构建我的应用程序 有人知道一种解决方案吗 错误 TS234
  • 如何让无限滚动发挥作用?

    我正在尝试让这个无限加载脚本在我的项目中工作 这是我的 HTML div div div class pagina div div class pagina div div class pagina div div class pagina
  • 为什么对于整数键,“Map”操作比 JavaScript (v8) 中的“Object”慢得多?

    我很高兴使用Map对于在我的 JavaScript 代码库中随处访问的索引 但我刚刚偶然发现了这个基准 https stackoverflow com a 54385459 365104 https stackoverflow com a
  • 网页执行回发时如何停止在注册表单上?

    我正在做我的最后一年的项目 其中 我在一页上有登录和注册表单 WebForm 当用户点击锚点时Sign Up下拉菜单ddlType 隐藏 和文本框 txtCustName txtEmail and txtConfirmPassword 显示
  • 通过jquery ajax()和serialize()提交html表单

    我想通过 jquery ajax 提交此表单 这是我所做的 但它不起作用 即表单正在提交并刷新页面 但我没有看到响应 即在同一页面上打印数组 HTML

随机推荐

  • python敏感字替换_Python敏感词替换成*

    敏感词文本文件 filtered words txt 当用户输入敏感词语 则用星号 替换 例如当用户输入 北京是个好城市 则变成 是个好城市 filtered words txt filtered words txt coding utf
  • U盘插上就让格式化是坏了吗?数据怎么恢复

    U盘插上就让格式化是坏了吗 当您遇到U盘插上后提示需要格式化的情况时 不要慌张 这种情况并不一定意味着U盘已经坏了 下面我们一起来了解下如何恢复里面的数据 并解决U盘提示格式化的问题 U盘一插上就提示格式化是什么原因 许多人可能会有一个困惑
  • springboot整合spring security + MybatisPlus入门

    springboot整合spring security入门 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架 它是用于保护基于Spring的应用程序的实际标准 Spring Security是一个框架 致力于
  • JDBC与PostgreSQL(三):存储过程和函数

    目录 一 过程化SQL简介 二 存储过程 三 函数 一 过程化SQL简介 SQL的一大优点就是高度非过程化 即开发人员只要面向结果编程 而无需关注具体的实现细节 然而高度非过程化使SQL语言缺少具体的业务逻辑控制功能 因此嵌入式SQL和过程
  • LeetCode 1812. 判断国际象棋棋盘中一个格子的颜色

    给你一个坐标 coordinates 它是一个字符串 如a1 b6 表示国际象棋棋盘中一个格子的坐标 下图是国际象棋棋盘示意图 如果所给格子的颜色是白色 请你返回 true 如果是黑色 请返回 false 给定坐标一定代表国际象棋棋盘上一个
  • 使用stata完成毕业实证论文的基础操作(上)

    想起本科毕业论文时要用 Stata 跑实证却一点都不会的痛苦 这学期学明白了一点 因此写个帖子帮助一点都不懂的小白上手使用 Stata 本文9000余字 非常详细地介绍了最基础的命令 上篇内容包括 Stata 简介 标签命名 格式设置 统计
  • 没有电商巨头有钱,又要挑战双十一流量高峰,一次低成本、高质量的大促是如何做到的?

    今年7月初 易车网数据库负责人田震愈发焦虑 此时 离易车818汽车狂欢节正式开幕只剩一月有余 但数据库压力测试结果并不理想 818汽车狂欢节乃易车网首次大促活动 并且采用台网互动的直播形式 涉及数据库的应用场景颇多 如实时数据看板 台网互动
  • 05libevent库下未决与非未决的解释

    05libevent库下未决与非未决的解释 以下是关于libevent学习的相关文章 01libevent库的下载与安装并且测试是否安装成功 02libevent库的整体框架思想 03libevent下通信的主要函数 04libevent库
  • mysql的SQL用法及Navicat的相关使用

    以下语法均在mysql 8 0下 一 建立约束 数据库中约束分为一下几种 主键约束 Primary Key constraint 要求主键列数据唯一 并且不允许为空 唯一约束 Unique constraint 要求该列唯一 允许为空 但只
  • 倾向得分匹配的stata命令_计量方法的适用条件汇总(二):倾向得分匹配

    独家揭秘 计量经济学的魅力与激情 陈强老师的高级计量现场班侧记 2019 5 1 如何学好高级计量 探秘陈强老师的高级计量及Stata现场班 2019 10 1 接上期推文 本期探讨倾向得分匹配的适用条件 倾向得分匹配 PSM 倾向得分匹配
  • 3、无人驾驶--路径规划算法:Floyd算法

    3 Floyd算法 1 算法简介 1 1 Floyd 佛洛依德 算法是解决给定的加权图中顶点间的最短路径的一种算法 可以正确处理有向图的最短路径问题 1 2 特点 Floyd算法是一种动态规划算法 稠密图效果最佳 节点间的连接权值可正可负
  • 模拟弱网测试方法总结

    我们测试某些需求 可能需要模拟弱网环境 下面介绍几种模拟弱网的方法 一 使用Fiddler 安装Fiddler 保证手机设备 笔记本IP都在同一个网段 Fiddler中在Rules Custom Rules中设置弱网的标准上传及下传10KB
  • Pandas是用于数据操作和分析的强大库

    Python中有许多流行的统计分析库 下面是其中一些主要的库及其主要用法 NumPy 用途 NumPy是Python中的数值计算库 提供多维数组对象和各种数学函数 用于高效处理大规模数据和执行数值计算 主要用法 创建和操作多维数组 执行数值
  • 比较好用的图床分享

    链接 https picx xpoet cn upload 网页上有教程 实用性强 转存很快 推荐
  • 2022版Web面试上岸手册,最新最细致!

    大裁员背景下 没什么比辞职后找不到工作更扎心 在行情好转前 前端程序员只能 猥琐发育 不轻易跳槽 同时要修炼内功 对八股文 底层源码 重点项目等进行查缺补漏 静待行情好转抓住机会 为帮大家在 就业寒冬 期更好的稳步提升 精进技术 以便保全自
  • MySQL中的日志

    查询日志 binlog redo log undo log介绍 目录 日志 MySQL中的4种日志 错误日志 查询日志和慢查询日志 二进制日志 binlog InnoDB 存储引擎的日志 重做日志 redo log 回滚日志 undo lo
  • clickhouse修改默认密码

    1 明文密码 vim etc clickhouse server users xml 找到下面的语句 增加明文密码
  • Centos7 配置Java开发(JDK)环境

    1 下载Java安装包 在Oracale Java 官网找到对应的JDK安装包 现在最常用 JDK1 8 而且现在的系统大都是64位 这里就以LInux64位为例 2 上传到Centos虚拟机 云主机中 将下载好的jdk for linux
  • Java入门(7)——循环和debug 调试

    循环 while 循环 格式 int i 0 初始化条件 while i lt 10 判断条件 System out println i 循环体 i 控制条件 执行顺序 第一次 第二次 第三次 最后一次 条件满
  • Vue2(路由)

    目录 一 路由原理 hash 二 路由安装和使用 vue2 三 路由跳转 四 路由的传参和取值 五 嵌套路由 六 路由守卫 最后 一 路由原理 hash 单页应用的路由模式有两种 1 哈希模式 利用hashchange 事件监听 url的h