weex入门到掌握

http://localhost:8081/index.android.bundle?platform=android
                                                            1.环境配置
1.下载安装node 
    检验安装成功:
        node -v
2.在cmd中安装npm
    检验安装成功:
        npm -v
3.下载git并安装
    检验安装成功:git -v
4.在cmd中安装webpack:安装命令:npm install webpack -g
    检验安装成功:webpack -v

                                                            2.创建weex项目
1.使用命令weex -v先检查是否安装了weex 
2.使用命令weex create firstWeexDemo(firstWeexDemo是工程名,自定义)注意的是:在接下来创建工程名时不要出现大写字母,否则会创建失败
3.创建完成之后,使用命令 npm install安装npm解析器
4.安装完成之后先cd到创建完成的工程目录在使用命令weex platform add android将创建的工程加入android项目平台
5.打开androidStudio->选择打开一个已经存在的工程->选择platform下的andriod目录导入
6.导入完成之后,添加虚拟设备,create virtual device 创建对应的屏幕尺寸等

                                                            3.weex常用命令和热更新        
1.先将创建好的工程拉入vscode
2.打开package.json,进入cmd 先cd到创建的目录之下,使用命令npm run dev命令运行项目文件
3.在打开一个终端,输入npm run serve,如果配置没有问题就会自己跳转到浏览器界面
4.weex支持热更新,所以在src/index.vue中改变,但是页面并不会随之改变
5.在打开一个终端,使用webpack进行打包,打完包之后就可以随时进行热更新了 注:如果之前没有安装webpack,还需要根据提示安装webpack-cli脚手架    
        注:每次更改完成之后,都要记得使用webpack打包到dist目录下(每次会自动打包到dist目录下),才能实现实时的页面更新
        但是添加监控之后,只要刷新界面就会起到更新作用:
        监控设置:在package.json文件中build改为这种: "build": "webpack --env.NODE_ENV=common",
        
        
        
        
        
                                                            4.Android Studio 开发设置以及weex init创建一个前端使用的weex项目
1.每次启动之前应该先开启两个服务:一个是npm  run build(用于开启打包的监控服务)
                                        npm run serve(用于在浏览器界面运行项目)
2.实时预览的浏览地址:http://192.168.239.1:8082/webpack-dev-server/web/
3.先在vscode中将dist目录下的index.js的内容copy到androidStudio中的app目录下的assets下的index.js中(注:如果有两个index.js,那就全部都copy)
4.更改应用图标:在androidStudio中,res/mipmap下就存放着图标
5.打包生成apk文件,build->Build Bundles/apk->bulid apk
    如果打包成功,就会出现打包成功的提示,如果失败,就按照提示进行修改
6.weex init 创建的project主要用于前端人员的开发
  weex create 创建的项目主要用于专门开发架构的人员进行开发
7.先切换到创建工程对应的目录,使用weex init projectName创建一个工程
8.创建完成之后,cd到新创建的工程目录,在进行npm install
9.把创建的项目使用vscode打开
10.使用指令 npm run serve打开对应的项目页面

                                                            5.weex和vue之间的联系
weex与vue之间的不同:
    1.布局不同:在html或者Vue中我们可以使用浮动布局,但是weex并不支持,所以请不要使用。
    2.不支持百分数:html中布局,经常使用百分比进行布局,这种布局可以适应不同屏幕,但是你用weex布局时百分比是不支持的。
    3.不支持综合写法:比如html中支持border:1px solid red;但是weex就不支持
    4.weex的像素只支持px,不支持em rem pt
    
    
    
    
    


                                                            6.自定义组件和Text组件
1.在src目录下先创建一个vue,里面用于写你自定义的内容
    自定义的vue内容:
        <!--html-->
<template>
<!--最外层必须用div包裹-->
    <div class="topHeader">
        <!--文字必须用text包裹-->
        <text class="top_text">你好,weex</text>
    </div>
</template>
<!--js-->
<script>
export default {
    
}
</script>
<!--css-->
<style scoped>
 .topHeader{
     background-color: red;
     padding: 10px;

 }
 .top_text{
     color: #fff;
     font-size: 46px;
     text-align: center;
     lines:1;
 }

</style>
    在显示的主页面(index.vue)引用:
        在<script></script>中进行引用:import topHeader from './topHeader.vue';
        在<script></script>中定义一个components,并且进行声明:
            components:{
    topHeader
  }
    定义完成之后就可以直接在template中定义使用了
    下面讲一下text组件:注:只有weex可以使用text组件:        详情参考此网址:https://weex.apache.org/cn/references/components/text.html
    在css样式中定义lines属性:lines=n,那么引用这个css样式之后的text中的内容就以n行显示 注:lines只能在css样式中定义
    
    
    
    
    
                                                            7.Input组件和初识内建模块
1.注意点一:
    我们在weex中<input />标签必须写成闭合形式,如果不闭合在手机或者模拟器中是渲染不出来的,会一直显示加载。
2.使用init创建的工程打包方式:
    使用命令:npm run build会在dist目录下生成两个文件:生成的两个文件名字会在最后提示,将index.web.js中的文件打开复制粘贴到androidStudio打开
    的文件assets/index.js文件中(注意是直接复制替换)
