VUE音乐播放器学习笔记(1)- ( JSONP ) + ( 插槽:分发内容,单个插槽,具名插槽 ) + ( 轮播图 ) + ( axios请求线上地址' 跨域请求 '报错 Access control allow origin 访问控制允许同源 ) + ( keep-alive ) + (destroyed生命周期) + ( axios用于服务器端的请求)

(1) babel-polyfill

  • 在低版本的浏览器中不能支持es6语法,所以用babel-polyfill来解决
  • 作用和babel-runtime类似,能够使用es6的api
  • 安装
cnpm install babel-polyfill --save-dev
  • 使用
在入口文件main.js中

1.require("babel-polyfill");      // es5
2.import "babel-polyfill";        // es6,写在main.js的最开始位置
3.module.exports = {
  entry: ["babel-polyfill", "./app/js"]
};

注:第三种方法适用于使用webpack构建的同学,加入到webpack配置文件(webpack.config.js)entry项中

ps: ( polyfill是补丁的意思 )

(2) babel-runtime 作用和babel-polyfill类似,能够使用es6的api

cnpm install babel-runtime --save         // 这里是--save,用在线上环境

(3) fastclick 解决移动端点击 300ms 延迟

  • 安装
cnpm install fastclick --save             // 这里是--save,用在线上环境
  • 引入
在入口文件main.js中

import fastclick from ' fastclick '
  • 使用
fastclick.attach(document.body)

(4) 两种方法实现,默认跳转到指定的路由页面

  • router.push('/xxx')
  • redirect
  • 区别:有痕和无痕的区别
    router.push('/') 只要刷新页面就会跳转到指定的路由页面
    而 redirect 会记住当前选中的路由页面
(1) router.push('/路由地址')使用方法


在main.js中:
router.push('/recommend')

-------------------------------------------------------------------


(2) redirect ( 跟路由重定向 ) 使用方法


在router/index.js路由入口页面中:

export default new Router({
  routes: [
    { path: '/', name: 'home', redirect: '/recommend' },   // 根路由重定向,会记住路由路径
    { path: '/recommend', name: 'recommend', component: Recommend },
    { path: '/singer', name: 'singer', component: Singer }
    { path: '/rank', name: 'rank', component: Rank },
    { path: '/search', name: 'search', component: Search },
  ]
})





(5) jsonp

(1) ( webmodules/jsonp )

  • 安装
cnpm install jsonp --save
  • 使用 ( api )
jsonp(url, options, fn)    // 现在基本用promise结构了
jsonp(url, options, (err, data) => { })
url : ( String ) 请求地址
opts : ( Object ) 有如下选项:
    param ( String ) 参数,默认是一个回调函数。和 后端约定的字段参数名   **
    timeout ( Number ) 超时时间,默认1分钟后。  **
    prefix ( String )  callback等于什么,在前面加个前缀。默认 __jp 
    name ( String )
fn callback回调函数,很少用回调,es6中基本用封装promise方法
  • jsonp的封装

(2) promise

  • (1) promise实例化:使用new来调用Promise的构造器来进行实例化

var promise = new Promise(function(resolve, reject) {

    // 异步处理
    // 处理结束后、调用resolve 或 reject

    // resolve 成功时候的回调
    // reject 失败时候的回调
});

  • (2) 用Promise() 封装 jsonp
 _getData() {
         return new Promise((resolve, reject) => {
            Jsonp('https://c.y.qq.com/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg?g_tk=5381&uin=0&format=json&inCharset=utf-8&outCharset=utf-8&notice=0&platform=h5&needNewCode=1&_=1505661043507', {param: 'jsonpCallback'}, (err, data) => {
              if (!err) {
                resolve(data)
                console.log(data)
              } else {
                reject(err)
              }
            })
          })
      }

(3) for in循环

for...in 语句用于对数组或者对象的属性进行循环操作。

与for循环的区别:
for循环是对数组的元素进行循环,而不能用于非数组对象。


for (变量 in 对象)
{
    在此执行代码
}
---------------------------------------------------

遇到数组时key为数据下标 ,遇到对象时 key为对象(名称:值)项的名称。

  for (var k in data) {
    let value = data[k] !== undefined ? data[k] : ''
    url += '&' + k + '=' + encodeURIComponent(value)   // 这里的k不是下标(数字),而是key:value中的key
  }




(4) encodeURIComponent( URIstring )

encodeURIComponent(URIstring) 函数可把字符串作为 URI 组件进行编码。

  • 返回值 :
    URIstring 的副本,其中的某些字符将被十六进制的转义序列进行替换。
<script type="text/javascript">

