精华内容
下载资源
问答
  • 前面说了Bootstrap4的下载和简单使用,现在我们接着往下学习,Bootstrap4的响应式布局主要依靠栅格系统来实现的。面老K先来讲解一下Bootstrap4的栅格系统,让你能够更快的了解Bootstrap4.(PS:更详细的介绍请访问原K...

    前面说了Bootstrap4的下载和简单使用,现在我们接着往下学习,Bootstrap4的响应式布局主要依靠栅格系统来实现的。面老K先来讲解一下Bootstrap4的栅格系统,让你能够更快的了解Bootstrap4.(PS:更详细的介绍请访问原K先生的博客)

    Bootstrap4栅格系统

    栅格系统是基于一个12列、有5种响应尺寸(对应不同的屏幕)的布局。Bootstrap4栅格系统共有五个类:

    .col- 针对所有设备

    .col-sm- 平板 - 屏幕宽度等于或大于 576px

    .col-md- 桌面显示器 - 屏幕宽度等于或大于 768px)

    .col-lg- 大桌面显示器 - 屏幕宽度等于或大于 992px)

    .col-xl- 超大桌面显示器 - 屏幕宽度等于或大于 1200px)

    这些类的意思通俗点说就是,当你同时使用这些类的时候,它会根据你的屏幕大小来使相应的类生效。

    下面我们再来看一下,这些类是怎么使用的

    这个div中放置轮播图片,并且它占9列

    展开全文
  • 拉勾教育WEB前端高薪训练营数据响应式的核心原理Vue 2.xVue 2.x深入响应式原理MDN - Object.defineProperty浏览器兼容 IE8 以上(不兼容 IE8)// 模拟 Vue 中的 data 选项 let data = { msg: 'hello' } // 模拟...

    拉勾教育WEB前端高薪训练营

    数据响应式的核心原理

    Vue 2.x

    • Vue 2.x深入响应式原理
    • MDN - Object.defineProperty
    • 浏览器兼容 IE8 以上(不兼容 IE8)
    // 模拟 Vue 中的 data 选项
        let data = {
          msg: 'hello'
        }
    
        // 模拟 Vue 的实例
        let vm = {}
    
        // 数据劫持:当访问或者设置 vm 中的成员的时候,做一些干预操作
        Object.defineProperty(vm, 'msg', {
          // 可枚举(可遍历)
          enumerable: true,
          // 可配置(可以使用 delete 删除,可以通过 defineProperty 重新定义)
          configurable: true,
          // 当获取值的时候执行
          get () {
            console.log('get: ', data.msg)
            return data.msg
          },
          // 当设置值的时候执行
          set (newValue) {
            console.log('set: ', newValue)
            if (newValue === data.msg) {
              return
            }
            data.msg = newValue
            // 数据更改,更新 DOM 的值
            document.querySelector('#app').textContent = data.msg
          }
        })
    
        // 测试
        vm.msg = 'Hello World'
        console.log(vm.msg)
    • 如果有一个对象中多个属性需要转换 getter/setter 如何处理?

    Vue 3.x

    • MDN - Proxy
    • 直接监听对象,而非属性
    • ES 6中新增,IE 不支持,性能由浏览器优化
    // 模拟 Vue 中的 data 选项
    let data = {
        msg: 'hello',
        count: 0
      }
    
    // 模拟 Vue 实例
     let vm = new Proxy(data, {
       // 执行代理行为的函数
       // 当访问 vm 的成员会执行
       get (target, key) {
         console.log('get, key: ', key, target[key])
         return target[key]
       },
       // 当设置 vm 的成员会执行
       set (target, key, newValue) {
         console.log('set, key: ', key, newValue)
         if (target[key] === newValue) {
           return
         }
         target[key] = newValue
         document.querySelector('#app').textContent = target[key]
       }
     })
    
     // 测试
     vm.msg = 'Hello World'
     console.log(vm.msg)

    发布订阅模式

    • 发布/订阅模式
      • 订阅者
      • 发布者
      • 信号中心
        我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern)
    • Vue 的自定义事件
      • https://cn.vuejs.org/v2/guide/migration.html#dispatch-%E5%92%8C-broadcast-%E6%9B%BF%E6%8D%A2

    模拟 Vue 自定义事件的实现

    // 事件触发器
    class EventEmitter {
      constructor () {
        // { 'click': [fn1, fn2], 'change': [fn] }
        this.subs = Object.create(null)
      }
    
      // 注册事件
      $on (eventType, handler) {
        this.subs[eventType] = this.subs[eventType] || []
        this.subs[eventType].push(handler)
      }
    
      // 触发事件
      $emit (eventType) {
        if (this.subs[eventType]) {
          this.subs[eventType].forEach(handler => {
            handler()
          })
        }
      }
    }
    
    // 测试
    let em = new EventEmitter()
    em.$on('click', () => {
      console.log('click1')
    })
    em.$on('click', () => {
      console.log('click2')
    })
    
    em.$emit('click')

    观察者模式

    • 观察者(订阅者) – Watcher
      • update():当事件发生时,具体要做的事情
    • 目标(发布者) – Dep
      • subs 数组:存储所有的观察者
      • addSub():添加观察者
      • notify():当事件发生,调用所有观察者的 update() 方法
    • 没有事件中心
    // 发布者-目标
    class Dep {
       constructor () {
         // 记录所有的订阅者
         this.subs = []
       }
       // 添加订阅者
       addSub (sub) {
         if (sub && sub.update) {
           this.subs.push(sub)
         }
       }
       // 发布通知
       notify () {
         this.subs.forEach(sub => {
           sub.update()
         })
       }
     }
     // 订阅者-观察者
     class Watcher {
       update () {
         console.log('update')
       }
     }
    
     // 测试
     let dep = new Dep()
     let watcher = new Watcher()
    
     dep.addSub(watcher)
    
     dep.notify()

    总结

    • 观察者模式是由具体目标调度,比如当事件触发,Dep 就会去调用观察者的方法,所以观察者模 式的订阅者与发布者之间是存在依赖的。
    • 发布/订阅模式由统一调度中心调用,因此发布者和订阅者不需要知道对方的存在

    Vue 响应式原理模拟

    • Vue
      • 把 data 中的成员注入到 Vue 实例,并且把 data 中的成员转成 getter/setter
    • Observer
      • 能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知 Dep
    • Compiler
      • 解析每个元素中的指令/插值表达式,并替换成相应的数据
    • Dep
      • 添加观察者(watcher),当数据变化通知所有观察者
    • Watcher
      • 数据变化更新视图

    Vue

    • 功能
      • 负责接收初始化的参数(选项)
      • 负责把 data 中的属性注入到 Vue 实例,转换成 getter/setter
      • 负责调用 observer 监听 data 中所有属性的变化
      • 负责调用 compiler 解析指令/插值表达式
    • 代码
    class Vue{
    	constructor(options) {
    		// 1. 通过属性保存选项的数据
    	    this.$options = options
    		if (options.methods) { 
    			this.initMethods(this, options.methods) 
    		}
    		this.$data = options.data
    		this.$el = typeof options.el === 'string' ? document.querySelector(options.el) : options.el,
    		 // 2. 把data中的成员转换成getter和setter,注入到vue实例中
    		 this._proxyData(this.$data)
    		 // 3. 调用observer对象,监听数据的变化
    		 new Observer(this.$data)
    		 // 4. 调用compiler对象,解析指令和差值表达式
    		 new Compiler(this)
    	}
    	initMethods(vm, methods){
    		for(let key in methods){
    			vm[key] = typeof methods[key] == 'function' && methods[key]
    		}
    	}
    	_proxyData(data){
    		// 遍历data中的所有属性
    		Object.keys(data).forEach(key => {
    			// 把data的属性注入到vue实例中
    			Object.defineProperty(this,key,{
    				enumerable: true,
    				configurable: true,
    				get(){
    					return data[key]
    				},
    				set(newValue){
    					if(newValue === data[key]) return
    					data[key] = newValue
    				}
    			})
    		})
    	}
    }

    Observer

    • 功能
      • 负责把 data 选项中的属性转换成响应式数据
      • data 中的某个属性也是对象,把该属性转换成响应式数据
      • 数据变化发送通知
    • 代码
    class Observer{
    	constructor(data) {
    	    this.walk(data)
    	}
    	walk(data){
    		// 1. 判断data是否是对象
    		if(!data || typeof data !== 'object') return
    		// 2. 遍历data对象的所有属性
    		Object.keys(data).forEach(key => {
    			this.defineReactive(data, key, data[key])
    		})
    	}
    	defineReactive(obj, key, val){
    		let that = this
    		// 负责收集依赖
    		let dep = new Dep()
    		//如果val是对象,将其内部也转化为响应式
    		this.walk(val)
    		Object.defineProperty(obj,key,{
    			enumerable: true,
    			configurable: true,
    			get(){
    				// 收集依赖
    				Dep.target && dep.addSub(Dep.target)
    				return val
    			},
    			set(newValue){
    				if(newValue === val) return
    				val = newValue
    				that.walk(newValue)
    				// 发送通知
    				dep.notify()
    			}
    		})
    	}
    }

    Compiler

    • 功能
      • 负责编译模板,解析指令/插值表达式
      • 负责页面的首次渲染
      • 当数据变化后重新渲染视图
    • 代码
    class Compiler{
    	constructor(vm) {
    	    this.el = vm.$el
    		this.vm = vm
    		this.compile(this.el)
    	}
    	// 编译模板,处理文本节点和元素节点
    	compile(el){
    		let childNodes = el.childNodes
    		Array.from(childNodes).forEach(node => {
    			//处理文本节点
    			if(this.isTextNode(node)){
    				this.compileText(node)
    			}else if(this.isElementNode(node)){
    				//处理元素节点
    				this.compileElement(node)
    			}
    			
    			// 判断当前节点下是否有子节点,有子节点时递归遍历compile
    			if(node.childNodes && node.childNodes.length){
    				this.compile(node)
    			}
    		})
    	}
    	// 编译文本节点
    	compileText(node){
    		let reg = /{{(.+?)}}/
    		let value = node.textContent
    		if(reg.test(value)){
    			let key = RegExp.$1.trim()
    			node.textContent = value.replace(reg,this.vm[key]) 
    		}
    	}
    	// 编译元素节点,处理指令
    	compileElement(node){
    		let onRE = /^@|^v-on:/
    		Array.from(node.attributes).forEach(attr => {
    			let attrName = attr.name
    			if(onRE.test(attrName)){//处理v-on
    				attrName = attrName.replace(onRE, '')
    				let key = attr.value
    				this.addHandler(node,attrName,this.vm[key])
    			}else if(this.isDirective(attrName)){
    				// v-text --> text
    				attrName = attrName.substr(2)
    				let key = attr.value
    				this.update(node, key, attrName)
    			}
    		}) 
    	}
    	addHandler(el, handleName, handle){
    		el.addEventListener(handleName,handle)
    	}
    	update(node, key, attrName){
    		let updateFn = this[attrName+'Updater']
    		updateFn && updateFn.call(this,node, this.vm[key], key)
    	}
    	// 处理 v-text 指令
    	textUpdater(node, value, key){
    		node.textContent = value
    		new Watcher(this.vm, key, (newValue) => {
    		  node.textContent = newValue
    		})
    	}
    	// 处理 v-model 指令
    	modelUpdater(node, value, key){
    		node.value = value
    		new Watcher(this.vm, key, (newValue) => {
    		  node.value = newValue
    		})
    		// 双向绑定
    		node.addEventListener('input', () => {
    		  this.vm[key] = node.value
    		})
    	}
    	// 处理 v-html 指令
    	htmlUpdater(node, value, key){
    		node.innerHTML = value
    		new Watcher(this.vm, key, (newValue) => {
    		  node.innerHTML = newValue
    		})
    	}
    	// 判断元素属性是否是指令
    	isDirective (attrName) {
    	  return attrName.startsWith('v-')
    	}
    	//判断是否为文本节点
    	isTextNode(node){
    		return node.nodeType === 3
    	}
    	//判断是否为元素节点
    	isElementNode(node){
    		return node.nodeType === 1
    	}
    }
    

    Dep(Dependency)

    • 功能
      • 收集依赖,添加观察者(watcher)
      • 通知所有观察者
    • 代码
    class Dep{
    	constructor(){
    		// 储存所有观察者
    		this.subs = []
    	}
    	// 添加观察者
    	addSub(sub){
    		if(sub && sub.update){
    			this.subs.push(sub)
    		}
    	}
    	// 发送通知
    	notify(){
    		this.subs.forEach(sub => {
    			sub.update()
    		})
    	}
    }

    Watcher

    be5fb1a1bf4ed2d7069c8a92866b3798.png
    • 功能
      • 当数据变化触发依赖, dep 通知所有的 Watcher 实例更新视图
      • 自身实例化的时候往 dep 对象中添加自己
    • 代码
    class Watcher{
    	constructor(vm, key, cb) {
    	    this.vm = vm
    		this.key = key
    		this.cb = cb
    		
    		// 把watcher对象记录到Dep类的静态属性target
    		Dep.target = this
    		// 触发get方法,在get方法中会调用addSub
    		this.oldValue = this.vm[this.key]
    		Dep.target = null
    	}
    	// 当数据发生变化的时候更新视图
    	update(){
    		let newValue = this.vm[this.key]
    		if(newValue === this.oldValue) return
    		this.cb(newValue)
    	}
    }

    总结

    • 通过下图回顾整体流程

    74b2dc0ff57c68f609cb426910cfb35c.png
    • Vue
      • 记录传入的选项,设置 d a t a / data/data/el
      • 把 data 的成员注入到 Vue 实例
      • 负责调用 Observer 实现数据响应式处理(数据劫持)
      • 负责调用 Compiler 编译指令/插值表达式等
    • Observer
      • 数据劫持
        • 负责把 data 中的成员转换成 getter/setter
        • 负责把多层属性转换成 getter/setter
        • 如果给属性赋值为新对象,把新对象的成员设置为 getter/setter
      • 添加 Dep 和 Watcher 的依赖关系
      • 数据变化发送通知
    • Compiler
      • 负责编译模板,解析指令/插值表达式
      • 负责页面的首次渲染过程
      • 当数据变化后重新渲染
    • Dep
      • 收集依赖,添加订阅者(watcher)
      • 通知所有订阅者
    • Watcher
      • 自身实例化的时候往dep对象中添加自己
      • 当数据变化dep通知所有的 Watcher 实例更新视图

    参考

    • 深入响应式原理
    • https://github.com/DMQ/mvvm
    展开全文
  • 12、Bootstrap响应式布局 这节课我们完成对博客列表页的修改 想要实现的效果如图 响应式布局:根据屏幕的大小自动地控制调整页面布局 在www.bootcss.com页面的“全局CSS样式”——“栅格系统”、“栅格参数”: ...

    12、Bootstrap响应式布局

    这节课我们完成对博客列表页的修改
    想要实现的效果如图
    在这里插入图片描述

    响应式布局:根据屏幕的大小自动地控制调整页面布局

    在www.bootcss.com页面的“全局CSS样式”——“栅格系统”、“栅格参数”:
    分为四种屏幕大小:xs(手机)、sm(平板)、md(桌面显示器)、lg(大桌面显示器)。“实例:从堆叠到水平排列”:.col-md-8表示:列-屏幕大小-占多少列宽度,
    在这里插入图片描述

    1、Bootstrap的响应式设计

    • 适应4种屏幕大小、12列布局
      • < 768px(手机)
      • > = 768px(平板)
      • >= 992px(小尺寸显示器)
      • >= 1200px(大尺寸显示器)
        在这里插入图片描述

    “布局容器”

    2、基本结构

    <div class="container">
    	<div class="row">
    		<div class="col-xx-*"></div>
    		<div class="col-xx-*"></div>
    	</div>
    </div>
    

    在这里插入图片描述

    先改博客列表,打开blog_list.html

    注意 ,博客具体分类这里,前面处理方法没有传递给它,是由前面blog/views.py中的blog_list中的context['blogs'],这里传了一个博客。这里有一个问题,博客列表的模板页面在mysite/templates/blog目录下,需要到mysite/blog/下找到views.py,这里出现了一个纰漏,前面说过,跟项目比较紧密的文件,放到全局静态文件夹里面,而这个模板页面文件跟app比较紧密一些,那么我们还是放到app目录下会好一点。所以我们将mysite/templates/blog整个文件夹剪切到mysite/blog/templates下
    在这里插入图片描述
    在这里插入图片描述
    修改views.py如下:
    在这里插入图片描述
    打开blog_list.html修改如下:
    在这里插入图片描述

    <!-- C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\templates\blog\blog_list.html -->
    {% extends 'base.html' %}	
    
    {# 页面标题 #}
    {% block title %}
    	我的网站	
    {% endblock %}
    
    {% block nav_blog_active %}active{% endblock %}
    
    {# 页面内容 #}
    {% block content %}
    	<div class="container">
    		<div class="row">
    			<div class="col-md-8">
    				{% for blog in blogs %}	
    					<a href="{% url 'blog_detail' blog.pk %}"> 
    						<h3>{{ blog.title }}</h3> 
    					</a> 
    					<p>{{ blog.content | truncatechars:50}}</p>	
    				{% empty %}
    					<p>-- 暂无博客,敬请期待 --</p>
    				{% endfor %}
    				<p>一共有{{ blogs | length}}	篇博客</p>
    			</div>	
    
    			<div class="col-md-4">
    				<h4>博客分类</h4>
    				<ul>
    					{% for blog_type in blog_types %}
    						<li>
    							<a href="{% url 'blogs_with_type' blog_type.pk %}">{{ blog_type.type_name }}</a> 
    						</li>
    					{% empty %}
    						<li>暂无分类</li>
    					{% endfor %}
    				</ul>
    			</div>					
    		</div>
    	</div>
    
    {% endblock %}
    

    刷新页面效果如下:
    在这里插入图片描述
    下面我们要对这两块进行更改。我们看一下官方文档里面的“组件”——“面板”
    修改blog_list.html如下:
    在这里插入图片描述

    <div class="col-md-4">
    	<div class=" panel panel-default">
    		<div class="panel-heading">博客分类</div>
    		<div class="panel-body">
    			<ul>
    				{% for blog_type in blog_types %}
    					<li><a href="{% url 'blogs_with_type' blog_type.pk %}">{{ blog_type.type_name }}</a> 
    					</li>
    				{% empty %}
    					<li>暂无分类</li>
    				{% endfor %}
    			</ul>
    		</div>
    	</div>
    </div>
    

    刷新页面:
    在这里插入图片描述
    这里博客分类前面的点,我们想要去掉,这就涉及到控制这里的样式,写到base_list.html中去
    在这里插入图片描述
    在这里插入图片描述
    同样的,我们对左边的博客列表进行相同的处理
    在这里插入图片描述
    在这里插入图片描述
    我们缩放屏幕发现,这一行两列会被压缩到两行,因为我们只是设置了md中等屏幕样式,而小屏幕我们没有设置,它是默认的按照12列去显示的,所以我们需要加上小屏幕的设置,col-sm-8我们设置为8和4,然后拉窄页面看看,是生效的。这里如果我们只写小屏幕sm,不写md,也可以,因为它是由小往大去适用的,而刚刚我们写了大的md,而没有写小的sm,是不生效中屏幕的。那我们超小屏幕,这根据需求定,想不想让博客分类栏显示在下一行,或直接不显示这一栏,这里我们先设为让它不显示,即设置它对应的超小屏幕为0 col-xs-0,发现会出问题。那么该怎么去设置呢,这里有另外一个东西,在官网文档的“响应式工具”这里“可用的类”里面有“可见”或者“隐藏”,我们将超小屏幕下设为隐藏就可以hidden-xs
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    这里,关于列的响应式布局大概讲到这个地方。

    接着我们往下将另外一个内容,将上面ul的样式保存到静态文件夹里面,修改blog_list.html如下,添加代码,加载静态文件:
    在这里插入图片描述
    给ul加一个class,便于后面css样式设置
    在这里插入图片描述
    在static目录下新建blog.css,将前面ul里面的css样式剪切过来,如下内容:
    在这里插入图片描述
    这里又出现了一个新的问题,和刚刚templates模板的问题差不多,我们这个css文件是要放到公共的static目录里面呢,还是要放到blog目录下呢?两者都可以,但为了统一和app的可维护性,我们可以放到app里面的目录,在blog目录下创建static文件夹,把blog.css剪切到这个static目录下
    在这里插入图片描述
    刷新页面,出现了not found的错误,这跟django的机制有关系(刚刚templates同样也有这个问题),原因是多个app可能模板文件名就会重复,重复了之后django找到第一个文件后就不再找第二个同名文件了。

    3、Django静态文件命名空间

    • 为了避免同名冲突问题
    • static/app/xxx.css
      在这里插入图片描述

    为了解决这个冲突,需要一个命名空间。命名空间是这么去建立的:在刚刚创建的static下新建一文件夹,这个文件夹名称就是app名称(这里是blog),然后将blog.css放入到blog文件夹下面。然后修改一下blog_list.html里面的路径
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    刷新页面,发现还是这个问题,原因是我们需要重启一下本地服务python manage.py runserver
    在这里插入图片描述

    接下来我们完善左边的博客列表样式,参考Bootstrap

    打开blog_list.html:
    在这里插入图片描述

    <!-- C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\templates\blog\blog_list.html -->
    {% extends 'base.html' %}
    
    {# 页面标题 #}
    {% block title %}
    	我的网站	
    {% endblock %}
    
    {% block nav_blog_active %}active{% endblock %}
    
    {% load staticfiles %}
    {% block header_extends %}
    	<link rel="stylesheet" type="text/css" href="{% static 'blog/blog.css' %}">
    {% endblock %}
    
    {# 页面内容 #}
    {% block content %}
    	<div class="container">
    		<div class="row">
    			<div class="col-xs-12 col-sm-8 col-md-8 col-lg-10">
    				<div class=" panel panel-default">
    					<div class="panel-heading">{% block blog_list_title %}博客列表(一共有{{ blogs | length}}篇博客){% endblock %}</div>
    					<div class="panel-body">
    						{% for blog in blogs %}
    							<div class="blog">
    								<h3><a href="{% url 'blog_detail' blog.pk %}">{{ blog.title }}</a></h3>
    								<p class="blog-info">
    									<span class="glyphicon glyphicon-tag"></span><a href="{% url 'blogs_with_type' blog.blog_type.pk %}">{{ blog.blog_type }}</a>
    									<span class="glyphicon glyphicon-time"></span>{{ blog.created_time|date:"Y-m-d" }}
    								</p>
    								<p>{{ blog.content | truncatechars:120}}</p>
    							</div>	
    						{% empty %}
    							<div class="blog">
    								<h3>暂无博客,敬请期待</h3>
    							</div>
    						{% endfor %}
    					</div>
    				</div>
    			</div>
    			<div class="hidden-xs col-sm-4 col-md-4 col-lg-2">
    				<div class=" panel panel-default">
    					<div class="panel-heading">博客分类</div>
    					<div class="panel-body">
    						<ul class="blog-types">
    							{% for blog_type in blog_types %}
    								<li><a href="{% url 'blogs_with_type' blog_type.pk %}">{{ blog_type.type_name }}</a> 
    								</li>
    							{% empty %}
    								<li>暂无分类</li>
    							{% endfor %}
    						</ul>
    					</div>
    				</div>
    			</div>					
    		</div>
    	</div>
    {% endblock %}
    

    修改blog.css如下:

    ul.blog-types{
    	list-style-type: none;
    }
    div.blog:not(:last-child){	/*最后一个元素不设置成这个样式*/
    	margin-bottom: 2em;
    	padding-bottom: 1em;
    	border-bottom: 1px solid #eee;
    }
    div.blog h3{
    	margin-top: 0.5em;
    }
    div.blog p.blog.info{
    	margin-bottom: 0;
    }
    

    在这里插入图片描述
    在这里插入图片描述
    我们点击“随笔”这个分类,进入博客分类列表页面如下:
    在这里插入图片描述
    对于这个页面,我们引用刚刚blog_list.html的模板样式,只需要替换掉“博客列表”这一块,所以在blog_list.html的这里添加一行block块的代码,然后修改blogs_with_type.html如下:
    在这里插入图片描述

    <!-- C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\templates\blog\blogs_with_type.html -->
    {% extends 'blog/blog_list.html' %}	
    
    {# 页面标题 #}
    {% block title %}
    	{{ blog_type.type_name }}
    {% endblock %}
    
    {% block blog_list_title %}
    	分类:{{ blog_type.type_name }}(一共有{{ blogs | length}}篇博客)
    {% endblock %}
    

    刷新页面:
    在这里插入图片描述
    而右边的“博客分类”没有显示分类,因为我们处理方法里面对应的分类信息blogs_with_type方法少了这一块(而views.py中blog_list方法里面是有的),所以没有,我们打开views.py,修改如下:
    在这里插入图片描述
    然后再刷新页面:
    在这里插入图片描述

    接下来我们完善一下具体的博客页面,
    打开blog_detail.html修改如下:
    在这里插入图片描述
    修改blog.css如下:
    在这里插入图片描述
    在这里插入图片描述

    这节内容大概讲到这么些知识:主要是Bootstrap响应式布局、static/templates处理、命名空间(避免文件之间的冲突)、分类页面延用博客列表页面的样式

    展开全文
  • 使用Scss敲一个响应式网格布局bootstarp 许多人都用过,是一个非常丰富的框架,那么,现在闲来无事,模仿 bootstrap 敲一个简单的响应式布局框架。1. 确定响应确立需要响应的屏幕设备宽度,仿 bootstrap 设计 超小...

    使用Scss敲一个响应式网格布局

    bootstarp 许多人都用过,是一个非常丰富的框架,那么,现在闲来无事,模仿 bootstrap 敲一个简单的响应式布局框架。

    1. 确定响应

    确立需要响应的屏幕设备宽度,仿 bootstrap 设计

    1. 超小屏幕的手机 576px
    2. 小型屏幕的平板电脑 768px
    3. 中型屏幕的台式电脑 992px
    4. 大型屏幕的台式电脑 1200px
    // 需响应屏幕宽度的变量
    $xs: 576px;
    $sm: 768px;
    $md: 992px;
    $lg: 1200px;

    2. 确定网格数

    bootstrap 是有 12 列的网格,但我往往在开发的时候需要用到更加细致的布局,所以现在我要整个 24 列的。

    $column-count: 24;

    3. 设置网格 DIV 和每个列的占比

    // 设置网格 DIV
    .grid {
        display: grid;
        width: 100%;
        grid-template-columns: repeat($column-count,1fr);
    }
    
    // 每个列的占比
    @for $i from 1 through $column-count {
        .grid-col-#{$i} {
            grid-column: span $i;
            width: 100%;
            box-sizing: border-box;
        }
    }

    4. 响应式设置, xs sm md lg 四个屏幕的响应式

    // xs
    @media (min-width: $xs) {
        @for $i from 1 through $column-count {
            .grid-col-xs-#{$i} {
                grid-column: span $i;
            }
        }
    }
    // sm
    @media (min-width: $sm) {
        @for $i from 1 through $column-count {
            .grid-col-sm-#{$i} {
                grid-column: span $i;
            }
        }
    }
    // md
    @media (min-width: $md) {
        @for $i from 1 through $column-count {
            .grid-col-md-#{$i} {
                grid-column: span $i;
            }
        }
    }
    // lg
    @media (min-width: $lg) {
        @for $i from 1 through $column-count {
            .grid-col-lg-#{$i} {
                grid-column: span $i;
            }
        }
    }

    5. 编译并实践

    使用 class

    <div class="grid">
    <div class="grid-col-24 grid-col-xs-20 grid-col-sm-12 grid-col-md-6 grid-col-lg-1" style="background-color: blueviolet;"></div>
    <div class="grid-col-24 grid-col-xs-4 grid-col-sm-12 grid-col-md-18 grid-col-lg-23" style="background-color: red;"></div>
    <div class="grid-col-24 grid-col-xs-4 grid-col-sm-12 grid-col-md-18 grid-col-lg-23" style="background-color: yellow;"></div>
    <div class="grid-col-24 grid-col-xs-20 grid-col-sm-12 grid-col-md-6 grid-col-lg-1" style="background-color: blue;"></div>
    </div>

    效果

    默认 效果 grid-col

    bf7f412f26acc23e378d25a8bfa99ee8.png

    1. 超小屏幕的手机 < 576px

    537775f72ec80fba018d8ed6a367c9cf.png

    2. 小型屏幕的平板电脑 < 768px

    fc0dcea055bbfceb9df43365334dbc4e.png

    3. 中型屏幕的台式电脑 < 992px

    38e9710871a341e2eee679e9fa6024fe.png

    4. 大型屏幕的台式电脑 < 1200px

    7cf20a813c258683e67b5258741248bb.png

    End

    GitHub 下载实例github.com
    展开全文
  •  这几天公司要求网站实现响应式布局,所以对响应式布局进行了相对全面的了解,并做了几个实例。  转载请注明源地址,谢谢^_^,http://www.cnblogs.com/liu-zhen/p/4493679.html 响应式布局介绍 参考:维基...
  • 响应式布局:就是一个网站为了兼容多个终端,而不是为每个终端制定特定的版本。这个概念是为解决移动互联网浏览而诞生的。...实现最基本的Bootstrap响应式布局实例:http://www.cnblogs.com/haogj/p/4980353.html
  • <link rel="stylesheet"href="bootstrap-3.3.5/dist/css/bootstrap.min.css"/> .container p { border:1px solid #c3c3c3; padding:5px; } 土耳其方面击落俄罗斯战机的事件仍在继续发酵的同时,...
  • 下面我们列出了如何禁用这一特性,就像这个非响应式布局实例页面一样。 禁止响应式布局有如下几步: 移除 此 CSS 文档中提到的设置浏览器视口(viewport)的标签:。通过为 .container 类设置一个 width ...
  • 下面我们列出了如何禁用这一特性,就像这个非响应式布局实例页面一样。 禁止响应式布局有如下几步: 移除此 CSS 文档中提到的设置浏览器视口(viewport)的标签:<meta>。 通过为.container类设置一个...
  • BootStrap栅格系统 ... 一、什么是响应式布局? 二、如何实现响应式布局 三、实现步骤 四、实例 一、什么是响应式布局? 同一套页面可以兼容不同分辨率的设备。如在电脑上访问苹果的网站:https:/...
  • 响应式布局Bootstrap

    2018-02-13 20:11:17
    一、响应式布局、跨平台、小而强大 二、css、组件、js简单实例 UsingBS.html<!DOCTYPE html> <html lang="zh-CN"><head> <meta name="viewpor
  • 屏幕端对不同尺寸页面响应式时更省时省力对一种方法,是让减轻我们工作量对方法,看到这里是不是心动了,那就往下看看~一、 什么是栅格1. 栅格的由来栅格就是网格。就是这种有规律的格子哈哈,这样一说是不是就很...
  • 主页面 media.html<!DOCTYPEhtml> <html> <head> <metacharset="utf-8"/> <title>响应式布局演示实例(MediasQuery)</title> <style> body,h2{margin:0...
  • Bootstrap3.3.5响应式导航栏 实例

    千次阅读 2016-07-01 11:01:38
    源代码: 涵涵博客响应式布局 <!-------------- CopyRight(C)2016-7-1 11:00:10 Author:邱于涵 -----------> <!-- fonts ,css,js都应该在同一个文件夹! -->
  • 响应式布局实例 其中这句话必须要有,这是获取屏幕分辨率的方法; 然后我们写css自适应: * { margin: 0px; padding: 0px; } html { background-color: beige; } .heading, ....
  • 下面我们列出了如何禁用这一特性,就像这个非响应式布局实例页面一样。 禁止响应式布局有如下几步 移除 此 CSS 文档中提到的设置浏览器视口(viewport)的标签:。 通过为 .container 类设置一个width 值从而...
  • 大家好,由于我现在还在学习,有什么不对,希望大家帮忙指点,能和像我一样的大白共同进步,以下是我在学习中的一些实例项目和 总结。 实现弹性布局方法 一般我们习惯设置宽高,大小用像素(px)来做作为单位,其实还一种...
  • 首先我们先看一个实例 <div class="jumbotron text-center"> <h1>我的第一个 Bootstrap 页面</h1> <p>重置浏览器大小查看效果!</p> </div> <div class="container"> ...
  • 响应实用工具目前只适用于块或表切换 大中小超小设备显示隐藏类   打印类  大中小超小设备综合实例: &lt;!DOCTYPE html&gt; &lt;html lang="zh-cn"&gt; &lt;head&gt...
  • 最近想买需要开发微站,微信公众号内嵌入的移动web,总结方法可以使用css3直接使用百分比布局,也可以使用bootstrap响应式布局等多种方法,个人感觉看项目需要,笔者使用rem.js进行移动前端布局,感觉容易接触,...
  • BootStrap

    2020-11-19 17:59:18
    什么是响应式布局响应式布局能够解决的问题 2.环境下载 下载 目录结构 内容结构 简洁模板 3.布局容器 二、bootstrap栅格系统 1.简述栅格系统 2.栅格系统的特点 3.入门案例 4.栅格屏幕尺寸设置 5....
  • 弹性盒子是 CSS3 的一种新的布局模式,更适合响应式的设计,如果你还不了解 flex,可以阅读我们的 创建显示在同一行上的弹性盒子容器可以使用 d-inline-flex 类: 实例 Flex item 1 Flex item 2 Flex item 3 ...
  • 前言Bootstrap是流行的HTML、CSS和JS框架,用于开发响应式布局、移动设备优先的WEB项目。源自于twiteer内部的开发框架。当前(2019-05)最新版本是v3.3.7。学习初衷:不能每来一个项目都重头开始吧,希望积累框架,...
  • Bootstrap是流行的HTML、CSS和JS框架,用于开发响应式布局、移动设备优先的WEB项目。源自于twiteer内部的开发框架。 当前(2019-05)最新版本是v3.3.7。 官网:https://v3.bootcss.com/ 学习初衷:不能每来一个...
  • Bootstrap

    2018-10-29 19:38:13
    Bootstarp:是基于HTML、CSS、JAVASCRIPT的前端框架(半成品),在jquery的基础工作(jQuery务必在bootStrap.mai.js之前引入),可以理解为Bootstrap就是jquery的一个插件,用于响应式布局(可以兼容多个设备(即...
  • 按照设备的尺寸型号进行自动布局,保证良好的人际交互体验效果,已经成为网页前端设计所需要考虑的问题,当前支持响应式开发的架构较多,如主流BootStrap可以支持网页在不同终端尺寸下智能调整页面布局。本文主要从...

空空如也

空空如也

1 2 3
收藏数 58
精华内容 23
关键字:

bootstrap响应式布局实例