Vue的路由和sass讲解

文章介绍了前端路由的三种模式:页面路由、hash路由和history路由,重点讲解了SPA(单页应用程序)和SSR(服务器渲染)的应用场景和优缺点。在Vue中展示了hash路由的实现,并给出了自定义模拟hash和history路由的示例。此外,还提到了Sass作为一种预编译CSS的工具,其特性与Less的区别。
摘要由CSDN通过智能技术生成

路由

  • 前端路由
  • 后端路由

前端路由

根据对于的url地址来渲染不同的内容

前端路由的分类

  • 页面路由 :通过页面的跳转来完成对应的切换,会刷新页面
  • hash路由 :通过对应hash值变化来控制内容的渲染(onhashchange),页面不刷新,只有一个页面
  • history路由 :通过对应的地址的变化来控制内容的渲染 (onpopstate) ,页面不刷新,只有一个页面

SPA(单页应用程序)

  • 单页应用程序 (single page application),顾名思义只有一个页面,通过控制渲染内容来完成对应的页面内容的切换。
  • 好处:对应页面的切换操作不再依赖于刷新,减少了页面的重绘和回流,单独一个页面打出来的包的大小也相对较小。
  • 坏处:不利于seo(电商网站不可能使用spa)。
  • react和vue都是为了减少对应的重绘和回流提高对应的性能,所以它一般都是采用对应的单页面应用。
  • SPA主要采用的路由模式为hash路由、history路由。默认情况下为hash模式。

SSR(服务器渲染)

  • 服务器渲染利于seo且速度快,但代码量大维护起来较为困难,对于服务器压力大。
  • 一般的大型电商网站都是采用 ssr 配合 spa 来共同作用。(前端采用的是 vue 的技术栈、配合 ssr 的框架nuxt.js;前端采用的是 react 配合 next.js)

vue中hash路由实现SPA

<!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.0">
    <title>Document</title>
    <script src="./vue.min.js"></script>
    <script src="./vue-router.js"></script>
    <style>
        /* 激活的链接 */
        .router-link-exact-active {
            color: red
        }
    </style>
</head>
<body>
    <!-- 容器 -->
    <div id="app">
        <!-- 路由链接 to指定的地址 router-link会解析成a标签-->
        <router-link to="/">去首页</router-link>
        <router-link to="/user">去用户页</router-link>
        <!-- 路由视图 显示的视图 router-view会解析你对应需要渲染的内容-->
        <router-view></router-view>
    </div>
    <script>
        //组件 渲染的内容
        let home = Vue.component('home', {
                template: '<div>首页</div>'
            })
            //渲染的内容
        let user = Vue.component('user', {
                template: '<div>用户页</div>'
            })
            //路由对象
        let router = new VueRouter({
            // mode:'hash', 模式默认为hash
            //路由配置 router 名词(路由对象) route 动词(路由配置) routes 多个(路由配置)
            routes: [
                //route规则
                {
                    name: 'home ', //名字
                    path: '/', //路由地址
                    component: home //组件 渲染什么
                }, {
                    name: 'user ',
                    path: '/user',
                    component: user
                }
            ]
        });
        new Vue({
            el: '#app',
            //传入路由配置 router
            // router:router
            router
        })
    </script>
</body>
</html>

自定义模拟hash路由实现SPA

  • 利用 onhashchange 事件监听 hash 值的变化
  • 通过对应的 routes 规则里面对应的 compoent 内容来渲染