下面讲一下内建模块:
    在主页面index.vue的<script>部分声明对内建模块的定义:
        var modal=weex.requireModule("modal");//参数必须是model
    接下来定义内建模块的声明周期:
        created(){
    modal.toast({
      message:'页面初始化成功',//用于提醒的字段
      duration:3//内建模块持续的秒数
    });
  }
  
  
  
  
  
                                                            8.Image和video组件
1.image组件及其对应的属性:
    <template></template>内容:
      <!--resize="stretch":重新定义图片尺寸,其中resize属性有:stretch默认值,指定图片按照容器拉伸,有可能使图片产生形变。
                                                             cover:指定图片可以被调整到容器,以使图片完全覆盖背景区域,图片有可能被剪裁。
                                                             contain:指定可以不用考虑容器的大小,把图像扩展至最大尺寸,以使其宽度和高度完全适应内容区域。
       -->
     <image class="testImage"   resize="cover"
     src="https://img-blog.csdnimg.cn/2022010617505325844.jpeg"></image>
    对应的<script></script>内容:无;
    对应的<style></style>内容: 
    .testImage{
    /*
    720px=100%
    1250px=100%
    */
    width:720px;
    height:300px;
  }
    注:image是weex独有的属性
2.video组件:
    <template></template>内容:
         <video class="video" :src="src" autoplay controls
      v-on:start="onstart"  v-on:pause="onpause"  v-on:finish="onfinish"  v-on:fail="onfail"></video>
    <script></script>中的内容:
 export default {
  name: 'App',
  data () {
    return {
     src:'https://www.youtube.com/watch?v=wn12uL6pYIc'
    }
  },
  methods:{
      onstart (event) {
        this.state = 'onstart'
      },
      onpause (event) {
        this.state = 'onpause'
      },
      onfinish (event) {
        this.state = 'onfinish'
      },
      onfail (event) {
        this.state = 'onfinish'
      }
  }
    对应的<style></style>样式:
        .video {
    width: 630px;
    height: 350px;
    margin-top: 60px;
    margin-left: 60px;
  }
所有的代码:
    <template>
  <div >
   <text class="text">Hello Word</text>
    <div>
      <input type="text"  placeholder="输入姓名" class="textInput" :autofocus=true />
       </div>
       <!--resize="stretch":重新定义图片尺寸,其中resize属性有:stretch是让图片按照容器的尺寸进行拉伸
                                                             cover:以中间为基准进行裁切 
                                                             contain:不用考虑容器尺寸,直接显示图片能够显示的最大尺寸
       -->
     <image class="testImage"   resize="cover"
     src="https://img-blog.csdnimg.cn/2022010617505325844.jpeg"></image>
  
   <video class="video" :src="src" autoplay controls
      v-on:start="onstart"  v-on:pause="onpause"  v-on:finish="onfinish"  v-on:fail="onfail"></video>
  </div>
</template>
<script>
import topHeader from './topHeader.vue';
var modal=weex.requireModule("modal");//参数必须是model
 export default {
  name: 'App',
  data () {
    return {
      logo: 
      'data:image/jpeg;base64,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',
     src:'https://www.youtube.com/watch?v=wn12uL6pYIc'
    }
  },
  components:{
    topHeader
  },
  created(){
    modal.toast({
      message:'页面初始化成功',//用于提醒的字段
      duration:3//内建模块持续的秒数
    });
  },
  methods:{
      onstart (event) {
        this.state = 'onstart'
      },
      onpause (event) {
        this.state = 'onpause'
      },
      onfinish (event) {
        this.state = 'onfinish'
      },
      onfail (event) {
        this.state = 'onfinish'
      }
  }

}
</script>

<style scoped>
  .wrapper {
    justify-content: center;
    align-items: center;
  }
  .logo {
    width: 424px;
    height: 200px;
  }
  .greeting {
    text-align: center;
    font-size: 50px;
    color: #41B883;
    background: rgb(90, 114, 1)
  }
  .message {
    margin: 30px;
    font-size: 32px;
    color: #727272;
  }
  .text{
  text-align:center;
 
  }
  .textInput{
   
    border-bottom-width:1px; 
  }
  .testImage{
    /*
    720px=100%
    1250px=100%
    */
    width:720px;
    height:300px;
  }
  .video {
    width: 630px;
    height: 350px;
    margin-top: 60px;
    margin-left: 60px;
  }
</style>

                                                            9.制作列表
1.先看一下loadmore组件的功能代码:用于上拉加载
    <template>
  <div >
    <!--list相当于html中的ul
           ceil相当于html中的li 
           注:list和ceil都不能进行样式的编写
-------------------------------------------------------------------------------------------------------------------
           loadmore:在移动端中上拉加载是经常使用的一个功能,weex中要实现这个功能需要使用一个loadmore属性,从英文单词中可以看出,
           就是加载更多的意思。我们在中加入loadmore属性,并绑定一个fetch方法 
           注:loadmore必须写在list里面,要不然就不起作用
           loadmoreoffset:是加载列偏移的意思 
       -->
    <list v-on:loadmore="fetch" loadmoreoffset="10">
      <cell v-for="rum in lists">
         <!--weex要想遍历数组,必须使用text,但是text组件应该单独放在div中-->
         <div class="panel">
           <text class="text">{{rum}}</text>
         </div>
      </cell>
    </list>
  </div>
</template>
<script>
  //声明一个内联模块
  var modal=weex.requireModule("modal");//参数必须是model
  export default {
    
    data () {
      return {
        lists:[1,2,3,4,5]
      }
    },
      methods:{
        //fetch(event):用于检测所有的事件
      fetch(event){
        /*使用内联模块
        duration:1 1:指的是1秒
        */
        modal.toast({message:'loadmore',duration:1});
        /*用于实现模拟下拉菜单的功能
        setTimeout方法解析:包含function delay code
        (注:code 这是一个替代语法,你可以使用字符串代替function ,在delay毫秒之后执行字符串 
        (使用该语法是不推荐的, 原因和使用 eval()一样,有安全风险)。)
        function 是你想要在delay毫秒之后执行的函数(function这个单词不一定要显示出来,不写function 直接写函数体也行)
        延迟的毫秒数 (一秒等于1000毫秒),函数的调用会在该延迟之后发生。如果省略该参数,delay取默认值0。实际的延迟时间可能会比 delay 值长
        */
        setTimeout(()=>{
          const length = this.lists.length;
          for(let i=length;i<length+4;i++){
            //给数组lists不停地添加新元素
            this.lists.push(i+1);
          }
        },800);//此处的800指的是毫秒
      }
    }
  }
  
</script>
<style scoped>
  .panel{
    width:600px;
    height:250px;
    margin-left:75px;
    margin-top:35px;
    margin-bottom:35px;
    flex-direction: column;
    justify-content: center;
    border-width: 2px;
    border-style: solid;
    border-color:rgb(162,217,192);
    background-color:rgba(162, 217, 192, 0.2)
  }
  .text{
    font-size:50px;
    text-align: center;
    color:#41B883;
  }
</style>
2.loading组件的使用:用于下拉加载的组件
    <loading>组件 要使用<loading>组件你需要先去<list>组件上的loadmore和loadmoreoffset属性,并在list中加入<loading>组件
    代码详情:
        <template>
  <div>
      <list>
        <cell v-for="rum in lists">
          <div class="panel">
            <text class="text">{{rum}}</text>
          </div>
        </cell>
        <!--loading必须写在list里面
        display:用于设置显示loading
        -->
        <loading class="loading" v-on:loading="onloading" :display="showLoading">
          <text class="indicator">Loading...</text>
        </loading>
      </list>
  </div>
</template>
<script>
  //声明一个内联模块
  var modal=weex.requireModule("modal");//参数必须是model
  export default {
    
    data () {
      return {
        lists:[1,2,3,4,5]
      }
    },
      methods:{ 
    onloading(event) {
    modal.toast({ message: 'loading', duration: 1 });
    //用于设置loading是否显示
    this.showLoading = 'show';
      setTimeout(() => {
        const length = this.lists.length;
        for (let i = length; i < length + 4; i++) {
          this.lists.push(i + 1);
        }
        //每次加载完之后就让loading消失,否则loading就会一直进行
        this.showLoading = 'hide';
      }, 1500)

    }
      }
  }
</script>
<style scoped>
  .panel{
    width:600px;
    height:250px;
    margin-left:75px;
    margin-top:35px;
    margin-bottom:35px;
    flex-direction: column;
    justify-content: center;
    border-width: 2px;
    border-style: solid;
    border-color:rgb(162,217,192);
    background-color:rgba(162, 217, 192, 0.2)
  }
  .text{
    font-size:50px;
    text-align: center;
    color:#41B883;
  }
</style>
3.<refresh>组件
    实际开发中还需要刷新页面,weex在列表中也为我们想好了,提供了 <refresh>组件,它的作用就是在上拉时进行刷新页面
    <template>
  <div>
    <!--refresh:用于粗略的刷新监控界面
        pullingdown:能够细致的监控界面,能够返回你下拉了多少像素
    -->
    <refresh class="refresh" v-on:refresh="onrefresh" v-on:pullingdown="onpullingdown" :display="refreshing">
        <text class="indicator">Refreshing ...</text>
</refresh>
      <list>
        <cell v-for="rum in lists">
          <div class="panel">
            <text class="text">{{rum}}</text>
          </div>
        </cell>
        <!--loading必须写在list里面
        display:用于设置显示loading
        -->
        <loading class="loading" v-on:loading="onloading" :display="showLoading">
          <text class="indicator">Loading...</text>
        </loading>
      </list>
  </div>
</template>
<script>
//声明一个内联模块
var modal = weex.requireModule("modal"); //参数必须是model
export default {
  data() {
    return {
      lists: [1, 2, 3, 4, 5],
      showLoading: "hide",
      refreshing: "hide"
    };
  },
  methods: {
    //下拉加载
    onloading(event) {
      modal.toast({ message: "loading", duration: 1 });
      //用于设置loading是否显示
      this.showLoading = "show";
      setTimeout(() => {
        const length = this.lists.length;
        for (let i = length; i < length + 4; i++) {
          this.lists.push(i + 1);
        }
        //每次加载完之后就让loading消失,否则loading就会一直进行
        this.showLoading = "hide";
      }, 1500);
    },
    onrefresh(event) {
      modal.toast({ message: "refresh", duration: 1 });
      this.refreshing = "show";
      setTimeout(() => {
        this.lists = [1, 2, 3, 4, 5];
        this.refreshing = "hide";
      }, 2000);
    },
    onpullingdown(event) {
      modal.toast({ message: "pulling down", duration: 1 });
    }
  }
};
</script>
<style scoped>
.panel {
  width: 600px;
  height: 250px;
  margin-left: 75px;
  margin-top: 35px;
  margin-bottom: 35px;
  flex-direction: column;
  justify-content: center;
  border-width: 2px;
  border-style: solid;
  border-color: rgb(162, 217, 192);
  background-color: rgba(162, 217, 192, 0.2);
}
.text {
  font-size: 50px;
  text-align: center;
  color: #41b883;
}
</style>

                                                            10.从后端服务器上获取数据
1.stream的引入
要想使用stream,必须使用weex来进行引入。
stream.fetch(options, callback[,progressCallback]):
    options {Object}:请求的一些选项 包含:
                                            method {string}:HTTP 方法 GET 或是 POST
                                            url {string}:请求的 URL
                                            headers {Object}:HTTP 请求头
                                            type {string}:响应类型, json,text 或是 jsonp {在原生实现中其实与 json 相同)
                                            body {string}:HTTP 请求体。
    注意:
        body 参数仅支持 string 类型的参数,请勿直接传递 JSON,必须先将其转为字符串。
        GET 请求不支持 body 方式传递参数,请使用 url 传参。
    callback:回调函数
        
    测试代码:
<template>
  <div>
    <list>
      <cell v-for="news in lists">
        <div class="panel">
          <text class="text">{{news.newsTitle}}</text>
          <text class="content">{{news.newsContent}}</text>
          <text class="content">{{news}}</text>
        </div>
        <div class="panel">
           <text class="title">method = GET</text>
      <text class="count">{{getResult}}</text>
        </div>
      </cell>
    </list>
  </div>
</template>
<script>
const modal = weex.requireModule('modal');
//要想使用stream,必须使用weex来进行引入stream模块。stream主要是用于接收json字符串
const stream = weex.requireModule('stream');
export default {
  data() {
    return {
      lists: [],
    }
  },
  /*钩子函数------在组件实例化完成之后就会执行这个函数,但是页面还未显示
  组件实例化之前先请求json数据
  */
  created(){
    let url='http://jsfiddle.net/echo/jsonp/?callback=anything&result=content_in_response';
    //调用getNews方法
    this.getNews(url,res=>{
      modal.toast({message:'请求成功',duration:1});
      //把获取的data数据赋值给lists
      this.lists=res.data;
      console.log("jsonData="+res.data);
    });
  },
  methods: {
    getNews(url,callback){
      //此处是stream的fetch方法
      return stream.fetch({
        //使用get的方式请求
        method:'GET',
        //请求的数据是json格式
        type:'json',
        url:url
        //callback是回调函数,也就是请求之后调用的函数
      },callback);
    }
  }
}
</script>

<style scoped>
.panel {
  width: 650px;
  height: 250px;
  margin-left: 50px;
  margin-top: 35px;
  margin-bottom: 35px;
  flex-direction: column;
  padding-top:15px;
   padding-left:10px;
  padding-right:10px;
  border-width: 2px;
  border-style: solid;
  border-color: rgb(162, 217, 192);
  background-color: rgba(162, 217, 192, 0.2)
}
.text {
  font-size: 36px;
  text-align: center;
  color: #41B883;
}
.content{
  lines:5;
  font-size: 28px;
}
</style>


    详细的stream使用代码:
        <template>
  <scroller>
    <div class="panel">
      <text class="title">method = GET</text>
      <text class="content">{{getResult}}</text>
    </div>
    <div class="panel">
      <text class="title">method = GET / type = jsonp</text>
      <text class="content">{{getJsonpResult}}</text>
    </div>
    <div class="panel">
      <text class="title">method = POST</text>
      <text class="content">{{postResult}}</text>
    </div>
    <div class="panel">
      <text class="title">method = PUT</text>
      <text class="content">{{putResult}}</text>
    </div>
    <div class="panel">
      <text class="title">method = DELETE</text>
      <text class="content">{{deleteResult}}</text>
    </div>
    <div class="panel">
      <text class="title">method = HEAD</text>
      <text class="content">{{headResult}}</text>
    </div>
    <div class="panel">
      <text class="title">method = PATCH</text>
      <text class="content">{{patchResult}}</text>
    </div>
  </scroller>
</template>

<script>
  var stream = weex.requireModule('stream');
  module.exports = {
    data: function () {
      return {
        getJsonpResult: 'loading...',
        getResult: 'loading...',
        postResult: 'loading...',
        putResult: 'loading...',
        deleteResult: 'loading...',
        headResult: 'loading...',
        patchResult: 'loading...'
      }
    },
    created: function() {
      var me = this;
      var GET_URL_JSONP = 'http://jsfiddle.net/echo/jsonp/?callback=anything&result=content_in_response';
      var GET_URL = 'http://httpbin.org/get';
      var POST_URL = 'http://httpbin.org/post';
      var PUT_URL = 'http://httpbin.org/put';
      var DELETE_URL = 'http://httpbin.org/delete';
      var HEAD_URL = 'http://httpbin.org/status/418';
      var PATCH_URL = 'http://httpbin.org/patch';

      stream.fetch({
        method: 'GET',
        url: GET_URL_JSONP,
        type:'jsonp'
      }, function(ret) {
        if(!ret.ok){
          me.getJsonpResult = "request failed";
        }else{
          console.log('get:'+ret);
          me.getJsonpResult =  JSON.stringify(ret.data);
        }
      },function(response){
        console.log('get jsonp in progress:'+response.length);
        me.getJsonpResult = "bytes received:"+response.length;
      });

      stream.fetch({
        method: 'GET',
        url: GET_URL,
        type:'json'
      }, function(ret) {
        if(!ret.ok){
          me.getResult = "request failed";
        }else{
          console.log('get:'+ret);
          me.getResult = JSON.stringify(ret.data);
        }
      },function(response){
        console.log('get in progress:'+response.length);
        me.getResult = "bytes received:"+response.length;
      });

      stream.fetch({
        method: 'POST',
        url: POST_URL,
        type:'json'
      }, function(ret) {
        if(!ret.ok){
          me.postResult = "request failed";
        }else{
          console.log('get:'+JSON.stringify(ret));
          me.postResult = JSON.stringify(ret.data);
        }
      },function(response){
        console.log('get in progress:'+response.length);
        me.postResult = "bytes received:"+response.length;
      });

      stream.fetch({
        method: 'PUT',
        url: PUT_URL,
        type:'json'
      }, function(ret) {
        if(!ret.ok){
          me.putResult = "request failed";
        }else{
          console.log('get:'+JSON.stringify(ret));
          me.putResult = JSON.stringify(ret.data);
        }
      },function(response){
        console.log('get in progress:'+response.length);
        me.putResult = "bytes received:"+response.length;
      });

      stream.fetch({
        method: 'DELETE',
        url: DELETE_URL,
        type:'json'
      }, function(ret) {

        if(!ret.ok){
          me.deleteResult = "request failed";
        }else{
          console.log('get:'+JSON.stringify(ret));
          me.deleteResult = JSON.stringify(ret.data);
        }
      },function(response){
        console.log('get in progress:'+response.length);
        me.deleteResult = "bytes received:"+response.length;
      });

      stream.fetch({
        method: 'HEAD',
        url: HEAD_URL,
        type:'json'
      }, function(ret) {
        if(ret.statusText !== 'I\'m a teapot'){
          me.headResult = "request failed";
        }else{
          console.log('get:'+JSON.stringify(ret));
          me.headResult = ret.statusText;
        }
      },function(response){
        console.log('get in progress:'+response.length);
        me.headResult = "bytes received:"+response.length;
      });

      stream.fetch({
        method: 'PATCH',
        url: PATCH_URL,
        type:'json'
      }, function(ret) {
        if(!ret.ok){
          me.patchResult = "request failed";
        }else{
          console.log('get:'+JSON.stringify(ret));
          me.patchResult = JSON.stringify(ret.data);
        }
      },function(response){
        console.log('get in progress:'+response.length);
        me.patchResult = "bytes received:"+response.length;
      });
    }
  };
</script>

<style scoped>
.panel {
  width: 650px;
  height: 250px;
  margin-left: 50px;
  margin-top: 35px;
  margin-bottom: 35px;
  flex-direction: column;
  padding-top:15px;
   padding-left:10px;
  padding-right:10px;
  border-width: 2px;
  border-style: solid;
  border-color: rgb(162, 217, 192);
  background-color: rgba(162, 217, 192, 0.2)
}
.text {
  font-size: 36px;
  text-align: center;
  color: #41B883;
}
.content{
  lines:5;
  font-size: 28px;
}
</style>

                                                            11.作轮播图片效果
<template>
  <div>
      <!--
      slider:是实现轮滑的组件,这个是weex的内置组件
      interval:以毫秒为单位,表示多久更换一次图片 但是要想使用自动轮播,必须配合另一个属性auto-play
    auto-play是自动播放,设置为true就可以实现自动播放
    infinite:用于循环播放,默认值为true
    indicator:是slider的子组件,用于显示书签效果 必须充当 组件的子组件使用
    -->
    <slider class="slider" interval="3000" auto-play="true" infinite="true">
      <div class="frame" v-for="img in imageList">
        <image class="image" resize="cover" :src="img.src"></image>
      </div>
      <!--由于indicator是slider的子组件,绝对不允许写在div中-->
      <indicator class="indicator"></indicator>
    </slider>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        imageList: [
          { src: 'https://gd2.alicdn.com/bao/uploaded/i2/T14H1LFwBcXXXXXXXX_!!0-item_pic.jpg'},
          { src: 'https://gd1.alicdn.com/bao/uploaded/i1/TB1PXJCJFXXXXciXFXXXXXXXXXX_!!0-item_pic.jpg'},
          { src: 'https://gd3.alicdn.com/bao/uploaded/i3/TB1x6hYLXXXXXazXVXXXXXXXXXX_!!0-item_pic.jpg'}
        ]
      }
    }
  }