document.write(encodeURIComponent("http://www.w3school.com.cn"))
document.write("<br />")
document.write(encodeURIComponent("http://www.w3school.com.cn/p 1/"))
document.write("<br />")
document.write(encodeURIComponent(",/?:@&=+$#"))

</script>
---------------------------------------

输出:
http%3A%2F%2Fwww.w3school.com.cn
http%3A%2F%2Fwww.w3school.com.cn%2Fp%201%2F
%2C%2F%3F%3A%40%26%3D%2B%24%23

http://www.w3school.com.cn/jsref/jsref_encodeURIComponent.asp

(5) stringObject.substring( start, stop )

  • stringObject.substring(start,stop)方法用于提取字符串中介于两个指定下标之间的字符。
  • start : 必须,提取的开始位置
  • stop : 可选,提取的结束位置
  • 返回值 :
    一个新的字符串,该字符串值包含 stringObject 的一个子字符串,其内容是从 start 处到 stop-1 处的所有字符,其长度为 stop 减 start。
  • ( substring是子链的意思 )
<html>
<body>

<script type="text/javascript">

var str="Helloworld!"

document.write(str.substring(3,7))

</script>

</body>
</html>
---------------------------------------------

输出结果:
lowo 

(6) stringObject.indexOf(searchvalue,fromindex)

  • indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
  • searchvalue : 必需。规定需检索的字符串值
  • fromindex : 可选。规定在字符串中开始检索的位置。
  • 位置是从0开始计算的
  • 大小写敏感
  • 如果要检索的字符串值没有出现,则该方法返回 -1。
<script type="text/javascript">

var str="Hello world!"
document.write(str.indexOf("Hello") + "<br />")
document.write(str.indexOf("World") + "<br />")    // 这个W是大写的
document.write(str.indexOf("world"))

</script>
----------------------------------------------


输出结果:

0
-1
6

(7) Object.assign( target, ...sources )

  • Object.assign() 方法用于将所有可枚举的属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
  • target : 目标对象。
  • sources : (多个)源对象
  • 返回值 :
    目标对象
  • assign : 是转让,受托的意思
复制一个 object

var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

--------------------------------

合并 objects

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。


  const data = Object.assign({}, commonParams, {       // 把commonParams和{}一起复制给data
    platform: 'yqq',     
    hostUin: 0,
    sin: 0,
    ein: 29,
    sortId: 5,
    needNewCode: 0,
    categoryId: 10000000,
    rnd: Math.random(),
    format: 'json'
  })


  export default {
    data() {
      return {
        aa: {爱好: '代码'}
      }
    },
    created() {
      this.getArray()
    },
    methods: {
      getArray() {
        const bb = Object.assign({}, {姓名: '张三', 年龄: '20', 性别: '男'}, this.aa)
        console.log(bb)
      }
    }
  }

输出结果:Object {姓名: "张三", 年龄: "20", 性别: "男", 爱好: "代码"}

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

(6) 插槽 < slot > 与 内容分发

  • 插槽作用: 为了让组件自由组合,分发内容。比如抽象scroll组件的时候,slot里面可以是任何内容,也不关心是什么内容。只要实现其滚动就好。

  • 什么是内容分发:
    为了让组件可以组合,我们需要一种方式来 混合父组件的内容与子组件自己的模板。这个过程被称为内容分发 (或“transclusion”如果你熟悉 Angular)。

  • 单个插槽:除非子组件模板包含至少一个 <slot> 插口,否则父组件的内容将会被丢弃。当子组件模板只有一个没有属性的插槽时,父组件整个内容片段将插入到插槽所在的 DOM 位置,并替换掉插槽标签本身。

父组件


<div>
  <h1>我是父组件的标题</h1>
  <my-component>                           // 子组件
    <p>这是一些初始内容</p>
    <p>这是更多的初始内容</p>
  </my-component>
</div>

-----------------------------------------------------------

子组件 my-component 


<div>
  <h2>我是子组件的标题</h2>
  <slot>
    只有在没有要分发的内容时才会显示。            // 备用内容,只有在没有要分发的内容时才会显示 
  </slot>                                      // 备用内容在子组件的作用域内编译
</div>
------------------------------------------------------------

渲染结果:

<div>
  <h1>我是父组件的标题</h1>                   // 父组件自己的内容
  <div>
    <h2>我是子组件的标题</h2>                 // 子组件自己的内容
    <p>这是一些初始内容</p>                   // 以下是插槽分发的内容
    <p>这是更多的初始内容</p>
  </div>
</div>

 
 父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。