class Vue {
    constructor(options) {
            //解构获取里面的el和对应的router
            let { el, router } = options
            this.el = document.querySelector(el) //元素
            this.router = router
                //调用解析a的方法 将这个this.el当作this
            this.router.analysisLink.call(this.el)
            this.router.listener(this.el)
        }
        //返回一个新的组件
    static component(name, { template }) {
        return new Component(name, template)
    }
}
//组件的构造
function Component(name, template) {
    this.name = name,
        this.template = template
}
//创建VueRouter的类
class VueRouter {
    constructor(options) {
            //解构获取对应的mode routes
            let { mode, routes } = options
            //如果mode没有默认为hash模式 如果mode有就是设置模式
            this.mode = mode ? mode : 'hash'
            this.routes = routes
        }
        //解析对应的router-link
    analysisLink() {
            //获取所有的router-link标签
            let links = this.querySelectorAll('router-link')
                //拿到它的to属性  变成对应的a to属性就是a的href
                //遍历
            Array.prototype.forEach.call(links, (v) => {
                //获取to属性的值
                let toValue = v.getAttribute('to')
                    //先创建对应的a标签 用a标签替换对应的links
                let target = document.createElement('a')
                target.href = `#${toValue}`
                target.innerHTML = v.innerHTML
                    //替换
                this.replaceChild(target, v)
            })
        }
        //解析router-view
        // 监听hash值得变化
    listener(el) {
        //进入就开始渲染
        window.onload = () => {
                location.hash = '/'
            }
            //变化的时候进行渲染
        window.onhashchange = () => {
            this.handler(el)
        }
    }
    handler(el) {
            //得到对应的hash值 
            let hash = location.hash.substring(1)
                //根据hash匹配对应的routes里面的path路径 找到对应的route配置
            let route = this.routes.find(({ path }) => {
                    return path == hash
                })
                //根据route里面component属性 找到对应渲染内容 template
                // route.component.template
                // 找到router-view标签进行innerHTML赋值
            let views = el.querySelectorAll('router-view')
            Array.from(views).forEach(v => {
                    v.innerHTML = route.component.template
                })
                //样式激活
            this.active(el)
        }
        //匹配当前的hash地址和对应的a标签的链接地址 添加对应的class
    active(el) {
        //得到hash值
        let hash = location.hash.substring(1)
            //得到所有的a标签
        let links = el.querySelectorAll('a')
            // 进行匹配
            //排他
        Array.prototype.forEach.call(links, v => {
            v.className = ''
        })
        Array.prototype.find.call(links, (v) => {
            return v.href.split('#')[1] == hash
        }).className = 'router-link-exact-active'
    }
}

自定义模拟history路由实现SPA

  • onpopstate 进行监听
  • 将 a 的内容全部重写,通过 pushState 来完成路径变化
class Vue {
    constructor(options) {
            //解构获取里面的el和对应的router
            let { el, router } = options
            this.el = document.querySelector(el) //元素
            this.router = router
                //调用解析a的方法 将这个this.el当作this
            this.router.analysisLink.call(this.el)
            this.router.listener(this.el)
        }
        //返回一个新的组件
    static component(name, { template }) {
        return new Component(name, template)
    }
}
//组件的构造
function Component(name, template) {
    this.name = name,
        this.template = template
}
//创建VueRouter的类
class VueRouter {
    constructor(options) {
            //解构获取对应的mode routes
            let { mode, routes } = options
            //如果mode没有默认为hash模式 如果mode有就是设置模式
            this.mode = mode ? mode : 'hash'
            this.routes = routes
        }
        //解析对应的router-link
    analysisLink() {
            //获取所有的router-link标签
            let links = this.querySelectorAll('router-link')
                //拿到它的to属性  变成对应的a to属性就是a的href
                //遍历
            Array.prototype.forEach.call(links, (v) => {
                //获取to属性的值
                let toValue = v.getAttribute('to')
                    //先创建对应的a标签 用a标签替换对应的links
                let target = document.createElement('a')
                target.href = `${toValue}`
                target.innerHTML = v.innerHTML
                    //替换
                this.replaceChild(target, v)
            })
        }
        //处理对应的a标签
    handlerA(el) {
            //获取所有的a标签
            let links = el.querySelectorAll('a')
            let that = this
                //给a标签添加点击事件
            Array.prototype.forEach.call(links, (link) => {
                link.onclick = function(e) {
                    e = e || window.event
                        //禁止刷新
                    e.preventDefault();
                    //点击对应的值 通过对应的pushState 来修改对应的页面
                    history.pushState('', '', this.href)
                        //渲染
                    that.handler(el)
                }
            })
        }
        //解析router-view
        // 监听对应的state的变化
    listener(el) {
        //监听a的点击事件
        this.handlerA(el)
            //变化的时候进行渲染
        window.onpopstate = () => {
            this.handler(el)
        }
    }
    handler(el) {
            //得到对应的地址
            let localPath = location.pathname
                //根据hash匹配对应的routes里面的path路径 找到对应的route配置
            let route = this.routes.find(({ path }) => {
                    return path == localPath
                })
                //根据route里面component属性 找到对应渲染内容 template
                // route.component.template
                // 找到router-view标签进行innerHTML赋值
            let views = el.querySelectorAll('router-view')
            Array.from(views).forEach(v => {
                    v.innerHTML = route.component.template
                })
                //样式激活
            this.active(el)
        }
        //匹配当前的地址和对应的a标签的链接地址 添加对应的class
    active(el) {
        //得到地址
        let localPath = location.pathname
            //得到所有的a标签
        let links = el.querySelectorAll('a')
            // 进行匹配
            //排他
        Array.prototype.forEach.call(links, v => {
            v.className = ''
        })
        Array.prototype.find.call(links, (v) => {
            let url = new URL(v.href)
            return url.pathname == localPath
        }).className = 'router-link-exact-active'
    }
}