</script>

<style scoped>
  .image {
    width: 700px;
    height: 700px;
  }
  .slider {
    margin-top: 25px;
    margin-left: 25px;
    width: 700px;
    height: 700px;
    border-width: 2px;
    border-style: solid;
    border-color: #41B883;
  }
  .frame {
    width: 700px;
    height: 700px;
    position: relative;
  }
  .indicator{
    height:700px ;
    width:700px ;
    /*
     item-color:是indicator独有的样式,它是用于定义书签圆点的颜色
     item-selected-color:是indicator独有的样式,它是用于设置被选中时的颜色
    */
    item-color:#ffff;
     item-selected-color:red;
     /*
     此处的设置是用于设置真实的运行时圆点标签的产生效果
     */
     position: absolute;
  }
</style>

                                                            12.a组件和web组件
使用<a>组件时需要和我们html中的<a>标签区分,html中的<a>标签是用来链接html页面的,而weex中的<a>组件是用来链接weex格式的js文件的
判断是否可以访问到你所创建的文件:
    先cd到创建的目录之下,使用命令ipconfig查看ipv4的地址
    比如我的是192.168.239.1
    后面添加端口号8080或者8081等。
    访问地址http://192.168.239.1:8081/slider.js(slider.js就是你要判断是否可以访问的文件)
    如果可以访问那么就会显示这个文件里面的内容,如果未显示,说明不能进行访问
    index.vue中的主要代码如下:
        <template>
  <div class="wrapper">
    <!--href如果是要访问连接,必须把地址路径写完整-->
    <a class="button" href="http://192.168.239.1:8081/slider.js">
    <text class="text">跳转轮播图</text>
    </a>
  </div>
