范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

如何在canvas中模拟css的背景图片样式

  笔者开源了一个Web思维导图mind-map,最近在优化背景图片效果的时候遇到了一个问题,页面上展示时背景图片是通过 css 使用background-image 渲染的,而导出的时候实际上是绘制到canvas 上导出的,那么就会有个问题,css 的背景图片支持比较丰富的效果,比如通过background-size 设置大小,通过background-position 设置位置,通过background-repeat 设置重复,但是canvas 笔者只找到一个createPattern() 方法,且只支持设置重复效果,那么如何在canvas 里模拟一定的css 背景效果呢,不要走开,接下来一起来试试。
  首先要说明的是不会去完美完整 100% 模拟css 的所有效果,因为css 太强大了,属性值组合很灵活,且种类非常多,其中单位就很多种,所有只会模拟一些常见的情况,单位也只考虑px 和% 。
  读完本文,你还可以顺便复习一下 canvas 的drawImage 方法,以及css 背景设置的几个属性的用法。canvas的drawImage()方法
  总的来说,我们会使用 canvas 的drawImage() 方法来绘制背景图片,先来大致看一下这个方法,这个方法接收的参数比较多:
  只有三个参数是必填的。 基本框架和工具方法
  核心逻辑就是加载图片,然后使用 drawImage 方法绘制图片,无非是根据各种css 的属性和值来计算drawImage 的参数,所以可以写出下面的函数基本框架:const drawBackgroundImageToCanvas = (   ctx,// canvas绘图上下文   width,// canvas宽度   height,// canvas高度   img,// 图片url   { backgroundSize, backgroundPosition, backgroundRepeat }// css样式,只模拟这三种 ) => {   // canvas的宽高比   let canvasRatio = width / height   // 加载图片   let image = new Image()   image.src = img   image.onload = () => {     // 图片的宽高及宽高比     let imgWidth = image.width     let imgHeight = image.height     let imageRatio = imgWidth / imgHeight     // 绘制图片     // drawImage方法的参数值     let drawOpt = {         sx: 0,         sy: 0,         swidth: imgWidth,// 默认绘制完整图片         sheight: imgHeight,         x: 0,         y: 0,         width: imgWidth,// 默认不缩放图片         height: imgHeight     }     // 根据css属性和值计算...     // 绘制图片     ctx.drawImage(image, drawOpt.sx, drawOpt.sy, drawOpt.swidth, drawOpt.sheight, drawOpt.x, drawOpt.y, drawOpt.width, drawOpt.height)   } }
  接下来看几个工具函数。 // 将以空格分隔的字符串值转换成成数字/单位/值数组 const getNumberValueFromStr = value => {   let arr = String(value).split(/s+/)   return arr.map(item => {     if (/^[d.]+/.test(item)) {         // 数字+单位         let res = /^([d.]+)(.*)$/.exec(item)         return [Number(res[1]), res[2]]     } else {         // 单个值         return item     }   }) }
  css 的属性值为字符串或数字类型,比如100px 100% auto ,不方便直接使用,所以转换成[[100, "px"], [100, "%"], "auto"] 形式。// 缩放宽度 const zoomWidth = (ratio, height) => {     // w / height = ratio     return ratio * height }  // 缩放高度 const zoomHeight = (ratio, width) => {   // width / h = ratio   return width / ratio }
  根据原比例和新的宽度或高度,计算缩放后的宽度或高度。 模拟background-size属性
  默认 background-repeat 的值为repeat ,我们先不考虑重复的情况,所以先把它设置成no-repeat 。
  background-size  属性用于设置背景图片的大小,可以接受四种类型的值,依次来模拟一下。length类型
  设置背景图片的高度和宽度。第一个值设置宽度,第二个值设置高度。如果只给出一个值,第二个默认为  auto (自动)。
  css 样式如下:.cssBox {     background-image: url("/1.jpg");     background-repeat: no-repeat;     background-size: 300px; }
  只设置一个值,那么代表背景图片显示的实际宽度,高度没有设置,那么会根据图片的长宽比自动缩放,效果如下:
  在 canvas 中模拟很简单,需要传给drawImage 方法四个参数:img、x、y、width、height ,img 代表图片,x、y 代表在画布上放置图片的位置,没有特殊设置,显然就是0、0 ,width、height 代表将图片缩放到指定大小,如果background-size 只传了一个值,那么width 直接设置成这个值,而height 则根据图片的长宽比进行计算,如果传了两个值,那么分别把两个值传给width、height 即可,另外需要对值为auto 的进行一下处理,实现如下:drawBackgroundImageToCanvas(ctx, width, height, this.img, {     backgroundSize: "300px" })  const drawBackgroundImageToCanvas = () =>{     // ...     image.onload = () => {         // ...         // 模拟background-size         handleBackgroundSize({             backgroundSize,              drawOpt,              imageRatio         })         // ...     } }  // 模拟background-size const handleBackgroundSize = ({ backgroundSize, drawOpt, imageRatio }) => {     if (backgroundSize) {       // 将值转换成数组       let backgroundSizeValueArr = getNumberValueFromStr(backgroundSize)       // 两个值都为auto,那就相当于不设置       if (backgroundSizeValueArr[0] === "auto" && backgroundSizeValueArr[1] === "auto") {         return       }       // 图片宽度       let newNumberWidth = -1       if (backgroundSizeValueArr[0]) {         if (Array.isArray(backgroundSizeValueArr[0])) {             // 数字+单位类型             drawOpt.width = backgroundSizeValueArr[0][0]             newNumberWidth = backgroundSizeValueArr[0][0]         } else if (backgroundSizeValueArr[0] === "auto") {             // auto类型,那么根据设置的新高度以图片原宽高比进行自适应             if (backgroundSizeValueArr[1]) {                 drawOpt.width = zoomWidth(imageRatio, backgroundSizeValueArr[1][0])             }         }       }       // 设置了图片高度       if (backgroundSizeValueArr[1] && Array.isArray(backgroundSizeValueArr[1])) {         // 数字+单位类型         drawOpt.height = backgroundSizeValueArr[1][0]       } else if (newNumberWidth !== -1) {         // 没有设置图片高度或者设置为auto,那么根据设置的新宽度以图片原宽高比进行自适应         drawOpt.height = zoomHeight(imageRatio, newNumberWidth)       }     } }
  效果如下:
  设置两个值的效果: background-size: 300px 400px;
  percentage类型
  将计算相对于背景定位区域的百分比。第一个值设置宽度百分比,第二个值设置的高度百分比。如果只给出一个值,第二个默认为 auto (自动)。比如设置了 50% 80% ,意思是将图片缩放到背景区域的50% 宽度和80% 高度。
  css 样式如下:.cssBox {     background-image: url("/1.jpg");     background-repeat: no-repeat;     background-size: 50% 80%; }
  实现也很简单,在前面的基础上判断一下单位是否是 % ,是的话就按照canvas 的宽高来计算图片要显示的宽高,第二值没有设置或者为auto ,跟之前一样也是根据图片的宽高比来自适应。drawBackgroundImageToCanvas(ctx, width, height, this.img, {     backgroundSize: "50% 80%" })  handleBackgroundSize({     backgroundSize,     drawOpt,     imageRatio,     canvasWidth: width,// 传参新增canvas的宽高     canvasHeight: height })  // 模拟background-size const handleBackgroundSize = ({ backgroundSize, drawOpt, imageRatio, canvasWidth, canvasHeight }) => {   if (backgroundSize) {     // ...     // 图片宽度     let newNumberWidth = -1     if (backgroundSizeValueArr[0]) {       if (Array.isArray(backgroundSizeValueArr[0])) {         // 数字+单位类型         if (backgroundSizeValueArr[0][1] === "%") {             // %单位,则图片显示的高度为画布的百分之多少             drawOpt.width = backgroundSizeValueArr[0][0] / 100 * canvasWidth             newNumberWidth = drawOpt.width         } else {             // 其他都认为是px单位             drawOpt.width = backgroundSizeValueArr[0][0]             newNumberWidth = backgroundSizeValueArr[0][0]         }       } else if (backgroundSizeValueArr[0] === "auto") {         // auto类型,那么根据设置的新高度以图片原宽高比进行自适应         if (backgroundSizeValueArr[1]) {             if (backgroundSizeValueArr[1][1] === "%") {                 // 高度为%单位                 drawOpt.width = zoomWidth(imageRatio, backgroundSizeValueArr[1][0] / 100 * canvasHeight)             } else {                 // 其他都认为是px单位                 drawOpt.width = zoomWidth(imageRatio, backgroundSizeValueArr[1][0])             }         }       }     }     // 设置了图片高度     if (backgroundSizeValueArr[1] && Array.isArray(backgroundSizeValueArr[1])) {       // 数字+单位类型       if (backgroundSizeValueArr[1][1] === "%") {         // 高度为%单位         drawOpt.height = backgroundSizeValueArr[1][0] / 100 * canvasHeight       } else {         // 其他都认为是px单位         drawOpt.height = backgroundSizeValueArr[1][0]       }     } else if (newNumberWidth !== -1) {       // 没有设置图片高度或者设置为auto,那么根据设置的新宽度以图片原宽高比进行自适应       drawOpt.height = zoomHeight(imageRatio, newNumberWidth)     }   } }
  效果如下:
  cover类型
  background-size 设置为cover 代表图片会保持原来的宽高比,并且缩放成将完全覆盖背景定位区域的最小大小,注意,图片不会变形。
  css 样式如下:.cssBox {     background-image: url("/3.jpeg");     background-repeat: no-repeat;     background-size: cover; }
  这个实现也很简单,根据图片的宽高比和 canvas 的宽高比判断,到底是缩放图片的宽度和canvas 的宽度一致,还是缩放图片的高度和canvas 的高度一致。drawBackgroundImageToCanvas(ctx, width, height, this.img, {     backgroundSize: "cover" })  handleBackgroundSize({     backgroundSize,     drawOpt,     imageRatio,     canvasWidth: width,     canvasHeight: height,     canvasRatio// 参数增加canvas的宽高比 })  const handleBackgroundSize = ({   backgroundSize,   drawOpt,   imageRatio,   canvasWidth,   canvasHeight,   canvasRatio }) => {     // ...     // 值为cover     if (backgroundSizeValueArr[0] === "cover") {         if (imageRatio > canvasRatio) {             // 图片的宽高比大于canvas的宽高比,那么图片高度缩放到和canvas的高度一致,宽度自适应             drawOpt.height = canvasHeight             drawOpt.width = zoomWidth(imageRatio, canvasHeight)         } else {             // 否则图片宽度缩放到和canvas的宽度一致,高度自适应             drawOpt.width = canvasWidth             drawOpt.height = zoomHeight(imageRatio, canvasWidth)         }         return     }     // ... }
  效果如下:
  contain类型
  background-size 设置为contain 类型表示图片还是会保持原有的宽高比,并且缩放成适合背景定位区域的最大大小,也就是图片会显示完整,但是不一定会铺满背景的水平和垂直两个方向,在某个方向可能会有留白。
  css 样式:.cssBox {     background-image: url("/1.jpg");     background-repeat: no-repeat;     background-size: contain; }
  实现刚好和 cover 类型的实现反过来即可,如果图片的宽高比大于canvas 的宽高比,为了让图片显示完全,让图片的宽度和canvas 的宽度一致,高度自适应。const handleBackgroundSize = () => {     // ...     // 值为contain     if (backgroundSizeValueArr[0] === "contain") {         if (imageRatio > canvasRatio) {             // 图片的宽高比大于canvas的宽高比,那么图片宽度缩放到和canvas的宽度一致,高度自适应             drawOpt.width = canvasWidth             drawOpt.height = zoomHeight(imageRatio, canvasWidth)         } else {             // 否则图片高度缩放到和canvas的高度一致,宽度自适应             drawOpt.height = canvasHeight             drawOpt.width = zoomWidth(imageRatio, canvasHeight)         }         return     } }
  效果如下:
  到这里对 background-size 的模拟就结束了,接下来看看background-position 。模拟background-position属性
  先看不设置 background-size 的情况。
  background-position 属性用于设置背景图像的起始位置,默认值为0% 0% ,它也支持几种不同类型的值,一一来看。percentage类型
  第一个值设置水平位置,第二个值设置垂直位置。左上角是 0%0% ,右下角是100%100% ,如果只设置了一个值,第二个默认为50% ,比如设置为50% 60% ,意思是将图片的50% 60% 位置和背景区域的50% 60% 位置进行对齐,又比如50% 50% ,代表图片中心点和背景区域中心点重合。
  css 样式:.cssBox {     background-image: url("/2.jpg");     background-repeat: no-repeat;     background-position: 50% 50%; }
  实现上我们只需要用到 drawImage 方法的img 、x、y 三个参数,图片的宽高不会进行缩放,根据比例分别算出在canvas 和图片上对应的距离,他们的差值即为图片在canvas 上显示的位置。drawBackgroundImageToCanvas(ctx, width, height, this.img, {     backgroundPosition: "50% 50%" })  const drawBackgroundImageToCanvas = () => {     // ...     // 模拟background-position     handleBackgroundPosition({       backgroundPosition,       drawOpt,       imgWidth,       imgHeight,       canvasWidth: width,       canvasHeight: height     })     // ... }  // 模拟background-position const handleBackgroundPosition = ({   backgroundPosition,   drawOpt,   imgWidth,   imgHeight,   canvasWidth,   canvasHeight }) => {   if (backgroundPosition) {     // 将值转换成数组     let backgroundPositionValueArr = getNumberValueFromStr(backgroundPosition)     if (Array.isArray(backgroundPositionValueArr[0])) {       if (backgroundPositionValueArr.length === 1) {         // 如果只设置了一个值,第二个默认为50%         backgroundPositionValueArr.push([50, "%"])       }       // 水平位置       if (backgroundPositionValueArr[0][1] === "%") {         // 单位为%         let canvasX = (backgroundPositionValueArr[0][0] / 100) * canvasWidth         let imgX = (backgroundPositionValueArr[0][0] / 100) * imgWidth         // 计算差值         drawOpt.x = canvasX - imgX       }       // 垂直位置       if (backgroundPositionValueArr[1][1] === "%") {         // 单位为%         let canvasY = (backgroundPositionValueArr[1][0] / 100) * canvasHeight         let imgY = (backgroundPositionValueArr[1][0] / 100) * imgHeight         // 计算差值         drawOpt.y = canvasY - imgY       }     }   } }
  效果如下:
  length类型
  第一个值代表水平位置,第二个值代表垂直位置。左上角是 0 0 。单位可以是px 或任何其他css 单位,当然,我们只考虑px 。如果仅指定了一个值,其他值将是50% 。所以你可以混合使用% 和px 。
  css 样式:.cssBox {     background-image: url("/2.jpg");     background-repeat: no-repeat;     background-position: 50px 150px; }
  这个实现更简单,直接把值传给 drawImage 的x、y 参数即可。drawBackgroundImageToCanvas(ctx, width, height, this.img, {     backgroundPosition: "50px 150px" })  // 模拟background-position const handleBackgroundPosition = ({}) => {     // ...     // 水平位置     if (backgroundPositionValueArr[0][1] === "%") {         // ...     } else {         // 其他单位默认都为px         drawOpt.x = backgroundPositionValueArr[0][0]     }     // 垂直位置     if (backgroundPositionValueArr[1][1] === "%") {         // ...     } else {         // 其他单位默认都为px         drawOpt.y = backgroundPositionValueArr[1][0]     } }
  关键词类型
  也就是通过 left 、top 之类的关键词进行组合,比如:left top 、center center 、center bottom 等。可以看做是特殊的% 值,所以我们只要写一个映射将这些关键词对应上百分比数值即可。.cssBox {     background-image: url("/2.jpg");     background-repeat: no-repeat;     background-position: right bottom; } drawBackgroundImageToCanvas(ctx, width, height, this.img, {     backgroundPosition: "right bottom" })  // 关键词到百分比值的映射 const keyWordToPercentageMap = {   left: 0,   top: 0,   center: 50,   bottom: 100,   right: 100 }  const handleBackgroundPosition = ({}) => {     // ...     // 将关键词转为百分比     backgroundPositionValueArr = backgroundPositionValueArr.map(item => {       if (typeof item === "string") {         return keyWordToPercentageMap[item] !== undefined           ? [keyWordToPercentageMap[item], "%"]           : item       }       return item     })     // ... }
  和background-size组合
  最后我们来看看和 background-size 组合使用会发生什么情况。.cssBox {     background-image: url("/2.jpg");     background-repeat: no-repeat;     background-size: cover;     background-position: right bottom; } drawBackgroundImageToCanvas(ctx, width, height, this.img, {     backgroundSize: "cover",     backgroundPosition: "right bottom" })
  结果如下:
  不一致,这是为啥呢,我们来梳理一下,首先在处理 background-size 会计算出drawImage 参数中的width、height ,也就是图片在canvas 中显示的宽高,而在处理background-position 时会用到图片的宽高,但是我们传的还是图片的原始宽高,这样计算出来当然是有问题的,修改一下:// 模拟background-position handleBackgroundPosition({     backgroundPosition,     drawOpt,     imgWidth: drawOpt.width,// 改为传计算后的图片的显示宽高     imgHeight: drawOpt.height,     imageRatio,     canvasWidth: width,     canvasHeight: height,     canvasRatio })
  现在再来看看效果:
  模拟background-repeat属性
  background-repeat 属性用于设置如何平铺对象的background-image 属性,默认值为repeat ,也就是当图片比背景区域小时默认会向垂直和水平方向重复,另外还有几个可选值:repeat-x :只有水平位置会重复背景图像repeat-y :只有垂直位置会重复背景图像no-repeat :background-image 不会重复
  接下来我们实现一下这几种情况。 no-repeat
  首先判断图片的宽高是否都比背景区域大,是的话就不需要平铺,也就不用处理,另外值为 no-repeat 也不需要做处理:// 模拟background-repeat handleBackgroundRepeat({     backgroundRepeat,     drawOpt,     imgWidth: drawOpt.width,     imgHeight: drawOpt.height,     imageRatio,     canvasWidth: width,     canvasHeight: height,     canvasRatio })
  可以看到这里我们传的图片的宽高也是经 background-size 计算后的图片显示宽高。// 模拟background-repeat const handleBackgroundRepeat = ({   backgroundRepeat,   drawOpt,   imgWidth,   imgHeight,   canvasWidth,   canvasHeight, }) => {     if (backgroundRepeat) {         // 将值转换成数组         let backgroundRepeatValueArr = getNumberValueFromStr(backgroundRepeat)         // 不处理         if (backgroundRepeatValueArr[0] === "no-repeat" || (imgWidth >= canvasWidth && imgHeight >= canvasHeight)) {             return         }     } } repeat-x
  接下来增加对 repeat-x 的支持,当canvas 的宽度大于图片的宽度,那么水平平铺进行绘制,绘制会重复调用drawImage 方法,所以还需要再传递ctx 、image 参数给handleBackgroundRepeat 方法,另外如果handleBackgroundRepeat 方法里进行了绘制,原来的绘制方法就不用再调用了:// 模拟background-repeat // 如果在handleBackgroundRepeat里进行了绘制,那么会返回true let notNeedDraw = handleBackgroundRepeat({     ctx,     image,     ... }) if (!notNeedDraw) {     drawImage(ctx, image, drawOpt) }  // 根据参数绘制图片 const drawImage = (ctx, image, drawOpt) => {   ctx.drawImage(     image,     drawOpt.sx,     drawOpt.sy,     drawOpt.swidth,     drawOpt.sheight,     drawOpt.x,     drawOpt.y,     drawOpt.width,     drawOpt.height   ) }
  将绘制的方法提取成了一个方法,方便复用。 const handleBackgroundRepeat = ({}) => {     // ...     // 水平平铺     if (backgroundRepeatValueArr[0] === "repeat-x") {       if (canvasWidth > imgWidth) {         let x = 0         while (x < canvasWidth) {           drawImage(ctx, image, {             ...drawOpt,             x           })           x += imgWidth         }         return true       }     }     // ... }
  每次更新图片的放置位置 x 参数,直到超出canvas 的宽度。
  repeat-y
  对 repeat-y 的处理也是类似的:const handleBackgroundRepeat = ({}) => {     // ...     // 垂直平铺     if (backgroundRepeatValueArr[0] === "repeat-y") {       if (canvasHeight > imgHeight) {         let y = 0         while (y < canvasHeight) {           drawImage(ctx, image, {             ...drawOpt,             y           })           y += imgHeight         }         return true       }     }     // ... }
  repeat
  最后就是 repeat 值,也就是水平和垂直都进行重复:const handleBackgroundRepeat = ({}) => {     // ...     // 平铺     if (backgroundRepeatValueArr[0] === "repeat") {       let x = 0       while (x < canvasWidth) {         if (canvasHeight > imgHeight) {           let y = 0           while (y < canvasHeight) {             drawImage(ctx, image, {               ...drawOpt,               x,               y             })             y += imgHeight           }         }         x += imgWidth       }       return true     } }
  从左到右,一列一列进行绘制,水平方向绘制到 x 超出canvas 的宽度为止,垂直方向绘制到y 超出canvas 的高度为止。
  和background-size、background-position组合
  最后同样看一下和前两个属性的组合情况。
  css 样式:.cssBox {     background-image: url("/4.png");     background-repeat: repeat;     background-size: 50%;     background-position: 50% 50%; }
  效果如下:
  图片大小是正确的,但是位置不正确, css 的做法应该是先根据background-position 的值定位一张图片,然后再向四周进行平铺,而我们显然忽略了这种情况,每次都从0 0 位置开始绘制。
  知道了原理,解决也很简单,在 handleBackgroundPosition 方法中已经计算出了x、y ,也就是没有平铺前第一张图片的放置位置:
  我们只要计算出左边和上边还能平铺多少张图片,把水平和垂直方向上第一张图片的位置计算出来,作为后续循环的 x、y 的初始值即可。const handleBackgroundRepeat = ({}) => {     // 保存在handleBackgroundPosition中计算出来的x、y     let ox = drawOpt.x     let oy = drawOpt.y     // 计算ox和oy能平铺的图片数量     let oxRepeatNum = Math.ceil(ox / imgWidth)     let oyRepeatNum = Math.ceil(oy / imgHeight)     // 计算ox和oy第一张图片的位置     let oxRepeatX = ox - oxRepeatNum * imgWidth      let oxRepeatY = oy - oyRepeatNum * imgHeight     // 将oxRepeatX和oxRepeatY作为后续循环的x、y的初始值     // ...     // 平铺     if (backgroundRepeatValueArr[0] === "repeat") {       let x = oxRepeatX       while (x < canvasWidth) {         if (canvasHeight > imgHeight) {           let y = oxRepeatY           // ...         }       }     } }
  结尾
  本文简单实现了一下在 canvas 中模拟css 的background-size 、background-position 、background-repeat 三个属性的部分效果,完整源码在https://github.com/wanglin2/simulateCSSBackgroundInCanvas。

印度铁娘子英迪拉下令阉割600万男性,67岁被贴身警卫打死1984年,印度第一位女性总理英迪拉死了,她被自己的两名贴身警卫打死在政府办公大楼前。英迪拉曾被称为亚洲的铁娘子,独自一人掌控印度政坛十五年。作为一名政客,英迪拉是一位十分具有争议中国铜贝人类最早的金属铸币说到古代中国的钱币,人们的第一印象,不是外圆内方,刻着某某通宝某某元宝的小铜钱,就是从袖口里随手掏出来的一把碎银子,或者是八仙桌上堆成小山的金锭银锭。在这里,我将要介绍的是这些金属1948年,石家庄雁北双雄越狱,卤肉成破案关键1947年10月,石家庄解放,大批国民党特务恶霸土匪等人都被抓获关入监狱。其中有些作恶多端的,需要解押回原籍审判。这天,监狱门前停了一长串大车,都是附近地区来提人的。一辆由两匹马拉藏民翻出红军借条,可换取任何物品,藏民却拒绝兑现债早还清了说到红军长征,相信每个人都不陌生,它是一条充满了艰难险阻,牺牲了无数革命战士的坎坷之路。但这也是一次成功的战略转移行动,在完成了极限换家之后,工农红军的不利局面彻底被扭转,历史至此李自成惊走的镇水神兽金头狼和珅清嘉庆八年,和珅被嘉庆帝赐死,在狱中留下绝命诗五十年来梦幻真,今朝撒手谢红尘。他日水泛合拢日,认取香烟是后身!这首诗流传到坊间,众说纷纭,都猜不透到底是什么意思。和珅要了解此诗背后1930年,彭德怀智破离间计,毛主席向他表示感谢,他却做起了检讨老覃在昨天写了1930年,毛主席的高超才能折服了彭德怀,陈毅却悲叹霉运将至矣一文,讲的是1930年,毛主席在李立三疯狂推出立三路线期间,根据实际情况机动用兵,巧妙地避免了左倾冒险主项羽自刎也不肯过乌江?并不是因为蠢,只是他发现一个天大的秘密司马迁曾在史记中评价项羽的垓下歌,力拔山兮气盖世,时不利兮骓不逝。司马迁感叹项羽是个千古英雄,但是生不逢时,最后无奈之下只能在乌江前自杀,了却一生。很多人在阅读这段历史的时候,都会卡扎菲惨死是咎由自取吗?访华时的态度,就注定了日后的结局众所周知,在2011年,利比亚的总统卡扎菲惨死,被叛军一枪击毙,身上的黄金手枪也被抢夺,尸体被扔在大街上,一国总统沦落至此,让人感到唏嘘。要知道,卡扎菲在非洲被称万王之王,接受各地武则天的男宠俱乐部,是欲望的泛滥?还是权力的斗争?乱伦坏纪注定与武媚娘的一生缠绕在一起,剪不断,理还乱,功过是非只能任后人随心评说。她的坏纪,无疑是为当时世人所指责谩骂的,万夫所指不为过也。唐高宗驾崩后,武则天以太后的力量先后废除古代女子验身方式?不和男人同房也能一眼看出,原因太辛酸古代女子失去贞操,不跟男子同房,也能被人一眼看出来有问题,真相让人不忍直视,古代女人简直活得艰难又耻辱,今天就让我们一起来了解一下,古人验明女性贞洁的秘密。守宫砂古代女子验身之谜在毛主席最看不起什么人?主子让他坐,他却说站惯了,一副奴才相头条创作挑战赛谁是你最崇拜的人?和许多毛主席的粉丝一样,我始终认为,除了毛主席,这个世界上别无他人。那么,毛主席最欣赏谁?最看不起什么样的人呢?几十年里,毛主席不止一次提到一个叫贾
蓦然回首,又是一年睡意朦胧中醒来,天色明亮,有一抹浅浅的冬日暖阳,连日来少有的微晴,我的心情也如同这天气随之放晴。起得稍迟,找几片吐丝面包抵早点裹腹充饥,坐在床上,拈几枚小字,记录生活某些瞬间。望着奥斯卡回归,助推海港冲击足协杯本报记者组联合报道中超还剩最后一轮,海港目前积62分,和浙江蓉城同分。不过,对于中超,他们已没有太多想法,接下来的足协杯,才是他们的目标,如果拿到冠军,赛季也不算失败。值得一提的是退出CBA!再见了!林书豪!下一站,台湾省书豪走了。离开CBA前,书豪留下一封推文。详细描述了他离开的原因。其实原因不用说,大家也清楚,在广州龙狮这几个月,书豪几乎得不到太多上场时间。一共出战7场比赛,场均上场时间只有12三镇提前一轮夺冠,山东泰山队无缘卫冕,下赛季外援选择提上日程2022赛季中超联赛在还剩下一轮的情况下,随着天津和北京国安的双双弃赛,冠军争夺也就此落下帷幕,武汉三镇队以升班马的身份,强势发挥夺取了2022赛季中超联赛的冠军,从本赛季的发挥和狄龙在猛龙的主场打球让我格外兴奋北京时间12月30日,灰熊客场119106大胜猛龙,结束2连败。此役狄龙布鲁克斯出战34分钟,14投7中,三分7中4,高效砍下了全场最高的25分,此外还送出了4篮板6助攻,正负值为官宣!国乒新一届教练组确定为期3天的国家乒乓球队教练员竞聘与交流活动12月29日圆满结束。经过两个阶段的投票评选,竞聘委员会选出新一届国家乒乓球队教练组负责人总教练为李隼,男队主教练为王皓,女队主教练为马琳布莱克尼415威廉姆斯1114江苏逆转13分送宁波20连败北京时间12月30日,CBA常规赛第20轮,江苏男篮对阵宁波男篮。经过四节比拼,最终江苏8974逆转宁波终结连败,同时送给对手20连败。双方数据江苏布莱克尼41分5板3助2断2帽史布鲁克斯4177命中9记三分0失误广东大胜北京迎11连胜北京时间12月30日1935,20222023赛季CBA常规赛第20轮一场焦点战展开争夺,广东队10284战胜北京队迎来11连胜,北京队的6连胜也被终结。比赛现场技术统计广东队布鲁中国第1,世界第4!丁俊晖1数据比肩小特,中国3人进前10!说到本赛季竞技状态最好的中国斯诺克选手,丁俊晖如是第2,就没人敢称第1!中国名将王者归来,第4次入围英锦赛决赛夺得亚军,目前最新世界排名升至第22位。在世界台联公布的另一项榜单上,让你失望了!82岁贝利曾直言中国男足是世界16强的水平巴西当地时间12月29日15时27分,球王贝利因结肠癌去世,享年82岁。这一位巴西传奇球星的离开让整个世界足坛都陷入了悲伤,而曾经他也与中国男足有过很深的缘分。曾在2002年的时候传统武术之透视抻筋拔骨抻筋拔骨是传统拳术攻防之道各门派拳种皆存有的一种修炼外形体功夫综合方法的名称。传统拳术讲究内外兼修。谚云内练一口气,外练筋骨皮。抻筋拔骨就是修炼筋骨皮的方法。拳经云肌肤骨节,处处开