Sass

Sass它底层采用的是python环境 Ruby语言书写,支持基本的css语法,最终还是会编译成对应的css,它在node环境中不需要你手动编译它会自动编译(sass-load的包)。

Sass 是一款强化 CSS 的辅助工具,它在 CSS 语法的基础上增加了变量 (variables)、嵌套 (nested rules)、混合 (mixins)、导入 (inline imports) 等高级功能

Sass和Less的区别和共性 *

  • Sass和Less都是动态样式语言,用来预编译css,都会创建一个 .css文件
  • Less基于JavaScript,在客户端处理。
  • Sass基于Ruby,在服务器端处理。
  • Sass有函数、进程控制、数组的概念
  • Less变量使用@定义;Sass使用$定义,它定义的变量有全局和局部之分,并且有优先级。
  • Less是通过客户端处理的,Sass是通过服务端处理,相比较之下Less解析会比Sass慢一点
  • Sass中有以下进程控制

        -条件:@if @else;

        -循环遍历:@for @each @while
        -继承:@extend
        -引用:@import

Less和Sass在语法上有些共性,比如下面这些:
1、混入(Mixins)——class中的class;
2、参数混入——可以传递参数的class,就像函数一样;
3、嵌套规则——Class中嵌套class,从而减少重复的代码;
4、运算——CSS中用上数学;
5、颜色功能——可以编辑颜色;
6、名字空间(namespace)——分组样式,从而可以被调用;
7、作用域——局部修改样式;
8、JavaScript 赋值——在CSS中使用JavaScript表达式赋值。

sass的编译环境

  • 借助node来进行编译

按照对应的sass及sass-load

npm i sass,sass-load

  • 借助第三方插件来进行编译

vscode插件:live Sass Compiler、easy sass

sass的书写

  • sass后缀:以缩进作为区分,没有分号和大括号(:、{}),跟stylus一样

sass编译前:

        div
                color:#fff
                a
                        color:#ccc

编译后:

        div {
                color: #fff;
        }
        div a {
                color: #ccc;
        }

  • scss后缀:和css语法一样

scss编译前:

        div{
                color:#000;
                a{
                        color:#333;
                }
        }

编译后:

        div {
                color: #000;
        }
        div a {
                color: #333;
        }

Sass的相关应用

  • 使用 $ 定义变量

  • 支持运算符 :+ - * / %

  • 注释支持:// 单行注释不会被编译、/**/ 多行注释会被编译
  • 条件判断 :@if @else

  • 伪类选择器:&:hover,需要加&表示自身
//伪类
#content {
    color: yellow;
    &:hover {
        color: palevioletred;
    }
}

// 编译后
#content {
  color: yellow;
}

#content:hover {
  color: palevioletred;
}
  • 函数 
  • @function 定义函数
  • @return 返回对应的内容

  

  • 循环
  • @for 从某个值到某个值:@for 变量 from 1 to 5
  • @while :@while 变量 > 0
  • @each 相当于forEach:@each 变量 in 数组

  • 混入器:用于设置对应的内容
  • @mixin 定义混入器
  • @include 引入混入器
//    混入器的使用
@mixin a {
    background: red;
}

@mixin border($size, $style, $color) {
    border: $size $style $color;
}

@mixin shadow($offsetleft:10px, $offsettop:20px, $width:30px, $color:green) {
    box-shadow: $offsetleft $offsettop $width $color;
}

div {
    font-size: 18px;
    @include a();
    @include border(1px, solid, red);
    @include shadow()
}
//  编译后
div {
  font-size: 18px;
  background: red;
  border: 1px solid red;
  box-shadow: 10px 20px 30px green;
}
  • 模块化:@import 省略后缀名 (css文件还是sass文件还是scss都能省略后缀名),无需导出,因为默认导出。
@import "foo.css";
@import "foo" screen;
@import "http://foo.com/bar";
@import url(foo);
  • 继承:@extend 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值