</template>
下面讲一下web组件    在原生的软件中嵌入网站页面
<template>
  <div class="wrapper">
    <!--直接引用web组件,在原生的软件中嵌入网站页面
   pagestart:<web>组件开始加载时此事件触发。
   pagefinish:<web>组件完成加载时此事件触发。
   error:如果<web>组件出现错误,会发送此事件消息。
    -->
  <web src="https://www.baidu.com/" class="web" v-on:pagestart="start" v-on:pagefinish="finish" v-on:error="error"></web>
  </div>
</template>
<script>
/*使用声明周期----钩子函数
先定义一个modal
*/
const modal = weex.requireModule("modal");
export default {
  data() {
    return {};
  },
  methods: {
    start() {
      modal.toast({
        message: "页面开始调用", //用于提醒的字段
        duration: 3 //内建模块持续的秒数
      });
    },
    finish() {
      modal.toast({
        message: "页面结束调用", //用于提醒的字段
        duration: 3 //内建模块持续的秒数
      });
    },
    error() {
      modal.toast({
        message: "页面调用错误", //用于提醒的字段
        duration: 3 //内建模块持续的秒数
      });
    }
  }
};
</script>
<style scoped>
.wrapper {
  flex-direction: column;
  justify-content: center;
}
.web {
  margin-left: 75px;
  width: 600px;
  height: 750px;
  border-width: 2px;
  border-style: solid;
  border-color: #41b883;
}
</style>

                                                            13.通用事件和动画模块