(6) 具名插槽 < slot name="xxx" >

  • < slot > 在子组件中用 name 来配置如何分发内容,多个插槽可以有不同的名字。
  • 具名插槽将匹配内容片段中有对应 slot 特性的元素。
  • ps:仍然可以有一个匿名插槽,它是默认插槽,作为找不到匹配的内容片段的备用插槽。如果没有默认插槽,这些找不到匹配的内容片段将被抛弃。
父组件



<app-layout>
  <h1 slot="header">这里可能是一个页面标题</h1>

  <p>主要内容的一个段落。</p>
  <p>另一个主要段落。</p>

  <p slot="footer">这里有一些联系信息</p>
</app-layout>

-----------------------------------------------------

子组件


<div class="container">
  <header>
    <slot name="header"></slot>                // 该具名插槽,将匹配父组件中slot="header"中的内容
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>                // 该具名插槽,将匹配父组件中slot="footer"中的内容
  </footer>
</div>

(7) Access control allow origin 访问控制允许同源

  • 用axios访问线上地址 get请求 ( 跨域 ),出现 Access-Control-Allow-Origin 报错
  • 解决方案:下载 allow control allow origin插件
  • 以上方法只能开发中解决,实际开发要用cors。(浏览器和服务端同时支持即可)
  • 报错如下图:
Access control allow origin 报错
  • axios请求
    安装其他插件的时候,可以直接在 main.js 中引入并使用 Vue.use()来注册,但是 axios并不是vue插件,所以不能 使用Vue.use(),所以只能在每个需要发送请求的组件中即时引入。
    为了解决这个问题,我们在引入 axios 之后,通过修改原型链,来更方便的使用。
    //main.js
    import axios from 'axios'
    Vue.prototype.$http = axios

main.js

import axios from 'axios'
Vue.prototype.$http = axios


// prototype属性 : 使您有能力向对象添加属性和方法。

// prototype是原型的意思
---------------------------------------------------------------------------------

recommend.vue

  dataImage() {   // 百度图片线上接口
           this.$http.get('http://image.baidu.com/channel/listjson?pn=15&rn=30&tag1=%E7%BE%8E%E5%A5%B3&tag2=%E5%85%A8%E9%83%A8&ie=utf8')
            .then((response) => {
               console.log(response)
            })
        }

(8) 轮播图

(1) 滚动的图片

  • clientWidth: 获取对象可见内容的宽度,不包括滚动条,不包括边框;(client:客户端的意思)
  • RegExp 对象表示正则表达式,它是对字符串执行模式匹配的强大工具。
  • new RegExp(pattern, attributes);
    (1)参数 pattern 是一个字符串,指定了正则表达式的模式或其他正则表达式。
    (2)参数 attributes 是一个可选的字符串,包含属性 "g"、"i" 和 "m",分别用于指定全局匹配、区分大小写的匹配和多行匹配。ECMAScript 标准化之前,不支持 m 属性。如果 pattern 是正则表达式,而不是字符串,则必须省略该参数。
  • test() 方法用于检测一个字符串是否匹配某个模式.
  • split() 方法用于把一个字符串分割成字符串数组。
  • join() 方法用于把数组中的所有元素放入一个字符串。
<template>
  <div class="slider" ref="slider">
    <div class="slider-group" ref="sliderGroup">
      <slot name="slider">
      </slot>
    </div>
    <div class="dots">
    </div>
  </div>
</template>
--------------------------------------------------------------------------
      methods: {
          _setSliderWidth() {
            this.children = this.$refs.sliderGroup.children     // 拿到sliderGroup的子元素
            let width = 0
            let sliderWidth = this.$refs.slider.clientWidth      // 拿到slider的宽度
            for (let i = 0; i < this.children.length; i++) {
                let child = this.children[i]      // 每一个子元素
                addClass(child, 'slider-item')    // 给每一个子元素添加名为'slider-item'的class

                child.style.width = sliderWidth + 'px'    // 每一个子元素的宽度和计算得到的父元素的宽度相同
                width += sliderWidth     // sliderGroup的总宽度
            }
            if (this.loop) {
                width += sliderWidth * 2
            }
            this.$refs.sliderGroup.style.width = width + 'px'      // sliderGroup的总宽度
          },
          _initSlider() {
            this.slider = new BScroll(this.$refs.slider, {       // 获取释口dom
                scrollX: true,
                scrollY: false,
                momentum: true,  // 惯性
                snap: true,     // 用户slider的属性
                snpaLoop: this.loop,
                snapThreshold: 0.3,
                snpaSpeed: 400,
                click: true
            })
          }
      }

(2) 滚动图片的dots

1. scrollEnd() 事件
  • better-scroll中的 scrollEnd() 事件
    scrollEnd()
    参数:{Object} {x, y} 滚动结束的位置坐标
    触发时机:滚动结束。