1.先描述一些常见的事件:
    <1>longpress(长按事件):如果一个组件被绑定了 longpress 事件,那么当用户长按这个组件时,该事件将会被触发。
    <2>Appear(屏幕内事件):如果一个位于某个可滚动区域内的组件被绑定了 appear 事件,那么当这个组件的状态变为在屏幕上可见时,
        该事件将被触发。
    <3>Disappear(屏幕外事件):如果一个位于某个可滚动区域内的组件被绑定了 disappear 事件,
        那么当这个组件被滑出屏幕变为不可见状态时,该事件将被触发。
2.动画效果:
    <template>
  <div class="wrapper">
    <!--ref:ref 被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的 $refs 对象上。
    如果在普通的 DOM 元素上使用,引用指向的就是DOM 元素;如果用在子组件上,引用就指向组件实例。-->
    <div ref="test" v-on:click="move" class="box"></div>
  </div>
</template>

<script>
  const modal = weex.requireModule('modal');
  //引入动画模块
  const animation =weex.requireModule('animation');
  export default {
    data () {
      return {
      }
    },
    methods:{
       move () {
        // 使用$refs属性可以通过test来引用和操作这个div
        var testEl = this.$refs.test;
        animation.transition(testEl, {
          //styles样式必须加在引号里,否则就是无效
          styles: {
            
            color: '#FF0000',
            //过渡方式:让动画以何种方式进行过渡,translate(250px, 100px):表示横轴移动250px,纵轴移动100px;
            transform: 'translate(250px, 100px)',
            //transformOrigin:移动的中心点
            transformOrigin: 'center center'
          },
          //duration:动画进行的秒数pick(options, callback[options])
          duration: 800, //ms
          //timingFunction:缓动,缓动的方式有ease ease-in ease-out
          timingFunction: 'ease ',
          //延迟动画
          delay: 1000 //ms
        //此处的function是动画完成之后的回调函数
        }, function () {
          modal.toast({ message: 'animation finished.' ,
          uration: 3 //内建模块持续的秒数
          }
          )
        })
      }
    }
  }
</script>

<style scoped>
 .box{
   width:250px;
   height:250px;
   background-color:#DDD;
 }
</style>

                                                            14.weex的时间选取模块picker
1.pick(options1, callback {function (ret)})
    options1:index {number}:默认选中的选项
             items {array}:picker 数据源
             textColor {color}:picker中文字的颜色
             selectionColor {color}:picker中选中item的背景色
             confirmTitle {string}:确认按钮的文案
             cancelTitle {string}:取消按钮的文案
             confirmTitleColor {color}:确认按钮的文字颜色
             cancelTitleColor {color}:取消按钮的文字颜色
             title {string}:对话框的标题
             titleColor {color}:对话框标题的文字颜色
             titleBackgroundColor {color}:对话框标题的背景色
    callback {function (ret)}:执行完读取操作后的回调函数。ret {Object} 为 callback 函数的参数,
    有两个属性:result {string}:结果三种类型 success, cancel, error
                data {number}:选择的选项,仅成功确认时候存在。time 格式为 HH:mm, 仅成功确认的时候存在。
                代码详情:
                <template>
  <div class="wrapper">
    <div class="group">
      <text class="label">Time: </text>
      <text class="title">{{value}}</text>
    </div>
    <div class="group">
      <text class="button" v-on:click="pickTime">Pick Time</text>
    </div>
  </div>