2. getCurrentPage() 方法
  • better-scroll中的 getCurrentPage() 事件
    getCurrentPage()
    参数:无
    返回值:{Object} { x: posX, y: posY,pageX: x, pageY: y} 其中,x 和 y 表示偏移的坐标值,pageX 和 pageY 表示横轴方向和纵轴方向的页面数。 ( pageIndex )
    作用:获取当前页面的信息。
3.goToPage(x, y, time, easing)

参数
{Number} x 横轴的页数
{Number} y 纵轴的页数
{Number} time 动画执行的时间
{Object} easing 缓动函数,一般不建议修改,如果想修改,参考源码中的 ease.js 里的写法
返回值:无
作用:当我们做 slide 组件的时候,slide 通常会分成多个页面。调用此方法可以滚动到指定的页面。

_initSlider() {
            this.slider = new BScroll(this.$refs.slider, {
                scrollX: true,
                scrollY: false,
                momentum: false,  // 惯性,物理学的动量
                snap: true,     // 用于slider
                snpaLoop: this.loop,
                snapThreshold: 0.3,
                snpaSpeed: 400,
                click: true
            })
            this.slider.on('scrollEnd', () => {      // 在滑动结束时触发事件
                let pageIndex = this.slider.getCurrentPage().pageX   // 得到当前的index
                if (this.loop) {
                    pageIndex -= 1
                }
                this.currentPageIndex = pageIndex
            })
          }
  _initDots() {     // dots的数量
            this.dots = new Array(this.$refs.sliderGroup.children.length)    // 长度为5的空数组
          }

-------------------------------------------------------------------

<div class="dots">
      <span v-for="(item,index) in dots"    // 循环dots
            class="dot"    // 每个dot的class
            v-bind:class="{'active': currentPageIndex === index }">    // 当前的dot的class
      </span>
</div>

(9) keep-alive

<keep-alive></keep-alive>

如果把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。也不会重新请求数据,为此可以添加一个 keep-alive 指令参数:

include 和 exclude 属性允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:

include - 字符串或正则表达式。只有匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何匹配的组件都不会被缓存。

<keep-alive>
  <component :is="currentView">
    <!-- 非活动组件将被缓存! -->
  </component>
</keep-alive>
--------------------------------------------------------------

实例:

  <keep-alive>
      <router-view></router-view>
  </keep-alive>

---------------------------------------------------------------

新增:

<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
  <component :is="view"></component>
</keep-alive>

<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>

<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>

(10) destroyed生命周期钩子

Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

(11) axios之服务器端的请求

(11) express Router的使用

(11) 前端不能直接修改request headers,所以需要使用后端代理:原理是,前端请求的url地址,不是直接请求别的网站地址,而是自己的server端 ( 后端路由给的地址),然后由后端再去请求别的网站地址。

1. referer 请求的来源

  • Http协议头中的Referer主要用来让服务器判断来源页面, 即用户是从哪个页面来的,通常被网站用来统计用户来源,是从搜索页面来的,还是从其他网站链接过来,或是从书签等访问,以便网站合理定位.
    Referer有时也被用作防盗链, 即下载时判断来源地址是不是在网站域名之内, 否则就不能下载或显示,很多网站,如天涯就是通过Referer页面来判断用户是否能够下载图片.
    当然,对于某些恶意用户,也可能伪造Referer来获得某些权限,在设计网站时要考虑到这个问题.

  • 还可用做电子商务网站的安全,在提交信用卡等重要信息的页面用referer来判断上一页是不是自己的网站,如果不是,可能是黑客用自己写的一个表单,来提交,为了能跳过你上一页里的javascript的验证等目的。
    但是注意不要把Rerferer用在身份验证或者其他非常重要的检查上,因为Rerferer非常容易在客户端被改变。


    推荐首页截图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 初衷:看了很多视频、文章,最后却通通忘记了,别人的知识依旧是别人的,自己却什么都没获得。此系列文章旨在加深自己的印...
    DCbryant阅读 3,896评论 0 20
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,152评论 0 4
  • 窗外风起,临窗听风语。耳中清音歌一曲,岸上柳丝缕缕。手抚书卷无意,秋风偷过窗来。悠然翻得几页,轻轻合上逃开。
    伯狼阅读 276评论 0 1
  • 本来以为下定决心这写点东西的,但隔了一个星期还是什么也没写出来。总是以各种理由说自己没时间,今夜是难得的独处之夜。...
    水田wxh阅读 168评论 0 0
  • 现在养宠的人越来越多了呢,宠物的数量也一直在不断增长,随之而来的是,宠物疾病的发病率也在不断地升高! 对于我们铲屎...
    甘棠君阅读 462评论 2 4