</template>

<script>
//引用picker组件
  const picker = weex.requireModule('picker')

  export default {
    data () {
      return {
        value: ''
      }
    },
    methods: {
      pickTime () {
        picker.pickTime({
          value: this.value
        }, event => {
          //调用回调函数,如果返回的结果是success,那么说明调用pickdate成功
          if (event.result === 'success') {
            this.value = event.data
          }
        })
      }
    }
  }
</script>

<style scoped>
  .wrapper {
    flex-direction: column;
    justify-content: center;
  }
  .group {
    flex-direction: row;
    justify-content: center;
    margin-bottom: 40px;
    align-items: center;
  }
  .label {
    font-size: 40px;
    color: #888888;
  }
  .title {
    font-size: 80px;
    color: #41B883;
  }
  .button {
    font-size: 36px;
    width: 280px;
    color: #41B883;
    text-align: center;
    padding-top: 25px;
    padding-bottom: 25px;
    border-width: 2px;
    border-style: solid;
    border-color: rgb(162, 217, 192);
    background-color: rgba(162, 217, 192, 0.2);
  }
</style>

                                                            15.weex的粘贴模块clipboard
1.我们可以通过 clipboard 模块的 getString()、setString() 接口从系统的粘贴板获取内容或者设置内容。
    但是需要注意的是clipboard仅支持文本拷贝,而且出于安全考虑和平台限制,只支持 Android 和 iOS,不支持 html5。
    下面先看一下getString(callback)功能:用于从系统粘贴板读取内容
    callback 函数的参数,有两个属性:
                                    ret.data:获取到的文本内容;
                                    ret.result:返回状态,可能为 success 或 fail。
    再看一下setString(text):用于将一段文本复制到剪切板,相当于手动复制文本。
        参数text {string}:要复制到剪切板的字符串。
        代码详情:
            <template>
  <div>
    <div class="div">
      <text class="text" v-on:click="onItemClick">{{message}}</text>
    </div>
    <div class="div">
      <text class="text" v-on:click="setContent">Click to copy: {{tobecopied}}</text>
    </div>
  </div>
</template>

<script>
//引入clipboard模块
  const clipboard = weex.requireModule('clipboard')

  export default {
    data () {
      return {
        tobecopied: 'yay!',
        message: 'nothing.'
      }
    },

    methods: {
      setContent () {
        clipboard.setString(this.tobecopied)
      },
      onItemClick () {
        this.message = 'please click the next table! '
        clipboard.getString(ret => {
          this.message = 'text from clipboard:' + ret.data
        })
      }
    }
  }
</script>

<style scoped>
  .div {
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    width: 750px;
    height: 90px;
    padding-left: 30px;
    padding-right: 30px;

    border-bottom-width: 1px;
    border-style: solid;
    border-color: #DDDDDD;
  }
  .text {
    width: 750px;
    height: 90px;
  }
</style>

                                                            16.weex的Navigator和webview模块
1.先看一下Naviator模块:
    这个就是原生系统上的前进和后退,里边的方法也很简单。只有两个方法。
        push:把一个weex页面URL压入导航堆栈中,可指定在页面跳转时是否需要动画,以及操作完成后需要执行的回调函数
        pop:把一个 Weex 页面 URL 弹出导航堆栈中,可指定在页面弹出时是否需要动画,以及操作完成后需要执行的回调函数。
        详细代码如下:
            <template>
  <div class="wrapper">
    <text class="button" @click="jump">Jump</text>
  </div>
</template>

<script>
const modal = weex.requireModule("modal");
//引入Naviator模块
const navigator = weex.requireModule("navigator");
export default {
  data() {
    return {};
  },
  methods: {
    jump(event) {
      navigator.push(
        {
          //url是指我们要前进到哪里
          url: "http://192.168.239.1:8081/slider.js",
          //animated表示是否调用动画效果,为true表示开启动画效果,为false表示关闭动画效果
          animated: true
        },
        //event是事件点击时的回调函数  
        event => {
          modal.toast({ message: "callback:" + event ,
          duration:3 //内建模块持续的秒数
          });
        }
      );
    }
  }
};
</script>

<style scoped>
.wrapper {
  /*
  flex-direction:指定如何柔性物品被放置在所述柔性容器限定主轴线和方向(正常或反向)
  row:Flex容器的主轴定义为与文本方向相同。所述主起动和主端点是一样的内容方向。
  row-reverse:行为相同row但主要起点和主要点都是置换的。
  column:Flex容器的主轴与块轴相同。在主启动和主结束点是一样的之前和之后的写作模式的要点。
  column-reverse:行为相同,column但主开始和主要端是置换的。
  */
  flex-direction: column;
  justify-content: center;
}
.button {
  font-size: 60px;
  width: 450px;
  text-align: center;
  margin-top: 30px;
  margin-left: 150px;
  padding-top: 20px;
  padding-bottom: 20px;
  border-width: 2px;
  border-style: solid;
  color: #666666;
  border-color: #dddddd;
  background-color: #f5f5f5;
}
</style>
2.webview模块
    webview是一系列的操作,必须和web组件配合使用。包括goback,goForward,reload。注意的是webview必须和组件共用。
    它有三个方法需要我们掌握:
                             goBack:相当于浏览器里的后退。
                             goForward:相当于浏览器里的前进。
                             reload:刷新页面。
    对应的详细代码:
        <template>
  <div class="wrapper">
    <div class="group">
      <input class="input" v-model="value" ref="input" type="url" autofocus="false"></input>
    </div>
   
    <div class="group">
       <!--loadURL就是将input中输入的网址进行渲染到我们的界面中,一点击按钮就会触发loadURL事件-->
      <text class="button" @click="loadURL">LoadURL</text>
      <text class="button" @click="reload">reload</text>
    </div>
    <!--上面的LoadURL以及reload都是对web组件的操作
    要使用web组件,必须搭配web,使用ref进行连接,才能使用
    -->
    <web ref="webview" :src="url" class="webview" @pagestart="start" @pagefinish="finish" @error="error"></web>
  </div>
</template>
<script>
  const webview = weex.requireModule('webview')
  const modal = weex.requireModule('modal')
  export default {
    data () {
      return {
        url : 'https://m.alibaba.com',
        value: 'https://m.alibaba.com'
      }
    },
    methods: {
      loadURL (event) {
        this.url = this.value
        modal.toast({ message: 'load url:' + this.url })
      //10s钟之后就会执行setTimeout中的回调函数
        setTimeout(() => {
          console.log('will go back.')
          modal.toast({ message: 'will go back' })
          //webview组件中的回退方法
          webview.goBack(this.$refs.webview)
        }, 10000)//ms
      },
      reload (event) {
        console.log('will reload webview')
        modal.toast({ message: 'reload' })
        webview.reload(this.$refs.webview)
      },
        //start finish error都是web组件中的方法
      start (event) {
        console.log('pagestart', event)
        modal.toast({ message: 'pagestart' })
      },

    
      finish (event) {
        console.log('pagefinish', event)
        modal.toast({ message: 'pagefinish' })
      },
      error (event) {
        console.log('error', event)
        modal.toast({ message: 'error' })
      }
    }
  }
</script>
<style scoped>
  .group {
    flex-direction: row;
    justify-content: space-around;
    margin-top: 20px;
  }
  .input {
    width: 600px;
    font-size: 36px;
    padding-top: 15px;
    padding-bottom: 15px;
    border-width: 2px;
    border-style: solid;
    border-color: #BBBBBB;
  }
  .button {
    width: 225px;
    text-align: center;
    background-color: #D3D3D3;
    padding-top: 15px;
    padding-bottom: 15px;
    margin-bottom: 30px;
    font-size: 30px;
  }
  .webview {
    margin-left: 75px;
    width: 600px;
    height: 750px;
    border-width: 2px;
    border-style: solid;
    border-color: #41B883;
  }
</style>

                                                            17.weex的vue-router的使用
1.路由的三个模式:hash,history,abstract只有我们的abstract是可以使用的,其它使用都会出现问题。
    router-link不能再使用   以前在写vue时,我们经常使用<router-link>标签进行连接跳转
    <router-link>中的用法:
        <!-- 只能在 Web 中使用,Native 环境不支持! -->
<template>
  <div>
    <router-link to="profile">
      <text>Profile</text>
    </router-link>
  </div>
</template>
    但是在weex当中这种形式是不可以使用的,要使用编程式导航的形式进行跳转。
    <template>
  <div>
    <text @click="jump">Profile</text>
  </div>
</template>
<script>
  import router from './path/to/router'
  export default {
    methods: {
      jump () {
        router.push('profile')
      }
    }
  }
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZNineSun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值